From 50375f96aa8ea096ffc0c3f3a5be1f3d74b3066e Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 18:30:16 +0100 Subject: [PATCH 01/10] Drop support for PostgreSQL <9.3 --- .scrutinizer.yml | 2 +- .travis.yml | 8 -- UPGRADE.md | 13 ++ docs/en/reference/configuration.rst | 10 +- docs/en/reference/platforms.rst | 5 +- docs/en/reference/types.rst | 4 +- .../DBAL/Driver/AbstractPostgreSQLDriver.php | 6 - .../Keywords/PostgreSQL91Keywords.php | 126 ------------------ .../Keywords/PostgreSQL92Keywords.php | 29 ---- .../Keywords/PostgreSQL94Keywords.php | 2 +- .../Platforms/Keywords/PostgreSQLKeywords.php | 22 ++- .../DBAL/Platforms/PostgreSQL91Platform.php | 48 ------- .../DBAL/Platforms/PostgreSQL92Platform.php | 71 ---------- .../DBAL/Platforms/PostgreSQL94Platform.php | 2 +- .../DBAL/Platforms/PostgreSqlPlatform.php | 44 +++++- .../Console/Command/ReservedWordsCommand.php | 29 +--- .../Driver/AbstractPostgreSQLDriverTest.php | 14 +- .../Platforms/PostgreSQL91PlatformTest.php | 41 ------ .../Platforms/PostgreSQL92PlatformTest.php | 72 ---------- .../Platforms/PostgreSQL94PlatformTest.php | 2 +- .../DBAL/Platforms/PostgreSqlPlatformTest.php | 63 +++++++++ 21 files changed, 155 insertions(+), 458 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL92Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php delete mode 100644 lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 13c3a25f75a..421e69a5fb5 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,7 +21,7 @@ before_commands: tools: external_code_coverage: timeout: 3600 - runs: 28 # 23x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP + runs: 27 # 22x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP filter: excluded_paths: diff --git a/.travis.yml b/.travis.yml index 44f3daa29a9..93cb74abcdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -95,14 +95,6 @@ jobs: - stage: Test php: 7.3 env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.3 COVERAGE=yes - - stage: Test - dist: trusty - php: 7.3 - env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes - services: - - postgresql - addons: - postgresql: "9.2" - stage: Test dist: trusty php: 7.3 diff --git a/UPGRADE.md b/UPGRADE.md index cb7a7d063b0..90cb7b26dfd 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,19 @@ All implementations of the `PingableConnection` and `ServerInfoAwareConnection` All implementations of the `VersionAwarePlatformDriver` interface have to implement the methods defined in the `Driver` interface as well. +## BC BREAK: Removed support for PostgreSQL 9.2 and older + +DBAL now requires PostgeSQL 9.3 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to a newer PostgreSQL version (9.6+ is recommended). +`Doctrine\DBAL\Platforms\PostgreSqlPlatform` and `Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords` now represent PostgreSQL 9.3. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\PostgreSQL91Platform` + * `Doctrine\DBAL\Platforms\PostgreSQL92Platform` + * `Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords` + * `Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords` + ## BC BREAK: Removed Doctrine\DBAL\Version The `Doctrine\DBAL\Version` class is no longer available: please refrain from checking the DBAL version at runtime. diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 5607c4b32f0..8d845fd2504 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -250,20 +250,20 @@ pdo_pgsql - ``sslmode`` (string): Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server. See the list of available modes: - `http://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE` + `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE` - ``sslrootcert`` (string): specifies the name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities. - See http://www.postgresql.org/docs/9.0/static/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT + See https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT - ``sslcert`` (string): specifies the file name of the client SSL certificate. - See `https://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-CONNECT-SSLCERT` + See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLCERT` - ``sslkey`` (string): specifies the location for the secret key used for the client certificate. - See `https://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-CONNECT-SSLKEY` + See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLKEY` - ``sslcrl`` (string): specifies the file name of the SSL certificate revocation list (CRL). - See `https://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-CONNECT-SSLCRL` + See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLCRL` - ``application_name`` (string): Name of the application that is connecting to database. Optional. It will be displayed at ``pg_stat_activity``. diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index 2b6516e269c..07190b18d99 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -58,10 +58,9 @@ Microsoft SQL Server PostgreSQL ^^^^^^^^^^ -- ``PostgreSqlPlatform`` for version 9.0 and below (deprecated). -- ``PostgreSQL91Platform`` for version 9.1 and above (deprecated). -- ``PostgreSQL92Platform`` for version 9.2 and above (deprecated). +- ``PostgreSqlPlatform`` for version 9.3 and below. - ``PostgreSQL94Platform`` for version 9.4 and above. +- ``PostgreSQL100Platform`` for version 10.0 and above. SAP Sybase SQL Anywhere ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index f4916a69672..63e6035ae65 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -781,9 +781,7 @@ Please also notice the mapping specific footnotes for additional information. | | | | +----------------------------------------------------------+ | | | | | ``LONGTEXT`` [20]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | < 9.2 | ``TEXT`` [1]_ | -| | | +---------+----------------------------------------------------------+ -| | | | < 9.4 | ``JSON`` | +| | | **PostgreSQL** | < 9.4 | ``JSON`` | | | | +---------+----------------------------------------------------------+ | | | | >= 9.4 | ``JSON`` [21]_ | | | | | +----------------------------------------------------------+ diff --git a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php index 25b6d8e528e..9b74ae98663 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -6,8 +6,6 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; -use Doctrine\DBAL\Platforms\PostgreSQL91Platform; -use Doctrine\DBAL\Platforms\PostgreSQL92Platform; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\PostgreSqlSchemaManager; @@ -100,10 +98,6 @@ public function createDatabasePlatformForVersion($version) return new PostgreSQL100Platform(); case version_compare($version, '9.4', '>='): return new PostgreSQL94Platform(); - case version_compare($version, '9.2', '>='): - return new PostgreSQL92Platform(); - case version_compare($version, '9.1', '>='): - return new PostgreSQL91Platform(); default: return new PostgreSqlPlatform(); } diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php deleted file mode 100644 index 75a93f5f197..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php +++ /dev/null @@ -1,126 +0,0 @@ -quoteSingleIdentifier($collation); - } - - /** - * {@inheritDoc} - */ - public function getListTableColumnsSQL($table, $database = null) - { - $sql = parent::getListTableColumnsSQL($table, $database); - $parts = explode('AS complete_type,', $sql, 2); - - return $parts[0] . 'AS complete_type, (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,' . $parts[1]; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php deleted file mode 100644 index c0b5675a383..00000000000 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php +++ /dev/null @@ -1,71 +0,0 @@ -doctrineTypeMapping['json'] = Types::JSON; - } - - /** - * {@inheritdoc} - */ - public function getCloseActiveDatabaseConnectionsSQL($database) - { - return sprintf( - 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = %s', - $this->quoteStringLiteral($database) - ); - } -} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php index fb559dea2ac..ae90e8ff4d4 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php @@ -7,7 +7,7 @@ /** * Provides the behavior, features and SQL dialect of the PostgreSQL 9.4 database platform. */ -class PostgreSQL94Platform extends PostgreSQL92Platform +class PostgreSQL94Platform extends PostgreSqlPlatform { /** * {@inheritdoc} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index b5cd8f8c769..ad50c3f754c 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -33,9 +33,7 @@ use function trim; /** - * PostgreSqlPlatform. - * - * @deprecated Use PostgreSQL 9.4 or newer + * Provides the behavior, features and SQL dialect of the PostgreSQL 9.4+ database platform. * * @todo Rename: PostgreSQLPlatform */ @@ -394,6 +392,7 @@ public function getListTableColumnsSQL($table, $database = null) quote_ident(a.attname) AS field, t.typname AS type, format_type(a.atttypid, a.atttypmod) AS complete_type, + (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation, (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type, @@ -454,7 +453,7 @@ public function getDisallowDatabaseConnectionsSQL($database) */ public function getCloseActiveDatabaseConnectionsSQL($database) { - return 'SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = ' + return 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = ' . $this->quoteStringLiteral($database); } @@ -975,6 +974,10 @@ public function getBigIntTypeDeclarationSQL(array $field) */ public function getSmallIntTypeDeclarationSQL(array $field) { + if (! empty($field['autoincrement'])) { + return 'SMALLSERIAL'; + } + return 'SMALLINT'; } @@ -1163,6 +1166,7 @@ protected function initializeDoctrineTypeMappings() 'year' => 'date', 'uuid' => 'guid', 'bytea' => 'blob', + 'json' => Type::JSON, ]; } @@ -1190,6 +1194,14 @@ public function getBinaryDefaultLength() return 0; } + /** + * {@inheritdoc} + */ + public function hasNativeJsonType() + { + return true; + } + /** * {@inheritDoc} */ @@ -1218,6 +1230,30 @@ public function getDefaultValueDeclarationSQL($field) return parent::getDefaultValueDeclarationSQL($field); } + /** + * {@inheritdoc} + */ + public function supportsColumnCollation() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getColumnCollationDeclarationSQL($collation) + { + return 'COLLATE ' . $this->quoteSingleIdentifier($collation); + } + + /** + * {@inheritdoc} + */ + public function getJsonTypeDeclarationSQL(array $field) + { + return 'JSON'; + } + /** * @param mixed[] $field */ diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 2e0c48a815b..0e5a74fea20 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -8,8 +8,8 @@ use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords; use Doctrine\DBAL\Platforms\Keywords\OracleKeywords; -use Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords; -use Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords; +use Doctrine\DBAL\Platforms\Keywords\PostgreSQL100Keywords; +use Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords; use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords; use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator; use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords; @@ -43,8 +43,8 @@ class ReservedWordsCommand extends Command 'sqlserver2012' => SQLServer2012Keywords::class, 'sqlite' => SQLiteKeywords::class, 'pgsql' => PostgreSQLKeywords::class, - 'pgsql91' => PostgreSQL91Keywords::class, - 'pgsql92' => PostgreSQL92Keywords::class, + 'pgsql94' => PostgreSQL94Keywords::class, + 'pgsql100' => PostgreSQL100Keywords::class, 'oracle' => OracleKeywords::class, 'db2' => DB2Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, @@ -101,7 +101,8 @@ protected function configure() * mysql57 * mysql80 * pgsql - * pgsql92 + * pgsql94 + * pgsql100 * sqlite * oracle * sqlserver @@ -127,23 +128,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $keywordLists = (array) $input->getOption('list'); if (! $keywordLists) { - $keywordLists = [ - 'mysql', - 'mysql57', - 'mysql80', - 'pgsql', - 'pgsql92', - 'sqlite', - 'oracle', - 'sqlserver', - 'sqlserver2005', - 'sqlserver2008', - 'sqlserver2012', - 'sqlanywhere', - 'sqlanywhere11', - 'sqlanywhere12', - 'sqlanywhere16', - ]; + $keywordLists = array_keys($this->keywordListClasses); } $keywords = []; diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php index 2ba6a732bd4..9f1daca35cd 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php @@ -8,8 +8,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; -use Doctrine\DBAL\Platforms\PostgreSQL91Platform; -use Doctrine\DBAL\Platforms\PostgreSQL92Platform; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; @@ -67,15 +65,9 @@ protected function createSchemaManager(Connection $connection) : AbstractSchemaM protected function getDatabasePlatformsForVersions() : array { return [ - ['9.0.9', PostgreSqlPlatform::class], - ['9.1', PostgreSQL91Platform::class], - ['9.1.0', PostgreSQL91Platform::class], - ['9.1.1', PostgreSQL91Platform::class], - ['9.1.9', PostgreSQL91Platform::class], - ['9.2', PostgreSQL92Platform::class], - ['9.2.0', PostgreSQL92Platform::class], - ['9.2.1', PostgreSQL92Platform::class], - ['9.3.6', PostgreSQL92Platform::class], + ['9.3', PostgreSqlPlatform::class], + ['9.3.0', PostgreSqlPlatform::class], + ['9.3.6', PostgreSqlPlatform::class], ['9.4', PostgreSQL94Platform::class], ['9.4.0', PostgreSQL94Platform::class], ['9.4.1', PostgreSQL94Platform::class], diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php deleted file mode 100644 index 3ed82529e08..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php +++ /dev/null @@ -1,41 +0,0 @@ -platform->supportsColumnCollation()); - } - - public function testColumnCollationDeclarationSQL() : void - { - self::assertSame( - 'COLLATE "en_US.UTF-8"', - $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') - ); - } - - public function testGetCreateTableSQLWithColumnCollation() : void - { - $table = new Table('foo'); - $table->addColumn('no_collation', 'string'); - $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'en_US.UTF-8'); - - self::assertSame( - ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE "en_US.UTF-8")'], - $this->platform->getCreateTableSQL($table), - 'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column' - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php deleted file mode 100644 index 7fbedd494be..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php +++ /dev/null @@ -1,72 +0,0 @@ -platform->hasNativeJsonType()); - } - - /** - * @group DBAL-553 - */ - public function testReturnsJsonTypeDeclarationSQL() : void - { - self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); - } - - public function testReturnsSmallIntTypeDeclarationSQL() : void - { - self::assertSame( - 'SMALLSERIAL', - $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) - ); - - self::assertSame( - 'SMALLINT', - $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => false]) - ); - - self::assertSame( - 'SMALLINT', - $this->platform->getSmallIntTypeDeclarationSQL([]) - ); - } - - /** - * @group DBAL-553 - */ - public function testInitializesJsonTypeMapping() : void - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); - self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); - } - - /** - * @group DBAL-1220 - */ - public function testReturnsCloseActiveDatabaseConnectionsSQL() : void - { - self::assertSame( - "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", - $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php index 179e005b2f9..3439bb95868 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php @@ -6,7 +6,7 @@ use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Types\Types; -class PostgreSQL94PlatformTest extends PostgreSQL92PlatformTest +class PostgreSQL94PlatformTest extends PostgreSqlPlatformTest { /** * {@inheritdoc} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php index 0b029d3497d..4a71b80026b 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -5,6 +5,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; class PostgreSqlPlatformTest extends AbstractPostgreSqlPlatformTestCase { @@ -32,4 +33,66 @@ public function testGetCreateTableSQLWithColumnCollation() : void 'Comments are added to table.' ); } + + public function testColumnCollationDeclarationSQL() : void + { + self::assertEquals( + 'COLLATE "en_US.UTF-8"', + $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') + ); + } + + /** + * @group DBAL-553 + */ + public function testHasNativeJsonType() : void + { + self::assertTrue($this->platform->hasNativeJsonType()); + } + + /** + * @group DBAL-553 + */ + public function testReturnsJsonTypeDeclarationSQL() : void + { + self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); + } + + public function testReturnsSmallIntTypeDeclarationSQL() : void + { + self::assertSame( + 'SMALLSERIAL', + $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) + ); + + self::assertSame( + 'SMALLINT', + $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => false]) + ); + + self::assertSame( + 'SMALLINT', + $this->platform->getSmallIntTypeDeclarationSQL([]) + ); + } + + /** + * @group DBAL-553 + */ + public function testInitializesJsonTypeMapping() : void + { + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); + self::assertEquals(Type::JSON, $this->platform->getDoctrineTypeMapping('json')); + } + + /** + * @group DBAL-1220 + */ + public function testReturnsCloseActiveDatabaseConnectionsSQL() : void + { + self::assertSame( + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", + $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') + ); + } } From db642e607cdf7a31181cb4e859435e1610809e0b Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 18:50:24 +0100 Subject: [PATCH 02/10] Drop support for SQL Server <2008 --- UPGRADE.md | 13 +++++ docs/en/reference/platforms.rst | 4 +- docs/en/reference/types.rst | 12 ++--- .../DBAL/Driver/AbstractSQLServerDriver.php | 8 +--- .../Keywords/SQLServer2012Keywords.php | 2 +- .../Platforms/Keywords/SQLServerKeywords.php | 1 + .../DBAL/Platforms/SQLServer2005Platform.php | 48 ------------------- .../DBAL/Platforms/SQLServer2008Platform.php | 2 +- .../DBAL/Platforms/SQLServer2012Platform.php | 2 +- .../DBAL/Platforms/SQLServerPlatform.php | 42 +++++++++++----- .../Console/Command/ReservedWordsCommand.php | 6 --- .../Driver/AbstractSQLServerDriverTest.php | 38 ++++++--------- .../DBAL/Platforms/SQLServerPlatformTest.php | 5 ++ 13 files changed, 72 insertions(+), 111 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php diff --git a/UPGRADE.md b/UPGRADE.md index 90cb7b26dfd..74779e55877 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,19 @@ All implementations of the `PingableConnection` and `ServerInfoAwareConnection` All implementations of the `VersionAwarePlatformDriver` interface have to implement the methods defined in the `Driver` interface as well. +## BC BREAK: Removed support for SQL Server 2005 and older + +DBAL now requires SQL Server 2008 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to newer SQL Server version (2012+ is recommended). +`Doctrine\DBAL\Platforms\SQLServerPlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords` now represent the SQL Server 2008. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\SQLServer2005Platform` + * `Doctrine\DBAL\Platforms\SQLServer2008Platform` + * `Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords` + ## BC BREAK: Removed support for PostgreSQL 9.2 and older DBAL now requires PostgeSQL 9.3 or newer, support for unmaintained versions has been dropped. diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index 07190b18d99..c5f1c409447 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -50,9 +50,7 @@ Oracle Microsoft SQL Server ^^^^^^^^^^^^^^^^^^^^ -- ``SQLServerPlatform`` for version 2000 and above (deprecated). -- ``SQLServer2005Platform`` for version 2005 and above (deprecated). -- ``SQLServer2008Platform`` for version 2008 and above (deprecated). +- ``SQLServerPlatform`` for version 2008 and above. - ``SQLServer2012Platform`` for version 2012 and above. PostgreSQL diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index 63e6035ae65..9703a2aa651 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -701,9 +701,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **Drizzle** | | | | | +--------------------------+---------+ | -| | | **SQL Server** | >= 2008 | | -| | | +---------+----------------------------------------------------------+ -| | | | < 2008 | ``DATETIME`` [16]_ | +| | | **SQL Server** | "all" | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | | | +--------------------------+ +----------------------------------------------------------+ @@ -725,9 +723,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+ | -| | | **SQL Server** | < 2008 | | -| | | +---------+----------------------------------------------------------+ -| | | | >= 2008 | ``DATETIMEOFFSET(6)`` | +| | | **SQL Server** | "all" | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITH TIME ZONE`` | | | +--------------------------+ | | @@ -749,9 +745,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``DATE`` [16]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | < 2008 | ``DATETIME`` [16]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 2008 | ``TIME(0)`` | +| | | **SQL Server** | "all" | ``TIME(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +-------------------+ | | +----------------------------------------------------------+ diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php index fb915aaf71f..1a86508549a 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php @@ -4,8 +4,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; -use Doctrine\DBAL\Platforms\SQLServer2005Platform; -use Doctrine\DBAL\Platforms\SQLServer2008Platform; use Doctrine\DBAL\Platforms\SQLServer2012Platform; use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\SQLServerSchemaManager; @@ -43,10 +41,6 @@ public function createDatabasePlatformForVersion($version) switch (true) { case version_compare($version, '11.00.2100', '>='): return new SQLServer2012Platform(); - case version_compare($version, '10.00.1600', '>='): - return new SQLServer2008Platform(); - case version_compare($version, '9.00.1399', '>='): - return new SQLServer2005Platform(); default: return new SQLServerPlatform(); } @@ -67,7 +61,7 @@ public function getDatabase(Connection $conn) */ public function getDatabasePlatform() { - return new SQLServer2008Platform(); + return new SQLServerPlatform(); } /** diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php index 142e8a388d0..d29225270aa 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php @@ -9,7 +9,7 @@ * * @link www.doctrine-project.com */ -class SQLServer2012Keywords extends SQLServer2008Keywords +class SQLServer2012Keywords extends SQLServerKeywords { /** * {@inheritdoc} diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywords.php index 1e477309c16..e43bde2fe5c 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywords.php @@ -121,6 +121,7 @@ protected function getKeywords() 'LIKE', 'LINENO', 'LOAD', + 'MERGE', 'NATIONAL', 'NOCHECK ', 'NONCLUSTERED', diff --git a/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php b/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php deleted file mode 100644 index 5cd3475c1e2..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php +++ /dev/null @@ -1,48 +0,0 @@ -getDateTimeFormatString(); + return 'Y-m-d H:i:s.u P'; } /** @@ -1506,6 +1514,10 @@ protected function initializeDoctrineTypeMappings() 'varbinary' => 'binary', 'image' => 'blob', 'uniqueidentifier' => 'guid', + 'datetime2' => 'datetime', + 'date' => 'date', + 'time' => 'time', + 'datetimeoffset' => 'datetimetz', ]; } @@ -1636,6 +1648,14 @@ public function getColumnDeclarationSQL($name, array $field) return $name . ' ' . $columnDef; } + /** + * {@inheritdoc} + */ + protected function getLikeWildcardCharacters() : string + { + return parent::getLikeWildcardCharacters() . '[]^'; + } + /** * Returns a unique default constraint name for a table and column. * diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 0e5a74fea20..32df5609eb3 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -17,8 +17,6 @@ use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords; use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords; use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords; -use Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords; -use Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords; use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords; use Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords; use InvalidArgumentException; @@ -38,8 +36,6 @@ class ReservedWordsCommand extends Command 'mysql57' => MySQL57Keywords::class, 'mysql80' => MySQL80Keywords::class, 'sqlserver' => SQLServerKeywords::class, - 'sqlserver2005' => SQLServer2005Keywords::class, - 'sqlserver2008' => SQLServer2008Keywords::class, 'sqlserver2012' => SQLServer2012Keywords::class, 'sqlite' => SQLiteKeywords::class, 'pgsql' => PostgreSQLKeywords::class, @@ -106,8 +102,6 @@ protected function configure() * sqlite * oracle * sqlserver - * sqlserver2005 - * sqlserver2008 * sqlserver2012 * sqlanywhere * sqlanywhere11 diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php index 0d34df8e81b..330b4b5e4d8 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php @@ -6,8 +6,6 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\AbstractSQLServerDriver; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SQLServer2005Platform; -use Doctrine\DBAL\Platforms\SQLServer2008Platform; use Doctrine\DBAL\Platforms\SQLServer2012Platform; use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; @@ -22,7 +20,7 @@ protected function createDriver() : Driver protected function createPlatform() : AbstractPlatform { - return new SQLServer2008Platform(); + return new SQLServerPlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager @@ -36,27 +34,19 @@ protected function createSchemaManager(Connection $connection) : AbstractSchemaM protected function getDatabasePlatformsForVersions() : array { return [ - ['9', SQLServerPlatform::class], - ['9.00', SQLServerPlatform::class], - ['9.00.0', SQLServerPlatform::class], - ['9.00.1398', SQLServerPlatform::class], - ['9.00.1398.99', SQLServerPlatform::class], - ['9.00.1399', SQLServer2005Platform::class], - ['9.00.1399.0', SQLServer2005Platform::class], - ['9.00.1399.99', SQLServer2005Platform::class], - ['9.00.1400', SQLServer2005Platform::class], - ['9.10', SQLServer2005Platform::class], - ['9.10.9999', SQLServer2005Platform::class], - ['10.00.1599', SQLServer2005Platform::class], - ['10.00.1599.99', SQLServer2005Platform::class], - ['10.00.1600', SQLServer2008Platform::class], - ['10.00.1600.0', SQLServer2008Platform::class], - ['10.00.1600.99', SQLServer2008Platform::class], - ['10.00.1601', SQLServer2008Platform::class], - ['10.10', SQLServer2008Platform::class], - ['10.10.9999', SQLServer2008Platform::class], - ['11.00.2099', SQLServer2008Platform::class], - ['11.00.2099.99', SQLServer2008Platform::class], + ['10', SQLServerPlatform::class], + ['10.00', SQLServerPlatform::class], + ['10.00.0', SQLServerPlatform::class], + ['10.00.1599', SQLServerPlatform::class], + ['10.00.1599.99', SQLServerPlatform::class], + ['10.00.1600', SQLServerPlatform::class], + ['10.00.1600.0', SQLServerPlatform::class], + ['10.00.1600.99', SQLServerPlatform::class], + ['10.00.1601', SQLServerPlatform::class], + ['10.10', SQLServerPlatform::class], + ['10.10.9999', SQLServerPlatform::class], + ['11.00.2099', SQLServerPlatform::class], + ['11.00.2099.99', SQLServerPlatform::class], ['11.00.2100', SQLServer2012Platform::class], ['11.00.2100.0', SQLServer2012Platform::class], ['11.00.2100.99', SQLServer2012Platform::class], diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php index 77cf7b17b41..a5d27823b38 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php @@ -75,4 +75,9 @@ public static function getModifyLimitQueries() : iterable ], ]; } + + public function testGeneratesTypeDeclarationForDateTimeTz() : void + { + self::assertEquals('DATETIMEOFFSET(6)', $this->platform->getDateTimeTzTypeDeclarationSQL([])); + } } From fc6091c363756063210b13e8bc0c6d1885c0e25a Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 20:06:21 +0100 Subject: [PATCH 03/10] Drop support for SQL Anywhere <16 --- UPGRADE.md | 15 ++ docs/en/reference/configuration.rst | 11 +- docs/en/reference/platforms.rst | 5 +- docs/en/reference/types.rst | 4 +- .../DBAL/Driver/AbstractSQLAnywhereDriver.php | 12 +- .../Keywords/SQLAnywhereKeywords.php | 19 +- .../DBAL/Platforms/SQLAnywhere11Platform.php | 28 --- .../DBAL/Platforms/SQLAnywhere12Platform.php | 116 ------------ .../DBAL/Platforms/SQLAnywhere16Platform.php | 39 ---- .../DBAL/Platforms/SQLAnywherePlatform.php | 95 +++++++++- .../Console/Command/ReservedWordsCommand.php | 9 - .../Driver/AbstractSQLAnywhereDriverTest.php | 41 +---- .../Platforms/SQLAnywhere11PlatformTest.php | 27 --- .../Platforms/SQLAnywhere12PlatformTest.php | 142 --------------- .../Platforms/SQLAnywhere16PlatformTest.php | 80 --------- .../Platforms/SQLAnywherePlatformTest.php | 169 ++++++++++++++++-- 16 files changed, 291 insertions(+), 521 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLAnywhere12Platform.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php diff --git a/UPGRADE.md b/UPGRADE.md index 74779e55877..5852ef815cb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,21 @@ All implementations of the `PingableConnection` and `ServerInfoAwareConnection` All implementations of the `VersionAwarePlatformDriver` interface have to implement the methods defined in the `Driver` interface as well. +## BC BREAK: Removed support for SQL Anywhere 12 and older + +DBAL now requires SQL Anywhere 16 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to a newer SQL Anywhere version (16+). +`Doctrine\DBAL\Platforms\SQLAnywherePlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords` now represent SQL Anywhere 16. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\SQLAnywhere11Platform` + * `Doctrine\DBAL\Platforms\SQLAnywhere12Platform` + * `Doctrine\DBAL\Platforms\SQLAnywhere16Platform` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords` + ## BC BREAK: Removed support for SQL Server 2005 and older DBAL now requires SQL Server 2008 or newer, support for unmaintained versions has been dropped. diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 8d845fd2504..cf7c42d943b 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -331,14 +331,9 @@ sqlanywhere Depending on the used underlying platform version, you can specify any other connection parameter that is supported by the particular platform version via the ``driverOptions`` option. -You can find a list of supported connection parameters for each -platform version here: - -- `SQL Anywhere 10.0.1 `_ -- `SQL Anywhere 11.0.0 `_ -- `SQL Anywhere 11.0.1 `_ -- `SQL Anywhere 12.0.0 `_ -- `SQL Anywhere 12.0.1 `_ +You can find a list of supported connection parameters for the +currently supported platform here: + - `SAP Sybase SQL Anywhere 16.0 `_ Automatic platform version detection diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index c5f1c409447..0d5ff83c4ce 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -63,10 +63,7 @@ PostgreSQL SAP Sybase SQL Anywhere ^^^^^^^^^^^^^^^^^^^^^^^ -- ``SQLAnywherePlatform`` for version 10 and above (deprecated). -- ``SQLAnywhere11Platform`` for version 11 and above (deprecated). -- ``SQLAnywhere12Platform`` for version 12 and above (deprecated). -- ``SQLAnywhere16Platform`` for version 16 and above. +- ``SQLAnywherePlatform`` for version 16 and above. SQLite ^^^^^^ diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index 9703a2aa651..4f6398525e4 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -729,9 +729,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **Oracle** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Anywhere** | < 12 | ``DATETIME`` [15]_ [16]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 12 | ``TIMESTAMP WITH TIME ZONE`` | +| | | **SQL Anywhere** | "all" | ``TIMESTAMP WITH TIME ZONE`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **time** | ``\DateTime`` | **MySQL** | *all* | ``TIME`` | | | +--------------------------+ | | diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php index 337fcdde5dd..fdf4432c773 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php @@ -5,14 +5,10 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Exception; -use Doctrine\DBAL\Platforms\SQLAnywhere11Platform; -use Doctrine\DBAL\Platforms\SQLAnywhere12Platform; -use Doctrine\DBAL\Platforms\SQLAnywhere16Platform; use Doctrine\DBAL\Platforms\SQLAnywherePlatform; use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager; use Doctrine\DBAL\VersionAwarePlatformDriver; use function preg_match; -use function version_compare; /** * Abstract base implementation of the {@link Doctrine\DBAL\Driver} interface for SAP Sybase SQL Anywhere based drivers. @@ -87,12 +83,6 @@ public function createDatabasePlatformForVersion($version) $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; switch (true) { - case version_compare($version, '16', '>='): - return new SQLAnywhere16Platform(); - case version_compare($version, '12', '>='): - return new SQLAnywhere12Platform(); - case version_compare($version, '11', '>='): - return new SQLAnywhere11Platform(); default: return new SQLAnywherePlatform(); } @@ -113,7 +103,7 @@ public function getDatabase(Connection $conn) */ public function getDatabasePlatform() { - return new SQLAnywhere12Platform(); + return new SQLAnywherePlatform(); } /** diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhereKeywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhereKeywords.php index 5223d4a9e43..dc60610738b 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhereKeywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhereKeywords.php @@ -28,6 +28,7 @@ protected function getKeywords() 'ALTER', 'AND', 'ANY', + 'ARRAY', 'AS', 'ASC', 'ATTACH', @@ -68,6 +69,7 @@ protected function getKeywords() 'CURRENT_USER', 'CURSOR', 'DATE', + 'DATETIMEOFFSET', 'DBSPACE', 'DEALLOCATE', 'DEC', @@ -114,7 +116,6 @@ protected function getKeywords() 'IF', 'IN', 'INDEX', - 'INDEX_LPAREN', 'INNER', 'INOUT', 'INSENSITIVE', @@ -127,20 +128,22 @@ protected function getKeywords() 'INTEGRATED', 'INTERSECT', 'INTO', - 'IQ', 'IS', 'ISOLATION', 'JOIN', + 'JSON', 'KERBEROS', 'KEY', 'LATERAL', 'LEFT', 'LIKE', + 'LIMIT', 'LOCK', 'LOGIN', 'LONG', 'MATCH', 'MEMBERSHIP', + 'MERGE', 'MESSAGE', 'MODE', 'MODIFY', @@ -158,6 +161,8 @@ protected function getKeywords() 'OFF', 'ON', 'OPEN', + 'OPENSTRING', + 'OPENXML', 'OPTION', 'OPTIONS', 'OR', @@ -194,6 +199,8 @@ protected function getKeywords() 'RIGHT', 'ROLLBACK', 'ROLLUP', + 'ROW', + 'ROWTYPE', 'SAVE', 'SAVEPOINT', 'SCROLL', @@ -205,6 +212,7 @@ protected function getKeywords() 'SHARE', 'SMALLINT', 'SOME', + 'SPATIAL', 'SQLCODE', 'SQLSTATE', 'START', @@ -212,7 +220,6 @@ protected function getKeywords() 'SUBTRANS', 'SUBTRANSACTION', 'SYNCHRONIZE', - 'SYNTAX_ERROR', 'TABLE', 'TEMPORARY', 'THEN', @@ -222,6 +229,7 @@ protected function getKeywords() 'TO', 'TOP', 'TRAN', + 'TREAT', 'TRIGGER', 'TRUNCATE', 'TSEQUAL', @@ -230,6 +238,7 @@ protected function getKeywords() 'UNIQUE', 'UNIQUEIDENTIFIER', 'UNKNOWN', + 'UNNEST', 'UNSIGNED', 'UPDATE', 'UPDATING', @@ -241,6 +250,7 @@ protected function getKeywords() 'VARBIT', 'VARCHAR', 'VARIABLE', + 'VARRAY', 'VARYING', 'VIEW', 'WAIT', @@ -250,9 +260,6 @@ protected function getKeywords() 'WHILE', 'WINDOW', 'WITH', - 'WITH_CUBE', - 'WITH_LPAREN', - 'WITH_ROLLUP', 'WITHIN', 'WORK', 'WRITETEXT', diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php deleted file mode 100644 index 71922b22769..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php +++ /dev/null @@ -1,28 +0,0 @@ -getQuotedName($this) . - ' INCREMENT BY ' . $sequence->getAllocationSize() . - ' START WITH ' . $sequence->getInitialValue() . - ' MINVALUE ' . $sequence->getInitialValue(); - } - - /** - * {@inheritdoc} - */ - public function getAlterSequenceSQL(Sequence $sequence) - { - return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . - ' INCREMENT BY ' . $sequence->getAllocationSize(); - } - - /** - * {@inheritdoc} - */ - public function getDateTimeTzFormatString() - { - return 'Y-m-d H:i:s.uP'; - } - - /** - * {@inheritdoc} - */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) - { - return 'TIMESTAMP WITH TIME ZONE'; - } - - /** - * {@inheritdoc} - */ - public function getDropSequenceSQL($sequence) - { - if ($sequence instanceof Sequence) { - $sequence = $sequence->getQuotedName($this); - } - - return 'DROP SEQUENCE ' . $sequence; - } - - /** - * {@inheritdoc} - */ - public function getListSequencesSQL($database) - { - return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; - } - - /** - * {@inheritdoc} - */ - public function getSequenceNextValSQL($sequenceName) - { - return 'SELECT ' . $sequenceName . '.NEXTVAL'; - } - - /** - * {@inheritdoc} - */ - public function supportsSequences() - { - return true; - } - - /** - * {@inheritdoc} - */ - protected function getAdvancedIndexOptionsSQL(Index $index) - { - if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { - return ' WITH NULLS NOT DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); - } - - return parent::getAdvancedIndexOptionsSQL($index); - } - - /** - * {@inheritdoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLAnywhere12Keywords::class; - } - - /** - * {@inheritDoc} - */ - protected function initializeDoctrineTypeMappings() - { - parent::initializeDoctrineTypeMappings(); - $this->doctrineTypeMapping['timestamp with time zone'] = 'datetime'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php deleted file mode 100644 index 35d4238e4a3..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php +++ /dev/null @@ -1,39 +0,0 @@ -hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { - throw new UnexpectedValueException( - 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' - ); - } - - if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { - return ' WITH NULLS DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); - } - - return parent::getAdvancedIndexOptionsSQL($index); - } - - /** - * {@inheritdoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLAnywhere16Keywords::class; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 3f23733fd1f..503fde23d56 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -10,10 +10,12 @@ use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Identifier; use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; use InvalidArgumentException; +use UnexpectedValueException; use function array_merge; use function array_unique; use function array_values; @@ -32,9 +34,7 @@ /** * The SQLAnywherePlatform provides the behavior, features and SQL dialect of the - * SAP Sybase SQL Anywhere 10 database platform. - * - * @deprecated Use SQLAnywhere 16 or newer + * SAP Sybase SQL Anywhere 16 database platform. */ class SQLAnywherePlatform extends AbstractPlatform { @@ -509,7 +509,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) */ public function getDateTimeTzFormatString() { - return $this->getDateTimeFormatString(); + return 'Y-m-d H:i:s.uP'; } /** @@ -1000,6 +1000,14 @@ public function getMd5Expression($column) return 'HASH(' . $column . ", 'MD5')"; } + /** + * {@inheritdoc} + */ + public function getRegexpExpression() + { + return 'REGEXP'; + } + /** * {@inheritdoc} */ @@ -1183,6 +1191,70 @@ public function getUniqueConstraintDeclarationSQL($name, Index $index) return $this->getTableConstraintDeclarationSQL($index, $name); } + /** + * {@inheritdoc} + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue(); + } + + /** + * {@inheritdoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritdoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritdoc} + */ + public function getListSequencesSQL($database) + { + return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; + } + + /** + * {@inheritdoc} + */ + public function getSequenceNextValSQL($sequenceName) + { + return 'SELECT ' . $sequenceName . '.NEXTVAL'; + } + + /** + * {@inheritdoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIMESTAMP WITH TIME ZONE'; + } + /** * {@inheritdoc} */ @@ -1347,12 +1419,26 @@ private function getTopClauseSQL(?int $limit, ?int $offset) : string */ protected function getAdvancedIndexOptionsSQL(Index $index) { + if ($index->hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { + throw new UnexpectedValueException( + 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' + ); + } + $sql = ''; if (! $index->isPrimary() && $index->hasFlag('for_olap_workload')) { $sql .= ' FOR OLAP WORKLOAD'; } + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { + return ' WITH NULLS NOT DISTINCT' . $sql; + } + + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { + return ' WITH NULLS DISTINCT' . $sql; + } + return $sql; } @@ -1504,6 +1590,7 @@ protected function initializeDoctrineTypeMappings() 'smalldatetime' => 'datetime', 'time' => 'time', 'timestamp' => 'datetime', + 'timestamp with time zone' => 'datetime', 'binary' => 'binary', 'image' => 'blob', 'long binary' => 'blob', diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 32df5609eb3..32f29b29619 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -12,9 +12,6 @@ use Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords; use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords; use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator; -use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords; -use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords; -use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords; use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords; use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords; use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords; @@ -44,9 +41,6 @@ class ReservedWordsCommand extends Command 'oracle' => OracleKeywords::class, 'db2' => DB2Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, - 'sqlanywhere11' => SQLAnywhere11Keywords::class, - 'sqlanywhere12' => SQLAnywhere12Keywords::class, - 'sqlanywhere16' => SQLAnywhere16Keywords::class, ]; /** @@ -104,9 +98,6 @@ protected function configure() * sqlserver * sqlserver2012 * sqlanywhere - * sqlanywhere11 - * sqlanywhere12 - * sqlanywhere16 * db2 (Not checked by default) EOT ); diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php index 4c51e7cb35f..e025ef82cd1 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php @@ -6,9 +6,6 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SQLAnywhere11Platform; -use Doctrine\DBAL\Platforms\SQLAnywhere12Platform; -use Doctrine\DBAL\Platforms\SQLAnywhere16Platform; use Doctrine\DBAL\Platforms\SQLAnywherePlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager; @@ -22,7 +19,7 @@ protected function createDriver() : Driver protected function createPlatform() : AbstractPlatform { - return new SQLAnywhere12Platform(); + return new SQLAnywherePlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager @@ -36,35 +33,13 @@ protected function createSchemaManager(Connection $connection) : AbstractSchemaM protected function getDatabasePlatformsForVersions() : array { return [ - ['10', SQLAnywherePlatform::class], - ['10.0', SQLAnywherePlatform::class], - ['10.0.0', SQLAnywherePlatform::class], - ['10.0.0.0', SQLAnywherePlatform::class], - ['10.1.2.3', SQLAnywherePlatform::class], - ['10.9.9.9', SQLAnywherePlatform::class], - ['11', SQLAnywhere11Platform::class], - ['11.0', SQLAnywhere11Platform::class], - ['11.0.0', SQLAnywhere11Platform::class], - ['11.0.0.0', SQLAnywhere11Platform::class], - ['11.1.2.3', SQLAnywhere11Platform::class], - ['11.9.9.9', SQLAnywhere11Platform::class], - ['12', SQLAnywhere12Platform::class], - ['12.0', SQLAnywhere12Platform::class], - ['12.0.0', SQLAnywhere12Platform::class], - ['12.0.0.0', SQLAnywhere12Platform::class], - ['12.1.2.3', SQLAnywhere12Platform::class], - ['12.9.9.9', SQLAnywhere12Platform::class], - ['13', SQLAnywhere12Platform::class], - ['14', SQLAnywhere12Platform::class], - ['15', SQLAnywhere12Platform::class], - ['15.9.9.9', SQLAnywhere12Platform::class], - ['16', SQLAnywhere16Platform::class], - ['16.0', SQLAnywhere16Platform::class], - ['16.0.0', SQLAnywhere16Platform::class], - ['16.0.0.0', SQLAnywhere16Platform::class], - ['16.1.2.3', SQLAnywhere16Platform::class], - ['16.9.9.9', SQLAnywhere16Platform::class], - ['17', SQLAnywhere16Platform::class], + ['16', SQLAnywherePlatform::class], + ['16.0', SQLAnywherePlatform::class], + ['16.0.0', SQLAnywherePlatform::class], + ['16.0.0.0', SQLAnywherePlatform::class], + ['16.1.2.3', SQLAnywherePlatform::class], + ['16.9.9.9', SQLAnywherePlatform::class], + ['17', SQLAnywherePlatform::class], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php deleted file mode 100644 index bf3f7372df3..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php +++ /dev/null @@ -1,27 +0,0 @@ -markTestSkipped('This version of the platform now supports regular expressions.'); - } - - public function testGeneratesRegularExpressionSQLSnippet() : void - { - self::assertEquals('REGEXP', $this->platform->getRegexpExpression()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php deleted file mode 100644 index e60f6b1c7f1..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php +++ /dev/null @@ -1,142 +0,0 @@ -markTestSkipped('This version of the platform now supports sequences.'); - } - - public function testSupportsSequences() : void - { - self::assertTrue($this->platform->supportsSequences()); - } - - public function testGeneratesSequenceSqlCommands() : void - { - $sequence = new Sequence('myseq', 20, 1); - self::assertEquals( - 'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1', - $this->platform->getCreateSequenceSQL($sequence) - ); - self::assertEquals( - 'ALTER SEQUENCE myseq INCREMENT BY 20', - $this->platform->getAlterSequenceSQL($sequence) - ); - self::assertEquals( - 'DROP SEQUENCE myseq', - $this->platform->getDropSequenceSQL('myseq') - ); - self::assertEquals( - 'DROP SEQUENCE myseq', - $this->platform->getDropSequenceSQL($sequence) - ); - self::assertEquals( - 'SELECT myseq.NEXTVAL', - $this->platform->getSequenceNextValSQL('myseq') - ); - self::assertEquals( - 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE', - $this->platform->getListSequencesSQL(null) - ); - } - - public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() : void - { - self::assertEquals( - 'TIMESTAMP WITH TIME ZONE', - $this->platform->getDateTimeTzTypeDeclarationSQL([ - 'length' => 10, - 'fixed' => true, - 'unsigned' => true, - 'autoincrement' => true, - ]) - ); - } - - public function testHasCorrectDateTimeTzFormatString() : void - { - self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); - } - - public function testInitializesDateTimeTzTypeMapping() : void - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); - self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); - } - - public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void - { - self::assertEquals( - 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - true, - false, - ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] - ), - 'footable' - ) - ); - self::assertEquals( - 'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] - ), - 'footable' - ) - ); - - // WITH NULLS NOT DISTINCT clause not available on primary indexes. - self::assertEquals( - 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - true, - ['with_nulls_not_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS NOT DISTINCT clause not available on non-unique indexes. - self::assertEquals( - 'CREATE INDEX fooindex ON footable (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_not_distinct'] - ), - 'footable' - ) - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php deleted file mode 100644 index a6a0018a06e..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php +++ /dev/null @@ -1,80 +0,0 @@ -platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - true, - false, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS DISTINCT clause not available on primary indexes. - self::assertEquals( - 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - true, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS DISTINCT clause not available on non-unique indexes. - self::assertEquals( - 'CREATE INDEX fooindex ON footable (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - parent::testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL(); - } - - public function testThrowsExceptionOnInvalidWithNullsNotDistinctIndexOptions() : void - { - $this->expectException('UnexpectedValueException'); - - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_distinct', 'with_nulls_not_distinct'] - ), - 'footable' - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index 0efa23b19c6..377abdb1abf 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Schema\Constraint; use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; @@ -484,18 +485,121 @@ public function testCannotGenerateCustomConstraintWithCreateConstraintSQL() : vo public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void { self::assertEquals( - 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', + 'CREATE UNIQUE INDEX fooindex ON footable (a, b) WITH NULLS DISTINCT', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], true, false, - ['virtual', 'clustered', 'for_olap_workload'] + ['with_nulls_distinct'] ), 'footable' ) ); + + // WITH NULLS DISTINCT clause not available on primary indexes. + self::assertEquals( + 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + true, + ['with_nulls_distinct'] + ), + 'footable' + ) + ); + + // WITH NULLS DISTINCT clause not available on non-unique indexes. + self::assertEquals( + 'CREATE INDEX fooindex ON footable (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_distinct'] + ), + 'footable' + ) + ); + + self::assertEquals( + 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + true, + false, + ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] + ), + 'footable' + ) + ); + self::assertEquals( + 'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] + ), + 'footable' + ) + ); + + // WITH NULLS NOT DISTINCT clause not available on primary indexes. + self::assertEquals( + 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + true, + ['with_nulls_not_distinct'] + ), + 'footable' + ) + ); + + // WITH NULLS NOT DISTINCT clause not available on non-unique indexes. + self::assertEquals( + 'CREATE INDEX fooindex ON footable (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_not_distinct'] + ), + 'footable' + ) + ); + } + + public function testThrowsExceptionOnInvalidWithNullsNotDistinctIndexOptions() : void + { + $this->expectException('UnexpectedValueException'); + + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_distinct', 'with_nulls_not_distinct'] + ), + 'footable' + ); } public function testDoesNotSupportIndexDeclarationInCreateAlterTableStatements() : void @@ -605,19 +709,28 @@ public function testGeneratesSQLSnippets() : void ); } - public function testDoesNotSupportRegexp() : void + public function testHasCorrectDateTimeTzFormatString() : void { - $this->expectException(DBALException::class); + self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); + } - $this->platform->getRegexpExpression(); + public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() : void + { + self::assertEquals( + 'TIMESTAMP WITH TIME ZONE', + $this->platform->getDateTimeTzTypeDeclarationSQL([ + 'length' => 10, + 'fixed' => true, + 'unsigned' => true, + 'autoincrement' => true, + ]) + ); } - public function testHasCorrectDateTimeTzFormatString() : void + public function testInitializesDateTimeTzTypeMapping() : void { - // Date time type with timezone is not supported before version 12. - // For versions before we have to ensure that the date time with timezone format - // equals the normal date time format so that it corresponds to the declaration SQL equality (datetimetz -> datetime). - self::assertEquals($this->platform->getDateTimeFormatString(), $this->platform->getDateTimeTzFormatString()); + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); + self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); } public function testHasCorrectDefaultTransactionIsolationLevel() : void @@ -776,7 +889,41 @@ public function testSupportsGettingAffectedRows() : void public function testDoesNotSupportSequences() : void { - self::assertFalse($this->platform->supportsSequences()); + self::markTestSkipped('This version of the platform now supports sequences.'); + } + + public function testSupportsSequences() : void + { + self::assertTrue($this->platform->supportsSequences()); + } + + public function testGeneratesSequenceSqlCommands() : void + { + $sequence = new Sequence('myseq', 20, 1); + self::assertEquals( + 'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1', + $this->platform->getCreateSequenceSQL($sequence) + ); + self::assertEquals( + 'ALTER SEQUENCE myseq INCREMENT BY 20', + $this->platform->getAlterSequenceSQL($sequence) + ); + self::assertEquals( + 'DROP SEQUENCE myseq', + $this->platform->getDropSequenceSQL('myseq') + ); + self::assertEquals( + 'DROP SEQUENCE myseq', + $this->platform->getDropSequenceSQL($sequence) + ); + self::assertEquals( + 'SELECT myseq.NEXTVAL', + $this->platform->getSequenceNextValSQL('myseq') + ); + self::assertEquals( + 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE', + $this->platform->getListSequencesSQL(null) + ); } public function testDoesNotSupportInlineColumnComments() : void From d1bbcbe8de8aa40509677829593e1c048c78acf4 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 17 Mar 2018 20:05:31 +0100 Subject: [PATCH 04/10] Drop PDO DB2 driver --- UPGRADE.md | 8 +++ lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php | 61 ------------------- .../Tests/DBAL/Driver/PDOIbm/DriverTest.php | 20 ------ 3 files changed, 8 insertions(+), 81 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php delete mode 100644 tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php diff --git a/UPGRADE.md b/UPGRADE.md index 5852ef815cb..fd6bec97a96 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,14 @@ All implementations of the `PingableConnection` and `ServerInfoAwareConnection` All implementations of the `VersionAwarePlatformDriver` interface have to implement the methods defined in the `Driver` interface as well. +## BC BREAK: Removed PDO DB2 driver + +This PDO-based IBM DB2 driver (built on top of `pdo_ibm` extension) has already been unsupported as of 2.5, it has been now removed. + +The following class has been removed: + + * `Doctrine\DBAL\Driver\PDOIbm\Driver` + ## BC BREAK: Removed support for SQL Anywhere 12 and older DBAL now requires SQL Anywhere 16 or newer, support for unmaintained versions has been dropped. diff --git a/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php b/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php deleted file mode 100644 index e57deca0c59..00000000000 --- a/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php +++ /dev/null @@ -1,61 +0,0 @@ -_constructPdoDsn($params), - $username, - $password, - $driverOptions - ); - } - - /** - * Constructs the IBM PDO DSN. - * - * @param mixed[] $params - * - * @return string The DSN. - */ - private function _constructPdoDsn(array $params) - { - $dsn = 'ibm:'; - if (isset($params['host'])) { - $dsn .= 'HOSTNAME=' . $params['host'] . ';'; - } - if (isset($params['port'])) { - $dsn .= 'PORT=' . $params['port'] . ';'; - } - $dsn .= 'PROTOCOL=TCPIP;'; - if (isset($params['dbname'])) { - $dsn .= 'DATABASE=' . $params['dbname'] . ';'; - } - - return $dsn; - } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_ibm'; - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php deleted file mode 100644 index 9eeeafb78aa..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} From 6a887097a64946725086cdb37c5ced44b79c2852 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 17 Mar 2018 20:44:53 +0100 Subject: [PATCH 05/10] Remove MsSQLKeywords --- UPGRADE.md | 5 +++++ .../DBAL/Platforms/Keywords/MsSQLKeywords.php | 21 ------------------- 2 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php diff --git a/UPGRADE.md b/UPGRADE.md index fd6bec97a96..6688fdfa316 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,11 @@ All implementations of the `PingableConnection` and `ServerInfoAwareConnection` All implementations of the `VersionAwarePlatformDriver` interface have to implement the methods defined in the `Driver` interface as well. +## BC BREAK: Removed MsSQLKeywords class + +The `Doctrine\DBAL\Platforms\MsSQLKeywords` class has been removed. +Please use `Doctrine\DBAL\Platforms\SQLServerPlatform `instead. + ## BC BREAK: Removed PDO DB2 driver This PDO-based IBM DB2 driver (built on top of `pdo_ibm` extension) has already been unsupported as of 2.5, it has been now removed. diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php deleted file mode 100644 index 5306b5b0d2b..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php +++ /dev/null @@ -1,21 +0,0 @@ - Date: Sat, 17 Mar 2018 20:54:50 +0100 Subject: [PATCH 06/10] Reorder keywords and type mappings alphabetically --- lib/Doctrine/DBAL/Platforms/DB2Platform.php | 30 +-- .../DBAL/Platforms/Keywords/DB2Keywords.php | 190 +++++++++--------- .../Platforms/Keywords/OracleKeywords.php | 164 +++++++-------- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 60 +++--- .../DBAL/Platforms/OraclePlatform.php | 46 ++--- .../DBAL/Platforms/PostgreSqlPlatform.php | 78 +++---- .../DBAL/Platforms/SQLAnywherePlatform.php | 76 +++---- .../DBAL/Platforms/SQLServerPlatform.php | 54 ++--- .../DBAL/Platforms/SqlitePlatform.php | 48 ++--- .../Console/Command/ReservedWordsCommand.php | 10 +- 10 files changed, 378 insertions(+), 378 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index 25d4163b6ec..58e9490527a 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -74,21 +74,21 @@ public function getBlobTypeDeclarationSQL(array $field) public function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'smallint' => 'smallint', - 'bigint' => 'bigint', - 'integer' => 'integer', - 'time' => 'time', - 'date' => 'date', - 'varchar' => 'string', - 'character' => 'string', - 'varbinary' => 'binary', - 'binary' => 'binary', - 'clob' => 'text', - 'blob' => 'blob', - 'decimal' => 'decimal', - 'double' => 'float', - 'real' => 'float', - 'timestamp' => 'datetime', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'blob' => 'blob', + 'character' => 'string', + 'clob' => 'text', + 'date' => 'date', + 'decimal' => 'decimal', + 'double' => 'float', + 'integer' => 'integer', + 'real' => 'float', + 'smallint' => 'smallint', + 'time' => 'time', + 'timestamp' => 'datetime', + 'varbinary' => 'binary', + 'varchar' => 'string', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php index 8533f579d71..db577d30207 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php @@ -27,24 +27,6 @@ protected function getKeywords() 'ALIAS', 'ALL', 'ALLOCATE', - 'DOCUMENT', - 'DOUBLE', - 'DROP', - 'DSSIZE', - 'DYNAMIC', - 'EACH', - 'LOCK', - 'LOCKMAX', - 'LOCKSIZE', - 'LONG', - 'LOOP', - 'MAINTAINED', - 'ROUND_CEILING', - 'ROUND_DOWN', - 'ROUND_FLOOR', - 'ROUND_HALF_DOWN', - 'ROUND_HALF_EVEN', - 'ROUND_HALF_UP', 'ALLOW', 'ALTER', 'AND', @@ -112,6 +94,38 @@ protected function getKeywords() 'DATABASE', 'DATAPARTITIONNAME', 'DATAPARTITIONNUM', + 'DATE', + 'DAY', + 'DAYS', + 'DB2GENERAL', + 'DB2GENRL', + 'DB2SQL', + 'DBINFO', + 'DBPARTITIONNAME', + 'DBPARTITIONNUM', + 'DEALLOCATE', + 'DECLARE', + 'DEFAULT', + 'DEFAULTS', + 'DEFINITION', + 'DELETE', + 'DENSE_RANK', + 'DENSERANK', + 'DESCRIBE', + 'DESCRIPTOR', + 'DETERMINISTIC', + 'DIAGNOSTICS', + 'DISABLE', + 'DISALLOW', + 'DISCONNECT', + 'DISTINCT', + 'DO', + 'DOCUMENT', + 'DOUBLE', + 'DROP', + 'DSSIZE', + 'DYNAMIC', + 'EACH', 'EDITPROC', 'ELSE', 'ELSEIF', @@ -179,6 +193,38 @@ protected function getKeywords() 'INSENSITIVE', 'INSERT', 'INTEGRITY', + 'INTERSECT', + 'INTO', + 'IS', + 'ISOBID', + 'ISOLATION', + 'ITERATE', + 'JAR', + 'JAVA', + 'JOIN', + 'KEEP', + 'KEY', + 'LABEL', + 'LANGUAGE', + 'LATERAL', + 'LC_CTYPE', + 'LEAVE', + 'LEFT', + 'LIKE', + 'LINKTYPE', + 'LOCAL', + 'LOCALDATE', + 'LOCALE', + 'LOCALTIME', + 'LOCALTIMESTAMP RIGHT', + 'LOCATOR', + 'LOCATORS', + 'LOCK', + 'LOCKMAX', + 'LOCKSIZE', + 'LONG', + 'LOOP', + 'MAINTAINED', 'MATERIALIZED', 'MAXVALUE', 'MICROSECOND', @@ -246,6 +292,37 @@ protected function getKeywords() 'PROCEDURE', 'PROGRAM', 'PSID', + 'PUBLIC', + 'QUERY', + 'QUERYNO', + 'RANGE', + 'RANK', + 'READ', + 'READS', + 'RECOVERY', + 'REFERENCES', + 'REFERENCING', + 'REFRESH', + 'RELEASE', + 'RENAME', + 'REPEAT', + 'RESET', + 'RESIGNAL', + 'RESTART', + 'RESTRICT', + 'RESULT', + 'RESULT_SET_LOCATOR WLM', + 'RETURN', + 'RETURNS', + 'REVOKE', + 'ROLE', + 'ROLLBACK', + 'ROUND_CEILING', + 'ROUND_DOWN', + 'ROUND_FLOOR', + 'ROUND_HALF_DOWN', + 'ROUND_HALF_EVEN', + 'ROUND_HALF_UP', 'ROUND_UP', 'ROUTINE', 'ROW', @@ -313,107 +390,30 @@ protected function getKeywords() 'UNIQUE', 'UNTIL', 'UPDATE', - 'DATE', - 'DAY', - 'DAYS', - 'DB2GENERAL', - 'DB2GENRL', - 'DB2SQL', - 'DBINFO', - 'DBPARTITIONNAME', - 'DBPARTITIONNUM', - 'DEALLOCATE', - 'DECLARE', - 'DEFAULT', - 'DEFAULTS', - 'DEFINITION', - 'DELETE', - 'DENSE_RANK', - 'DENSERANK', - 'DESCRIBE', - 'DESCRIPTOR', - 'DETERMINISTIC', - 'DIAGNOSTICS', - 'DISABLE', - 'DISALLOW', - 'DISCONNECT', - 'DISTINCT', - 'DO', - 'INTERSECT', - 'PUBLIC', 'USAGE', - 'INTO', - 'QUERY', 'USER', - 'IS', - 'QUERYNO', 'USING', - 'ISOBID', - 'RANGE', 'VALIDPROC', - 'ISOLATION', - 'RANK', 'VALUE', - 'ITERATE', - 'READ', 'VALUES', - 'JAR', - 'READS', 'VARIABLE', - 'JAVA', - 'RECOVERY', 'VARIANT', - 'JOIN', - 'REFERENCES', 'VCAT', - 'KEEP', - 'REFERENCING', 'VERSION', - 'KEY', - 'REFRESH', 'VIEW', - 'LABEL', - 'RELEASE', 'VOLATILE', - 'LANGUAGE', - 'RENAME', 'VOLUMES', - 'LATERAL', - 'REPEAT', 'WHEN', - 'LC_CTYPE', - 'RESET', 'WHENEVER', - 'LEAVE', - 'RESIGNAL', 'WHERE', - 'LEFT', - 'RESTART', 'WHILE', - 'LIKE', - 'RESTRICT', 'WITH', - 'LINKTYPE', - 'RESULT', 'WITHOUT', - 'LOCAL', - 'RESULT_SET_LOCATOR WLM', - 'LOCALDATE', - 'RETURN', 'WRITE', - 'LOCALE', - 'RETURNS', 'XMLELEMENT', - 'LOCALTIME', - 'REVOKE', 'XMLEXISTS', - 'LOCALTIMESTAMP RIGHT', 'XMLNAMESPACES', - 'LOCATOR', - 'ROLE', 'YEAR', - 'LOCATORS', - 'ROLLBACK', 'YEARS', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php index 92ca81a079b..a73a93d60c0 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php @@ -22,118 +22,118 @@ protected function getKeywords() { return [ 'ACCESS', - 'ELSE', - 'MODIFY', - 'START', 'ADD', - 'EXCLUSIVE', - 'NOAUDIT', - 'SELECT', 'ALL', - 'EXISTS', - 'NOCOMPRESS', - 'SESSION', 'ALTER', - 'FILE', - 'NOT', - 'SET', 'AND', - 'FLOAT', - 'NOTFOUND ', - 'SHARE', 'ANY', - 'FOR', - 'NOWAIT', - 'SIZE', 'ARRAYLEN', - 'FROM', - 'NULL', - 'SMALLINT', 'AS', - 'GRANT', - 'NUMBER', - 'SQLBUF', 'ASC', - 'GROUP', - 'OF', - 'SUCCESSFUL', 'AUDIT', - 'HAVING', - 'OFFLINE ', - 'SYNONYM', 'BETWEEN', - 'IDENTIFIED', - 'ON', - 'SYSDATE', 'BY', - 'IMMEDIATE', - 'ONLINE', - 'TABLE', 'CHAR', - 'IN', - 'OPTION', - 'THEN', 'CHECK', - 'INCREMENT', - 'OR', - 'TO', 'CLUSTER', - 'INDEX', - 'ORDER', - 'TRIGGER', 'COLUMN', - 'INITIAL', - 'PCTFREE', - 'UID', 'COMMENT', - 'INSERT', - 'PRIOR', - 'UNION', 'COMPRESS', - 'INTEGER', - 'PRIVILEGES', - 'UNIQUE', 'CONNECT', - 'INTERSECT', - 'PUBLIC', - 'UPDATE', 'CREATE', - 'INTO', - 'RAW', - 'USER', 'CURRENT', - 'IS', - 'RENAME', - 'VALIDATE', 'DATE', - 'LEVEL', - 'RESOURCE', - 'VALUES', 'DECIMAL', - 'LIKE', - 'REVOKE', - 'VARCHAR', 'DEFAULT', - 'LOCK', - 'ROW', - 'VARCHAR2', 'DELETE', - 'LONG', - 'ROWID', - 'VIEW', 'DESC', - 'MAXEXTENTS', - 'ROWLABEL', - 'WHENEVER', 'DISTINCT', - 'MINUS', - 'ROWNUM', - 'WHERE', 'DROP', + 'ELSE', + 'EXCLUSIVE', + 'EXISTS', + 'FILE', + 'FLOAT', + 'FOR', + 'FROM', + 'GRANT', + 'GROUP', + 'HAVING', + 'IDENTIFIED', + 'IMMEDIATE', + 'IN', + 'INCREMENT', + 'INDEX', + 'INITIAL', + 'INSERT', + 'INTEGER', + 'INTERSECT', + 'INTO', + 'IS', + 'LEVEL', + 'LIKE', + 'LOCK', + 'LONG', + 'MAXEXTENTS', + 'MINUS', 'MODE', + 'MODIFY', + 'NOAUDIT', + 'NOCOMPRESS', + 'NOT', + 'NOTFOUND', + 'NOWAIT', + 'NULL', + 'NUMBER', + 'OF', + 'OFFLINE', + 'ON', + 'ONLINE', + 'OPTION', + 'OR', + 'ORDER', + 'PCTFREE', + 'PRIOR', + 'PRIVILEGES', + 'PUBLIC', + 'RANGE', + 'RAW', + 'RENAME', + 'RESOURCE', + 'REVOKE', + 'ROW', + 'ROWID', + 'ROWLABEL', + 'ROWNUM', 'ROWS', + 'SELECT', + 'SESSION', + 'SET', + 'SHARE', + 'SIZE', + 'SMALLINT', + 'SQLBUF', + 'START', + 'SUCCESSFUL', + 'SYNONYM', + 'SYSDATE', + 'TABLE', + 'THEN', + 'TO', + 'TRIGGER', + 'UID', + 'UNION', + 'UNIQUE', + 'UPDATE', + 'USER', + 'VALIDATE', + 'VALUES', + 'VARCHAR', + 'VARCHAR2', + 'VIEW', + 'WHENEVER', + 'WHERE', 'WITH', - 'RANGE', ]; } } diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 57c448ce93e..5fad73aa301 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -1055,36 +1055,36 @@ public function getReadLockSQL() protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'tinyint' => 'boolean', - 'smallint' => 'smallint', - 'mediumint' => 'integer', - 'int' => 'integer', - 'integer' => 'integer', - 'bigint' => 'bigint', - 'tinytext' => 'text', - 'mediumtext' => 'text', - 'longtext' => 'text', - 'text' => 'text', - 'varchar' => 'string', - 'string' => 'string', - 'char' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'time' => 'time', - 'float' => 'float', - 'double' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', - 'numeric' => 'decimal', - 'year' => 'date', - 'longblob' => 'blob', - 'blob' => 'blob', - 'mediumblob' => 'blob', - 'tinyblob' => 'blob', - 'binary' => 'binary', - 'varbinary' => 'binary', - 'set' => 'simple_array', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'blob' => 'blob', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'decimal' => 'decimal', + 'double' => 'float', + 'float' => 'float', + 'int' => 'integer', + 'integer' => 'integer', + 'longblob' => 'blob', + 'longtext' => 'text', + 'mediumblob' => 'blob', + 'mediumint' => 'integer', + 'mediumtext' => 'text', + 'numeric' => 'decimal', + 'real' => 'float', + 'set' => 'simple_array', + 'smallint' => 'smallint', + 'string' => 'string', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'tinyblob' => 'blob', + 'tinyint' => 'boolean', + 'tinytext' => 'text', + 'varbinary' => 'binary', + 'varchar' => 'string', + 'year' => 'date', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 21b13a2d691..25e4094f82d 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -1133,29 +1133,29 @@ public function getDummySelectSQL() protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'integer' => 'integer', - 'number' => 'integer', - 'pls_integer' => 'boolean', - 'binary_integer' => 'boolean', - 'varchar' => 'string', - 'varchar2' => 'string', - 'nvarchar2' => 'string', - 'char' => 'string', - 'nchar' => 'string', - 'date' => 'date', - 'timestamp' => 'datetime', - 'timestamptz' => 'datetimetz', - 'float' => 'float', - 'binary_float' => 'float', - 'binary_double' => 'float', - 'long' => 'string', - 'clob' => 'text', - 'nclob' => 'text', - 'raw' => 'binary', - 'long raw' => 'blob', - 'rowid' => 'string', - 'urowid' => 'string', - 'blob' => 'blob', + 'binary_double' => 'float', + 'binary_float' => 'float', + 'binary_integer' => 'boolean', + 'blob' => 'blob', + 'char' => 'string', + 'clob' => 'text', + 'date' => 'date', + 'float' => 'float', + 'integer' => 'integer', + 'long' => 'string', + 'long raw' => 'blob', + 'nchar' => 'string', + 'nclob' => 'text', + 'number' => 'integer', + 'nvarchar2' => 'string', + 'pls_integer' => 'boolean', + 'raw' => 'binary', + 'rowid' => 'string', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'urowid' => 'string', + 'varchar' => 'string', + 'varchar2' => 'string', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index ad50c3f754c..64fd2700218 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -1127,46 +1127,46 @@ public function getReadLockSQL() protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'smallint' => 'smallint', - 'int2' => 'smallint', - 'serial' => 'integer', - 'serial4' => 'integer', - 'int' => 'integer', - 'int4' => 'integer', - 'integer' => 'integer', - 'bigserial' => 'bigint', - 'serial8' => 'bigint', - 'bigint' => 'bigint', - 'int8' => 'bigint', - 'bool' => 'boolean', - 'boolean' => 'boolean', - 'text' => 'text', - 'tsvector' => 'text', - 'varchar' => 'string', - 'interval' => 'string', - '_varchar' => 'string', - 'char' => 'string', - 'bpchar' => 'string', - 'inet' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'timestamptz' => 'datetimetz', - 'time' => 'time', - 'timetz' => 'time', - 'float' => 'float', - 'float4' => 'float', - 'float8' => 'float', - 'double' => 'float', + 'bigint' => 'bigint', + 'bigserial' => 'bigint', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'bpchar' => 'string', + 'bytea' => 'blob', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'decimal' => 'decimal', + 'double' => 'float', 'double precision' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', - 'money' => 'decimal', - 'numeric' => 'decimal', - 'year' => 'date', - 'uuid' => 'guid', - 'bytea' => 'blob', - 'json' => Type::JSON, + 'float' => 'float', + 'float4' => 'float', + 'float8' => 'float', + 'inet' => 'string', + 'int' => 'integer', + 'int2' => 'smallint', + 'int4' => 'integer', + 'int8' => 'bigint', + 'integer' => 'integer', + 'interval' => 'string', + 'json' => Type::JSON, + 'money' => 'decimal', + 'numeric' => 'decimal', + 'serial' => 'integer', + 'serial4' => 'integer', + 'serial8' => 'bigint', + 'real' => 'float', + 'smallint' => 'smallint', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'timetz' => 'time', + 'tsvector' => 'text', + 'uuid' => 'guid', + 'varchar' => 'string', + 'year' => 'date', + '_varchar' => 'string', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 503fde23d56..0bde50c18f1 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1557,45 +1557,45 @@ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'char' => 'string', - 'long nvarchar' => 'text', - 'long varchar' => 'text', - 'nchar' => 'string', - 'ntext' => 'text', - 'nvarchar' => 'string', - 'text' => 'text', - 'uniqueidentifierstr' => 'guid', - 'varchar' => 'string', - 'xml' => 'text', - 'bigint' => 'bigint', - 'unsigned bigint' => 'bigint', - 'bit' => 'boolean', - 'decimal' => 'decimal', - 'double' => 'float', - 'float' => 'float', - 'int' => 'integer', - 'integer' => 'integer', - 'unsigned int' => 'integer', - 'numeric' => 'decimal', - 'smallint' => 'smallint', - 'unsigned smallint' => 'smallint', - 'tinyint' => 'smallint', - 'unsigned tinyint' => 'smallint', - 'money' => 'decimal', - 'smallmoney' => 'decimal', - 'long varbit' => 'text', - 'varbit' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'smalldatetime' => 'datetime', - 'time' => 'time', - 'timestamp' => 'datetime', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'bit' => 'boolean', + 'char' => 'string', + 'decimal' => 'decimal', + 'date' => 'date', + 'datetime' => 'datetime', + 'double' => 'float', + 'float' => 'float', + 'image' => 'blob', + 'int' => 'integer', + 'integer' => 'integer', + 'long binary' => 'blob', + 'long nvarchar' => 'text', + 'long varbit' => 'text', + 'long varchar' => 'text', + 'money' => 'decimal', + 'nchar' => 'string', + 'ntext' => 'text', + 'numeric' => 'decimal', + 'nvarchar' => 'string', + 'smalldatetime' => 'datetime', + 'smallint' => 'smallint', + 'smallmoney' => 'decimal', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', 'timestamp with time zone' => 'datetime', - 'binary' => 'binary', - 'image' => 'blob', - 'long binary' => 'blob', - 'uniqueidentifier' => 'guid', - 'varbinary' => 'binary', + 'tinyint' => 'smallint', + 'uniqueidentifier' => 'guid', + 'uniqueidentifierstr' => 'guid', + 'unsigned bigint' => 'bigint', + 'unsigned int' => 'integer', + 'unsigned smallint' => 'smallint', + 'unsigned tinyint' => 'smallint', + 'varbinary' => 'binary', + 'varbit' => 'string', + 'varchar' => 'string', + 'xml' => 'text', ]; } } diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index e0b186257e2..c29d488cbbb 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1489,35 +1489,35 @@ public function getName() protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'bigint' => 'bigint', - 'numeric' => 'decimal', - 'bit' => 'boolean', - 'smallint' => 'smallint', - 'decimal' => 'decimal', - 'smallmoney' => 'integer', - 'int' => 'integer', - 'tinyint' => 'smallint', - 'money' => 'integer', - 'float' => 'float', - 'real' => 'float', - 'double' => 'float', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'bit' => 'boolean', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'datetime2' => 'datetime', + 'datetimeoffset' => 'datetimetz', + 'decimal' => 'decimal', + 'double' => 'float', 'double precision' => 'float', - 'smalldatetime' => 'datetime', - 'datetime' => 'datetime', - 'char' => 'string', - 'varchar' => 'string', - 'text' => 'text', - 'nchar' => 'string', - 'nvarchar' => 'string', - 'ntext' => 'text', - 'binary' => 'binary', - 'varbinary' => 'binary', - 'image' => 'blob', + 'float' => 'float', + 'image' => 'blob', + 'int' => 'integer', + 'money' => 'integer', + 'nchar' => 'string', + 'ntext' => 'text', + 'numeric' => 'decimal', + 'nvarchar' => 'string', + 'real' => 'float', + 'smalldatetime' => 'datetime', + 'smallint' => 'smallint', + 'smallmoney' => 'integer', + 'text' => 'text', + 'time' => 'time', + 'tinyint' => 'smallint', 'uniqueidentifier' => 'guid', - 'datetime2' => 'datetime', - 'date' => 'date', - 'time' => 'time', - 'datetimeoffset' => 'datetimetz', + 'varbinary' => 'binary', + 'varchar' => 'string', ]; } diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 02d2482c86e..af3d279cb4d 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -624,38 +624,38 @@ private function getInlineTableCommentSQL(string $comment) : string protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ - 'boolean' => 'boolean', - 'tinyint' => 'boolean', - 'smallint' => 'smallint', - 'mediumint' => 'integer', - 'int' => 'integer', - 'integer' => 'integer', - 'serial' => 'integer', 'bigint' => 'bigint', 'bigserial' => 'bigint', - 'clob' => 'text', - 'tinytext' => 'text', - 'mediumtext' => 'text', - 'longtext' => 'text', - 'text' => 'text', - 'varchar' => 'string', - 'longvarchar' => 'string', - 'varchar2' => 'string', - 'nvarchar' => 'string', - 'image' => 'string', - 'ntext' => 'string', + 'blob' => 'blob', + 'boolean' => 'boolean', 'char' => 'string', + 'clob' => 'text', 'date' => 'date', 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'time' => 'time', - 'float' => 'float', + 'decimal' => 'decimal', 'double' => 'float', 'double precision' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', + 'float' => 'float', + 'image' => 'string', + 'int' => 'integer', + 'integer' => 'integer', + 'longtext' => 'text', + 'longvarchar' => 'string', + 'mediumint' => 'integer', + 'mediumtext' => 'text', + 'ntext' => 'string', 'numeric' => 'decimal', - 'blob' => 'blob', + 'nvarchar' => 'string', + 'real' => 'float', + 'serial' => 'integer', + 'smallint' => 'smallint', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'tinyint' => 'boolean', + 'tinytext' => 'text', + 'varchar' => 'string', + 'varchar2' => 'string', ]; } diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 32f29b29619..a8020a15399 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -29,18 +29,18 @@ class ReservedWordsCommand extends Command { /** @var string[] */ private $keywordListClasses = [ + 'db2' => DB2Keywords::class, 'mysql' => MySQLKeywords::class, 'mysql57' => MySQL57Keywords::class, 'mysql80' => MySQL80Keywords::class, - 'sqlserver' => SQLServerKeywords::class, - 'sqlserver2012' => SQLServer2012Keywords::class, - 'sqlite' => SQLiteKeywords::class, + 'oracle' => OracleKeywords::class, 'pgsql' => PostgreSQLKeywords::class, 'pgsql94' => PostgreSQL94Keywords::class, 'pgsql100' => PostgreSQL100Keywords::class, - 'oracle' => OracleKeywords::class, - 'db2' => DB2Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, + 'sqlite' => SQLiteKeywords::class, + 'sqlserver' => SQLServerKeywords::class, + 'sqlserver2012' => SQLServer2012Keywords::class, ]; /** From 42dfc79a4fa2badd3bb1e2a823e50180b4fc3693 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Wed, 7 Mar 2018 20:04:42 +0100 Subject: [PATCH 07/10] Drop Drizzle support --- UPGRADE.md | 4 + docs/en/reference/configuration.rst | 29 +- docs/en/reference/introduction.rst | 1 - docs/en/reference/platforms.rst | 5 - docs/en/reference/schema-representation.rst | 10 +- docs/en/reference/types.rst | 118 ++-- .../Driver/DrizzlePDOMySql/Connection.php | 24 - .../DBAL/Driver/DrizzlePDOMySql/Driver.php | 61 -- lib/Doctrine/DBAL/DriverManager.php | 2 - .../DBAL/Platforms/DrizzlePlatform.php | 623 ------------------ .../Platforms/Keywords/DrizzleKeywords.php | 326 --------- lib/Doctrine/DBAL/Portability/Connection.php | 3 - .../DBAL/Schema/DrizzleSchemaManager.php | 103 --- .../Driver/DrizzlePDOMySql/DriverTest.php | 52 -- .../Doctrine/Tests/DBAL/DriverManagerTest.php | 7 +- .../Tests/DBAL/Functional/ExceptionTest.php | 5 - .../Schema/DrizzleSchemaManagerTest.php | 48 -- 17 files changed, 55 insertions(+), 1366 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php delete mode 100644 lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php delete mode 100644 lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php delete mode 100644 lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php delete mode 100644 tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php diff --git a/UPGRADE.md b/UPGRADE.md index 6688fdfa316..57f20bc6a30 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -103,6 +103,10 @@ After: $stmt->bindValue(1, 1, ParameterType::INTEGER); $stmt->fetchAll(FetchMode::COLUMN); +## BC BREAK: Removed Drizzle support + +The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL anymore. + ## BC BREAK: Removed dbal:import CLI command The `dbal:import` CLI command has been removed since it only worked with PDO-based drivers by relying on a non-documented behavior of the extension, and it was impossible to make it work with other drivers. diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index cf7c42d943b..5a4c872cd76 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -71,12 +71,8 @@ full driver name:: pdo-mysql://localhost:4486/foo?charset=UTF-8 -If you wanted to use the ``drizzle_pdo__mysql`` driver instead:: - - drizzle-pdo-mysql://localhost:4486/foo?charset=UTF-8 - -In the last two examples above, mind the dashes instead of the -underscores in the URL schemes. +In the example above, mind the dashes instead of the +underscores in the URL scheme. For connecting to an SQLite database, the authority portion of the URL is obviously irrelevant and thus can be omitted. The path part @@ -126,8 +122,6 @@ interfaces to use. It can be configured in one of three ways: - ``pdo_mysql``: A MySQL driver that uses the pdo_mysql PDO extension. - - ``drizzle_pdo_mysql``: A Drizzle driver that uses pdo_mysql PDO - extension. - ``mysqli``: A MySQL driver that uses the mysqli extension. - ``pdo_sqlite``: An SQLite driver that uses the pdo_sqlite PDO extension. @@ -195,23 +189,6 @@ pdo_mysql - ``charset`` (string): The charset used when connecting to the database. -drizzle_pdo_mysql -^^^^^^^^^^^^^^^^^ - -**Requires** drizzle plugin ``mysql_protocol`` or ``mysql_unix_socket_protocol`` to be enabled. -On Ubuntu this can be done by editing ``/etc/drizzle/conf.d/mysql-protocol.cnf`` -or ``/etc/drizzle/conf.d/mysql-unix-socket-protocol.cnf`` and restarting the drizzled daemon. - -- ``user`` (string): Username to use when connecting to the - database. Only needed if authentication is configured for drizzled. -- ``password`` (string): Password to use when connecting to the - database. Only needed if authentication is configured for drizzled. -- ``host`` (string): Hostname of the database to connect to. -- ``port`` (integer): Port of the database to connect to. -- ``dbname`` (string): Name of the database/schema to connect to. -- ``unix_socket`` (string): Name of the socket used to connect to - the database. - mysqli ^^^^^^ @@ -374,7 +351,7 @@ You can also pass this option if you want to disable automatic database platform detection for a driver that natively supports it and choose the platform version implementation explicitly. -If you are running a MariaDB database, you should prefix the ``serverVersion`` +If you are running a MariaDB database, you should prefix the ``serverVersion`` with ``mariadb-`` (ex: ``mariadb-10.2.12``). Custom Platform diff --git a/docs/en/reference/introduction.rst b/docs/en/reference/introduction.rst index ae495ea9815..5318303a7c6 100644 --- a/docs/en/reference/introduction.rst +++ b/docs/en/reference/introduction.rst @@ -21,7 +21,6 @@ The following database vendors are currently supported: - PostgreSQL - SAP Sybase SQL Anywhere - SQLite -- Drizzle The Doctrine 2 database layer can be used independently of the object-relational mapper. In order to use the DBAL all you need is diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index 0d5ff83c4ce..163cf230e77 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -70,11 +70,6 @@ SQLite - ``SqlitePlatform`` for all versions. -Drizzle -^^^^^^ - -- ``DrizzlePlatform`` for all versions (deprecated). - It is highly encouraged to use the platform class that matches your database vendor and version best. Otherwise it is not guaranteed that the compatibility in terms of SQL dialect and feature support diff --git a/docs/en/reference/schema-representation.rst b/docs/en/reference/schema-representation.rst index e1beff8a0df..712de04b007 100644 --- a/docs/en/reference/schema-representation.rst +++ b/docs/en/reference/schema-representation.rst @@ -116,10 +116,10 @@ The following options are not completely portable but are supported by most of t vendors: - **unsigned** (boolean): Whether a ``smallint``, ``integer`` or ``bigint`` Doctrine - type column should allow unsigned values only. Supported by MySQL, SQL Anywhere - and Drizzle. Defaults to ``false``. + type column should allow unsigned values only. Supported by MySQL and SQL Anywhere. + Defaults to ``false``. - **comment** (integer|string): The column comment. Supported by MySQL, PostgreSQL, - Oracle, SQL Server, SQL Anywhere and Drizzle. Defaults to ``null``. + Oracle, SQL Server and SQL Anywhere. Defaults to ``null``. Vendor specific options ^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,8 +134,8 @@ The following options are completely vendor specific and absolutely not portable supported by some vendors but not portable: - **charset** (string): The character set to use for the column. Currently only supported - on MySQL and Drizzle. + on MySQL. - **collation** (string): The collation to use for the column. Supported by MySQL, PostgreSQL, - Sqlite, SQL Server and Drizzle. + Sqlite and SQL Server. - **check** (string): The check constraint clause to add to the column. Defaults to ``null``. diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index 4f6398525e4..dd733f33a51 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -517,8 +517,6 @@ Please also notice the mapping specific footnotes for additional information. +===================+===============+==========================+=========+==========================================================+ | **smallint** | ``integer`` | **MySQL** | *all* | ``SMALLINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``INT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``SMALLINT`` | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``NUMBER(5)`` | @@ -527,11 +525,9 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``SMALLINT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **integer** | ``integer`` | **MySQL** | *all* | ``INT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``INT`` [12]_ | | | | | +----------------------------------------------------------+ @@ -543,12 +539,10 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``INT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **bigint** | ``string`` | **MySQL** | *all* | ``BIGINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | [8]_ +--------------------------+ | | -| | | **Drizzle** | | | -| | +--------------------------+---------+----------------------------------------------------------+ +| | [8]_ +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``BIGINT`` [12]_ | | | | | +----------------------------------------------------------+ | | | | | ``BIGSERIAL`` [11]_ | @@ -559,7 +553,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``BIGINT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **decimal** [7]_ | ``string`` | **MySQL** | *all* | ``NUMERIC(p, s)`` ``UNSIGNED`` [10]_ | | | [9]_ +--------------------------+---------+----------------------------------------------------------+ @@ -572,8 +566,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **float** | ``float`` | **MySQL** | *all* | ``DOUBLE PRECISION`` ``UNSIGNED`` [10]_ | | | +--------------------------+---------+----------------------------------------------------------+ @@ -586,8 +578,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **string** | ``string`` | **MySQL** | *all* | ``VARCHAR(n)`` [3]_ | | [2]_ [5]_ | +--------------------------+ | | @@ -597,8 +587,6 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``VARCHAR(n)`` | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``VARCHAR2(n)`` [3]_ | | | | | +----------------------------------------------------------+ | | | | | ``CHAR(n)`` [4]_ | @@ -607,19 +595,17 @@ Please also notice the mapping specific footnotes for additional information. | | | | +----------------------------------------------------------+ | | | | | ``NCHAR(n)`` [4]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -632,8 +618,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **Oracle** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``UNIQUEIDENTIFIER`` | | | +--------------------------+ | | @@ -647,27 +631,23 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | ``BINARY(n)`` [4]_ | | | | **SQL Anywhere** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``VARBINARY(n)`` | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``RAW(n)`` | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BYTEA`` [16]_ | +| | | **PostgreSQL** | *all* | ``BYTEA`` [15]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``BLOB`` [16]_ | +| | | **SQLite** | *all* | ``BLOB`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [17]_ | +| **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``BLOB`` [18]_ | +| | | | | ``BLOB`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMBLOB`` [19]_ | +| | | | | ``MEDIUMBLOB`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGBLOB`` [20]_ | +| | | | | ``LONGBLOB`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``BLOB`` | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARBINARY(MAX)`` | | | +--------------------------+---------+----------------------------------------------------------+ @@ -680,8 +660,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **PostgreSQL** | *all* | ``BOOLEAN`` | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``BIT`` | | | +--------------------------+ | | @@ -698,14 +676,10 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+ | | | | **SQL Server** | "all" | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | -| | +--------------------------+ +----------------------------------------------------------+ -| | | **Drizzle** | | ``TIMESTAMP`` [14]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``DATETIME`` | | | +--------------------------+ | | @@ -717,9 +691,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``TIMESTAMP(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [15]_ [16]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | +| **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [14]_ [15]_ | | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+ | @@ -736,28 +708,24 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TIME(0) WITHOUT TIME ZONE`` | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``DATE`` [16]_ | +| | | **Oracle** | *all* | ``DATE`` [15]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | "all" | ``TIME(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | +-------------------+ | | +----------------------------------------------------------+ -| **simple array** | | | | ``TEXT`` [18]_ | +| **simple array** | | | | ``TEXT`` [17]_ | | [1]_ | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -765,23 +733,21 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **json_array** | ``array`` | **MySQL** [1]_ | *all* | ``TINYTEXT`` [17]_ | +| **json_array** | ``array`` | **MySQL** [1]_ | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | < 9.4 | ``JSON`` | | | | +---------+----------------------------------------------------------+ -| | | | >= 9.4 | ``JSON`` [21]_ | +| | | | >= 9.4 | ``JSON`` [20]_ | | | | | +----------------------------------------------------------+ -| | | | | ``JSONB`` [22]_ | +| | | | | ``JSONB`` [21]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``TEXT`` [1]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` [1]_ | | | +--------------------------+ | | @@ -789,19 +755,17 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` [1]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **object** [1]_ | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **object** [1]_ | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -817,10 +781,10 @@ Please also notice the mapping specific footnotes for additional information. .. [4] Chosen if the column definition has the **fixed** attribute set to ``true``. .. [5] Silently maps to the vendor specific ``text`` type if the given **length** attribute for **n** exceeds the maximum length the related platform allows. If this is the case, please - see [16]_. + see [15]_. .. [6] Silently maps to the vendor specific ``blob`` type if the given **length** attribute for **n** exceeds the maximum length the related platform allows. If this is the case, please - see [16]_. + see [15]_. .. [7] **p** is the precision and **s** the scale set in the column definition. The precision defaults to ``10`` and the scale to ``0`` if not set. .. [8] Returns PHP ``string`` type value instead of ``integer`` because of maximum integer value @@ -832,22 +796,20 @@ Please also notice the mapping specific footnotes for additional information. .. [12] Chosen if the column definition has the **autoincrement** attribute set to ``false`` (default). .. [13] Chosen if the column definition does not contain the **version** option inside the **platformOptions** attribute array or is set to ``false`` which marks it as a non-locking information column. -.. [14] Chosen if the column definition contains the **version** option inside the **platformOptions** - attribute array and is set to ``true`` which marks it as a locking information column. -.. [15] Fallback type as the vendor does not support a native date time type with timezone information. +.. [14] Fallback type as the vendor does not support a native date time type with timezone information. This means that the timezone information gets lost when storing a value. -.. [16] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a +.. [15] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a native distinct data type for this mapping. Using this type with this vendor can therefore have implications on schema comparison (*online* vs *offline* schema) and PHP type safety (data conversion from database to PHP value) because it silently falls back to its appropriate Doctrine type. -.. [17] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. -.. [18] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. -.. [19] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. -.. [20] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. -.. [21] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** +.. [16] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. +.. [17] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. +.. [18] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. +.. [19] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. +.. [20] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** attribute array or is set to ``false``. -.. [22] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** +.. [21] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** attribute array and is set to ``true``. Detection of Database Types diff --git a/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php b/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php deleted file mode 100644 index 058bd19e2d0..00000000000 --- a/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php +++ /dev/null @@ -1,24 +0,0 @@ -constructPdoDsn($params), - $username, - $password, - $driverOptions - ); - } - - /** - * {@inheritdoc} - */ - public function createDatabasePlatformForVersion($version) - { - return $this->getDatabasePlatform(); - } - - /** - * {@inheritdoc} - */ - public function getDatabasePlatform() - { - return new DrizzlePlatform(); - } - - /** - * {@inheritdoc} - */ - public function getSchemaManager(\Doctrine\DBAL\Connection $conn) - { - return new DrizzleSchemaManager($conn); - } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'drizzle_pdo_mysql'; - } -} diff --git a/lib/Doctrine/DBAL/DriverManager.php b/lib/Doctrine/DBAL/DriverManager.php index d1e89372f6e..def881cc4d0 100644 --- a/lib/Doctrine/DBAL/DriverManager.php +++ b/lib/Doctrine/DBAL/DriverManager.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL; use Doctrine\Common\EventManager; -use Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver as DrizzlePDOMySQLDriver; use Doctrine\DBAL\Driver\IBMDB2\DB2Driver; use Doctrine\DBAL\Driver\Mysqli\Driver as MySQLiDriver; use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver; @@ -51,7 +50,6 @@ final class DriverManager 'ibm_db2' => DB2Driver::class, 'pdo_sqlsrv' => PDOSQLSrvDriver::class, 'mysqli' => MySQLiDriver::class, - 'drizzle_pdo_mysql' => DrizzlePDOMySQLDriver::class, 'sqlanywhere' => SQLAnywhereDriver::class, 'sqlsrv' => SQLSrvDriver::class, ]; diff --git a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php b/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php deleted file mode 100644 index 8ea51c27a24..00000000000 --- a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php +++ /dev/null @@ -1,623 +0,0 @@ -_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) - { - $autoinc = ''; - if (! empty($columnDef['autoincrement'])) { - $autoinc = ' AUTO_INCREMENT'; - } - - return $autoinc; - } - - /** - * {@inheritDoc} - */ - public function getBigIntTypeDeclarationSQL(array $field) - { - return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - public function getSmallIntTypeDeclarationSQL(array $field) - { - return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) - { - return $length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'; - } - - /** - * {@inheritdoc} - */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) - { - return 'VARBINARY(' . ($length ?: 255) . ')'; - } - - /** - * {@inheritDoc} - */ - protected function initializeDoctrineTypeMappings() - { - $this->doctrineTypeMapping = [ - 'boolean' => 'boolean', - 'varchar' => 'string', - 'varbinary' => 'binary', - 'integer' => 'integer', - 'blob' => 'blob', - 'decimal' => 'decimal', - 'datetime' => 'datetime', - 'date' => 'date', - 'time' => 'time', - 'text' => 'text', - 'timestamp' => 'datetime', - 'double' => 'float', - 'bigint' => 'bigint', - ]; - } - - /** - * {@inheritDoc} - */ - public function getClobTypeDeclarationSQL(array $field) - { - return 'TEXT'; - } - - /** - * {@inheritDoc} - */ - public function getBlobTypeDeclarationSQL(array $field) - { - return 'BLOB'; - } - - /** - * {@inheritDoc} - */ - public function getCreateDatabaseSQL($name) - { - return 'CREATE DATABASE ' . $name; - } - - /** - * {@inheritDoc} - */ - public function getDropDatabaseSQL($name) - { - return 'DROP DATABASE ' . $name; - } - - /** - * {@inheritDoc} - */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) - { - $queryFields = $this->getColumnDeclarationListSQL($columns); - - if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { - foreach ($options['uniqueConstraints'] as $index => $definition) { - $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); - } - } - - // add all indexes - if (isset($options['indexes']) && ! empty($options['indexes'])) { - foreach ($options['indexes'] as $index => $definition) { - $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); - } - } - - // attach all primary keys - if (isset($options['primary']) && ! empty($options['primary'])) { - $keyColumns = array_unique(array_values($options['primary'])); - $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; - } - - $query = 'CREATE '; - - if (! empty($options['temporary'])) { - $query .= 'TEMPORARY '; - } - - $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; - $query .= $this->buildTableOptions($options); - $query .= $this->buildPartitionOptions($options); - - $sql = [$query]; - - if (isset($options['foreignKeys'])) { - foreach ((array) $options['foreignKeys'] as $definition) { - $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); - } - } - - return $sql; - } - - /** - * Build SQL for table options - * - * @param mixed[] $options - * - * @return string - */ - private function buildTableOptions(array $options) - { - if (isset($options['table_options'])) { - return $options['table_options']; - } - - $tableOptions = []; - - // Collate - if (! isset($options['collate'])) { - $options['collate'] = 'utf8_unicode_ci'; - } - - $tableOptions[] = sprintf('COLLATE %s', $options['collate']); - - // Engine - if (! isset($options['engine'])) { - $options['engine'] = 'InnoDB'; - } - - $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); - - // Auto increment - if (isset($options['auto_increment'])) { - $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); - } - - // Comment - if (isset($options['comment'])) { - $comment = trim($options['comment'], " '"); - - $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($comment)); - } - - // Row format - if (isset($options['row_format'])) { - $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); - } - - return implode(' ', $tableOptions); - } - - /** - * Build SQL for partition options. - * - * @param mixed[] $options - * - * @return string - */ - private function buildPartitionOptions(array $options) - { - return isset($options['partition_options']) - ? ' ' . $options['partition_options'] - : ''; - } - - /** - * {@inheritDoc} - */ - public function getListDatabasesSQL() - { - return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'"; - } - - /** - * {@inheritDoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\DrizzleKeywords::class; - } - - /** - * {@inheritDoc} - */ - public function getListTablesSQL() - { - return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE' AND TABLE_SCHEMA=DATABASE()"; - } - - /** - * {@inheritDoc} - */ - public function getListTableColumnsSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return 'SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT,' . - ' NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME' . - ' FROM DATA_DICTIONARY.COLUMNS' . - ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME = ' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function getListTableForeignKeysSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return 'SELECT CONSTRAINT_NAME, CONSTRAINT_COLUMNS, REFERENCED_TABLE_NAME, REFERENCED_TABLE_COLUMNS, UPDATE_RULE, DELETE_RULE' . - ' FROM DATA_DICTIONARY.FOREIGN_KEYS' . - ' WHERE CONSTRAINT_SCHEMA=' . $databaseSQL . ' AND CONSTRAINT_TABLE=' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function getListTableIndexesSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return "SELECT INDEX_NAME AS 'key_name', COLUMN_NAME AS 'column_name', IS_USED_IN_PRIMARY AS 'primary', IS_UNIQUE=0 AS 'non_unique'" . - ' FROM DATA_DICTIONARY.INDEX_PARTS' . - ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME=' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function prefersIdentityColumns() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsIdentityColumns() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsInlineColumnComments() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsViews() - { - return false; - } - - /** - * {@inheritdoc} - */ - public function supportsColumnCollation() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function getDropIndexSQL($index, $table = null) - { - if ($index instanceof Index) { - $indexName = $index->getQuotedName($this); - } elseif (is_string($index)) { - $indexName = $index; - } else { - throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); - } - - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } elseif (! is_string($table)) { - throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } - - if ($index instanceof Index && $index->isPrimary()) { - // drizzle primary keys are always named "PRIMARY", - // so we cannot use them in statements because of them being keyword. - return $this->getDropPrimaryKeySQL($table); - } - - return 'DROP INDEX ' . $indexName . ' ON ' . $table; - } - - /** - * {@inheritDoc} - */ - protected function getDropPrimaryKeySQL($table) - { - return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; - } - - /** - * {@inheritDoc} - */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) - { - if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { - return 'TIMESTAMP'; - } - - return 'DATETIME'; - } - - /** - * {@inheritDoc} - */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) - { - return 'TIME'; - } - - /** - * {@inheritDoc} - */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) - { - return 'DATE'; - } - - /** - * {@inheritDoc} - */ - public function getAlterTableSQL(TableDiff $diff) - { - $columnSql = []; - $queryParts = []; - - $newName = $diff->getNewName(); - - if ($newName !== false) { - $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); - } - - foreach ($diff->addedColumns as $column) { - if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { - continue; - } - - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - foreach ($diff->removedColumns as $column) { - if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { - continue; - } - - $queryParts[] = 'DROP ' . $column->getQuotedName($this); - } - - foreach ($diff->changedColumns as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { - continue; - } - - $column = $columnDiff->column; - $columnArray = $column->toArray(); - - // Do not generate column alteration clause if type is binary and only fixed property has changed. - // Drizzle only supports binary type columns with variable length. - // Avoids unnecessary table alteration statements. - if ($columnArray['type'] instanceof BinaryType && - $columnDiff->hasChanged('fixed') && - count($columnDiff->changedProperties) === 1 - ) { - continue; - } - - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - foreach ($diff->renamedColumns as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } - - $oldColumnName = new Identifier($oldColumnName); - - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - $sql = []; - $tableSql = []; - - if (! $this->onSchemaAlterTable($diff, $tableSql)) { - if (count($queryParts) > 0) { - $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(', ', $queryParts); - } - $sql = array_merge( - $this->getPreAlterTableIndexForeignKeySQL($diff), - $sql, - $this->getPostAlterTableIndexForeignKeySQL($diff) - ); - } - - return array_merge($sql, $tableSql, $columnSql); - } - - /** - * {@inheritDoc} - */ - public function getDropTemporaryTableSQL($table) - { - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } elseif (! is_string($table)) { - throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } - - return 'DROP TEMPORARY TABLE ' . $table; - } - - /** - * {@inheritDoc} - */ - public function convertBooleans($item) - { - if (is_array($item)) { - foreach ($item as $key => $value) { - if (! is_bool($value) && ! is_numeric($value)) { - continue; - } - - $item[$key] = $value ? 'true' : 'false'; - } - } elseif (is_bool($item) || is_numeric($item)) { - $item = $item ? 'true' : 'false'; - } - - return $item; - } - - /** - * {@inheritDoc} - */ - public function getLocateExpression($str, $substr, $startPos = false) - { - if ($startPos === false) { - return 'LOCATE(' . $substr . ', ' . $str . ')'; - } - - return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; - } - - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'UUID()'; - } - - /** - * {@inheritDoc} - */ - public function getRegexpExpression() - { - return 'RLIKE'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php deleted file mode 100644 index 70f69f44b0b..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php +++ /dev/null @@ -1,326 +0,0 @@ -getDatabasePlatform()->getName() === 'sqlite') { $params['portability'] &= self::PORTABILITY_SQLITE; - } elseif ($this->getDatabasePlatform()->getName() === 'drizzle') { - $params['portability'] &= self::PORTABILITY_DRIZZLE; } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { $params['portability'] &= self::PORTABILITY_SQLANYWHERE; } elseif ($this->getDatabasePlatform()->getName() === 'db2') { diff --git a/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php b/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php deleted file mode 100644 index c334db2797b..00000000000 --- a/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php +++ /dev/null @@ -1,103 +0,0 @@ -_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); - $tableColumn['COLUMN_COMMENT'] = $this->removeDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); - - $options = [ - 'notnull' => ! (bool) $tableColumn['IS_NULLABLE'], - 'length' => (int) $tableColumn['CHARACTER_MAXIMUM_LENGTH'], - 'default' => $tableColumn['COLUMN_DEFAULT'] ?? null, - 'autoincrement' => (bool) $tableColumn['IS_AUTO_INCREMENT'], - 'scale' => (int) $tableColumn['NUMERIC_SCALE'], - 'precision' => (int) $tableColumn['NUMERIC_PRECISION'], - 'comment' => isset($tableColumn['COLUMN_COMMENT']) && $tableColumn['COLUMN_COMMENT'] !== '' - ? $tableColumn['COLUMN_COMMENT'] - : null, - ]; - - $column = new Column($tableColumn['COLUMN_NAME'], Type::getType($type), $options); - - if (! empty($tableColumn['COLLATION_NAME'])) { - $column->setPlatformOption('collation', $tableColumn['COLLATION_NAME']); - } - - return $column; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableDatabaseDefinition($database) - { - return $database['SCHEMA_NAME']; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableTableDefinition($table) - { - return $table['TABLE_NAME']; - } - - /** - * {@inheritdoc} - */ - public function _getPortableTableForeignKeyDefinition($tableForeignKey) - { - $columns = []; - foreach (explode(',', $tableForeignKey['CONSTRAINT_COLUMNS']) as $value) { - $columns[] = trim($value, ' `'); - } - - $refColumns = []; - foreach (explode(',', $tableForeignKey['REFERENCED_TABLE_COLUMNS']) as $value) { - $refColumns[] = trim($value, ' `'); - } - - return new ForeignKeyConstraint( - $columns, - $tableForeignKey['REFERENCED_TABLE_NAME'], - $refColumns, - $tableForeignKey['CONSTRAINT_NAME'], - [ - 'onUpdate' => $tableForeignKey['UPDATE_RULE'], - 'onDelete' => $tableForeignKey['DELETE_RULE'], - ] - ); - } - - /** - * {@inheritdoc} - */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) - { - $indexes = []; - foreach ($tableIndexes as $k) { - $k['primary'] = (bool) $k['primary']; - $indexes[] = $k; - } - - return parent::_getPortableTableIndexesList($indexes, $tableName); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php deleted file mode 100644 index 5af24b8454a..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php +++ /dev/null @@ -1,52 +0,0 @@ -driver->getName()); - } - - public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() : void - { - $this->markTestSkipped('This test does not work on Drizzle as it is not version aware.'); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } - - protected function createPlatform() : AbstractPlatform - { - return new DrizzlePlatform(); - } - - protected function createSchemaManager(Connection $connection) : AbstractSchemaManager - { - return new DrizzleSchemaManager($connection); - } - - /** - * @return mixed[][] - */ - protected function getDatabasePlatformsForVersions() : array - { - return [ - ['foo', DrizzlePlatform::class], - ['bar', DrizzlePlatform::class], - ['baz', DrizzlePlatform::class], - ]; - } -} diff --git a/tests/Doctrine/Tests/DBAL/DriverManagerTest.php b/tests/Doctrine/Tests/DBAL/DriverManagerTest.php index 08ed2f106ee..16b7f688be4 100644 --- a/tests/Doctrine/Tests/DBAL/DriverManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/DriverManagerTest.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Connections\MasterSlaveConnection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver; -use Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver as DrizzlePDOMySqlDriver; use Doctrine\DBAL\Driver\PDOMySql\Driver as PDOMySQLDriver; use Doctrine\DBAL\Driver\PDOSqlite\Driver as PDOSqliteDriver; use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver; @@ -308,17 +307,17 @@ public function databaseUrls() : iterable ], ], 'simple URL with fallthrough scheme containing underscores fails' => [ - 'drizzle_pdo_mysql://foo:bar@localhost/baz', + 'pdo_mysql://foo:bar@localhost/baz', false, ], 'simple URL with fallthrough scheme containing dashes works' => [ - 'drizzle-pdo-mysql://foo:bar@localhost/baz', + 'pdo-mysql://foo:bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', - 'driver' => DrizzlePDOMySqlDriver::class, + 'driver' => PDOMySQLDriver::class, ], ], 'simple URL with percent encoding' => [ diff --git a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php index 3b9649d5595..cd47e77f4f5 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Exception; -use Doctrine\DBAL\Platforms\DrizzlePlatform; use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; @@ -357,10 +356,6 @@ public function testConnectionException(array $params) : void $this->markTestSkipped('Only skipped if platform is not sqlite'); } - if ($platform instanceof DrizzlePlatform) { - $this->markTestSkipped('Drizzle does not always support authentication'); - } - if ($platform instanceof PostgreSqlPlatform && isset($params['password'])) { $this->markTestSkipped('Does not work on Travis'); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php deleted file mode 100644 index b1a47bc417c..00000000000 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php +++ /dev/null @@ -1,48 +0,0 @@ -addColumn('id', 'integer'); - $table->addColumn('column_varbinary', 'binary', []); - $table->addColumn('column_binary', 'binary', ['fixed' => true]); - $table->setPrimaryKey(['id']); - - $this->schemaManager->createTable($table); - - $table = $this->schemaManager->listTableDetails($tableName); - - self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType()); - self::assertFalse($table->getColumn('column_varbinary')->getFixed()); - - self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType()); - self::assertFalse($table->getColumn('column_binary')->getFixed()); - } - - public function testColumnCollation() : void - { - $table = new Table('test_collation'); - $table->addOption('collate', $collation = 'utf8_unicode_ci'); - $table->addColumn('id', 'integer'); - $table->addColumn('text', 'text'); - $table->addColumn('foo', 'text')->setPlatformOption('collation', 'utf8_swedish_ci'); - $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci'); - $this->schemaManager->dropAndCreateTable($table); - - $columns = $this->schemaManager->listTableColumns('test_collation'); - - self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions()); - self::assertEquals('utf8_unicode_ci', $columns['text']->getPlatformOption('collation')); - self::assertEquals('utf8_swedish_ci', $columns['foo']->getPlatformOption('collation')); - self::assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation')); - } -} From b10befc4068e2172e3fb65fec9acae22eba0cd81 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 7 Jun 2019 08:14:33 -0700 Subject: [PATCH 08/10] Remove support for sharding and the Azure platform --- docs/design/AZURE_FEDERATIONS.md | 94 ---- docs/design/SHARDING.md | 74 --- docs/en/reference/sharding.rst | 477 ------------------ docs/en/reference/sharding_azure_tutorial.rst | 423 ---------------- docs/en/sidebar.rst | 2 - docs/examples/sharding/README.md | 26 - docs/examples/sharding/bootstrap.php | 26 - docs/examples/sharding/composer.json | 6 - docs/examples/sharding/create_schema.php | 51 -- docs/examples/sharding/insert_data.php | 132 ----- .../sharding/insert_data_aftersplit.php | 27 - .../examples/sharding/query_filtering_off.php | 8 - docs/examples/sharding/query_filtering_on.php | 9 - docs/examples/sharding/split_federation.php | 5 - .../sharding/view_federation_members.php | 8 - lib/Doctrine/DBAL/DriverManager.php | 11 - .../DBAL/Platforms/SQLAzurePlatform.php | 35 -- .../DBAL/Sharding/PoolingShardConnection.php | 251 --------- .../DBAL/Sharding/PoolingShardManager.php | 103 ---- .../SQLAzureFederationsSynchronizer.php | 273 ---------- .../SQLAzure/SQLAzureShardManager.php | 210 -------- .../SQLAzure/Schema/MultiTenantVisitor.php | 150 ------ .../ShardChoser/MultiTenantShardChoser.php | 22 - .../DBAL/Sharding/ShardChoser/ShardChoser.php | 23 - lib/Doctrine/DBAL/Sharding/ShardManager.php | 76 --- .../DBAL/Sharding/ShardingException.php | 61 --- .../Doctrine/Tests/DBAL/DriverManagerTest.php | 38 -- .../DBAL/Platforms/SQLAzurePlatformTest.php | 31 -- .../Sharding/PoolingShardConnectionTest.php | 319 ------------ .../DBAL/Sharding/PoolingShardManagerTest.php | 148 ------ .../Sharding/SQLAzure/AbstractTestCase.php | 95 ---- .../DBAL/Sharding/SQLAzure/FunctionalTest.php | 45 -- .../SQLAzure/MultiTenantVisitorTest.php | 48 -- .../SQLAzureFederationsSynchronizerTest.php | 49 -- .../SQLAzure/SQLAzureShardManagerTest.php | 95 ---- .../MultiTenantShardChoserTest.php | 27 - 36 files changed, 3478 deletions(-) delete mode 100644 docs/design/AZURE_FEDERATIONS.md delete mode 100644 docs/design/SHARDING.md delete mode 100644 docs/en/reference/sharding.rst delete mode 100644 docs/en/reference/sharding_azure_tutorial.rst delete mode 100644 docs/examples/sharding/README.md delete mode 100644 docs/examples/sharding/bootstrap.php delete mode 100644 docs/examples/sharding/composer.json delete mode 100644 docs/examples/sharding/create_schema.php delete mode 100644 docs/examples/sharding/insert_data.php delete mode 100644 docs/examples/sharding/insert_data_aftersplit.php delete mode 100644 docs/examples/sharding/query_filtering_off.php delete mode 100644 docs/examples/sharding/query_filtering_on.php delete mode 100644 docs/examples/sharding/split_federation.php delete mode 100644 docs/examples/sharding/view_federation_members.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php delete mode 100644 lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php delete mode 100644 lib/Doctrine/DBAL/Sharding/PoolingShardManager.php delete mode 100644 lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php delete mode 100644 lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php delete mode 100644 lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php delete mode 100644 lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php delete mode 100644 lib/Doctrine/DBAL/Sharding/ShardChoser/ShardChoser.php delete mode 100644 lib/Doctrine/DBAL/Sharding/ShardManager.php delete mode 100644 lib/Doctrine/DBAL/Sharding/ShardingException.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php delete mode 100644 tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php diff --git a/docs/design/AZURE_FEDERATIONS.md b/docs/design/AZURE_FEDERATIONS.md deleted file mode 100644 index fda5591b105..00000000000 --- a/docs/design/AZURE_FEDERATIONS.md +++ /dev/null @@ -1,94 +0,0 @@ -# Azure Federations - -Implementing Federations inside a new Doctrine Sharding Extension. Some extensions to the DBAL and ORM core have to be done to get this working. - -1. DBAL (Database Abstraction Layer) - -* Add support for Database Schema Operations - * CREATE FEDERATION - * CREATE TABLE ... FEDERATED ON - * Add support to create a multi-tenant schema from any given schema -* Add API to pick a shard based on distribution key and atomic value -* Add API to ask about federations, federation members and so on. -* Add Sharding Abstraction - * If a shard is picked via distribution key and atomic value fire queries against this only - * Or query the global database. - -2. ORM (Object-Relational Mapper) - -* Federation Key has to be part of the clustered index of the table - * Test with a pure Multi-Tenant App with Filtering = ON (TaskList) - * Test with sharded app (Weather) - -## Implementation Details - -SQL Azure requires one and exactly one clustered index. It makes no difference if the primary key -or any other key is the clustered index. Sharding requires an external ID generation (no auto-increment) -such as GUIDs. GUIDs have negative properties with regard to clustered index performance, so that -typically you would add a "created" timestamp for example that holds the clustered index instead -of making the GUID a clustered index. - -## Example API: - - @@@ php - 'tcp:dbname.database.windows.net', - 'sharding' => array( - 'federationName' => 'Orders_Federation', - 'distributionKey' => 'CustID', - 'distributionType' => 'integer', - 'filteringEnabled' => false, - ), - // ... - ); - - $conn = DriverManager::getConnection($dbParams); - $shardManager = $conn->getShardManager(); - - // Example 1: query against root database - $sql = "SELECT * FROM Products"; - $rows = $conn->executeQuery($sql); - - // Example 2: query against the selected shard with CustomerId = 100 - $aCustomerID = 100; - $shardManager->selectShard($aCustomerID); // Using Default federationName and distributionKey - // Query: "USE FEDERATION Orders_Federation (CustID = $aCustomerID) WITH RESET, FILTERING OFF;" - - $sql = "SELECT * FROM Customers"; - $rows = $conn->executeQuery($sql); - - // Example 3: Reset API to root database again - $shardManager->selectGlobal(); - -## ID Generation - -With sharding all the ids have to be generated for global uniqueness. There are three strategies for this. - -1. Use GUIDs as described here http://blogs.msdn.com/b/cbiyikoglu/archive/2011/06/20/id-generation-in-federations-identity-sequences-and-guids-uniqueidentifier.aspx -2. Having a central table that is accessed with a second connection to generate sequential ids -3. Using natural keys from the domain. - -The second approach has the benefit of having numerical primary keys, however also a central failure location. The third strategy can seldom be used, because the domains don't allow this. Identity columns cannot be used at all. - - @@@ php - 'dbname.database.windows.net', - // ... - ); - $conn = DriverManager::getConnection($dbParams); - - $idGenerator = new TableHiLoIdGenerator($conn, 'id_table_name', $multiplicator = 1); - // only once, create this table - $idGenerator->createTable(); - - $nextId = $idGenerator->generateId('for_table_name'); - $nextOtherId = $idGenerator->generateId('for_other_table'); - -The connection for the table generator has to be a different one than the one used for the main app to avoid transaction clashes. diff --git a/docs/design/SHARDING.md b/docs/design/SHARDING.md deleted file mode 100644 index c5256b386d5..00000000000 --- a/docs/design/SHARDING.md +++ /dev/null @@ -1,74 +0,0 @@ -# Doctrine Shards - -Doctrine Extension to support horizontal sharding in the Doctrine ORM. - -## Idea - -Implement sharding inside Doctrine at a level that is as unobtrusive to the developer as possible. - -Problems to tackle: - -1. Where to send INSERT statements? -2. How to generate primary keys? -3. How to pick shards for update, delete statements? -4. How to pick shards for select operations? -5. How to merge select queries that span multiple shards? -6. How to handle/prevent multi-shard queries that cannot be merged (GROUP BY)? -7. How to handle non-sharded data? (static metadata tables for example) -8. How to handle multiple connections? -9. Implementation on the DBAL or ORM level? - -## Roadmap - -Version 1: DBAL 2.3 (Multi-Tenant Apps) - - 1. ID Generation support (in DBAL + ORM done) - 2. Multi-Tenant Support: Either pick a global metadata database or exactly one shard. - 3. Fan-out queries over all shards (or a subset) by result appending - -Version 2: ORM related (complex): - - 4. ID resolving (Pick shard for a new ID) - 5. Query resolving (Pick shards a query should send to) - 6. Shard resolving (Pick shards an ID could be on) - 7. Transactions - 8. Read Only objects - -## Technical Requirements for Database Schemas - -Sharded tables require the sharding-distribution key as one of their columns. This will affect your code compared to a normalized db-schema. If you have a Blog <-> BlogPost <-> PostComments entity setup sharded by `blog_id` then even the PostComment table needs this column, even if an "unsharded", normalized DB-Schema does not need this information. - -## Implementation Details - -Assumptions: - -* For querying you either want to query ALL or just exactly one shard. -* IDs for ALL sharded tables have to be unique across all shards. -* Non-sharded data is replicated between all shards. They redundantly keep the information available. This is necessary so join queries on shards to reference data work. -* If you retrieve an object A from a shard, then all references and collections of this object reside on the same shard. -* The database schema on all shards is the same (or compatible) - -### SQL Azure Federations - -SQL Azure is a special case, points 1, 2, 3, 4, 7 and 8 are partly handled on the database level. This makes it a perfect test-implementation for just the subset of features in points 5-6. However there needs to be a way to configure SchemaTool to generate the correct Schema on SQL Azure. - -* SELECT Operations: The most simple assumption is to always query all shards unless the user specifies otherwise explicitly. -* Queries can be merged in PHP code, this obviously does not work for DISTINCT, GROUP BY and ORDER BY queries. - -### Generic Sharding - -More features are necessary to implement sharding on the PHP level, independent from database support: - -1. Configuration of multiple connections, one connection = one shard. -2. Primary Key Generation mechanisms (UUID, central table, sequence emulation) - -## Primary Use-Cases - -1. Multi-Tenant Applications - -These are easier to support as you have some value to determine the shard id for the whole request very early on. -Here also queries can always be limited to a single shard. - -2. Scale-Out by some attribute (Round-Robin?) - -This strategy requires access to multiple shards in a single request based on the data accessed. diff --git a/docs/en/reference/sharding.rst b/docs/en/reference/sharding.rst deleted file mode 100644 index 2b2f804da53..00000000000 --- a/docs/en/reference/sharding.rst +++ /dev/null @@ -1,477 +0,0 @@ -Sharding -======== - -.. note:: - - The sharding extension is currently in transition from a separate Project - into DBAL. Class names may differ. - -Starting with 2.3 Doctrine DBAL contains some functionality to simplify the -development of horizontally sharded applications. In this first release it -contains a ``ShardManager`` interface. This interface allows to programatically -select a shard to send queries to. At the moment there are no functionalities -yet to dynamically pick a shard based on ID, query or database row yet. That -means the sharding extension is primarily suited for: - -- multi-tenant applications or -- applications with completely separated datasets (example: weather data). - -Both kind of application will work with both DBAL and ORM. - -.. note:: - - Horizontal sharding is an evasive architecture that will affect your application code and using this - extension to Doctrine will not make it work "magically". - -You have to understand and integrate the following drawbacks: - -- Pre-generation of IDs that are unique across all shards required. -- No transaction support across shards. -- No foreign key support across shards (meaning no "real" relations). -- Very complex (or impossible) to query aggregates across shards. -- Denormalization: Composite keys required where normalized non-sharded db schemas don't need them. -- Schema Operations have to be done on all shards. - -The primary questions in a sharding architecture are: - -* Where is my data located? -* Where should I save this new data to find it later? - -To answer these questions you generally have to craft a function that will tell -you for a given ID, on which shard the data for this ID is located. To simplify -this approach you will generally just pick a table which is the root of a set of -related data and decide for the IDs of this table. All the related data that -belong to this table are saved on the same shard. - -Take for example a multi-user blog application with the following tables: - -- Blog [id, name] -- Post [id, blog_id, subject, body, author_id] -- Comment [id, post_id, comment, author_id] -- User [id, username] - -A sensible sharding architecture will split the application by blog. That means -all the data for a particular blog will be on a single shard and scaling is -done by putting the amount of blogs on many different database servers. - -Now users can post and comment on different blogs that reside on different -shards. This makes the database schema above slightly tricky, because both -`author_id` columns cannot have foreign keys to `User (id)`. Instead the User -table is located in an entirely different "dimension" of the application in -terms of the sharding architecture. - -To simplify working with this kind of multi-dimensional database schema, you -can replace the author_ids with something more "meaningful", for example the -e-mail address of the users if that is always known. The "user" table can then -be separated from the database schema above and put on a second horizontally -scaled sharding architecture. - -As you can see, even with just the four tables above, sharding actually becomes -quite complex to think about. - -The rest of this section discusses Doctrine sharding functionality in technical -detail. - -ID Generation -------------- - -To solve the issue of unique ID-generation across all shards are several -approaches you should evaluate: - -Use GUID/UUIDs -~~~~~~~~~~~~~~ - -The most simple ID-generation mechanism for sharding are -universally unique identifiers. These are 16-byte -(128-bit) numbers that are guaranteed to be unique across different servers. -You can `read up on UUIDs on Wikipedia `_. - -The drawback of UUIDs is the segmentation they cause on indexes. Because UUIDs -are not sequentially generated, they can have negative impact on index access -performance. Additionally they are much bigger -than numerical primary keys (which are normally 4-bytes in length). - -At the moment Doctrine DBAL drivers MySQL and SQL Server support the generation -of UUID/GUIDs. You can use the following bit of code to generate them across -platforms: - -.. code-block:: php - - insert('my_table', [ - 'id' => $guid->toString(), - 'foo' => 'bar', - ]); - -In your application you should hide this details in Id-Generation services: - -.. code-block:: php - - `_. - -Table Generator -~~~~~~~~~~~~~~~ - -In some scenarios there is no way around a numerical, automatically -incrementing id. The way Auto incrementing IDs are implemented in MySQL and SQL -Server however is completely unsuitable for sharding. Remember in a sharding -architecture you have to know where the row for a specific ID is located and -IDs have to be globally unique across all servers. Auto-Increment Primary Keys -are missing both properties. - -To get around this issue you can use the so-called "table-generator" strategy. -In this case you define a single database that is responsible for the -generation of auto-incremented ids. You create a table on this database and -through the use of locking create new sequential ids. - -There are three important drawbacks to this strategy: - -- Single point of failure -- Bottleneck when application is write-heavy -- A second independent database connection is needed to guarantee transaction - safety. - -If you can live with this drawbacks then you can use table-generation with the -following code in Doctrine: - -.. code-block:: php - - nextValue("sequence_name1"); - $id2 = $tableGenerator->nextValue("sequence_name2"); - -The table generator obviously needs a table to work. The schema of this table -is described in the ``TableGenerator`` class-docblock. Alternatively you -can use the ``Doctrine\DBAL\Id\TableGeneratorSchemaVisitor`` and apply it to your -``Doctrine\DBAL\Schema\Schema`` instance. It will automatically add the required -sequence table. - -Natural Identifiers -~~~~~~~~~~~~~~~~~~~ - -Sometimes you are lucky and your application data-model comes with a natural -id. This is mostly the case for applications who get their IDs generated -somewhere else (exogeneous ID-generation) or that work with temporal data. In -that case you can just define the natural primary key and shard your -application based on this data. - -Transactions ------------- - -Transactions in sharding can only work for data that is located on a single -shard. If you need transactions in your sharding architecture then you have to -make sure that the data updated during a transaction is located on a single -shard. - -Foreign Keys ------------- - -Since you cannot create foreign keys between remote database servers, in a -sharding architecture you should put the data on a shard that belongs to each -other. But even if you can isolate most of the rows on a single shard there may -exist relations between tables that exist on different shards. In this case -your application should be aware of the potential inconsistencies and handle -them graciously. - -Complex Queries ---------------- - -GROUP BY, DISTINCT and ORDER BY are clauses that cannot be easily used in a -sharding architecture. If you have to execute these queries against multiple -shards then you cannot just append the different results to each other. - -You have to be aware of this problem and design your queries accordingly or -shard the data in a way that you never have to query multiple shards to -calculate a result. - -ShardManager Interface ----------------------- - -The central API of the sharding extension is the ``ShardManager`` interface. -It contains two different groups of functions with regard to sharding. - -First, it contains the Shard Selection API. You can pick a shard based on a -so-called "distribution-value" or reset the connection to the "global" shard, -a necessary database that often contains heavily cached, sharding independent -data such as meta tables or the "user/tenant" table. - -.. code-block:: php - - array( - 'federationName' => 'my_database', - 'distributionKey' => 'customer_id', - ) - )); - $shardManager = new SQLAzureShardManager($conn); - - $currentCustomerId = 1234; - $shardManager->selectShard($currentCustomerId); - // all queries after this call hit the shard - // where customer with id 1234 is on. - - $shardManager->selectGlobal(); - // the global database is selected. - -To access the currently selected distribution value use the following API -method: - -.. code-block:: php - - getCurrentDistributionValue(); - -The shard manager will prevent you switching shards when a transaction is open. -This is especially important when using sharding with the ORM. Because the ORM -uses a single transaction during the flush-operation this means that you can -only ever use one ``EntityManager`` with data from a single shard. - -The second API is the "fan-out" query API. This allows you to execute queries against -ALL shards. The order of the results of this operation is undefined, that means -your query has to return the data in a way that works for the application, or -you have to sort the data in the application. - -.. code-block:: php - - queryAll($sql, $params); - -Schema Operations: SchemaSynchronizer Interface ------------------------------------------------ - -Schema Operations in a sharding architecture are tricky. You have to perform -them on all databases instances (shards) at the same time. Also Doctrine -has problems with this in particular as you cannot generate an SQL file with -changes on any development machine anymore and apply this on production. The -required changes depend on the amount of shards. - -To allow the Doctrine Schema API operations on a sharding architecture we -performed a refactored from code inside ORM ``Doctrine\ORM\Tools\SchemaTool`` -class and extracted the code for operations on Schema instances into a new -``Doctrine\Shards\DBAL\SchemaSynchronizer`` interface. - -Every sharding implementation can implement this interface and allow schema -operations to take part on multiple shards. - -SQL Azure Federations ---------------------- - -Doctrine Shards ships with a custom implementation for Microsoft SQL -Azure. The Azure platform provides a native sharding functionality. In SQL -Azure the sharding functionality is called Federations. This -functionality applies the following restrictions (in line with the ones listed -above): - -- IDENTITY columns are not allowed on sharded tables (federated tables) -- Each table may only have exactly one clustered index and this index has to - have the distribution key/sharding-id as one column. -- Every unique index (or primary key) has to contain the - distribution-key/sharding-id. - -Especially the requirements 2 and 3 prevent normalized database schemas. You -have to put the distribution key on every sharded table, which can affect your -application code quite a bit. This may lead to the creation of composite keys -where you normally wouldn't need them. - -The benefit of SQL Azure Federations is that they implement all the -shard-picking logic on the server. You only have to make use of the ``USE -FEDERATION`` statement. You don't have to maintain a list of all the shards -inside your application and more importantly, resizing shards is done -transparently on the server. - -Features of SQL Azure are: - -- Central server to log into federations architecture. No need to know all - connection details of all shards. -- Database level operation to split shards, taking away the tediousness of this - operation for application developers. -- A global tablespace that can contain global data to all shards. -- One or many different federations (this library only supports working with - one) -- Sharded or non-sharded tables inside federations -- Allows filtering SELECT queries on the database based on the selected - sharding key value. This allows to implement sharded Multi-Tenant Apps very easily. - -To setup an SQL Azure ShardManager use the following code: - -.. code-block:: php - - 'my_database', - 'host' => 'tcp:dbname.windows.net', - 'user' => 'user@dbname', - 'password' => 'XXX', - 'sharding' => array( - 'federationName' => 'my_federation', - 'distributionKey' => 'customer_id', - 'distributionType' => 'integer', - ) - )); - $shardManager = new SQLAzureShardManager($conn); - -Currently you are limited to one federation in your application. - -You can inspect all the currently known shards on SQL Azure using the -``ShardManager#getShards()`` function: - -.. code-block:: php - - getShards() as $shard) { - echo $shard['id'] . " " . $shard['rangeLow'] . " - " . $shard['rangeHigh']; - } - -Schema Operations -~~~~~~~~~~~~~~~~~ - -Schema Operations on SQL Azure Federations are possible with the -``SQLAzureSchemaSynchronizer``. You can instantiate this from your code: - -.. code-block:: php - - createTable('Users'); - //... - - // marked as sharded, but no distribution column given: - // non-federated table inside the federation - $products = $schema->createTable('Products'); - $products->addOption('azure.federated', true); - //... - - // shared + distribution column: - // federated table - $customers = $schema->createTable('Customers'); - $customers->addColumn('CustomerID', 'integer'); - //... - $customers->addOption('azure.federated', true); - $customers->addOption('azure.federatedOnColumnName', 'CustomerID'); - -SQLAzure Filtering -~~~~~~~~~~~~~~~~~~ - -SQL Azure comes with a powerful filtering feature, that allows you to -automatically implement a multi-tenant application for a formerly single-tenant -application. The restriction to make this work is that your application does not work with -IDENTITY columns. - -Normally when you select a shard using ``ShardManager#selectShard()`` any query -executed against this shard will return data from ALL the tenants located on -this shard. With the "FILTERING=ON" flag on the ``USE FEDERATION`` query -however SQL Azure can automatically filter all SELECT queries with the chosen -distribution value. Additionally you can automatically set the currently -selected distribution value in every INSERT statement using a function for this -value as the ``DEFAULT`` part of the column. If you are using GUIDs for every -row then UPDATE and DELETE statements using only GUIDs will work out perfectly -as well, as they are by definition for unique rows. This feature allows you to -build multi-tenant applications, even though they were not originally designed -that way. - -To enable filtering you can use the -``SQLAzureShardManager#setFilteringEnabled()`` method. This method is not part -of the interface. You can also set a default value for filtering by passing it -as the "sharding.filteringEnabled" parameter to -``DriverManager#getConnection()``. - -Generic SQL Sharding Support ----------------------------- - -Besides the custom SQL Azure support there is a generic implementation that -works with all database drivers. It requires to specify all database -connections and will switch between the different connections under the hood -when using the ``ShardManager`` API. This is also the biggest drawback of this -approach, since fan-out queries need to connect to all databases in a single -request. - -See the configuration for a sample sharding connection: - -.. code-block:: php - - 'Doctrine\DBAL\Sharding\PoolingShardConnection', - 'driver' => 'pdo_sqlite', - 'global' => array('memory' => true), - 'shards' => array( - array('id' => 1, 'memory' => true), - array('id' => 2, 'memory' => true), - ), - 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', - )); - -You have to configure the following options: - -- 'wrapperClass' - Selecting the PoolingShardConnection as above. -- 'global' - An array of database parameters that is used for connecting to the - global database. -- 'shards' - An array of shard database parameters. You have to specify an - 'id' parameter for each of the shard configurations. -- 'shardChoser' - Implementation of the - ``Doctrine\Shards\DBAL\ShardChoser\ShardChoser`` interface. - -The Shard Choser interface maps the distribution value to a shard-id. This -gives you the freedom to implement your own strategy for sharding the data -horizontally. diff --git a/docs/en/reference/sharding_azure_tutorial.rst b/docs/en/reference/sharding_azure_tutorial.rst deleted file mode 100644 index 71a4fab5594..00000000000 --- a/docs/en/reference/sharding_azure_tutorial.rst +++ /dev/null @@ -1,423 +0,0 @@ -SQLAzure Sharding Tutorial -========================== - -.. note:: - - The sharding extension is currently in transition from a separate Project - into DBAL. Class names may differ. - -This tutorial builds upon the `Brian Swans tutorial `_ -on SQLAzure Sharding and turns all the examples into examples using the Doctrine Sharding support. - -It introduces SQL Azure Sharding, which is an abstraction layer in SQL Azure to -support sharding. Many features for sharding are implemented on the database -level, which makes it much easier to work with than generic sharding -implementations. - -For this tutorial you need an Azure account. You don't need to deploy the code -on Azure, you can run it from your own machine against the remote database. - -.. note:: - - You can look at the code from the 'examples/sharding' directory. - -Install Doctrine ----------------- - -For this tutorial we will install Doctrine and the Sharding Extension through -`Composer `_ which is the easiest way to install -Doctrine. Composer is a new package manager for PHP. Download the -``composer.phar`` from their website and put it into a newly created folder for -this tutorial. Now create a ``composer.json`` file in this project root with -the following content: - - { - "require": { - "doctrine/dbal": "2.2.2", - "doctrine/shards": "0.2" - } - } - -Open up the commandline and switch to your tutorial root directory, then call -``php composer.phar install``. It will grab the code and install it into the -``vendor`` subdirectory of your project. It also creates an autoloader, so that -we don't have to care about this. - -Setup Connection ----------------- - -The first thing to start with is setting up Doctrine and the database connection: - -.. code-block:: php - - 'pdo_sqlsrv', - 'dbname' => 'SalesDB', - 'host' => 'tcp:dbname.windows.net', - 'user' => 'user@dbname', - 'password' => 'XXX', - 'platform' => new \Doctrine\DBAL\Platforms\SQLAzurePlatform(), - 'driverOptions' => array('MultipleActiveResultSets' => false), - 'sharding' => array( - 'federationName' => 'Orders_Federation', - 'distributionKey' => 'CustId', - 'distributionType' => 'integer', - ) - )); - - $shardManager = new SQLAzureShardManager($conn); - -Create Database ---------------- - -Create a new database using the Azure/SQL Azure management console. - -Create Schema -------------- - -Doctrine has a powerful schema API. We don't need to use low-level DDL -statements to generate the database schema. Instead you can use an Object-Oriented API -to create the database schema and then have Doctrine turn it into DDL -statements. - -We will recreate Brians example schema with Doctrine DBAL. Instead of having to -create federations and schema separately as in his example, Doctrine will do it -all in one step: - -.. code-block:: php - - createTable('Products'); - $products->addColumn('ProductID', 'integer'); - $products->addColumn('SupplierID', 'integer'); - $products->addColumn('ProductName', 'string'); - $products->addColumn('Price', 'decimal', array('scale' => 2, 'precision' => 12)); - $products->setPrimaryKey(array('ProductID')); - $products->addOption('azure.federated', true); - - $customers = $schema->createTable('Customers'); - $customers->addColumn('CustomerID', 'integer'); - $customers->addColumn('CompanyName', 'string'); - $customers->addColumn('FirstName', 'string'); - $customers->addColumn('LastName', 'string'); - $customers->setPrimaryKey(array('CustomerID')); - $customers->addOption('azure.federated', true); - $customers->addOption('azure.federatedOnColumnName', 'CustomerID'); - - $orders = $schema->createTable('Orders'); - $orders->addColumn('CustomerID', 'integer'); - $orders->addColumn('OrderID', 'integer'); - $orders->addColumn('OrderDate', 'datetime'); - $orders->setPrimaryKey(array('CustomerID', 'OrderID')); - $orders->addOption('azure.federated', true); - $orders->addOption('azure.federatedOnColumnName', 'CustomerID'); - - $orderItems = $schema->createTable('OrderItems'); - $orderItems->addColumn('CustomerID', 'integer'); - $orderItems->addColumn('OrderID', 'integer'); - $orderItems->addColumn('ProductID', 'integer'); - $orderItems->addColumn('Quantity', 'integer'); - $orderItems->setPrimaryKey(array('CustomerID', 'OrderID', 'ProductID')); - $orderItems->addOption('azure.federated', true); - $orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); - - // Create the Schema + Federation: - $synchronizer = new SQLAzureSchemaSynchronizer($conn, $shardManager); - $synchronizer->createSchema($schema); - - // Or jut look at the SQL: - echo implode("\n", $synchronizer->getCreateSchema($schema)); - -View Federation Members ------------------------ - -To see how many shard instances (called Federation Members) your SQLAzure database currently has -you can ask the ``ShardManager`` to enumerate all shards: - -.. code-block:: php - - getShards(); - foreach ($shards as $shard) { - print_r($shard); - } - -Insert Data ------------ - -Now we want to insert some test data into the database to see the behavior when -we split the shards. We use the same test data as Brian, but use the Doctrine -API to insert them. To insert data into federated tables we have to select the -shard we want to put the data into. We can use the ShardManager to execute this -operation for us: - -.. code-block:: php - - selectShard(0); - - $conn->insert("Products", array( - "ProductID" => 386, - "SupplierID" => 1001, - "ProductName" => 'Titanium Extension Bracket Left Hand', - "Price" => 5.25, - )); - $conn->insert("Products", array( - "ProductID" => 387, - "SupplierID" => 1001, - "ProductName" => 'Titanium Extension Bracket Right Hand', - "Price" => 5.25, - )); - $conn->insert("Products", array( - "ProductID" => 388, - "SupplierID" => 1001, - "ProductName" => 'Fusion Generator Module 5 kV', - "Price" => 10.50, - )); - $conn->insert("Products", array( - "ProductID" => 388, - "SupplierID" => 1001, - "ProductName" => 'Bypass Filter 400 MHz Low Pass', - "Price" => 10.50, - )); - - $conn->insert("Customers", array( - 'CustomerID' => 10, - 'CompanyName' => 'Van Nuys', - 'FirstName' => 'Catherine', - 'LastName' => 'Abel', - )); - $conn->insert("Customers", array( - 'CustomerID' => 20, - 'CompanyName' => 'Abercrombie', - 'FirstName' => 'Kim', - 'LastName' => 'Branch', - )); - $conn->insert("Customers", array( - 'CustomerID' => 30, - 'CompanyName' => 'Contoso', - 'FirstName' => 'Frances', - 'LastName' => 'Adams', - )); - $conn->insert("Customers", array( - 'CustomerID' => 40, - 'CompanyName' => 'A. Datum Corporation', - 'FirstName' => 'Mark', - 'LastName' => 'Harrington', - )); - $conn->insert("Customers", array( - 'CustomerID' => 50, - 'CompanyName' => 'Adventure Works', - 'FirstName' => 'Keith', - 'LastName' => 'Harris', - )); - $conn->insert("Customers", array( - 'CustomerID' => 60, - 'CompanyName' => 'Alpine Ski House', - 'FirstName' => 'Wilson', - 'LastName' => 'Pais', - )); - $conn->insert("Customers", array( - 'CustomerID' => 70, - 'CompanyName' => 'Baldwin Museum of Science', - 'FirstName' => 'Roger', - 'LastName' => 'Harui', - )); - $conn->insert("Customers", array( - 'CustomerID' => 80, - 'CompanyName' => 'Blue Yonder Airlines', - 'FirstName' => 'Pilar', - 'LastName' => 'Pinilla', - )); - $conn->insert("Customers", array( - 'CustomerID' => 90, - 'CompanyName' => 'City Power & Light', - 'FirstName' => 'Kari', - 'LastName' => 'Hensien', - )); - $conn->insert("Customers", array( - 'CustomerID' => 100, - 'CompanyName' => 'Coho Winery', - 'FirstName' => 'Peter', - 'LastName' => 'Brehm', - )); - - $conn->executeUpdate("DECLARE @orderId INT - - DECLARE @customerId INT - - SET @orderId = 10 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Hensien' and FirstName = 'Kari' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 388, 4) - - SET @orderId = 20 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Harui' and FirstName = 'Roger' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 389, 2) - - SET @orderId = 30 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Brehm' and FirstName = 'Peter' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 387, 3) - - SET @orderId = 40 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Pais' and FirstName = 'Wilson' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 388, 1)" - ); - -This puts the data into the currently only existing federation member. We -selected that federation member by picking 0 as distribution value, which is by -definition part of the only existing federation. - -Split Federation ----------------- - -Now lets split the federation, creating a second federation member. SQL Azure -will automatically redistribute the data into the two federations after you -executed this command. - -.. code-block:: php - - splitFederation(60); - -This little script uses the shard manager with a special method only existing -on the SQL AZure implementation ``splitFederation``. It accepts a value at -at which the split is executed. - -If you reexecute the ``view_federation_members.php`` script you can now see -that there are two federation members instead of just one as before. You can -see with the ``rangeLow`` and ``rangeHigh`` parameters what customers and -related entries are now served by which federation. - -Inserting Data after Split --------------------------- - -Now after we splitted the data we now have to make sure to be connected to the -right federation before inserting data. Lets add a new customer with ID 55 and -have him create an order. - -.. code-block:: php - - selectShard($newCustomerId); - - $conn->insert("Customers", array( - "CustomerID" => $newCustomerId, - "CompanyName" => "Microsoft", - "FirstName" => "Brian", - "LastName" => "Swan", - )); - - $conn->insert("Orders", array( - "CustomerID" => 55, - "OrderID" => 37, - "OrderDate" => date('Y-m-d H:i:s'), - )); - - $conn->insert("OrderItems", array( - "CustomerID" => 55, - "OrderID" => 37, - "ProductID" => 387, - "Quantity" => 1, - )); - -As you can see its very important to pick the right distribution key in your -sharded application. Otherwise you have to switch the shards very often, which -is not really easy to work with. If you pick the sharding key right then it -should be possible to select the shard only once per request for the major -number of use-cases. - -Fan-out the queries accross multiple shards should only be necessary for a -small number of queries, because these kind of queries are complex. - -Querying data with filtering off --------------------------------- - -To access the data you have to pick a shard again and then start selecting data -from it. - -.. code-block:: php - - selectShard(0); - - $data = $conn->fetchAll('SELECT * FROM Customers'); - print_r($data); - -This returns all customers from the shard with distribution value 0. This will -be all customers with id 10 to less than 60, since we split federations at 60. - -Querying data with filtering on -------------------------------- - -One special feature of SQL Azure is the possibility to database level filtering -based on the sharding distribution values. This means that SQL Azure will add -WHERE clauses with distributionkey=current distribution value conditions to -each distribution key. - -.. code-block:: php - - setFilteringEnabled(true); - $shardManager->selectShard(55); - - $data = $conn->fetchAll('SELECT * FROM Customers'); - print_r($data); - -Now you only get the customer with id = 55. The same holds for queries on the -``Orders`` and ``OrderItems`` table, which are restricted by customer id = 55. - diff --git a/docs/en/sidebar.rst b/docs/en/sidebar.rst index 0935c8dc179..c053421724a 100644 --- a/docs/en/sidebar.rst +++ b/docs/en/sidebar.rst @@ -13,8 +13,6 @@ reference/schema-representation reference/events reference/security - reference/sharding - reference/sharding_azure_tutorial reference/supporting-other-databases reference/portability reference/caching diff --git a/docs/examples/sharding/README.md b/docs/examples/sharding/README.md deleted file mode 100644 index 3680e544f40..00000000000 --- a/docs/examples/sharding/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Sharding with SQLAzure Example - -This example demonstrates Sharding with SQL Azure Federations. - -## Requirements - -1. Windows Azure Account -2. SQL Azure Database -3. Composer for dependencies - -## Install - - composer install - -Change "examples/sharding/bootstrap.php" to contain Database connection. - -## Order to execute Scripts - -1. create_schema.php -2. view_federation_members.php -3. insert_data.php -4. split_federation.php -5. insert_data_after_split.php -6. query_filtering_off.php -7. query_filtering_on.php - diff --git a/docs/examples/sharding/bootstrap.php b/docs/examples/sharding/bootstrap.php deleted file mode 100644 index fe174f1c1b7..00000000000 --- a/docs/examples/sharding/bootstrap.php +++ /dev/null @@ -1,26 +0,0 @@ - 'SalesDB', - 'host' => 'tcp:dbname.windows.net', - 'user' => 'user@dbname', - 'password' => 'XXX', - 'sharding' => array( - 'federationName' => 'Orders_Federation', - 'distributionKey' => 'CustId', - 'distributionType' => 'integer', - ) -); - -if ($config['host'] == "tcp:dbname.windows.net") { - die("You have to change the configuration to your Azure account.\n"); -} - -$conn = DriverManager::getConnection($config); -$shardManager = new SQLAzureShardManager($conn); - diff --git a/docs/examples/sharding/composer.json b/docs/examples/sharding/composer.json deleted file mode 100644 index 214f922178e..00000000000 --- a/docs/examples/sharding/composer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "require": { - "doctrine/dbal": "*", - "doctrine/shards": "0.3" - } -} diff --git a/docs/examples/sharding/create_schema.php b/docs/examples/sharding/create_schema.php deleted file mode 100644 index afdf7cbacf7..00000000000 --- a/docs/examples/sharding/create_schema.php +++ /dev/null @@ -1,51 +0,0 @@ -createTable('Products'); -$products->addColumn('ProductID', 'integer'); -$products->addColumn('SupplierID', 'integer'); -$products->addColumn('ProductName', 'string'); -$products->addColumn('Price', 'decimal', array('scale' => 2, 'precision' => 12)); -$products->setPrimaryKey(array('ProductID')); -$products->addOption('azure.federated', true); - -$customers = $schema->createTable('Customers'); -$customers->addColumn('CustomerID', 'integer'); -$customers->addColumn('CompanyName', 'string'); -$customers->addColumn('FirstName', 'string'); -$customers->addColumn('LastName', 'string'); -$customers->setPrimaryKey(array('CustomerID')); -$customers->addOption('azure.federated', true); -$customers->addOption('azure.federatedOnColumnName', 'CustomerID'); - -$orders = $schema->createTable('Orders'); -$orders->addColumn('CustomerID', 'integer'); -$orders->addColumn('OrderID', 'integer'); -$orders->addColumn('OrderDate', 'datetime'); -$orders->setPrimaryKey(array('CustomerID', 'OrderID')); -$orders->addOption('azure.federated', true); -$orders->addOption('azure.federatedOnColumnName', 'CustomerID'); - -$orderItems = $schema->createTable('OrderItems'); -$orderItems->addColumn('CustomerID', 'integer'); -$orderItems->addColumn('OrderID', 'integer'); -$orderItems->addColumn('ProductID', 'integer'); -$orderItems->addColumn('Quantity', 'integer'); -$orderItems->setPrimaryKey(array('CustomerID', 'OrderID', 'ProductID')); -$orderItems->addOption('azure.federated', true); -$orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); - -// Create the Schema + Federation: -$synchronizer = new SQLAzureSchemaSynchronizer($conn, $shardManager); - -// Or just look at the SQL: -echo implode("\n", $synchronizer->getCreateSchema($schema)); - -$synchronizer->createSchema($schema); - diff --git a/docs/examples/sharding/insert_data.php b/docs/examples/sharding/insert_data.php deleted file mode 100644 index 57aeda6c9f8..00000000000 --- a/docs/examples/sharding/insert_data.php +++ /dev/null @@ -1,132 +0,0 @@ -selectShard(0); - -$conn->insert("Products", array( - "ProductID" => 386, - "SupplierID" => 1001, - "ProductName" => 'Titanium Extension Bracket Left Hand', - "Price" => 5.25, -)); -$conn->insert("Products", array( - "ProductID" => 387, - "SupplierID" => 1001, - "ProductName" => 'Titanium Extension Bracket Right Hand', - "Price" => 5.25, -)); -$conn->insert("Products", array( - "ProductID" => 388, - "SupplierID" => 1001, - "ProductName" => 'Fusion Generator Module 5 kV', - "Price" => 10.50, -)); -$conn->insert("Products", array( - "ProductID" => 389, - "SupplierID" => 1001, - "ProductName" => 'Bypass Filter 400 MHz Low Pass', - "Price" => 10.50, -)); - -$conn->insert("Customers", array( - 'CustomerID' => 10, - 'CompanyName' => 'Van Nuys', - 'FirstName' => 'Catherine', - 'LastName' => 'Abel', -)); -$conn->insert("Customers", array( - 'CustomerID' => 20, - 'CompanyName' => 'Abercrombie', - 'FirstName' => 'Kim', - 'LastName' => 'Branch', -)); -$conn->insert("Customers", array( - 'CustomerID' => 30, - 'CompanyName' => 'Contoso', - 'FirstName' => 'Frances', - 'LastName' => 'Adams', -)); -$conn->insert("Customers", array( - 'CustomerID' => 40, - 'CompanyName' => 'A. Datum Corporation', - 'FirstName' => 'Mark', - 'LastName' => 'Harrington', -)); -$conn->insert("Customers", array( - 'CustomerID' => 50, - 'CompanyName' => 'Adventure Works', - 'FirstName' => 'Keith', - 'LastName' => 'Harris', -)); -$conn->insert("Customers", array( - 'CustomerID' => 60, - 'CompanyName' => 'Alpine Ski House', - 'FirstName' => 'Wilson', - 'LastName' => 'Pais', -)); -$conn->insert("Customers", array( - 'CustomerID' => 70, - 'CompanyName' => 'Baldwin Museum of Science', - 'FirstName' => 'Roger', - 'LastName' => 'Harui', -)); -$conn->insert("Customers", array( - 'CustomerID' => 80, - 'CompanyName' => 'Blue Yonder Airlines', - 'FirstName' => 'Pilar', - 'LastName' => 'Pinilla', -)); -$conn->insert("Customers", array( - 'CustomerID' => 90, - 'CompanyName' => 'City Power & Light', - 'FirstName' => 'Kari', - 'LastName' => 'Hensien', -)); -$conn->insert("Customers", array( - 'CustomerID' => 100, - 'CompanyName' => 'Coho Winery', - 'FirstName' => 'Peter', - 'LastName' => 'Brehm', -)); - -$conn->executeUpdate(" - DECLARE @orderId INT - - DECLARE @customerId INT - - SET @orderId = 10 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Hensien' and FirstName = 'Kari' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 388, 4) - - SET @orderId = 20 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Harui' and FirstName = 'Roger' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 389, 2) - - SET @orderId = 30 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Brehm' and FirstName = 'Peter' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 387, 3) - - SET @orderId = 40 - SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Pais' and FirstName = 'Wilson' - - INSERT INTO Orders (CustomerId, OrderId, OrderDate) - VALUES (@customerId, @orderId, GetDate()) - - INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) - VALUES (@customerId, @orderId, 388, 1)"); diff --git a/docs/examples/sharding/insert_data_aftersplit.php b/docs/examples/sharding/insert_data_aftersplit.php deleted file mode 100644 index 312e90b235b..00000000000 --- a/docs/examples/sharding/insert_data_aftersplit.php +++ /dev/null @@ -1,27 +0,0 @@ -selectShard($newCustomerId); - -$conn->insert("Customers", array( - "CustomerID" => $newCustomerId, - "CompanyName" => "Microsoft", - "FirstName" => "Brian", - "LastName" => "Swan", -)); - -$conn->insert("Orders", array( - "CustomerID" => 55, - "OrderID" => 37, - "OrderDate" => date('Y-m-d H:i:s'), -)); - -$conn->insert("OrderItems", array( - "CustomerID" => 55, - "OrderID" => 37, - "ProductID" => 387, - "Quantity" => 1, -)); diff --git a/docs/examples/sharding/query_filtering_off.php b/docs/examples/sharding/query_filtering_off.php deleted file mode 100644 index c0b24fa087d..00000000000 --- a/docs/examples/sharding/query_filtering_off.php +++ /dev/null @@ -1,8 +0,0 @@ -selectShard(0); - -$data = $conn->fetchAll('SELECT * FROM Customers'); -print_r($data); diff --git a/docs/examples/sharding/query_filtering_on.php b/docs/examples/sharding/query_filtering_on.php deleted file mode 100644 index e7d9e14546c..00000000000 --- a/docs/examples/sharding/query_filtering_on.php +++ /dev/null @@ -1,9 +0,0 @@ -setFilteringEnabled(true); -$shardManager->selectShard(55); - -$data = $conn->fetchAll('SELECT * FROM Customers'); -print_r($data); diff --git a/docs/examples/sharding/split_federation.php b/docs/examples/sharding/split_federation.php deleted file mode 100644 index ff681edfd2a..00000000000 --- a/docs/examples/sharding/split_federation.php +++ /dev/null @@ -1,5 +0,0 @@ -splitFederation(60); diff --git a/docs/examples/sharding/view_federation_members.php b/docs/examples/sharding/view_federation_members.php deleted file mode 100644 index 497e4df6d2f..00000000000 --- a/docs/examples/sharding/view_federation_members.php +++ /dev/null @@ -1,8 +0,0 @@ -getShards(); -foreach ($shards as $shard) { - print_r($shard); -} diff --git a/lib/Doctrine/DBAL/DriverManager.php b/lib/Doctrine/DBAL/DriverManager.php index def881cc4d0..6be382b6f4b 100644 --- a/lib/Doctrine/DBAL/DriverManager.php +++ b/lib/Doctrine/DBAL/DriverManager.php @@ -144,17 +144,6 @@ public static function getConnection( } } - // URL support for PoolingShardConnection - if (isset($params['global'])) { - $params['global'] = self::parseDatabaseUrl($params['global']); - } - - if (isset($params['shards'])) { - foreach ($params['shards'] as $key => $shardParams) { - $params['shards'][$key] = self::parseDatabaseUrl($shardParams); - } - } - self::_checkParams($params); $className = $params['driverClass'] ?? self::$_driverMap[$params['driver']]; diff --git a/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php deleted file mode 100644 index f281f4fc4e4..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php +++ /dev/null @@ -1,35 +0,0 @@ -hasOption('azure.federatedOnColumnName')) { - $distributionName = $table->getOption('azure.federatedOnDistributionName'); - $columnName = $table->getOption('azure.federatedOnColumnName'); - $stmt = ' FEDERATED ON (' . $distributionName . ' = ' . $columnName . ')'; - - $sql[0] .= $stmt; - } - - return $sql; - } -} diff --git a/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php b/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php deleted file mode 100644 index 871b54eec9e..00000000000 --- a/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php +++ /dev/null @@ -1,251 +0,0 @@ - "client" to the ShardChoser interface. - * - An exception is thrown if trying to switch shards during an open - * transaction. - * - * Instantiation through the DriverManager looks like: - * - * @deprecated - * - * @example - * - * $conn = DriverManager::getConnection(array( - * 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', - * 'driver' => 'pdo_mysql', - * 'global' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), - * 'shards' => array( - * array('id' => 1, 'user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), - * array('id' => 2, 'user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), - * ), - * 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', - * )); - * $shardManager = $conn->getShardManager(); - * $shardManager->selectGlobal(); - * $shardManager->selectShard($value); - */ -class PoolingShardConnection extends Connection -{ - /** @var DriverConnection[] */ - private $activeConnections = []; - - /** @var string|int|null */ - private $activeShardId; - - /** @var mixed[] */ - private $connectionParameters = []; - - /** - * {@inheritDoc} - * - * @throws InvalidArgumentException - */ - public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null) - { - if (! isset($params['global'], $params['shards'])) { - throw new InvalidArgumentException("Connection Parameters require 'global' and 'shards' configurations."); - } - - if (! isset($params['shardChoser'])) { - throw new InvalidArgumentException("Missing Shard Choser configuration 'shardChoser'"); - } - - if (is_string($params['shardChoser'])) { - $params['shardChoser'] = new $params['shardChoser'](); - } - - if (! ($params['shardChoser'] instanceof ShardChoser)) { - throw new InvalidArgumentException("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); - } - - $this->connectionParameters[0] = array_merge($params, $params['global']); - - foreach ($params['shards'] as $shard) { - if (! isset($shard['id'])) { - throw new InvalidArgumentException("Missing 'id' for one configured shard. Please specify a unique shard-id."); - } - - if (! is_numeric($shard['id']) || $shard['id'] < 1) { - throw new InvalidArgumentException('Shard Id has to be a non-negative number.'); - } - - if (isset($this->connectionParameters[$shard['id']])) { - throw new InvalidArgumentException('Shard ' . $shard['id'] . ' is duplicated in the configuration.'); - } - - $this->connectionParameters[$shard['id']] = array_merge($params, $shard); - } - - parent::__construct($params, $driver, $config, $eventManager); - } - - /** - * Get active shard id. - * - * @return string|int|null - */ - public function getActiveShardId() - { - return $this->activeShardId; - } - - /** - * {@inheritdoc} - */ - public function getParams() - { - return $this->activeShardId ? $this->connectionParameters[$this->activeShardId] : $this->connectionParameters[0]; - } - - /** - * {@inheritdoc} - */ - public function getHost() - { - $params = $this->getParams(); - - return $params['host'] ?? parent::getHost(); - } - - /** - * {@inheritdoc} - */ - public function getPort() - { - $params = $this->getParams(); - - return $params['port'] ?? parent::getPort(); - } - - /** - * {@inheritdoc} - */ - public function getUsername() - { - $params = $this->getParams(); - - return $params['user'] ?? parent::getUsername(); - } - - /** - * {@inheritdoc} - */ - public function getPassword() - { - $params = $this->getParams(); - - return $params['password'] ?? parent::getPassword(); - } - - /** - * Connects to a given shard. - * - * @param string|int|null $shardId - * - * @return bool - * - * @throws ShardingException - */ - public function connect($shardId = null) - { - if ($shardId === null && $this->_conn) { - return false; - } - - if ($shardId !== null && $shardId === $this->activeShardId) { - return false; - } - - if ($this->getTransactionNestingLevel() > 0) { - throw new ShardingException('Cannot switch shard when transaction is active.'); - } - - $activeShardId = $this->activeShardId = (int) $shardId; - - if (isset($this->activeConnections[$activeShardId])) { - $this->_conn = $this->activeConnections[$activeShardId]; - - return false; - } - - $this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId); - - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); - } - - return true; - } - - /** - * Connects to a specific connection. - * - * @param string|int $shardId - * - * @return \Doctrine\DBAL\Driver\Connection - */ - protected function connectTo($shardId) - { - $params = $this->getParams(); - - $driverOptions = $params['driverOptions'] ?? []; - - $connectionParams = $this->connectionParameters[$shardId]; - - $user = $connectionParams['user'] ?? null; - $password = $connectionParams['password'] ?? null; - - return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); - } - - /** - * @param string|int|null $shardId - * - * @return bool - */ - public function isConnected($shardId = null) - { - if ($shardId === null) { - return $this->_conn !== null; - } - - return isset($this->activeConnections[$shardId]); - } - - /** - * @return void - */ - public function close() - { - $this->_conn = null; - $this->activeConnections = []; - $this->activeShardId = null; - } -} diff --git a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php b/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php deleted file mode 100644 index 2687c9d98ea..00000000000 --- a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php +++ /dev/null @@ -1,103 +0,0 @@ -getParams(); - $this->conn = $conn; - $this->choser = $params['shardChoser']; - } - - /** - * {@inheritDoc} - */ - public function selectGlobal() - { - $this->conn->connect(0); - $this->currentDistributionValue = null; - } - - /** - * {@inheritDoc} - */ - public function selectShard($distributionValue) - { - $shardId = $this->choser->pickShard($distributionValue, $this->conn); - $this->conn->connect($shardId); - $this->currentDistributionValue = $distributionValue; - } - - /** - * {@inheritDoc} - */ - public function getCurrentDistributionValue() - { - return $this->currentDistributionValue; - } - - /** - * {@inheritDoc} - */ - public function getShards() - { - $params = $this->conn->getParams(); - $shards = []; - - foreach ($params['shards'] as $shard) { - $shards[] = ['id' => $shard['id']]; - } - - return $shards; - } - - /** - * {@inheritDoc} - * - * @throws RuntimeException - */ - public function queryAll($sql, array $params, array $types) - { - $shards = $this->getShards(); - if (! $shards) { - throw new RuntimeException('No shards found.'); - } - - $result = []; - $oldDistribution = $this->getCurrentDistributionValue(); - - foreach ($shards as $shard) { - $this->conn->connect($shard['id']); - foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { - $result[] = $row; - } - } - - if ($oldDistribution === null) { - $this->selectGlobal(); - } else { - $this->selectShard($oldDistribution); - } - - return $result; - } -} diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php deleted file mode 100644 index e889edbc5d7..00000000000 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php +++ /dev/null @@ -1,273 +0,0 @@ -shardManager = $shardManager; - $this->synchronizer = $sync ?: new SingleDatabaseSynchronizer($conn); - } - - /** - * {@inheritdoc} - */ - public function getCreateSchema(Schema $createSchema) - { - $sql = []; - - [$global, $federation] = $this->partitionSchema($createSchema); - - $globalSql = $this->synchronizer->getCreateSchema($global); - if ($globalSql) { - $sql[] = "-- Create Root Federation\n" . - 'USE FEDERATION ROOT WITH RESET;'; - $sql = array_merge($sql, $globalSql); - } - - $federationSql = $this->synchronizer->getCreateSchema($federation); - - if ($federationSql) { - $defaultValue = $this->getFederationTypeDefaultValue(); - - $sql[] = $this->getCreateFederationStatement(); - $sql[] = 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $defaultValue . ') WITH RESET, FILTERING = OFF;'; - $sql = array_merge($sql, $federationSql); - } - - return $sql; - } - - /** - * {@inheritdoc} - */ - public function getUpdateSchema(Schema $toSchema, $noDrops = false) - { - return $this->work($toSchema, static function ($synchronizer, $schema) use ($noDrops) { - return $synchronizer->getUpdateSchema($schema, $noDrops); - }); - } - - /** - * {@inheritdoc} - */ - public function getDropSchema(Schema $dropSchema) - { - return $this->work($dropSchema, static function ($synchronizer, $schema) { - return $synchronizer->getDropSchema($schema); - }); - } - - /** - * {@inheritdoc} - */ - public function createSchema(Schema $createSchema) - { - $this->processSql($this->getCreateSchema($createSchema)); - } - - /** - * {@inheritdoc} - */ - public function updateSchema(Schema $toSchema, $noDrops = false) - { - $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); - } - - /** - * {@inheritdoc} - */ - public function dropSchema(Schema $dropSchema) - { - $this->processSqlSafely($this->getDropSchema($dropSchema)); - } - - /** - * {@inheritdoc} - */ - public function getDropAllSchema() - { - $this->shardManager->selectGlobal(); - $globalSql = $this->synchronizer->getDropAllSchema(); - - if ($globalSql) { - $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; - $sql = array_merge($sql, $globalSql); - } - - $shards = $this->shardManager->getShards(); - foreach ($shards as $shard) { - $this->shardManager->selectShard($shard['rangeLow']); - - $federationSql = $this->synchronizer->getDropAllSchema(); - if (! $federationSql) { - continue; - } - - $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" . - 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ') WITH RESET, FILTERING = OFF;'; - $sql = array_merge($sql, $federationSql); - } - - $sql[] = 'USE FEDERATION ROOT WITH RESET;'; - $sql[] = 'DROP FEDERATION ' . $this->shardManager->getFederationName(); - - return $sql; - } - - /** - * {@inheritdoc} - */ - public function dropAllSchema() - { - $this->processSqlSafely($this->getDropAllSchema()); - } - - /** - * @return Schema[] - */ - private function partitionSchema(Schema $schema) - { - return [ - $this->extractSchemaFederation($schema, false), - $this->extractSchemaFederation($schema, true), - ]; - } - - /** - * @param bool $isFederation - * - * @return Schema - * - * @throws RuntimeException - */ - private function extractSchemaFederation(Schema $schema, $isFederation) - { - $partitionedSchema = clone $schema; - - foreach ($partitionedSchema->getTables() as $table) { - if ($isFederation) { - $table->addOption(self::FEDERATION_DISTRIBUTION_NAME, $this->shardManager->getDistributionKey()); - } - - if ($table->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { - $partitionedSchema->dropTable($table->getName()); - } else { - foreach ($table->getForeignKeys() as $fk) { - $foreignTable = $schema->getTable($fk->getForeignTableName()); - if ($foreignTable->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { - throw new RuntimeException('Cannot have foreign key between global/federation.'); - } - } - } - } - - return $partitionedSchema; - } - - /** - * Work on the Global/Federation based on currently existing shards and - * perform the given operation on the underlying schema synchronizer given - * the different partitioned schema instances. - * - * @return string[] - */ - private function work(Schema $schema, Closure $operation) - { - [$global, $federation] = $this->partitionSchema($schema); - $sql = []; - - $this->shardManager->selectGlobal(); - $globalSql = $operation($this->synchronizer, $global); - - if ($globalSql) { - $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; - $sql = array_merge($sql, $globalSql); - } - - $shards = $this->shardManager->getShards(); - - foreach ($shards as $shard) { - $this->shardManager->selectShard($shard['rangeLow']); - - $federationSql = $operation($this->synchronizer, $federation); - if (! $federationSql) { - continue; - } - - $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" . - 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ') WITH RESET, FILTERING = OFF;'; - $sql = array_merge($sql, $federationSql); - } - - return $sql; - } - - /** - * @return string - */ - private function getFederationTypeDefaultValue() - { - $federationType = Type::getType($this->shardManager->getDistributionType()); - - switch ($federationType->getName()) { - case Types::GUID: - $defaultValue = '00000000-0000-0000-0000-000000000000'; - break; - case Types::INTEGER: - case Types::SMALLINT: - case Types::BIGINT: - $defaultValue = '0'; - break; - default: - $defaultValue = ''; - break; - } - - return $defaultValue; - } - - /** - * @return string - */ - private function getCreateFederationStatement() - { - $federationType = Type::getType($this->shardManager->getDistributionType()); - $federationTypeSql = $federationType->getSQLDeclaration([], $this->conn->getDatabasePlatform()); - - return "--Create Federation\n" . - 'CREATE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' ' . $federationTypeSql . ' RANGE)'; - } -} diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php deleted file mode 100644 index 62a6fd48447..00000000000 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php +++ /dev/null @@ -1,210 +0,0 @@ -conn = $conn; - $params = $conn->getParams(); - - if (! isset($params['sharding']['federationName'])) { - throw ShardingException::missingDefaultFederationName(); - } - - if (! isset($params['sharding']['distributionKey'])) { - throw ShardingException::missingDefaultDistributionKey(); - } - - if (! isset($params['sharding']['distributionType'])) { - throw ShardingException::missingDistributionType(); - } - - $this->federationName = $params['sharding']['federationName']; - $this->distributionKey = $params['sharding']['distributionKey']; - $this->distributionType = $params['sharding']['distributionType']; - $this->filteringEnabled = (bool) ($params['sharding']['filteringEnabled'] ?? false); - } - - /** - * Gets the name of the federation. - * - * @return string - */ - public function getFederationName() - { - return $this->federationName; - } - - /** - * Gets the distribution key. - * - * @return string - */ - public function getDistributionKey() - { - return $this->distributionKey; - } - - /** - * Gets the Doctrine Type name used for the distribution. - * - * @return string - */ - public function getDistributionType() - { - return $this->distributionType; - } - - /** - * Sets Enabled/Disable filtering on the fly. - * - * @param bool $flag - * - * @return void - */ - public function setFilteringEnabled($flag) - { - $this->filteringEnabled = (bool) $flag; - } - - /** - * {@inheritDoc} - */ - public function selectGlobal() - { - if ($this->conn->isTransactionActive()) { - throw ShardingException::activeTransaction(); - } - - $sql = 'USE FEDERATION ROOT WITH RESET'; - $this->conn->exec($sql); - $this->currentDistributionValue = null; - } - - /** - * {@inheritDoc} - */ - public function selectShard($distributionValue) - { - if ($this->conn->isTransactionActive()) { - throw ShardingException::activeTransaction(); - } - - $platform = $this->conn->getDatabasePlatform(); - $sql = sprintf( - 'USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;', - $platform->quoteIdentifier($this->federationName), - $platform->quoteIdentifier($this->distributionKey), - $this->conn->quote($distributionValue), - ($this->filteringEnabled ? 'ON' : 'OFF') - ); - - $this->conn->exec($sql); - $this->currentDistributionValue = $distributionValue; - } - - /** - * {@inheritDoc} - */ - public function getCurrentDistributionValue() - { - return $this->currentDistributionValue; - } - - /** - * {@inheritDoc} - */ - public function getShards() - { - $sql = 'SELECT member_id as id, - distribution_name as distribution_key, - CAST(range_low AS CHAR) AS rangeLow, - CAST(range_high AS CHAR) AS rangeHigh - FROM sys.federation_member_distributions d - INNER JOIN sys.federations f ON f.federation_id = d.federation_id - WHERE f.name = ' . $this->conn->quote($this->federationName); - - return $this->conn->fetchAll($sql); - } - - /** - * {@inheritDoc} - */ - public function queryAll($sql, array $params = [], array $types = []) - { - $shards = $this->getShards(); - if (! $shards) { - throw new RuntimeException('No shards found for ' . $this->federationName); - } - - $result = []; - $oldDistribution = $this->getCurrentDistributionValue(); - - foreach ($shards as $shard) { - $this->selectShard($shard['rangeLow']); - foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { - $result[] = $row; - } - } - - if ($oldDistribution === null) { - $this->selectGlobal(); - } else { - $this->selectShard($oldDistribution); - } - - return $result; - } - - /** - * Splits Federation at a given distribution value. - * - * @param mixed $splitDistributionValue - * - * @return void - */ - public function splitFederation($splitDistributionValue) - { - $type = Type::getType($this->distributionType); - - $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' . - 'SPLIT AT (' . $this->getDistributionKey() . ' = ' . - $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')'; - $this->conn->exec($sql); - } -} diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php deleted file mode 100644 index 79ac61abdcb..00000000000 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php +++ /dev/null @@ -1,150 +0,0 @@ -excludedTables = $excludedTables; - $this->tenantColumnName = $tenantColumnName; - $this->distributionName = $distributionName ?: $tenantColumnName; - } - - /** - * {@inheritdoc} - */ - public function acceptTable(Table $table) - { - if (in_array($table->getName(), $this->excludedTables)) { - return; - } - - $table->addColumn($this->tenantColumnName, $this->tenantColumnType, [ - 'default' => "federation_filtering_value('" . $this->distributionName . "')", - ]); - - $clusteredIndex = $this->getClusteredIndex($table); - - $indexColumns = $clusteredIndex->getColumns(); - $indexColumns[] = $this->tenantColumnName; - - if ($clusteredIndex->isPrimary()) { - $table->dropPrimaryKey(); - $table->setPrimaryKey($indexColumns); - } else { - $table->dropIndex($clusteredIndex->getName()); - $table->addIndex($indexColumns, $clusteredIndex->getName()); - $table->getIndex($clusteredIndex->getName())->addFlag('clustered'); - } - } - - /** - * @param Table $table - * - * @return Index - * - * @throws RuntimeException - */ - private function getClusteredIndex($table) - { - foreach ($table->getIndexes() as $index) { - if ($index->isPrimary() && ! $index->hasFlag('nonclustered')) { - return $index; - } - - if ($index->hasFlag('clustered')) { - return $index; - } - } - throw new RuntimeException('No clustered index found on table ' . $table->getName()); - } - - /** - * {@inheritdoc} - */ - public function acceptSchema(Schema $schema) - { - } - - /** - * {@inheritdoc} - */ - public function acceptColumn(Table $table, Column $column) - { - } - - /** - * {@inheritdoc} - */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) - { - } - - /** - * {@inheritdoc} - */ - public function acceptIndex(Table $table, Index $index) - { - } - - /** - * {@inheritdoc} - */ - public function acceptSequence(Sequence $sequence) - { - } -} diff --git a/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php b/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php deleted file mode 100644 index f44c3af4322..00000000000 --- a/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php +++ /dev/null @@ -1,22 +0,0 @@ - 'pdo_mysql', - 'shardChoser' => MultiTenantShardChoser::class, - 'global' => ['url' => 'mysql://foo:bar@localhost:11211/baz'], - 'shards' => [ - [ - 'id' => 1, - 'url' => 'mysql://foo:bar@localhost:11211/baz_slave', - ], - ], - 'wrapperClass' => PoolingShardConnection::class, - ]; - - $conn = DriverManager::getConnection($options); - - $params = $conn->getParams(); - self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver()); - - $expected = [ - 'user' => 'foo', - 'password' => 'bar', - 'host' => 'localhost', - 'port' => 11211, - ]; - - foreach ($expected as $key => $value) { - self::assertEquals($value, $params['global'][$key]); - self::assertEquals($value, $params['shards'][0][$key]); - } - - self::assertEquals('baz', $params['global']['dbname']); - self::assertEquals('baz_slave', $params['shards'][0]['dbname']); - } - /** * @param mixed $url * @param mixed $expected diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php deleted file mode 100644 index 65b5e85f219..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php +++ /dev/null @@ -1,31 +0,0 @@ -platform = new SQLAzurePlatform(); - } - - public function testCreateFederatedOnTable() : void - { - $table = new Table('tbl'); - $table->addColumn('id', 'integer'); - $table->addOption('azure.federatedOnDistributionName', 'TblId'); - $table->addOption('azure.federatedOnColumnName', 'id'); - - self::assertEquals(['CREATE TABLE tbl (id INT NOT NULL) FEDERATED ON (TblId = id)'], $this->platform->getCreateTableSQL($table)); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php deleted file mode 100644 index c782b06b919..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php +++ /dev/null @@ -1,319 +0,0 @@ - PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ['id' => 2, 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertFalse($conn->isConnected(0)); - $conn->connect(0); - self::assertEquals(1, $conn->fetchColumn('SELECT 1')); - self::assertTrue($conn->isConnected(0)); - - self::assertFalse($conn->isConnected(1)); - $conn->connect(1); - self::assertEquals(1, $conn->fetchColumn('SELECT 1')); - self::assertTrue($conn->isConnected(1)); - - self::assertFalse($conn->isConnected(2)); - $conn->connect(2); - self::assertEquals(1, $conn->fetchColumn('SELECT 1')); - self::assertTrue($conn->isConnected(2)); - - $conn->close(); - self::assertFalse($conn->isConnected(0)); - self::assertFalse($conn->isConnected(1)); - self::assertFalse($conn->isConnected(2)); - } - - public function testNoGlobalServerException() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'shards' => [ - ['id' => 1, 'memory' => true], - ['id' => 2, 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - } - - public function testNoShardsServersException() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - } - - public function testNoShardsChoserException() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Missing Shard Choser configuration 'shardChoser'"); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ['id' => 2, 'memory' => true], - ], - ]); - } - - public function testShardChoserWrongInstance() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ['id' => 2, 'memory' => true], - ], - 'shardChoser' => new stdClass(), - ]); - } - - public function testShardNonNumericId() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Shard Id has to be a non-negative number.'); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 'foo', 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - } - - public function testShardMissingId() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Missing 'id' for one configured shard. Please specify a unique shard-id."); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - } - - public function testDuplicateShardId() : void - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Shard 1 is duplicated in the configuration.'); - - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ['id' => 1, 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - } - - public function testSwitchShardWithOpenTransactionException() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - $conn->beginTransaction(); - - $this->expectException(ShardingException::class); - $this->expectExceptionMessage('Cannot switch shard when transaction is active.'); - $conn->connect(1); - } - - public function testGetActiveShardId() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertNull($conn->getActiveShardId()); - - $conn->connect(0); - self::assertEquals(0, $conn->getActiveShardId()); - - $conn->connect(1); - self::assertEquals(1, $conn->getActiveShardId()); - - $conn->close(); - self::assertNull($conn->getActiveShardId()); - } - - public function testGetParamsOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true, 'host' => 'localhost'], - 'shards' => [ - ['id' => 1, 'memory' => true, 'host' => 'foo'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true, 'host' => 'localhost'], - 'shards' => [ - ['id' => 1, 'memory' => true, 'host' => 'foo'], - ], - 'shardChoser' => new MultiTenantShardChoser(), - 'memory' => true, - 'host' => 'localhost', - ], $conn->getParams()); - - $conn->connect(1); - self::assertEquals([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'global' => ['memory' => true, 'host' => 'localhost'], - 'shards' => [ - ['id' => 1, 'memory' => true, 'host' => 'foo'], - ], - 'shardChoser' => new MultiTenantShardChoser(), - 'id' => 1, - 'memory' => true, - 'host' => 'foo', - ], $conn->getParams()); - } - - public function testGetHostOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'host' => 'localhost', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'host' => 'foo'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals('localhost', $conn->getHost()); - - $conn->connect(1); - self::assertEquals('foo', $conn->getHost()); - } - - public function testGetPortOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'port' => 3306, - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'port' => 3307], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals(3306, $conn->getPort()); - - $conn->connect(1); - self::assertEquals(3307, $conn->getPort()); - } - - public function testGetUsernameOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'user' => 'foo', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'user' => 'bar'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals('foo', $conn->getUsername()); - - $conn->connect(1); - self::assertEquals('bar', $conn->getUsername()); - } - - public function testGetPasswordOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'password' => 'foo', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'password' => 'bar'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals('foo', $conn->getPassword()); - - $conn->connect(1); - self::assertEquals('bar', $conn->getPassword()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php deleted file mode 100644 index eafbd69cfcb..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php +++ /dev/null @@ -1,148 +0,0 @@ -getMockBuilder(PoolingShardConnection::class) - ->onlyMethods(['connect', 'getParams', 'fetchAll']) - ->disableOriginalConstructor() - ->getMock(); - } - - private function createPassthroughShardChoser() : ShardChoser - { - $mock = $this->createMock(ShardChoser::class); - $mock->expects($this->any()) - ->method('pickShard') - ->will($this->returnCallback(static function ($value) { - return $value; - })); - - return $mock; - } - - private function createStaticShardChooser() : ShardChoser - { - $mock = $this->createMock(ShardChoser::class); - $mock->expects($this->any()) - ->method('pickShard') - ->willReturn(1); - - return $mock; - } - - public function testSelectGlobal() : void - { - $conn = $this->createConnectionMock(); - $conn->expects($this->once())->method('connect')->with($this->equalTo(0)); - $conn->method('getParams') - ->willReturn([ - 'shardChoser' => $this->createMock(ShardChoser::class), - ]); - - $shardManager = new PoolingShardManager($conn); - $shardManager->selectGlobal(); - - self::assertNull($shardManager->getCurrentDistributionValue()); - } - - public function testSelectShard() : void - { - $shardId = 10; - $conn = $this->createConnectionMock(); - $conn->expects($this->at(0))->method('getParams')->will($this->returnValue(['shardChoser' => $this->createPassthroughShardChoser()])); - $conn->expects($this->at(1))->method('connect')->with($this->equalTo($shardId)); - - $shardManager = new PoolingShardManager($conn); - $shardManager->selectShard($shardId); - - self::assertEquals($shardId, $shardManager->getCurrentDistributionValue()); - } - - public function testGetShards() : void - { - $conn = $this->createConnectionMock(); - $conn->expects($this->any())->method('getParams')->will( - $this->returnValue( - ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] - ) - ); - - $shardManager = new PoolingShardManager($conn); - $shards = $shardManager->getShards(); - - self::assertEquals([['id' => 1], ['id' => 2]], $shards); - } - - public function testQueryAll() : void - { - $sql = 'SELECT * FROM table'; - $params = [1]; - $types = [1]; - - $conn = $this->createConnectionMock(); - $conn->expects($this->at(0))->method('getParams')->will($this->returnValue( - ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] - )); - $conn->expects($this->at(1))->method('getParams')->will($this->returnValue( - ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] - )); - $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); - $conn->expects($this->at(3)) - ->method('fetchAll') - ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) - ->will($this->returnValue([ ['id' => 1] ])); - $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); - $conn->expects($this->at(5)) - ->method('fetchAll') - ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) - ->will($this->returnValue([ ['id' => 2] ])); - - $shardManager = new PoolingShardManager($conn); - $result = $shardManager->queryAll($sql, $params, $types); - - self::assertEquals([['id' => 1], ['id' => 2]], $result); - } - - public function testQueryAllWithStaticShardChoser() : void - { - $sql = 'SELECT * FROM table'; - $params = [1]; - $types = [1]; - - $conn = $this->createConnectionMock(); - $conn->expects($this->at(0))->method('getParams')->will($this->returnValue( - ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createStaticShardChooser()] - )); - $conn->expects($this->at(1))->method('getParams')->will($this->returnValue( - ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createStaticShardChooser()] - )); - $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); - $conn->expects($this->at(3)) - ->method('fetchAll') - ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) - ->will($this->returnValue([ ['id' => 1] ])); - $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); - $conn->expects($this->at(5)) - ->method('fetchAll') - ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) - ->will($this->returnValue([ ['id' => 2] ])); - - $shardManager = new PoolingShardManager($conn); - $result = $shardManager->queryAll($sql, $params, $types); - - self::assertEquals([['id' => 1], ['id' => 2]], $result); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php deleted file mode 100644 index b0439d5dfe2..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php +++ /dev/null @@ -1,95 +0,0 @@ -markTestSkipped('No driver or sqlserver driver specified.'); - } - - $params = [ - 'driver' => $GLOBALS['db_type'], - 'dbname' => $GLOBALS['db_name'], - 'user' => $GLOBALS['db_username'], - 'password' => $GLOBALS['db_password'], - 'host' => $GLOBALS['db_host'], - 'sharding' => [ - 'federationName' => 'Orders_Federation', - 'distributionKey' => 'CustID', - 'distributionType' => 'integer', - 'filteringEnabled' => false, - ], - 'driverOptions' => ['MultipleActiveResultSets' => false], - ]; - $this->conn = DriverManager::getConnection($params); - - $serverEdition = $this->conn->fetchColumn("SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY('Edition'))"); - - if (strpos($serverEdition, 'SQL Azure') !== 0) { - $this->markTestSkipped('SQL Azure only test.'); - } - - // assume database is created and schema is: - // Global products table - // Customers, Orders, OrderItems federation tables. - // See http://cloud.dzone.com/articles/using-sql-azure-federations - $this->sm = new SQLAzureShardManager($this->conn); - } - - protected function createShopSchema() : Schema - { - $schema = new Schema(); - - $products = $schema->createTable('Products'); - $products->addColumn('ProductID', 'integer'); - $products->addColumn('SupplierID', 'integer'); - $products->addColumn('ProductName', 'string'); - $products->addColumn('Price', 'decimal', ['scale' => 2, 'precision' => 12]); - $products->setPrimaryKey(['ProductID']); - $products->addOption('azure.federated', true); - - $customers = $schema->createTable('Customers'); - $customers->addColumn('CustomerID', 'integer'); - $customers->addColumn('CompanyName', 'string'); - $customers->addColumn('FirstName', 'string'); - $customers->addColumn('LastName', 'string'); - $customers->setPrimaryKey(['CustomerID']); - $customers->addOption('azure.federated', true); - $customers->addOption('azure.federatedOnColumnName', 'CustomerID'); - - $orders = $schema->createTable('Orders'); - $orders->addColumn('CustomerID', 'integer'); - $orders->addColumn('OrderID', 'integer'); - $orders->addColumn('OrderDate', 'datetime'); - $orders->setPrimaryKey(['CustomerID', 'OrderID']); - $orders->addOption('azure.federated', true); - $orders->addOption('azure.federatedOnColumnName', 'CustomerID'); - - $orderItems = $schema->createTable('OrderItems'); - $orderItems->addColumn('CustomerID', 'integer'); - $orderItems->addColumn('OrderID', 'integer'); - $orderItems->addColumn('ProductID', 'integer'); - $orderItems->addColumn('Quantity', 'integer'); - $orderItems->setPrimaryKey(['CustomerID', 'OrderID', 'ProductID']); - $orderItems->addOption('azure.federated', true); - $orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); - - return $schema; - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php deleted file mode 100644 index 6e31d8716ed..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php +++ /dev/null @@ -1,45 +0,0 @@ -createShopSchema(); - - $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); - $synchronizer->dropAllSchema(); - $synchronizer->createSchema($schema); - - $this->sm->selectShard(0); - - $this->conn->insert('Products', [ - 'ProductID' => 1, - 'SupplierID' => 2, - 'ProductName' => 'Test', - 'Price' => 10.45, - ]); - - $this->conn->insert('Customers', [ - 'CustomerID' => 1, - 'CompanyName' => 'Foo', - 'FirstName' => 'Benjamin', - 'LastName' => 'E.', - ]); - - $query = 'SELECT * FROM Products'; - $data = $this->conn->fetchAll($query); - self::assertGreaterThan(0, count($data)); - - $query = 'SELECT * FROM Customers'; - $data = $this->conn->fetchAll($query); - self::assertGreaterThan(0, count($data)); - - $data = $this->sm->queryAll('SELECT * FROM Customers'); - self::assertGreaterThan(0, count($data)); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php deleted file mode 100644 index 3549cf40b0e..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php +++ /dev/null @@ -1,48 +0,0 @@ -createTable('foo'); - $foo->addColumn('id', 'string'); - $foo->setPrimaryKey(['id']); - $schema->visit($visitor); - - self::assertEquals(['id', 'tenant_id'], $foo->getPrimaryKey()->getColumns()); - self::assertTrue($foo->hasColumn('tenant_id')); - } - - public function testMultiTenantNonPrimaryKey() : void - { - $platform = new SQLAzurePlatform(); - $visitor = new MultiTenantVisitor(); - - $schema = new Schema(); - $foo = $schema->createTable('foo'); - $foo->addColumn('id', 'string'); - $foo->addColumn('created', 'datetime'); - $foo->setPrimaryKey(['id']); - $foo->addIndex(['created'], 'idx'); - - $foo->getPrimaryKey()->addFlag('nonclustered'); - $foo->getIndex('idx')->addFlag('clustered'); - - $schema->visit($visitor); - - self::assertEquals(['id'], $foo->getPrimaryKey()->getColumns()); - self::assertTrue($foo->hasColumn('tenant_id')); - self::assertEquals(['created', 'tenant_id'], $foo->getIndex('idx')->getColumns()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php deleted file mode 100644 index 2185a9fc8d1..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php +++ /dev/null @@ -1,49 +0,0 @@ -createShopSchema(); - - $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); - $sql = $synchronizer->getCreateSchema($schema); - - self::assertEquals([ - "--Create Federation\nCREATE FEDERATION Orders_Federation (CustID INT RANGE)", - 'USE FEDERATION Orders_Federation (CustID = 0) WITH RESET, FILTERING = OFF;', - 'CREATE TABLE Products (ProductID INT NOT NULL, SupplierID INT NOT NULL, ProductName NVARCHAR(255) NOT NULL, Price NUMERIC(12, 2) NOT NULL, PRIMARY KEY (ProductID))', - 'CREATE TABLE Customers (CustomerID INT NOT NULL, CompanyName NVARCHAR(255) NOT NULL, FirstName NVARCHAR(255) NOT NULL, LastName NVARCHAR(255) NOT NULL, PRIMARY KEY (CustomerID))', - 'CREATE TABLE Orders (CustomerID INT NOT NULL, OrderID INT NOT NULL, OrderDate DATETIME2(6) NOT NULL, PRIMARY KEY (CustomerID, OrderID))', - 'CREATE TABLE OrderItems (CustomerID INT NOT NULL, OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity INT NOT NULL, PRIMARY KEY (CustomerID, OrderID, ProductID))', - ], $sql); - } - - public function testUpdateSchema() : void - { - $schema = $this->createShopSchema(); - - $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); - $synchronizer->dropAllSchema(); - - $sql = $synchronizer->getUpdateSchema($schema); - - self::assertEquals([], $sql); - } - - public function testDropSchema() : void - { - $schema = $this->createShopSchema(); - - $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); - $synchronizer->dropAllSchema(); - $synchronizer->createSchema($schema); - $sql = $synchronizer->getDropSchema($schema); - - self::assertCount(5, $sql); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php deleted file mode 100644 index 78d6afe593c..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php +++ /dev/null @@ -1,95 +0,0 @@ -expectException(ShardingException::class); - $this->expectExceptionMessage('SQLAzure requires a federation name to be set during sharding configuration.'); - - $conn = $this->createConnection(['sharding' => ['distributionKey' => 'abc', 'distributionType' => 'integer']]); - new SQLAzureShardManager($conn); - } - - public function testNoDistributionKey() : void - { - $this->expectException(ShardingException::class); - $this->expectExceptionMessage('SQLAzure requires a distribution key to be set during sharding configuration.'); - - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionType' => 'integer']]); - new SQLAzureShardManager($conn); - } - - public function testNoDistributionType() : void - { - $this->expectException(ShardingException::class); - - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo']]); - new SQLAzureShardManager($conn); - } - - public function testGetDefaultDistributionValue() : void - { - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); - - $sm = new SQLAzureShardManager($conn); - self::assertNull($sm->getCurrentDistributionValue()); - } - - public function testSelectGlobalTransactionActive() : void - { - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); - $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); - - $this->expectException(ShardingException::class); - $this->expectExceptionMessage('Cannot switch shard during an active transaction.'); - - $sm = new SQLAzureShardManager($conn); - $sm->selectGlobal(); - } - - public function testSelectGlobal() : void - { - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); - $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(false)); - $conn->expects($this->at(2))->method('exec')->with($this->equalTo('USE FEDERATION ROOT WITH RESET')); - - $sm = new SQLAzureShardManager($conn); - $sm->selectGlobal(); - } - - public function testSelectShard() : void - { - $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); - $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); - - $this->expectException(ShardingException::class); - $this->expectExceptionMessage('Cannot switch shard during an active transaction.'); - - $sm = new SQLAzureShardManager($conn); - $sm->selectShard(1234); - - self::assertEquals(1234, $sm->getCurrentDistributionValue()); - } - - /** - * @param mixed[] $params - */ - private function createConnection(array $params) : Connection - { - $conn = $this->getMockBuilder(Connection::class) - ->onlyMethods(['getParams', 'exec', 'isTransactionActive']) - ->disableOriginalConstructor() - ->getMock(); - $conn->expects($this->at(0))->method('getParams')->will($this->returnValue($params)); - - return $conn; - } -} diff --git a/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php b/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php deleted file mode 100644 index 5b65deecc77..00000000000 --- a/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php +++ /dev/null @@ -1,27 +0,0 @@ -createConnectionMock(); - - self::assertEquals(1, $choser->pickShard(1, $conn)); - self::assertEquals(2, $choser->pickShard(2, $conn)); - } - - private function createConnectionMock() : PoolingShardConnection - { - return $this->getMockBuilder(PoolingShardConnection::class) - ->onlyMethods(['connect', 'getParams', 'fetchAll']) - ->disableOriginalConstructor() - ->getMock(); - } -} From 20229b19fd162cffe8d6a5c67d6f26c28670b114 Mon Sep 17 00:00:00 2001 From: Claudio Zizza Date: Thu, 13 Jun 2019 23:11:19 +0200 Subject: [PATCH 09/10] Remove Postgres 9.3 and MariaDB 10.0 support --- .scrutinizer.yml | 2 +- .travis.yml | 8 ---- UPGRADE.md | 16 ++++++++ docs/en/reference/configuration.rst | 10 ++--- docs/en/reference/platforms.rst | 3 +- docs/en/reference/types.rst | 4 +- .../DBAL/Driver/AbstractPostgreSQLDriver.php | 14 +++---- .../Keywords/PostgreSQL100Keywords.php | 2 +- .../Keywords/PostgreSQL94Keywords.php | 32 --------------- .../Platforms/Keywords/PostgreSQLKeywords.php | 4 +- .../DBAL/Platforms/PostgreSQL100Platform.php | 2 +- .../DBAL/Platforms/PostgreSQL94Platform.php | 41 ------------------- .../DBAL/Platforms/PostgreSqlPlatform.php | 5 +++ .../Console/Command/ReservedWordsCommand.php | 6 +-- .../Driver/AbstractPostgreSQLDriverTest.php | 10 ++--- .../Schema/PostgreSqlSchemaManagerTest.php | 4 +- .../Platforms/PostgreSQL100PlatformTest.php | 2 +- .../Platforms/PostgreSQL94PlatformTest.php | 32 --------------- .../DBAL/Platforms/PostgreSqlPlatformTest.php | 4 ++ 19 files changed, 51 insertions(+), 150 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL94Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 421e69a5fb5..54e2627460b 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,7 +21,7 @@ before_commands: tools: external_code_coverage: timeout: 3600 - runs: 27 # 22x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP + runs: 26 # 21x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP filter: excluded_paths: diff --git a/.travis.yml b/.travis.yml index 93cb74abcdb..dc9079c2eb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -95,14 +95,6 @@ jobs: - stage: Test php: 7.3 env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.3 COVERAGE=yes - - stage: Test - dist: trusty - php: 7.3 - env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes - services: - - postgresql - addons: - postgresql: "9.3" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.4 COVERAGE=yes diff --git a/UPGRADE.md b/UPGRADE.md index 57f20bc6a30..96e6d01614a 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,21 @@ # Upgrade to 3.0 +## BC BREAK: Removed support for PostgreSQL 9.3 and older + +DBAL now requires PostgeSQL 9.4 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to a newer PostgreSQL version (9.6+ is recommended). +`Doctrine\DBAL\Platforms\PostgreSqlPlatform` and `Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords` now represent PostgreSQL 9.4. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\PostgreSQL94Platform` + * `Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords` + +## BC BREAK: Removed support for MariaDB 10.0 and older + +DBAL now requires MariaDB 10.1 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to a newer MariaDB version (10.1+ is recommended). + ## BC BREAK: PingableConnection and ServerInfoAwareConnection interfaces now extend Connection All implementations of the `PingableConnection` and `ServerInfoAwareConnection` interfaces have to implement the methods defined in the `Connection` interface as well. diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 5a4c872cd76..e9a623b80da 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -227,20 +227,20 @@ pdo_pgsql - ``sslmode`` (string): Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server. See the list of available modes: - `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE` + `https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE` - ``sslrootcert`` (string): specifies the name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities. - See https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT + See https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT - ``sslcert`` (string): specifies the file name of the client SSL certificate. - See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLCERT` + See `https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNECT-SSLCERT` - ``sslkey`` (string): specifies the location for the secret key used for the client certificate. - See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLKEY` + See `https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNECT-SSLKEY` - ``sslcrl`` (string): specifies the file name of the SSL certificate revocation list (CRL). - See `https://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNECT-SSLCRL` + See `https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNECT-SSLCRL` - ``application_name`` (string): Name of the application that is connecting to database. Optional. It will be displayed at ``pg_stat_activity``. diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index 163cf230e77..f2f36592e8e 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -56,8 +56,7 @@ Microsoft SQL Server PostgreSQL ^^^^^^^^^^ -- ``PostgreSqlPlatform`` for version 9.3 and below. -- ``PostgreSQL94Platform`` for version 9.4 and above. +- ``PostgreSqlPlatform`` for version 9.4 and above. - ``PostgreSQL100Platform`` for version 10.0 and above. SAP Sybase SQL Anywhere diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index dd733f33a51..81efed85885 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -741,9 +741,7 @@ Please also notice the mapping specific footnotes for additional information. | | | | +----------------------------------------------------------+ | | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | < 9.4 | ``JSON`` | -| | | +---------+----------------------------------------------------------+ -| | | | >= 9.4 | ``JSON`` [20]_ | +| | | **PostgreSQL** | *all* | ``JSON`` [20]_ | | | | | +----------------------------------------------------------+ | | | | | ``JSONB`` [21]_ | | | +--------------------------+---------+----------------------------------------------------------+ diff --git a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php index 9b74ae98663..a051bf569c5 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; -use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\PostgreSqlSchemaManager; use Doctrine\DBAL\VersionAwarePlatformDriver; @@ -22,7 +21,7 @@ abstract class AbstractPostgreSQLDriver implements ExceptionConverterDriver, Ver /** * {@inheritdoc} * - * @link http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html + * @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html */ public function convertException($message, DriverException $exception) { @@ -93,14 +92,11 @@ public function createDatabasePlatformForVersion($version) $patchVersion = $versionParts['patch'] ?? 0; $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; - switch (true) { - case version_compare($version, '10.0', '>='): - return new PostgreSQL100Platform(); - case version_compare($version, '9.4', '>='): - return new PostgreSQL94Platform(); - default: - return new PostgreSqlPlatform(); + if (version_compare($version, '10.0', '>=')) { + return new PostgreSQL100Platform(); } + + return new PostgreSqlPlatform(); } /** diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php index 3402db1902c..80e4efadd60 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php @@ -7,7 +7,7 @@ /** * PostgreSQL 10.0 reserved keywords list. */ -class PostgreSQL100Keywords extends PostgreSQL94Keywords +class PostgreSQL100Keywords extends PostgreSQLKeywords { /** * {@inheritdoc} diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL94Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL94Keywords.php deleted file mode 100644 index 7bf29cd2aa5..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL94Keywords.php +++ /dev/null @@ -1,32 +0,0 @@ -doctrineTypeMapping['jsonb'] = Types::JSON; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index 64fd2700218..3c03ca86637 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -1150,6 +1150,7 @@ protected function initializeDoctrineTypeMappings() 'integer' => 'integer', 'interval' => 'string', 'json' => Type::JSON, + 'jsonb' => Type::JSON, 'money' => 'decimal', 'numeric' => 'decimal', 'serial' => 'integer', @@ -1251,6 +1252,10 @@ public function getColumnCollationDeclarationSQL($collation) */ public function getJsonTypeDeclarationSQL(array $field) { + if (! empty($field['jsonb'])) { + return 'JSONB'; + } + return 'JSON'; } diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index a8020a15399..13d885fdb6c 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -4,12 +4,12 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\Keywords\DB2Keywords; +use Doctrine\DBAL\Platforms\Keywords\MariaDb102Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQL57Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords; use Doctrine\DBAL\Platforms\Keywords\OracleKeywords; use Doctrine\DBAL\Platforms\Keywords\PostgreSQL100Keywords; -use Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords; use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords; use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator; use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords; @@ -33,9 +33,9 @@ class ReservedWordsCommand extends Command 'mysql' => MySQLKeywords::class, 'mysql57' => MySQL57Keywords::class, 'mysql80' => MySQL80Keywords::class, + 'mariadb102' => MariaDb102Keywords::class, 'oracle' => OracleKeywords::class, 'pgsql' => PostgreSQLKeywords::class, - 'pgsql94' => PostgreSQL94Keywords::class, 'pgsql100' => PostgreSQL100Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, 'sqlite' => SQLiteKeywords::class, @@ -90,8 +90,8 @@ protected function configure() * mysql * mysql57 * mysql80 + * mariadb102 * pgsql - * pgsql94 * pgsql100 * sqlite * oracle diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php index 9f1daca35cd..7536c02fbde 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php @@ -8,7 +8,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; -use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\PostgreSqlSchemaManager; @@ -65,12 +64,9 @@ protected function createSchemaManager(Connection $connection) : AbstractSchemaM protected function getDatabasePlatformsForVersions() : array { return [ - ['9.3', PostgreSqlPlatform::class], - ['9.3.0', PostgreSqlPlatform::class], - ['9.3.6', PostgreSqlPlatform::class], - ['9.4', PostgreSQL94Platform::class], - ['9.4.0', PostgreSQL94Platform::class], - ['9.4.1', PostgreSQL94Platform::class], + ['9.4', PostgreSqlPlatform::class], + ['9.4.0', PostgreSqlPlatform::class], + ['9.4.1', PostgreSqlPlatform::class], ['10', PostgreSQL100Platform::class], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php index b8a26af3c65..b2aa46c296c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php @@ -3,7 +3,7 @@ namespace Doctrine\Tests\DBAL\Functional\Schema; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\PostgreSQL94Platform; +use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema; use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\ForeignKeyConstraint; @@ -401,7 +401,7 @@ public function testPartialIndexes() : void */ public function testJsonbColumn(string $type) : void { - if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSQL94Platform) { + if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSqlPlatform) { $this->markTestSkipped('Requires PostgresSQL 9.4+'); return; diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL100PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL100PlatformTest.php index 8eb58c98e72..4fb9c795371 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL100PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL100PlatformTest.php @@ -7,7 +7,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; -class PostgreSQL100PlatformTest extends PostgreSQL94PlatformTest +class PostgreSQL100PlatformTest extends PostgreSqlPlatformTest { /** * {@inheritdoc} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php deleted file mode 100644 index 3439bb95868..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php +++ /dev/null @@ -1,32 +0,0 @@ -platform->getJsonTypeDeclarationSQL(['jsonb' => false])); - self::assertSame('JSONB', $this->platform->getJsonTypeDeclarationSQL(['jsonb' => true])); - } - - public function testInitializesJsonTypeMapping() : void - { - parent::testInitializesJsonTypeMapping(); - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('jsonb')); - self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('jsonb')); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php index 4a71b80026b..2549facca99 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -56,6 +56,8 @@ public function testHasNativeJsonType() : void public function testReturnsJsonTypeDeclarationSQL() : void { self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); + self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL(['jsonb' => false])); + self::assertSame('JSONB', $this->platform->getJsonTypeDeclarationSQL(['jsonb' => true])); } public function testReturnsSmallIntTypeDeclarationSQL() : void @@ -83,6 +85,8 @@ public function testInitializesJsonTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); self::assertEquals(Type::JSON, $this->platform->getDoctrineTypeMapping('json')); + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('jsonb')); + self::assertEquals(Type::JSON, $this->platform->getDoctrineTypeMapping('jsonb')); } /** From e360ba05143ca2132d56f2c91ef36cfc37b47780 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 27 Nov 2019 17:50:21 -0800 Subject: [PATCH 10/10] Dropped SQL Server 2008 support --- .appveyor.yml | 5 - UPGRADE.md | 12 +- docs/en/reference/platforms.rst | 3 +- .../DBAL/Driver/AbstractSQLServerDriver.php | 38 +- .../Keywords/SQLServer2012Keywords.php | 37 -- .../Platforms/Keywords/SQLServerKeywords.php | 5 + .../DBAL/Platforms/SQLServer2012Platform.php | 143 ------- .../DBAL/Platforms/SQLServerPlatform.php | 215 +++++----- .../Console/Command/ReservedWordsCommand.php | 2 - .../Driver/AbstractSQLServerDriverTest.php | 20 +- .../AbstractSQLServerPlatformTestCase.php | 298 +++++++------- .../Platforms/SQLServer2012PlatformTest.php | 372 ------------------ .../DBAL/Platforms/SQLServerPlatformTest.php | 33 -- 13 files changed, 275 insertions(+), 908 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php diff --git a/.appveyor.yml b/.appveyor.yml index 352719e2617..2257d2b6e91 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,11 +18,6 @@ cache: ## Build matrix for lowest and highest possible targets environment: matrix: - - db: mssql - driver: sqlsrv - db_version: sql2008r2sp2 - coverage: yes - php: 7.3 - db: mssql driver: sqlsrv db_version: sql2012sp1 diff --git a/UPGRADE.md b/UPGRADE.md index 96e6d01614a..c6ecc04fca2 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -52,18 +52,22 @@ The following classes have been removed: * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords` * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords` -## BC BREAK: Removed support for SQL Server 2005 and older +## BC BREAK: Removed support for SQL Server 2008 and older -DBAL now requires SQL Server 2008 or newer, support for unmaintained versions has been dropped. -If you are using any of the legacy versions, you have to upgrade to newer SQL Server version (2012+ is recommended). -`Doctrine\DBAL\Platforms\SQLServerPlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords` now represent the SQL Server 2008. +DBAL now requires SQL Server 2012 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to a newer SQL Server version. +`Doctrine\DBAL\Platforms\SQLServerPlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords` now represent SQL Server 2012. The following classes have been removed: * `Doctrine\DBAL\Platforms\SQLServer2005Platform` * `Doctrine\DBAL\Platforms\SQLServer2008Platform` + * `Doctrine\DBAL\Platforms\SQLServer2012Platform` * `Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords` * `Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords` + +The `AbstractSQLServerDriver` class and its subclasses no longer implement the `VersionAwarePlatformDriver` interface. ## BC BREAK: Removed support for PostgreSQL 9.2 and older diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index f2f36592e8e..142f6fd7550 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -50,8 +50,7 @@ Oracle Microsoft SQL Server ^^^^^^^^^^^^^^^^^^^^ -- ``SQLServerPlatform`` for version 2008 and above. -- ``SQLServer2012Platform`` for version 2012 and above. +- ``SQLServerPlatform`` for version 2012 and above. PostgreSQL ^^^^^^^^^^ diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php index 1a86508549a..f010fc325c7 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php @@ -3,49 +3,15 @@ namespace Doctrine\DBAL\Driver; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\DBALException; -use Doctrine\DBAL\Platforms\SQLServer2012Platform; +use Doctrine\DBAL\Driver; use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\SQLServerSchemaManager; -use Doctrine\DBAL\VersionAwarePlatformDriver; -use function preg_match; -use function version_compare; /** * Abstract base implementation of the {@link Doctrine\DBAL\Driver} interface for Microsoft SQL Server based drivers. */ -abstract class AbstractSQLServerDriver implements VersionAwarePlatformDriver +abstract class AbstractSQLServerDriver implements Driver { - /** - * {@inheritdoc} - */ - public function createDatabasePlatformForVersion($version) - { - if (! preg_match( - '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', - $version, - $versionParts - )) { - throw DBALException::invalidPlatformVersionSpecified( - $version, - '...' - ); - } - - $majorVersion = $versionParts['major']; - $minorVersion = $versionParts['minor'] ?? 0; - $patchVersion = $versionParts['patch'] ?? 0; - $buildVersion = $versionParts['build'] ?? 0; - $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; - - switch (true) { - case version_compare($version, '11.00.2100', '>='): - return new SQLServer2012Platform(); - default: - return new SQLServerPlatform(); - } - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php deleted file mode 100644 index d29225270aa..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php +++ /dev/null @@ -1,37 +0,0 @@ -getQuotedName($this) . - ' INCREMENT BY ' . $sequence->getAllocationSize(); - } - - /** - * {@inheritdoc} - */ - public function getCreateSequenceSQL(Sequence $sequence) - { - return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . - ' START WITH ' . $sequence->getInitialValue() . - ' INCREMENT BY ' . $sequence->getAllocationSize() . - ' MINVALUE ' . $sequence->getInitialValue(); - } - - /** - * {@inheritdoc} - */ - public function getDropSequenceSQL($sequence) - { - if ($sequence instanceof Sequence) { - $sequence = $sequence->getQuotedName($this); - } - - return 'DROP SEQUENCE ' . $sequence; - } - - /** - * {@inheritdoc} - */ - public function getListSequencesSQL($database) - { - return 'SELECT seq.name, - CAST( - seq.increment AS VARCHAR(MAX) - ) AS increment, -- CAST avoids driver error for sql_variant type - CAST( - seq.start_value AS VARCHAR(MAX) - ) AS start_value -- CAST avoids driver error for sql_variant type - FROM sys.sequences AS seq'; - } - - /** - * {@inheritdoc} - */ - public function getSequenceNextValSQL($sequenceName) - { - return 'SELECT NEXT VALUE FOR ' . $sequenceName; - } - - /** - * {@inheritdoc} - */ - public function supportsSequences() - { - return true; - } - - /** - * {@inheritdoc} - * - * Returns Microsoft SQL Server 2012 specific keywords class - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLServer2012Keywords::class; - } - - /** - * {@inheritdoc} - */ - protected function doModifyLimitQuery($query, $limit, $offset = null) - { - if ($limit === null && $offset <= 0) { - return $query; - } - - // Queries using OFFSET... FETCH MUST have an ORDER BY clause - // Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement - // but can be in a newline - $matches = []; - $matchesCount = preg_match_all('/[\\s]+order\\s+by\\s/im', $query, $matches, PREG_OFFSET_CAPTURE); - $orderByPos = false; - if ($matchesCount > 0) { - $orderByPos = $matches[0][($matchesCount - 1)][1]; - } - - if ($orderByPos === false - || substr_count($query, '(', $orderByPos) - substr_count($query, ')', $orderByPos) - ) { - if (preg_match('/^SELECT\s+DISTINCT/im', $query)) { - // SQL Server won't let us order by a non-selected column in a DISTINCT query, - // so we have to do this madness. This says, order by the first column in the - // result. SQL Server's docs say that a nonordered query's result order is non- - // deterministic anyway, so this won't do anything that a bunch of update and - // deletes to the table wouldn't do anyway. - $query .= ' ORDER BY 1'; - } else { - // In another DBMS, we could do ORDER BY 0, but SQL Server gets angry if you - // use constant expressions in the order by list. - $query .= ' ORDER BY (SELECT 0)'; - } - } - - if ($offset === null) { - $offset = 0; - } - - // This looks somewhat like MYSQL, but limit/offset are in inverse positions - // Supposedly SQL:2008 core standard. - // Per TSQL spec, FETCH NEXT n ROWS ONLY is not valid without OFFSET n ROWS. - $query .= ' OFFSET ' . (int) $offset . ' ROWS'; - - if ($limit !== null) { - $query .= ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; - } - - return $query; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index c29d488cbbb..d17229d5cc5 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -8,9 +8,11 @@ use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Identifier; use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use InvalidArgumentException; +use const PREG_OFFSET_CAPTURE; use function array_merge; use function array_unique; use function array_values; @@ -25,14 +27,11 @@ use function is_numeric; use function is_string; use function preg_match; +use function preg_match_all; use function sprintf; use function str_replace; -use function stripos; -use function stristr; -use function strlen; use function strpos; use function strtoupper; -use function substr; use function substr_count; /** @@ -145,6 +144,69 @@ public function supportsColumnCollation() return true; } + /** + * {@inheritdoc} + */ + public function supportsSequences() : bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) : string + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritdoc} + */ + public function getCreateSequenceSQL(Sequence $sequence) : string + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' START WITH ' . $sequence->getInitialValue() . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' MINVALUE ' . $sequence->getInitialValue(); + } + + /** + * {@inheritdoc} + */ + public function getDropSequenceSQL($sequence) : string + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritdoc} + */ + public function getListSequencesSQL($database) + { + return 'SELECT seq.name, + CAST( + seq.increment AS VARCHAR(MAX) + ) AS increment, -- CAST avoids driver error for sql_variant type + CAST( + seq.start_value AS VARCHAR(MAX) + ) AS start_value -- CAST avoids driver error for sql_variant type + FROM sys.sequences AS seq'; + } + + /** + * {@inheritdoc} + */ + public function getSequenceNextValSQL($sequenceName) + { + return 'SELECT NEXT VALUE FOR ' . $sequenceName; + } + /** * {@inheritDoc} */ @@ -1271,132 +1333,47 @@ public function getBooleanTypeDeclarationSQL(array $field) */ protected function doModifyLimitQuery($query, $limit, $offset = null) { - $where = []; - - if ($offset > 0) { - $where[] = sprintf('doctrine_rownum >= %d', $offset + 1); - } - - if ($limit !== null) { - $where[] = sprintf('doctrine_rownum <= %d', $offset + $limit); - $top = sprintf('TOP %d', $offset + $limit); - } else { - $top = 'TOP 9223372036854775807'; - } - - if (empty($where)) { + if ($limit === null && $offset <= 0) { return $query; } - // We'll find a SELECT or SELECT distinct and prepend TOP n to it - // Even if the TOP n is very large, the use of a CTE will - // allow the SQL Server query planner to optimize it so it doesn't - // actually scan the entire range covered by the TOP clause. - if (! preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/is', $query, $matches)) { - return $query; + // Queries using OFFSET... FETCH MUST have an ORDER BY clause + // Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement + // but can be in a newline + $matches = []; + $matchesCount = preg_match_all('/[\\s]+order\\s+by\\s/im', $query, $matches, PREG_OFFSET_CAPTURE); + $orderByPos = false; + if ($matchesCount > 0) { + $orderByPos = $matches[0][($matchesCount - 1)][1]; } - $query = $matches[1] . $top . ' ' . $matches[2]; - - if (stristr($query, 'ORDER BY')) { - // Inner order by is not valid in SQL Server for our purposes - // unless it's in a TOP N subquery. - $query = $this->scrubInnerOrderBy($query); - } - - // Build a new limited query around the original, using a CTE - return sprintf( - 'WITH dctrn_cte AS (%s) ' - . 'SELECT * FROM (' - . 'SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte' - . ') AS doctrine_tbl ' - . 'WHERE %s ORDER BY doctrine_rownum ASC', - $query, - implode(' AND ', $where) - ); - } - - /** - * Remove ORDER BY clauses in subqueries - they're not supported by SQL Server. - * Caveat: will leave ORDER BY in TOP N subqueries. - * - * @param string $query - * - * @return string - */ - private function scrubInnerOrderBy($query) - { - $count = substr_count(strtoupper($query), 'ORDER BY'); - $offset = 0; - - while ($count-- > 0) { - $orderByPos = stripos($query, ' ORDER BY', $offset); - if ($orderByPos === false) { - break; + if ($orderByPos === false + || substr_count($query, '(', $orderByPos) - substr_count($query, ')', $orderByPos) + ) { + if (preg_match('/^SELECT\s+DISTINCT/im', $query)) { + // SQL Server won't let us order by a non-selected column in a DISTINCT query, + // so we have to do this madness. This says, order by the first column in the + // result. SQL Server's docs say that a nonordered query's result order is non- + // deterministic anyway, so this won't do anything that a bunch of update and + // deletes to the table wouldn't do anyway. + $query .= ' ORDER BY 1'; + } else { + // In another DBMS, we could do ORDER BY 0, but SQL Server gets angry if you + // use constant expressions in the order by list. + $query .= ' ORDER BY (SELECT 0)'; } - - $qLen = strlen($query); - $parenCount = 0; - $currentPosition = $orderByPos; - - while ($parenCount >= 0 && $currentPosition < $qLen) { - if ($query[$currentPosition] === '(') { - $parenCount++; - } elseif ($query[$currentPosition] === ')') { - $parenCount--; - } - - $currentPosition++; - } - - if ($this->isOrderByInTopNSubquery($query, $orderByPos)) { - // If the order by clause is in a TOP N subquery, do not remove - // it and continue iteration from the current position. - $offset = $currentPosition; - continue; - } - - if ($currentPosition >= $qLen - 1) { - continue; - } - - $query = substr($query, 0, $orderByPos) . substr($query, $currentPosition - 1); - $offset = $orderByPos; } - return $query; - } + // This looks somewhat like MYSQL, but limit/offset are in inverse positions + // Supposedly SQL:2008 core standard. + // Per TSQL spec, FETCH NEXT n ROWS ONLY is not valid without OFFSET n ROWS. + $query .= sprintf(' OFFSET %d ROWS', $offset); - /** - * Check an ORDER BY clause to see if it is in a TOP N query or subquery. - * - * @param string $query The query - * @param int $currentPosition Start position of ORDER BY clause - * - * @return bool true if ORDER BY is in a TOP N query, false otherwise - */ - private function isOrderByInTopNSubquery($query, $currentPosition) - { - // Grab query text on the same nesting level as the ORDER BY clause we're examining. - $subQueryBuffer = ''; - $parenCount = 0; - - // If $parenCount goes negative, we've exited the subquery we're examining. - // If $currentPosition goes negative, we've reached the beginning of the query. - while ($parenCount >= 0 && $currentPosition >= 0) { - if ($query[$currentPosition] === '(') { - $parenCount--; - } elseif ($query[$currentPosition] === ')') { - $parenCount++; - } - - // Only yank query text on the same nesting level as the ORDER BY clause. - $subQueryBuffer = ($parenCount === 0 ? $query[$currentPosition] : ' ') . $subQueryBuffer; - - $currentPosition--; + if ($limit !== null) { + $query .= sprintf(' FETCH NEXT %d ROWS ONLY', $limit); } - return (bool) preg_match('/SELECT\s+(DISTINCT\s+)?TOP\s/i', $subQueryBuffer); + return $query; } /** diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 13d885fdb6c..60c8f021c74 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -14,7 +14,6 @@ use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator; use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords; use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords; -use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords; use Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords; use InvalidArgumentException; use Symfony\Component\Console\Command\Command; @@ -40,7 +39,6 @@ class ReservedWordsCommand extends Command 'sqlanywhere' => SQLAnywhereKeywords::class, 'sqlite' => SQLiteKeywords::class, 'sqlserver' => SQLServerKeywords::class, - 'sqlserver2012' => SQLServer2012Keywords::class, ]; /** diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php index 330b4b5e4d8..a0ea28b63ab 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\AbstractSQLServerDriver; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SQLServer2012Platform; use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\SQLServerSchemaManager; @@ -34,24 +33,7 @@ protected function createSchemaManager(Connection $connection) : AbstractSchemaM protected function getDatabasePlatformsForVersions() : array { return [ - ['10', SQLServerPlatform::class], - ['10.00', SQLServerPlatform::class], - ['10.00.0', SQLServerPlatform::class], - ['10.00.1599', SQLServerPlatform::class], - ['10.00.1599.99', SQLServerPlatform::class], - ['10.00.1600', SQLServerPlatform::class], - ['10.00.1600.0', SQLServerPlatform::class], - ['10.00.1600.99', SQLServerPlatform::class], - ['10.00.1601', SQLServerPlatform::class], - ['10.10', SQLServerPlatform::class], - ['10.10.9999', SQLServerPlatform::class], - ['11.00.2099', SQLServerPlatform::class], - ['11.00.2099.99', SQLServerPlatform::class], - ['11.00.2100', SQLServer2012Platform::class], - ['11.00.2100.0', SQLServer2012Platform::class], - ['11.00.2100.99', SQLServer2012Platform::class], - ['11.00.2101', SQLServer2012Platform::class], - ['12', SQLServer2012Platform::class], + ['12', SQLServerPlatform::class], ]; } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index 46627bd8cf2..75e54470505 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -6,11 +6,11 @@ use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ColumnDiff; use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; -use function sprintf; abstract class AbstractSQLServerPlatformTestCase extends AbstractPlatformTestCase { @@ -184,115 +184,77 @@ public function getGenerateForeignKeySql() : string public function testModifyLimitQuery() : void { - $querySql = 'SELECT * FROM user'; - $alteredSql = 'SELECT TOP 10 * FROM user'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 0); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { - $querySql = 'SELECT * FROM user'; - $alteredSql = 'SELECT TOP 10 * FROM user'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); + self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithOffset() : void { - if (! $this->platform->supportsLimitOffset()) { - $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); - } - - $querySql = 'SELECT * FROM user ORDER BY username DESC'; - $alteredSql = 'SELECT TOP 15 * FROM user ORDER BY username DESC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); - - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10, 5); + self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithAscOrderBy() : void { - $querySql = 'SELECT * FROM user ORDER BY username ASC'; - $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username ASC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); + self::assertEquals('SELECT * FROM user ORDER BY username ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithLowercaseOrderBy() : void { - $querySql = 'SELECT * FROM user order by username'; - $alteredSql = 'SELECT TOP 10 * FROM user order by username'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user order by username', 10); + self::assertEquals('SELECT * FROM user order by username OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithDescOrderBy() : void { - $querySql = 'SELECT * FROM user ORDER BY username DESC'; - $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username DESC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); + self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithMultipleOrderBy() : void { - $querySql = 'SELECT * FROM user ORDER BY username DESC, usereamil ASC'; - $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username DESC, usereamil ASC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC, usereamil ASC', 10); + self::assertEquals('SELECT * FROM user ORDER BY username DESC, usereamil ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelect() : void { - $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; - $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result', 10); + self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelectAndOrder() : void { - $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname ORDER BY u.name DESC) dctrn_result'; - $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC', 10); + self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - $querySql = 'SELECT * FROM (SELECT u.id, u.name ORDER BY u.name DESC) dctrn_result'; - $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id, u.name) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC', 10); + self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelectAndMultipleOrder() : void { - if (! $this->platform->supportsLimitOffset()) { - $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); - } - - $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname ORDER BY u.name DESC, id ASC) dctrn_result'; - $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); + self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - $querySql = 'SELECT * FROM (SELECT u.id uid, u.name uname ORDER BY u.name DESC, id ASC) dctrn_result'; - $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id uid, u.name uname) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); + self::assertEquals('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - $querySql = 'SELECT * FROM (SELECT u.id, u.name ORDER BY u.name DESC, id ASC) dctrn_result'; - $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id, u.name) dctrn_result'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC', 10, 5); + self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithFromColumnNames() : void { - $querySql = 'SELECT a.fromFoo, fromBar FROM foo'; - $alteredSql = 'SELECT TOP 10 a.fromFoo, fromBar FROM foo'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $sql = $this->platform->modifyLimitQuery('SELECT a.fromFoo, fromBar FROM foo', 10); + self::assertEquals('SELECT a.fromFoo, fromBar FROM foo ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } /** @@ -305,13 +267,15 @@ public function testModifyLimitQueryWithExtraLongQuery() : void $query .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; $query .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; - $alteredSql = 'SELECT TOP 10 table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; - $alteredSql .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; - $alteredSql .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; - $alteredSql .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; - $sql = $this->platform->modifyLimitQuery($query, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + + $expected = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; + $expected .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; + $expected .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; + $expected .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8) '; + $expected .= 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + + self::assertEquals($expected, $sql); } /** @@ -319,15 +283,11 @@ public function testModifyLimitQueryWithExtraLongQuery() : void */ public function testModifyLimitQueryWithOrderByClause() : void { - if (! $this->platform->supportsLimitOffset()) { - $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); - } + $sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; + $expected = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY'; + $actual = $this->platform->modifyLimitQuery($sql, 10, 5); - $sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; - $alteredSql = 'SELECT TOP 15 m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; - $actual = $this->platform->modifyLimitQuery($sql, 10, 5); - - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $actual); + self::assertEquals($expected, $actual); } /** @@ -335,23 +295,28 @@ public function testModifyLimitQueryWithOrderByClause() : void */ public function testModifyLimitQueryWithSubSelectInSelectList() : void { - $querySql = 'SELECT ' . + $sql = $this->platform->modifyLimitQuery( + 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . - "WHERE u.status = 'disabled'"; - $alteredSql = 'SELECT TOP 10 ' . + "WHERE u.status = 'disabled'", + 10 + ); + + self::assertEquals( + 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . - "WHERE u.status = 'disabled'"; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + "WHERE u.status = 'disabled' " . + 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', + $sql + ); } /** @@ -359,28 +324,31 @@ public function testModifyLimitQueryWithSubSelectInSelectList() : void */ public function testModifyLimitQueryWithSubSelectInSelectListAndOrderByClause() : void { - if (! $this->platform->supportsLimitOffset()) { - $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); - } - - $querySql = 'SELECT ' . + $sql = $this->platform->modifyLimitQuery( + 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . - 'ORDER BY u.username DESC'; - $alteredSql = 'SELECT TOP 15 ' . + 'ORDER BY u.username DESC', + 10, + 5 + ); + + self::assertEquals( + 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . - 'ORDER BY u.username DESC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); - $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); + 'ORDER BY u.username DESC ' . + 'OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', + $sql + ); } /** @@ -388,20 +356,27 @@ public function testModifyLimitQueryWithSubSelectInSelectListAndOrderByClause() */ public function testModifyLimitQueryWithAggregateFunctionInOrderByClause() : void { - $querySql = 'SELECT ' . + $sql = $this->platform->modifyLimitQuery( + 'SELECT ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . - 'ORDER BY MAX(heading_id) DESC'; - $alteredSql = 'SELECT TOP 1 ' . + 'ORDER BY MAX(heading_id) DESC', + 1, + 0 + ); + + self::assertEquals( + 'SELECT ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . - 'ORDER BY MAX(heading_id) DESC'; - $sql = $this->platform->modifyLimitQuery($querySql, 1, 0); - $this->expectCteWithMaxRowNum($alteredSql, 1, $sql); + 'ORDER BY MAX(heading_id) DESC ' . + 'OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY', + $sql + ); } /** @@ -413,19 +388,18 @@ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromBas . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' - . 'ORDER BY t1.id ASC' + . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY id_0 ASC'; - $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1 ' + $alteredSql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' - . 'ORDER BY id_0 ASC'; + . 'ORDER BY id_0 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); - $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); + self::assertEquals($alteredSql, $sql); } /** @@ -437,19 +411,18 @@ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromJoi . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' - . 'ORDER BY t2.name ASC' + . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC'; - $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1 ' + $alteredSql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' - . 'ORDER BY name_1 ASC'; + . 'ORDER BY name_1 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); - $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); + self::assertEquals($alteredSql, $sql); } /** @@ -461,19 +434,18 @@ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnsFromBo . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' - . 'ORDER BY t2.name ASC, t2.foo DESC' + . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC, foo_2 DESC'; - $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1, foo_2 ' + $alteredSql = 'SELECT DISTINCT id_0, name_1, foo_2 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' - . 'ORDER BY name_1 ASC, foo_2 DESC'; + . 'ORDER BY name_1 ASC, foo_2 DESC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); - $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); + self::assertEquals($alteredSql, $sql); } public function testModifyLimitSubquerySimple() : void @@ -481,10 +453,10 @@ public function testModifyLimitSubquerySimple() : void $querySql = 'SELECT DISTINCT id_0 FROM ' . '(SELECT k0_.id AS id_0, k0_.field AS field_1 ' . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; - $alteredSql = 'SELECT DISTINCT TOP 20 id_0 FROM (SELECT k0_.id AS id_0, k0_.field AS field_1 ' - . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; + $alteredSql = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0, k0_.field AS field_1 ' + . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 20); - $this->expectCteWithMaxRowNum($alteredSql, 20, $sql); + self::assertEquals($alteredSql, $sql); } /** @@ -1453,15 +1425,50 @@ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : arra public function testModifyLimitQueryWithTopNSubQueryWithOrderBy() : void { - $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; - $alteredSql = 'SELECT TOP 10 * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; + $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + $sql = $this->platform->modifyLimitQuery($querySql, 10); + self::assertEquals($expectedSql, $sql); + + $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; + $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + $sql = $this->platform->modifyLimitQuery($querySql, 10); + self::assertEquals($expectedSql, $sql); + } + + public function testModifyLimitQueryWithFromSubquery() : void + { + $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result', 10); + + $expected = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + + self::assertEquals($sql, $expected); + } + + public function testModifyLimitQueryWithFromSubqueryAndOrder() : void + { + $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC', 10); + + $expected = 'SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; - $alteredSql = 'SELECT TOP 10 * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); + self::assertEquals($sql, $expected); + } + + public function testModifyLimitQueryWithComplexOrderByExpression() : void + { + $sql = $this->platform->modifyLimitQuery('SELECT * FROM table ORDER BY (table.x * table.y) DESC', 10); + + $expected = 'SELECT * FROM table ORDER BY (table.x * table.y) DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + + self::assertEquals($sql, $expected); + } + + public function testModifyLimitQueryWithNewlineBeforeOrderBy() : void + { + $querySql = "SELECT * FROM test\nORDER BY col DESC"; + $expectedSql = "SELECT * FROM test\nORDER BY col DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY"; + $sql = $this->platform->modifyLimitQuery($querySql, 10); + self::assertEquals($expectedSql, $sql); } /** @@ -1575,15 +1582,34 @@ public function testGetCreateTableSQLWithColumnCollation() : void ); } - private function expectCteWithMaxRowNum(string $expectedSql, int $expectedMax, string $sql) : void + public function testSupportsSequences() : void { - $pattern = 'WITH dctrn_cte AS (%s) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= %d ORDER BY doctrine_rownum ASC'; - self::assertEquals(sprintf($pattern, $expectedSql, $expectedMax), $sql); + self::assertTrue($this->platform->supportsSequences()); } - private function expectCteWithMinAndMaxRowNums(string $expectedSql, int $expectedMin, int $expectedMax, string $sql) : void + public function testDoesNotPreferSequences() : void { - $pattern = 'WITH dctrn_cte AS (%s) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum >= %d AND doctrine_rownum <= %d ORDER BY doctrine_rownum ASC'; - self::assertEquals(sprintf($pattern, $expectedSql, $expectedMin, $expectedMax), $sql); + self::assertFalse($this->platform->prefersSequences()); + } + + public function testGeneratesSequenceSqlCommands() : void + { + $sequence = new Sequence('myseq', 20, 1); + self::assertEquals( + 'CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 20 MINVALUE 1', + $this->platform->getCreateSequenceSQL($sequence) + ); + self::assertEquals( + 'ALTER SEQUENCE myseq INCREMENT BY 20', + $this->platform->getAlterSequenceSQL($sequence) + ); + self::assertEquals( + 'DROP SEQUENCE myseq', + $this->platform->getDropSequenceSQL('myseq') + ); + self::assertEquals( + 'SELECT NEXT VALUE FOR myseq', + $this->platform->getSequenceNextValSQL('myseq') + ); } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php deleted file mode 100644 index e6d4975daed..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php +++ /dev/null @@ -1,372 +0,0 @@ -platform->supportsSequences()); - } - - public function testDoesNotPreferSequences() : void - { - self::assertFalse($this->platform->prefersSequences()); - } - - public function testGeneratesSequenceSqlCommands() : void - { - $sequence = new Sequence('myseq', 20, 1); - self::assertEquals( - 'CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 20 MINVALUE 1', - $this->platform->getCreateSequenceSQL($sequence) - ); - self::assertEquals( - 'ALTER SEQUENCE myseq INCREMENT BY 20', - $this->platform->getAlterSequenceSQL($sequence) - ); - self::assertEquals( - 'DROP SEQUENCE myseq', - $this->platform->getDropSequenceSQL('myseq') - ); - self::assertEquals( - 'SELECT NEXT VALUE FOR myseq', - $this->platform->getSequenceNextValSQL('myseq') - ); - } - - public function testModifyLimitQuery() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); - self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithEmptyOffset() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); - self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithOffset() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10, 5); - self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithAscOrderBy() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); - self::assertEquals('SELECT * FROM user ORDER BY username ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithLowercaseOrderBy() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user order by username', 10); - self::assertEquals('SELECT * FROM user order by username OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithDescOrderBy() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); - self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithMultipleOrderBy() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC, usereamil ASC', 10); - self::assertEquals('SELECT * FROM user ORDER BY username DESC, usereamil ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithSubSelect() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result', 10); - self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithSubSelectAndOrder() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC', 10); - self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC', 10); - self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithSubSelectAndMultipleOrder() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); - self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); - self::assertEquals('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - - $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC', 10, 5); - self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - public function testModifyLimitQueryWithFromColumnNames() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT a.fromFoo, fromBar FROM foo', 10); - self::assertEquals('SELECT a.fromFoo, fromBar FROM foo ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); - } - - /** - * @group DBAL-927 - */ - public function testModifyLimitQueryWithExtraLongQuery() : void - { - $query = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; - $query .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; - $query .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; - $query .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; - - $sql = $this->platform->modifyLimitQuery($query, 10); - - $expected = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; - $expected .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; - $expected .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; - $expected .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8) '; - $expected .= 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - - self::assertEquals($expected, $sql); - } - - /** - * @group DDC-2470 - */ - public function testModifyLimitQueryWithOrderByClause() : void - { - $sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; - $expected = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY'; - $actual = $this->platform->modifyLimitQuery($sql, 10, 5); - - self::assertEquals($expected, $actual); - } - - /** - * @group DBAL-713 - */ - public function testModifyLimitQueryWithSubSelectInSelectList() : void - { - $sql = $this->platform->modifyLimitQuery( - 'SELECT ' . - 'u.id, ' . - '(u.foo/2) foodiv, ' . - 'CONCAT(u.bar, u.baz) barbaz, ' . - '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . - 'FROM user u ' . - "WHERE u.status = 'disabled'", - 10 - ); - - self::assertEquals( - 'SELECT ' . - 'u.id, ' . - '(u.foo/2) foodiv, ' . - 'CONCAT(u.bar, u.baz) barbaz, ' . - '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . - 'FROM user u ' . - "WHERE u.status = 'disabled' " . - 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', - $sql - ); - } - - /** - * @group DBAL-713 - */ - public function testModifyLimitQueryWithSubSelectInSelectListAndOrderByClause() : void - { - $sql = $this->platform->modifyLimitQuery( - 'SELECT ' . - 'u.id, ' . - '(u.foo/2) foodiv, ' . - 'CONCAT(u.bar, u.baz) barbaz, ' . - '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . - 'FROM user u ' . - "WHERE u.status = 'disabled' " . - 'ORDER BY u.username DESC', - 10, - 5 - ); - - self::assertEquals( - 'SELECT ' . - 'u.id, ' . - '(u.foo/2) foodiv, ' . - 'CONCAT(u.bar, u.baz) barbaz, ' . - '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . - 'FROM user u ' . - "WHERE u.status = 'disabled' " . - 'ORDER BY u.username DESC ' . - 'OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', - $sql - ); - } - - /** - * @group DBAL-834 - */ - public function testModifyLimitQueryWithAggregateFunctionInOrderByClause() : void - { - $sql = $this->platform->modifyLimitQuery( - 'SELECT ' . - 'MAX(heading_id) aliased, ' . - 'code ' . - 'FROM operator_model_operator ' . - 'GROUP BY code ' . - 'ORDER BY MAX(heading_id) DESC', - 1, - 0 - ); - - self::assertEquals( - 'SELECT ' . - 'MAX(heading_id) aliased, ' . - 'code ' . - 'FROM operator_model_operator ' . - 'GROUP BY code ' . - 'ORDER BY MAX(heading_id) DESC ' . - 'OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY', - $sql - ); - } - - public function testModifyLimitQueryWithFromSubquery() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result', 10); - - $expected = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - - self::assertEquals($sql, $expected); - } - - public function testModifyLimitQueryWithFromSubqueryAndOrder() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC', 10); - - $expected = 'SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - - self::assertEquals($sql, $expected); - } - - public function testModifyLimitQueryWithComplexOrderByExpression() : void - { - $sql = $this->platform->modifyLimitQuery('SELECT * FROM table ORDER BY (table.x * table.y) DESC', 10); - - $expected = 'SELECT * FROM table ORDER BY (table.x * table.y) DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - - self::assertEquals($sql, $expected); - } - - /** - * @throws DBALException - */ - public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromBaseTable() : void - { - $querySql = 'SELECT DISTINCT id_0, name_1 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY id_0 ASC'; - $alteredSql = 'SELECT DISTINCT id_0, name_1 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY id_0 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 5); - self::assertEquals($alteredSql, $sql); - } - - /** - * @throws DBALException - */ - public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromJoinTable() : void - { - $querySql = 'SELECT DISTINCT id_0, name_1 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY name_1 ASC'; - $alteredSql = 'SELECT DISTINCT id_0, name_1 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY name_1 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 5); - self::assertEquals($alteredSql, $sql); - } - - /** - * @throws DBALException - */ - public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnsFromBothTables() : void - { - $querySql = 'SELECT DISTINCT id_0, name_1, foo_2 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY name_1 ASC, foo_2 DESC'; - $alteredSql = 'SELECT DISTINCT id_0, name_1, foo_2 ' - . 'FROM (' - . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' - . 'FROM table_parent t1 ' - . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' - . ') dctrn_result ' - . 'ORDER BY name_1 ASC, foo_2 DESC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 5); - self::assertEquals($alteredSql, $sql); - } - - public function testModifyLimitSubquerySimple() : void - { - $querySql = 'SELECT DISTINCT id_0 FROM ' - . '(SELECT k0_.id AS id_0, k0_.field AS field_1 ' - . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; - $alteredSql = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0, k0_.field AS field_1 ' - . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 20); - self::assertEquals($alteredSql, $sql); - } - - public function testModifyLimitQueryWithTopNSubQueryWithOrderBy() : void - { - $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; - $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - self::assertEquals($expectedSql, $sql); - - $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; - $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - self::assertEquals($expectedSql, $sql); - } - - public function testModifyLimitQueryWithNewlineBeforeOrderBy() : void - { - $querySql = "SELECT * FROM test\nORDER BY col DESC"; - $expectedSql = "SELECT * FROM test\nORDER BY col DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY"; - $sql = $this->platform->modifyLimitQuery($querySql, 10); - self::assertEquals($expectedSql, $sql); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php index a5d27823b38..4760c502149 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php @@ -27,15 +27,6 @@ public function testAppendsLockHint($lockMode, string $lockHint) : void self::assertSame($expectedResult, $this->platform->appendLockHint($fromClause, $lockMode)); } - /** - * @group DBAL-2408 - * @dataProvider getModifyLimitQueries - */ - public function testScrubInnerOrderBy(string $query, int $limit, ?int $offset, string $expectedResult) : void - { - self::assertSame($expectedResult, $this->platform->modifyLimitQuery($query, $limit, $offset)); - } - /** * @return mixed[][] */ @@ -52,30 +43,6 @@ public static function getLockHints() : iterable ]; } - /** - * @return mixed[][] - */ - public static function getModifyLimitQueries() : iterable - { - return [ - // Test re-ordered query with correctly-scrubbed ORDER BY clause - [ - 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_ ORDER BY c0_.title ASC) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', - 30, - null, - 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', - ], - - // Test re-ordered query with no scrubbed ORDER BY clause - [ - 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', - 30, - null, - 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', - ], - ]; - } - public function testGeneratesTypeDeclarationForDateTimeTz() : void { self::assertEquals('DATETIMEOFFSET(6)', $this->platform->getDateTimeTzTypeDeclarationSQL([]));