diff --git a/.gitignore b/.gitignore index ff72e2d0..2cac7943 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /composer.lock /vendor +/.idea diff --git a/.phpstan.neon b/.phpstan.neon index 5ee599d8..ae21d0f3 100644 --- a/.phpstan.neon +++ b/.phpstan.neon @@ -2,6 +2,10 @@ includes: - phar://%rootDir%/phpstan.phar/conf/bleedingEdge.neon parameters: + level: 7 + paths: + - src + # never type is not supported: https://github.com/phpstan/phpstan/issues/2297 earlyTerminatingMethodCalls: Nextras\Dbal\SqlProcessor: diff --git a/.travis.yml b/.travis.yml index a2024c85..dc3defd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,60 +1,58 @@ language: php php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 + - 7.1 + - 7.2 + - 7.3 + - 7.4 services: - - mysql - - postgresql + - mysql + - postgresql -env: - matrix: - - dependencies=lowest - - dependencies=highest +cache: + directories: + - $HOME/.composer/cache -matrix: - fast_finish: true +before_install: + - phpenv config-rm xdebug.ini || true -cache: - directories: - - $HOME/.composer/cache + # Create php.ini & databases.ini + - cp ./tests/php.unix-sample.ini ./tests/php.ini + - cp ./tests/databases.sample.ini ./tests/databases.ini + + # Create MySQL & PostgreSQL database + - psql -c 'CREATE DATABASE nextras_dbal_test' -U postgres + - sleep 2 + - mysql -e 'CREATE DATABASE nextras_dbal_test;' + - mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql + - mysql -u root -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('')" + +install: + - travis_retry composer update --no-interaction --prefer-dist --no-progress + +jobs: + fast_finish: true + include: + - name: Lowest Dependencies + install: + - travis_retry composer update --prefer-lowest --prefer-stable --no-interaction --prefer-dist --no-progress before_script: - # Create php.ini & databases.ini - - cp ./tests/php.unix-sample.ini ./tests/php.ini - - - if [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then cat ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini >> ./tests/php.ini; fi - - if [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then NTESTER_FLAGS="--coverage ./coverage.xml --coverage-src ./src"; else TESTER_FLAGS=""; fi - - cp ./tests/databases.sample.ini ./tests/databases.ini - - # Create MySQL & Postgre database - - psql -c 'CREATE DATABASE nextras_dbal_test' -U postgres - - sleep 2 - - mysql -e 'CREATE DATABASE nextras_dbal_test;' - - mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql - # https://github.com/travis-ci/travis-ci/issues/6961#issuecomment-264283390 - - mysql -u root -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('')" - - # Install dependencies - - phpenv config-rm xdebug.ini || true - - if [ "$dependencies" = "lowest" ]; then composer update --prefer-lowest --no-interaction; fi - - if [ "$dependencies" = "highest" ]; then composer update --no-interaction; fi + - if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then NTESTER_FLAGS="-p phpdbg --coverage ./coverage.xml --coverage-src ./src"; fi script: - - ./tests/run.sh -s $NTESTER_FLAGS ./tests/cases - - if [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then composer phpstan; fi + - ./tests/run.sh -s $NTESTER_FLAGS ./tests/cases + - if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then composer phpstan; fi after_script: - - if [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then - wget https://github.com/satooshi/php-coveralls/releases/download/v2.0.0/php-coveralls.phar - && php php-coveralls.phar --verbose --config tests/.coveralls.yml - || true; - fi + - if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then + wget https://github.com/satooshi/php-coveralls/releases/download/v2.0.0/php-coveralls.phar + && php php-coveralls.phar --verbose --config tests/.coveralls.yml + || true; + fi after_failure: - # Print *.actual content & log content - - for i in $(find tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done - - for i in $(find tests -name \*.log); do echo "--- $i"; cat $i; echo; echo; done + # Print *.actual content & log content + - for i in $(find tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done + - for i in $(find tests -name \*.log); do echo "--- $i"; cat $i; echo; echo; done diff --git a/composer.json b/composer.json index 93de05fb..bfaad565 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "nette/utils": "~3.0", "nette/finder": "~2.5", "nette/neon": "~3.0", - "phpstan/phpstan": "0.12.17", + "phpstan/phpstan": "0.12.18", + "phpstan/phpstan-deprecation-rules": "0.12.2", "tracy/tracy": "~2.7" }, "autoload": { @@ -30,7 +31,7 @@ "classmap": ["src/exceptions.php"] }, "scripts": { - "phpstan": "phpstan analyse -l 7 -c .phpstan.neon src" + "phpstan": "phpstan analyze -c .phpstan.neon" }, "extra": { "branch-alias": { diff --git a/doc/param-modifiers.texy b/doc/param-modifiers.texy index c001f82a..741356d8 100644 --- a/doc/param-modifiers.texy +++ b/doc/param-modifiers.texy @@ -32,11 +32,12 @@ Other available modifiers: |* `%multiOr` | OR condition with multiple conditions in pairs |* `%values`, `%values[]` | expands array for INSERT clause, multi insert |* `%set` | expands array for SET clause -|* `%table`, `%table[]` | escapes string as table name, surrounding parentheses are not added to `%table[]` modifier; may contain a database or schema name separated by a dot, will be correctly escaped; -|* `%column`, `%column[]` | escapes string as column name, surrounding parentheses are not added to `%column[]` modifier may contain a database name, schema name or asterisk (`*`) separated by a dot, will be correctly escaped; +|* `%table`, `%table[]` | escapes string as table name, may contain a database or schema name separated by a dot; surrounding parentheses are not added to `%table[]` modifier; +|* `%column`, `%column[]` | escapes string as column name, may contain a database name, schema name or asterisk (`*`) separated by a dot; surrounding parentheses are not added to `%column[]` modifier; |* `%ex` | expands array as processor arguments |* `%raw` | inserts string argument as is |* `%%` | escapes to single `%` (useful in `date_format()`, etc.) +|* `[[`, `]]` | escapes to single `[` or `]` (useful when working with array, etc.) Let's examine `%and` and `%or` behavior. If array key is numeric and its value is an array, value is expanded with `%ex` modifier. (See below.) diff --git a/src/Platforms/CachedPlatform.php b/src/Platforms/CachedPlatform.php index c53bcbc6..f95cdd15 100644 --- a/src/Platforms/CachedPlatform.php +++ b/src/Platforms/CachedPlatform.php @@ -35,10 +35,10 @@ public function getName(): string } - public function getTables(): array + public function getTables(?string $schema = null): array { - return $this->cache->load(self::CACHE_VERSION . '.tables', function () { - return $this->platform->getTables(); + return $this->cache->load(self::CACHE_VERSION . '.tables.' . $schema , function () use ($schema) { + return $this->platform->getTables($schema); }); } diff --git a/src/Platforms/IPlatform.php b/src/Platforms/IPlatform.php index 22260b9e..b72d20db 100644 --- a/src/Platforms/IPlatform.php +++ b/src/Platforms/IPlatform.php @@ -27,10 +27,11 @@ public function getName(): string; /** * Returns list of tables names indexed by FQN table name. + * If no schema is provided, uses current schema name (search path). * @return Table[] * @phpstan-return array */ - public function getTables(): array; + public function getTables(?string $schema = null): array; /** diff --git a/src/Platforms/MySqlPlatform.php b/src/Platforms/MySqlPlatform.php index a301c8c0..0766a1b8 100644 --- a/src/Platforms/MySqlPlatform.php +++ b/src/Platforms/MySqlPlatform.php @@ -33,7 +33,7 @@ public function getName(): string /** @inheritDoc */ - public function getTables(): array + public function getTables(?string $schema = null): array { $result = $this->connection->query(' SELECT @@ -41,8 +41,8 @@ public function getTables(): array TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES - WHERE TABLE_SCHEMA = DATABASE() - '); + WHERE TABLE_SCHEMA = COALESCE(%?s, DATABASE()) + ', $schema); $tables = []; foreach ($result as $row) { diff --git a/src/Platforms/PostgreSqlPlatform.php b/src/Platforms/PostgreSqlPlatform.php index 4771bf34..6bc752e5 100644 --- a/src/Platforms/PostgreSqlPlatform.php +++ b/src/Platforms/PostgreSqlPlatform.php @@ -33,7 +33,7 @@ public function getName(): string /** @inheritDoc */ - public function getTables(): array + public function getTables(?string $schema = null): array { $result = $this->connection->query(" SELECT @@ -46,10 +46,12 @@ public function getTables(): array JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'v') - AND n.nspname = ANY (pg_catalog.current_schemas(FALSE)) + AND n.nspname = ANY ( + CASE %?s IS NULL WHEN true THEN pg_catalog.current_schemas(FALSE) ELSE ARRAY[[%?s]] END + ) ORDER BY c.relname - "); + ", $schema, $schema); $tables = []; foreach ($result as $row) { @@ -70,13 +72,13 @@ public function getColumns(string $table): array $result = $this->connection->query(" SELECT a.attname::varchar AS name, - upper(t.typname) AS type, + UPPER(t.typname) AS type, CASE WHEN a.atttypmod = -1 THEN NULL ELSE a.atttypmod -4 END AS size, pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass)::varchar AS default, - coalesce(co.contype = 'p', FALSE) AS is_primary, - coalesce(co.contype = 'p' AND strpos(pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1, FALSE) AS is_autoincrement, + COALESCE(co.contype = 'p', FALSE) AS is_primary, + COALESCE(co.contype = 'p' AND strpos(pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1, FALSE) AS is_autoincrement, NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS is_nullable, - substring(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) from %s) AS sequence + SUBSTRING(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) FROM %s) AS sequence FROM pg_catalog.pg_attribute AS a JOIN pg_catalog.pg_class AS c ON a.attrelid = c.oid @@ -85,7 +87,7 @@ public function getColumns(string $table): array LEFT JOIN pg_catalog.pg_constraint AS co ON co.connamespace = c.relnamespace AND contype = 'p' AND co.conrelid = c.oid AND a.attnum = ANY(co.conkey) WHERE c.relkind IN ('r', 'v') - AND c.oid = '%column'::regclass + AND c.oid = '%table'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY @@ -96,7 +98,7 @@ public function getColumns(string $table): array foreach ($result as $row) { $column = new Column(); $column->name = (string) $row->name; - $column->type = (string) $row->type; + $column->type = (string) $row->type; $column->size = $row->size !== null ? (int) $row->size : null; $column->default = $row->default !== null ? (string) $row->default : null; $column->isPrimary = (bool) $row->is_primary; @@ -128,12 +130,12 @@ public function getForeignKeys(string $table): array JOIN pg_catalog.pg_class AS clf ON co.confrelid = clf.oid JOIN pg_catalog.pg_namespace AS ns ON ns.oid = cl.relnamespace JOIN pg_catalog.pg_namespace AS nsf ON nsf.oid = clf.relnamespace - JOIN pg_catalog.pg_attribute AS at ON at.attrelid = cl.oid AND at.attnum = %raw - JOIN pg_catalog.pg_attribute AS atf ON atf.attrelid = clf.oid AND atf.attnum = %raw + JOIN pg_catalog.pg_attribute AS at ON at.attrelid = cl.oid AND at.attnum = co.conkey[[1]] + JOIN pg_catalog.pg_attribute AS atf ON atf.attrelid = clf.oid AND atf.attnum = co.confkey[[1]] WHERE co.contype = 'f' AND cl.oid = '%column'::regclass - ", 'co.conkey[1]', 'co.confkey[1]', $table); + ", $table); $keys = []; foreach ($result as $row) { diff --git a/src/Platforms/SqlServerPlatform.php b/src/Platforms/SqlServerPlatform.php index 9f9c47cb..880a8a2f 100644 --- a/src/Platforms/SqlServerPlatform.php +++ b/src/Platforms/SqlServerPlatform.php @@ -12,6 +12,8 @@ use Nextras\Dbal\Platforms\Data\Column; use Nextras\Dbal\Platforms\Data\ForeignKey; use Nextras\Dbal\Platforms\Data\Table; +use function count; +use function explode; class SqlServerPlatform implements IPlatform @@ -33,13 +35,14 @@ public function getName(): string /** @inheritDoc */ - public function getTables(): array + public function getTables(?string $schema = null): array { $result = $this->connection->query(" SELECT TABLE_NAME, TABLE_TYPE, TABLE_SCHEMA FROM information_schema.tables + WHERE TABLE_SCHEMA = COALESCE(%?s, SCHEMA_NAME()) ORDER BY TABLE_NAME - "); + ", $schema); $tables = []; foreach ($result as $row) { @@ -57,6 +60,14 @@ public function getTables(): array /** @inheritDoc */ public function getColumns(string $table): array { + $parts = explode('.', $table); + if (count($parts) === 2) { + $schema = $parts[0]; + $table = $parts[1]; + } else { + $schema = null; + } + $result = $this->connection->query(" SELECT [a].[COLUMN_NAME] AS [name], @@ -73,7 +84,7 @@ public function getColumns(string $table): array ELSE CONVERT(BIT, 0) END AS [is_primary], CONVERT( - BIT, COLUMNPROPERTY(object_id([a].[TABLE_NAME]), [a].[COLUMN_NAME], 'IsIdentity') + BIT, COLUMNPROPERTY(object_id(CONCAT([a].[TABLE_SCHEMA], '.', [a].[TABLE_NAME])), [a].[COLUMN_NAME], 'IsIdentity') ) AS [is_autoincrement], CASE WHEN [a].[IS_NULLABLE] = 'YES' @@ -93,8 +104,9 @@ public function getColumns(string $table): array [b].[COLUMN_NAME] = [a].[COLUMN_NAME] ) WHERE [a].[TABLE_NAME] = %s + AND [a].[TABLE_SCHEMA] = COALESCE(%?s, SCHEMA_NAME()) ORDER BY [a].[ORDINAL_POSITION] - ", $table); + ", $table, $schema); $columns = []; foreach ($result as $row) { @@ -119,8 +131,8 @@ public function getColumns(string $table): array /** @inheritDoc */ public function getForeignKeys(string $table): array { - $parts = \explode('.', $table); - if (\count($parts) === 2) { + $parts = explode('.', $table); + if (count($parts) === 2) { $schema = $parts[0]; $table = $parts[1]; } else { diff --git a/src/SqlProcessor.php b/src/SqlProcessor.php index aa151e80..e5cb57a5 100644 --- a/src/SqlProcessor.php +++ b/src/SqlProcessor.php @@ -105,7 +105,7 @@ public function process(array $args): string $i = $j; $fragments[] = preg_replace_callback( - '#%(\??+\w++(?:\[\]){0,2}+)|(%%)|\[(.+?)\]#S', // %modifier | %% | [identifier] + '#%(\??+\w++(?:\[\]){0,2}+)|(%%)|(\[\[)|(\]\])|\[(.+?)\]#S', // %modifier | %% | %[ | %] | [identifier] function ($matches) use ($args, &$j, $last) { if ($matches[1] !== '') { if ($j === $last) { @@ -116,11 +116,17 @@ function ($matches) use ($args, &$j, $last) { } elseif ($matches[2] !== '') { return '%'; - } elseif (!ctype_digit($matches[3])) { - return $this->identifierToSql($matches[3]); + } elseif ($matches[3] !== '') { + return '['; + + } elseif ($matches[4] !== '') { + return ']'; + + } elseif (!ctype_digit($matches[5])) { + return $this->identifierToSql($matches[5]); } else { - return "[$matches[3]]"; + return "[$matches[5]]"; } }, $args[$i] diff --git a/tests/cases/integration/platform.mysqli.phpt b/tests/cases/integration/platform.mysqli.phpt index b05993a4..fe701aaf 100644 --- a/tests/cases/integration/platform.mysqli.phpt +++ b/tests/cases/integration/platform.mysqli.phpt @@ -27,6 +27,12 @@ class PlatformMysqlTest extends IntegrationTestCase Assert::true(isset($tables["$dbName.my_books"])); Assert::same('my_books', $tables["$dbName.my_books"]->name); Assert::same(true, $tables["$dbName.my_books"]->isView); + + $dbName = $dbName . '2'; + $tables = $this->connection->getPlatform()->getTables($dbName); + Assert::true(isset($tables["$dbName.authors"])); + Assert::same('authors', $tables["$dbName.authors"]->name); + Assert::same(false, $tables["$dbName.authors"]->isView); } @@ -105,28 +111,56 @@ class PlatformMysqlTest extends IntegrationTestCase ], $columns); $dbName2 = $this->connection->getConfig()['database'] . '2'; - $this->connection->query("DROP TABLE IF EXISTS $dbName2.book_cols"); - $this->connection->query(" - CREATE TABLE $dbName2.book_cols ( - book_id int NOT NULL - ); - "); - $columns = $this->connection->getPlatform()->getColumns("$dbName2.book_cols"); - $columns = \array_map(function ($table) { return (array) $table; }, $columns); + $schemaColumns = $this->connection->getPlatform()->getColumns("$dbName2.authors"); + $schemaColumns = \array_map(function ($table) { return (array) $table; }, $schemaColumns); + Assert::same([ - 'book_id' => [ - 'name' => 'book_id', + 'id' => [ + 'name' => 'id', 'type' => 'INT', 'size' => 11, 'default' => null, + 'isPrimary' => true, + 'isAutoincrement' => true, + 'isUnsigned' => false, + 'isNullable' => false, + 'meta' => [], + ], + 'name' => [ + 'name' => 'name', + 'type' => 'VARCHAR', + 'size' => 50, + 'default' => null, 'isPrimary' => false, 'isAutoincrement' => false, 'isUnsigned' => false, 'isNullable' => false, 'meta' => [], ], - ], $columns); + 'web' => [ + 'name' => 'web', + 'type' => 'VARCHAR', + 'size' => 100, + 'default' => null, + 'isPrimary' => false, + 'isAutoincrement' => false, + 'isUnsigned' => false, + 'isNullable' => false, + 'meta' => [], + ], + 'born' => [ + 'name' => 'born', + 'type' => 'DATE', + 'size' => null, + 'default' => null, + 'isPrimary' => false, + 'isAutoincrement' => false, + 'isUnsigned' => false, + 'isNullable' => true, + 'meta' => [], + ], + ], $schemaColumns); } @@ -142,7 +176,7 @@ class PlatformMysqlTest extends IntegrationTestCase 'schema' => $dbName, 'column' => 'author_id', 'refTable' => 'authors', - 'refTableSchema' => $dbName, + 'refTableSchema' => $dbName . '2', 'refColumn' => 'id', ], 'ean_id' => [ @@ -166,7 +200,7 @@ class PlatformMysqlTest extends IntegrationTestCase 'schema' => $dbName, 'column' => 'translator_id', 'refTable' => 'authors', - 'refTableSchema' => $dbName, + 'refTableSchema' => $dbName . '2', 'refColumn' => 'id', ], ], $keys); @@ -180,8 +214,8 @@ class PlatformMysqlTest extends IntegrationTestCase ); "); - $keys = $this->connection->getPlatform()->getForeignKeys("$dbName2.book_fk"); - $keys = \array_map(function ($key) { return (array) $key; }, $keys); + $schemaKeys = $this->connection->getPlatform()->getForeignKeys("$dbName2.book_fk"); + $schemaKeys = \array_map(function ($key) { return (array) $key; }, $schemaKeys); Assert::same([ 'book_id' => [ 'name' => 'book_id', @@ -191,7 +225,7 @@ class PlatformMysqlTest extends IntegrationTestCase 'refTableSchema' => $dbName, 'refColumn' => 'id', ], - ], $keys); + ], $schemaKeys); } diff --git a/tests/cases/integration/platform.pgsql.phpt b/tests/cases/integration/platform.pgsql.phpt index e9358121..78906d5a 100644 --- a/tests/cases/integration/platform.pgsql.phpt +++ b/tests/cases/integration/platform.pgsql.phpt @@ -26,6 +26,11 @@ class PlatformPostgreTest extends IntegrationTestCase Assert::true(isset($tables["public.my_books"])); Assert::same('my_books', $tables["public.my_books"]->name); Assert::same(true, $tables["public.my_books"]->isView); + + $tables = $this->connection->getPlatform()->getTables('second_schema'); + Assert::true(isset($tables['second_schema.authors'])); + Assert::same('authors', $tables['second_schema.authors']->name); + Assert::same(false, $tables['second_schema.authors']->isView); } diff --git a/tests/cases/integration/platform.sqlsrv.phpt b/tests/cases/integration/platform.sqlsrv.phpt index c6bffd2a..387eaf13 100644 --- a/tests/cases/integration/platform.sqlsrv.phpt +++ b/tests/cases/integration/platform.sqlsrv.phpt @@ -26,6 +26,11 @@ class PlatformSqlServerTest extends IntegrationTestCase Assert::true(isset($tables["dbo.my_books"])); Assert::same('my_books', $tables["dbo.my_books"]->name); Assert::same(true, $tables["dbo.my_books"]->isView); + + $tables = $this->connection->getPlatform()->getTables('second_schema'); + Assert::true(isset($tables['second_schema.authors'])); + Assert::same('authors', $tables['second_schema.authors']->name); + Assert::same(false, $tables['second_schema.authors']->isView); } @@ -103,36 +108,36 @@ class PlatformSqlServerTest extends IntegrationTestCase ], ], $columns); - $columns = $this->connection->getPlatform()->getColumns('tag_followers'); - $columns = \array_map(function ($column) { return (array) $column; }, $columns); + $schemaColumns = $this->connection->getPlatform()->getColumns('second_schema.authors'); + $schemaColumns = \array_map(function ($column) { return (array) $column; }, $schemaColumns); Assert::same([ - 'tag_id' => [ - 'name' => 'tag_id', + 'id' => [ + 'name' => 'id', 'type' => 'INT', 'size' => 10, 'default' => null, 'isPrimary' => true, - 'isAutoincrement' => false, + 'isAutoincrement' => true, 'isUnsigned' => false, 'isNullable' => false, 'meta' => [], ], - 'author_id' => [ - 'name' => 'author_id', - 'type' => 'INT', - 'size' => 10, + 'name' => [ + 'name' => 'name', + 'type' => 'VARCHAR', + 'size' => 50, 'default' => null, - 'isPrimary' => true, + 'isPrimary' => false, 'isAutoincrement' => false, 'isUnsigned' => false, 'isNullable' => false, 'meta' => [], ], - 'created_at' => [ - 'name' => 'created_at', - 'type' => 'DATETIMEOFFSET', - 'size' => null, + 'web' => [ + 'name' => 'web', + 'type' => 'VARCHAR', + 'size' => 100, 'default' => null, 'isPrimary' => false, 'isAutoincrement' => false, @@ -140,7 +145,18 @@ class PlatformSqlServerTest extends IntegrationTestCase 'isNullable' => false, 'meta' => [], ], - ], $columns); + 'born' => [ + 'name' => 'born', + 'type' => 'DATE', + 'size' => null, + 'default' => '(NULL)', + 'isPrimary' => false, + 'isAutoincrement' => false, + 'isUnsigned' => false, + 'isNullable' => true, + 'meta' => [], + ], + ], $schemaColumns); } diff --git a/tests/cases/unit/SqlProcessorTest.identifiers.phpt b/tests/cases/unit/SqlProcessorTest.identifiers.phpt index bf2c81ff..183d9cd7 100644 --- a/tests/cases/unit/SqlProcessorTest.identifiers.phpt +++ b/tests/cases/unit/SqlProcessorTest.identifiers.phpt @@ -36,10 +36,11 @@ class SqlProcessorIdentifiersTest extends TestCase $this->driver->shouldReceive('convertIdentifierToSql')->once()->with('a')->andReturn('`a`'); $this->driver->shouldReceive('convertIdentifierToSql')->once()->with('b.c')->andReturn('`b`.`c`'); $this->driver->shouldReceive('convertIdentifierToSql')->once()->with('d.e')->andReturn('`d`.`e`'); + $this->driver->shouldReceive('convertIdentifierToSql')->once()->with('name')->andReturn('`name`'); Assert::same( - 'SELECT `a`, `b`.`c` FROM `d`.`e`', - $this->parser->process(['SELECT [a], [b.c] FROM [d.e]']) + 'SELECT `a`, `b`.`c` FROM `d`.`e` WHERE `name` = ANY(ARRAY[\'Jan\'])', + $this->parser->process(["SELECT [a], [b.c] FROM [d.e] WHERE [name] = ANY(ARRAY[['Jan']])"]) ); } } diff --git a/tests/data/mysql-data.sql b/tests/data/mysql-data.sql index 23d11fd6..197bcb45 100644 --- a/tests/data/mysql-data.sql +++ b/tests/data/mysql-data.sql @@ -2,13 +2,21 @@ SET FOREIGN_KEY_CHECKS = 0; TRUNCATE books_x_tags; TRUNCATE books; TRUNCATE tags; -TRUNCATE authors; +SET @authorsTruncate = CONCAT('TRUNCATE ', DATABASE(), '2.authors;'); +PREPARE authorsTruncateCommand FROM @authorsTruncate; +EXECUTE authorsTruncateCommand; TRUNCATE publishers; TRUNCATE tag_followers; SET FOREIGN_KEY_CHECKS = 1; -INSERT INTO authors (id, name, web, born) VALUES (1, 'Writer 1', 'http://example.com/1', NULL); -INSERT INTO authors (id, name, web, born) VALUES (2, 'Writer 2', 'http://example.com/2', NULL); +SET @authorsInsert = CONCAT( + 'INSERT INTO ', DATABASE(), '2.authors (id, name, web, born) VALUES + (1, \'Writer 1\', \'http://example.com/1\', NULL), + (2, \'Writer 2\', \'http://example.com/2\', NULL) + ;' +); +PREPARE authorsInsertCommand FROM @authorsInsert; +EXECUTE authorsInsertCommand; INSERT INTO publishers (id, name) VALUES (1, 'Nextras publisher'); diff --git a/tests/data/mysql-init.sql b/tests/data/mysql-init.sql index a3d3d943..1353c073 100644 --- a/tests/data/mysql-init.sql +++ b/tests/data/mysql-init.sql @@ -1,11 +1,16 @@ -CREATE TABLE authors ( - id int NOT NULL AUTO_INCREMENT, - name varchar(50) NOT NULL, - web varchar(100) NOT NULL, - born date DEFAULT NULL, - PRIMARY KEY(id) +SET @authorsStruct = CONCAT( + 'CREATE TABLE ', + DATABASE(), + '2.authors ( + id int NOT NULL AUTO_INCREMENT, + name varchar(50) NOT NULL, + web varchar(100) NOT NULL, + born date DEFAULT NULL, + PRIMARY KEY(id) + );' ); - +PREPARE authorsCreateCommand FROM @authorsStruct; +EXECUTE authorsCreateCommand; CREATE TABLE publishers ( id int NOT NULL AUTO_INCREMENT, @@ -27,19 +32,23 @@ CREATE TABLE eans ( PRIMARY KEY(id) ); -CREATE TABLE books ( - id int NOT NULL AUTO_INCREMENT, - author_id int NOT NULL, - translator_id int, - title varchar(50) NOT NULL, - publisher_id int NOT NULL, - ean_id int, - PRIMARY KEY (id), - CONSTRAINT books_authors FOREIGN KEY (author_id) REFERENCES authors (id), - CONSTRAINT books_translator FOREIGN KEY (translator_id) REFERENCES authors (id), - CONSTRAINT books_publisher FOREIGN KEY (publisher_id) REFERENCES publishers (id), - CONSTRAINT books_ean FOREIGN KEY (ean_id) REFERENCES eans (id) +SET @booksStruct = CONCAT( + 'CREATE TABLE books ( + id int NOT NULL AUTO_INCREMENT, + author_id int NOT NULL, + translator_id int, + title varchar(50) NOT NULL, + publisher_id int NOT NULL, + ean_id int, + PRIMARY KEY (id), + CONSTRAINT books_authors FOREIGN KEY (author_id) REFERENCES ', DATABASE(), '2.authors (id), + CONSTRAINT books_translator FOREIGN KEY (translator_id) REFERENCES ', DATABASE(), '2.authors (id), + CONSTRAINT books_publisher FOREIGN KEY (publisher_id) REFERENCES publishers (id), + CONSTRAINT books_ean FOREIGN KEY (ean_id) REFERENCES eans (id) + );' ); +PREPARE booksCreateCommand FROM @booksStruct; +EXECUTE booksCreateCommand; CREATE INDEX book_title ON books (title); @@ -53,14 +62,18 @@ CREATE TABLE books_x_tags ( CONSTRAINT books_x_tags_book FOREIGN KEY (book_id) REFERENCES books (id) ON DELETE CASCADE ); -CREATE TABLE tag_followers ( - tag_id int NOT NULL, - author_id int NOT NULL, - created_at timestamp NOT NULL, - PRIMARY KEY (tag_id, author_id), - CONSTRAINT tag_followers_tag FOREIGN KEY (tag_id) REFERENCES tags (id) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT tag_followers_author FOREIGN KEY (author_id) REFERENCES authors (id) ON DELETE CASCADE ON UPDATE CASCADE +SET @tagFollowersStruct = CONCAT( + 'CREATE TABLE tag_followers ( + tag_id int NOT NULL, + author_id int NOT NULL, + created_at timestamp NOT NULL, + PRIMARY KEY (tag_id, author_id), + CONSTRAINT tag_followers_tag FOREIGN KEY (tag_id) REFERENCES tags (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT tag_followers_author FOREIGN KEY (author_id) REFERENCES ', DATABASE(), '2.authors (id) ON DELETE CASCADE ON UPDATE CASCADE + );' ); +PREPARE tagFollowersCommand FROM @tagFollowersStruct; +EXECUTE tagFollowersCommand; CREATE TABLE table_with_defaults ( name VARCHAR(255) DEFAULT "Jon Snow" diff --git a/tests/data/mysql-reset.php b/tests/data/mysql-reset.php index ce59dacb..d2729a04 100644 --- a/tests/data/mysql-reset.php +++ b/tests/data/mysql-reset.php @@ -3,9 +3,11 @@ use Nextras\Dbal\Connection; return function (Connection $connection, $dbname) { - $connection->query('DROP DATABASE IF EXISTS %table', "{$dbname}2"); + $connection->query('SET FOREIGN_KEY_CHECKS = 0;'); $connection->query('DROP DATABASE IF EXISTS %table', $dbname); + $connection->query('DROP DATABASE IF EXISTS %table', "{$dbname}2"); $connection->query('CREATE DATABASE IF NOT EXISTS %table', $dbname); $connection->query('CREATE DATABASE IF NOT EXISTS %table', "{$dbname}2"); $connection->query('USE %table', $dbname); + $connection->query('SET FOREIGN_KEY_CHECKS = 1;'); };