From 2f4809aa1557ef8361d1ea7eed9fc99c970b66db Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Thu, 22 Sep 2016 22:10:36 +0000 Subject: [PATCH 01/66] Decouple unique index from unique constraint --- .../DBAL/Platforms/AbstractPlatform.php | 33 +- .../DBAL/Platforms/SqlitePlatform.php | 3 +- .../DBAL/Schema/AbstractSchemaManager.php | 5 +- lib/Doctrine/DBAL/Schema/Index.php | 2 + lib/Doctrine/DBAL/Schema/SchemaException.php | 18 +- lib/Doctrine/DBAL/Schema/Table.php | 497 ++++++++++++------ lib/Doctrine/DBAL/Schema/UniqueConstraint.php | 121 +++++ .../Tests/DBAL/Functional/ExceptionTest.php | 1 + .../SchemaManagerFunctionalTestCase.php | 7 +- .../Tests/DBAL/Schema/ComparatorTest.php | 2 + .../Doctrine/Tests/DBAL/Schema/TableTest.php | 4 +- 11 files changed, 518 insertions(+), 175 deletions(-) create mode 100644 lib/Doctrine/DBAL/Schema/UniqueConstraint.php diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index abb7333ac1d..3cdcdfc9ac3 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -23,6 +23,7 @@ use Doctrine\DBAL\Schema\Sequence; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\Schema\UniqueConstraint; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types; use Doctrine\DBAL\Types\Type; @@ -1546,15 +1547,30 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE $options['indexes'] = []; $options['primary'] = []; - if (($createFlags&self::CREATE_INDEXES) > 0) { + if (($createFlags & self::CREATE_INDEXES) > 0) { foreach ($table->getIndexes() as $index) { /** @var $index Index */ - if ($index->isPrimary()) { - $options['primary'] = $index->getQuotedColumns($this); - $options['primary_index'] = $index; - } else { + if (! $index->isPrimary()) { $options['indexes'][$index->getQuotedName($this)] = $index; + + continue; } + + $options['primary'] = $index->getQuotedColumns($this); + $options['primary_index'] = $index; + } + + foreach ($table->getUniqueConstraints() as $uniqueConstraint) { + /** @var UniqueConstraint $uniqueConstraint */ + $options['uniqueConstraints'][$uniqueConstraint->getQuotedName($this)] = $uniqueConstraint; + } + } + + if (($createFlags & self::CREATE_FOREIGNKEYS) > 0) { + $options['foreignKeys'] = []; + + foreach ($table->getForeignKeys() as $fkConstraint) { + $options['foreignKeys'][] = $fkConstraint; } } @@ -1589,13 +1605,6 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE $columns[$columnData['name']] = $columnData; } - if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) { - $options['foreignKeys'] = []; - foreach ($table->getForeignKeys() as $fkConstraint) { - $options['foreignKeys'][] = $fkConstraint; - } - } - if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) { $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this); $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs); diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index b7382ec08b0..68b2eb8bb92 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -898,10 +898,11 @@ public function getAlterTableSQL(TableDiff $diff) $sql = []; $tableSql = []; + if (! $this->onSchemaAlterTable($diff, $tableSql)) { $dataTable = new Table('__temp__' . $table->getName()); - $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions()); + $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), [], $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions()); $newTable->addOption('alter', true); $sql = $this->getPreAlterTableIndexForeignKeySQL($diff); diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 5c92c2e3f7b..f932e354b5c 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -268,12 +268,14 @@ public function listTableDetails($tableName) { $columns = $this->listTableColumns($tableName); $foreignKeys = []; + if ($this->_platform->supportsForeignKeyConstraints()) { $foreignKeys = $this->listTableForeignKeys($tableName); } + $indexes = $this->listTableIndexes($tableName); - return new Table($tableName, $columns, $indexes, $foreignKeys); + return new Table($tableName, $columns, $indexes, [], $foreignKeys); } /** @@ -592,6 +594,7 @@ public function dropAndCreateView(View $view) public function alterTable(TableDiff $tableDiff) { $queries = $this->_platform->getAlterTableSQL($tableDiff); + if (! is_array($queries) || ! count($queries)) { return; } diff --git a/lib/Doctrine/DBAL/Schema/Index.php b/lib/Doctrine/DBAL/Schema/Index.php index 7a31c7824bf..18a26b8d306 100644 --- a/lib/Doctrine/DBAL/Schema/Index.php +++ b/lib/Doctrine/DBAL/Schema/Index.php @@ -58,6 +58,7 @@ public function __construct($indexName, array $columns, $isUnique = false, $isPr $isUnique = $isUnique || $isPrimary; $this->_setName($indexName); + $this->_isUnique = $isUnique; $this->_isPrimary = $isPrimary; $this->options = $options; @@ -65,6 +66,7 @@ public function __construct($indexName, array $columns, $isUnique = false, $isPr foreach ($columns as $column) { $this->_addColumn($column); } + foreach ($flags as $flag) { $this->addFlag($flag); } diff --git a/lib/Doctrine/DBAL/Schema/SchemaException.php b/lib/Doctrine/DBAL/Schema/SchemaException.php index 213d218475b..658663ac16a 100644 --- a/lib/Doctrine/DBAL/Schema/SchemaException.php +++ b/lib/Doctrine/DBAL/Schema/SchemaException.php @@ -18,7 +18,8 @@ class SchemaException extends DBALException public const SEQUENCE_ALREADY_EXISTS = 80; public const INDEX_INVALID_NAME = 90; public const FOREIGNKEY_DOESNT_EXIST = 100; - public const NAMESPACE_ALREADY_EXISTS = 110; + public const CONSTRAINT_DOESNT_EXIST = 110; + public const NAMESPACE_ALREADY_EXISTS = 120; /** * @param string $tableName @@ -142,6 +143,21 @@ public static function sequenceDoesNotExist($sequenceName) return new self("There exists no sequence with the name '" . $sequenceName . "'.", self::SEQUENCE_DOENST_EXIST); } + /** + * @param string $constraintName + * @param string $table + * + * @return self + */ + public static function uniqueConstraintDoesNotExist($constraintName, $table) + { + return new self(sprintf( + 'There exists no unique constraint with the name "%s" on table "%s".', + $constraintName, + $table + ), self::CONSTRAINT_DOESNT_EXIST); + } + /** * @param string $fkName * @param string $table diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index af853c277d5..adeae4fe60e 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -7,8 +7,11 @@ use Doctrine\DBAL\Types\Type; use const ARRAY_FILTER_USE_KEY; use function array_filter; +use function array_keys; use function array_merge; +use function array_unique; use function in_array; +use function is_string; use function preg_match; use function strlen; use function strtolower; @@ -30,6 +33,9 @@ class Table extends AbstractAsset /** @var string */ protected $_primaryKeyName = false; + /** @var UniqueConstraint[] */ + protected $_uniqueConstraints = []; + /** @var ForeignKeyConstraint[] */ protected $_fkConstraints = []; @@ -43,14 +49,22 @@ class Table extends AbstractAsset * @param string $tableName * @param Column[] $columns * @param Index[] $indexes + * @param UniqueConstraint[] $uniqueConstraints * @param ForeignKeyConstraint[] $fkConstraints * @param int $idGeneratorType * @param mixed[] $options * * @throws DBALException */ - public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = []) - { + public function __construct( + $tableName, + array $columns = [], + array $indexes = [], + array $uniqueConstraints = [], + array $fkConstraints = [], + $idGeneratorType = 0, + array $options = [] + ) { if (strlen($tableName) === 0) { throw DBALException::invalidTableName($tableName); } @@ -65,8 +79,12 @@ public function __construct($tableName, array $columns = [], array $indexes = [] $this->_addIndex($idx); } - foreach ($fkConstraints as $constraint) { - $this->_addForeignKeyConstraint($constraint); + foreach ($uniqueConstraints as $uniqueConstraint) { + $this->_addUniqueConstraint($uniqueConstraint); + } + + foreach ($fkConstraints as $fkConstraint) { + $this->_addForeignKeyConstraint($fkConstraint); } $this->_options = $options; @@ -80,18 +98,6 @@ public function setSchemaConfig(SchemaConfig $schemaConfig) $this->_schemaConfig = $schemaConfig; } - /** - * @return int - */ - protected function _getMaxIdentifierLength() - { - if ($this->_schemaConfig instanceof SchemaConfig) { - return $this->_schemaConfig->getMaxIdentifierLength(); - } - - return 63; - } - /** * Sets the Primary Key. * @@ -112,6 +118,26 @@ public function setPrimaryKey(array $columnNames, $indexName = false) return $this; } + /** + * @param mixed[] $columnNames + * @param string|null $indexName + * @param mixed[] $options + * + * @return self + */ + public function addUniqueConstraint(array $columnNames, $indexName = null, array $options = []) + { + if ($indexName === null) { + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $columnNames), + 'uniq', + $this->_getMaxIdentifierLength() + ); + } + + return $this->_addUniqueConstraint($this->_createUniqueConstraint($columnNames, $indexName, $options)); + } + /** * @param string[] $columnNames * @param string|null $indexName @@ -156,9 +182,11 @@ public function dropPrimaryKey() public function dropIndex($indexName) { $indexName = $this->normalizeIdentifier($indexName); + if (! $this->hasIndex($indexName)) { throw SchemaException::indexDoesNotExist($indexName, $this->_name); } + unset($this->_indexes[$indexName]); } @@ -247,33 +275,6 @@ public function columnsAreIndexed(array $columnNames) return false; } - /** - * @param string[] $columnNames - * @param string $indexName - * @param bool $isUnique - * @param bool $isPrimary - * @param string[] $flags - * @param mixed[] $options - * - * @return Index - * - * @throws SchemaException - */ - private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = []) - { - if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { - throw SchemaException::indexNameInvalid($indexName); - } - - foreach ($columnNames as $columnName) { - if (! $this->hasColumn($columnName)) { - throw SchemaException::columnDoesNotExist($columnName, $this->_name); - } - } - - return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options); - } - /** * @param string $columnName * @param string $typeName @@ -302,9 +303,11 @@ public function addColumn($columnName, $typeName, array $options = []) */ public function renameColumn($oldColumnName, $newColumnName) { - throw new DBALException('Table#renameColumn() was removed, because it drops and recreates ' . - 'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' . - 'column was renamed or one column was created and another one dropped.'); + throw new DBALException( + 'Table#renameColumn() was removed, because it drops and recreates the column instead. ' . + 'There is no fix available, because a schema diff cannot reliably detect if a column ' . + 'was renamed or one column was created and another one dropped.' + ); } /** @@ -318,6 +321,7 @@ public function renameColumn($oldColumnName, $newColumnName) public function changeColumn($columnName, array $options) { $column = $this->getColumn($columnName); + $column->setOptions($options); return $this; @@ -333,6 +337,7 @@ public function changeColumn($columnName, array $options) public function dropColumn($columnName) { $columnName = $this->normalizeIdentifier($columnName); + unset($this->_columns[$columnName]); return $this; @@ -353,7 +358,13 @@ public function dropColumn($columnName) */ public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], $constraintName = null) { - $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), 'fk', $this->_getMaxIdentifierLength()); + if (! $constraintName) { + $constraintName = $this->_generateIdentifierName( + array_merge((array) $this->getName(), $localColumnNames), + 'fk', + $this->_getMaxIdentifierLength() + ); + } return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options); } @@ -415,9 +426,8 @@ public function addNamedForeignKeyConstraint($name, $foreignTable, array $localC $name, $options ); - $this->_addForeignKeyConstraint($constraint); - return $this; + return $this->_addForeignKeyConstraint($constraint); } /** @@ -434,137 +444,95 @@ public function addOption($name, $value) } /** - * @return void + * Returns whether this table has a foreign key constraint with the given name. * - * @throws SchemaException + * @param string $constraintName + * + * @return bool */ - protected function _addColumn(Column $column) + public function hasForeignKey($constraintName) { - $columnName = $column->getName(); - $columnName = $this->normalizeIdentifier($columnName); - - if (isset($this->_columns[$columnName])) { - throw SchemaException::columnAlreadyExists($this->getName(), $columnName); - } + $constraintName = $this->normalizeIdentifier($constraintName); - $this->_columns[$columnName] = $column; + return isset($this->_fkConstraints[$constraintName]); } /** - * Adds an index to the table. + * Returns the foreign key constraint with the given name. * - * @return self + * @param string $constraintName The constraint name. * - * @throws SchemaException + * @return ForeignKeyConstraint + * + * @throws SchemaException If the foreign key does not exist. */ - protected function _addIndex(Index $indexCandidate) + public function getForeignKey($constraintName) { - $indexName = $indexCandidate->getName(); - $indexName = $this->normalizeIdentifier($indexName); - $replacedImplicitIndexes = []; - - foreach ($this->implicitIndexes as $name => $implicitIndex) { - if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { - continue; - } - - $replacedImplicitIndexes[] = $name; - } - - if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || - ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) - ) { - throw SchemaException::indexAlreadyExists($indexName, $this->_name); - } - - foreach ($replacedImplicitIndexes as $name) { - unset($this->_indexes[$name], $this->implicitIndexes[$name]); - } + $constraintName = $this->normalizeIdentifier($constraintName); - if ($indexCandidate->isPrimary()) { - $this->_primaryKeyName = $indexName; + if (! $this->hasForeignKey($constraintName)) { + throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); } - $this->_indexes[$indexName] = $indexCandidate; - - return $this; + return $this->_fkConstraints[$constraintName]; } /** + * Removes the foreign key constraint with the given name. + * + * @param string $constraintName The constraint name. + * * @return void + * + * @throws SchemaException */ - protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) + public function removeForeignKey($constraintName) { - $constraint->setLocalTable($this); - - if (strlen($constraint->getName())) { - $name = $constraint->getName(); - } else { - $name = $this->_generateIdentifierName( - array_merge((array) $this->getName(), $constraint->getLocalColumns()), - 'fk', - $this->_getMaxIdentifierLength() - ); - } - $name = $this->normalizeIdentifier($name); - - $this->_fkConstraints[$name] = $constraint; - - // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request. - // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes - // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns). - $indexName = $this->_generateIdentifierName( - array_merge([$this->getName()], $constraint->getColumns()), - 'idx', - $this->_getMaxIdentifierLength() - ); - $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); + $constraintName = $this->normalizeIdentifier($constraintName); - foreach ($this->_indexes as $existingIndex) { - if ($indexCandidate->isFullfilledBy($existingIndex)) { - return; - } + if (! $this->hasForeignKey($constraintName)) { + throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); } - $this->_addIndex($indexCandidate); - $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + unset($this->_fkConstraints[$constraintName]); } /** - * Returns whether this table has a foreign key constraint with the given name. + * Returns whether this table has a unique constraint with the given name. * * @param string $constraintName * * @return bool */ - public function hasForeignKey($constraintName) + public function hasUniqueConstraint($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); - return isset($this->_fkConstraints[$constraintName]); + return isset($this->_uniqueConstraints[$constraintName]); } /** - * Returns the foreign key constraint with the given name. + * Returns the unique constraint with the given name. * * @param string $constraintName The constraint name. * - * @return ForeignKeyConstraint + * @return UniqueConstraint * * @throws SchemaException If the foreign key does not exist. */ - public function getForeignKey($constraintName) + public function getUniqueConstraint($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); - if (! $this->hasForeignKey($constraintName)) { - throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + + if (! $this->hasUniqueConstraint($constraintName)) { + throw SchemaException::uniqueConstraintDoesNotExist($constraintName, $this->_name); } - return $this->_fkConstraints[$constraintName]; + return $this->_uniqueConstraints[$constraintName]; } /** - * Removes the foreign key constraint with the given name. + * Removes the unique constraint with the given name. * * @param string $constraintName The constraint name. * @@ -572,14 +540,15 @@ public function getForeignKey($constraintName) * * @throws SchemaException */ - public function removeForeignKey($constraintName) + public function removeUniqueConstraint($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); - if (! $this->hasForeignKey($constraintName)) { - throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + + if (! $this->hasUniqueConstraint($constraintName)) { + throw SchemaException::uniqueConstraintDoesNotExist($constraintName, $this->_name); } - unset($this->_fkConstraints[$constraintName]); + unset($this->_uniqueConstraints[$constraintName]); } /** @@ -589,29 +558,21 @@ public function removeForeignKey($constraintName) */ public function getColumns() { - $primaryKey = $this->getPrimaryKey(); - $primaryKeyColumns = []; + $pkCols = []; + $fkCols = []; + + $primaryKey = $this->getPrimaryKey(); if ($primaryKey !== null) { - $primaryKeyColumns = $this->filterColumns($primaryKey->getColumns()); + $pkCols = $this->filterColumns($primaryKey->getColumns()); } - return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns); - } - - /** - * Returns foreign key columns - * - * @return Column[] - */ - private function getForeignKeyColumns() - { - $foreignKeyColumns = []; - foreach ($this->getForeignKeys() as $foreignKey) { - $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns()); + foreach ($this->getForeignKeys() as $fk) { + /** @var ForeignKeyConstraint $fk */ + $fkCols = array_merge($fkCols, $fk->getColumns()); } - return $this->filterColumns($foreignKeyColumns); + return array_unique(array_merge($pkCols, $fkCols, array_keys($this->_columns))); } /** @@ -654,6 +615,7 @@ public function hasColumn($columnName) public function getColumn($columnName) { $columnName = $this->normalizeIdentifier($columnName); + if (! $this->hasColumn($columnName)) { throw SchemaException::columnDoesNotExist($columnName, $this->_name); } @@ -668,11 +630,9 @@ public function getColumn($columnName) */ public function getPrimaryKey() { - if (! $this->hasPrimaryKey()) { - return null; - } - - return $this->getIndex($this->_primaryKeyName); + return $this->hasPrimaryKey() + ? $this->getIndex($this->_primaryKeyName) + : null; } /** @@ -729,6 +689,7 @@ public function hasIndex($indexName) public function getIndex($indexName) { $indexName = $this->normalizeIdentifier($indexName); + if (! $this->hasIndex($indexName)) { throw SchemaException::indexDoesNotExist($indexName, $this->_name); } @@ -744,6 +705,16 @@ public function getIndexes() return $this->_indexes; } + /** + * Returns the unique constraints. + * + * @return UniqueConstraint[] + */ + public function getUniqueConstraints() + { + return $this->_uniqueConstraints; + } + /** * Returns the foreign key constraints. * @@ -812,15 +783,166 @@ public function __clone() foreach ($this->_columns as $k => $column) { $this->_columns[$k] = clone $column; } + foreach ($this->_indexes as $k => $index) { $this->_indexes[$k] = clone $index; } + foreach ($this->_fkConstraints as $k => $fk) { $this->_fkConstraints[$k] = clone $fk; $this->_fkConstraints[$k]->setLocalTable($this); } } + /** + * @return int + */ + protected function _getMaxIdentifierLength() + { + return $this->_schemaConfig instanceof SchemaConfig + ? $this->_schemaConfig->getMaxIdentifierLength() + : 63; + } + + /** + * @return void + * + * @throws SchemaException + */ + protected function _addColumn(Column $column) + { + $columnName = $column->getName(); + $columnName = $this->normalizeIdentifier($columnName); + + if (isset($this->_columns[$columnName])) { + throw SchemaException::columnAlreadyExists($this->getName(), $columnName); + } + + $this->_columns[$columnName] = $column; + } + + /** + * Adds an index to the table. + * + * @return self + * + * @throws SchemaException + */ + protected function _addIndex(Index $indexCandidate) + { + $indexName = $indexCandidate->getName(); + $indexName = $this->normalizeIdentifier($indexName); + $replacedImplicitIndexes = []; + + foreach ($this->implicitIndexes as $name => $implicitIndex) { + if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { + continue; + } + + $replacedImplicitIndexes[] = $name; + } + + if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || + ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) + ) { + throw SchemaException::indexAlreadyExists($indexName, $this->_name); + } + + foreach ($replacedImplicitIndexes as $name) { + unset($this->_indexes[$name], $this->implicitIndexes[$name]); + } + + if ($indexCandidate->isPrimary()) { + $this->_primaryKeyName = $indexName; + } + + $this->_indexes[$indexName] = $indexCandidate; + + return $this; + } + + /** + * @return self + */ + protected function _addUniqueConstraint(UniqueConstraint $uniqueConstraint) + { + $name = strlen($uniqueConstraint->getName()) + ? $uniqueConstraint->getName() + : $this->_generateIdentifierName( + array_merge((array) $this->getName(), $uniqueConstraint->getLocalColumns()), + 'fk', + $this->_getMaxIdentifierLength() + ); + + $name = $this->normalizeIdentifier($name); + + $this->_uniqueConstraints[$name] = $uniqueConstraint; + + // If there is already an index that fulfills this requirements drop the request. In the case of __construct + // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. + // This creates computation overhead in this case, however no duplicate indexes are ever added (column based). + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $uniqueConstraint->getColumns()), + 'idx', + $this->_getMaxIdentifierLength() + ); + + $indexCandidate = $this->_createIndex($uniqueConstraint->getColumns(), $indexName, true, false); + + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return $this; + } + } + + $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + + return $this; + } + + /** + * @return self + */ + protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) + { + $constraint->setLocalTable($this); + + $name = strlen($constraint->getName()) + ? $constraint->getName() + : $this->_generateIdentifierName( + array_merge((array) $this->getName(), $constraint->getLocalColumns()), + 'fk', + $this->_getMaxIdentifierLength() + ); + + $name = $this->normalizeIdentifier($name); + + $this->_fkConstraints[$name] = $constraint; + + // add an explicit index on the foreign key columns. + // If there is already an index that fulfills this requirements drop the request. In the case of __construct + // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. + // This creates computation overhead in this case, however no duplicate indexes are ever added (column based). + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $constraint->getColumns()), + 'idx', + $this->_getMaxIdentifierLength() + ); + + $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); + + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return $this; + } + } + + $this->_addIndex($indexCandidate); + $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + + return $this; + } + /** * Normalizes a given identifier. * @@ -838,4 +960,67 @@ private function normalizeIdentifier($identifier) return $this->trimQuotes(strtolower($identifier)); } + + /** + * @param mixed[] $columns + * @param string $indexName + * @param mixed[] $options + * + * @return UniqueConstraint + * + * @throws SchemaException + */ + private function _createUniqueConstraint(array $columns, $indexName, array $options = []) + { + if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { + throw SchemaException::indexNameInvalid($indexName); + } + + foreach ($columns as $index => $value) { + if (is_string($index)) { + $columnName = $index; + } else { + $columnName = $value; + } + + if (! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + + return new UniqueConstraint($indexName, $columns, $options); + } + + /** + * @param mixed[] $columns + * @param string $indexName + * @param bool $isUnique + * @param bool $isPrimary + * @param string[] $flags + * @param mixed[] $options + * + * @return Index + * + * @throws SchemaException + */ + private function _createIndex(array $columns, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = []) + { + if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { + throw SchemaException::indexNameInvalid($indexName); + } + + foreach ($columns as $index => $value) { + if (is_string($index)) { + $columnName = $index; + } else { + $columnName = $value; + } + + if (! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + + return new Index($indexName, $columns, $isUnique, $isPrimary, $flags, $options); + } } diff --git a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php new file mode 100644 index 00000000000..0f0ba14d076 --- /dev/null +++ b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php @@ -0,0 +1,121 @@ + Identifier) + * + * @var Identifier[] + */ + protected $columns = []; + + /** + * Platform specific options + * + * @var mixed[] + */ + private $options = []; + + /** + * @param string $indexName + * @param string[] $columns + * @param mixed[] $options + */ + public function __construct($indexName, array $columns, array $options = []) + { + $this->_setName($indexName); + + $this->options = $options; + + foreach ($columns as $column) { + $this->_addColumn($column); + } + } + + /** + * @param string $column + * + * @return void + * + * @throws InvalidArgumentException + */ + protected function _addColumn($column) + { + if (! is_string($column)) { + throw new InvalidArgumentException('Expecting a string as Index Column'); + } + + $this->_columns[$column] = new Identifier($column); + } + + /** + * {@inheritdoc} + */ + public function getColumns() + { + return array_keys($this->_columns); + } + + /** + * {@inheritdoc} + */ + public function getQuotedColumns(AbstractPlatform $platform) + { + $columns = []; + + foreach ($this->_columns as $column) { + $columns[] = $column->getQuotedName($platform); + } + + return $columns; + } + + /** + * @return string[] + */ + public function getUnquotedColumns() + { + return array_map([$this, 'trimQuotes'], $this->getColumns()); + } + + /** + * @param string $name + * + * @return bool + */ + public function hasOption($name) + { + return isset($this->options[strtolower($name)]); + } + + /** + * @param string $name + * + * @return mixed + */ + public function getOption($name) + { + return $this->options[strtolower($name)]; + } + + /** + * @return mixed[] + */ + public function getOptions() + { + return $this->options; + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php index 54b4bc1d90a..3aa1a19e81f 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php @@ -314,6 +314,7 @@ public function testConnectionExceptionSqLite($mode, $exceptionClass) $table->addColumn('id', 'integer'); $this->expectException($exceptionClass); + foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) { $conn->exec($sql); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index aeb9f4c90dd..58f7554d7c7 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -974,7 +974,7 @@ protected function createTestTable($name = 'test_table', array $data = []) protected function getTestTable($name, $options = []) { - $table = new Table($name, [], [], [], false, $options); + $table = new Table($name, [], [], [], [], false, $options); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id']); @@ -986,7 +986,7 @@ protected function getTestTable($name, $options = []) protected function getTestCompositeTable($name) { - $table = new Table($name, [], [], [], false, []); + $table = new Table($name, [], [], [], [], false, []); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('other_id', 'integer', ['notnull' => true]); @@ -999,14 +999,17 @@ protected function getTestCompositeTable($name) protected function assertHasTable($tables, $tableName) { $foundTable = false; + foreach ($tables as $table) { self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.'); + if (strtolower($table->getName()) !== 'list_tables_test_new_name') { continue; } $foundTable = true; } + self::assertTrue($foundTable, 'Could not find new table'); } diff --git a/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php b/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php index 5222a1ee548..6395479b2ed 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php @@ -1269,6 +1269,7 @@ public function testForeignKeyRemovalWithRenamedLocalColumn() 'id_table1' => new Column('id_table1', Type::getType('integer')), ], [], + [], [ new ForeignKeyConstraint(['id_table1'], 'table1', ['id'], 'fk_table2_table1'), ] @@ -1282,6 +1283,7 @@ public function testForeignKeyRemovalWithRenamedLocalColumn() 'id_table3' => new Column('id_table3', Type::getType('integer')), ], [], + [], [ new ForeignKeyConstraint(['id_table3'], 'table3', ['id'], 'fk_table2_table3'), ] diff --git a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php index 154a29ad7b0..c1d05ceedb1 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php @@ -200,7 +200,7 @@ public function testConstraints() { $constraint = new ForeignKeyConstraint([], 'foo', []); - $tableA = new Table('foo', [], [], [$constraint]); + $tableA = new Table('foo', [], [], [], [$constraint]); $constraints = $tableA->getForeignKeys(); self::assertCount(1, $constraints); @@ -209,7 +209,7 @@ public function testConstraints() public function testOptions() { - $table = new Table('foo', [], [], [], false, ['foo' => 'bar']); + $table = new Table('foo', [], [], [], [], false, ['foo' => 'bar']); self::assertTrue($table->hasOption('foo')); self::assertEquals('bar', $table->getOption('foo')); From 75ca0b983ca9719cfb51da17b08a6aea4f6778f5 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Thu, 22 Sep 2016 22:53:42 +0000 Subject: [PATCH 02/66] Added flag support to unique constraint --- .../DBAL/Platforms/AbstractPlatform.php | 18 +++-- .../DBAL/Platforms/DrizzlePlatform.php | 4 +- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 4 +- .../DBAL/Platforms/OraclePlatform.php | 8 +-- .../DBAL/Platforms/SQLAnywherePlatform.php | 21 ------ .../DBAL/Platforms/SQLServerPlatform.php | 12 ---- .../DBAL/Platforms/SqlitePlatform.php | 16 +++-- lib/Doctrine/DBAL/Schema/Table.php | 16 +++-- lib/Doctrine/DBAL/Schema/UniqueConstraint.php | 65 ++++++++++++++++++- 9 files changed, 102 insertions(+), 62 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 3cdcdfc9ac3..153bae9a80b 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -2355,25 +2355,31 @@ public function getCheckDeclarationSQL(array $definition) * Obtains DBMS specific SQL code portion needed to set a unique * constraint declaration to be used in statements like CREATE TABLE. * - * @param string $name The name of the unique constraint. - * @param Index $index The index definition. + * @param string $name The name of the unique constraint. + * @param UniqueConstraint $constraint The unique constraint definition. * * @return string DBMS specific SQL code portion needed to set a constraint. * * @throws InvalidArgumentException */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) + public function getUniqueConstraintDeclarationSQL($name, UniqueConstraint $constraint) { - $columns = $index->getColumns(); + $columns = $constraint->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } - return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE (' + $flags = ''; + + if ($constraint->hasFlag('clustered')) { + $flags = 'CLUSTERED '; + } + + return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ' . $flags . ' (' . $this->getIndexFieldDeclarationListSQL($index) - . ')' . $this->getPartialIndexSQL($index); + . ')'; } /** diff --git a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php b/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php index 8f6f0966323..48c5a6c00eb 100644 --- a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php @@ -191,8 +191,8 @@ 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); + foreach ($options['uniqueConstraints'] as $name => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 9679a8447e7..311574226b8 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -418,8 +418,8 @@ 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); + foreach ($options['uniqueConstraints'] as $name => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index ced7fbf9bdc..c7691c076fb 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -376,11 +376,11 @@ public function getListSequencesSQL($database) /** * {@inheritDoc} */ - protected function _getCreateTableSQL($table, array $columns, array $options = []) + protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $indexes = $options['indexes'] ?? []; $options['indexes'] = []; - $sql = parent::_getCreateTableSQL($table, $columns, $options); + $sql = parent::_getCreateTableSQL($tableName, $columns, $options); foreach ($columns as $name => $column) { if (isset($column['sequence'])) { @@ -392,12 +392,12 @@ protected function _getCreateTableSQL($table, array $columns, array $options = [ continue; } - $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table)); + $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $tableName)); } if (isset($indexes) && ! empty($indexes)) { foreach ($indexes as $index) { - $sql[] = $this->getCreateIndexSQL($index, $table); + $sql[] = $this->getCreateIndexSQL($index, $tableName); } } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 6e3b2fcb958..773e9a27368 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1160,27 +1160,6 @@ public function getTruncateTableSQL($tableName, $cascade = false) return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); } - /** - * {@inheritdoc} - */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) - { - if ($index->isPrimary()) { - throw new InvalidArgumentException( - 'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().' - ); - } - - if (! $index->isUnique()) { - throw new InvalidArgumentException( - 'Can only create unique constraint declarations, no common index declarations with ' . - 'getUniqueConstraintDeclarationSQL().' - ); - } - - return $this->getTableConstraintDeclarationSQL($index, $name); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index a2e68049d68..4c7be5f2199 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -393,18 +393,6 @@ public function getDefaultConstraintDeclarationSQL($table, array $column) ' FOR ' . $columnName->getQuotedName($this); } - /** - * {@inheritDoc} - */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) - { - $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index); - - $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); - - return $constraint; - } - /** * {@inheritDoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 68b2eb8bb92..f64409e6485 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -313,9 +313,9 @@ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) /** * {@inheritDoc} */ - protected function _getCreateTableSQL($name, array $columns, array $options = []) + protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { - $name = str_replace('.', '__', $name); + $tableName = str_replace('.', '__', $tableName); $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { @@ -332,7 +332,7 @@ protected function _getCreateTableSQL($name, array $columns, array $options = [] } } - $query = ['CREATE TABLE ' . $name . ' (' . $queryFields . ')']; + $query = ['CREATE TABLE ' . $tableName . ' (' . $queryFields . ')']; if (isset($options['alter']) && $options['alter'] === true) { return $query; @@ -340,13 +340,13 @@ protected function _getCreateTableSQL($name, array $columns, array $options = [] if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $indexDef) { - $query[] = $this->getCreateIndexSQL($indexDef, $name); + $query[] = $this->getCreateIndexSQL($indexDef, $tableName); } } if (isset($options['unique']) && ! empty($options['unique'])) { foreach ($options['unique'] as $indexDef) { - $query[] = $this->getCreateIndexSQL($indexDef, $name); + $query[] = $this->getCreateIndexSQL($indexDef, $tableName); } } @@ -381,8 +381,10 @@ private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $ */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') - : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); + return $fixed + ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT') + ; } /** diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index adeae4fe60e..05a4f2cb8d4 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -121,11 +121,12 @@ public function setPrimaryKey(array $columnNames, $indexName = false) /** * @param mixed[] $columnNames * @param string|null $indexName + * @param array $flags * @param mixed[] $options * * @return self */ - public function addUniqueConstraint(array $columnNames, $indexName = null, array $options = []) + public function addUniqueConstraint(array $columnNames, $indexName = null, array $flags = array(), array $options = []) { if ($indexName === null) { $indexName = $this->_generateIdentifierName( @@ -135,7 +136,7 @@ public function addUniqueConstraint(array $columnNames, $indexName = null, array ); } - return $this->_addUniqueConstraint($this->_createUniqueConstraint($columnNames, $indexName, $options)); + return $this->_addUniqueConstraint($this->_createUniqueConstraint($columnNames, $indexName, $flags, $options)); } /** @@ -864,7 +865,7 @@ protected function _addIndex(Index $indexCandidate) /** * @return self */ - protected function _addUniqueConstraint(UniqueConstraint $uniqueConstraint) + protected function _addUniqueConstraint(UniqueConstraint $constraint) { $name = strlen($uniqueConstraint->getName()) ? $uniqueConstraint->getName() @@ -876,7 +877,7 @@ protected function _addUniqueConstraint(UniqueConstraint $uniqueConstraint) $name = $this->normalizeIdentifier($name); - $this->_uniqueConstraints[$name] = $uniqueConstraint; + $this->_uniqueConstraints[$name] = $constraint; // If there is already an index that fulfills this requirements drop the request. In the case of __construct // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. @@ -964,13 +965,14 @@ private function normalizeIdentifier($identifier) /** * @param mixed[] $columns * @param string $indexName - * @param mixed[] $options + * @param mixed[] $flags + * @param array $options * * @return UniqueConstraint * * @throws SchemaException */ - private function _createUniqueConstraint(array $columns, $indexName, array $options = []) + private function _createUniqueConstraint(array $columns, $indexName, array $flags = array(), array $options = []) { if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { throw SchemaException::indexNameInvalid($indexName); @@ -988,7 +990,7 @@ private function _createUniqueConstraint(array $columns, $indexName, array $opti } } - return new UniqueConstraint($indexName, $columns, $options); + return new UniqueConstraint($indexName, $columns, $flags, $options); } /** diff --git a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php index 0f0ba14d076..5c8a43afb7c 100644 --- a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php +++ b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php @@ -22,6 +22,14 @@ class UniqueConstraint extends AbstractAsset implements Constraint */ protected $columns = []; + /** + * Platform specific flags + * array($flagName => true) + * + * @var array + */ + protected $flags = array(); + /** * Platform specific options * @@ -32,9 +40,10 @@ class UniqueConstraint extends AbstractAsset implements Constraint /** * @param string $indexName * @param string[] $columns + * @param array $flags * @param mixed[] $options */ - public function __construct($indexName, array $columns, array $options = []) + public function __construct($indexName, array $columns, array $flags = array(), array $options = []) { $this->_setName($indexName); @@ -43,6 +52,10 @@ public function __construct($indexName, array $columns, array $options = []) foreach ($columns as $column) { $this->_addColumn($column); } + + foreach ($flags as $flag) { + $this->addFlag($flag); + } } /** @@ -91,6 +104,56 @@ public function getUnquotedColumns() return array_map([$this, 'trimQuotes'], $this->getColumns()); } + /** + * Returns platform specific flags for unique constraint. + * + * @return string[] + */ + public function getFlags() + { + return array_keys($this->flags); + } + + /** + * Adds flag for a unique constraint that translates to platform specific handling. + * + * @example $uniqueConstraint->addFlag('CLUSTERED') + * + * @param string $flag + * + * @return self + */ + public function addFlag($flag) + { + $this->flags[strtolower($flag)] = true; + + return $this; + } + + /** + * Does this unique constraint have a specific flag? + * + * @param string $flag + * + * @return boolean + */ + public function hasFlag($flag) + { + return isset($this->flags[strtolower($flag)]); + } + + /** + * Removes a flag. + * + * @param string $flag + * + * @return void + */ + public function removeFlag($flag) + { + unset($this->flags[strtolower($flag)]); + } + /** * @param string $name * From 64a1f9507e66222f0681875c0322b8b31b66462a Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Sat, 24 Sep 2016 03:36:58 +0000 Subject: [PATCH 03/66] Fixed tests --- .../DBAL/Platforms/AbstractPlatform.php | 12 +++-- .../DBAL/Platforms/SqlitePlatform.php | 5 +- lib/Doctrine/DBAL/Schema/Table.php | 8 +-- lib/Doctrine/DBAL/Schema/UniqueConstraint.php | 50 +++++++++---------- .../Platforms/AbstractPlatformTestCase.php | 26 +++++----- .../AbstractSQLServerPlatformTestCase.php | 2 +- .../Platforms/SQLAnywherePlatformTest.php | 9 ++-- 7 files changed, 57 insertions(+), 55 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 153bae9a80b..490e92b3847 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -2371,15 +2371,17 @@ public function getUniqueConstraintDeclarationSQL($name, UniqueConstraint $const throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } - $flags = ''; + $flags = ['UNIQUE']; if ($constraint->hasFlag('clustered')) { - $flags = 'CLUSTERED '; + $flags[] = 'CLUSTERED'; } - return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ' . $flags . ' (' - . $this->getIndexFieldDeclarationListSQL($index) - . ')'; + $constraintName = $name->getQuotedName($this); + $constraintName = ! empty($constraintName) ? $constraintName . ' ' : ''; + $columnListNames = $this->getIndexFieldDeclarationListSQL($columns); + + return sprintf('CONSTRAINT %s%s (%s)', $constraintName, implode(' ', $flags), $columnListNames); } /** diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index f64409e6485..944f5a42b8e 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -315,7 +315,7 @@ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { - $tableName = str_replace('.', '__', $tableName); + $tableName = str_replace('.', '__', $tableName); $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { @@ -383,8 +383,7 @@ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') - : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT') - ; + : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); } /** diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index 05a4f2cb8d4..4cb21a085f5 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -121,12 +121,12 @@ public function setPrimaryKey(array $columnNames, $indexName = false) /** * @param mixed[] $columnNames * @param string|null $indexName - * @param array $flags + * @param string[] $flags * @param mixed[] $options * * @return self */ - public function addUniqueConstraint(array $columnNames, $indexName = null, array $flags = array(), array $options = []) + public function addUniqueConstraint(array $columnNames, $indexName = null, array $flags = [], array $options = []) { if ($indexName === null) { $indexName = $this->_generateIdentifierName( @@ -966,13 +966,13 @@ private function normalizeIdentifier($identifier) * @param mixed[] $columns * @param string $indexName * @param mixed[] $flags - * @param array $options + * @param mixed[] $options * * @return UniqueConstraint * * @throws SchemaException */ - private function _createUniqueConstraint(array $columns, $indexName, array $flags = array(), array $options = []) + private function _createUniqueConstraint(array $columns, $indexName, array $flags = [], array $options = []) { if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { throw SchemaException::indexNameInvalid($indexName); diff --git a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php index 5c8a43afb7c..8d47424769c 100644 --- a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php +++ b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php @@ -26,9 +26,9 @@ class UniqueConstraint extends AbstractAsset implements Constraint * Platform specific flags * array($flagName => true) * - * @var array + * @var true[] */ - protected $flags = array(); + protected $flags = []; /** * Platform specific options @@ -40,10 +40,10 @@ class UniqueConstraint extends AbstractAsset implements Constraint /** * @param string $indexName * @param string[] $columns - * @param array $flags + * @param string[] $flags * @param mixed[] $options */ - public function __construct($indexName, array $columns, array $flags = array(), array $options = []) + public function __construct($indexName, array $columns, array $flags = [], array $options = []) { $this->_setName($indexName); @@ -58,28 +58,12 @@ public function __construct($indexName, array $columns, array $flags = array(), } } - /** - * @param string $column - * - * @return void - * - * @throws InvalidArgumentException - */ - protected function _addColumn($column) - { - if (! is_string($column)) { - throw new InvalidArgumentException('Expecting a string as Index Column'); - } - - $this->_columns[$column] = new Identifier($column); - } - /** * {@inheritdoc} */ public function getColumns() { - return array_keys($this->_columns); + return array_keys($this->columns); } /** @@ -89,7 +73,7 @@ public function getQuotedColumns(AbstractPlatform $platform) { $columns = []; - foreach ($this->_columns as $column) { + foreach ($this->columns as $column) { $columns[] = $column->getQuotedName($platform); } @@ -117,11 +101,11 @@ public function getFlags() /** * Adds flag for a unique constraint that translates to platform specific handling. * - * @example $uniqueConstraint->addFlag('CLUSTERED') - * * @param string $flag * * @return self + * + * @example $uniqueConstraint->addFlag('CLUSTERED') */ public function addFlag($flag) { @@ -135,7 +119,7 @@ public function addFlag($flag) * * @param string $flag * - * @return boolean + * @return bool */ public function hasFlag($flag) { @@ -181,4 +165,20 @@ public function getOptions() { return $this->options; } + + /** + * @param string $column + * + * @return void + * + * @throws InvalidArgumentException + */ + protected function _addColumn($column) + { + if (! is_string($column)) { + throw new InvalidArgumentException('Expecting a string as Index Column'); + } + + $this->columns[$column] = new Identifier($column); + } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php index 910f2daa2c1..3b66ff41e0e 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php @@ -14,6 +14,7 @@ use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\Schema\UniqueConstraint; use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalTestCase; use Doctrine\Tests\Types\CommentedType; @@ -212,9 +213,9 @@ abstract public function getGenerateUniqueIndexSql(); public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() { - $where = 'test IS NULL AND test2 IS NOT NULL'; - $indexDef = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]); - $uniqueIndex = new Index('name', ['test', 'test2'], true, false, [], ['where' => $where]); + $where = 'test IS NULL AND test2 IS NOT NULL'; + $indexDef = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]); + $uniqueConstraint = new UniqueConstraint('name', ['test', 'test2'], [], []); $expected = ' WHERE ' . $where; @@ -224,15 +225,14 @@ public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() $actuals[] = $this->platform->getIndexDeclarationSQL('name', $indexDef); } - $actuals[] = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueIndex); - $actuals[] = $this->platform->getCreateIndexSQL($indexDef, 'table'); + $uniqueConstraintSQL = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueConstraint); + $indexSQL = $this->platform->getCreateIndexSQL($indexDef, 'table'); - foreach ($actuals as $actual) { - if ($this->platform->supportsPartialIndexes()) { - self::assertStringEndsWith($expected, $actual, 'WHERE clause should be present'); - } else { - self::assertStringEndsNotWith($expected, $actual, 'WHERE clause should NOT be present'); - } + $this->assertStringEndsNotWith($expected, $uniqueConstraintSQL, 'WHERE clause should NOT be present'); + if ($this->platform->supportsPartialIndexes()) { + self::assertStringEndsWith($expected, $indexSQL, 'WHERE clause should be present'); + } else { + self::assertStringEndsNotWith($expected, $indexSQL, 'WHERE clause should NOT be present'); } } @@ -701,11 +701,11 @@ public function testQuotedColumnInForeignKeyPropagation() */ public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() { - $index = new Index('select', ['foo'], true); + $constraint = new UniqueConstraint('select', ['foo'], [], []); self::assertSame( $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(), - $this->platform->getUniqueConstraintDeclarationSQL('select', $index) + $this->platform->getUniqueConstraintDeclarationSQL('select', $constraint) ); } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index b43facd2406..52dd5753443 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -1369,7 +1369,7 @@ public function getReturnsForeignKeyReferentialActionSQL() */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() { - return 'CONSTRAINT [select] UNIQUE (foo) WHERE foo IS NOT NULL'; + return 'CONSTRAINT [select] UNIQUE (foo)'; } /** diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index 767fb268408..5d312ba7c0f 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -15,6 +15,7 @@ use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\Schema\UniqueConstraint; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; use InvalidArgumentException; @@ -359,12 +360,12 @@ public function testGeneratesUniqueConstraintDeclarationSQL() 'CONSTRAINT unique_constraint UNIQUE CLUSTERED (a, b)', $this->platform->getUniqueConstraintDeclarationSQL( 'unique_constraint', - new Index(null, ['a', 'b'], true, false, ['clustered']) + new UniqueConstraint(null, ['a', 'b'], ['clustered']) ) ); self::assertEquals( - 'UNIQUE (a, b)', - $this->platform->getUniqueConstraintDeclarationSQL(null, new Index(null, ['a', 'b'], true, false)) + 'CONSTRAINT UNIQUE (a, b)', + $this->platform->getUniqueConstraintDeclarationSQL(null, new UniqueConstraint(null, ['a', 'b'])) ); } @@ -372,7 +373,7 @@ public function testCannotGenerateUniqueConstraintDeclarationSQLWithEmptyColumns { $this->expectException(InvalidArgumentException::class); - $this->platform->getUniqueConstraintDeclarationSQL('constr', new Index('constr', [], true)); + $this->platform->getUniqueConstraintDeclarationSQL('constr', new UniqueConstraint('constr', [])); } public function testGeneratesForeignKeyConstraintsWithAdvancedPlatformOptionsSQL() From dc9696ebf8f62cce2feead479dca1fe2281da300 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Sat, 24 Sep 2016 04:02:45 +0000 Subject: [PATCH 04/66] Removed identifier generator type from schema table definition --- lib/Doctrine/DBAL/Platforms/SqlitePlatform.php | 2 +- lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php | 2 +- lib/Doctrine/DBAL/Schema/Table.php | 2 -- .../Functional/Schema/SchemaManagerFunctionalTestCase.php | 4 ++-- tests/Doctrine/Tests/DBAL/Schema/TableTest.php | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 944f5a42b8e..01fe94e3068 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -903,7 +903,7 @@ public function getAlterTableSQL(TableDiff $diff) if (! $this->onSchemaAlterTable($diff, $tableSql)) { $dataTable = new Table('__temp__' . $table->getName()); - $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), [], $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions()); + $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), [], $this->getForeignKeysInAlteredTable($diff), $table->getOptions()); $newTable->addOption('alter', true); $sql = $this->getPreAlterTableIndexForeignKeySQL($diff); diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index f932e354b5c..2bb71224e70 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -275,7 +275,7 @@ public function listTableDetails($tableName) $indexes = $this->listTableIndexes($tableName); - return new Table($tableName, $columns, $indexes, [], $foreignKeys); + return new Table($tableName, $columns, $indexes, [], $foreignKeys, []); } /** diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index 4cb21a085f5..c6c3e5007cb 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -51,7 +51,6 @@ class Table extends AbstractAsset * @param Index[] $indexes * @param UniqueConstraint[] $uniqueConstraints * @param ForeignKeyConstraint[] $fkConstraints - * @param int $idGeneratorType * @param mixed[] $options * * @throws DBALException @@ -62,7 +61,6 @@ public function __construct( array $indexes = [], array $uniqueConstraints = [], array $fkConstraints = [], - $idGeneratorType = 0, array $options = [] ) { if (strlen($tableName) === 0) { diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 58f7554d7c7..50fa10b4196 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -974,7 +974,7 @@ protected function createTestTable($name = 'test_table', array $data = []) protected function getTestTable($name, $options = []) { - $table = new Table($name, [], [], [], [], false, $options); + $table = new Table($name, [], [], [], [], $options); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id']); @@ -986,7 +986,7 @@ protected function getTestTable($name, $options = []) protected function getTestCompositeTable($name) { - $table = new Table($name, [], [], [], [], false, []); + $table = new Table($name, [], [], [], [], []); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('other_id', 'integer', ['notnull' => true]); diff --git a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php index c1d05ceedb1..4dc01fff7f4 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php @@ -209,7 +209,7 @@ public function testConstraints() public function testOptions() { - $table = new Table('foo', [], [], [], [], false, ['foo' => 'bar']); + $table = new Table('foo', [], [], [], [], ['foo' => 'bar']); self::assertTrue($table->hasOption('foo')); self::assertEquals('bar', $table->getOption('foo')); From b4da554bfbb697c390eb486cbc53bb28e79430f5 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Wed, 21 Jun 2017 18:40:47 -0400 Subject: [PATCH 05/66] Fixing rebase with master --- lib/Doctrine/DBAL/Schema/Table.php | 31 +++++++------------ .../Driver/Mysqli/MysqliConnectionTest.php | 2 +- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index c6c3e5007cb..814f7885a68 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -5,16 +5,16 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Schema\Visitor\Visitor; use Doctrine\DBAL\Types\Type; -use const ARRAY_FILTER_USE_KEY; -use function array_filter; use function array_keys; use function array_merge; +use function array_search; use function array_unique; use function in_array; use function is_string; use function preg_match; use function strlen; use function strtolower; +use function uksort; /** * Object Representation of a table. @@ -557,13 +557,14 @@ public function removeUniqueConstraint($constraintName) */ public function getColumns() { - $pkCols = []; - $fkCols = []; + $columns = $this->_columns; + $pkCols = []; + $fkCols = []; $primaryKey = $this->getPrimaryKey(); if ($primaryKey !== null) { - $pkCols = $this->filterColumns($primaryKey->getColumns()); + $pkCols = $primaryKey->getColumns(); } foreach ($this->getForeignKeys() as $fk) { @@ -571,21 +572,13 @@ public function getColumns() $fkCols = array_merge($fkCols, $fk->getColumns()); } - return array_unique(array_merge($pkCols, $fkCols, array_keys($this->_columns))); - } + $colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns))); - /** - * Returns only columns that have specified names - * - * @param string[] $columnNames - * - * @return Column[] - */ - private function filterColumns(array $columnNames) - { - return array_filter($this->_columns, static function ($columnName) use ($columnNames) { - return in_array($columnName, $columnNames, true); - }, ARRAY_FILTER_USE_KEY); + uksort($columns, static function ($a, $b) use ($colNames) { + return array_search($a, $colNames) >= array_search($b, $colNames); + }); + + return $columns; } /** diff --git a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php index a192edf6f52..52dc12eb693 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php @@ -53,7 +53,7 @@ public function testRestoresErrorHandlerOnException() new MysqliConnection(['host' => '255.255.255.255'], 'user', 'pass'); self::fail('An exception was supposed to be raised'); } catch (MysqliException $e) { - self::assertSame('Network is unreachable', $e->getMessage()); + // Do nothing } self::assertSame($handler, set_error_handler($default_handler), 'Restoring error handler failed.'); From ca0e17de902d37fbe8b17ba40d13996e91425cf1 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Wed, 21 Jun 2017 21:50:42 -0400 Subject: [PATCH 06/66] Fixed undefined result of rebase --- lib/Doctrine/DBAL/Schema/Table.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index 814f7885a68..781df0ed27a 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -858,10 +858,10 @@ protected function _addIndex(Index $indexCandidate) */ protected function _addUniqueConstraint(UniqueConstraint $constraint) { - $name = strlen($uniqueConstraint->getName()) - ? $uniqueConstraint->getName() + $name = strlen($constraint->getName()) + ? $constraint->getName() : $this->_generateIdentifierName( - array_merge((array) $this->getName(), $uniqueConstraint->getLocalColumns()), + array_merge((array) $this->getName(), $constraint->getLocalColumns()), 'fk', $this->_getMaxIdentifierLength() ); @@ -874,12 +874,12 @@ protected function _addUniqueConstraint(UniqueConstraint $constraint) // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. // This creates computation overhead in this case, however no duplicate indexes are ever added (column based). $indexName = $this->_generateIdentifierName( - array_merge([$this->getName()], $uniqueConstraint->getColumns()), + array_merge([$this->getName()], $constraint->getColumns()), 'idx', $this->_getMaxIdentifierLength() ); - $indexCandidate = $this->_createIndex($uniqueConstraint->getColumns(), $indexName, true, false); + $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, true, false); foreach ($this->_indexes as $existingIndex) { if ($indexCandidate->isFullfilledBy($existingIndex)) { From 2513424265c0808b1837a467252a2264fdf2d366 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Mon, 10 Jul 2017 22:13:43 -0400 Subject: [PATCH 07/66] Moved getSequencePrefix() from ClassMetadata (ORM) to AbstractPlatform (DBAL) --- .../DBAL/Platforms/AbstractPlatform.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 490e92b3847..df56a61aa02 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -3076,6 +3076,26 @@ public function usesSequenceEmulatedIdentityColumns() return false; } + /** + * Gets the sequence name prefix based on table information. + * + * @param string $tableName + * @param string|null $schemaName + * + * @return string + */ + public function getSequencePrefix($tableName, $schemaName = null) + { + if (! $schemaName) { + return $tableName; + } + + // Prepend the schema name to the table name if there is one + return ! $this->supportsSchemas() && $this->canEmulateSchemas() + ? $schemaName . '__' . $tableName + : $schemaName . '.' . $tableName; + } + /** * Returns the name of the sequence for a particular identity column in a particular table. * From e656cd5fd96479f11f621a236ca1fa3c37e07ded Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 5 Jan 2018 05:16:58 +0100 Subject: [PATCH 08/66] Bump version to 3.0.x-dev --- lib/Doctrine/DBAL/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/DBAL/Version.php b/lib/Doctrine/DBAL/Version.php index 93be3a1dfba..d9d48eb7d3f 100644 --- a/lib/Doctrine/DBAL/Version.php +++ b/lib/Doctrine/DBAL/Version.php @@ -14,7 +14,7 @@ class Version /** * Current Doctrine Version. */ - public const VERSION = '2.10.0-DEV'; + public const VERSION = '3.0.0-DEV'; /** * Compares a Doctrine version with the current one. From d2f585a981126b1250d24dea678fd0cdd828d755 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 26 Dec 2017 21:01:19 -0800 Subject: [PATCH 09/66] [BC] Removed support for PDO::PARAM_INPUT_OUTPUT in Statement::bindParam() --- lib/Doctrine/DBAL/Driver/Statement.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index 388983e46a6..3c778eeb74c 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -49,8 +49,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING); * question mark placeholders, this will be the 1-indexed position of the parameter. * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. * @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType} - * constants. To return an INOUT parameter from a stored procedure, use the bitwise - * OR operator to set the PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. + * constants. * @param int|null $length You must specify maxlength when using an OUT bind * so that PHP allocates enough memory to hold the returned value. * From b542a51079356bec7d02a1c2f0256ced416808df Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 2 Jan 2018 15:07:37 -0800 Subject: [PATCH 10/66] [BC] Replaced extension of \PDOStatement with a composition to avoid having to replicate the \PDOStatement interface in ResultStatement --- lib/Doctrine/DBAL/Cache/ArrayStatement.php | 11 +- .../DBAL/Cache/ResultCacheStatement.php | 9 +- .../DBAL/Driver/IBMDB2/DB2Statement.php | 31 +++-- .../DBAL/Driver/Mysqli/MysqliStatement.php | 7 +- .../DBAL/Driver/OCI8/OCI8Statement.php | 7 +- lib/Doctrine/DBAL/Driver/PDOConnection.php | 21 ++- lib/Doctrine/DBAL/Driver/PDOStatement.php | 126 ++++++++++-------- lib/Doctrine/DBAL/Driver/ResultStatement.php | 58 +++----- .../SQLAnywhere/SQLAnywhereStatement.php | 30 +++-- .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 29 ++-- lib/Doctrine/DBAL/Portability/Statement.php | 17 +-- lib/Doctrine/DBAL/Statement.php | 25 +--- 12 files changed, 185 insertions(+), 186 deletions(-) diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 449a220a2af..494876c935e 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\FetchMode; use InvalidArgumentException; use IteratorAggregate; -use PDO; use function array_merge; use function array_values; use function count; @@ -59,9 +58,9 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { - if ($arg2 !== null || $arg3 !== null) { + if (count($args) > 0) { throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); } @@ -83,7 +82,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { if (! isset($this->data[$this->num])) { return false; @@ -114,10 +113,10 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $rows = []; - while ($row = $this->fetch($fetchMode)) { + while ($row = $this->fetch($fetchMode, ...$args)) { $rows[] = $row; } diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index 8fbae62de29..e4436b986dc 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -9,7 +9,6 @@ use Doctrine\DBAL\FetchMode; use InvalidArgumentException; use IteratorAggregate; -use PDO; use function array_merge; use function array_values; use function assert; @@ -105,7 +104,7 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { $this->defaultFetchMode = $fetchMode; @@ -125,7 +124,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { if ($this->data === null) { $this->data = []; @@ -165,9 +164,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { - $this->data = $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + $this->data = $this->statement->fetchAll($fetchMode, ...$args); $this->emptied = true; return $this->data; diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index af6e852bc43..052fbbe1266 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use IteratorAggregate; -use PDO; use ReflectionClass; use ReflectionObject; use ReflectionProperty; @@ -19,6 +18,7 @@ use const DB2_PARAM_FILE; use const DB2_PARAM_IN; use function array_change_key_case; +use function count; use function db2_bind_param; use function db2_execute; use function db2_fetch_array; @@ -32,8 +32,6 @@ use function db2_stmt_errormsg; use function error_get_last; use function fclose; -use function func_get_args; -use function func_num_args; use function fwrite; use function gettype; use function is_object; @@ -229,11 +227,17 @@ public function execute($params = null) /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; + + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (isset($args[1])) { + $this->defaultFetchClassCtorArgs = (array) $args[2]; + } return true; } @@ -249,7 +253,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -272,10 +276,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (func_num_args() >= 2) { - $args = func_get_args(); - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } $result = db2_fetch_object($this->stmt); @@ -300,13 +303,13 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch(...func_get_args())) !== false) { + while (($row = $this->fetch($fetchMode, ...$args)) !== false) { $rows[] = $row; } break; diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 43d70853ef5..acf8b4ec54c 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -10,7 +10,6 @@ use IteratorAggregate; use mysqli; use mysqli_stmt; -use PDO; use function array_combine; use function array_fill; use function assert; @@ -303,7 +302,7 @@ private function _fetch() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -353,7 +352,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; @@ -436,7 +435,7 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { $this->_defaultFetchMode = $fetchMode; diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index f9540110263..20081cbb892 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -8,7 +8,6 @@ use Doctrine\DBAL\ParameterType; use InvalidArgumentException; use IteratorAggregate; -use PDO; use const OCI_ASSOC; use const OCI_B_BIN; use const OCI_B_BLOB; @@ -397,7 +396,7 @@ public function execute($params = null) /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { $this->_defaultFetchMode = $fetchMode; @@ -415,7 +414,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -446,7 +445,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 336542ea50a..8827d4ca037 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\ParameterType; use PDO; -use function assert; use function func_get_args; /** @@ -25,7 +24,6 @@ public function __construct($dsn, $user = null, $password = null, ?array $option { try { parent::__construct($dsn, (string) $user, (string) $password, (array) $options); - $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (\PDOException $exception) { throw new PDOException($exception); @@ -58,7 +56,9 @@ public function getServerVersion() public function prepare($prepareString, $driverOptions = []) { try { - return parent::prepare($prepareString, $driverOptions); + return $this->createStatement( + parent::prepare($prepareString, $driverOptions) + ); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -72,10 +72,9 @@ public function query() $args = func_get_args(); try { - $stmt = parent::query(...$args); - assert($stmt instanceof \PDOStatement); - - return $stmt; + return $this->createStatement( + parent::query(...$args) + ); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -112,4 +111,12 @@ public function requiresQueryForServerVersion() { return false; } + + /** + * Creates a wrapped statement + */ + private function createStatement(\PDOStatement $stmt) : PDOStatement + { + return new PDOStatement($stmt); + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 5be4f2c046d..01c1d490031 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; +use IteratorAggregate; use PDO; use const E_USER_DEPRECATED; use function array_slice; @@ -17,7 +18,7 @@ * The PDO implementation of the Statement interface. * Used by all PDO-based drivers. */ -class PDOStatement extends \PDOStatement implements Statement +class PDOStatement implements IteratorAggregate, Statement { private const PARAM_TYPE_MAP = [ ParameterType::NULL => PDO::PARAM_NULL, @@ -37,34 +38,23 @@ class PDOStatement extends \PDOStatement implements Statement FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, ]; - /** - * Protected constructor. - */ - protected function __construct() + /** @var \PDOStatement */ + private $stmt; + + public function __construct(\PDOStatement $stmt) { + $this->stmt = $stmt; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { $fetchMode = $this->convertFetchMode($fetchMode); - // This thin wrapper is necessary to shield against the weird signature - // of PDOStatement::setFetchMode(): even if the second and third - // parameters are optional, PHP will not let us remove it from this - // declaration. try { - if ($arg2 === null && $arg3 === null) { - return parent::setFetchMode($fetchMode); - } - - if ($arg3 === null) { - return parent::setFetchMode($fetchMode, $arg2); - } - - return parent::setFetchMode($fetchMode, $arg2, $arg3); + return $this->stmt->setFetchMode($fetchMode, ...$args); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -78,7 +68,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING) $type = $this->convertParamType($type); try { - return parent::bindValue($param, $value, $type); + return $this->stmt->bindValue($param, $value, $type); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -92,7 +82,7 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $type = $this->convertParamType($type); try { - return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); + return $this->stmt->bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -104,7 +94,7 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l public function closeCursor() { try { - return parent::closeCursor(); + return $this->stmt->closeCursor(); } catch (\PDOException $exception) { // Exceptions not allowed by the interface. // In case driver implementations do not adhere to the interface, silence exceptions here. @@ -115,28 +105,34 @@ public function closeCursor() /** * {@inheritdoc} */ - public function execute($params = null) + public function columnCount() { - try { - return parent::execute($params); - } catch (\PDOException $exception) { - throw new PDOException($exception); - } + return $this->stmt->columnCount(); } /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function errorCode() { - $args = func_get_args(); + return $this->stmt->errorCode(); + } - if (isset($args[0])) { - $args[0] = $this->convertFetchMode($args[0]); - } + /** + * {@inheritdoc} + */ + public function errorInfo() + { + return $this->stmt->errorInfo(); + } + /** + * {@inheritdoc} + */ + public function execute($params = null) + { try { - return parent::fetch(...$args); + return $this->stmt->execute($params); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -145,32 +141,50 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function rowCount() + { + return $this->stmt->rowCount(); + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchMode = null, ...$args) { - $args = func_get_args(); + try { + if ($fetchMode === null) { + return $this->stmt->fetch(); + } - if (isset($args[0])) { - $args[0] = $this->convertFetchMode($args[0]); - } + $fetchMode = $this->convertFetchMode($fetchMode); - if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) { - $args = []; - } elseif ($fetchArgument === null && $ctorArgs === null) { - $args = [$fetchMode]; - } elseif ($ctorArgs === null) { - $args = [$fetchMode, $fetchArgument]; - } else { - $args = [$fetchMode, $fetchArgument, $ctorArgs]; + return $this->stmt->fetch($fetchMode, ...$args); + } catch (\PDOException $exception) { + throw new PDOException($exception); } + } + /** + * {@inheritdoc} + */ + public function fetchAll($fetchMode = null, ...$args) + { try { - $data = parent::fetchAll(...$args); - assert(is_array($data)); - - return $data; + if ($fetchMode === null) { + $data = $this->stmt->fetchAll(); + } else { + $data = $this->stmt->fetchAll( + $this->convertFetchMode($fetchMode), + ...$args + ); + } } catch (\PDOException $exception) { throw new PDOException($exception); } + + assert(is_array($data)); + + return $data; } /** @@ -179,7 +193,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n public function fetchColumn($columnIndex = 0) { try { - return parent::fetchColumn($columnIndex); + return $this->stmt->fetchColumn($columnIndex); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -225,4 +239,12 @@ private function convertFetchMode(int $fetchMode) : int return self::FETCH_MODE_MAP[$fetchMode]; } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + yield from $this->stmt; + } } diff --git a/lib/Doctrine/DBAL/Driver/ResultStatement.php b/lib/Doctrine/DBAL/Driver/ResultStatement.php index 1e6df0269b8..17bc28e37ef 100644 --- a/lib/Doctrine/DBAL/Driver/ResultStatement.php +++ b/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL\Driver; -use PDO; use Traversable; /** @@ -29,62 +28,43 @@ public function columnCount(); /** * Sets the fetch mode to use while iterating this statement. * - * @param int $fetchMode The fetch mode must be one of the {@link \Doctrine\DBAL\FetchMode} constants. - * @param mixed $arg2 - * @param mixed $arg3 + * @param int $fetchMode Controls how the next row will be returned to the caller. + * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants. + * @param mixed ...$args Optional mode-specific arguments (see {@link self::fetchAll()}). * * @return bool */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null); + public function setFetchMode($fetchMode, ...$args); /** * Returns the next row of a result set. * - * @param int|null $fetchMode Controls how the next row will be returned to the caller. - * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, - * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. - * @param int $cursorOrientation For a ResultStatement object representing a scrollable cursor, - * this value determines which row will be returned to the caller. - * This value must be one of the \PDO::FETCH_ORI_* constants, - * defaulting to \PDO::FETCH_ORI_NEXT. To request a scrollable - * cursor for your ResultStatement object, you must set the \PDO::ATTR_CURSOR - * attribute to \PDO::CURSOR_SCROLL when you prepare the SQL statement with - * \PDO::prepare(). - * @param int $cursorOffset For a ResultStatement object representing a scrollable cursor for which the - * cursorOrientation parameter is set to \PDO::FETCH_ORI_ABS, this value - * specifies the absolute number of the row in the result set that shall be - * fetched. - * For a ResultStatement object representing a scrollable cursor for which the - * cursorOrientation parameter is set to \PDO::FETCH_ORI_REL, this value - * specifies the row to fetch relative to the cursor position before - * ResultStatement::fetch() was called. + * @param int|null $fetchMode Controls how the next row will be returned to the caller. + * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, + * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. + * @param mixed ...$args Optional mode-specific arguments (see {@link self::fetchAll()}). * * @return mixed The return value of this method on success depends on the fetch mode. In all cases, FALSE is * returned on failure. */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0); + public function fetch($fetchMode = null, ...$args); /** * Returns an array containing all of the result set rows. * - * @param int|null $fetchMode Controls how the next row will be returned to the caller. - * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, - * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. - * @param int|null $fetchArgument This argument has a different meaning depending on the value of the $fetchMode parameter: - * * {@link \Doctrine\DBAL\FetchMode::COLUMN}: - * Returns the indicated 0-indexed column. - * * {@link \Doctrine\DBAL\FetchMode::CUSTOM_OBJECT}: - * Returns instances of the specified class, mapping the columns of each row - * to named properties in the class. - * * \PDO::FETCH_FUNC: Returns the results of calling the specified function, using each row's - * columns as parameters in the call. - * @param mixed[]|null $ctorArgs Controls how the next row will be returned to the caller. - * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, - * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. + * @param int|null $fetchMode Controls how the next row will be returned to the caller. + * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, + * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. + * @param mixed ...$args Optional mode-specific arguments. Supported modes: + * * {@link \Doctrine\DBAL\FetchMode::COLUMN} + * 1. The 0-indexed column to be returned. + * * {@link \Doctrine\DBAL\FetchMode::CUSTOM_OBJECT} + * 1. The classname of the object to be created, + * 2. Array of constructor arguments * * @return mixed[] */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null); + public function fetchAll($fetchMode = null, ...$args); /** * Returns a single column from the next row of a result set or FALSE if there are no more rows. diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index 886bb245873..f35ce204aba 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -7,14 +7,13 @@ use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use IteratorAggregate; -use PDO; use ReflectionClass; use ReflectionObject; use stdClass; use const SASQL_BOTH; use function array_key_exists; +use function count; use function func_get_args; -use function func_num_args; use function gettype; use function is_array; use function is_int; @@ -199,7 +198,7 @@ public function execute($params = null) * * @throws SQLAnywhereException */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { if (! is_resource($this->result)) { return false; @@ -221,10 +220,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (func_num_args() >= 2) { - $args = func_get_args(); - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } $result = sasql_fetch_object($this->result); @@ -249,7 +247,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $rows = []; @@ -308,11 +306,19 @@ public function rowCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; + + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (isset($args[1])) { + $this->defaultFetchClassCtorArgs = (array) $args[1]; + } + + return true; } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index 453bc8b3f3f..af07561167f 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use IteratorAggregate; -use PDO; use const SQLSRV_ENC_BINARY; use const SQLSRV_ERR_ERRORS; use const SQLSRV_FETCH_ASSOC; @@ -16,7 +15,6 @@ use const SQLSRV_PARAM_IN; use function array_key_exists; use function count; -use function func_get_args; use function in_array; use function is_int; use function is_numeric; @@ -311,11 +309,17 @@ private function prepare() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; + + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (isset($args[1])) { + $this->defaultFetchClassCtorArgs = (array) $args[2]; + } return true; } @@ -333,7 +337,7 @@ public function getIterator() * * @throws SQLSrvException */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -341,7 +345,6 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX return false; } - $args = func_get_args(); $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchMode === FetchMode::COLUMN) { @@ -356,9 +359,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (count($args) >= 2) { - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false; @@ -370,13 +373,13 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch(...func_get_args())) !== false) { + while (($row = $this->fetch($fetchMode, $args)) !== false) { $rows[] = $row; } break; diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index 514b3be2d74..51deeb5aff1 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -8,7 +8,6 @@ use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use IteratorAggregate; -use PDO; use function array_change_key_case; use function assert; use function is_string; @@ -112,11 +111,11 @@ public function execute($params = null) /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) + public function setFetchMode($fetchMode, ...$args) { $this->defaultFetchMode = $fetchMode; - return $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); + return $this->stmt->setFetchMode($fetchMode, ...$args); } /** @@ -130,11 +129,11 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { $fetchMode = $fetchMode ?: $this->defaultFetchMode; - $row = $this->stmt->fetch($fetchMode); + $row = $this->stmt->fetch($fetchMode, ...$args); $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $fixCase = $this->case !== null @@ -149,15 +148,11 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { $fetchMode = $fetchMode ?: $this->defaultFetchMode; - if ($fetchArgument) { - $rows = $this->stmt->fetchAll($fetchMode, $fetchArgument); - } else { - $rows = $this->stmt->fetchAll($fetchMode); - } + $rows = $this->stmt->fetchAll($fetchMode, ...$args); $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $fixCase = $this->case !== null diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index 09913bb56ae..e6881093bf7 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; use IteratorAggregate; -use PDO; use Throwable; use function is_array; use function is_string; @@ -213,17 +212,9 @@ public function errorInfo() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode($fetchMode, ...$args) { - if ($arg2 === null) { - return $this->stmt->setFetchMode($fetchMode); - } - - if ($arg3 === null) { - return $this->stmt->setFetchMode($fetchMode, $arg2); - } - - return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + return $this->stmt->setFetchMode($fetchMode, ...$args); } /** @@ -239,21 +230,17 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch($fetchMode = null, ...$args) { - return $this->stmt->fetch($fetchMode); + return $this->stmt->fetch($fetchMode, ...$args); } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll($fetchMode = null, ...$args) { - if ($fetchArgument) { - return $this->stmt->fetchAll($fetchMode, $fetchArgument); - } - - return $this->stmt->fetchAll($fetchMode); + return $this->stmt->fetchAll($fetchMode, ...$args); } /** From c4f5d5085a5c7752f03c05dbbb7332c8e11ea2c4 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 31 Dec 2017 19:25:28 -0800 Subject: [PATCH 11/66] [BC] Replaced PDO constants with values --- composer.json | 1 - composer.lock | 5 ++--- lib/Doctrine/DBAL/ColumnCase.php | 6 ++---- lib/Doctrine/DBAL/FetchMode.php | 14 ++++++-------- lib/Doctrine/DBAL/ParameterType.php | 12 +++++------- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/composer.json b/composer.json index 3ba89fcd764..f2da26555d4 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,6 @@ ], "require": { "php": "^7.2", - "ext-pdo": "*", "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0" }, diff --git a/composer.lock b/composer.lock index 7ba548e3d11..cd77280bae4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ddba260b7dfb84d2591b0a71a885166a", + "content-hash": "f56aea09f935f4149022c0b822984b2b", "packages": [ { "name": "doctrine/cache", @@ -3099,8 +3099,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2", - "ext-pdo": "*" + "php": "^7.2" }, "platform-dev": [] } diff --git a/lib/Doctrine/DBAL/ColumnCase.php b/lib/Doctrine/DBAL/ColumnCase.php index 872d3ede873..c78ad372e65 100644 --- a/lib/Doctrine/DBAL/ColumnCase.php +++ b/lib/Doctrine/DBAL/ColumnCase.php @@ -2,8 +2,6 @@ namespace Doctrine\DBAL; -use PDO; - /** * Contains portable column case conversions. */ @@ -14,14 +12,14 @@ final class ColumnCase * * @see \PDO::CASE_UPPER */ - public const UPPER = PDO::CASE_UPPER; + public const UPPER = 1; /** * Convert column names to lower case. * * @see \PDO::CASE_LOWER */ - public const LOWER = PDO::CASE_LOWER; + public const LOWER = 2; /** * This class cannot be instantiated. diff --git a/lib/Doctrine/DBAL/FetchMode.php b/lib/Doctrine/DBAL/FetchMode.php index b3fe42f4ceb..65af014f1e0 100644 --- a/lib/Doctrine/DBAL/FetchMode.php +++ b/lib/Doctrine/DBAL/FetchMode.php @@ -2,8 +2,6 @@ namespace Doctrine\DBAL; -use PDO; - /** * Contains statement fetch modes. */ @@ -17,7 +15,7 @@ final class FetchMode * * @see \PDO::FETCH_ASSOC */ - public const ASSOCIATIVE = PDO::FETCH_ASSOC; + public const ASSOCIATIVE = 2; /** * Specifies that the fetch method shall return each row as an array indexed @@ -26,7 +24,7 @@ final class FetchMode * * @see \PDO::FETCH_NUM */ - public const NUMERIC = PDO::FETCH_NUM; + public const NUMERIC = 3; /** * Specifies that the fetch method shall return each row as an array indexed @@ -35,7 +33,7 @@ final class FetchMode * * @see \PDO::FETCH_BOTH */ - public const MIXED = PDO::FETCH_BOTH; + public const MIXED = 4; /** * Specifies that the fetch method shall return each row as an object with @@ -44,7 +42,7 @@ final class FetchMode * * @see \PDO::FETCH_OBJ */ - public const STANDARD_OBJECT = PDO::FETCH_OBJ; + public const STANDARD_OBJECT = 5; /** * Specifies that the fetch method shall return only a single requested @@ -52,7 +50,7 @@ final class FetchMode * * @see \PDO::FETCH_COLUMN */ - public const COLUMN = PDO::FETCH_COLUMN; + public const COLUMN = 7; /** * Specifies that the fetch method shall return a new instance of the @@ -60,7 +58,7 @@ final class FetchMode * * @see \PDO::FETCH_CLASS */ - public const CUSTOM_OBJECT = PDO::FETCH_CLASS; + public const CUSTOM_OBJECT = 8; /** * This class cannot be instantiated. diff --git a/lib/Doctrine/DBAL/ParameterType.php b/lib/Doctrine/DBAL/ParameterType.php index 422fee895ee..022b2703ef5 100644 --- a/lib/Doctrine/DBAL/ParameterType.php +++ b/lib/Doctrine/DBAL/ParameterType.php @@ -2,8 +2,6 @@ namespace Doctrine\DBAL; -use PDO; - /** * Contains statement parameter types. */ @@ -14,35 +12,35 @@ final class ParameterType * * @see \PDO::PARAM_NULL */ - public const NULL = PDO::PARAM_NULL; + public const NULL = 0; /** * Represents the SQL INTEGER data type. * * @see \PDO::PARAM_INT */ - public const INTEGER = PDO::PARAM_INT; + public const INTEGER = 1; /** * Represents the SQL CHAR, VARCHAR, or other string data type. * * @see \PDO::PARAM_STR */ - public const STRING = PDO::PARAM_STR; + public const STRING = 2; /** * Represents the SQL large object data type. * * @see \PDO::PARAM_LOB */ - public const LARGE_OBJECT = PDO::PARAM_LOB; + public const LARGE_OBJECT = 3; /** * Represents a boolean data type. * * @see \PDO::PARAM_BOOL */ - public const BOOLEAN = PDO::PARAM_BOOL; + public const BOOLEAN = 5; /** * Represents a binary string data type. From 97f4fdb0d65770ee6849eb64475a8e837320d9c0 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Mon, 25 Dec 2017 13:02:38 -0800 Subject: [PATCH 12/66] Updated UPGRADE.md for 3.x --- UPGRADE.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index a5ca5ddb6d5..8eeadf51737 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,3 +1,37 @@ +# Upgrade to 3.0 + +## BC BREAK: the PDO symbols are no longer part of the DBAL API + +1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. +2. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. + +Before: + + use Doctrine\DBAL\Portability\Connection; + + $params = array( + 'wrapperClass' => Connection::class, + 'fetch_case' => PDO::CASE_LOWER, + ); + + $stmt->bindValue(1, 1, PDO::PARAM_INT); + $stmt->fetchAll(PDO::FETCH_COLUMN); + +After: + + use Doctrine\DBAL\ColumnCase; + use Doctrine\DBAL\FetchMode; + use Doctrine\DBAL\ParameterType; + use Doctrine\DBAL\Portability\Connection; + + $params = array( + 'wrapperClass' => Connection::class, + 'fetch_case' => ColumnCase::LOWER, + ); + + $stmt->bindValue(1, 1, ParameterType::INTEGER); + $stmt->fetchAll(FetchMode::COLUMN); + # Upgrade to 2.10 ## Deprecated `Type::*` constants From ecd2959165a122263b372c49753f91a3fa84f419 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 5 Jan 2018 05:27:22 +0100 Subject: [PATCH 13/66] Drop Doctrine\DBAL\Version in favor of Ocramius\PackageVersions --- UPGRADE.md | 4 + composer.json | 3 +- composer.lock | 102 +++++++++--------- .../DBAL/Tools/Console/ConsoleRunner.php | 4 +- lib/Doctrine/DBAL/Version.php | 33 ------ 5 files changed, 59 insertions(+), 87 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Version.php diff --git a/UPGRADE.md b/UPGRADE.md index 8eeadf51737..07f2cb5929a 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK: Removed Doctrine\DBAL\Version + +The Doctrine\DBAL\Version class is no longer available: please refrain from checking the DBAL version at runtime. + ## BC BREAK: the PDO symbols are no longer part of the DBAL API 1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. diff --git a/composer.json b/composer.json index f2da26555d4..e500fadce6e 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "require": { "php": "^7.2", "doctrine/cache": "^1.0", - "doctrine/event-manager": "^1.0" + "doctrine/event-manager": "^1.0", + "ocramius/package-versions": "^1.2" }, "require-dev": { "doctrine/coding-standard": "^6.0", diff --git a/composer.lock b/composer.lock index cd77280bae4..0ebaf91a8a1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f56aea09f935f4149022c0b822984b2b", + "content-hash": "d3d90c1610c13280a504da32dd4cff4a", "packages": [ { "name": "doctrine/cache", @@ -153,6 +153,56 @@ "eventmanager" ], "time": "2018-06-11T11:59:03+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.1.0" + }, + "require-dev": { + "composer/composer": "^1.6.3", + "doctrine/coding-standard": "^5.0.1", + "ext-zip": "*", + "infection/infection": "^0.7.1", + "phpunit/phpunit": "^7.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-02-21T12:16:21+00:00" } ], "packages-dev": [ @@ -1046,56 +1096,6 @@ ], "time": "2019-02-16T20:54:15+00:00" }, - { - "name": "ocramius/package-versions", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" - }, - "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", - "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" - }, { "name": "phar-io/manifest", "version": "1.0.3", diff --git a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php index 520a9af80aa..94a87cb63c1 100644 --- a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php +++ b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php @@ -7,7 +7,7 @@ use Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand; use Doctrine\DBAL\Tools\Console\Command\RunSqlCommand; use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; -use Doctrine\DBAL\Version; +use PackageVersions\Versions; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\HelperSet; @@ -38,7 +38,7 @@ public static function createHelperSet(Connection $connection) */ public static function run(HelperSet $helperSet, $commands = []) { - $cli = new Application('Doctrine Command Line Interface', Version::VERSION); + $cli = new Application('Doctrine Command Line Interface', Versions::getVersion('doctrine/dbal')); $cli->setCatchExceptions(true); $cli->setHelperSet($helperSet); diff --git a/lib/Doctrine/DBAL/Version.php b/lib/Doctrine/DBAL/Version.php deleted file mode 100644 index d9d48eb7d3f..00000000000 --- a/lib/Doctrine/DBAL/Version.php +++ /dev/null @@ -1,33 +0,0 @@ - Date: Wed, 7 Mar 2018 20:04:42 +0100 Subject: [PATCH 14/66] Drop Drizzle support --- docs/en/reference/configuration.rst | 27 +- docs/en/reference/introduction.rst | 1 - docs/en/reference/platforms.rst | 5 - docs/en/reference/schema-representation.rst | 10 +- docs/en/reference/types.rst | 124 ++-- .../Driver/DrizzlePDOMySql/Connection.php | 21 - .../DBAL/Driver/DrizzlePDOMySql/Driver.php | 57 -- lib/Doctrine/DBAL/DriverManager.php | 23 +- .../DBAL/Platforms/DrizzlePlatform.php | 621 ------------------ .../Platforms/Keywords/DrizzleKeywords.php | 326 --------- lib/Doctrine/DBAL/Portability/Connection.php | 3 - .../DBAL/Schema/DrizzleSchemaManager.php | 103 --- .../Driver/DrizzlePDOMySql/DriverTest.php | 49 -- .../Doctrine/Tests/DBAL/DriverManagerTest.php | 7 +- .../Tests/DBAL/Functional/ExceptionTest.php | 4 - .../Schema/DrizzleSchemaManagerTest.php | 48 -- 16 files changed, 63 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/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 4fa8991ec33..9068869035f 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -73,12 +73,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 @@ -128,8 +124,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. @@ -197,23 +191,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 ^^^^^^ 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 32ef74304ea..8fdbaa168df 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -76,11 +76,6 @@ SQLite - ``SqlitePlatform`` for all versions. -Drizzle -^^^^^^ - -- ``DrizzlePlatform`` for all versions. - 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 b250a5c5109..381a997e321 100644 --- a/docs/en/reference/schema-representation.rst +++ b/docs/en/reference/schema-representation.rst @@ -115,10 +115,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 ^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,8 +133,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 f4916a69672..04f80a9c113 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,16 +676,12 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+ | | | | **SQL Server** | >= 2008 | | | | | +---------+----------------------------------------------------------+ -| | | | < 2008 | ``DATETIME`` [16]_ | +| | | | < 2008 | ``DATETIME`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | -| | +--------------------------+ +----------------------------------------------------------+ -| | | **Drizzle** | | ``TIMESTAMP`` [14]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``DATETIME`` | | | +--------------------------+ | | @@ -719,9 +693,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** | | | | | +--------------------------+---------+ | @@ -733,7 +705,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **Oracle** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Anywhere** | < 12 | ``DATETIME`` [15]_ [16]_ | +| | | **SQL Anywhere** | < 12 | ``DATETIME`` [14]_ [15]_ | | | | +---------+----------------------------------------------------------+ | | | | >= 12 | ``TIMESTAMP WITH TIME ZONE`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ @@ -742,30 +714,26 @@ 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** | < 2008 | ``DATETIME`` [16]_ | +| | | **SQL Server** | < 2008 | ``DATETIME`` [15]_ | | | | +---------+----------------------------------------------------------+ | | | | >= 2008 | ``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`` | | | +--------------------------+ | | @@ -773,25 +741,23 @@ 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.2 | ``TEXT`` [1]_ | | | | +---------+----------------------------------------------------------+ | | | | < 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]_ | | | +--------------------------+ | | @@ -799,19 +765,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`` | | | +--------------------------+ | | @@ -827,10 +791,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 @@ -842,22 +806,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 4089ab26e11..00000000000 --- a/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php +++ /dev/null @@ -1,21 +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} - */ - public function getName() - { - return 'drizzle_pdo_mysql'; - } -} diff --git a/lib/Doctrine/DBAL/DriverManager.php b/lib/Doctrine/DBAL/DriverManager.php index 6888d73b0c4..d44b314262e 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; @@ -44,17 +43,16 @@ final class DriverManager * @var string[] */ private static $_driverMap = [ - 'pdo_mysql' => PDOMySQLDriver::class, - 'pdo_sqlite' => PDOSQLiteDriver::class, - 'pdo_pgsql' => PDOPgSQLDriver::class, - 'pdo_oci' => PDOOCIDriver::class, - 'oci8' => OCI8Driver::class, - 'ibm_db2' => DB2Driver::class, - 'pdo_sqlsrv' => PDOSQLSrvDriver::class, - 'mysqli' => MySQLiDriver::class, - 'drizzle_pdo_mysql' => DrizzlePDOMySQLDriver::class, - 'sqlanywhere' => SQLAnywhereDriver::class, - 'sqlsrv' => SQLSrvDriver::class, + 'pdo_mysql' => PDOMySQLDriver::class, + 'pdo_sqlite' => PDOSQLiteDriver::class, + 'pdo_pgsql' => PDOPgSQLDriver::class, + 'pdo_oci' => PDOOCIDriver::class, + 'oci8' => OCI8Driver::class, + 'ibm_db2' => DB2Driver::class, + 'pdo_sqlsrv' => PDOSQLSrvDriver::class, + 'mysqli' => MySQLiDriver::class, + 'sqlanywhere' => SQLAnywhereDriver::class, + 'sqlsrv' => SQLSrvDriver::class, ]; /** @@ -100,7 +98,6 @@ private function __construct() * sqlanywhere * sqlsrv * ibm_db2 (unstable) - * drizzle_pdo_mysql * * OR 'driverClass' that contains the full class name (with namespace) of the * driver class to instantiate. diff --git a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php b/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php deleted file mode 100644 index 48c5a6c00eb..00000000000 --- a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php +++ /dev/null @@ -1,621 +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 $name => $definition) { - $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $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 520a732a0c3..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php +++ /dev/null @@ -1,49 +0,0 @@ -driver->getName()); - } - - public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() - { - $this->markTestSkipped('This test does not work on Drizzle as it is not version aware.'); - } - - protected function createDriver() - { - return new Driver(); - } - - protected function createPlatform() - { - return new DrizzlePlatform(); - } - - protected function createSchemaManager(Connection $connection) - { - 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 0346405cb82..c454bbea2e3 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; @@ -349,17 +348,17 @@ public function databaseUrls() ], ], '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 3aa1a19e81f..841b4c599cb 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php @@ -338,10 +338,6 @@ public function testConnectionException($params) $this->markTestSkipped('Only skipped if platform is not sqlite'); } - if ($this->connection->getDatabasePlatform()->getName() === 'drizzle') { - $this->markTestSkipped('Drizzle does not always support authentication'); - } - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql' && 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 070e2173d63..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() - { - $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 b03995ff1b1608d96532580dbcd842bf611fb5a0 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Wed, 7 Mar 2018 23:36:32 +0100 Subject: [PATCH 15/66] Add note to UPGRADE.md --- UPGRADE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 07f2cb5929a..50f6b7cf06c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -36,6 +36,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. + # Upgrade to 2.10 ## Deprecated `Type::*` constants From 1ede74ffb3cdc19570130621905486784296f9f9 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 14:13:26 +0100 Subject: [PATCH 16/66] Introduce a null SQL logger --- lib/Doctrine/DBAL/Configuration.php | 11 ++- lib/Doctrine/DBAL/Connection.php | 84 +++++-------------- .../Connections/MasterSlaveConnection.php | 8 +- lib/Doctrine/DBAL/Logging/NullLogger.php | 23 +++++ lib/Doctrine/DBAL/Statement.php | 12 +-- 5 files changed, 55 insertions(+), 83 deletions(-) create mode 100644 lib/Doctrine/DBAL/Logging/NullLogger.php diff --git a/lib/Doctrine/DBAL/Configuration.php b/lib/Doctrine/DBAL/Configuration.php index 2cc0070d0cb..78760d7be57 100644 --- a/lib/Doctrine/DBAL/Configuration.php +++ b/lib/Doctrine/DBAL/Configuration.php @@ -3,6 +3,7 @@ namespace Doctrine\DBAL; use Doctrine\Common\Cache\Cache; +use Doctrine\DBAL\Logging\NullLogger; use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\DBAL\Schema\AbstractAsset; use function preg_match; @@ -35,12 +36,14 @@ public function setSQLLogger(?SQLLogger $logger = null) /** * Gets the SQL logger that is used. - * - * @return SQLLogger|null */ - public function getSQLLogger() + public function getSQLLogger() : SQLLogger { - return $this->_attributes['sqlLogger'] ?? null; + if (! isset($this->_attributes['sqlLogger'])) { + $this->_attributes['sqlLogger'] = new NullLogger(); + } + + return $this->_attributes['sqlLogger']; } /** diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 75b862bf74f..90593770440 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -881,9 +881,7 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($query, $params, $types); - } + $logger->startQuery($query, $params, $types); try { if ($params) { @@ -905,9 +903,7 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach $stmt->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $stmt; } @@ -995,9 +991,7 @@ public function query() $args = func_get_args(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($args[0]); - } + $logger->startQuery($args[0]); try { $statement = $connection->query(...$args); @@ -1007,9 +1001,7 @@ public function query() $statement->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $statement; } @@ -1033,9 +1025,7 @@ public function executeUpdate($query, array $params = [], array $types = []) $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($query, $params, $types); - } + $logger->startQuery($query, $params, $types); try { if ($params) { @@ -1057,9 +1047,7 @@ public function executeUpdate($query, array $params = [], array $types = []) throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); } - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $result; } @@ -1078,9 +1066,7 @@ public function exec($statement) $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($statement); - } + $logger->startQuery($statement); try { $result = $connection->exec($statement); @@ -1088,9 +1074,7 @@ public function exec($statement) throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); } - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $result; } @@ -1227,23 +1211,13 @@ public function beginTransaction() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"START TRANSACTION"'); - } - + $logger->startQuery('"START TRANSACTION"'); $connection->beginTransaction(); - - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"SAVEPOINT"'); - } + $logger->startQuery('"SAVEPOINT"'); $this->createSavepoint($this->_getNestedTransactionSavePointName()); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } return true; @@ -1269,23 +1243,13 @@ public function commit() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"COMMIT"'); - } - + $logger->startQuery('"COMMIT"'); $connection->commit(); - - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"RELEASE SAVEPOINT"'); - } + $logger->startQuery('"RELEASE SAVEPOINT"'); $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } --$this->transactionNestingLevel; @@ -1333,28 +1297,20 @@ public function rollBack() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"ROLLBACK"'); - } + $logger->startQuery('"ROLLBACK"'); $this->transactionNestingLevel = 0; $connection->rollBack(); $this->isRollbackOnly = false; - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); if ($this->autoCommit === false) { $this->beginTransaction(); } } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); - } + $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); --$this->transactionNestingLevel; - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } else { $this->isRollbackOnly = true; --$this->transactionNestingLevel; diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index ff310d9196b..ba76be2db79 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -350,17 +350,13 @@ public function query() $args = func_get_args(); $logger = $this->getConfiguration()->getSQLLogger(); - if ($logger) { - $logger->startQuery($args[0]); - } + $logger->startQuery($args[0]); $statement = $this->_conn->query(...$args); $statement->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $statement; } diff --git a/lib/Doctrine/DBAL/Logging/NullLogger.php b/lib/Doctrine/DBAL/Logging/NullLogger.php new file mode 100644 index 00000000000..ff165d6106c --- /dev/null +++ b/lib/Doctrine/DBAL/Logging/NullLogger.php @@ -0,0 +1,23 @@ +conn->getConfiguration()->getSQLLogger(); - if ($logger) { - $logger->startQuery($this->sql, $this->params, $this->types); - } + $logger->startQuery($this->sql, $this->params, $this->types); try { $stmt = $this->stmt->execute($params); } catch (Throwable $ex) { - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); throw DBALException::driverExceptionDuringQuery( $this->conn->getDriver(), $ex, @@ -162,9 +158,7 @@ public function execute($params = null) ); } - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); $this->params = []; $this->types = []; From a604c93f49919fc57dd8a484de6dac5506d11044 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 19:26:49 +0100 Subject: [PATCH 17/66] Make NullLogger final --- lib/Doctrine/DBAL/Logging/NullLogger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/DBAL/Logging/NullLogger.php b/lib/Doctrine/DBAL/Logging/NullLogger.php index ff165d6106c..93d111f09bc 100644 --- a/lib/Doctrine/DBAL/Logging/NullLogger.php +++ b/lib/Doctrine/DBAL/Logging/NullLogger.php @@ -5,7 +5,7 @@ /** * A SQL logger that does nothing. */ -class NullLogger implements SQLLogger +final class NullLogger implements SQLLogger { /** * {@inheritdoc} From 0cd43bb17addb8c7c3c7fdfee9239fe7bc2f2cd7 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 19:32:24 +0100 Subject: [PATCH 18/66] One-liner for Configuration::getSQLLogger() --- lib/Doctrine/DBAL/Configuration.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/Doctrine/DBAL/Configuration.php b/lib/Doctrine/DBAL/Configuration.php index 78760d7be57..35d92814799 100644 --- a/lib/Doctrine/DBAL/Configuration.php +++ b/lib/Doctrine/DBAL/Configuration.php @@ -39,11 +39,7 @@ public function setSQLLogger(?SQLLogger $logger = null) */ public function getSQLLogger() : SQLLogger { - if (! isset($this->_attributes['sqlLogger'])) { - $this->_attributes['sqlLogger'] = new NullLogger(); - } - - return $this->_attributes['sqlLogger']; + return $this->_attributes['sqlLogger'] ?? $this->_attributes['sqlLogger'] = new NullLogger(); } /** From f851b66c3674abc778006deb0c06bcf3879b302a Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 19:40:42 +0100 Subject: [PATCH 19/66] Change the SQLLogger interface signature --- lib/Doctrine/DBAL/Logging/DebugStack.php | 4 ++-- lib/Doctrine/DBAL/Logging/EchoSQLLogger.php | 4 ++-- lib/Doctrine/DBAL/Logging/LoggerChain.php | 8 +++----- lib/Doctrine/DBAL/Logging/NullLogger.php | 4 ++-- lib/Doctrine/DBAL/Logging/SQLLogger.php | 14 +++++--------- .../Doctrine/Tests/DBAL/Logging/DebugStackTest.php | 4 ++-- 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/Doctrine/DBAL/Logging/DebugStack.php b/lib/Doctrine/DBAL/Logging/DebugStack.php index e1ccaad6ba0..5d2c8cf62ab 100644 --- a/lib/Doctrine/DBAL/Logging/DebugStack.php +++ b/lib/Doctrine/DBAL/Logging/DebugStack.php @@ -32,7 +32,7 @@ class DebugStack implements SQLLogger /** * {@inheritdoc} */ - public function startQuery($sql, ?array $params = null, ?array $types = null) + public function startQuery(string $sql, array $params = [], array $types = []) : void { if (! $this->enabled) { return; @@ -45,7 +45,7 @@ public function startQuery($sql, ?array $params = null, ?array $types = null) /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { if (! $this->enabled) { return; diff --git a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php index 657abb4d378..4a7da004cb7 100644 --- a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php +++ b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php @@ -13,7 +13,7 @@ class EchoSQLLogger implements SQLLogger /** * {@inheritdoc} */ - public function startQuery($sql, ?array $params = null, ?array $types = null) + public function startQuery(string $sql, array $params = [], array $types = []) : void { echo $sql . PHP_EOL; @@ -31,7 +31,7 @@ public function startQuery($sql, ?array $params = null, ?array $types = null) /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { } } diff --git a/lib/Doctrine/DBAL/Logging/LoggerChain.php b/lib/Doctrine/DBAL/Logging/LoggerChain.php index 2b5404b25c7..d1598da950d 100644 --- a/lib/Doctrine/DBAL/Logging/LoggerChain.php +++ b/lib/Doctrine/DBAL/Logging/LoggerChain.php @@ -12,10 +12,8 @@ class LoggerChain implements SQLLogger /** * Adds a logger in the chain. - * - * @return void */ - public function addLogger(SQLLogger $logger) + public function addLogger(SQLLogger $logger) : void { $this->loggers[] = $logger; } @@ -23,7 +21,7 @@ public function addLogger(SQLLogger $logger) /** * {@inheritdoc} */ - public function startQuery($sql, ?array $params = null, ?array $types = null) + public function startQuery(string $sql, array $params = [], array $types = []) : void { foreach ($this->loggers as $logger) { $logger->startQuery($sql, $params, $types); @@ -33,7 +31,7 @@ public function startQuery($sql, ?array $params = null, ?array $types = null) /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { foreach ($this->loggers as $logger) { $logger->stopQuery(); diff --git a/lib/Doctrine/DBAL/Logging/NullLogger.php b/lib/Doctrine/DBAL/Logging/NullLogger.php index 93d111f09bc..f8f7cb7a123 100644 --- a/lib/Doctrine/DBAL/Logging/NullLogger.php +++ b/lib/Doctrine/DBAL/Logging/NullLogger.php @@ -10,14 +10,14 @@ final class NullLogger implements SQLLogger /** * {@inheritdoc} */ - public function startQuery($sql, ?array $params = null, ?array $types = null) + public function startQuery(string $sql, ?array $params = [], ?array $types = []) : void { } /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { } } diff --git a/lib/Doctrine/DBAL/Logging/SQLLogger.php b/lib/Doctrine/DBAL/Logging/SQLLogger.php index 2e94611b6a2..99aa494426b 100644 --- a/lib/Doctrine/DBAL/Logging/SQLLogger.php +++ b/lib/Doctrine/DBAL/Logging/SQLLogger.php @@ -10,18 +10,14 @@ interface SQLLogger /** * Logs a SQL statement somewhere. * - * @param string $sql The SQL to be executed. - * @param mixed[]|null $params The SQL parameters. - * @param int[]|string[]|null $types The SQL parameter types. - * - * @return void + * @param string $sql The SQL to be executed. + * @param mixed[] $params The SQL parameters. + * @param int[]|string[] $types The SQL parameter types. */ - public function startQuery($sql, ?array $params = null, ?array $types = null); + public function startQuery(string $sql, array $params = [], array $types = []) : void; /** * Marks the last started query as stopped. This can be used for timing of queries. - * - * @return void */ - public function stopQuery(); + public function stopQuery() : void; } diff --git a/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php b/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php index c2239639f26..b663f4959c7 100644 --- a/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php +++ b/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php @@ -27,8 +27,8 @@ public function testLoggedQuery() [ 1 => [ 'sql' => 'SELECT column FROM table', - 'params' => null, - 'types' => null, + 'params' => [], + 'types' => [], 'executionMS' => 0, ], ], From c8cc485d4607bceec1c1a8c5c6a76db3509af687 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 20:08:13 +0100 Subject: [PATCH 20/66] Add UPGRADE note --- UPGRADE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 50f6b7cf06c..300e80ad7c7 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -9,6 +9,10 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec 1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. 2. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. +## BC BREAK: the SQLLogger interface has changed + +The methods are the same but use scalar type hints, return types, and non-nullable arrays. + Before: use Doctrine\DBAL\Portability\Connection; From afc806bacc8344f0770320e33eeb3a8ae1b076fb Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 22:48:23 +0100 Subject: [PATCH 21/66] Ignore NullLogger in code coverage --- lib/Doctrine/DBAL/Logging/NullLogger.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Doctrine/DBAL/Logging/NullLogger.php b/lib/Doctrine/DBAL/Logging/NullLogger.php index f8f7cb7a123..b0ffb53c817 100644 --- a/lib/Doctrine/DBAL/Logging/NullLogger.php +++ b/lib/Doctrine/DBAL/Logging/NullLogger.php @@ -4,6 +4,8 @@ /** * A SQL logger that does nothing. + * + * @codeCoverageIgnore */ final class NullLogger implements SQLLogger { From b15132c70653e97c60847747fdb59693ed2d7452 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 8 Mar 2018 23:47:39 +0100 Subject: [PATCH 22/66] Make SQLLogger implementations final --- UPGRADE.md | 1 + lib/Doctrine/DBAL/Logging/DebugStack.php | 2 +- lib/Doctrine/DBAL/Logging/EchoSQLLogger.php | 2 +- lib/Doctrine/DBAL/Logging/LoggerChain.php | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 300e80ad7c7..81e163af84c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -12,6 +12,7 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec ## BC BREAK: the SQLLogger interface has changed The methods are the same but use scalar type hints, return types, and non-nullable arrays. +SQLLogger implementations are now final. Before: diff --git a/lib/Doctrine/DBAL/Logging/DebugStack.php b/lib/Doctrine/DBAL/Logging/DebugStack.php index 5d2c8cf62ab..bd1358f321d 100644 --- a/lib/Doctrine/DBAL/Logging/DebugStack.php +++ b/lib/Doctrine/DBAL/Logging/DebugStack.php @@ -7,7 +7,7 @@ /** * Includes executed SQLs in a Debug Stack. */ -class DebugStack implements SQLLogger +final class DebugStack implements SQLLogger { /** * Executed SQL queries. diff --git a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php index 4a7da004cb7..cfca9dd7c90 100644 --- a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php +++ b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php @@ -8,7 +8,7 @@ /** * A SQL logger that logs to the standard output using echo/var_dump. */ -class EchoSQLLogger implements SQLLogger +final class EchoSQLLogger implements SQLLogger { /** * {@inheritdoc} diff --git a/lib/Doctrine/DBAL/Logging/LoggerChain.php b/lib/Doctrine/DBAL/Logging/LoggerChain.php index d1598da950d..226faae83da 100644 --- a/lib/Doctrine/DBAL/Logging/LoggerChain.php +++ b/lib/Doctrine/DBAL/Logging/LoggerChain.php @@ -5,7 +5,7 @@ /** * Chains multiple SQLLogger. */ -class LoggerChain implements SQLLogger +final class LoggerChain implements SQLLogger { /** @var SQLLogger[] */ private $loggers = []; From a947bf8182840fa5388346fd0816ca912e4cfb94 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Fri, 9 Mar 2018 00:35:00 +0100 Subject: [PATCH 23/66] Update UPGRADE.md --- UPGRADE.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 81e163af84c..2b9c246f6a0 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -9,11 +9,6 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec 1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. 2. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. -## BC BREAK: the SQLLogger interface has changed - -The methods are the same but use scalar type hints, return types, and non-nullable arrays. -SQLLogger implementations are now final. - Before: use Doctrine\DBAL\Portability\Connection; @@ -45,6 +40,12 @@ After: The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL anymore. +## BC BREAK: SQLLogger changes + +- The SQLLogger interface has changed; the methods are the same but use scalar type hints, return types, and non-nullable arrays. +- SQLLogger implementations: `DebugStack`, `EchoSQLLogger`, `LoggerChain` are now final. +- `Configuration::getSQLLogger()` does not return `null` anymore, but a `NullLogger` implementation. + # Upgrade to 2.10 ## Deprecated `Type::*` constants From 52f4680cb8c75a63369e414ff6709fd03f731350 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Fri, 9 Mar 2018 00:37:46 +0100 Subject: [PATCH 24/66] Do not accept null in Configuration::setSQLLogger() --- lib/Doctrine/DBAL/Configuration.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/DBAL/Configuration.php b/lib/Doctrine/DBAL/Configuration.php index 35d92814799..06b3603ed1e 100644 --- a/lib/Doctrine/DBAL/Configuration.php +++ b/lib/Doctrine/DBAL/Configuration.php @@ -25,11 +25,9 @@ class Configuration protected $_attributes = []; /** - * Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled. - * - * @return void + * Sets the SQL logger to use. */ - public function setSQLLogger(?SQLLogger $logger = null) + public function setSQLLogger(?SQLLogger $logger) : void { $this->_attributes['sqlLogger'] = $logger; } From 238ec651281a28518608c81a69465d4ef6712f84 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Fri, 9 Mar 2018 00:42:15 +0100 Subject: [PATCH 25/66] Add note about setSQLLogger() --- UPGRADE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 2b9c246f6a0..e7dc5e49357 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -42,9 +42,10 @@ The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL ## BC BREAK: SQLLogger changes -- The SQLLogger interface has changed; the methods are the same but use scalar type hints, return types, and non-nullable arrays. -- SQLLogger implementations: `DebugStack`, `EchoSQLLogger`, `LoggerChain` are now final. +- The `SQLLogger` interface has changed; the methods are the same but use scalar type hints, return types, and non-nullable arrays. +- `SQLLogger` implementations: `DebugStack`, `EchoSQLLogger`, `LoggerChain` are now final. - `Configuration::getSQLLogger()` does not return `null` anymore, but a `NullLogger` implementation. +- `Configuration::setSQLLogger()` does not allow `null` anymore. # Upgrade to 2.10 From b938e315b8803288f0fa73c301a04473a764ef31 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Fri, 9 Mar 2018 22:40:05 +0100 Subject: [PATCH 26/66] Don't catch Exception anymore --- lib/Doctrine/DBAL/Connection.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 90593770440..056a77e5f5e 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -1136,7 +1136,6 @@ public function lastInsertId($seqName = null) * * @return mixed The value returned by $func * - * @throws Exception * @throws Throwable */ public function transactional(Closure $func) @@ -1147,9 +1146,6 @@ public function transactional(Closure $func) $this->commit(); return $res; - } catch (Exception $e) { - $this->rollBack(); - throw $e; } catch (Throwable $e) { $this->rollBack(); throw $e; From aa17f5a011cc7cba92771073de19cd467e5593ad Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 13 Mar 2018 16:24:09 -0700 Subject: [PATCH 27/66] When rendering SQL, only render the alias if it's different from the table name --- lib/Doctrine/DBAL/Query/QueryBuilder.php | 18 ++++++++++-- .../Tests/DBAL/Query/QueryBuilderTest.php | 29 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/DBAL/Query/QueryBuilder.php b/lib/Doctrine/DBAL/Query/QueryBuilder.php index 50c08655ff3..5c18d6edd4f 100644 --- a/lib/Doctrine/DBAL/Query/QueryBuilder.php +++ b/lib/Doctrine/DBAL/Query/QueryBuilder.php @@ -1127,7 +1127,7 @@ private function getFromClauses() // Loop through all FROM clauses foreach ($this->sqlParts['from'] as $from) { - if ($from['alias'] === null) { + if ($from['alias'] === null || $from['alias'] === $from['table']) { $tableSql = $from['table']; $tableReference = $from['table']; } else { @@ -1186,7 +1186,13 @@ private function getSQLForInsert() */ private function getSQLForUpdate() { - $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $from = $this->sqlParts['from']; + + if ($from['alias'] === null || $from['alias'] === $from['table']) { + $table = $from['table']; + } else { + $table = $from['table'] . ' ' . $from['alias']; + } return 'UPDATE ' . $table . ' SET ' . implode(', ', $this->sqlParts['set']) @@ -1200,7 +1206,13 @@ private function getSQLForUpdate() */ private function getSQLForDelete() { - $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $from = $this->sqlParts['from']; + + if ($from['alias'] === null || $from['alias'] === $from['table']) { + $table = $from['table']; + } else { + $table = $from['table'] . ' ' . $from['alias']; + } return 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); } diff --git a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php index b6d4d090374..4394ef38286 100644 --- a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php @@ -411,6 +411,16 @@ public function testUpdateWithoutAlias() self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); } + public function testUpdateWithMatchingAlias() + { + $qb = new QueryBuilder($this->conn); + $qb->update('users', 'users') + ->set('foo', '?') + ->set('bar', '?'); + + self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); + } + public function testUpdateWhere() { $qb = new QueryBuilder($this->conn); @@ -448,6 +458,15 @@ public function testDeleteWithoutAlias() self::assertEquals('DELETE FROM users', (string) $qb); } + public function testDeleteWithMatchingAlias() + { + $qb = new QueryBuilder($this->conn); + $qb->delete('users', 'users'); + + self::assertEquals(QueryBuilder::DELETE, $qb->getType()); + self::assertEquals('DELETE FROM users', (string) $qb); + } + public function testDeleteWhere() { $qb = new QueryBuilder($this->conn); @@ -776,6 +795,16 @@ public function testSimpleSelectWithoutTableAlias() self::assertEquals('SELECT id FROM users', (string) $qb); } + public function testSimpleSelectWithMatchingTableAlias() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('users', 'users'); + + self::assertEquals('SELECT id FROM users', (string) $qb); + } + public function testSelectWithSimpleWhereWithoutTableAlias() { $qb = new QueryBuilder($this->conn); From ad400b92be20c55f3b8085877d3527be8977073c Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 18:30:16 +0100 Subject: [PATCH 28/66] Drop support for PostgreSQL <9.3 --- .scrutinizer.yml | 2 +- .travis.yml | 7 - UPGRADE.md | 13 ++ docs/en/reference/configuration.rst | 10 +- docs/en/reference/platforms.rst | 3 +- 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 | 46 ------- .../DBAL/Platforms/PostgreSQL92Platform.php | 69 ---------- .../DBAL/Platforms/PostgreSQL94Platform.php | 2 +- .../DBAL/Platforms/PostgreSqlPlatform.php | 42 +++++- .../Console/Command/ReservedWordsCommand.php | 29 +--- .../Driver/AbstractPostgreSQLDriverTest.php | 14 +- .../Platforms/PostgreSQL91PlatformTest.php | 40 ------ .../Platforms/PostgreSQL92PlatformTest.php | 71 ---------- .../Platforms/PostgreSQL94PlatformTest.php | 2 +- .../DBAL/Platforms/PostgreSqlPlatformTest.php | 63 +++++++++ 21 files changed, 154 insertions(+), 448 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 a3b8a5621ca..031103d47d8 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,7 +21,7 @@ before_commands: tools: external_code_coverage: timeout: 3600 - runs: 30 # 25x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP + runs: 29 # 24x 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 6b1fd5913a1..19d37bde1fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -185,13 +185,6 @@ jobs: env: DB=mariadb.mysqli MARIADB_VERSION=10.3 COVERAGE=yes addons: mariadb: 10.3 - - stage: Test - php: 7.3 - env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes - services: - - postgresql - addons: - postgresql: "9.2" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes diff --git a/UPGRADE.md b/UPGRADE.md index e7dc5e49357..c959e632086 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,18 @@ # Upgrade to 3.0 +## 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 newer PostgreSQL version (9.6+ is recommended). +`Doctrine\DBAL\Platforms\PostgreSqlPlatform` and `Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords` now represent the 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 9068869035f..bb99e6ca1fa 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -229,20 +229,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 8fdbaa168df..93a2358cec4 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -59,9 +59,8 @@ PostgreSQL ^^^^^^^^^^ - ``PostgreSqlPlatform`` for all versions. -- ``PostgreSQL91Platform`` for version 9.1 and above. -- ``PostgreSQL92Platform`` for version 9.2 and above. - ``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 04f80a9c113..15a62014f03 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -749,9 +749,7 @@ Please also notice the mapping specific footnotes for additional information. | | | | +----------------------------------------------------------+ | | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | < 9.2 | ``TEXT`` [1]_ | -| | | +---------+----------------------------------------------------------+ -| | | | < 9.4 | ``JSON`` | +| | | **PostgreSQL** | < 9.4 | ``JSON`` | | | | +---------+----------------------------------------------------------+ | | | | >= 9.4 | ``JSON`` [20]_ | | | | | +----------------------------------------------------------+ diff --git a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php index 916d924980c..bdfd6cd894b 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -7,8 +7,6 @@ use Doctrine\DBAL\Driver; 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; @@ -101,10 +99,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 1703056143f..00000000000 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php +++ /dev/null @@ -1,69 +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 4458ae27750..1aede00c7da 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -33,7 +33,7 @@ use function trim; /** - * PostgreSqlPlatform. + * Provides the behavior, features and SQL dialect of the PostgreSQL 9.4+ database platform. * * @todo Rename: PostgreSQLPlatform */ @@ -392,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, @@ -452,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); } @@ -973,6 +974,10 @@ public function getBigIntTypeDeclarationSQL(array $field) */ public function getSmallIntTypeDeclarationSQL(array $field) { + if (! empty($field['autoincrement'])) { + return 'SMALLSERIAL'; + } + return 'SMALLINT'; } @@ -1161,6 +1166,7 @@ protected function initializeDoctrineTypeMappings() 'year' => 'date', 'uuid' => 'guid', 'bytea' => 'blob', + 'json' => Type::JSON, ]; } @@ -1188,6 +1194,14 @@ public function getBinaryDefaultLength() return 0; } + /** + * {@inheritdoc} + */ + public function hasNativeJsonType() + { + return true; + } + /** * {@inheritDoc} */ @@ -1216,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 d1159c80308..c51617bafc4 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php @@ -5,8 +5,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver; 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; @@ -61,15 +59,9 @@ protected function createSchemaManager(Connection $connection) protected function getDatabasePlatformsForVersions() { 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 ec62ac8b026..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php +++ /dev/null @@ -1,40 +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 123425b3879..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php +++ /dev/null @@ -1,71 +0,0 @@ -platform->hasNativeJsonType()); - } - - /** - * @group DBAL-553 - */ - public function testReturnsJsonTypeDeclarationSQL() - { - self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); - } - - public function testReturnsSmallIntTypeDeclarationSQL() - { - 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() - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); - self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); - } - - /** - * @group DBAL-1220 - */ - public function testReturnsCloseActiveDatabaseConnectionsSQL() - { - 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 9643bdb5fd7..bf6e374ee77 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php @@ -5,7 +5,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 b45a152ab0a..9fdffcb951e 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\DBAL\Platforms; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; +use Doctrine\DBAL\Types\Type; class PostgreSqlPlatformTest extends AbstractPostgreSqlPlatformTestCase { @@ -15,4 +16,66 @@ public function testSupportsPartialIndexes() { self::assertTrue($this->platform->supportsPartialIndexes()); } + + public function testColumnCollationDeclarationSQL() + { + self::assertEquals( + 'COLLATE "en_US.UTF-8"', + $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') + ); + } + + /** + * @group DBAL-553 + */ + public function testHasNativeJsonType() + { + self::assertTrue($this->platform->hasNativeJsonType()); + } + + /** + * @group DBAL-553 + */ + public function testReturnsJsonTypeDeclarationSQL() + { + self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); + } + + public function testReturnsSmallIntTypeDeclarationSQL() + { + 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() + { + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); + self::assertEquals(Type::JSON, $this->platform->getDoctrineTypeMapping('json')); + } + + /** + * @group DBAL-1220 + */ + public function testReturnsCloseActiveDatabaseConnectionsSQL() + { + self::assertSame( + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", + $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') + ); + } } From d116e746b017a1a2874835363f5a5cccf974808b Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 18:50:24 +0100 Subject: [PATCH 29/66] 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/SQLServer2005Keywords.php | 39 ------ .../Keywords/SQLServer2008Keywords.php | 31 ----- .../Keywords/SQLServer2012Keywords.php | 2 +- .../Platforms/Keywords/SQLServerKeywords.php | 1 + .../DBAL/Platforms/SQLAzurePlatform.php | 2 +- .../DBAL/Platforms/SQLServer2005Platform.php | 46 ------- .../DBAL/Platforms/SQLServer2008Platform.php | 117 ------------------ .../DBAL/Platforms/SQLServer2012Platform.php | 2 +- .../DBAL/Platforms/SQLServerPlatform.php | 40 ++++-- .../Console/Command/ReservedWordsCommand.php | 6 - .../Driver/AbstractSQLServerDriverTest.php | 38 +++--- .../Platforms/SQLServer2008PlatformTest.php | 18 --- .../DBAL/Platforms/SQLServerPlatformTest.php | 5 + 17 files changed, 72 insertions(+), 312 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2005Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2008Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php delete mode 100644 lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.php delete mode 100644 tests/Doctrine/Tests/DBAL/Platforms/SQLServer2008PlatformTest.php diff --git a/UPGRADE.md b/UPGRADE.md index c959e632086..d4b74fe1a88 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,18 @@ # Upgrade to 3.0 +## 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 93a2358cec4..12e292eec11 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. -- ``SQLServer2005Platform`` for version 2005 and above. -- ``SQLServer2008Platform`` for version 2008 and above. +- ``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 15a62014f03..af0425c10a6 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -677,9 +677,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+ | -| | | **SQL Server** | >= 2008 | | -| | | +---------+----------------------------------------------------------+ -| | | | < 2008 | ``DATETIME`` [15]_ | +| | | **SQL Server** | "all" | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | | | +--------------------------+---------+----------------------------------------------------------+ @@ -697,9 +695,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`` | | | +--------------------------+ | | @@ -719,9 +715,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``DATE`` [15]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | < 2008 | ``DATETIME`` [15]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 2008 | ``TIME(0)`` | +| | | **SQL Server** | "all" | ``TIME(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | +-------------------+ | | +----------------------------------------------------------+ diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php index 421d82b3951..280f72544e0 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php @@ -5,8 +5,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver; -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; @@ -44,10 +42,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(); } @@ -68,7 +62,7 @@ public function getDatabase(Connection $conn) */ public function getDatabasePlatform() { - return new SQLServer2008Platform(); + return new SQLServerPlatform(); } /** diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2005Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2005Keywords.php deleted file mode 100644 index c4fc6c838ff..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2005Keywords.php +++ /dev/null @@ -1,39 +0,0 @@ -doctrineTypeMapping['datetime2'] = 'datetime'; - $this->doctrineTypeMapping['date'] = 'date'; - $this->doctrineTypeMapping['time'] = 'time'; - $this->doctrineTypeMapping['datetimeoffset'] = 'datetimetz'; - } - - /** - * {@inheritdoc} - * - * Returns Microsoft SQL Server 2008 specific keywords class - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLServer2008Keywords::class; - } - - protected function getLikeWildcardCharacters() : string - { - return parent::getLikeWildcardCharacters() . '[]^'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php index 009a37d33b0..1262e2be3e5 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php @@ -14,7 +14,7 @@ * Differences to SQL Server 2008 and before are that sequences are introduced, * and support for the new OFFSET... FETCH syntax for result pagination has been added. */ -class SQLServer2012Platform extends SQLServer2008Platform +class SQLServer2012Platform extends SQLServerPlatform { /** * {@inheritdoc} diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index 4c7be5f2199..432f6f85e5c 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -880,7 +880,7 @@ public function getListTablesSQL() { // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams // Category 2 must be ignored as it is "MS SQL Server 'pseudo-system' object[s]" for replication - return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; + return "SELECT name, SCHEMA_NAME (uid) AS schema_name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; } /** @@ -1168,6 +1168,14 @@ public function getGuidTypeDeclarationSQL(array $field) return 'UNIQUEIDENTIFIER'; } + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATETIMEOFFSET(6)'; + } + /** * {@inheritDoc} */ @@ -1213,7 +1221,9 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { - return 'DATETIME'; + // 3 - microseconds precision length + // http://msdn.microsoft.com/en-us/library/ms187819.aspx + return 'DATETIME2(6)'; } /** @@ -1221,7 +1231,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { - return 'DATETIME'; + return 'DATE'; } /** @@ -1229,7 +1239,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { - return 'DATETIME'; + return 'TIME(0)'; } /** @@ -1378,7 +1388,7 @@ private function isOrderByInTopNSubquery($query, $currentPosition) */ public function supportsLimitOffset() { - return false; + return true; } /** @@ -1422,7 +1432,7 @@ public function getTemporaryTableName($tableName) */ public function getDateTimeFormatString() { - return 'Y-m-d H:i:s.000'; + return 'Y-m-d H:i:s.u'; } /** @@ -1430,7 +1440,7 @@ public function getDateTimeFormatString() */ public function getDateFormatString() { - return 'Y-m-d H:i:s.000'; + return 'Y-m-d'; } /** @@ -1438,7 +1448,7 @@ public function getDateFormatString() */ public function getTimeFormatString() { - return 'Y-m-d H:i:s.000'; + return 'H:i:s'; } /** @@ -1446,7 +1456,7 @@ public function getTimeFormatString() */ public function getDateTimeTzFormatString() { - return $this->getDateTimeFormatString(); + return 'Y-m-d H:i:s.u P'; } /** @@ -1488,6 +1498,10 @@ protected function initializeDoctrineTypeMappings() 'varbinary' => 'binary', 'image' => 'blob', 'uniqueidentifier' => 'guid', + 'datetime2' => 'datetime', + 'date' => 'date', + 'time' => 'time', + 'datetimeoffset' => 'datetimetz', ]; } @@ -1648,6 +1662,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 48fb3b29f3e..69eea132855 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php @@ -4,8 +4,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\AbstractSQLServerDriver; -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; @@ -19,7 +17,7 @@ protected function createDriver() protected function createPlatform() { - return new SQLServer2008Platform(); + return new SQLServerPlatform(); } protected function createSchemaManager(Connection $connection) @@ -30,27 +28,19 @@ protected function createSchemaManager(Connection $connection) protected function getDatabasePlatformsForVersions() { 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/SQLServer2008PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2008PlatformTest.php deleted file mode 100644 index 3083ab7b606..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2008PlatformTest.php +++ /dev/null @@ -1,18 +0,0 @@ -platform->getDateTimeTzTypeDeclarationSQL([])); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php index ed2842813aa..d86485866d0 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php @@ -66,4 +66,9 @@ public function getModifyLimitQueries() ], ]; } + + public function testGeneratesTypeDeclarationForDateTimeTz() + { + self::assertEquals('DATETIMEOFFSET(6)', $this->platform->getDateTimeTzTypeDeclarationSQL([])); + } } From e785a54f35feee43f23741aea41bd96056051522 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 16 Mar 2018 20:06:21 +0100 Subject: [PATCH 30/66] Drop support for SQL Anywhere <16 --- UPGRADE.md | 15 ++ docs/en/reference/configuration.rst | 11 +- docs/en/reference/types.rst | 4 +- .../DBAL/Driver/AbstractSQLAnywhereDriver.php | 18 +- .../Keywords/SQLAnywhere11Keywords.php | 39 ---- .../Keywords/SQLAnywhere12Keywords.php | 48 ----- .../Keywords/SQLAnywhere16Keywords.php | 39 ---- .../Keywords/SQLAnywhereKeywords.php | 19 +- .../DBAL/Platforms/SQLAnywhere11Platform.php | 26 --- .../DBAL/Platforms/SQLAnywhere12Platform.php | 114 ------------ .../DBAL/Platforms/SQLAnywhere16Platform.php | 39 ---- .../DBAL/Platforms/SQLAnywherePlatform.php | 93 +++++++++- .../Console/Command/ReservedWordsCommand.php | 9 - .../Driver/AbstractSQLAnywhereDriverTest.php | 41 +---- .../Platforms/SQLAnywhere11PlatformTest.php | 26 --- .../Platforms/SQLAnywhere12PlatformTest.php | 141 --------------- .../Platforms/SQLAnywhere16PlatformTest.php | 79 -------- .../Platforms/SQLAnywherePlatformTest.php | 169 ++++++++++++++++-- 18 files changed, 290 insertions(+), 640 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere12Keywords.php delete mode 100644 lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere16Keywords.php 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 d4b74fe1a88..63fcb89d2fb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,20 @@ # Upgrade to 3.0 +## 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 newer SQL Anywhere version (16+). +`Doctrine\DBAL\Platforms\SQLAnywherePlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords` now represent the 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 bb99e6ca1fa..a4fba806a0c 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -310,14 +310,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/types.rst b/docs/en/reference/types.rst index af0425c10a6..dd733f33a51 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. | | +--------------------------+ | | | | | **Oracle** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Anywhere** | < 12 | ``DATETIME`` [14]_ [15]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 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 88f26ce7def..f93b576e202 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php @@ -6,14 +6,10 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver; 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. @@ -81,19 +77,7 @@ public function createDatabasePlatformForVersion($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, '16', '>='): - return new SQLAnywhere16Platform(); - case version_compare($version, '12', '>='): - return new SQLAnywhere12Platform(); - case version_compare($version, '11', '>='): - return new SQLAnywhere11Platform(); default: return new SQLAnywherePlatform(); } @@ -114,7 +98,7 @@ public function getDatabase(Connection $conn) */ public function getDatabasePlatform() { - return new SQLAnywhere12Platform(); + return new SQLAnywherePlatform(); } /** diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php deleted file mode 100644 index 09513c5770e..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php +++ /dev/null @@ -1,39 +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 773e9a27368..7a288d7a292 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,7 +34,7 @@ /** * The SQLAnywherePlatform provides the behavior, features and SQL dialect of the - * SAP Sybase SQL Anywhere 10 database platform. + * SAP Sybase SQL Anywhere 12 database platform. */ class SQLAnywherePlatform extends AbstractPlatform { @@ -507,7 +509,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) */ public function getDateTimeTzFormatString() { - return $this->getDateTimeFormatString(); + return 'Y-m-d H:i:s.uP'; } /** @@ -998,6 +1000,14 @@ public function getMd5Expression($column) return 'HASH(' . $column . ", 'MD5')"; } + /** + * {@inheritdoc} + */ + public function getRegexpExpression() + { + return 'REGEXP'; + } + /** * {@inheritdoc} */ @@ -1160,6 +1170,70 @@ public function getTruncateTableSQL($tableName, $cascade = false) return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); } + /** + * {@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} */ @@ -1324,12 +1398,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; } @@ -1481,6 +1569,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 cbd23505bae..a05fef71214 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php @@ -4,9 +4,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver; -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; @@ -19,7 +16,7 @@ protected function createDriver() protected function createPlatform() { - return new SQLAnywhere12Platform(); + return new SQLAnywherePlatform(); } protected function createSchemaManager(Connection $connection) @@ -30,35 +27,13 @@ protected function createSchemaManager(Connection $connection) protected function getDatabasePlatformsForVersions() { 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 7e91777d6ef..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php +++ /dev/null @@ -1,26 +0,0 @@ -markTestSkipped('This version of the platform now supports regular expressions.'); - } - - public function testGeneratesRegularExpressionSQLSnippet() - { - 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 7cbb2c69bb8..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php +++ /dev/null @@ -1,141 +0,0 @@ -markTestSkipped('This version of the platform now supports sequences.'); - } - - public function testSupportsSequences() - { - self::assertTrue($this->platform->supportsSequences()); - } - - public function testGeneratesSequenceSqlCommands() - { - $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() - { - self::assertEquals( - 'TIMESTAMP WITH TIME ZONE', - $this->platform->getDateTimeTzTypeDeclarationSQL([ - 'length' => 10, - 'fixed' => true, - 'unsigned' => true, - 'autoincrement' => true, - ]) - ); - } - - public function testHasCorrectDateTimeTzFormatString() - { - self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); - } - - public function testInitializesDateTimeTzTypeMapping() - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); - self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); - } - - public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() - { - 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 9692ffb1f76..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php +++ /dev/null @@ -1,79 +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() - { - $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 5d312ba7c0f..8189f0d5856 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\Schema\UniqueConstraint; @@ -453,18 +454,121 @@ public function testCannotGenerateCustomConstraintWithCreateConstraintSQL() public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() { 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() + { + $this->expectException('UnexpectedValueException'); + + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_distinct', 'with_nulls_not_distinct'] + ), + 'footable' + ); } public function testDoesNotSupportIndexDeclarationInCreateAlterTableStatements() @@ -574,19 +678,28 @@ public function testGeneratesSQLSnippets() ); } - public function testDoesNotSupportRegexp() + public function testHasCorrectDateTimeTzFormatString() { - $this->expectException(DBALException::class); + self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); + } - $this->platform->getRegexpExpression(); + public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() + { + self::assertEquals( + 'TIMESTAMP WITH TIME ZONE', + $this->platform->getDateTimeTzTypeDeclarationSQL([ + 'length' => 10, + 'fixed' => true, + 'unsigned' => true, + 'autoincrement' => true, + ]) + ); } - public function testHasCorrectDateTimeTzFormatString() + public function testInitializesDateTimeTzTypeMapping() { - // 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() @@ -745,7 +858,41 @@ public function testSupportsGettingAffectedRows() public function testDoesNotSupportSequences() { - self::assertFalse($this->platform->supportsSequences()); + self::markTestSkipped('This version of the platform now supports sequences.'); + } + + public function testSupportsSequences() + { + self::assertTrue($this->platform->supportsSequences()); + } + + public function testGeneratesSequenceSqlCommands() + { + $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() From 419166638aab4bb95e0a89253e979b513c7c87f8 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 17 Mar 2018 20:05:31 +0100 Subject: [PATCH 31/66] Drop PDO DB2 driver --- UPGRADE.md | 8 +++ lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php | 57 ------------------- .../Tests/DBAL/Driver/PDOIbm/DriverTest.php | 19 ------- 3 files changed, 8 insertions(+), 76 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 63fcb89d2fb..f3fa41c885f 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,13 @@ # Upgrade to 3.0 +## 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 now 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 4291e1e17f0..00000000000 --- a/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php +++ /dev/null @@ -1,57 +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} - */ - 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 6361f05575c..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php +++ /dev/null @@ -1,19 +0,0 @@ -driver->getName()); - } - - protected function createDriver() - { - return new Driver(); - } -} From 0d01d3e2ba8807ce802c3eb5906643f21a763dd4 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 17 Mar 2018 20:44:53 +0100 Subject: [PATCH 32/66] 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 f3fa41c885f..d527d0b1160 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,10 @@ # Upgrade to 3.0 +## BC BREAK: Removed MsSQLKeywords class + +The `Doctrine\DBAL\Platforms\MsSQLKeywords` 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 now 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 33/66] 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 fcc8c1c67f4..1ecc4d4d791 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 311574226b8..86081b1d5ef 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -1049,36 +1049,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 c7691c076fb..811e9cff164 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 1aede00c7da..fe868aadbd2 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 7a288d7a292..14cea4cd516 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1536,45 +1536,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 432f6f85e5c..f8d3985930e 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1473,35 +1473,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 01fe94e3068..30bf99a970e 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -612,38 +612,38 @@ public function getInlineColumnCommentSQL($comment) 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 f934f89de61052c5b1b81a075ec854dddf396aa6 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Mon, 19 Mar 2018 19:59:11 -0700 Subject: [PATCH 34/66] Fixed build failure on SQL Server (sqlsrv) The regression was introduced by 2b8c40d267b4ac699ea878dcca07332e1697978c. Fixes #3060. --- lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index af07561167f..7438eaada62 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -318,7 +318,7 @@ public function setFetchMode($fetchMode, ...$args) } if (isset($args[1])) { - $this->defaultFetchClassCtorArgs = (array) $args[2]; + $this->defaultFetchClassCtorArgs = (array) $args[1]; } return true; @@ -379,7 +379,7 @@ public function fetchAll($fetchMode = null, ...$args) switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch($fetchMode, $args)) !== false) { + while (($row = $this->fetch($fetchMode, ...$args)) !== false) { $rows[] = $row; } break; From 03917d35a623db23fb011950f954ddc446a1e41c Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Mon, 19 Mar 2018 22:15:10 -0700 Subject: [PATCH 35/66] Fixed build failure on SQL Server (pdo_sqlsrv) Use a wrapped PDO Statement instead of a custom class for `pdo_sqlsrv` since `PDOSqlsrv\Statement` doesn't extend `PDOStatement` anymore. --- lib/Doctrine/DBAL/Driver/PDOConnection.php | 2 +- .../DBAL/Driver/PDOSqlsrv/Connection.php | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 8827d4ca037..e3736a9da8b 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -115,7 +115,7 @@ public function requiresQueryForServerVersion() /** * Creates a wrapped statement */ - private function createStatement(\PDOStatement $stmt) : PDOStatement + protected function createStatement(\PDOStatement $stmt) : PDOStatement { return new PDOStatement($stmt); } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php index bd3894477b5..33331bd0a5a 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -3,8 +3,8 @@ namespace Doctrine\DBAL\Driver\PDOSqlsrv; use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\Driver\PDOStatement; use Doctrine\DBAL\ParameterType; -use PDO; use function strpos; use function substr; @@ -13,15 +13,6 @@ */ class Connection extends PDOConnection { - /** - * {@inheritdoc} - */ - public function __construct($dsn, $user = null, $password = null, ?array $options = null) - { - parent::__construct($dsn, $user, $password, $options); - $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]); - } - /** * {@inheritDoc} */ @@ -51,4 +42,12 @@ public function quote($value, $type = ParameterType::STRING) return $val; } + + /** + * {@inheritDoc} + */ + protected function createStatement(\PDOStatement $stmt) : PDOStatement + { + return new Statement($stmt); + } } From 21cf640d728eaf5ad79911b41deed5e733158b71 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 1 Apr 2018 19:53:57 -0700 Subject: [PATCH 36/66] [DBAL-3079] Reworked the usage of PDO in PDOConnection from inheritance to composition --- lib/Doctrine/DBAL/Connection.php | 17 ++-- .../Connections/MasterSlaveConnection.php | 9 +- lib/Doctrine/DBAL/Driver/Connection.php | 5 +- .../DBAL/Driver/IBMDB2/DB2Connection.php | 5 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 5 +- .../DBAL/Driver/OCI8/OCI8Connection.php | 6 +- lib/Doctrine/DBAL/Driver/PDOConnection.php | 82 +++++++++++++++---- lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 8 +- lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 6 +- .../SQLAnywhere/SQLAnywhereConnection.php | 7 +- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 5 +- lib/Doctrine/DBAL/Portability/Connection.php | 7 +- .../Tests/DBAL/Driver/PDOPgSql/DriverTest.php | 9 +- .../Tests/DBAL/Functional/DataAccessTest.php | 5 +- .../Functional/Driver/PDOConnectionTest.php | 4 +- .../Driver/PDOSqlsrv/DriverTest.php | 11 ++- .../DBAL/Functional/Ticket/DBAL630Test.php | 16 +++- .../Tests/Mocks/DriverConnectionMock.php | 2 +- 18 files changed, 129 insertions(+), 80 deletions(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 056a77e5f5e..c3f195d69ad 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -23,7 +23,6 @@ use Throwable; use function array_key_exists; use function assert; -use function func_get_args; use function implode; use function is_int; use function is_string; @@ -978,25 +977,19 @@ public function project($query, array $params, Closure $function) } /** - * Executes an SQL statement, returning a result set as a Statement object. - * - * @return \Doctrine\DBAL\Driver\Statement - * - * @throws DBALException + * {@inheritDoc} */ - public function query() + public function query(string $sql) { $connection = $this->getWrappedConnection(); - $args = func_get_args(); - $logger = $this->_config->getSQLLogger(); - $logger->startQuery($args[0]); + $logger->startQuery($sql); try { - $statement = $connection->query(...$args); + $statement = $connection->query($sql); } catch (Throwable $ex) { - throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); + throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } $statement->setFetchMode($this->defaultFetchMode); diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index ba76be2db79..6cf1c371d83 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -13,7 +13,6 @@ use function array_rand; use function assert; use function count; -use function func_get_args; /** * Master-Slave Connection @@ -342,17 +341,15 @@ public function rollbackSavepoint($savepoint) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) { $this->connect('master'); assert($this->_conn instanceof DriverConnection); - $args = func_get_args(); - $logger = $this->getConfiguration()->getSQLLogger(); - $logger->startQuery($args[0]); + $logger->startQuery($sql); - $statement = $this->_conn->query(...$args); + $statement = $this->_conn->query($sql); $statement->setFetchMode($this->defaultFetchMode); diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 1574581c2ad..8d1d1384db0 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\ParameterType; /** @@ -25,8 +26,10 @@ public function prepare($prepareString); * Executes an SQL statement, returning a result set as a Statement object. * * @return Statement + * + * @throws DBALException */ - public function query(); + public function query(string $sql); /** * Quotes a string for use in a query. diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index cb1e6018f3e..561c9eb22a9 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -22,7 +22,6 @@ use function db2_rollback; use function db2_server_info; use function db2_stmt_errormsg; -use function func_get_args; class DB2Connection implements Connection, ServerInfoAwareConnection { @@ -89,10 +88,8 @@ public function prepare($sql) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 1f1a1d218c3..39ef8b2bd2a 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -15,7 +15,6 @@ use const MYSQLI_SERVER_PUBLIC_KEY; use function defined; use function floor; -use function func_get_args; use function in_array; use function ini_get; use function mysqli_errno; @@ -134,10 +133,8 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index c1857936f5a..4d95b66628b 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -10,7 +10,6 @@ use const OCI_DEFAULT; use const OCI_NO_AUTO_COMMIT; use function addcslashes; -use function func_get_args; use function is_float; use function is_int; use function oci_commit; @@ -111,11 +110,8 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; - //$fetchMode = $args[1]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index e3736a9da8b..09edf471662 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -4,14 +4,18 @@ use Doctrine\DBAL\ParameterType; use PDO; -use function func_get_args; +use function assert; /** * PDO implementation of the Connection interface. + * * Used by all PDO-based drivers. */ -class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection +class PDOConnection implements Connection, ServerInfoAwareConnection { + /** @var PDO */ + private $connection; + /** * @param string $dsn * @param string|null $user @@ -23,8 +27,8 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection public function __construct($dsn, $user = null, $password = null, ?array $options = null) { try { - parent::__construct($dsn, (string) $user, (string) $password, (array) $options); - $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection = new PDO($dsn, (string) $user, (string) $password, (array) $options); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -36,7 +40,7 @@ public function __construct($dsn, $user = null, $password = null, ?array $option public function exec($statement) { try { - return parent::exec($statement); + return $this->connection->exec($statement); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -47,17 +51,17 @@ public function exec($statement) */ public function getServerVersion() { - return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); + return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION); } /** * {@inheritdoc} */ - public function prepare($prepareString, $driverOptions = []) + public function prepare($prepareString) { try { return $this->createStatement( - parent::prepare($prepareString, $driverOptions) + $this->connection->prepare($prepareString) ); } catch (\PDOException $exception) { throw new PDOException($exception); @@ -67,14 +71,13 @@ public function prepare($prepareString, $driverOptions = []) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - try { - return $this->createStatement( - parent::query(...$args) - ); + $stmt = $this->connection->query($sql); + assert($stmt instanceof \PDOStatement); + + return $this->createStatement($stmt); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -85,7 +88,7 @@ public function query() */ public function quote($input, $type = ParameterType::STRING) { - return parent::quote($input, $type); + return $this->connection->quote($input, $type); } /** @@ -95,10 +98,10 @@ public function lastInsertId($name = null) { try { if ($name === null) { - return parent::lastInsertId(); + return $this->connection->lastInsertId(); } - return parent::lastInsertId($name); + return $this->connection->lastInsertId($name); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -119,4 +122,49 @@ protected function createStatement(\PDOStatement $stmt) : PDOStatement { return new PDOStatement($stmt); } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + return $this->connection->beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() + { + return $this->connection->commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + return $this->connection->rollBack(); + } + + /** + * {@inheritDoc} + */ + public function errorCode() + { + return $this->connection->errorCode(); + } + + /** + * {@inheritDoc} + */ + public function errorInfo() + { + return $this->connection->errorInfo(); + } + + public function getWrappedConnection() : PDO + { + return $this->connection; + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php index 972dbadcd5d..c3b9e39a026 100644 --- a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -20,7 +20,7 @@ class Driver extends AbstractPostgreSQLDriver public function connect(array $params, $username = null, $password = null, array $driverOptions = []) { try { - $pdo = new PDOConnection( + $connection = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, @@ -32,7 +32,7 @@ public function connect(array $params, $username = null, $password = null, array || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true ) ) { - $pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); + $connection->getWrappedConnection()->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); } /* defining client_encoding via SET NAMES to avoid inconsistent DSN support @@ -40,10 +40,10 @@ public function connect(array $params, $username = null, $password = null, array * - passing client_encoding via the 'options' param breaks pgbouncer support */ if (isset($params['charset'])) { - $pdo->exec('SET NAMES \'' . $params['charset'] . '\''); + $connection->exec('SET NAMES \'' . $params['charset'] . '\''); } - return $pdo; + return $connection; } catch (PDOException $e) { throw DBALException::driverException($this, $e); } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php index 7a28b831027..c00589101c9 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -35,7 +35,7 @@ public function connect(array $params, $username = null, $password = null, array } try { - $pdo = new PDOConnection( + $connection = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, @@ -45,11 +45,13 @@ public function connect(array $params, $username = null, $password = null, array throw DBALException::driverException($this, $ex); } + $pdo = $connection->getWrappedConnection(); + foreach ($this->_userDefinedFunctions as $fn => $data) { $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); } - return $pdo; + return $connection; } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index d47782003e6..29de2ab95f3 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\ParameterType; use function assert; -use function func_get_args; use function is_float; use function is_int; use function is_resource; @@ -151,11 +150,9 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $stmt = $this->prepare($args[0]); - + $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index 35ad913ff5b..f64c5c537b2 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\ParameterType; use const SQLSRV_ERR_ERRORS; -use function func_get_args; use function is_float; use function is_int; use function sprintf; @@ -83,10 +82,8 @@ public function prepare($sql) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Portability/Connection.php b/lib/Doctrine/DBAL/Portability/Connection.php index 0d5a7b3de8c..e2f660cef0c 100644 --- a/lib/Doctrine/DBAL/Portability/Connection.php +++ b/lib/Doctrine/DBAL/Portability/Connection.php @@ -8,7 +8,6 @@ use PDO; use const CASE_LOWER; use const CASE_UPPER; -use function func_get_args; /** * Portability wrapper for a Connection. @@ -65,7 +64,7 @@ public function connect() if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { if ($this->_conn instanceof PDOConnection) { // make use of c-level support for case handling - $this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); + $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); } else { $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; } @@ -116,11 +115,11 @@ public function prepare($statement) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { $connection = $this->getWrappedConnection(); - $stmt = $connection->query(...func_get_args()); + $stmt = $connection->query($sql); $stmt = new Statement($stmt, $this); $stmt->setFetchMode($this->defaultFetchMode); diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php index a6ac2456b64..1e3a2745b65 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php @@ -36,7 +36,7 @@ public function testConnectionDisablesPreparesOnPhp56() self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); @@ -63,7 +63,10 @@ public function testConnectionDoesNotDisablePreparesOnPhp56WhenAttributeDefined( self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertNotSame(true, $connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertNotSame( + true, + $connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES) + ); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); @@ -90,7 +93,7 @@ public function testConnectionDisablePreparesOnPhp56WhenDisablePreparesIsExplici self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index a0b8db003da..62c9bd9b405 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -949,8 +949,9 @@ private function beforeFetchClassTest() } /** @var PDOConnection $connection */ - $connection = $this->connection->getWrappedConnection(); - $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); + $connection = $this->connection + ->getWrappedConnection(); + $connection->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php index 9a12cb8f714..e8ef3aa23c1 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php @@ -72,7 +72,9 @@ public function testThrowsWrappedExceptionOnPrepare() // Emulated prepared statements have to be disabled for this test // so that PDO actually communicates with the database server to check the query. - $this->driverConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->driverConnection + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->expectException(PDOException::class); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php index 955a90cdaf1..84d8bbfd822 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php @@ -3,9 +3,11 @@ namespace Doctrine\Tests\DBAL\Functional\Driver\PDOSqlsrv; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver; use Doctrine\Tests\DBAL\Functional\Driver\AbstractDriverTest; use PDO; +use function assert; use function extension_loaded; class DriverTest extends AbstractDriverTest @@ -69,6 +71,13 @@ public function testDriverOptions() : void { $connection = $this->getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]); - self::assertSame(PDO::CASE_UPPER, $connection->getAttribute(PDO::ATTR_CASE)); + assert($connection instanceof PDOConnection); + + self::assertSame( + PDO::CASE_UPPER, + $connection + ->getWrappedConnection() + ->getAttribute(PDO::ATTR_CASE) + ); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php index 21c6e492622..ab703e7dab1 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php @@ -37,7 +37,9 @@ protected function setUp() : void protected function tearDown() : void { if ($this->running) { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } parent::tearDown(); @@ -71,7 +73,9 @@ public function testBooleanConversionBoolParamRealPrepares() public function testBooleanConversionBoolParamEmulatedPrepares() { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -95,7 +99,9 @@ public function testBooleanConversionNullParamEmulatedPrepares( $statementValue, $databaseConvertedValue ) { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -119,7 +125,9 @@ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInB $statementValue, $databaseConvertedValue ) { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); diff --git a/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php b/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php index fa22cc5f91b..06131bd234b 100644 --- a/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php +++ b/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php @@ -11,7 +11,7 @@ public function prepare($prepareString) { } - public function query() + public function query(string $sql) { } From c28d7dacc7a3d9315e10916252fb0d1751c62a22 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 10 Apr 2018 23:58:28 -0700 Subject: [PATCH 37/66] [DBAL-3079] Added type hints to query-related method parameters and return values --- .../DBAL/Cache/ResultCacheStatement.php | 2 +- lib/Doctrine/DBAL/Connection.php | 42 ++++++---------- .../Connections/MasterSlaveConnection.php | 12 +++-- lib/Doctrine/DBAL/Driver/Connection.php | 16 ++---- .../DBAL/Driver/IBMDB2/DB2Connection.php | 8 +-- .../DBAL/Driver/IBMDB2/DB2Statement.php | 2 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 10 ++-- .../DBAL/Driver/Mysqli/MysqliStatement.php | 2 +- .../DBAL/Driver/OCI8/OCI8Connection.php | 10 ++-- .../DBAL/Driver/OCI8/OCI8Statement.php | 2 +- lib/Doctrine/DBAL/Driver/PDOConnection.php | 8 +-- lib/Doctrine/DBAL/Driver/PDOStatement.php | 2 +- .../SQLAnywhere/SQLAnywhereConnection.php | 10 ++-- .../SQLAnywhere/SQLAnywhereStatement.php | 2 +- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 8 +-- .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 2 +- lib/Doctrine/DBAL/Driver/Statement.php | 2 +- lib/Doctrine/DBAL/Portability/Connection.php | 10 ++-- lib/Doctrine/DBAL/Portability/Statement.php | 2 +- lib/Doctrine/DBAL/Statement.php | 2 +- .../Driver/SQLSrv/StatementTest.php | 2 +- tests/Doctrine/Tests/DBAL/StatementTest.php | 16 +++--- .../Tests/Mocks/DriverConnectionMock.php | 49 ------------------- 23 files changed, 81 insertions(+), 140 deletions(-) delete mode 100644 tests/Doctrine/Tests/Mocks/DriverConnectionMock.php diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index e4436b986dc..bd80dadb96e 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -194,7 +194,7 @@ public function fetchColumn($columnIndex = 0) * * @return int The number of rows. */ - public function rowCount() + public function rowCount() : int { assert($this->statement instanceof Statement); diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index c3f195d69ad..182624380aa 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -837,18 +837,16 @@ public function fetchAll($sql, array $params = [], $types = []) /** * Prepares an SQL statement. * - * @param string $statement The SQL statement to prepare. - * - * @return DriverStatement The prepared statement. + * @param string $sql The SQL statement to prepare. * * @throws DBALException */ - public function prepare($statement) + public function prepare(string $sql) : DriverStatement { try { - $stmt = new Statement($statement, $this); + $stmt = new Statement($sql, $this); } catch (Throwable $ex) { - throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); + throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } $stmt->setFetchMode($this->defaultFetchMode); @@ -871,7 +869,7 @@ public function prepare($statement) * * @throws DBALException */ - public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement { if ($qcp !== null) { return $this->executeCacheQuery($query, $params, $types, $qcp); @@ -915,11 +913,9 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach * @param int[]|string[] $types The types the previous parameters are in. * @param QueryCacheProfile $qcp The query cache profile. * - * @return ResultStatement - * * @throws CacheException */ - public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) + public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) : ResultStatement { $resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl(); @@ -979,7 +975,7 @@ public function project($query, array $params, Closure $function) /** * {@inheritDoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $connection = $this->getWrappedConnection(); @@ -1009,11 +1005,9 @@ public function query(string $sql) * @param mixed[] $params The query parameters. * @param int[]|string[] $types The parameter types. * - * @return int The number of affected rows. - * * @throws DBALException */ - public function executeUpdate($query, array $params = [], array $types = []) + public function executeUpdate(string $query, array $params = [], array $types = []) : int { $connection = $this->getWrappedConnection(); @@ -1046,15 +1040,9 @@ public function executeUpdate($query, array $params = [], array $types = []) } /** - * Executes an SQL statement and return the number of affected rows. - * - * @param string $statement - * - * @return int The number of affected rows. - * - * @throws DBALException + * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $connection = $this->getWrappedConnection(); @@ -1459,13 +1447,11 @@ public function convertToPHPValue($value, $type) * @internal Duck-typing used on the $stmt parameter to support driver statements as well as * raw PDOStatement instances. * - * @param \Doctrine\DBAL\Driver\Statement $stmt The statement to bind the values to. - * @param mixed[] $params The map/list of named/positional parameters. - * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). - * - * @return void + * @param DriverStatement $stmt The statement to bind the values to. + * @param mixed[] $params The map/list of named/positional parameters. + * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). */ - private function _bindTypedValues($stmt, array $params, array $types) + private function _bindTypedValues(DriverStatement $stmt, array $params, array $types) : void { // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. if (is_int(key($params))) { diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index 6cf1c371d83..fe94636f443 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -7,6 +7,8 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Event\ConnectionEventArgs; use Doctrine\DBAL\Events; use InvalidArgumentException; @@ -218,7 +220,7 @@ protected function chooseConnectionConfiguration($connectionName, $params) /** * {@inheritDoc} */ - public function executeUpdate($query, array $params = [], array $types = []) + public function executeUpdate(string $query, array $params = [], array $types = []) : int { $this->connect('master'); @@ -301,7 +303,7 @@ public function insert($tableName, array $data, array $types = []) /** * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $this->connect('master'); @@ -341,7 +343,7 @@ public function rollbackSavepoint($savepoint) /** * {@inheritDoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $this->connect('master'); assert($this->_conn instanceof DriverConnection); @@ -361,10 +363,10 @@ public function query(string $sql) /** * {@inheritDoc} */ - public function prepare($statement) + public function prepare(string $sql) : Statement { $this->connect('master'); - return parent::prepare($statement); + return parent::prepare($sql); } } diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 8d1d1384db0..2632483e931 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -15,21 +15,15 @@ interface Connection { /** * Prepares a statement for execution and returns a Statement object. - * - * @param string $prepareString - * - * @return Statement */ - public function prepare($prepareString); + public function prepare(string $sql) : Statement; /** * Executes an SQL statement, returning a result set as a Statement object. * - * @return Statement - * * @throws DBALException */ - public function query(string $sql); + public function query(string $sql) : ResultStatement; /** * Quotes a string for use in a query. @@ -44,11 +38,9 @@ public function quote($input, $type = ParameterType::STRING); /** * Executes an SQL statement and return the number of affected rows. * - * @param string $statement - * - * @return int + * @throws DBALException */ - public function exec($statement); + public function exec(string $statement) : int; /** * Returns the ID of the last inserted row or sequence value. diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index 561c9eb22a9..20ecd7fc86a 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -3,7 +3,9 @@ namespace Doctrine\DBAL\Driver\IBMDB2; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\ParameterType; use stdClass; use const DB2_AUTOCOMMIT_OFF; @@ -75,7 +77,7 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($sql) + public function prepare(string $sql) : DriverStatement { $stmt = @db2_prepare($this->conn, $sql); if (! $stmt) { @@ -88,7 +90,7 @@ public function prepare($sql) /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $stmt = $this->prepare($sql); $stmt->execute(); @@ -113,7 +115,7 @@ public function quote($input, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = @db2_exec($this->conn, $statement); diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index 052fbbe1266..d7cea000a0e 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -344,7 +344,7 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return @db2_num_rows($this->stmt) ? : 0; } diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 39ef8b2bd2a..80a23087591 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -4,7 +4,9 @@ use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\PingableConnection; +use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\ParameterType; use mysqli; use const MYSQLI_INIT_COMMAND; @@ -125,15 +127,15 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new MysqliStatement($this->conn, $prepareString); + return new MysqliStatement($this->conn, $sql); } /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $stmt = $this->prepare($sql); $stmt->execute(); @@ -152,7 +154,7 @@ public function quote($input, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { if ($this->conn->query($statement) === false) { throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index acf8b4ec54c..eff8f88c569 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -415,7 +415,7 @@ public function closeCursor() /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { if ($this->_columnNames === false) { return $this->_stmt->affected_rows; diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index 4d95b66628b..ce651559eb5 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -3,7 +3,9 @@ namespace Doctrine\DBAL\Driver\OCI8; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\ParameterType; use UnexpectedValueException; use const OCI_COMMIT_ON_SUCCESS; @@ -102,15 +104,15 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new OCI8Statement($this->dbh, $prepareString, $this); + return new OCI8Statement($this->dbh, $sql, $this); } /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $stmt = $this->prepare($sql); $stmt->execute(); @@ -134,7 +136,7 @@ public function quote($value, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = $this->prepare($statement); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index 20081cbb892..8730009f731 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -519,7 +519,7 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return oci_num_rows($this->_sth) ?: 0; } diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 09edf471662..995ebee6adb 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -37,7 +37,7 @@ public function __construct($dsn, $user = null, $password = null, ?array $option /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { try { return $this->connection->exec($statement); @@ -57,11 +57,11 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : Statement { try { return $this->createStatement( - $this->connection->prepare($prepareString) + $this->connection->prepare($sql) ); } catch (\PDOException $exception) { throw new PDOException($exception); @@ -71,7 +71,7 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { try { $stmt = $this->connection->query($sql); diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 01c1d490031..8d935b55b39 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -141,7 +141,7 @@ public function execute($params = null) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return $this->stmt->rowCount(); } diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index 29de2ab95f3..6c117904c58 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -3,7 +3,9 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\ParameterType; use function assert; use function is_float; @@ -106,7 +108,7 @@ public function errorInfo() /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { if (sasql_real_query($this->connection, $statement) === false) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); @@ -142,15 +144,15 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new SQLAnywhereStatement($this->connection, $prepareString); + return new SQLAnywhereStatement($this->connection, $sql); } /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index f35ce204aba..b67b67de8a1 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -298,7 +298,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return sasql_stmt_affected_rows($this->stmt); } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index f64c5c537b2..caa04efce5f 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -3,7 +3,9 @@ namespace Doctrine\DBAL\Driver\SQLSrv; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\ParameterType; use const SQLSRV_ERR_ERRORS; use function is_float; @@ -74,7 +76,7 @@ public function requiresQueryForServerVersion() /** * {@inheritDoc} */ - public function prepare($sql) + public function prepare(string $sql) : DriverStatement { return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId); } @@ -82,7 +84,7 @@ public function prepare($sql) /** * {@inheritDoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $stmt = $this->prepare($sql); $stmt->execute(); @@ -109,7 +111,7 @@ public function quote($value, $type = ParameterType::STRING) /** * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = sqlsrv_query($this->conn, $statement); diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index 7438eaada62..2229e442b54 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -416,7 +416,7 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { if ($this->stmt === null) { return 0; diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index 3c778eeb74c..fd3c0bd0bf6 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -100,5 +100,5 @@ public function execute($params = null); * * @return int The number of rows. */ - public function rowCount(); + public function rowCount() : int; } diff --git a/lib/Doctrine/DBAL/Portability/Connection.php b/lib/Doctrine/DBAL/Portability/Connection.php index e2f660cef0c..f152b82dc94 100644 --- a/lib/Doctrine/DBAL/Portability/Connection.php +++ b/lib/Doctrine/DBAL/Portability/Connection.php @@ -5,6 +5,8 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\ColumnCase; use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use PDO; use const CASE_LOWER; use const CASE_UPPER; @@ -93,7 +95,7 @@ public function getFetchCase() /** * {@inheritdoc} */ - public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement { $stmt = new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); $stmt->setFetchMode($this->defaultFetchMode); @@ -104,9 +106,9 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach /** * {@inheritdoc} */ - public function prepare($statement) + public function prepare(string $sql) : DriverStatement { - $stmt = new Statement(parent::prepare($statement), $this); + $stmt = new Statement(parent::prepare($sql), $this); $stmt->setFetchMode($this->defaultFetchMode); return $stmt; @@ -115,7 +117,7 @@ public function prepare($statement) /** * {@inheritdoc} */ - public function query(string $sql) + public function query(string $sql) : ResultStatement { $connection = $this->getWrappedConnection(); diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index 51deeb5aff1..38173c286d4 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -233,7 +233,7 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { assert($this->stmt instanceof DriverStatement); diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index a27fbe48a6d..fd8db886b8b 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -250,7 +250,7 @@ public function fetchColumn($columnIndex = 0) * * @return int The number of affected rows. */ - public function rowCount() + public function rowCount() : int { return $this->stmt->rowCount(); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/StatementTest.php index 2d52b5c0cd3..6f315716fa4 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/StatementTest.php @@ -27,7 +27,7 @@ protected function setUp() : void public function testFailureToPrepareResultsInException() { // use the driver connection directly to avoid having exception wrapped - $stmt = $this->connection->getWrappedConnection()->prepare(null); + $stmt = $this->connection->getWrappedConnection()->prepare(''); // it's impossible to prepare the statement without bound variables for SQL Server, // so the preparation happens before the first execution when variables are already in place diff --git a/tests/Doctrine/Tests/DBAL/StatementTest.php b/tests/Doctrine/Tests/DBAL/StatementTest.php index 1dae44d253d..81e6314eae5 100644 --- a/tests/Doctrine/Tests/DBAL/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/StatementTest.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Statement; @@ -23,18 +24,15 @@ class StatementTest extends DbalTestCase private $configuration; /** @var PDOStatement */ - private $pdoStatement; + private $driverStatement; protected function setUp() : void { - $this->pdoStatement = $this->getMockBuilder(PDOStatement::class) - ->setMethods(['execute', 'bindParam', 'bindValue']) - ->getMock(); + $this->driverStatement = $this->createMock(DriverStatement::class); - $driverConnection = $this->createMock(DriverConnection::class); - $driverConnection->expects($this->any()) - ->method('prepare') - ->will($this->returnValue($this->pdoStatement)); + $driverConnection = $this->createConfiguredMock(DriverConnection::class, [ + 'prepare' => $this->driverStatement, + ]); $driver = $this->createMock(Driver::class); @@ -140,7 +138,7 @@ public function testExecuteCallsLoggerStopQueryOnException() $logger->expects($this->once()) ->method('stopQuery'); - $this->pdoStatement->expects($this->once()) + $this->driverStatement->expects($this->once()) ->method('execute') ->will($this->throwException(new Exception('Mock test exception'))); diff --git a/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php b/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php deleted file mode 100644 index 06131bd234b..00000000000 --- a/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php +++ /dev/null @@ -1,49 +0,0 @@ - Date: Sat, 28 Apr 2018 16:24:26 +0200 Subject: [PATCH 38/66] Added string mapping in SqlitePlatform - used by make bundle - fix 'Unknown database type string requested, Doctrine\DBAL\Platforms\SqlitePlatform may not support it.' error --- lib/Doctrine/DBAL/Platforms/SqlitePlatform.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 30bf99a970e..c3460157211 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -637,6 +637,7 @@ protected function initializeDoctrineTypeMappings() 'real' => 'float', 'serial' => 'integer', 'smallint' => 'smallint', + 'string' => 'string', 'text' => 'text', 'time' => 'time', 'timestamp' => 'datetime', From 1eb9aaf2d8026ec6e816a11c2a7aae76dde491fc Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 11 Apr 2018 20:27:31 -0700 Subject: [PATCH 39/66] [DBAL-3079] Updated upgrade documentation --- UPGRADE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index d527d0b1160..2d09afe097c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -61,7 +61,8 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec ## BC BREAK: the PDO symbols are no longer part of the DBAL API 1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. -2. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. +2. `\Doctrine\DBAL\Driver\PDOConnection` does not extend `\PDO` anymore. Please use `\Doctrine\DBAL\Driver\PDOConnection::getWrappedConnection()` to access the underlying `PDO` object. +3. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. Before: From 6cec5504be2f4f54d10ac4ef898010674e4a0c04 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 20 Apr 2018 16:12:48 +0200 Subject: [PATCH 40/66] Revert complex type specification in Connection --- lib/Doctrine/DBAL/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 182624380aa..ea4878125d4 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -1449,7 +1449,7 @@ public function convertToPHPValue($value, $type) * * @param DriverStatement $stmt The statement to bind the values to. * @param mixed[] $params The map/list of named/positional parameters. - * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). + * @param int[]|string[] $types The parameter types. */ private function _bindTypedValues(DriverStatement $stmt, array $params, array $types) : void { From f3fc96fdb7af5e21ab302d2f56fa011de132355f Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 6 Jun 2018 14:38:36 -0700 Subject: [PATCH 41/66] Removed the logic of using BLOB columns for BINARY type of fields --- UPGRADE.md | 6 +++ .../DBAL/Platforms/AbstractPlatform.php | 16 -------- lib/Doctrine/DBAL/Types/BinaryType.php | 15 ++------ .../DBAL/Functional/Types/BinaryTest.php | 13 +------ .../AbstractMySQLPlatformTestCase.php | 32 +++++++--------- .../Platforms/AbstractPlatformTestCase.php | 5 --- .../AbstractSQLServerPlatformTestCase.php | 20 ++++------ .../Tests/DBAL/Platforms/DB2PlatformTest.php | 10 ----- .../DBAL/Platforms/OraclePlatformTest.php | 20 ++++------ .../Platforms/SQLAnywherePlatformTest.php | 20 ++++------ .../Doctrine/Tests/DBAL/Types/BinaryTest.php | 19 +++++++--- tests/Doctrine/Tests/DBAL/Types/BlobTest.php | 37 ------------------- 12 files changed, 63 insertions(+), 150 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 2d09afe097c..702f0b08aba 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -102,6 +102,12 @@ The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL - `Configuration::getSQLLogger()` does not return `null` anymore, but a `NullLogger` implementation. - `Configuration::setSQLLogger()` does not allow `null` anymore. +## BC BREAK: Changes to handling binary fields + +- Binary fields whose length exceeds the maximum field size on a given platform are no longer represented as `BLOB`s. + Use binary fields of a size which fits all target platforms, or use blob explicitly instead. +- Binary fields are no longer represented as streams in PHP. They are represented as strings. + # Upgrade to 2.10 ## Deprecated `Type::*` constants diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index df56a61aa02..e8c4959e766 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -29,7 +29,6 @@ use Doctrine\DBAL\Types\Type; use InvalidArgumentException; use UnexpectedValueException; -use const E_USER_DEPRECATED; use function addcslashes; use function array_map; use function array_merge; @@ -55,7 +54,6 @@ use function strpos; use function strtolower; use function strtoupper; -use function trigger_error; /** * Base class for all DatabasePlatforms. The DatabasePlatforms are the central @@ -283,20 +281,6 @@ public function getBinaryTypeDeclarationSQL(array $field) $fixed = $field['fixed'] ?? false; - $maxLength = $this->getBinaryMaxLength(); - - if ($field['length'] > $maxLength) { - if ($maxLength > 0) { - @trigger_error(sprintf( - 'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.', - $field['length'], - $maxLength - ), E_USER_DEPRECATED); - } - - return $this->getBlobTypeDeclarationSQL($field); - } - return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed); } diff --git a/lib/Doctrine/DBAL/Types/BinaryType.php b/lib/Doctrine/DBAL/Types/BinaryType.php index d604b3bff69..8aefd610401 100644 --- a/lib/Doctrine/DBAL/Types/BinaryType.php +++ b/lib/Doctrine/DBAL/Types/BinaryType.php @@ -4,12 +4,9 @@ use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Platforms\AbstractPlatform; -use function assert; -use function fopen; -use function fseek; -use function fwrite; use function is_resource; use function is_string; +use function stream_get_contents; /** * Type that maps ab SQL BINARY/VARBINARY to a PHP resource stream. @@ -33,15 +30,11 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return null; } - if (is_string($value)) { - $fp = fopen('php://temp', 'rb+'); - assert(is_resource($fp)); - fwrite($fp, $value); - fseek($fp, 0); - $value = $fp; + if (is_resource($value)) { + $value = stream_get_contents($value); } - if (! is_resource($value)) { + if (! is_string($value)) { throw ConversionException::conversionFailed($value, Types::BINARY); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php b/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php index d212b969997..44e4f557e84 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php @@ -8,11 +8,10 @@ use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalFunctionalTestCase; -use function is_resource; use function random_bytes; use function str_replace; -use function stream_get_contents; class BinaryTest extends DbalFunctionalTestCase { @@ -79,14 +78,6 @@ private function select(string $id) [ParameterType::BINARY] ); - // Currently, `BinaryType` mistakenly converts string values fetched from the DB to a stream. - // It should be the opposite. Streams should be used to represent large objects, not binary - // strings. The confusion comes from the PostgreSQL's type system where binary strings and - // large objects are represented by the same BYTEA type - if (is_resource($value)) { - $value = stream_get_contents($value); - } - - return $value; + return Type::getType('binary')->convertToPHPValue($value, $this->connection->getDatabasePlatform()); } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractMySQLPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractMySQLPlatformTestCase.php index ea6a6ffe59e..d309a83c8d4 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractMySQLPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractMySQLPlatformTestCase.php @@ -512,27 +512,21 @@ public function testReturnsBinaryTypeDeclarationSQL() self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('VARBINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65535])); + self::assertSame('VARBINARY(65536)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65536])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65535])); - } - - /** - * @group legacy - * @expectedDeprecation Binary field length 65536 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - * @expectedDeprecation Binary field length 16777215 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - * @expectedDeprecation Binary field length 16777216 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65536])); - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777215])); - self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777216])); - - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65536])); - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777215])); - self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777216])); + self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 0, + ])); + self::assertSame('BINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 65535, + ])); + self::assertSame('BINARY(65536)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 65536, + ])); } public function testDoesNotPropagateForeignKeyCreationForNonSupportingEngines() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php index 3b66ff41e0e..44acd8127cf 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php @@ -847,11 +847,6 @@ public function testReturnsBinaryTypeDeclarationSQL() $this->platform->getBinaryTypeDeclarationSQL([]); } - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - $this->markTestSkipped('Not applicable to the platform'); - } - /** * @group DBAL-553 */ diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index 52dd5753443..f06834913eb 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -984,18 +984,14 @@ public function testReturnsBinaryTypeDeclarationSQL() self::assertSame('VARBINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8000])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8000])); - } - - /** - * @group legacy - * @expectedDeprecation Binary field length 8001 is greater than supported by the platform (8000). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8001])); - self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8001])); + self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 0, + ])); + self::assertSame('BINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 8000, + ])); } /** diff --git a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php index f1260b2d5c1..6ca66c7dcc1 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php @@ -416,16 +416,6 @@ public function testReturnsBinaryTypeDeclarationSQL() self::assertSame('CHAR(254) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); } - /** - * @group legacy - * @expectedDeprecation Binary field length 32705 is greater than supported by the platform (32704). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32705])); - self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32705])); - } - /** * @group DBAL-234 */ diff --git a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php index 439c413d1a0..79a84945399 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php @@ -479,18 +479,14 @@ public function testReturnsBinaryTypeDeclarationSQL() self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2000])); self::assertSame('RAW(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2000])); - } - - /** - * @group legacy - * @expectedDeprecation Binary field length 2001 is greater than supported by the platform (2000). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2001])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2001])); + self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 0, + ])); + self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 2000, + ])); } public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index 8189f0d5856..c4c4d5cd2d7 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -934,18 +934,14 @@ public function testReturnsBinaryTypeDeclarationSQL() self::assertSame('VARBINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32767])); self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32767])); - } - - /** - * @group legacy - * @expectedDeprecation Binary field length 32768 is greater than supported by the platform (32767). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() - { - self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32768])); - self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32768])); + self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 0, + ])); + self::assertSame('BINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 32767, + ])); } /** diff --git a/tests/Doctrine/Tests/DBAL/Types/BinaryTest.php b/tests/Doctrine/Tests/DBAL/Types/BinaryTest.php index 4eed8f7e4fd..acee3ec673f 100644 --- a/tests/Doctrine/Tests/DBAL/Types/BinaryTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/BinaryTest.php @@ -10,9 +10,11 @@ use Doctrine\DBAL\Types\Types; use Doctrine\Tests\DbalTestCase; use PHPUnit\Framework\MockObject\MockObject; +use function array_map; use function base64_encode; use function fopen; -use function stream_get_contents; +use function implode; +use function range; class BinaryTest extends DbalTestCase { @@ -57,11 +59,10 @@ public function testBinaryNullConvertsToPHPValue() public function testBinaryStringConvertsToPHPValue() { - $databaseValue = 'binary string'; + $databaseValue = $this->getBinaryString(); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - self::assertIsResource($phpValue); - self::assertEquals($databaseValue, stream_get_contents($phpValue)); + self::assertSame($databaseValue, $phpValue); } public function testBinaryResourceConvertsToPHPValue() @@ -69,7 +70,15 @@ public function testBinaryResourceConvertsToPHPValue() $databaseValue = fopen('data://text/plain;base64,' . base64_encode('binary string'), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - self::assertSame($databaseValue, $phpValue); + self::assertSame('binary string', $phpValue); + } + + /** + * Creates a binary string containing all possible byte values. + */ + private function getBinaryString() : string + { + return implode(array_map('chr', range(0, 255))); } /** diff --git a/tests/Doctrine/Tests/DBAL/Types/BlobTest.php b/tests/Doctrine/Tests/DBAL/Types/BlobTest.php index 70bbcf55967..69a29c6b1db 100644 --- a/tests/Doctrine/Tests/DBAL/Types/BlobTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/BlobTest.php @@ -7,10 +7,6 @@ use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalTestCase; use PHPUnit\Framework\MockObject\MockObject; -use function base64_encode; -use function chr; -use function fopen; -use function stream_get_contents; class BlobTest extends DbalTestCase { @@ -33,37 +29,4 @@ public function testBlobNullConvertsToPHPValue() { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } - - public function testBinaryStringConvertsToPHPValue() - { - $databaseValue = $this->getBinaryString(); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertIsResource($phpValue); - self::assertSame($databaseValue, stream_get_contents($phpValue)); - } - - public function testBinaryResourceConvertsToPHPValue() - { - $databaseValue = fopen('data://text/plain;base64,' . base64_encode($this->getBinaryString()), 'r'); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertSame($databaseValue, $phpValue); - } - - /** - * Creates a binary string containing all possible byte values. - * - * @return string - */ - private function getBinaryString() - { - $string = ''; - - for ($i = 0; $i < 256; $i++) { - $string .= chr($i); - } - - return $string; - } } From 5f704b6e11abd196e3c9473083d3c08d8049cc8d Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 10 Jul 2018 23:27:01 -0700 Subject: [PATCH 42/66] Removed support for DB-generated UUIDs --- UPGRADE.md | 5 ++ .../DBAL/Platforms/AbstractPlatform.php | 14 ----- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 10 ---- .../DBAL/Platforms/OraclePlatform.php | 10 ---- .../DBAL/Platforms/PostgreSqlPlatform.php | 10 ---- .../DBAL/Platforms/SQLAnywherePlatform.php | 10 ---- .../DBAL/Platforms/SQLServerPlatform.php | 10 ---- .../DBAL/Platforms/SqlitePlatform.php | 13 ----- .../DBAL/Functional/Ticket/DBAL421Test.php | 56 ------------------- .../Platforms/SQLAnywherePlatformTest.php | 1 - 10 files changed, 5 insertions(+), 134 deletions(-) delete mode 100644 tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php diff --git a/UPGRADE.md b/UPGRADE.md index 702f0b08aba..da26040268c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,10 @@ # Upgrade to 3.0 +## BC BREAK: Removed support for DB-generated UUIDs + +The support for DB-generated UUIDs was removed as non-portable. +Please generate UUIDs on the application side (e.g. using [ramsey/uuid](https://packagist.org/packages/ramsey/uuid)). + ## BC BREAK: Removed MsSQLKeywords class The `Doctrine\DBAL\Platforms\MsSQLKeywords` has been removed. diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index e8c4959e766..4c941a975c1 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -622,20 +622,6 @@ public function getRegexpExpression() throw DBALException::notSupported(__METHOD__); } - /** - * Returns the global unique identifier expression. - * - * @deprecated Use application-generated UUIDs instead - * - * @return string - * - * @throws DBALException If not supported on this platform. - */ - public function getGuidExpression() - { - throw DBALException::notSupported(__METHOD__); - } - /** * Returns the SQL snippet to get the average value of a column. * diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 86081b1d5ef..a3cc8b730a2 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -78,16 +78,6 @@ public function getRegexpExpression() return 'RLIKE'; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'UUID()'; - } - /** * {@inheritDoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 811e9cff164..aa79848afa1 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -84,16 +84,6 @@ public function getLocateExpression($str, $substr, $startPos = false) return 'INSTR(' . $str . ', ' . $substr . ', ' . $startPos . ')'; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'SYS_GUID()'; - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index fe868aadbd2..f5603c5928d 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -1021,16 +1021,6 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) return 'TIME(0) WITHOUT TIME ZONE'; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'UUID_GENERATE_V4()'; - } - /** * {@inheritDoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 14cea4cd516..c0abd1ef4ec 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -667,16 +667,6 @@ public function getForUpdateSQL() return ''; } - /** - * {@inheritdoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'NEWID()'; - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index f8d3985930e..ec900a21a5e 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1008,16 +1008,6 @@ public function getDropViewSQL($name) return 'DROP VIEW ' . $name; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'NEWID()'; - } - /** * {@inheritDoc} */ diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index c3460157211..68c3b72d447 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -40,19 +40,6 @@ public function getRegexpExpression() return 'REGEXP'; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return "HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-4' || " - . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || " - . "SUBSTR('89AB', 1 + (ABS(RANDOM()) % 4), 1) || " - . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))"; - } - /** * {@inheritDoc} */ diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php deleted file mode 100644 index 6b77db02f0a..00000000000 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php +++ /dev/null @@ -1,56 +0,0 @@ -connection->getDatabasePlatform()->getName(); - if (in_array($platform, ['mysql', 'sqlite'])) { - return; - } - - $this->markTestSkipped('Currently restricted to MySQL and SQLite.'); - } - - public function testGuidShouldMatchPattern() - { - $guid = $this->connection->query($this->getSelectGuidSql())->fetchColumn(); - $pattern = '/[0-9A-F]{8}\-[0-9A-F]{4}\-[0-9A-F]{4}\-[8-9A-B][0-9A-F]{3}\-[0-9A-F]{12}/i'; - self::assertEquals(1, preg_match($pattern, $guid), 'GUID does not match pattern'); - } - - /** - * This test does (of course) not proof that all generated GUIDs are - * random, it should however provide some basic confidence. - */ - public function testGuidShouldBeRandom() - { - $statement = $this->connection->prepare($this->getSelectGuidSql()); - $guids = []; - - for ($i = 0; $i < 99; $i++) { - $statement->execute(); - $guid = $statement->fetchColumn(); - self::assertNotContains($guid, $guids, 'Duplicate GUID detected'); - $guids[] = $guid; - } - - $statement->closeCursor(); - } - - private function getSelectGuidSql() - { - return 'SELECT ' . $this->connection->getDatabasePlatform()->getGuidExpression(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index c4c4d5cd2d7..8122a64302c 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -635,7 +635,6 @@ public function testGeneratesSQLSnippets() self::assertEquals('Y-m-d H:i:s.u', $this->platform->getDateTimeFormatString()); self::assertEquals('H:i:s.u', $this->platform->getTimeFormatString()); self::assertEquals('', $this->platform->getForUpdateSQL()); - self::assertEquals('NEWID()', $this->platform->getGuidExpression()); self::assertEquals('LOCATE(string_column, substring_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); self::assertEquals("HASH(column, 'MD5')", $this->platform->getMd5Expression('column')); From defd944bb1904b39d42bc658222701b5e1edbffb Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 2 Aug 2018 23:24:39 -0700 Subject: [PATCH 43/66] Fixed and suppressed issues found by PHPStan on develop --- phpstan.neon.dist | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7aca228c393..e532fa5b918 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -29,7 +29,7 @@ parameters: - '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~' # http://php.net/manual/en/pdo.sqlitecreatefunction.php - - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOConnection::sqliteCreateFunction\(\)\.\z~' + - '~^Call to an undefined method PDO::sqliteCreateFunction\(\)\.\z~' # https://github.com/JetBrains/phpstorm-stubs/pull/488 - '~^Parameter #1 \$byteCount of function SQLSRV_SQLTYPE_VARBINARY expects int, string given\.\z~' @@ -59,3 +59,9 @@ parameters: # weird class name, doesn't exist in stubs either - '~unknown class OCI-(Lob|Collection)~' + + # https://github.com/doctrine/dbal/issues/3236 + - '~^Call to an undefined method Doctrine\\DBAL\\Schema\\UniqueConstraint::getLocalColumns\(\)~' + + # https://github.com/doctrine/dbal/issues/3237 + - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOStatement::nextRowset\(\)~' From db1f1567d150d0aefd873f0affa6e458ed371ff2 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 7 Aug 2018 09:13:23 -0700 Subject: [PATCH 44/66] Removed dbal:import CLI command --- UPGRADE.md | 9 ++ .../Tools/Console/Command/ImportCommand.php | 138 ------------------ .../DBAL/Tools/Console/ConsoleRunner.php | 2 - 3 files changed, 9 insertions(+), 140 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php diff --git a/UPGRADE.md b/UPGRADE.md index da26040268c..4c28a777902 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,14 @@ # Upgrade to 3.0 +## 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. +Please use other database client applications for import, e.g.: + + * For MySQL and MariaDB: `mysql [dbname] < data.sql`. + * For PostgreSQL: `psql [dbname] < data.sql`. + * For SQLite: `sqlite3 /path/to/file.db < data.sql`. + ## BC BREAK: Removed support for DB-generated UUIDs The support for DB-generated UUIDs was removed as non-portable. diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php deleted file mode 100644 index a45a60c6085..00000000000 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php +++ /dev/null @@ -1,138 +0,0 @@ -setName('dbal:import') - ->setDescription('Import SQL file(s) directly to Database.') - ->setDefinition([new InputArgument( - 'file', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'File path(s) of SQL to be executed.' - ), - ]) - ->setHelp(<<getHelper('db')->getConnection(); - - $fileNames = $input->getArgument('file'); - - if ($fileNames === null) { - return null; - } - - foreach ((array) $fileNames as $fileName) { - $filePath = realpath($fileName); - - // Phar compatibility. - if ($filePath === false) { - $filePath = $fileName; - } - - if (! file_exists($filePath)) { - throw new InvalidArgumentException( - sprintf("SQL file '%s' does not exist.", $filePath) - ); - } - - if (! is_readable($filePath)) { - throw new InvalidArgumentException( - sprintf("SQL file '%s' does not have read permissions.", $filePath) - ); - } - - $output->write(sprintf("Processing file '%s'... ", $filePath)); - $sql = @file_get_contents($filePath); - - if ($sql === false) { - throw new RuntimeException( - sprintf("Unable to read SQL file '%s': %s", $filePath, error_get_last()['message']) - ); - } - - if ($conn instanceof PDOConnection) { - // PDO Drivers - try { - $lines = 0; - - $stmt = $conn->prepare($sql); - assert($stmt instanceof PDOStatement); - - $stmt->execute(); - - do { - // Required due to "MySQL has gone away!" issue - $stmt->fetch(); - $stmt->closeCursor(); - - $lines++; - } while ($stmt->nextRowset()); - - $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); - } catch (PDOException $e) { - $output->write('error!' . PHP_EOL); - - throw new RuntimeException($e->getMessage(), $e->getCode(), $e); - } - } else { - // Non-PDO Drivers (ie. OCI8 driver) - $stmt = $conn->prepare($sql); - $rs = $stmt->execute(); - - if (! $rs) { - $error = $stmt->errorInfo(); - - $output->write('error!' . PHP_EOL); - - throw new RuntimeException($error[2], $error[0]); - } - - $output->writeln('OK!' . PHP_EOL); - - $stmt->closeCursor(); - } - } - - return null; - } -} diff --git a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php index 94a87cb63c1..0df6f086f2c 100644 --- a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php +++ b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL\Tools\Console; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Tools\Console\Command\ImportCommand; use Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand; use Doctrine\DBAL\Tools\Console\Command\RunSqlCommand; use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; @@ -56,7 +55,6 @@ public static function addCommands(Application $cli) { $cli->addCommands([ new RunSqlCommand(), - new ImportCommand(), new ReservedWordsCommand(), ]); } From f7ad1fe763136d12260eb55bdca4942e7455838a Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 10 Aug 2018 20:55:34 -0700 Subject: [PATCH 45/66] Made the OFFSET in LIMIT queries non-nullable --- UPGRADE.md | 4 +++ .../DBAL/Platforms/AbstractPlatform.php | 26 +++---------------- lib/Doctrine/DBAL/Platforms/DB2Platform.php | 2 +- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 2 +- .../DBAL/Platforms/OraclePlatform.php | 2 +- .../DBAL/Platforms/SQLAnywherePlatform.php | 2 +- .../DBAL/Platforms/SQLServer2012Platform.php | 11 +++----- .../DBAL/Platforms/SQLServerPlatform.php | 2 +- .../DBAL/Platforms/SqlitePlatform.php | 4 +-- .../Tests/DBAL/Platforms/DB2PlatformTest.php | 2 +- .../DBAL/Platforms/SQLServerPlatformTest.php | 4 +-- 11 files changed, 22 insertions(+), 39 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 4c28a777902..9afa07e2fbf 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK: The `NULL` value of `$offset` in LIMIT queries is not allowed + +The `NULL` value of the `$offset` argument in `AbstractPlatform::(do)?ModifyLimitQuery()` methods is no longer allowed. The absence of the offset should be indicated with a `0` which is now the default value. + ## 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/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 4c941a975c1..05bd3ed68da 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -3356,22 +3356,10 @@ public function getTimeFormatString() /** * Adds an driver-specific LIMIT clause to the query. * - * @param string $query - * @param int|null $limit - * @param int|null $offset - * - * @return string - * * @throws DBALException */ - final public function modifyLimitQuery($query, $limit, $offset = null) + final public function modifyLimitQuery(string $query, ?int $limit, int $offset = 0) : string { - if ($limit !== null) { - $limit = (int) $limit; - } - - $offset = (int) $offset; - if ($offset < 0) { throw new DBALException(sprintf( 'Offset must be a positive integer or zero, %d given', @@ -3391,21 +3379,15 @@ final public function modifyLimitQuery($query, $limit, $offset = null) /** * Adds an platform-specific LIMIT clause to the query. - * - * @param string $query - * @param int|null $limit - * @param int|null $offset - * - * @return string */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit !== null) { - $query .= ' LIMIT ' . $limit; + $query .= sprintf(' LIMIT %d', $limit); } if ($offset > 0) { - $query .= ' OFFSET ' . $offset; + $query .= sprintf(' OFFSET %d', $offset); } return $query; diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index 1ecc4d4d791..53643124f26 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -789,7 +789,7 @@ public function getTemporaryTableName($tableName) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $where = []; diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index a3cc8b730a2..6c5fb2e92dd 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -46,7 +46,7 @@ class MySqlPlatform extends AbstractPlatform /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit !== null) { $query .= ' LIMIT ' . $limit; diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index aa79848afa1..0af86dc8829 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -979,7 +979,7 @@ public function getName() /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset <= 0) { return $query; diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index c0abd1ef4ec..f3a2bf3c185 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1354,7 +1354,7 @@ protected function _getTransactionIsolationLevelSQL($level) /** * {@inheritdoc} */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $limitOffsetClause = $this->getTopClauseSQL($limit, $offset); diff --git a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php index 1262e2be3e5..afc6a32b060 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php @@ -6,6 +6,7 @@ use const PREG_OFFSET_CAPTURE; use function preg_match; use function preg_match_all; +use function sprintf; use function substr_count; /** @@ -92,7 +93,7 @@ protected function getReservedKeywordsClass() /** * {@inheritdoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset <= 0) { return $query; @@ -125,17 +126,13 @@ protected function doModifyLimitQuery($query, $limit, $offset = null) } } - 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'; + $query .= sprintf(' OFFSET %d ROWS', $offset); if ($limit !== null) { - $query .= ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; + $query .= sprintf(' FETCH NEXT %d ROWS ONLY', $limit); } return $query; diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index ec900a21a5e..5b8f8c07e1d 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1243,7 +1243,7 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $where = []; diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 68c3b72d447..023c14963dc 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -694,10 +694,10 @@ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset > 0) { - return $query . ' LIMIT -1 OFFSET ' . $offset; + $limit = -1; } return parent::doModifyLimitQuery($query, $limit, $offset); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php index 6ca66c7dcc1..a9d61a7d6a1 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php @@ -343,7 +343,7 @@ public function testModifiesLimitQuery() { self::assertEquals( 'SELECT * FROM user', - $this->platform->modifyLimitQuery('SELECT * FROM user', null, null) + $this->platform->modifyLimitQuery('SELECT * FROM user', null, 0) ); self::assertEquals( diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php index d86485866d0..f2f72719eff 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php @@ -53,7 +53,7 @@ public function getModifyLimitQueries() [ '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, + 0, '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', ], @@ -61,7 +61,7 @@ public function getModifyLimitQueries() [ '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, + 0, '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', ], ]; From 0756867387485aa47400069f04cc9a0b87c353b8 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 17 Aug 2018 22:30:20 +0200 Subject: [PATCH 46/66] Remove Doctrine\DBAL\Types\Type::__toString() --- UPGRADE.md | 4 ++++ lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php | 2 +- lib/Doctrine/DBAL/Types/Type.php | 20 ------------------- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 9afa07e2fbf..30fabdec8b0 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK: `Doctrine\DBAL\Types\Type::__toString()` removed + +Relying on string representation was discouraged and has been removed. + ## BC BREAK: The `NULL` value of `$offset` in LIMIT queries is not allowed The `NULL` value of the `$offset` argument in `AbstractPlatform::(do)?ModifyLimitQuery()` methods is no longer allowed. The absence of the offset should be indicated with a `0` which is now the default value. diff --git a/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php b/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php index d5e94cf6ea3..06e8413c8a4 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php @@ -79,7 +79,7 @@ private function createTableLabel(Table $table) $label .= ''; $label .= ''; $label .= '' . $columnLabel . ''; - $label .= '' . strtolower($column->getType()) . ''; + $label .= '' . strtolower($column->getType()->getName()) . ''; $label .= ''; $primaryKey = $table->getPrimaryKey(); diff --git a/lib/Doctrine/DBAL/Types/Type.php b/lib/Doctrine/DBAL/Types/Type.php index ac7ab7bec13..6ebed0ed476 100644 --- a/lib/Doctrine/DBAL/Types/Type.php +++ b/lib/Doctrine/DBAL/Types/Type.php @@ -7,9 +7,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use function array_map; use function get_class; -use function str_replace; -use function strrpos; -use function substr; /** * The base class for so-called Doctrine mapping types. @@ -302,23 +299,6 @@ static function (Type $type) : string { ); } - /** - * @deprecated Relying on string representation is discouraged and will be removed in DBAL 3.0. - * - * @return string - */ - public function __toString() - { - $type = static::class; - $position = strrpos($type, '\\'); - - if ($position !== false) { - $type = substr($type, $position); - } - - return str_replace('Type', '', $type); - } - /** * Does working with this column require SQL conversion functions? * From aa30617051f782f6978d4f03868b5a78fa523eab Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 17 Aug 2018 22:05:37 +0200 Subject: [PATCH 47/66] Remove Doctrine\DBAL\Types\Type::getDefaultLength() --- UPGRADE.md | 4 ++++ lib/Doctrine/DBAL/Types/StringType.php | 8 -------- lib/Doctrine/DBAL/Types/Type.php | 12 ------------ tests/Doctrine/Tests/DBAL/Types/StringTest.php | 9 --------- 4 files changed, 4 insertions(+), 29 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 30fabdec8b0..16915743ad0 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK: `Doctrine\DBAL\Types\Type::getDefaultLength()` removed + +The `Doctrine\DBAL\Types\Type::getDefaultLength()` method has been removed as it served no purpose. + ## BC BREAK: `Doctrine\DBAL\Types\Type::__toString()` removed Relying on string representation was discouraged and has been removed. diff --git a/lib/Doctrine/DBAL/Types/StringType.php b/lib/Doctrine/DBAL/Types/StringType.php index e0d1a552f5d..8a4d7e28a39 100644 --- a/lib/Doctrine/DBAL/Types/StringType.php +++ b/lib/Doctrine/DBAL/Types/StringType.php @@ -17,14 +17,6 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration); } - /** - * {@inheritdoc} - */ - public function getDefaultLength(AbstractPlatform $platform) - { - return $platform->getVarcharDefaultLength(); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Types/Type.php b/lib/Doctrine/DBAL/Types/Type.php index 6ebed0ed476..f9e1bfbe595 100644 --- a/lib/Doctrine/DBAL/Types/Type.php +++ b/lib/Doctrine/DBAL/Types/Type.php @@ -159,18 +159,6 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return $value; } - /** - * Gets the default length of this type. - * - * @deprecated Rely on information provided by the platform instead. - * - * @return int|null - */ - public function getDefaultLength(AbstractPlatform $platform) - { - return null; - } - /** * Gets the SQL declaration snippet for a field of this type. * diff --git a/tests/Doctrine/Tests/DBAL/Types/StringTest.php b/tests/Doctrine/Tests/DBAL/Types/StringTest.php index 4ffb9af7d96..2c725686d1c 100644 --- a/tests/Doctrine/Tests/DBAL/Types/StringTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/StringTest.php @@ -31,15 +31,6 @@ public function testReturnsSqlDeclarationFromPlatformVarchar() self::assertEquals('TEST_VARCHAR', $this->type->getSqlDeclaration([], $this->platform)); } - public function testReturnsDefaultLengthFromPlatformVarchar() - { - $this->platform->expects($this->once()) - ->method('getVarcharDefaultLength') - ->willReturn(255); - - self::assertEquals(255, $this->type->getDefaultLength($this->platform)); - } - public function testConvertToPHPValue() { self::assertIsString($this->type->convertToPHPValue('foo', $this->platform)); From 8d24216352fedad150501cb33391efb371a6c96f Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 5 Oct 2018 20:00:49 -0700 Subject: [PATCH 48/66] Got rid of func_num_args in AbstractPlatform::getDummySelectSQL() --- lib/Doctrine/DBAL/Platforms/AbstractPlatform.php | 8 +------- lib/Doctrine/DBAL/Platforms/DB2Platform.php | 6 +----- lib/Doctrine/DBAL/Platforms/OraclePlatform.php | 6 +----- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 05bd3ed68da..ede1f5cd91c 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -37,9 +37,7 @@ use function assert; use function count; use function explode; -use function func_get_arg; use function func_get_args; -use function func_num_args; use function implode; use function in_array; use function is_array; @@ -3471,13 +3469,9 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * This is for test reasons, many vendors have special requirements for dummy statements. - * - * @return string */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s', $expression); } diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index 53643124f26..0555b8754d3 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -13,8 +13,6 @@ use function count; use function current; use function explode; -use function func_get_arg; -use function func_num_args; use function implode; use function sprintf; use function strpos; @@ -874,10 +872,8 @@ public function getForUpdateSQL() /** * {@inheritDoc} */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s FROM sysibm.sysdummy1', $expression); } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 0af86dc8829..f621f454f6c 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -15,8 +15,6 @@ use function array_merge; use function count; use function explode; -use function func_get_arg; -use function func_num_args; use function implode; use function preg_match; use function sprintf; @@ -1110,10 +1108,8 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * {@inheritDoc} */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s FROM DUAL', $expression); } From 8dc0b8d81c36416b302f2f25c1c69f72445554db Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 30 Nov 2018 16:42:07 -0800 Subject: [PATCH 49/66] Handle binding errors in OCI8Statement::execute() and MySQLiStatement::execute() --- UPGRADE.md | 4 ++ .../DBAL/Driver/Mysqli/MysqliStatement.php | 16 ++++---- .../DBAL/Driver/OCI8/OCI8Statement.php | 8 +++- .../DBAL/Driver/OCI8/OCI8StatementTest.php | 27 +++++-------- .../Tests/DBAL/Functional/StatementTest.php | 38 +++++++++++++++++++ 5 files changed, 64 insertions(+), 29 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 16915743ad0..44268a342dc 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement::execute()` with redundant parameters. + +Similarly to the drivers based on `pdo_pgsql` and `pdo_sqlsrv`, `OCI8Statement::execute()` and `MySQLiStatement::execute()` do not longer ignore redundant parameters. + ## BC BREAK: `Doctrine\DBAL\Types\Type::getDefaultLength()` removed The `Doctrine\DBAL\Types\Type::getDefaultLength()` method has been removed as it served no purpose. diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index eff8f88c569..36a474fd488 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -48,7 +48,7 @@ class MysqliStatement implements IteratorAggregate, Statement protected $_rowBindedValues = []; /** @var mixed[] */ - protected $_bindedValues; + protected $_bindedValues = []; /** @var string */ protected $types; @@ -136,14 +136,12 @@ public function bindValue($param, $value, $type = ParameterType::STRING) */ public function execute($params = null) { - if ($this->_bindedValues !== null) { - if ($params !== null) { - if (! $this->bindUntypedValues($params)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->errno); - } - } else { - $this->bindTypedParameters(); + if ($params !== null && count($params) > 0) { + if (! $this->bindUntypedValues($params)) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); } + } else { + $this->bindTypedParameters(); } if (! $this->_stmt->execute()) { @@ -232,7 +230,7 @@ private function bindTypedParameters() $values[$parameter] = $value; } - if (! $this->_stmt->bind_param($types, ...$values)) { + if (count($values) > 0 && ! $this->_stmt->bind_param($types, ...$values)) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index 8730009f731..c1191bea4cf 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -376,9 +376,13 @@ public function execute($params = null) foreach ($params as $key => $val) { if ($hasZeroIndex && is_int($key)) { - $this->bindValue($key + 1, $val); + $param = $key + 1; } else { - $this->bindValue($key, $val); + $param = $key; + } + + if (! $this->bindValue($param, $val)) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); } } } diff --git a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php index 86d57105cbb..ec2e69a8f6d 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php @@ -40,24 +40,15 @@ public function testExecute(array $params) ->disableOriginalConstructor() ->getMock(); - $statement->expects($this->at(0)) - ->method('bindValue') - ->with( - $this->equalTo(1), - $this->equalTo($params[0]) - ); - $statement->expects($this->at(1)) - ->method('bindValue') - ->with( - $this->equalTo(2), - $this->equalTo($params[1]) - ); - $statement->expects($this->at(2)) - ->method('bindValue') - ->with( - $this->equalTo(3), - $this->equalTo($params[2]) - ); + foreach ($params as $index => $value) { + $statement->expects($this->at($index)) + ->method('bindValue') + ->with( + $this->equalTo($index + 1), + $this->equalTo($value) + ) + ->willReturn(true); + } // can't pass to constructor since we don't have a real database handle, // but execute must check the connection for the executeMode diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php index 66b4a93a207..ad7f71018f9 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php @@ -2,6 +2,7 @@ namespace Doctrine\Tests\DBAL\Functional; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\FetchMode; @@ -10,6 +11,7 @@ use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalFunctionalTestCase; use function base64_decode; +use function sprintf; use function stream_get_contents; class StatementTest extends DbalFunctionalTestCase @@ -311,4 +313,40 @@ public function testFetchInColumnMode() : void self::assertEquals(1, $result); } + + public function testExecWithRedundantParameters() : void + { + $driver = $this->connection->getDriver()->getName(); + + switch ($driver) { + case 'pdo_mysql': + case 'pdo_oracle': + case 'pdo_sqlsrv': + self::markTestSkipped(sprintf( + 'PDOStatement::execute() implemented in the "%s" driver does not report redundant parameters', + $driver + )); + + return; + case 'ibm_db2': + self::markTestSkipped('db2_execute() does not report redundant parameters'); + + return; + case 'sqlsrv': + self::markTestSkipped('sqlsrv_prepare() does not report redundant parameters'); + + return; + } + + $platform = $this->connection->getDatabasePlatform(); + $query = $platform->getDummySelectSQL(); + $stmt = $this->connection->prepare($query); + + // we want to make sure the exception is thrown by the DBAL code, not by PHPUnit due to a PHP-level error, + // but the wrapper connection wraps everything in a DBAL exception + $this->iniSet('error_reporting', 0); + + self::expectException(DBALException::class); + $stmt->execute([null]); + } } From 90011dfd04f97efe83fa729df1cfe06a992ec0c9 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 30 Nov 2018 22:45:20 -0800 Subject: [PATCH 50/66] Statement::fetchColumn() will throw an exception in the case of invalid index --- UPGRADE.md | 4 +++ lib/Doctrine/DBAL/Cache/ArrayStatement.php | 13 ++++++-- .../DBAL/Cache/ResultCacheStatement.php | 14 +++++++-- lib/Doctrine/DBAL/DBALException.php | 10 ++++++ .../DBAL/Driver/IBMDB2/DB2Statement.php | 8 ++++- .../DBAL/Driver/Mysqli/MysqliStatement.php | 8 ++++- .../DBAL/Driver/OCI8/OCI8Statement.php | 7 ++++- lib/Doctrine/DBAL/Driver/PDOStatement.php | 13 +++++++- .../SQLAnywhere/SQLAnywhereStatement.php | 5 ++- .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 7 ++++- phpstan.neon.dist | 5 +++ .../Tests/DBAL/Functional/StatementTest.php | 31 +++++++++++++++++++ 12 files changed, 115 insertions(+), 10 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 44268a342dc..78b095207b8 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## MINOR BC BREAK `Statement::fetchColumn()` with an invalid index. + +Similarly to `PDOStatement::fetchColumn()`, DBAL statements throw an exception in case of an invalid column index. + ## BC BREAK `Statement::execute()` with redundant parameters. Similarly to the drivers based on `pdo_pgsql` and `pdo_sqlsrv`, `OCI8Statement::execute()` and `MySQLiStatement::execute()` do not longer ignore redundant parameters. diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 494876c935e..27ca4a83ccb 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -3,10 +3,12 @@ namespace Doctrine\DBAL\Cache; use ArrayIterator; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\FetchMode; use InvalidArgumentException; use IteratorAggregate; +use function array_key_exists; use function array_merge; use function array_values; use function count; @@ -130,7 +132,14 @@ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); - // TODO: verify that return false is the correct behavior - return $row[$columnIndex] ?? false; + if ($row === false) { + return false; + } + + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } } diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index bd80dadb96e..66461976f75 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -4,14 +4,17 @@ use ArrayIterator; use Doctrine\Common\Cache\Cache; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\FetchMode; use InvalidArgumentException; use IteratorAggregate; +use function array_key_exists; use function array_merge; use function array_values; use function assert; +use function count; use function reset; /** @@ -179,8 +182,15 @@ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); - // TODO: verify that return false is the correct behavior - return $row[$columnIndex] ?? false; + if ($row === false) { + return false; + } + + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** diff --git a/lib/Doctrine/DBAL/DBALException.php b/lib/Doctrine/DBAL/DBALException.php index 4961af2f35f..87a03daf595 100644 --- a/lib/Doctrine/DBAL/DBALException.php +++ b/lib/Doctrine/DBAL/DBALException.php @@ -291,4 +291,14 @@ public static function typeAlreadyRegistered(Type $type) : self sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type)) ); } + + public static function invalidColumnIndex(int $index, int $count) : self + { + return new self(sprintf( + 'Invalid column index %d. The statement result contains %d column%s.', + $index, + $count, + $count === 1 ? '' : 's' + )); + } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index d7cea000a0e..d3d0a454dad 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver\IBMDB2; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; @@ -18,6 +19,7 @@ use const DB2_PARAM_FILE; use const DB2_PARAM_IN; use function array_change_key_case; +use function array_key_exists; use function count; use function db2_bind_param; use function db2_execute; @@ -338,7 +340,11 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 36a474fd488..9be2c3f167c 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver\Mysqli; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\Exception\InvalidArgumentException; @@ -12,6 +13,7 @@ use mysqli_stmt; use function array_combine; use function array_fill; +use function array_key_exists; use function assert; use function count; use function feof; @@ -380,7 +382,11 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index c1191bea4cf..3ab77fd1f07 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver\OCI8; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; @@ -517,7 +518,11 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 8d935b55b39..e8f0a33e890 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use IteratorAggregate; @@ -193,7 +194,17 @@ public function fetchAll($fetchMode = null, ...$args) public function fetchColumn($columnIndex = 0) { try { - return $this->stmt->fetchColumn($columnIndex); + $value = $this->stmt->fetchColumn($columnIndex); + + if ($value === null) { + $columnCount = $this->columnCount(); + + if ($columnIndex < 0 || $columnIndex >= $columnCount) { + throw DBALException::invalidColumnIndex($columnIndex, $columnCount); + } + } + + return $value; } catch (\PDOException $exception) { throw new PDOException($exception); } diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index b67b67de8a1..03139989be0 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; @@ -284,7 +285,9 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index 2229e442b54..56763ac7dcb 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver\SQLSrv; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; @@ -410,7 +411,11 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw DBALException::invalidColumnIndex($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e532fa5b918..428af1038d4 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -65,3 +65,8 @@ parameters: # https://github.com/doctrine/dbal/issues/3237 - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOStatement::nextRowset\(\)~' + + # https://github.com/phpstan/phpstan/pull/1886 + - + message: '~^Strict comparison using === between string|false and null will always evaluate to false\.~' + path: %currentWorkingDirectory%/lib/Doctrine/DBAL/Driver/PDOStatement.php diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php index ad7f71018f9..0a455bd1313 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\DBAL\Functional; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\FetchMode; @@ -349,4 +350,34 @@ public function testExecWithRedundantParameters() : void self::expectException(DBALException::class); $stmt->execute([null]); } + + /** + * @throws DBALException + * + * @dataProvider nonExistingIndexProvider + */ + public function testFetchColumnNonExistingIndex(int $index) : void + { + if ($this->connection->getWrappedConnection() instanceof PDOConnection) { + $this->markTestSkipped('PDO supports this behavior natively but throws a different exception'); + } + + $platform = $this->connection->getDatabasePlatform(); + $query = $platform->getDummySelectSQL(); + $stmt = $this->connection->query($query); + + self::expectException(DBALException::class); + $stmt->fetchColumn($index); + } + + /** + * @return mixed[][] + */ + public static function nonExistingIndexProvider() : iterable + { + return [ + [1], + [-1], + ]; + } } From 9fe284d578a34c0e0e197d2b02ba0c21aa0b91bd Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 12 Mar 2019 23:41:28 -0700 Subject: [PATCH 51/66] Transaction-related Statement methods return void --- UPGRADE.md | 4 ++ lib/Doctrine/DBAL/Connection.php | 51 ++++++++++++------- .../Connections/MasterSlaveConnection.php | 12 ++--- lib/Doctrine/DBAL/Driver/Connection.php | 12 ++--- .../DBAL/Driver/IBMDB2/DB2Connection.php | 20 +++++--- .../DBAL/Driver/IBMDB2/DB2Exception.php | 4 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 18 ++++--- .../DBAL/Driver/OCI8/OCI8Connection.php | 14 ++--- lib/Doctrine/DBAL/Driver/PDOConnection.php | 12 ++--- .../SQLAnywhere/SQLAnywhereConnection.php | 18 ++----- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 6 +-- 11 files changed, 92 insertions(+), 79 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 78b095207b8..b094e9af5af 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK Transaction-related `Statement` methods return `void`. + +`Statement::beginTransaction()`, `::commit()` and `::rollBack()` no longer return a boolean value. They will throw a `DriverException` in case of failure. + ## MINOR BC BREAK `Statement::fetchColumn()` with an invalid index. Similarly to `PDOStatement::fetchColumn()`, DBAL statements throw an exception in case of an invalid column index. diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index ea4878125d4..f89407d2a78 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -9,6 +9,7 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Cache\ResultCacheStatement; use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\PingableConnection; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; @@ -1179,7 +1180,7 @@ protected function _getNestedTransactionSavePointName() /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { $connection = $this->getWrappedConnection(); @@ -1189,15 +1190,17 @@ public function beginTransaction() if ($this->transactionNestingLevel === 1) { $logger->startQuery('"START TRANSACTION"'); - $connection->beginTransaction(); - $logger->stopQuery(); + + try { + $connection->beginTransaction(); + } finally { + $logger->stopQuery(); + } } elseif ($this->nestTransactionsWithSavepoints) { $logger->startQuery('"SAVEPOINT"'); $this->createSavepoint($this->_getNestedTransactionSavePointName()); $logger->stopQuery(); } - - return true; } /** @@ -1206,11 +1209,12 @@ public function beginTransaction() * @throws ConnectionException If the commit failed due to no active transaction or * because the transaction was marked for rollback only. */ - public function commit() + public function commit() : void { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); } + if ($this->isRollbackOnly) { throw ConnectionException::commitFailedRollbackOnly(); } @@ -1221,8 +1225,12 @@ public function commit() if ($this->transactionNestingLevel === 1) { $logger->startQuery('"COMMIT"'); - $connection->commit(); - $logger->stopQuery(); + + try { + $connection->commit(); + } finally { + $logger->stopQuery(); + } } elseif ($this->nestTransactionsWithSavepoints) { $logger->startQuery('"RELEASE SAVEPOINT"'); $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); @@ -1232,18 +1240,19 @@ public function commit() --$this->transactionNestingLevel; if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) { - return true; + return; } $this->beginTransaction(); - - return true; } /** * Commits all current nesting transactions. + * + * @throws ConnectionException + * @throws DriverException */ - private function commitAll() + private function commitAll() : void { while ($this->transactionNestingLevel !== 0) { if ($this->autoCommit === false && $this->transactionNestingLevel === 1) { @@ -1259,11 +1268,11 @@ private function commitAll() } /** - * Cancels any database changes done during the current transaction. + * {@inheritDoc} * * @throws ConnectionException If the rollback operation failed. */ - public function rollBack() + public function rollBack() : void { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); @@ -1276,12 +1285,16 @@ public function rollBack() if ($this->transactionNestingLevel === 1) { $logger->startQuery('"ROLLBACK"'); $this->transactionNestingLevel = 0; - $connection->rollBack(); - $this->isRollbackOnly = false; - $logger->stopQuery(); - if ($this->autoCommit === false) { - $this->beginTransaction(); + try { + $connection->rollBack(); + } finally { + $this->isRollbackOnly = false; + $logger->stopQuery(); + + if ($this->autoCommit === false) { + $this->beginTransaction(); + } } } elseif ($this->nestTransactionsWithSavepoints) { $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index fe94636f443..66a895d81f3 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -230,31 +230,31 @@ public function executeUpdate(string $query, array $params = [], array $types = /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->connect('master'); - return parent::beginTransaction(); + parent::beginTransaction(); } /** * {@inheritDoc} */ - public function commit() + public function commit() : void { $this->connect('master'); - return parent::commit(); + parent::commit(); } /** * {@inheritDoc} */ - public function rollBack() + public function rollBack() : void { $this->connect('master'); - return parent::rollBack(); + parent::rollBack(); } /** diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 2632483e931..a8981548821 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -54,23 +54,23 @@ public function lastInsertId($name = null); /** * Initiates a transaction. * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function beginTransaction(); + public function beginTransaction() : void; /** * Commits a transaction. * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function commit(); + public function commit() : void; /** * Rolls back the current transaction, as initiated by beginTransaction(). * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function rollBack(); + public function rollBack() : void; /** * Returns the error code associated with the last operation on the database handle. diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index 20ecd7fc86a..3d48d60b718 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -137,31 +137,39 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { - db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF); + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF)) { + throw new DB2Exception(db2_conn_errormsg($this->conn)); + } } /** * {@inheritdoc} */ - public function commit() + public function commit() : void { if (! db2_commit($this->conn)) { throw new DB2Exception(db2_conn_errormsg($this->conn)); } - db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); + + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { + throw new DB2Exception(db2_conn_errormsg($this->conn)); + } } /** * {@inheritdoc} */ - public function rollBack() + public function rollBack() : void { if (! db2_rollback($this->conn)) { throw new DB2Exception(db2_conn_errormsg($this->conn)); } - db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); + + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { + throw new DB2Exception(db2_conn_errormsg($this->conn)); + } } /** diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php index b01c4552a23..cb8e626fcdb 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php @@ -2,8 +2,8 @@ namespace Doctrine\DBAL\Driver\IBMDB2; -use Exception; +use Doctrine\DBAL\Driver\AbstractDriverException; -class DB2Exception extends Exception +class DB2Exception extends AbstractDriverException { } diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 80a23087591..0a199649454 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -174,27 +174,29 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->conn->query('START TRANSACTION'); - - return true; } /** * {@inheritdoc} */ - public function commit() + public function commit() : void { - return $this->conn->commit(); + if (! $this->conn->commit()) { + throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + } } /** - * {@inheritdoc}non-PHPdoc) + * {@inheritdoc} */ - public function rollBack() + public function rollBack() : void { - return $this->conn->rollback(); + if (! $this->conn->rollback()) { + throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + } } /** diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index ce651559eb5..861facbb03c 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -177,37 +177,33 @@ public function getExecuteMode() /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->executeMode = OCI_NO_AUTO_COMMIT; - - return true; } /** * {@inheritdoc} */ - public function commit() + public function commit() : void { if (! oci_commit($this->dbh)) { throw OCI8Exception::fromErrorInfo($this->errorInfo()); } - $this->executeMode = OCI_COMMIT_ON_SUCCESS; - return true; + $this->executeMode = OCI_COMMIT_ON_SUCCESS; } /** * {@inheritdoc} */ - public function rollBack() + public function rollBack() : void { if (! oci_rollback($this->dbh)) { throw OCI8Exception::fromErrorInfo($this->errorInfo()); } - $this->executeMode = OCI_COMMIT_ON_SUCCESS; - return true; + $this->executeMode = OCI_COMMIT_ON_SUCCESS; } /** diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 995ebee6adb..171f85118d0 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -126,25 +126,25 @@ protected function createStatement(\PDOStatement $stmt) : PDOStatement /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { - return $this->connection->beginTransaction(); + $this->connection->beginTransaction(); } /** * {@inheritDoc} */ - public function commit() + public function commit() : void { - return $this->connection->commit(); + $this->connection->commit(); } /** * {@inheritDoc} */ - public function rollBack() + public function rollBack() : void { - return $this->connection->rollBack(); + $this->connection->rollBack(); } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index 6c117904c58..5d6361069ac 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -64,13 +64,11 @@ public function __construct($dsn, $persistent = false) * * @throws SQLAnywhereException */ - public function beginTransaction() + public function beginTransaction() : void { if (! sasql_set_option($this->connection, 'auto_commit', 'off')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } - - return true; } /** @@ -78,15 +76,13 @@ public function beginTransaction() * * @throws SQLAnywhereException */ - public function commit() + public function commit() : void { if (! sasql_commit($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); - - return true; } /** @@ -185,30 +181,24 @@ public function requiresQueryForServerVersion() * * @throws SQLAnywhereException */ - public function rollBack() + public function rollBack() : void { if (! sasql_rollback($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); - - return true; } /** * Ends transactional mode and enables auto commit again. * - * @return bool Whether or not ending transactional mode succeeded. - * * @throws SQLAnywhereException */ - private function endTransaction() + private function endTransaction() : void { if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } - - return true; } } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index caa04efce5f..ff6ef9b9bd8 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -146,7 +146,7 @@ public function lastInsertId($name = null) /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { if (! sqlsrv_begin_transaction($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); @@ -156,7 +156,7 @@ public function beginTransaction() /** * {@inheritDoc} */ - public function commit() + public function commit() : void { if (! sqlsrv_commit($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); @@ -166,7 +166,7 @@ public function commit() /** * {@inheritDoc} */ - public function rollBack() + public function rollBack() : void { if (! sqlsrv_rollback($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); From b7d18b5da91209114a28c6f6807874a37f82f947 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 13 Mar 2019 00:15:47 -0700 Subject: [PATCH 52/66] Connection::setAutoCommit() will return void --- lib/Doctrine/DBAL/Connection.php | 7 +++---- tests/Doctrine/Tests/DBAL/ConnectionTest.php | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index f89407d2a78..5c7f310db97 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -494,12 +494,11 @@ public function isAutoCommit() * * @see isAutoCommit * - * @param bool $autoCommit True to enable auto-commit mode; false to disable it. + * @throws ConnectionException + * @throws DriverException */ - public function setAutoCommit($autoCommit) + public function setAutoCommit(bool $autoCommit) : void { - $autoCommit = (bool) $autoCommit; - // Mode not changed, no-op. if ($autoCommit === $this->autoCommit) { return; diff --git a/tests/Doctrine/Tests/DBAL/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/ConnectionTest.php index c036bd89885..c47e9fc1ce9 100644 --- a/tests/Doctrine/Tests/DBAL/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/ConnectionTest.php @@ -249,8 +249,6 @@ public function testSetAutoCommit() { $this->connection->setAutoCommit(false); self::assertFalse($this->connection->isAutoCommit()); - $this->connection->setAutoCommit(0); - self::assertFalse($this->connection->isAutoCommit()); } /** From bc9a8d2026233c91c0933928cdd3636fb0f1c4f4 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 24 Jan 2019 10:46:28 -0800 Subject: [PATCH 53/66] Moved rowCount() from Statement to ResultStatement --- UPGRADE.md | 8 ++++++-- lib/Doctrine/DBAL/Cache/ArrayStatement.php | 12 ++++++++++++ lib/Doctrine/DBAL/Cache/ResultCacheStatement.php | 4 ---- lib/Doctrine/DBAL/Driver/ResultStatement.php | 11 +++++++++++ lib/Doctrine/DBAL/Driver/Statement.php | 13 ------------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index b094e9af5af..e0fab7083cb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement::rowCount()` is moved. + +`Statement::rowCount()` has been moved to the `ResultStatement` interface where it belongs by definition. + ## BC BREAK Transaction-related `Statement` methods return `void`. `Statement::beginTransaction()`, `::commit()` and `::rollBack()` no longer return a boolean value. They will throw a `DriverException` in case of failure. @@ -61,7 +65,7 @@ The following classes have been removed: * `Doctrine\DBAL\Platforms\SQLAnywhere11Platform` * `Doctrine\DBAL\Platforms\SQLAnywhere12Platform` - * `Doctrine\DBAL\Platforms\SQLAnywhere16Platform` + * `Doctrine\DBAL\Platforms\SQLAnywhere16Platform` * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords` * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords` * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords` @@ -228,7 +232,7 @@ This method now throws SPL ``UnexpectedValueException`` instead of accidentally ## Doctrine\DBAL\Connection::TRANSACTION_* constants deprecated -``Doctrine\DBAL\Connection::TRANSACTION_*`` were moved into ``Doctrine\DBAL\TransactionIsolationLevel`` class without the ``TRANSACTION_`` prefix. +``Doctrine\DBAL\Connection::TRANSACTION_*`` were moved into ``Doctrine\DBAL\TransactionIsolationLevel`` class without the ``TRANSACTION_`` prefix. ## DEPRECATION: direct usage of the PDO APIs in the DBAL API diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 27ca4a83ccb..18d660be1ca 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -57,6 +57,18 @@ public function columnCount() return $this->columnCount; } + /** + * {@inheritdoc} + */ + public function rowCount() : int + { + if ($this->data === null) { + return 0; + } + + return count($this->data); + } + /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index 66461976f75..c0b28bb8740 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -6,14 +6,12 @@ use Doctrine\Common\Cache\Cache; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ResultStatement; -use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\FetchMode; use InvalidArgumentException; use IteratorAggregate; use function array_key_exists; use function array_merge; use function array_values; -use function assert; use function count; use function reset; @@ -206,8 +204,6 @@ public function fetchColumn($columnIndex = 0) */ public function rowCount() : int { - assert($this->statement instanceof Statement); - return $this->statement->rowCount(); } } diff --git a/lib/Doctrine/DBAL/Driver/ResultStatement.php b/lib/Doctrine/DBAL/Driver/ResultStatement.php index 17bc28e37ef..321778e1c60 100644 --- a/lib/Doctrine/DBAL/Driver/ResultStatement.php +++ b/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -25,6 +25,17 @@ public function closeCursor(); */ public function columnCount(); + /** + * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + */ + public function rowCount() : int; + /** * Sets the fetch mode to use while iterating this statement. * diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index fd3c0bd0bf6..c5f2e3e2546 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -88,17 +88,4 @@ public function errorInfo(); * @return bool TRUE on success or FALSE on failure. */ public function execute($params = null); - - /** - * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement - * executed by the corresponding object. - * - * If the last SQL statement executed by the associated Statement object was a SELECT statement, - * some databases may return the number of rows returned by that statement. However, - * this behaviour is not guaranteed for all databases and should not be - * relied on for portable applications. - * - * @return int The number of rows. - */ - public function rowCount() : int; } From a801466575caa0b203974c5f4260a92cb2d1dbed Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 14 Mar 2019 23:16:56 -0700 Subject: [PATCH 54/66] Converted Connection and Statement methods which returned false in case of a failure into void --- UPGRADE.md | 4 ++ lib/Doctrine/DBAL/Cache/ArrayStatement.php | 6 +- .../DBAL/Cache/ResultCacheStatement.php | 11 ++-- lib/Doctrine/DBAL/Connection.php | 19 +++--- .../Connections/MasterSlaveConnection.php | 14 ++-- .../DBAL/Driver/IBMDB2/DB2Statement.php | 30 ++++----- .../DBAL/Driver/Mysqli/MysqliStatement.php | 23 +++---- .../DBAL/Driver/OCI8/OCI8Statement.php | 30 ++++----- .../DBAL/Driver/PDOSqlsrv/Statement.php | 8 +-- lib/Doctrine/DBAL/Driver/PDOStatement.php | 26 +++----- lib/Doctrine/DBAL/Driver/ResultStatement.php | 8 +-- .../SQLAnywhere/SQLAnywhereStatement.php | 30 +++------ .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 20 +++--- lib/Doctrine/DBAL/Driver/Statement.php | 12 ++-- lib/Doctrine/DBAL/Portability/Connection.php | 64 ++++++++++--------- lib/Doctrine/DBAL/Portability/Statement.php | 20 +++--- .../DBAL/Sharding/PoolingShardConnection.php | 18 +++--- lib/Doctrine/DBAL/Statement.php | 62 ++++++++---------- .../Tests/DBAL/Functional/ConnectionTest.php | 4 +- .../Tests/DBAL/Functional/StatementTest.php | 17 ++++- .../Tests/DBAL/Portability/StatementTest.php | 22 +++---- 21 files changed, 205 insertions(+), 243 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index e0fab7083cb..d17cc2da8de 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement` and `Connection` methods return `void`. + +`Connection::connect()`, `Statement::bindParam()`, `::bindValue()`, `::execute()`, `ResultStatement::setFetchMode()` and `::closeCursor()` no longer return a boolean value. They will throw an exception in case of failure. + ## BC BREAK `Statement::rowCount()` is moved. `Statement::rowCount()` has been moved to the `ResultStatement` interface where it belongs by definition. diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 18d660be1ca..ef9bf7bff25 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -44,7 +44,7 @@ public function __construct(array $data) /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { unset($this->data); } @@ -72,15 +72,13 @@ public function rowCount() : int /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { if (count($args) > 0) { throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); } $this->defaultFetchMode = $fetchMode; - - return true; } /** diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index c0b28bb8740..527c730a2fb 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -75,11 +75,12 @@ public function __construct(ResultStatement $stmt, Cache $resultCache, $cacheKey /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { $this->statement->closeCursor(); + if (! $this->emptied || $this->data === null) { - return true; + return; } $data = $this->resultCache->fetch($this->cacheKey); @@ -90,8 +91,6 @@ public function closeCursor() $this->resultCache->save($this->cacheKey, $data, $this->lifetime); unset($this->data); - - return true; } /** @@ -105,11 +104,9 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; - - return true; } /** diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 5c7f310db97..f258ef50cd4 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -339,13 +339,12 @@ public function getExpressionBuilder() /** * Establishes the connection with the database. * - * @return bool TRUE if the connection was successfully established, FALSE if - * the connection is already open. + * @throws DriverException */ - public function connect() + public function connect() : void { if ($this->isConnected) { - return false; + return; } $driverOptions = $this->params['driverOptions'] ?? []; @@ -359,12 +358,12 @@ public function connect() $this->beginTransaction(); } - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new Event\ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new Event\ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** @@ -518,10 +517,8 @@ public function setAutoCommit(bool $autoCommit) : void * Sets the fetch mode. * * @param int $fetchMode - * - * @return void */ - public function setFetchMode($fetchMode) + public function setFetchMode($fetchMode) : void { $this->defaultFetchMode = $fetchMode; } diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index 66a895d81f3..6ef3d034438 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -123,7 +123,7 @@ public function isConnectedToMaster() /** * {@inheritDoc} */ - public function connect($connectionName = null) + public function connect($connectionName = null) : void { $requestedConnectionChange = ($connectionName !== null); $connectionName = $connectionName ?: 'slave'; @@ -136,7 +136,7 @@ public function connect($connectionName = null) // change request, then abort right here, because we are already done. // This prevents writes to the slave in case of "keepSlave" option enabled. if ($this->_conn !== null && ! $requestedConnectionChange) { - return false; + return; } $forceMasterAsSlave = false; @@ -153,7 +153,7 @@ public function connect($connectionName = null) $this->connections['slave'] = $this->_conn; } - return false; + return; } if ($connectionName === 'master') { @@ -167,12 +167,12 @@ public function connect($connectionName = null) $this->connections['slave'] = $this->_conn = $this->connectTo($connectionName); } - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index d3d0a454dad..d829c7c79ee 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -89,15 +89,15 @@ public function __construct($stmt) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { switch ($type) { case ParameterType::INTEGER: @@ -122,8 +122,6 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $this->bind($column, $variable, DB2_PARAM_IN, DB2_CHAR); break; } - - return true; } /** @@ -144,17 +142,17 @@ private function bind($position, &$variable, int $parameterType, int $dataType) /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { $this->bindParam = []; - if (! db2_free_result($this->stmt)) { - return false; + if (! $this->result) { + return; } - $this->result = false; + db2_free_result($this->stmt); - return true; + $this->result = false; } /** @@ -187,7 +185,7 @@ public function errorInfo() /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { if ($params === null) { ksort($this->bindParam); @@ -222,14 +220,12 @@ public function execute($params = null) } $this->result = true; - - return $retval; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; @@ -237,11 +233,11 @@ public function setFetchMode($fetchMode, ...$args) $this->defaultFetchClass = $args[0]; } - if (isset($args[1])) { - $this->defaultFetchClassCtorArgs = (array) $args[2]; + if (! isset($args[1])) { + return; } - return true; + $this->defaultFetchClassCtorArgs = (array) $args[2]; } /** diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 9be2c3f167c..2faed0afb3c 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -3,6 +3,7 @@ namespace Doctrine\DBAL\Driver\Mysqli; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\Exception\InvalidArgumentException; @@ -101,7 +102,7 @@ public function __construct(mysqli $conn, $prepareString) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { assert(is_int($column)); @@ -111,14 +112,12 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $this->_bindedValues[$column] =& $variable; $this->types[$column - 1] = self::$_paramTypeMap[$type]; - - return true; } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { assert(is_int($param)); @@ -129,14 +128,12 @@ public function bindValue($param, $value, $type = ParameterType::STRING) $this->_values[$param] = $value; $this->_bindedValues[$param] =& $this->_values[$param]; $this->types[$param - 1] = self::$_paramTypeMap[$type]; - - return true; } /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { if ($params !== null && count($params) > 0) { if (! $this->bindUntypedValues($params)) { @@ -199,12 +196,12 @@ public function execute($params = null) } $this->result = true; - - return true; } /** * Binds parameters with known types previously bound to the statement + * + * @throws DriverException */ private function bindTypedParameters() { @@ -408,12 +405,10 @@ public function errorInfo() /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { $this->_stmt->free_result(); $this->result = false; - - return true; } /** @@ -439,11 +434,9 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->_defaultFetchMode = $fetchMode; - - return true; } /** diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index 3ab77fd1f07..57f14afeb12 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -264,15 +264,15 @@ private static function findToken($statement, &$offset, $regex) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type, null); + $this->bindParam($param, $value, $type, null); } /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { $column = $this->_paramMap[$column]; @@ -289,13 +289,15 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $this->boundValues[$column] =& $variable; - return oci_bind_by_name( + if (! oci_bind_by_name( $this->_sth, $column, $variable, $length ?? -1, $this->convertParameterType($type) - ); + )) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } } /** @@ -318,18 +320,16 @@ private function convertParameterType(int $type) : int /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { // not having the result means there's nothing to close if (! $this->result) { - return true; + return; } oci_cancel($this->_sth); $this->result = false; - - return true; } /** @@ -370,7 +370,7 @@ public function errorInfo() /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { if ($params) { $hasZeroIndex = array_key_exists(0, $params); @@ -382,9 +382,7 @@ public function execute($params = null) $param = $key; } - if (! $this->bindValue($param, $val)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); - } + $this->bindValue($param, $val); } } @@ -394,18 +392,14 @@ public function execute($params = null) } $this->result = true; - - return $ret; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->_defaultFetchMode = $fetchMode; - - return true; } /** diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php index 6803bb14ed7..2844a682697 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php @@ -14,7 +14,7 @@ class Statement extends PDOStatement /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) : void { if (($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY) && $driverOptions === null @@ -22,14 +22,14 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $driverOptions = PDO::SQLSRV_ENCODING_BINARY; } - return parent::bindParam($column, $variable, $type, $length, $driverOptions); + parent::bindParam($column, $variable, $type, $length, $driverOptions); } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } } diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index e8f0a33e890..c89507d0e79 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -50,12 +50,12 @@ public function __construct(\PDOStatement $stmt) /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $fetchMode = $this->convertFetchMode($fetchMode); try { - return $this->stmt->setFetchMode($fetchMode, ...$args); + $this->stmt->setFetchMode($fetchMode, ...$args); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -64,12 +64,12 @@ public function setFetchMode($fetchMode, ...$args) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { $type = $this->convertParamType($type); try { - return $this->stmt->bindValue($param, $value, $type); + $this->stmt->bindValue($param, $value, $type); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -78,12 +78,12 @@ public function bindValue($param, $value, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) : void { $type = $this->convertParamType($type); try { - return $this->stmt->bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); + $this->stmt->bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -92,15 +92,9 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { - try { - return $this->stmt->closeCursor(); - } catch (\PDOException $exception) { - // Exceptions not allowed by the interface. - // In case driver implementations do not adhere to the interface, silence exceptions here. - return true; - } + $this->stmt->closeCursor(); } /** @@ -130,10 +124,10 @@ public function errorInfo() /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { try { - return $this->stmt->execute($params); + $this->stmt->execute($params); } catch (\PDOException $exception) { throw new PDOException($exception); } diff --git a/lib/Doctrine/DBAL/Driver/ResultStatement.php b/lib/Doctrine/DBAL/Driver/ResultStatement.php index 321778e1c60..02422c50177 100644 --- a/lib/Doctrine/DBAL/Driver/ResultStatement.php +++ b/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -11,10 +11,8 @@ interface ResultStatement extends Traversable { /** * Closes the cursor, enabling the statement to be executed again. - * - * @return bool TRUE on success or FALSE on failure. */ - public function closeCursor(); + public function closeCursor() : void; /** * Returns the number of columns in the result set @@ -42,10 +40,8 @@ public function rowCount() : int; * @param int $fetchMode Controls how the next row will be returned to the caller. * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants. * @param mixed ...$args Optional mode-specific arguments (see {@link self::fetchAll()}). - * - * @return bool */ - public function setFetchMode($fetchMode, ...$args); + public function setFetchMode($fetchMode, ...$args) : void; /** * Returns the next row of a result set. diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index 03139989be0..8b02b9456bb 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -89,7 +89,7 @@ public function __construct($conn, $sql) * * @throws SQLAnywhereException */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { switch ($type) { case ParameterType::INTEGER: @@ -116,30 +116,22 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) { throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); } - - return true; } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } /** * {@inheritdoc} - * - * @throws SQLAnywhereException */ - public function closeCursor() + public function closeCursor() : void { - if (! sasql_stmt_reset($this->stmt)) { - throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); - } - - return true; + sasql_stmt_reset($this->stmt); } /** @@ -171,7 +163,7 @@ public function errorInfo() * * @throws SQLAnywhereException */ - public function execute($params = null) + public function execute($params = null) : void { if (is_array($params)) { $hasZeroIndex = array_key_exists(0, $params); @@ -190,8 +182,6 @@ public function execute($params = null) } $this->result = sasql_stmt_result_metadata($this->stmt); - - return true; } /** @@ -309,7 +299,7 @@ public function rowCount() : int /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; @@ -317,11 +307,11 @@ public function setFetchMode($fetchMode, ...$args) $this->defaultFetchClass = $args[0]; } - if (isset($args[1])) { - $this->defaultFetchClassCtorArgs = (array) $args[1]; + if (! isset($args[1])) { + return; } - return true; + $this->defaultFetchClassCtorArgs = (array) $args[1]; } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index 56763ac7dcb..0cd29288d8f 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -145,7 +145,7 @@ public function __construct($conn, $sql, ?LastInsertId $lastInsertId = null) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { if (! is_numeric($param)) { throw new SQLSrvException( @@ -160,7 +160,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { if (! is_numeric($column)) { throw new SQLSrvException('sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.'); @@ -176,11 +176,11 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { // not having the result means there's nothing to close if ($this->stmt === null || ! $this->result) { - return true; + return; } // emulate it by fetching and discarding rows, similarly to what PDO does in this case @@ -191,8 +191,6 @@ public function closeCursor() } $this->result = false; - - return true; } /** @@ -231,7 +229,7 @@ public function errorInfo() /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { if ($params) { $hasZeroIndex = array_key_exists(0, $params); @@ -310,7 +308,7 @@ private function prepare() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; @@ -318,11 +316,11 @@ public function setFetchMode($fetchMode, ...$args) $this->defaultFetchClass = $args[0]; } - if (isset($args[1])) { - $this->defaultFetchClassCtorArgs = (array) $args[1]; + if (! isset($args[1])) { + return; } - return true; + $this->defaultFetchClassCtorArgs = (array) $args[1]; } /** diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index c5f2e3e2546..dca1ecda43e 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -26,9 +26,9 @@ interface Statement extends ResultStatement * @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType} * constants. * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function bindValue($param, $value, $type = ParameterType::STRING); + public function bindValue($param, $value, $type = ParameterType::STRING) : void; /** * Binds a PHP variable to a corresponding named (not supported by mysqli driver, see comment below) or question @@ -53,9 +53,9 @@ public function bindValue($param, $value, $type = ParameterType::STRING); * @param int|null $length You must specify maxlength when using an OUT bind * so that PHP allocates enough memory to hold the returned value. * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null); + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void; /** * Fetches the SQLSTATE associated with the last operation on the statement handle. @@ -85,7 +85,7 @@ public function errorInfo(); * @param mixed[]|null $params An array of values with as many elements as there are * bound parameters in the SQL statement being executed. * - * @return bool TRUE on success or FALSE on failure. + * @throws DriverException */ - public function execute($params = null); + public function execute($params = null) : void; } diff --git a/lib/Doctrine/DBAL/Portability/Connection.php b/lib/Doctrine/DBAL/Portability/Connection.php index f152b82dc94..5194b66a611 100644 --- a/lib/Doctrine/DBAL/Portability/Connection.php +++ b/lib/Doctrine/DBAL/Portability/Connection.php @@ -39,41 +39,45 @@ class Connection extends \Doctrine\DBAL\Connection /** * {@inheritdoc} */ - public function connect() + public function connect() : void { - $ret = parent::connect(); - if ($ret) { - $params = $this->getParams(); - if (isset($params['portability'])) { - if ($this->getDatabasePlatform()->getName() === 'oracle') { - $params['portability'] &= self::PORTABILITY_ORACLE; - } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { - $params['portability'] &= self::PORTABILITY_POSTGRESQL; - } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { - $params['portability'] &= self::PORTABILITY_SQLITE; - } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { - $params['portability'] &= self::PORTABILITY_SQLANYWHERE; - } elseif ($this->getDatabasePlatform()->getName() === 'db2') { - $params['portability'] &= self::PORTABILITY_DB2; - } elseif ($this->getDatabasePlatform()->getName() === 'mssql') { - $params['portability'] &= self::PORTABILITY_SQLSRV; - } else { - $params['portability'] &= self::PORTABILITY_OTHERVENDORS; - } - $this->portability = $params['portability']; - } + if ($this->isConnected()) { + return; + } - if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { - if ($this->_conn instanceof PDOConnection) { - // make use of c-level support for case handling - $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); - } else { - $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; - } + parent::connect(); + + $params = $this->getParams(); + + if (isset($params['portability'])) { + if ($this->getDatabasePlatform()->getName() === 'oracle') { + $params['portability'] &= self::PORTABILITY_ORACLE; + } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { + $params['portability'] &= self::PORTABILITY_POSTGRESQL; + } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { + $params['portability'] &= self::PORTABILITY_SQLITE; + } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { + $params['portability'] &= self::PORTABILITY_SQLANYWHERE; + } elseif ($this->getDatabasePlatform()->getName() === 'db2') { + $params['portability'] &= self::PORTABILITY_DB2; + } elseif ($this->getDatabasePlatform()->getName() === 'mssql') { + $params['portability'] &= self::PORTABILITY_SQLSRV; + } else { + $params['portability'] &= self::PORTABILITY_OTHERVENDORS; } + $this->portability = $params['portability']; } - return $ret; + if (! isset($params['fetch_case']) || ! ($this->portability & self::PORTABILITY_FIX_CASE)) { + return; + } + + if ($this->_conn instanceof PDOConnection) { + // make use of c-level support for case handling + $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); + } else { + $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; + } } /** diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index 38173c286d4..7e9edfeadb3 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -45,29 +45,29 @@ public function __construct($stmt, Connection $conn) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void { assert($this->stmt instanceof DriverStatement); - return $this->stmt->bindParam($column, $variable, $type, $length); + $this->stmt->bindParam($column, $variable, $type, $length); } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { assert($this->stmt instanceof DriverStatement); - return $this->stmt->bindValue($param, $value, $type); + $this->stmt->bindValue($param, $value, $type); } /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { - return $this->stmt->closeCursor(); + $this->stmt->closeCursor(); } /** @@ -101,21 +101,21 @@ public function errorInfo() /** * {@inheritdoc} */ - public function execute($params = null) + public function execute($params = null) : void { assert($this->stmt instanceof DriverStatement); - return $this->stmt->execute($params); + $this->stmt->execute($params); } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; - return $this->stmt->setFetchMode($fetchMode, ...$args); + $this->stmt->setFetchMode($fetchMode, ...$args); } /** diff --git a/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php b/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php index 8d8134127d7..649a4e256fe 100644 --- a/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php +++ b/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php @@ -166,18 +166,16 @@ public function getPassword() * * @param string|int|null $shardId * - * @return bool - * * @throws ShardingException */ - public function connect($shardId = null) + public function connect($shardId = null) : void { if ($shardId === null && $this->_conn) { - return false; + return; } if ($shardId !== null && $shardId === $this->activeShardId) { - return false; + return; } if ($this->getTransactionNestingLevel() > 0) { @@ -189,17 +187,17 @@ public function connect($shardId = null) if (isset($this->activeConnections[$activeShardId])) { $this->_conn = $this->activeConnections[$activeShardId]; - return false; + return; } $this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId); - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index fd8db886b8b..fc6608fb3d2 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL; +use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; @@ -84,27 +85,26 @@ public function __construct($sql, Connection $conn) * @param mixed $value The value of the parameter. * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance. * - * @return bool TRUE on success, FALSE on failure. + * @throws DBALException + * @throws DriverException */ - public function bindValue($name, $value, $type = ParameterType::STRING) + public function bindValue($name, $value, $type = ParameterType::STRING) : void { $this->params[$name] = $value; $this->types[$name] = $type; - if ($type !== null) { - if (is_string($type)) { - $type = Type::getType($type); - } - if ($type instanceof Type) { - $value = $type->convertToDatabaseValue($value, $this->platform); - $bindingType = $type->getBindingType(); - } else { - $bindingType = $type; - } - return $this->stmt->bindValue($name, $value, $bindingType); + if (is_string($type)) { + $type = Type::getType($type); + } + + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->platform); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type; } - return $this->stmt->bindValue($name, $value); + $this->stmt->bindValue($name, $value, $bindingType); } /** @@ -118,26 +118,22 @@ public function bindValue($name, $value, $type = ParameterType::STRING) * @param int|null $length Must be specified when using an OUT bind * so that PHP allocates enough memory to hold the returned value. * - * @return bool TRUE on success, FALSE on failure. + * @throws DriverException */ - public function bindParam($name, &$var, $type = ParameterType::STRING, $length = null) + public function bindParam($name, &$var, $type = ParameterType::STRING, $length = null) : void { $this->params[$name] = $var; $this->types[$name] = $type; - return $this->stmt->bindParam($name, $var, $type, $length); + $this->stmt->bindParam($name, $var, $type, $length); } /** - * Executes the statement with the currently bound parameters. - * - * @param mixed[]|null $params - * - * @return bool TRUE on success, FALSE on failure. + * {@inheritDoc} * * @throws DBALException */ - public function execute($params = null) + public function execute($params = null) : void { if (is_array($params)) { $this->params = $params; @@ -147,32 +143,28 @@ public function execute($params = null) $logger->startQuery($this->sql, $this->params, $this->types); try { - $stmt = $this->stmt->execute($params); + $this->stmt->execute($params); } catch (Throwable $ex) { - $logger->stopQuery(); throw DBALException::driverExceptionDuringQuery( $this->conn->getDriver(), $ex, $this->sql, $this->conn->resolveParams($this->params, $this->types) ); + } finally { + $logger->stopQuery(); } - $logger->stopQuery(); $this->params = []; $this->types = []; - - return $stmt; } /** - * Closes the cursor, freeing the database resources used by this statement. - * - * @return bool TRUE on success, FALSE on failure. + * {@inheritDoc} */ - public function closeCursor() + public function closeCursor() : void { - return $this->stmt->closeCursor(); + $this->stmt->closeCursor(); } /** @@ -206,9 +198,9 @@ public function errorInfo() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, ...$args) + public function setFetchMode($fetchMode, ...$args) : void { - return $this->stmt->setFetchMode($fetchMode, ...$args); + $this->stmt->setFetchMode($fetchMode, ...$args); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php index c8684a60498..2fd90bca44e 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php @@ -281,7 +281,9 @@ public function testConnectWithoutExplicitDatabaseName() $this->connection->getEventManager() ); - self::assertTrue($connection->connect()); + $connection->connect(); + + self::assertTrue($connection->isConnected()); $connection->close(); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php index 0a455bd1313..23119f734f0 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php @@ -239,9 +239,11 @@ public function testFetchFromNonExecutedStatement(callable $fetch, $expected) public function testCloseCursorOnNonExecutedStatement() { + $this->expectNotToPerformAssertions(); + $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); - self::assertTrue($stmt->closeCursor()); + $stmt->closeCursor(); } /** @@ -249,12 +251,23 @@ public function testCloseCursorOnNonExecutedStatement() */ public function testCloseCursorAfterCursorEnd() { + $this->expectNotToPerformAssertions(); + $stmt = $this->connection->prepare('SELECT name FROM stmt_test'); $stmt->execute(); $stmt->fetch(); - self::assertTrue($stmt->closeCursor()); + $stmt->closeCursor(); + } + + public function testCloseCursorAfterClosingCursor() + { + $this->expectNotToPerformAssertions(); + + $stmt = $this->connection->executeQuery('SELECT name FROM stmt_test'); + $stmt->closeCursor(); + $stmt->closeCursor(); } /** diff --git a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php index 74ace7cc042..622e030c245 100644 --- a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php @@ -46,10 +46,9 @@ public function testBindParam() $this->wrappedStmt->expects($this->once()) ->method('bindParam') - ->with($column, $variable, $type, $length) - ->will($this->returnValue(true)); + ->with($column, $variable, $type, $length); - self::assertTrue($this->stmt->bindParam($column, $variable, $type, $length)); + $this->stmt->bindParam($column, $variable, $type, $length); } public function testBindValue() @@ -60,19 +59,17 @@ public function testBindValue() $this->wrappedStmt->expects($this->once()) ->method('bindValue') - ->with($param, $value, $type) - ->will($this->returnValue(true)); + ->with($param, $value, $type); - self::assertTrue($this->stmt->bindValue($param, $value, $type)); + $this->stmt->bindValue($param, $value, $type); } public function testCloseCursor() { $this->wrappedStmt->expects($this->once()) - ->method('closeCursor') - ->will($this->returnValue(true)); + ->method('closeCursor'); - self::assertTrue($this->stmt->closeCursor()); + $this->stmt->closeCursor(); } public function testColumnCount() @@ -117,10 +114,9 @@ public function testExecute() $this->wrappedStmt->expects($this->once()) ->method('execute') - ->with($params) - ->will($this->returnValue(true)); + ->with($params); - self::assertTrue($this->stmt->execute($params)); + $this->stmt->execute($params); } public function testSetFetchMode() @@ -138,7 +134,7 @@ public function testSetFetchMode() $re->setAccessible(true); self::assertSame(FetchMode::MIXED, $re->getValue($this->stmt)); - self::assertTrue($this->stmt->setFetchMode($fetchMode, $arg1, $arg2)); + $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); self::assertSame($fetchMode, $re->getValue($this->stmt)); } From 2cabfeb35fa1be8bcfa87da8580cf4655c837471 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 15 Mar 2019 23:53:25 -0700 Subject: [PATCH 55/66] Connection::quote() can only quote strings --- UPGRADE.md | 4 ++++ lib/Doctrine/DBAL/Connection.php | 8 ++------ lib/Doctrine/DBAL/Driver/Connection.php | 8 +------- .../DBAL/Driver/IBMDB2/DB2Connection.php | 11 ++--------- .../DBAL/Driver/Mysqli/MysqliConnection.php | 3 +-- lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php | 12 ++---------- lib/Doctrine/DBAL/Driver/PDOConnection.php | 5 ++--- .../DBAL/Driver/PDOSqlsrv/Connection.php | 5 ++--- .../Driver/SQLAnywhere/SQLAnywhereConnection.php | 9 +-------- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 16 ++-------------- .../DBAL/Query/Expression/ExpressionBuilder.php | 11 +++-------- .../Sharding/SQLAzure/SQLAzureShardManager.php | 2 +- .../Tests/DBAL/Functional/ConnectionTest.php | 6 ++---- .../Tests/DBAL/Functional/DataAccessTest.php | 4 ++-- .../Doctrine/Tests/DBAL/Functional/WriteTest.php | 2 +- 15 files changed, 28 insertions(+), 78 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index d17cc2da8de..fba5a6c2ac3 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement::quote()` only accepts strings. + +`Statement::quote()` and `ExpressionBuilder::literal()` no longer accept arguments of an arbitrary type and and don't implement type-specific handling. Only strings can be quoted. + ## BC BREAK `Statement` and `Connection` methods return `void`. `Connection::connect()`, `Statement::bindParam()`, `::bindValue()`, `::execute()`, `ResultStatement::setFetchMode()` and `::closeCursor()` no longer return a boolean value. They will throw an exception in case of failure. diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index f258ef50cd4..fe9343b49d6 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -808,13 +808,9 @@ public function quoteIdentifier($str) /** * {@inheritDoc} */ - public function quote($input, $type = null) + public function quote(string $input) : string { - $connection = $this->getWrappedConnection(); - - [$value, $bindingType] = $this->getBindingInfo($input, $type); - - return $connection->quote($value, $bindingType); + return $this->getWrappedConnection()->quote($input); } /** diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index a8981548821..14dbb54f31f 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL\Driver; use Doctrine\DBAL\DBALException; -use Doctrine\DBAL\ParameterType; /** * Connection interface. @@ -27,13 +26,8 @@ public function query(string $sql) : ResultStatement; /** * Quotes a string for use in a query. - * - * @param mixed $input - * @param int $type - * - * @return mixed */ - public function quote($input, $type = ParameterType::STRING); + public function quote(string $input) : string; /** * Executes an SQL statement and return the number of affected rows. diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index 3d48d60b718..4f88decbd69 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ParameterType; use stdClass; use const DB2_AUTOCOMMIT_OFF; use const DB2_AUTOCOMMIT_ON; @@ -101,15 +100,9 @@ public function query(string $sql) : ResultStatement /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - $input = db2_escape_string($input); - - if ($type === ParameterType::INTEGER) { - return $input; - } - - return "'" . $input . "'"; + return "'" . db2_escape_string($input) . "'"; } /** diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 0a199649454..789b2c8b4ba 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ParameterType; use mysqli; use const MYSQLI_INIT_COMMAND; use const MYSQLI_OPT_CONNECT_TIMEOUT; @@ -146,7 +145,7 @@ public function query(string $sql) : ResultStatement /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { return "'" . $this->conn->escape_string($input) . "'"; } diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index 861facbb03c..20fb9d4b2e6 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -6,14 +6,11 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ParameterType; use UnexpectedValueException; use const OCI_COMMIT_ON_SUCCESS; use const OCI_DEFAULT; use const OCI_NO_AUTO_COMMIT; use function addcslashes; -use function is_float; -use function is_int; use function oci_commit; use function oci_connect; use function oci_error; @@ -123,14 +120,9 @@ public function query(string $sql) : ResultStatement /** * {@inheritdoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($value) || is_float($value)) { - return $value; - } - $value = str_replace("'", "''", $value); - - return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + return "'" . addcslashes(str_replace("'", "''", $input), "\000\n\r\\\032") . "'"; } /** diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 171f85118d0..d9cbb681c8c 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL\Driver; -use Doctrine\DBAL\ParameterType; use PDO; use function assert; @@ -86,9 +85,9 @@ public function query(string $sql) : ResultStatement /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - return $this->connection->quote($input, $type); + return $this->connection->quote($input); } /** diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php index 33331bd0a5a..803ab9e022f 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOStatement; -use Doctrine\DBAL\ParameterType; use function strpos; use function substr; @@ -31,9 +30,9 @@ public function lastInsertId($name = null) /** * {@inheritDoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - $val = parent::quote($value, $type); + $val = parent::quote($input); // Fix for a driver version terminating all values with null byte if (strpos($val, "\0") !== false) { diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index 5d6361069ac..1ba572dc6e0 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -6,10 +6,7 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ParameterType; use function assert; -use function is_float; -use function is_int; use function is_resource; use function is_string; use function sasql_affected_rows; @@ -159,12 +156,8 @@ public function query(string $sql) : ResultStatement /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($input) || is_float($input)) { - return $input; - } - return "'" . sasql_escape_string($this->connection, $input) . "'"; } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index ff6ef9b9bd8..7fc1fa0fccc 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ParameterType; use const SQLSRV_ERR_ERRORS; -use function is_float; -use function is_int; -use function sprintf; use function sqlsrv_begin_transaction; use function sqlsrv_commit; use function sqlsrv_configure; @@ -95,17 +91,9 @@ public function query(string $sql) : ResultStatement /** * {@inheritDoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($value)) { - return $value; - } - - if (is_float($value)) { - return sprintf('%F', $value); - } - - return "'" . str_replace("'", "''", $value) . "'"; + return "'" . str_replace("'", "''", $input) . "'"; } /** diff --git a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php index dfcc31ec709..93cbd31e95f 100644 --- a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php +++ b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php @@ -284,15 +284,10 @@ public function notIn($x, $y) } /** - * Quotes a given input parameter. - * - * @param mixed $input The parameter to be quoted. - * @param int|null $type The type of the parameter. - * - * @return string + * Creates an SQL literal expression from the string. */ - public function literal($input, $type = null) + public function literal(string $input) { - return $this->connection->quote($input, $type); + return $this->connection->quote($input); } } diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php index d8178ee07db..11bd965c158 100644 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php +++ b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php @@ -202,7 +202,7 @@ public function splitFederation($splitDistributionValue) $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' . 'SPLIT AT (' . $this->getDistributionKey() . ' = ' . - $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')'; + $this->conn->quote($splitDistributionValue) . ')'; $this->conn->exec($sql); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php index 2fd90bca44e..ad86f9c87d1 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php @@ -6,9 +6,7 @@ use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Types\Types; use Doctrine\Tests\DbalFunctionalTestCase; use Error; use Exception; @@ -252,8 +250,8 @@ public function testTransactionalReturnValue() public function testQuote() { self::assertEquals( - $this->connection->quote('foo', Types::STRING), - $this->connection->quote('foo', ParameterType::STRING) + $this->connection->quote('foo'), + $this->connection->quote('foo') ); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index 62c9bd9b405..0182fdef4a6 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -177,9 +177,9 @@ public function testPrepareWithQuoted() $paramStr = 'foo'; $stmt = $this->connection->prepare(sprintf( - 'SELECT test_int, test_string FROM %s WHERE test_int = %s AND test_string = %s', + 'SELECT test_int, test_string FROM %s WHERE test_int = %d AND test_string = %s', $this->connection->quoteIdentifier($table), - $this->connection->quote($paramInt), + $paramInt, $this->connection->quote($paramStr) )); self::assertInstanceOf(Statement::class, $stmt); diff --git a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php index 52cef4d9fc2..b253fea9e53 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php @@ -46,7 +46,7 @@ public function testExecuteUpdateFirstTypeIsNull() public function testExecuteUpdate() { - $sql = 'INSERT INTO write_table (test_int) VALUES ( ' . $this->connection->quote(1) . ')'; + $sql = 'INSERT INTO write_table (test_int) VALUES (1)'; $affected = $this->connection->executeUpdate($sql); self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!'); From c5ec536b862d31a1ca1db2ddbead6fa18d8daabb Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sat, 16 Mar 2019 10:33:49 -0700 Subject: [PATCH 56/66] Assert that the username is specified on the connection when listing DB2 tables --- lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 12 ++++++++---- .../DBAL/Schema/DB2SchemaManagerTest.php | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index 0ae7aba2cf4..7d836b78dc4 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -5,7 +5,9 @@ use Doctrine\DBAL\Types\Type; use const CASE_LOWER; use function array_change_key_case; +use function assert; use function is_resource; +use function is_string; use function strpos; use function strtolower; use function substr; @@ -22,12 +24,14 @@ class DB2SchemaManager extends AbstractSchemaManager * Apparently creator is the schema not the user who created it: * {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm} */ - public function listTableNames() + public function listTableNames() : array { - $sql = $this->_platform->getListTablesSQL(); - $sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')'; + $username = $this->_conn->getUsername(); + assert(is_string($username)); - $tables = $this->_conn->fetchAll($sql); + $sql = $this->_platform->getListTablesSQL() . ' AND CREATOR = UPPER(?)'; + + $tables = $this->_conn->fetchAll($sql, [$username]); return $this->filterAssetNames($this->_getPortableTablesList($tables)); } diff --git a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php index b3f91149b32..7d11c926750 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php @@ -25,14 +25,19 @@ final class DB2SchemaManagerTest extends TestCase protected function setUp() : void { - $eventManager = new EventManager(); - $driverMock = $this->createMock(Driver::class); - $platform = $this->createMock(DB2Platform::class); - $this->conn = $this + $eventManager = new EventManager(); + $driverMock = $this->createMock(Driver::class); + $platform = $this->createMock(DB2Platform::class); + $this->conn = $this ->getMockBuilder(Connection::class) - ->setMethods(['fetchAll', 'quote']) + ->setMethods(['fetchAll', 'getUsername']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); + + $this->conn->expects($this->any()) + ->method('getUsername') + ->willReturn('db2inst1'); + $this->manager = new DB2SchemaManager($this->conn); } @@ -102,7 +107,7 @@ public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { return in_array($assetName, $accepted); }); - $this->conn->expects($this->any())->method('quote'); + $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], @@ -130,7 +135,7 @@ public function testSettingNullExpressionWillResetCallable() $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { return in_array($assetName, $accepted); }); - $this->conn->expects($this->any())->method('quote'); + $this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], From 83e3b7ac39d9eba45a25754da1f6dd4123f8670f Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sat, 16 Mar 2019 10:40:48 -0700 Subject: [PATCH 57/66] Make the $tableName argument of _getPortableTableIndexesList() required 1. The argument is always available since the method is only called from listTableIndexes() which requires a table name. 2. The argument itself seems a workaround and only needed to bypass the fact that the SQLiteSchemaManager violates the method contract: instead of reformatting the provided data it fetches more data from the DB schema which requires a table name. This argument should be dropped completely later. --- lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php | 5 ++--- lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 2 +- lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php | 8 ++++---- lib/Doctrine/DBAL/Schema/OracleSchemaManager.php | 4 ++-- lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php | 4 ++-- lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php | 2 +- lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php | 2 +- lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php | 4 ++-- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 2bb71224e70..46fbff6da30 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -830,12 +830,11 @@ abstract protected function _getPortableTableColumnDefinition($tableColumn); /** * Aggregates and groups the index results according to the required data result. * - * @param mixed[][] $tableIndexRows - * @param string|null $tableName + * @param mixed[][] $tableIndexRows * * @return Index[] */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $result = []; foreach ($tableIndexRows as $tableIndex) { diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index 7d836b78dc4..ba6048a092b 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -121,7 +121,7 @@ protected function _getPortableTablesList($tables) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndexRow) { $tableIndexRow = array_change_key_case($tableIndexRow, CASE_LOWER); diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index fb957f247ff..b39db01ffaa 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -54,9 +54,9 @@ protected function _getPortableUserDefinition($user) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { - foreach ($tableIndexes as $k => $v) { + foreach ($tableIndexRows as $k => $v) { $v = array_change_key_case($v, CASE_LOWER); if ($v['key_name'] === 'PRIMARY') { $v['primary'] = true; @@ -70,10 +70,10 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null } $v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null; - $tableIndexes[$k] = $v; + $tableIndexRows[$k] = $v; } - return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + return parent::_getPortableTableIndexesList($tableIndexRows, $tableName); } /** diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index 0a3e76b1c51..cabc94b1867 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -89,10 +89,10 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $indexBuffer = []; - foreach ($tableIndexes as $tableIndex) { + foreach ($tableIndexRows as $tableIndex) { $tableIndex = array_change_key_case($tableIndex, CASE_LOWER); $keyName = strtolower($tableIndex['name']); diff --git a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php index 8b2ac98457e..36baa5f5521 100644 --- a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -210,10 +210,10 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $buffer = []; - foreach ($tableIndexes as $row) { + foreach ($tableIndexRows as $row) { $colNumbers = array_map('intval', explode(' ', $row['indkey'])); $columnNameSql = sprintf( 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', diff --git a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php index c169a6e0708..0d875491167 100644 --- a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php @@ -194,7 +194,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['primary'] = (bool) $tableIndex['primary']; diff --git a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php index bd6b02cb9a0..757136418bd 100644 --- a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -168,7 +168,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['non_unique'] = (bool) $tableIndex['non_unique']; diff --git a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php index e819d963f03..5e03342e482 100644 --- a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -163,7 +163,7 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $indexBuffer = []; @@ -195,7 +195,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null } // fetch regular indexes - foreach ($tableIndexes as $tableIndex) { + foreach ($tableIndexRows as $tableIndex) { // Ignore indexes with reserved names, e.g. autoindexes if (strpos($tableIndex['name'], 'sqlite_') === 0) { continue; From 319b51eac79c904a3786d7a5df9d8be0409c5a1a Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 17 Mar 2019 09:32:55 -0700 Subject: [PATCH 58/66] Changed the type of `$char` in `AbstractPlatform::getTrimExpression()` from `string|false` to `?string` --- UPGRADE.md | 4 ++ .../DBAL/Platforms/AbstractPlatform.php | 37 +++++++++++++------ .../DBAL/Platforms/SQLAnywherePlatform.php | 15 ++++++-- .../DBAL/Platforms/SQLServerPlatform.php | 25 +++++++------ .../DBAL/Platforms/SqlitePlatform.php | 25 ++++++++++--- .../Tests/DBAL/Functional/DataAccessTest.php | 23 ++++++++---- .../Platforms/SQLAnywherePlatformTest.php | 5 --- 7 files changed, 89 insertions(+), 45 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index fba5a6c2ac3..59ff7b31de2 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK The type of `$char` in `AbstractPlatform::getTrimExpression()` changed from `string|false` to `?string` + +The default value of `$char` is now `null`, not `false`. Additionally, the method will throw an `InvalidArgumentException` in an invalid value of `$mode` is passed. + ## BC BREAK `Statement::quote()` only accepts strings. `Statement::quote()` and `ExpressionBuilder::literal()` no longer accept arguments of an arbitrary type and and don't implement type-specific handling. Only strings can be quoted. diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index ede1f5cd91c..cea76b80e55 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -753,37 +753,50 @@ public function getModExpression($expression1, $expression2) * * @param string $str The expression to apply the trim to. * @param int $mode The position of the trim (leading/trailing/both). - * @param string|bool $char The char to trim, has to be quoted already. Defaults to space. + * @param string|null $char The char to trim, has to be quoted already. Defaults to space. * - * @return string + * @throws InvalidArgumentException */ - public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - $expression = ''; + $tokens = []; switch ($mode) { + case TrimMode::UNSPECIFIED: + break; + case TrimMode::LEADING: - $expression = 'LEADING '; + $tokens[] = 'LEADING'; break; case TrimMode::TRAILING: - $expression = 'TRAILING '; + $tokens[] = 'TRAILING'; break; case TrimMode::BOTH: - $expression = 'BOTH '; + $tokens[] = 'BOTH'; break; + + default: + throw new InvalidArgumentException( + sprintf( + 'The value of $mode is expected to be one of the TrimMode constants, %d given', + $mode + ) + ); } - if ($char !== false) { - $expression .= $char . ' '; + if ($char !== null) { + $tokens[] = $char; } - if ($mode || $char !== false) { - $expression .= 'FROM '; + if (count($tokens) > 0) { + $tokens[] = 'FROM'; } - return 'TRIM(' . $expression . $str . ')'; + $tokens[] = $str; + + return sprintf('TRIM(%s)', implode(' ', $tokens)); } /** diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index f3a2bf3c185..794fdf33a67 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -24,6 +24,7 @@ use function func_get_args; use function get_class; use function implode; +use function in_array; use function is_string; use function preg_match; use function sprintf; @@ -1124,10 +1125,16 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritdoc} */ - public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - if (! $char) { - switch ($pos) { + if (! in_array($mode, [TrimMode::UNSPECIFIED, TrimMode::LEADING, TrimMode::TRAILING, TrimMode::BOTH], true)) { + throw new InvalidArgumentException( + sprintf('The value of $mode is expected to be one of the TrimMode constants, %d given', $mode) + ); + } + + if ($char === null) { + switch ($mode) { case TrimMode::LEADING: return $this->getLtrimExpression($str); case TrimMode::TRAILING: @@ -1139,7 +1146,7 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa $pattern = "'%[^' + " . $char . " + ']%'"; - switch ($pos) { + switch ($mode) { case TrimMode::LEADING: return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))'; case TrimMode::TRAILING: diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index 5b8f8c07e1d..ed3131ac9c3 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -21,6 +21,7 @@ use function explode; use function func_get_args; use function implode; +use function in_array; use function is_array; use function is_bool; use function is_numeric; @@ -1031,23 +1032,25 @@ public function getModExpression($expression1, $expression2) /** * {@inheritDoc} */ - public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - if (! $char) { - switch ($pos) { + if (! in_array($mode, [TrimMode::UNSPECIFIED, TrimMode::LEADING, TrimMode::TRAILING, TrimMode::BOTH], true)) { + throw new InvalidArgumentException( + sprintf('The value of $mode is expected to be one of the TrimMode constants, %d given', $mode) + ); + } + + if ($char === null) { + switch ($mode) { case TrimMode::LEADING: - $trimFn = 'LTRIM'; - break; + return 'LTRIM(' . $str . ')'; case TrimMode::TRAILING: - $trimFn = 'RTRIM'; - break; + return 'RTRIM(' . $str . ')'; default: return 'LTRIM(RTRIM(' . $str . '))'; } - - return $trimFn . '(' . $str . ')'; } /** Original query used to get those expressions @@ -1061,11 +1064,11 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa */ $pattern = "'%[^' + " . $char . " + ']%'"; - if ($pos === TrimMode::LEADING) { + if ($mode === TrimMode::LEADING) { return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)'; } - if ($pos === TrimMode::TRAILING) { + if ($mode === TrimMode::TRAILING) { return 'reverse(stuff(reverse(' . $str . '), 1, patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))'; } diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 023c14963dc..848f3a7f3fc 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -12,6 +12,7 @@ use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types; +use InvalidArgumentException; use function array_merge; use function array_unique; use function array_values; @@ -59,11 +60,14 @@ public function getNowExpression($type = 'timestamp') /** * {@inheritDoc} */ - public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - $trimChar = $char !== false ? (', ' . $char) : ''; + switch ($mode) { + case TrimMode::UNSPECIFIED: + case TrimMode::BOTH: + $trimFn = 'TRIM'; + break; - switch ($pos) { case TrimMode::LEADING: $trimFn = 'LTRIM'; break; @@ -73,10 +77,21 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa break; default: - $trimFn = 'TRIM'; + throw new InvalidArgumentException( + sprintf( + 'The value of $mode is expected to be one of the TrimMode constants, %d given', + $mode + ) + ); + } + + $arguments = [$str]; + + if ($char !== null) { + $arguments[] = $char; } - return $trimFn . '(' . $str . $trimChar . ')'; + return sprintf('%s(%s)', $trimFn, implode(', ', $arguments)); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index 0182fdef4a6..68287557dfe 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -18,6 +18,7 @@ use Doctrine\DBAL\Statement; use Doctrine\DBAL\Types\Types; use Doctrine\Tests\DbalFunctionalTestCase; +use InvalidArgumentException; use PDO; use const CASE_LOWER; use const PHP_EOL; @@ -525,10 +526,10 @@ public function testTrimExpression($value, $position, $char, $expectedResult) public function getTrimExpressionData() { return [ - ['test_string', TrimMode::UNSPECIFIED, false, 'foo'], - ['test_string', TrimMode::LEADING, false, 'foo'], - ['test_string', TrimMode::TRAILING, false, 'foo'], - ['test_string', TrimMode::BOTH, false, 'foo'], + ['test_string', TrimMode::UNSPECIFIED, null, 'foo'], + ['test_string', TrimMode::LEADING, null, 'foo'], + ['test_string', TrimMode::TRAILING, null, 'foo'], + ['test_string', TrimMode::BOTH, null, 'foo'], ['test_string', TrimMode::UNSPECIFIED, "'f'", 'oo'], ['test_string', TrimMode::UNSPECIFIED, "'o'", 'f'], ['test_string', TrimMode::UNSPECIFIED, "'.'", 'foo'], @@ -541,10 +542,10 @@ public function getTrimExpressionData() ['test_string', TrimMode::BOTH, "'f'", 'oo'], ['test_string', TrimMode::BOTH, "'o'", 'f'], ['test_string', TrimMode::BOTH, "'.'", 'foo'], - ["' foo '", TrimMode::UNSPECIFIED, false, 'foo'], - ["' foo '", TrimMode::LEADING, false, 'foo '], - ["' foo '", TrimMode::TRAILING, false, ' foo'], - ["' foo '", TrimMode::BOTH, false, 'foo'], + ["' foo '", TrimMode::UNSPECIFIED, null, 'foo'], + ["' foo '", TrimMode::LEADING, null, 'foo '], + ["' foo '", TrimMode::TRAILING, null, ' foo'], + ["' foo '", TrimMode::BOTH, null, 'foo'], ["' foo '", TrimMode::UNSPECIFIED, "'f'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'o'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'.'", ' foo '], @@ -564,6 +565,12 @@ public function getTrimExpressionData() ]; } + public function testTrimExpressionInvalidMode() : void + { + $this->expectException(InvalidArgumentException::class); + $this->connection->getDatabasePlatform()->getTrimExpression('Trim me!', 0xBEEF); + } + /** * @group DDC-1014 */ diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index 8122a64302c..51989653425 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -665,11 +665,6 @@ public function testGeneratesSQLSnippets() "REVERSE(SUBSTR(REVERSE(column), PATINDEX('%[^' + c + ']%', REVERSE(column))))", $this->platform->getTrimExpression('column', TrimMode::TRAILING, 'c') ); - self::assertEquals( - "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . - "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", - $this->platform->getTrimExpression('column', null, 'c') - ); self::assertEquals( "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", From fab415a9369d869d9d1bf68ade94efba9215d119 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 17 Mar 2019 21:46:56 -0700 Subject: [PATCH 59/66] Modified AbstractPlatform::getLocateExpression() and ::getSubstringExpression() signatures --- UPGRADE.md | 8 ++++ .../DBAL/Platforms/AbstractPlatform.php | 32 +++++++-------- lib/Doctrine/DBAL/Platforms/DB2Platform.php | 14 +++---- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 8 ++-- .../DBAL/Platforms/OraclePlatform.php | 16 ++++---- .../DBAL/Platforms/PostgreSqlPlatform.php | 22 +++------- .../DBAL/Platforms/SQLAnywherePlatform.php | 14 +++---- .../DBAL/Platforms/SQLServerPlatform.php | 16 ++++---- .../DBAL/Platforms/SqlitePlatform.php | 18 ++++---- .../Tests/DBAL/Functional/DataAccessTest.php | 41 +++++++++++++++++++ .../Tests/DBAL/Platforms/DB2PlatformTest.php | 1 - .../DBAL/Platforms/SqlitePlatformTest.php | 2 +- 12 files changed, 111 insertions(+), 81 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 59ff7b31de2..b6b9eaba026 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,13 @@ # Upgrade to 3.0 +## BC BREAK The type of `$start` in `AbstractPlatform::getLocateExpression()` changed from `string|false` to `?string` + +The default value of `$start` is now `null`, not `false`. + +## BC BREAK The types of `$start` and `$length` in `AbstractPlatform::getSubstringExpression()` changed from `int` and `?int` to `string` and `?string` respectively + +The platform abstraction allows building arbitrary SQL expressions, so even if the arguments represent numeric literals, they should be passed as a string. + ## BC BREAK The type of `$char` in `AbstractPlatform::getTrimExpression()` changed from `string|false` to `?string` The default value of `$char` is now `null`, not `false`. Additionally, the method will throw an `InvalidArgumentException` in an invalid value of `$mode` is passed. diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index cea76b80e55..72f2c937cd6 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -850,17 +850,16 @@ public function getLowerExpression($str) } /** - * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str. + * Returns the SQL snippet to get the position of the first occurrence of the substring in the string. * - * @param string $str Literal string. - * @param string $substr Literal string to find. - * @param int|false $startPos Position to start at, beginning of string by default. - * - * @return string + * @param string $string SQL expression producing the string to locate the substring in. + * @param string $substring SQL expression producing the substring to locate. + * @param string|null $start SQL expression producing the position to start at. + * Defaults to the beginning of the string. * * @throws DBALException If not supported on this platform. */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { throw DBALException::notSupported(__METHOD__); } @@ -876,25 +875,22 @@ public function getNowExpression() } /** - * Returns a SQL snippet to get a substring inside an SQL statement. + * Returns an SQL snippet to get a substring inside the string. * * Note: Not SQL92, but common functionality. * - * SQLite only supports the 2 parameter variant of this function. - * - * @param string $value An sql string literal or column name/alias. - * @param int $from Where to start the substring portion. - * @param int|null $length The substring portion length. - * - * @return string + * @param string $string SQL expression producing the string from which a substring should be extracted. + * @param string $start SQL expression producing the position to start at, + * @param string|null $length SQL expression producing the length of the substring portion to be returned. + * By default, the entire substring is returned. */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; + return sprintf('SUBSTRING(%s FROM %s)', $string, $start); } - return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; + return sprintf('SUBSTRING(%s FROM %s FOR %s)', $string, $start, $length); } /** diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index 0555b8754d3..36317b589ed 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -814,25 +814,25 @@ protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $substr . ', ' . $str . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $substring, $string); } - return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $substring, $string, $start); } /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTR(' . $value . ', ' . $from . ')'; + return sprintf('SUBSTR(%s, %s)', $string, $start); } - return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')'; + return sprintf('SUBSTR(%s, %s, %s)', $string, $start, $length); } /** diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 6c5fb2e92dd..c9d814b6cce 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -81,13 +81,13 @@ public function getRegexpExpression() /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $substr . ', ' . $str . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $substring, $string); } - return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $substring, $string, $start); } /** diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index f621f454f6c..28db38583e5 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -47,13 +47,13 @@ public static function assertValidIdentifier($identifier) /** * {@inheritDoc} */ - public function getSubstringExpression($value, $position, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { - if ($length !== null) { - return sprintf('SUBSTR(%s, %d, %d)', $value, $position, $length); + if ($length === null) { + return sprintf('SUBSTR(%s, %s)', $string, $start); } - return sprintf('SUBSTR(%s, %d)', $value, $position); + return sprintf('SUBSTR(%s, %s, %s)', $string, $start, $length); } /** @@ -73,13 +73,13 @@ public function getNowExpression($type = 'timestamp') /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'INSTR(' . $str . ', ' . $substr . ')'; + if ($start === null) { + return sprintf('INSTR(%s, %s)', $string, $substring); } - return 'INSTR(' . $str . ', ' . $substr . ', ' . $startPos . ')'; + return sprintf('INSTR(%s, %s, %s)', $string, $substring, $start); } /** diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index f5603c5928d..47f80579ff2 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -75,18 +75,6 @@ public function setUseBooleanTrueFalseStrings($flag) $this->useBooleanTrueFalseStrings = (bool) $flag; } - /** - * {@inheritDoc} - */ - public function getSubstringExpression($value, $from, $length = null) - { - if ($length === null) { - return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; - } - - return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; - } - /** * {@inheritDoc} */ @@ -106,15 +94,15 @@ public function getRegexpExpression() /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos !== false) { - $str = $this->getSubstringExpression($str, $startPos); + if ($start !== null) { + $string = $this->getSubstringExpression($string, $start); - return 'CASE WHEN (POSITION(' . $substr . ' IN ' . $str . ') = 0) THEN 0 ELSE (POSITION(' . $substr . ' IN ' . $str . ') + ' . ($startPos-1) . ') END'; + return 'CASE WHEN (POSITION(' . $substring . ' IN ' . $string . ') = 0) THEN 0 ELSE (POSITION(' . $substring . ' IN ' . $string . ') + ' . $start . ' - 1) END'; } - return 'POSITION(' . $substr . ' IN ' . $str . ')'; + return sprintf('POSITION(%s IN %s)', $substring, $string); } /** diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 794fdf33a67..91f2334fe8a 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -966,13 +966,13 @@ public function getListViewsSQL($database) /** * {@inheritdoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $str . ', ' . $substr . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $string, $substring); } - return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $string, $substring, $start); } /** @@ -1089,13 +1089,13 @@ public function getStopDatabaseSQL($database) /** * {@inheritdoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTRING(' . $value . ', ' . $from . ')'; + return sprintf('SUBSTRING(%s, %s)', $string, $start); } - return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; + return sprintf('SUBSTRING(%s, %s, %s)', $string, $start, $length); } /** diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index ed3131ac9c3..f6af60750ba 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1012,13 +1012,13 @@ public function getDropViewSQL($name) /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'CHARINDEX(' . $substr . ', ' . $str . ')'; + if ($start === null) { + return sprintf('CHARINDEX(%s, %s)', $substring, $string); } - return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + return sprintf('CHARINDEX(%s, %s, %s)', $substring, $string, $start); } /** @@ -1104,13 +1104,13 @@ public function getListNamespacesSQL() /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { - if ($length !== null) { - return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; + if ($length === null) { + return sprintf('SUBSTRING(%s, %s, LEN(%s) - %s + 1)', $string, $start, $string, $start); } - return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)'; + return sprintf('SUBSTRING(%s, %s, %s)', $string, $start, $length); } /** diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 848f3a7f3fc..397cff35692 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -96,28 +96,26 @@ public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED /** * {@inheritDoc} - * - * SQLite only supports the 2 parameter variant of this function */ - public function getSubstringExpression($value, $position, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { - if ($length !== null) { - return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')'; + if ($length === null) { + return sprintf('SUBSTR(%s, %s)', $string, $start); } - return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))'; + return sprintf('SUBSTR(%s, %s, %s)', $string, $start, $length); } /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $str . ', ' . $substr . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $string, $substring); } - return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $string, $substring, $start); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index 68287557dfe..7b84381e579 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -674,6 +674,47 @@ public function testLocateExpression() self::assertEquals(0, $row['locate9']); } + /** + * @dataProvider substringExpressionProvider + */ + public function testSubstringExpression(string $string, string $start, ?string $length, string $expected) : void + { + $platform = $this->connection->getDatabasePlatform(); + + $query = $platform->getDummySelectSQL( + $platform->getSubstringExpression($string, $start, $length) + ); + + $this->assertEquals($expected, $this->connection->fetchColumn($query)); + } + + /** + * @return mixed[][] + */ + public static function substringExpressionProvider() : iterable + { + return [ + 'start-no-length' => [ + "'abcdef'", + '3', + null, + 'cdef', + ], + 'start-with-length' => [ + "'abcdef'", + '2', + '4', + 'bcde', + ], + 'expressions' => [ + "'abcdef'", + '1 + 1', + '1 + 1', + 'bc', + ], + ]; + } + public function testQuoteSQLInjection() { $sql = 'SELECT * FROM fetch_table WHERE test_string = ' . $this->connection->quote("bar' OR '1'='1"); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php index a9d61a7d6a1..3cc6f51992a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php @@ -333,7 +333,6 @@ public function testGeneratesSQLSnippets() self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5)); self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index 26cc4d304eb..027764c6726 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -33,7 +33,7 @@ public function getGenerateTableWithMultiColumnUniqueIndexSql() public function testGeneratesSqlSnippets() { self::assertEquals('REGEXP', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct'); - self::assertEquals('SUBSTR(column, 5, LENGTH(column))', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); + self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); } From f771d670f015af0cb9ec90af3041142e4e945569 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 21 Mar 2019 22:15:03 -0700 Subject: [PATCH 60/66] Reworked AbstractPlatform::get*Expression() methods --- UPGRADE.md | 27 ++ .../DBAL/Platforms/AbstractPlatform.php | 404 +++++++----------- lib/Doctrine/DBAL/Platforms/DB2Platform.php | 16 +- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 11 +- .../DBAL/Platforms/OraclePlatform.php | 14 +- .../DBAL/Platforms/PostgreSqlPlatform.php | 12 +- .../DBAL/Platforms/SQLAnywherePlatform.php | 15 +- .../DBAL/Platforms/SQLServerPlatform.php | 19 +- .../DBAL/Platforms/SqlitePlatform.php | 45 +- .../Tests/DBAL/Functional/DataAccessTest.php | 343 +++++++++++++-- .../Tests/DBAL/Platforms/DB2PlatformTest.php | 8 +- .../DBAL/Platforms/SqlitePlatformTest.php | 4 +- 12 files changed, 554 insertions(+), 364 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index b6b9eaba026..1e2a9257f1e 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,32 @@ # Upgrade to 3.0 +## BC BREAK `AbstractPlatform::get*Expression()` methods no loner accept integer values as arguments + +The following methods' arguments do not longer accept integer value: + +- the `$expression` argument in `::getCountExpression()`, +- the `$decimals` argument in `::getRoundExpression()`, +- the `$seconds` argument in `::getDateAddSecondsExpression()`, +- the `$seconds` argument in `::getDateSubSecondsExpression()`, +- the `$minutes` argument in `::getDateAddMinutesExpression()`, +- the `$minutes` argument in `::getDateSubMinutesExpression()`, +- the `$hours` argument in `::getDateAddHourExpression()`, +- the `$hours` argument in `::getDateAddHourExpression()`, +- the `$days` argument in `::getDateAddDaysExpression()`, +- the `$days` argument in `::getDateSubDaysExpression()`, +- the `$weeks` argument in `::getDateAddWeeksExpression()`, +- the `$weeks` argument in `::getDateSubWeeksExpression()`, +- the `$months` argument in `::getDateAddMonthExpression()`, +- the `$months` argument in `::getDateSubMonthExpression()`, +- the `$quarters` argument in `::getDateAddQuartersExpression()`, +- the `$quarters` argument in `::getDateSubQuartersExpression()`, +- the `$years` argument in `::getDateAddYearsExpression()`, +- the `$years` argument in `::getDateSubYearsExpression()`. + +Please use the strings representing numeric SQL literals instead (e.g. `'1'` instead of `1`). + +The signature of `AbstractPlatform::getConcatExpression()` changed to `::getConcatExpression(string ...$string)`. + ## BC BREAK The type of `$start` in `AbstractPlatform::getLocateExpression()` changed from `string|false` to `?string` The default value of `$start` is now `null`, not `false`. diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 72f2c937cd6..739d3ca6930 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -37,7 +37,6 @@ use function assert; use function count; use function explode; -use function func_get_args; use function implode; use function in_array; use function is_array; @@ -611,11 +610,9 @@ public function getWildcards() /** * Returns the regular expression operator. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getRegexpExpression() + public function getRegexpExpression() : string { throw DBALException::notSupported(__METHOD__); } @@ -623,13 +620,11 @@ public function getRegexpExpression() /** * Returns the SQL snippet to get the average value of a column. * - * @param string $column The column to use. - * - * @return string Generated SQL including an AVG aggregate function. + * @param string $value SQL expression producing the value. */ - public function getAvgExpression($column) + public function getAvgExpression(string $value) : string { - return 'AVG(' . $column . ')'; + return 'AVG(' . $value . ')'; } /** @@ -637,115 +632,97 @@ public function getAvgExpression($column) * * If a '*' is used instead of a column the number of selected rows is returned. * - * @param string|int $column The column to use. - * - * @return string Generated SQL including a COUNT aggregate function. + * @param string $expression The expression to count. */ - public function getCountExpression($column) + public function getCountExpression(string $expression) : string { - return 'COUNT(' . $column . ')'; + return 'COUNT(' . $expression . ')'; } /** - * Returns the SQL snippet to get the highest value of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the maximum value in a set of values. * - * @return string Generated SQL including a MAX aggregate function. + * @param string $value SQL expression producing the value. */ - public function getMaxExpression($column) + public function getMaxExpression(string $value) : string { - return 'MAX(' . $column . ')'; + return 'MAX(' . $value . ')'; } /** - * Returns the SQL snippet to get the lowest value of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the minimum value in a set of values. * - * @return string Generated SQL including a MIN aggregate function. + * @param string $value SQL expression producing the value. */ - public function getMinExpression($column) + public function getMinExpression(string $value) : string { - return 'MIN(' . $column . ')'; + return 'MIN(' . $value . ')'; } /** - * Returns the SQL snippet to get the total sum of a column. + * Returns the SQL snippet to get the total sum of the values in a set. * - * @param string $column The column to use. - * - * @return string Generated SQL including a SUM aggregate function. + * @param string $value SQL expression producing the value. */ - public function getSumExpression($column) + public function getSumExpression(string $value) : string { - return 'SUM(' . $column . ')'; + return 'SUM(' . $value . ')'; } // scalar functions /** - * Returns the SQL snippet to get the md5 sum of a field. + * Returns the SQL snippet to get the md5 sum of the value. * * Note: Not SQL92, but common functionality. * - * @param string $column - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getMd5Expression($column) + public function getMd5Expression(string $string) : string { - return 'MD5(' . $column . ')'; + return 'MD5(' . $string . ')'; } /** * Returns the SQL snippet to get the length of a text field. * - * @param string $column - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLengthExpression($column) + public function getLengthExpression(string $string) : string { - return 'LENGTH(' . $column . ')'; + return 'LENGTH(' . $string . ')'; } /** - * Returns the SQL snippet to get the squared value of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the square root of the value. * - * @return string Generated SQL including an SQRT aggregate function. + * @param string $number SQL expression producing the number. */ - public function getSqrtExpression($column) + public function getSqrtExpression(string $number) : string { - return 'SQRT(' . $column . ')'; + return 'SQRT(' . $number . ')'; } /** - * Returns the SQL snippet to round a numeric field to the number of decimals specified. + * Returns the SQL snippet to round a number to the number of decimals specified. * - * @param string $column - * @param int $decimals - * - * @return string + * @param string $number SQL expression producing the number to round. + * @param string $decimals SQL expression producing the number of decimals. */ - public function getRoundExpression($column, $decimals = 0) + public function getRoundExpression(string $number, string $decimals = '0') : string { - return 'ROUND(' . $column . ', ' . $decimals . ')'; + return 'ROUND(' . $number . ', ' . $decimals . ')'; } /** - * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2. - * - * @param string $expression1 - * @param string $expression2 + * Returns the SQL snippet to get the remainder of the operation of division of dividend by divisor. * - * @return string + * @param string $dividend SQL expression producing the dividend. + * @param string $divisor SQL expression producing the divisor. */ - public function getModExpression($expression1, $expression2) + public function getModExpression(string $dividend, string $divisor) : string { - return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; + return 'MOD(' . $dividend . ', ' . $divisor . ')'; } /** @@ -800,53 +777,45 @@ public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED } /** - * Returns the SQL snippet to trim trailing space characters from the expression. - * - * @param string $str Literal string or column name. + * Returns the SQL snippet to trim trailing space characters from the string. * - * @return string + * @param string $string SQL expression producing the string. */ - public function getRtrimExpression($str) + public function getRtrimExpression(string $string) : string { - return 'RTRIM(' . $str . ')'; + return 'RTRIM(' . $string . ')'; } /** - * Returns the SQL snippet to trim leading space characters from the expression. + * Returns the SQL snippet to trim leading space characters from the string. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLtrimExpression($str) + public function getLtrimExpression(string $string) : string { - return 'LTRIM(' . $str . ')'; + return 'LTRIM(' . $string . ')'; } /** - * Returns the SQL snippet to change all characters from the expression to uppercase, + * Returns the SQL snippet to change all characters from the string to uppercase, * according to the current character set mapping. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getUpperExpression($str) + public function getUpperExpression(string $string) : string { - return 'UPPER(' . $str . ')'; + return 'UPPER(' . $string . ')'; } /** - * Returns the SQL snippet to change all characters from the expression to lowercase, + * Returns the SQL snippet to change all characters from the string to lowercase, * according to the current character set mapping. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLowerExpression($str) + public function getLowerExpression(string $string) : string { - return 'LOWER(' . $str . ')'; + return 'LOWER(' . $string . ')'; } /** @@ -866,10 +835,8 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * Returns the SQL snippet to get the current system date. - * - * @return string */ - public function getNowExpression() + public function getNowExpression() : string { return 'NOW()'; } @@ -894,111 +861,87 @@ public function getSubstringExpression(string $string, string $start, ?string $l } /** - * Returns a SQL snippet to concatenate the given expressions. + * Returns a SQL snippet to concatenate the given strings. * - * Accepts an arbitrary number of string parameters. Each parameter must contain an expression. - * - * @return string + * @param string[] ...$string */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - return implode(' || ', func_get_args()); + return implode(' || ', $string); } /** * Returns the SQL for a logical not. * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * $q->select('*')->from('table') - * ->where($e->eq('id', $e->not('null')); - * - * - * @param string $expression - * - * @return string The logical expression. + * @param string $value SQL expression producing the value to negate. */ - public function getNotExpression($expression) + public function getNotExpression(string $value) : string { - return 'NOT(' . $expression . ')'; + return 'NOT(' . $value . ')'; } /** * Returns the SQL that checks if an expression is null. * - * @param string $expression The expression that should be compared to null. - * - * @return string The logical expression. + * @param string $value SQL expression producing the to be compared to null. */ - public function getIsNullExpression($expression) + public function getIsNullExpression(string $value) : string { - return $expression . ' IS NULL'; + return $value . ' IS NULL'; } /** * Returns the SQL that checks if an expression is not null. * - * @param string $expression The expression that should be compared to null. - * - * @return string The logical expression. + * @param string $value SQL expression producing the to be compared to null. */ - public function getIsNotNullExpression($expression) + public function getIsNotNullExpression(string $value) : string { - return $expression . ' IS NOT NULL'; + return $value . ' IS NOT NULL'; } /** * Returns the SQL that checks if an expression evaluates to a value between two values. * - * The parameter $expression is checked if it is between $value1 and $value2. + * The parameter $value is checked if it is between $min and $max. * * Note: There is a slight difference in the way BETWEEN works on some databases. * http://www.w3schools.com/sql/sql_between.asp. If you want complete database * independence you should avoid using between(). * - * @param string $expression The value to compare to. - * @param string $value1 The lower value to compare with. - * @param string $value2 The higher value to compare with. - * - * @return string The logical expression. + * @param string $value SQL expression producing the value to compare. + * @param string $min SQL expression producing the lower value to compare with. + * @param string $max SQL expression producing the higher value to compare with. */ - public function getBetweenExpression($expression, $value1, $value2) + public function getBetweenExpression(string $value, string $min, string $max) : string { - return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2; + return $value . ' BETWEEN ' . $min . ' AND ' . $max; } /** * Returns the SQL to get the arccosine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getAcosExpression($value) + public function getAcosExpression(string $number) : string { - return 'ACOS(' . $value . ')'; + return 'ACOS(' . $number . ')'; } /** * Returns the SQL to get the sine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getSinExpression($value) + public function getSinExpression(string $number) : string { - return 'SIN(' . $value . ')'; + return 'SIN(' . $number . ')'; } /** * Returns the SQL to get the PI value. - * - * @return string */ - public function getPiExpression() + public function getPiExpression() : string { return 'PI()'; } @@ -1006,13 +949,11 @@ public function getPiExpression() /** * Returns the SQL to get the cosine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getCosExpression($value) + public function getCosExpression(string $number) : string { - return 'COS(' . $value . ')'; + return 'COS(' . $number . ')'; } /** @@ -1020,14 +961,9 @@ public function getCosExpression($value) * * Computes diff = date1 - date2. * - * @param string $date1 - * @param string $date2 - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { throw DBALException::notSupported(__METHOD__); } @@ -1035,14 +971,12 @@ public function getDateDiffExpression($date1, $date2) /** * Returns the SQL to add the number of given seconds to a date. * - * @param string $date - * @param int $seconds - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $seconds SQL expression producing the number of seconds. * * @throws DBALException If not supported on this platform. */ - public function getDateAddSecondsExpression($date, $seconds) + public function getDateAddSecondsExpression(string $date, string $seconds) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND); } @@ -1050,14 +984,12 @@ public function getDateAddSecondsExpression($date, $seconds) /** * Returns the SQL to subtract the number of given seconds from a date. * - * @param string $date - * @param int $seconds - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $seconds SQL expression producing the number of seconds. * * @throws DBALException If not supported on this platform. */ - public function getDateSubSecondsExpression($date, $seconds) + public function getDateSubSecondsExpression(string $date, string $seconds) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND); } @@ -1065,14 +997,12 @@ public function getDateSubSecondsExpression($date, $seconds) /** * Returns the SQL to add the number of given minutes to a date. * - * @param string $date - * @param int $minutes - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $minutes SQL expression producing the number of minutes. * * @throws DBALException If not supported on this platform. */ - public function getDateAddMinutesExpression($date, $minutes) + public function getDateAddMinutesExpression(string $date, string $minutes) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE); } @@ -1080,14 +1010,12 @@ public function getDateAddMinutesExpression($date, $minutes) /** * Returns the SQL to subtract the number of given minutes from a date. * - * @param string $date - * @param int $minutes - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $minutes SQL expression producing the number of minutes. * * @throws DBALException If not supported on this platform. */ - public function getDateSubMinutesExpression($date, $minutes) + public function getDateSubMinutesExpression(string $date, string $minutes) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE); } @@ -1095,14 +1023,12 @@ public function getDateSubMinutesExpression($date, $minutes) /** * Returns the SQL to add the number of given hours to a date. * - * @param string $date - * @param int $hours - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $hours SQL expression producing the number of hours. * * @throws DBALException If not supported on this platform. */ - public function getDateAddHourExpression($date, $hours) + public function getDateAddHourExpression(string $date, string $hours) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR); } @@ -1110,14 +1036,12 @@ public function getDateAddHourExpression($date, $hours) /** * Returns the SQL to subtract the number of given hours to a date. * - * @param string $date - * @param int $hours - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $hours SQL expression producing the number of hours. * * @throws DBALException If not supported on this platform. */ - public function getDateSubHourExpression($date, $hours) + public function getDateSubHourExpression(string $date, string $hours) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR); } @@ -1125,14 +1049,12 @@ public function getDateSubHourExpression($date, $hours) /** * Returns the SQL to add the number of given days to a date. * - * @param string $date - * @param int $days - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $days SQL expression producing the number of days. * * @throws DBALException If not supported on this platform. */ - public function getDateAddDaysExpression($date, $days) + public function getDateAddDaysExpression(string $date, string $days) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY); } @@ -1140,14 +1062,12 @@ public function getDateAddDaysExpression($date, $days) /** * Returns the SQL to subtract the number of given days to a date. * - * @param string $date - * @param int $days - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $days SQL expression producing the number of days. * * @throws DBALException If not supported on this platform. */ - public function getDateSubDaysExpression($date, $days) + public function getDateSubDaysExpression(string $date, string $days) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY); } @@ -1155,14 +1075,12 @@ public function getDateSubDaysExpression($date, $days) /** * Returns the SQL to add the number of given weeks to a date. * - * @param string $date - * @param int $weeks - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $weeks SQL expression producing the number of weeks. * * @throws DBALException If not supported on this platform. */ - public function getDateAddWeeksExpression($date, $weeks) + public function getDateAddWeeksExpression(string $date, string $weeks) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK); } @@ -1170,14 +1088,12 @@ public function getDateAddWeeksExpression($date, $weeks) /** * Returns the SQL to subtract the number of given weeks from a date. * - * @param string $date - * @param int $weeks - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $weeks SQL expression producing the number of weeks. * * @throws DBALException If not supported on this platform. */ - public function getDateSubWeeksExpression($date, $weeks) + public function getDateSubWeeksExpression(string $date, string $weeks) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK); } @@ -1185,14 +1101,12 @@ public function getDateSubWeeksExpression($date, $weeks) /** * Returns the SQL to add the number of given months to a date. * - * @param string $date - * @param int $months - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $months SQL expression producing the number of months. * * @throws DBALException If not supported on this platform. */ - public function getDateAddMonthExpression($date, $months) + public function getDateAddMonthExpression(string $date, string $months) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH); } @@ -1200,14 +1114,12 @@ public function getDateAddMonthExpression($date, $months) /** * Returns the SQL to subtract the number of given months to a date. * - * @param string $date - * @param int $months - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $months SQL expression producing the number of months. * * @throws DBALException If not supported on this platform. */ - public function getDateSubMonthExpression($date, $months) + public function getDateSubMonthExpression(string $date, string $months) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH); } @@ -1215,14 +1127,12 @@ public function getDateSubMonthExpression($date, $months) /** * Returns the SQL to add the number of given quarters to a date. * - * @param string $date - * @param int $quarters - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $quarters SQL expression producing the number of quarters. * * @throws DBALException If not supported on this platform. */ - public function getDateAddQuartersExpression($date, $quarters) + public function getDateAddQuartersExpression(string $date, string $quarters) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER); } @@ -1230,14 +1140,12 @@ public function getDateAddQuartersExpression($date, $quarters) /** * Returns the SQL to subtract the number of given quarters from a date. * - * @param string $date - * @param int $quarters - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $quarters SQL expression producing the number of quarters. * * @throws DBALException If not supported on this platform. */ - public function getDateSubQuartersExpression($date, $quarters) + public function getDateSubQuartersExpression(string $date, string $quarters) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER); } @@ -1245,14 +1153,12 @@ public function getDateSubQuartersExpression($date, $quarters) /** * Returns the SQL to add the number of given years to a date. * - * @param string $date - * @param int $years - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $years SQL expression producing the number of years. * * @throws DBALException If not supported on this platform. */ - public function getDateAddYearsExpression($date, $years) + public function getDateAddYearsExpression(string $date, string $years) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR); } @@ -1260,14 +1166,12 @@ public function getDateAddYearsExpression($date, $years) /** * Returns the SQL to subtract the number of given years from a date. * - * @param string $date - * @param int $years - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $years SQL expression producing the number of years. * * @throws DBALException If not supported on this platform. */ - public function getDateSubYearsExpression($date, $years) + public function getDateSubYearsExpression(string $date, string $years) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR); } @@ -1275,30 +1179,40 @@ public function getDateSubYearsExpression($date, $years) /** * Returns the SQL for a date arithmetic expression. * - * @param string $date The column or literal representing a date to perform the arithmetic operation on. + * @param string $date SQL expression representing a date to perform the arithmetic operation on. * @param string $operator The arithmetic operator (+ or -). - * @param int $interval The interval that shall be calculated into the date. + * @param string $interval SQL expression representing the value of the interval that shall be calculated + * into the date. * @param string $unit The unit of the interval that shall be calculated into the date. * One of the DATE_INTERVAL_UNIT_* constants. * - * @return string - * * @throws DBALException If not supported on this platform. */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { throw DBALException::notSupported(__METHOD__); } /** - * Returns the SQL bit AND comparison expression. + * Generates the SQL expression which represents the given date interval multiplied by a number * - * @param string $value1 - * @param string $value2 + * @param string $interval SQL expression describing the interval value + * @param int $multiplier Interval multiplier * - * @return string + * @throws DBALException */ - public function getBitAndComparisonExpression($value1, $value2) + protected function multiplyInterval(string $interval, int $multiplier) : string + { + return sprintf('(%s * %d)', $interval, $multiplier); + } + + /** + * Returns the SQL bit AND comparison expression. + * + * @param string $value1 SQL expression producing the first value. + * @param string $value2 SQL expression producing the second value. + */ + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . ' & ' . $value2 . ')'; } @@ -1306,12 +1220,10 @@ public function getBitAndComparisonExpression($value1, $value2) /** * Returns the SQL bit OR comparison expression. * - * @param string $value1 - * @param string $value2 - * - * @return string + * @param string $value1 SQL expression producing the first value. + * @param string $value2 SQL expression producing the second value. */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . ' | ' . $value2 . ')'; } diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index 36317b589ed..f625b081905 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -186,7 +186,7 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - public function getBitAndComparisonExpression($value1, $value2) + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } @@ -194,7 +194,7 @@ public function getBitAndComparisonExpression($value1, $value2) /** * {@inheritdoc} */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return 'BITOR(' . $value1 . ', ' . $value2 . ')'; } @@ -202,17 +202,17 @@ public function getBitOrComparisonExpression($value1, $value2) /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { switch ($unit) { case DateIntervalUnit::WEEK: - $interval *= 7; - $unit = DateIntervalUnit::DAY; + $interval = $this->multiplyInterval($interval, 7); + $unit = DateIntervalUnit::DAY; break; case DateIntervalUnit::QUARTER: - $interval *= 3; - $unit = DateIntervalUnit::MONTH; + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; break; } @@ -222,7 +222,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritdoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')'; } diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index c9d814b6cce..78e318df264 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -16,7 +16,6 @@ use function array_unique; use function array_values; use function count; -use function func_get_args; use function implode; use function in_array; use function is_numeric; @@ -73,7 +72,7 @@ public function getIdentifierQuoteCharacter() /** * {@inheritDoc} */ - public function getRegexpExpression() + public function getRegexpExpression() : string { return 'RLIKE'; } @@ -93,15 +92,15 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * {@inheritDoc} */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - return sprintf('CONCAT(%s)', implode(', ', func_get_args())); + return sprintf('CONCAT(%s)', implode(', ', $string)); } /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { $function = $operator === '+' ? 'DATE_ADD' : 'DATE_SUB'; @@ -111,7 +110,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 28db38583e5..c463f722e5e 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -59,7 +59,7 @@ public function getSubstringExpression(string $string, string $start, ?string $l /** * {@inheritDoc} */ - public function getNowExpression($type = 'timestamp') + public function getNowExpression($type = 'timestamp') : string { switch ($type) { case 'date': @@ -85,7 +85,7 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { switch ($unit) { case DateIntervalUnit::MONTH: @@ -93,11 +93,11 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv case DateIntervalUnit::YEAR: switch ($unit) { case DateIntervalUnit::QUARTER: - $interval *= 3; + $interval = $this->multiplyInterval($interval, 3); break; case DateIntervalUnit::YEAR: - $interval *= 12; + $interval = $this->multiplyInterval($interval, 12); break; } @@ -131,7 +131,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return sprintf('TRUNC(%s) - TRUNC(%s)', $date1, $date2); } @@ -139,7 +139,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - public function getBitAndComparisonExpression($value1, $value2) + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } @@ -147,7 +147,7 @@ public function getBitAndComparisonExpression($value1, $value2) /** * {@inheritDoc} */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . '-' . $this->getBitAndComparisonExpression($value1, $value2) diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index 47f80579ff2..3b5d46648e6 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -78,7 +78,7 @@ public function setUseBooleanTrueFalseStrings($flag) /** * {@inheritDoc} */ - public function getNowExpression() + public function getNowExpression() : string { return 'LOCALTIMESTAMP(0)'; } @@ -86,7 +86,7 @@ public function getNowExpression() /** * {@inheritDoc} */ - public function getRegexpExpression() + public function getRegexpExpression() : string { return 'SIMILAR TO'; } @@ -108,11 +108,11 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { if ($unit === DateIntervalUnit::QUARTER) { - $interval *= 3; - $unit = DateIntervalUnit::MONTH; + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; } return '(' . $date . ' ' . $operator . ' (' . $interval . " || ' " . $unit . "')::interval)"; @@ -121,7 +121,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))'; } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 91f2334fe8a..36714143b85 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -21,7 +21,6 @@ use function array_values; use function count; use function explode; -use function func_get_args; use function get_class; use function implode; use function in_array; @@ -373,9 +372,9 @@ public function getCommentOnColumnSQL($tableName, $columnName, $comment) /** * {@inheritdoc} */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - return 'STRING(' . implode(', ', (array) func_get_args()) . ')'; + return 'STRING(' . implode(', ', $string) . ')'; } /** @@ -470,7 +469,7 @@ public function getCurrentTimestampSQL() /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { $factorClause = ''; @@ -484,7 +483,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritdoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')'; } @@ -986,15 +985,15 @@ public function getMaxIdentifierLength() /** * {@inheritdoc} */ - public function getMd5Expression($column) + public function getMd5Expression(string $string) : string { - return 'HASH(' . $column . ", 'MD5')"; + return 'HASH(' . $string . ", 'MD5')"; } /** * {@inheritdoc} */ - public function getRegexpExpression() + public function getRegexpExpression() : string { return 'REGEXP'; } diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index f6af60750ba..d385f334f8d 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -19,7 +19,6 @@ use function crc32; use function dechex; use function explode; -use function func_get_args; use function implode; use function in_array; use function is_array; @@ -75,7 +74,7 @@ private function getConvertExpression($dataType, $expression) /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { $factorClause = ''; @@ -89,7 +88,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')'; } @@ -1024,9 +1023,9 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * {@inheritDoc} */ - public function getModExpression($expression1, $expression2) + public function getModExpression(string $dividend, string $divisor) : string { - return $expression1 . ' % ' . $expression2; + return $dividend . ' % ' . $divisor; } /** @@ -1078,11 +1077,9 @@ public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED /** * {@inheritDoc} */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - $args = func_get_args(); - - return '(' . implode(' + ', $args) . ')'; + return '(' . implode(' + ', $string) . ')'; } /** @@ -1116,9 +1113,9 @@ public function getSubstringExpression(string $string, string $start, ?string $l /** * {@inheritDoc} */ - public function getLengthExpression($column) + public function getLengthExpression(string $string) : string { - return 'LEN(' . $column . ')'; + return 'LEN(' . $string . ')'; } /** diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 397cff35692..f2842f8e16a 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -17,7 +17,6 @@ use function array_unique; use function array_values; use function implode; -use function is_numeric; use function sprintf; use function sqrt; use function str_replace; @@ -36,7 +35,7 @@ class SqlitePlatform extends AbstractPlatform /** * {@inheritDoc} */ - public function getRegexpExpression() + public function getRegexpExpression() : string { return 'REGEXP'; } @@ -44,7 +43,7 @@ public function getRegexpExpression() /** * {@inheritDoc} */ - public function getNowExpression($type = 'timestamp') + public function getNowExpression($type = 'timestamp') : string { switch ($type) { case 'time': @@ -121,39 +120,31 @@ public function getLocateExpression(string $string, string $substring, ?string $ /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { switch ($unit) { - case DateIntervalUnit::SECOND: - case DateIntervalUnit::MINUTE: - case DateIntervalUnit::HOUR: - return 'DATETIME(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')"; - - default: - switch ($unit) { - case DateIntervalUnit::WEEK: - $interval *= 7; - $unit = DateIntervalUnit::DAY; - break; - - case DateIntervalUnit::QUARTER: - $interval *= 3; - $unit = DateIntervalUnit::MONTH; - break; - } - - if (! is_numeric($interval)) { - $interval = "' || " . $interval . " || '"; - } + case DateIntervalUnit::WEEK: + $interval = $this->multiplyInterval($interval, 7); + $unit = DateIntervalUnit::DAY; + break; - return 'DATE(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')"; + case DateIntervalUnit::QUARTER: + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; + break; } + + return 'DATETIME(' . $date . ',' . $this->getConcatExpression( + $this->quoteStringLiteral($operator), + $interval, + $this->quoteStringLiteral(' ' . $unit) + ) . ')'; } /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return sprintf("JULIANDAY(%s, 'start of day') - JULIANDAY(%s, 'start of day')", $date1, $date2); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index 7b84381e579..c7e0fdddf77 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -12,6 +12,7 @@ use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver; use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; +use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Platforms\TrimMode; use Doctrine\DBAL\Schema\Table; @@ -572,49 +573,313 @@ public function testTrimExpressionInvalidMode() : void } /** - * @group DDC-1014 + * @dataProvider modeProvider */ - public function testDateArithmetics() + public function testDateAddSeconds(callable $buildQuery, callable $bindParams) : void { - $p = $this->connection->getDatabasePlatform(); - $sql = 'SELECT '; - $sql .= $p->getDateAddSecondsExpression('test_datetime', 1) . ' AS add_seconds, '; - $sql .= $p->getDateSubSecondsExpression('test_datetime', 1) . ' AS sub_seconds, '; - $sql .= $p->getDateAddMinutesExpression('test_datetime', 5) . ' AS add_minutes, '; - $sql .= $p->getDateSubMinutesExpression('test_datetime', 5) . ' AS sub_minutes, '; - $sql .= $p->getDateAddHourExpression('test_datetime', 3) . ' AS add_hour, '; - $sql .= $p->getDateSubHourExpression('test_datetime', 3) . ' AS sub_hour, '; - $sql .= $p->getDateAddDaysExpression('test_datetime', 10) . ' AS add_days, '; - $sql .= $p->getDateSubDaysExpression('test_datetime', 10) . ' AS sub_days, '; - $sql .= $p->getDateAddWeeksExpression('test_datetime', 1) . ' AS add_weeks, '; - $sql .= $p->getDateSubWeeksExpression('test_datetime', 1) . ' AS sub_weeks, '; - $sql .= $p->getDateAddMonthExpression('test_datetime', 2) . ' AS add_month, '; - $sql .= $p->getDateSubMonthExpression('test_datetime', 2) . ' AS sub_month, '; - $sql .= $p->getDateAddQuartersExpression('test_datetime', 3) . ' AS add_quarters, '; - $sql .= $p->getDateSubQuartersExpression('test_datetime', 3) . ' AS sub_quarters, '; - $sql .= $p->getDateAddYearsExpression('test_datetime', 6) . ' AS add_years, '; - $sql .= $p->getDateSubYearsExpression('test_datetime', 6) . ' AS sub_years '; - $sql .= 'FROM fetch_table'; + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddSecondsExpression('test_datetime', $interval); + }, + 1, + '2010-01-01 10:10:11' + ); + } - $row = $this->connection->fetchAssoc($sql); - $row = array_change_key_case($row, CASE_LOWER); + /** + * @dataProvider modeProvider + */ + public function testDateSubSeconds(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubSecondsExpression('test_datetime', $interval); + }, + 1, + '2010-01-01 10:10:09' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddMinutes(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddMinutesExpression('test_datetime', $interval); + }, + 5, + '2010-01-01 10:15:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubMinutes(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubMinutesExpression('test_datetime', $interval); + }, + 5, + '2010-01-01 10:05:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddHours(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddHourExpression('test_datetime', $interval); + }, + 3, + '2010-01-01 13:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubHours(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubHourExpression('test_datetime', $interval); + }, + 3, + '2010-01-01 07:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddDays(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddDaysExpression('test_datetime', $interval); + }, + 10, + '2010-01-11 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubDays(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubDaysExpression('test_datetime', $interval); + }, + 10, + '2009-12-22 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddWeeks(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddWeeksExpression('test_datetime', $interval); + }, + 1, + '2010-01-08 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubWeeks(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubWeeksExpression('test_datetime', $interval); + }, + 1, + '2009-12-25 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddMonths(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddMonthExpression('test_datetime', $interval); + }, + 2, + '2010-03-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubMonths(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubMonthExpression('test_datetime', $interval); + }, + 2, + '2009-11-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddQuarters(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddQuartersExpression('test_datetime', $interval); + }, + 3, + '2010-10-01 10:10:10' + ); + } - self::assertEquals('2010-01-01 10:10:11', date('Y-m-d H:i:s', strtotime($row['add_seconds'])), 'Adding second should end up on 2010-01-01 10:10:11'); - self::assertEquals('2010-01-01 10:10:09', date('Y-m-d H:i:s', strtotime($row['sub_seconds'])), 'Subtracting second should end up on 2010-01-01 10:10:09'); - self::assertEquals('2010-01-01 10:15:10', date('Y-m-d H:i:s', strtotime($row['add_minutes'])), 'Adding minutes should end up on 2010-01-01 10:15:10'); - self::assertEquals('2010-01-01 10:05:10', date('Y-m-d H:i:s', strtotime($row['sub_minutes'])), 'Subtracting minutes should end up on 2010-01-01 10:05:10'); - self::assertEquals('2010-01-01 13:10', date('Y-m-d H:i', strtotime($row['add_hour'])), 'Adding date should end up on 2010-01-01 13:10'); - self::assertEquals('2010-01-01 07:10', date('Y-m-d H:i', strtotime($row['sub_hour'])), 'Subtracting date should end up on 2010-01-01 07:10'); - self::assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), 'Adding date should end up on 2010-01-11'); - self::assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), 'Subtracting date should end up on 2009-12-22'); - self::assertEquals('2010-01-08', date('Y-m-d', strtotime($row['add_weeks'])), 'Adding week should end up on 2010-01-08'); - self::assertEquals('2009-12-25', date('Y-m-d', strtotime($row['sub_weeks'])), 'Subtracting week should end up on 2009-12-25'); - self::assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), 'Adding month should end up on 2010-03-01'); - self::assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), 'Subtracting month should end up on 2009-11-01'); - self::assertEquals('2010-10-01', date('Y-m-d', strtotime($row['add_quarters'])), 'Adding quarters should end up on 2010-04-01'); - self::assertEquals('2009-04-01', date('Y-m-d', strtotime($row['sub_quarters'])), 'Subtracting quarters should end up on 2009-10-01'); - self::assertEquals('2016-01-01', date('Y-m-d', strtotime($row['add_years'])), 'Adding years should end up on 2016-01-01'); - self::assertEquals('2004-01-01', date('Y-m-d', strtotime($row['sub_years'])), 'Subtracting years should end up on 2004-01-01'); + /** + * @dataProvider modeProvider + */ + public function testDateSubQuarters(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubQuartersExpression('test_datetime', $interval); + }, + 3, + '2009-04-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddYears(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddYearsExpression('test_datetime', $interval); + }, + 6, + '2016-01-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubYears(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubYearsExpression('test_datetime', $interval); + }, + 6, + '2004-01-01 10:10:10' + ); + } + + /** + * @param callable $buildQuery Builds the portion of the query representing the interval value + * @param callable $bindParams Binds the interval value to the statement + * @param callable $expression Builds the platform-specific interval expression + * @param int $interval Interval value + * @param string $expected Expected value + */ + private function assertDateExpression(callable $buildQuery, callable $bindParams, callable $expression, int $interval, string $expected) : void + { + $connection = $this->connection; + $platform = $connection->getDatabasePlatform(); + + $query = sprintf('SELECT %s FROM fetch_table', $expression($platform, $buildQuery($interval))); + $stmt = $connection->prepare($query); + $bindParams($stmt, $interval); + + $stmt->execute(); + + $date = $stmt->fetchColumn(); + + $this->assertEquals($expected, date('Y-m-d H:i:s', strtotime($date))); + } + + /** + * @return mixed[][] + */ + public static function modeProvider() : array + { + return [ + 'bind' => [ + static function (int $interval) : string { + return '?'; + }, + static function (Statement $stmt, int $interval) : void { + $stmt->bindParam(1, $interval, ParameterType::INTEGER); + }, + ], + 'literal' => [ + static function (int $interval) : string { + return sprintf('%d', $interval); + }, + static function (Statement $stmt, int $interval) : void { + }, + ], + 'expression' => [ + static function (int $interval) : string { + return sprintf('(0 + %d)', $interval); + }, + static function (Statement $stmt, int $interval) : void { + }, + ], + ]; } public function testSqliteDateArithmeticWithDynamicInterval() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php index 3cc6f51992a..ad52abae0e7 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php @@ -318,18 +318,18 @@ public function testGeneratesSQLSnippets() self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' + 15 MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); + self::assertEquals("'1987/05/02' + (5 * 3) MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' + 21 DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); + self::assertEquals("'1987/05/02' + (3 * 7) DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); self::assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' - 15 MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); + self::assertEquals("'1987/05/02' - (5 * 3) MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' - 21 DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); + self::assertEquals("'1987/05/02' - (3 * 7) DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index 027764c6726..79f07ef6d79 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -766,12 +766,12 @@ public function testQuotesTableNameInListTableForeignKeysSQL() public function testDateAddStaticNumberOfDays() { - self::assertSame("DATE(rentalBeginsOn,'+12 DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12)); + self::assertSame("DATETIME(rentalBeginsOn,'+' || 12 || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12)); } public function testDateAddNumberOfDaysFromColumn() { - self::assertSame("DATE(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration')); + self::assertSame("DATETIME(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration')); } public function testSupportsColumnCollation() : void From 82f5fe317bedf9f328c06aeaab5a2f586810e94a Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 9 Feb 2019 00:36:00 +0100 Subject: [PATCH 61/66] Enable strict types --- bin/doctrine-dbal.php | 2 + lib/Doctrine/DBAL/Cache/ArrayStatement.php | 2 + lib/Doctrine/DBAL/Cache/CacheException.php | 2 + lib/Doctrine/DBAL/Cache/QueryCacheProfile.php | 2 + .../DBAL/Cache/ResultCacheStatement.php | 2 + lib/Doctrine/DBAL/ColumnCase.php | 2 + lib/Doctrine/DBAL/Configuration.php | 2 + lib/Doctrine/DBAL/Connection.php | 2 + lib/Doctrine/DBAL/ConnectionException.php | 2 + .../Connections/MasterSlaveConnection.php | 2 + lib/Doctrine/DBAL/DBALException.php | 2 + lib/Doctrine/DBAL/Driver.php | 2 + .../DBAL/Driver/AbstractDB2Driver.php | 2 + .../DBAL/Driver/AbstractDriverException.php | 2 + .../DBAL/Driver/AbstractMySQLDriver.php | 2 + .../DBAL/Driver/AbstractOracleDriver.php | 2 + .../DBAL/Driver/AbstractPostgreSQLDriver.php | 2 + .../DBAL/Driver/AbstractSQLAnywhereDriver.php | 2 + .../DBAL/Driver/AbstractSQLServerDriver.php | 2 + .../DBAL/Driver/AbstractSQLiteDriver.php | 2 + lib/Doctrine/DBAL/Driver/Connection.php | 2 + lib/Doctrine/DBAL/Driver/DriverException.php | 2 + .../DBAL/Driver/ExceptionConverterDriver.php | 2 + .../DBAL/Driver/IBMDB2/DB2Connection.php | 2 + lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php | 2 + .../DBAL/Driver/IBMDB2/DB2Exception.php | 2 + .../DBAL/Driver/IBMDB2/DB2Statement.php | 2 + lib/Doctrine/DBAL/Driver/Mysqli/Driver.php | 2 + .../DBAL/Driver/Mysqli/MysqliConnection.php | 8 ++-- .../DBAL/Driver/Mysqli/MysqliException.php | 2 + .../DBAL/Driver/Mysqli/MysqliStatement.php | 2 + lib/Doctrine/DBAL/Driver/OCI8/Driver.php | 2 + .../DBAL/Driver/OCI8/OCI8Connection.php | 6 ++- .../DBAL/Driver/OCI8/OCI8Exception.php | 2 + .../DBAL/Driver/OCI8/OCI8Statement.php | 6 ++- lib/Doctrine/DBAL/Driver/PDOConnection.php | 2 + lib/Doctrine/DBAL/Driver/PDOException.php | 2 + lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php | 2 + lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php | 2 + lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 2 + lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 2 + .../DBAL/Driver/PDOSqlsrv/Connection.php | 2 + lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php | 2 + .../DBAL/Driver/PDOSqlsrv/Statement.php | 2 + lib/Doctrine/DBAL/Driver/PDOStatement.php | 12 ++++- .../DBAL/Driver/PingableConnection.php | 2 + lib/Doctrine/DBAL/Driver/ResultStatement.php | 2 + .../DBAL/Driver/SQLAnywhere/Driver.php | 2 + .../SQLAnywhere/SQLAnywhereConnection.php | 2 + .../SQLAnywhere/SQLAnywhereException.php | 2 + .../SQLAnywhere/SQLAnywhereStatement.php | 2 + lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php | 2 + .../DBAL/Driver/SQLSrv/LastInsertId.php | 2 + .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 2 + .../DBAL/Driver/SQLSrv/SQLSrvException.php | 2 + .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 2 + .../DBAL/Driver/ServerInfoAwareConnection.php | 2 + lib/Doctrine/DBAL/Driver/Statement.php | 2 + .../DBAL/Driver/StatementIterator.php | 2 + lib/Doctrine/DBAL/DriverManager.php | 2 + .../DBAL/Event/ConnectionEventArgs.php | 2 + .../DBAL/Event/Listeners/MysqlSessionInit.php | 2 + .../Event/Listeners/OracleSessionInit.php | 2 + .../DBAL/Event/Listeners/SQLSessionInit.php | 2 + .../SchemaAlterTableAddColumnEventArgs.php | 2 + .../SchemaAlterTableChangeColumnEventArgs.php | 2 + .../DBAL/Event/SchemaAlterTableEventArgs.php | 2 + .../SchemaAlterTableRemoveColumnEventArgs.php | 2 + .../SchemaAlterTableRenameColumnEventArgs.php | 2 + .../Event/SchemaColumnDefinitionEventArgs.php | 2 + .../SchemaCreateTableColumnEventArgs.php | 2 + .../DBAL/Event/SchemaCreateTableEventArgs.php | 2 + .../DBAL/Event/SchemaDropTableEventArgs.php | 2 + lib/Doctrine/DBAL/Event/SchemaEventArgs.php | 2 + .../Event/SchemaIndexDefinitionEventArgs.php | 2 + lib/Doctrine/DBAL/Events.php | 2 + .../DBAL/Exception/ConnectionException.php | 2 + .../ConstraintViolationException.php | 2 + .../DatabaseObjectExistsException.php | 2 + .../DatabaseObjectNotFoundException.php | 2 + .../DBAL/Exception/DeadlockException.php | 2 + .../DBAL/Exception/DriverException.php | 2 + ...ForeignKeyConstraintViolationException.php | 2 + .../Exception/InvalidArgumentException.php | 2 + .../Exception/InvalidFieldNameException.php | 2 + .../Exception/LockWaitTimeoutException.php | 2 + .../Exception/NonUniqueFieldNameException.php | 2 + .../NotNullConstraintViolationException.php | 2 + .../DBAL/Exception/ReadOnlyException.php | 2 + .../DBAL/Exception/RetryableException.php | 2 + .../DBAL/Exception/ServerException.php | 2 + .../DBAL/Exception/SyntaxErrorException.php | 2 + .../DBAL/Exception/TableExistsException.php | 2 + .../DBAL/Exception/TableNotFoundException.php | 2 + .../UniqueConstraintViolationException.php | 2 + lib/Doctrine/DBAL/FetchMode.php | 2 + lib/Doctrine/DBAL/Id/TableGenerator.php | 2 + .../DBAL/Id/TableGeneratorSchemaVisitor.php | 2 + lib/Doctrine/DBAL/LockMode.php | 2 + lib/Doctrine/DBAL/Logging/DebugStack.php | 2 + lib/Doctrine/DBAL/Logging/EchoSQLLogger.php | 2 + lib/Doctrine/DBAL/Logging/LoggerChain.php | 2 + lib/Doctrine/DBAL/Logging/NullLogger.php | 2 + lib/Doctrine/DBAL/Logging/SQLLogger.php | 2 + lib/Doctrine/DBAL/ParameterType.php | 2 + .../DBAL/Platforms/AbstractPlatform.php | 2 + lib/Doctrine/DBAL/Platforms/DB2Platform.php | 2 + .../DBAL/Platforms/Keywords/DB2Keywords.php | 2 + .../DBAL/Platforms/Keywords/KeywordList.php | 2 + .../Platforms/Keywords/MariaDb102Keywords.php | 2 + .../Platforms/Keywords/MySQL57Keywords.php | 2 + .../Platforms/Keywords/MySQL80Keywords.php | 2 + .../DBAL/Platforms/Keywords/MySQLKeywords.php | 2 + .../Platforms/Keywords/OracleKeywords.php | 2 + .../Keywords/PostgreSQL94Keywords.php | 2 + .../Platforms/Keywords/PostgreSQLKeywords.php | 2 + .../Keywords/ReservedKeywordsValidator.php | 2 + .../Keywords/SQLAnywhereKeywords.php | 2 + .../Keywords/SQLServer2012Keywords.php | 2 + .../Platforms/Keywords/SQLServerKeywords.php | 2 + .../Platforms/Keywords/SQLiteKeywords.php | 2 + .../DBAL/Platforms/MariaDb1027Platform.php | 2 + .../DBAL/Platforms/MySQL57Platform.php | 2 + .../DBAL/Platforms/MySQL80Platform.php | 2 + lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 2 + .../DBAL/Platforms/OraclePlatform.php | 2 + .../DBAL/Platforms/PostgreSQL94Platform.php | 2 + .../DBAL/Platforms/PostgreSqlPlatform.php | 4 +- .../DBAL/Platforms/SQLAnywherePlatform.php | 2 + .../DBAL/Platforms/SQLAzurePlatform.php | 2 + .../DBAL/Platforms/SQLServer2012Platform.php | 2 + .../DBAL/Platforms/SQLServerPlatform.php | 2 + .../DBAL/Platforms/SqlitePlatform.php | 2 + lib/Doctrine/DBAL/Portability/Connection.php | 2 + lib/Doctrine/DBAL/Portability/Statement.php | 2 + .../Query/Expression/CompositeExpression.php | 2 + .../Query/Expression/ExpressionBuilder.php | 2 + lib/Doctrine/DBAL/Query/QueryBuilder.php | 2 + lib/Doctrine/DBAL/Query/QueryException.php | 2 + lib/Doctrine/DBAL/SQLParserUtils.php | 2 + lib/Doctrine/DBAL/SQLParserUtilsException.php | 2 + lib/Doctrine/DBAL/Schema/AbstractAsset.php | 4 +- .../DBAL/Schema/AbstractSchemaManager.php | 2 + lib/Doctrine/DBAL/Schema/Column.php | 2 + lib/Doctrine/DBAL/Schema/ColumnDiff.php | 2 + lib/Doctrine/DBAL/Schema/Comparator.php | 2 + lib/Doctrine/DBAL/Schema/Constraint.php | 2 + lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 2 + .../DBAL/Schema/ForeignKeyConstraint.php | 4 +- lib/Doctrine/DBAL/Schema/Identifier.php | 2 + lib/Doctrine/DBAL/Schema/Index.php | 6 ++- .../DBAL/Schema/MySqlSchemaManager.php | 2 + .../DBAL/Schema/OracleSchemaManager.php | 8 +++- .../DBAL/Schema/PostgreSqlSchemaManager.php | 15 ++++--- .../DBAL/Schema/SQLAnywhereSchemaManager.php | 2 + .../DBAL/Schema/SQLServerSchemaManager.php | 2 + lib/Doctrine/DBAL/Schema/Schema.php | 2 + lib/Doctrine/DBAL/Schema/SchemaConfig.php | 2 + lib/Doctrine/DBAL/Schema/SchemaDiff.php | 2 + lib/Doctrine/DBAL/Schema/SchemaException.php | 2 + lib/Doctrine/DBAL/Schema/Sequence.php | 2 + .../DBAL/Schema/SqliteSchemaManager.php | 2 + .../AbstractSchemaSynchronizer.php | 2 + .../Synchronizer/SchemaSynchronizer.php | 2 + .../SingleDatabaseSynchronizer.php | 2 + lib/Doctrine/DBAL/Schema/Table.php | 2 + lib/Doctrine/DBAL/Schema/TableDiff.php | 2 + lib/Doctrine/DBAL/Schema/UniqueConstraint.php | 2 + lib/Doctrine/DBAL/Schema/View.php | 2 + .../DBAL/Schema/Visitor/AbstractVisitor.php | 2 + .../Visitor/CreateSchemaSqlCollector.php | 2 + .../Schema/Visitor/DropSchemaSqlCollector.php | 2 + lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php | 2 + .../DBAL/Schema/Visitor/NamespaceVisitor.php | 2 + .../Schema/Visitor/RemoveNamespacedAssets.php | 2 + .../DBAL/Schema/Visitor/SchemaDiffVisitor.php | 2 + lib/Doctrine/DBAL/Schema/Visitor/Visitor.php | 2 + .../DBAL/Sharding/PoolingShardConnection.php | 2 + .../DBAL/Sharding/PoolingShardManager.php | 2 + .../SQLAzureFederationsSynchronizer.php | 2 + .../SQLAzure/SQLAzureShardManager.php | 2 + .../SQLAzure/Schema/MultiTenantVisitor.php | 2 + .../ShardChoser/MultiTenantShardChoser.php | 2 + .../DBAL/Sharding/ShardChoser/ShardChoser.php | 2 + lib/Doctrine/DBAL/Sharding/ShardManager.php | 2 + .../DBAL/Sharding/ShardingException.php | 2 + lib/Doctrine/DBAL/Statement.php | 2 + .../Console/Command/ReservedWordsCommand.php | 2 + .../Tools/Console/Command/RunSqlCommand.php | 2 + .../DBAL/Tools/Console/ConsoleRunner.php | 2 + .../Tools/Console/Helper/ConnectionHelper.php | 2 + lib/Doctrine/DBAL/Tools/Dumper.php | 8 ++-- lib/Doctrine/DBAL/Types/ArrayType.php | 2 + lib/Doctrine/DBAL/Types/BigIntType.php | 2 + lib/Doctrine/DBAL/Types/BinaryType.php | 2 + lib/Doctrine/DBAL/Types/BlobType.php | 2 + lib/Doctrine/DBAL/Types/BooleanType.php | 2 + .../DBAL/Types/ConversionException.php | 11 +++-- lib/Doctrine/DBAL/Types/DateImmutableType.php | 2 + lib/Doctrine/DBAL/Types/DateIntervalType.php | 2 + .../DBAL/Types/DateTimeImmutableType.php | 2 + lib/Doctrine/DBAL/Types/DateTimeType.php | 2 + .../DBAL/Types/DateTimeTzImmutableType.php | 2 + lib/Doctrine/DBAL/Types/DateTimeTzType.php | 2 + lib/Doctrine/DBAL/Types/DateType.php | 2 + lib/Doctrine/DBAL/Types/DecimalType.php | 2 + lib/Doctrine/DBAL/Types/FloatType.php | 2 + lib/Doctrine/DBAL/Types/GuidType.php | 2 + lib/Doctrine/DBAL/Types/IntegerType.php | 2 + lib/Doctrine/DBAL/Types/JsonArrayType.php | 2 + lib/Doctrine/DBAL/Types/JsonType.php | 2 + lib/Doctrine/DBAL/Types/ObjectType.php | 2 + .../DBAL/Types/PhpDateTimeMappingType.php | 2 + .../DBAL/Types/PhpIntegerMappingType.php | 2 + lib/Doctrine/DBAL/Types/SimpleArrayType.php | 2 + lib/Doctrine/DBAL/Types/SmallIntType.php | 2 + lib/Doctrine/DBAL/Types/StringType.php | 2 + lib/Doctrine/DBAL/Types/TextType.php | 2 + lib/Doctrine/DBAL/Types/TimeImmutableType.php | 2 + lib/Doctrine/DBAL/Types/TimeType.php | 2 + lib/Doctrine/DBAL/Types/Type.php | 2 + .../DBAL/Types/VarDateTimeImmutableType.php | 2 + lib/Doctrine/DBAL/Types/VarDateTimeType.php | 2 + .../DBAL/VersionAwarePlatformDriver.php | 2 + phpcs.xml.dist | 7 ++- .../DBAL/Cache/QueryCacheProfileTest.php | 2 + .../Doctrine/Tests/DBAL/ConfigurationTest.php | 2 + tests/Doctrine/Tests/DBAL/ConnectionTest.php | 2 + .../Doctrine/Tests/DBAL/DBALExceptionTest.php | 2 + .../DBAL/Driver/AbstractDB2DriverTest.php | 2 + .../Tests/DBAL/Driver/AbstractDriverTest.php | 4 +- .../DBAL/Driver/AbstractMySQLDriverTest.php | 2 + .../EasyConnectStringTest.php | 2 + .../DBAL/Driver/AbstractOracleDriverTest.php | 2 + .../Driver/AbstractPostgreSQLDriverTest.php | 2 + .../Driver/AbstractSQLAnywhereDriverTest.php | 2 + .../Driver/AbstractSQLServerDriverTest.php | 2 + .../DBAL/Driver/AbstractSQLiteDriverTest.php | 2 + .../DBAL/Driver/IBMDB2/DB2ConnectionTest.php | 2 + .../DBAL/Driver/IBMDB2/DB2DriverTest.php | 2 + .../Tests/DBAL/Driver/Mysqli/DriverTest.php | 2 + .../Driver/Mysqli/MysqliConnectionTest.php | 2 + .../Tests/DBAL/Driver/OCI8/DriverTest.php | 2 + .../DBAL/Driver/OCI8/OCI8ConnectionTest.php | 2 + .../DBAL/Driver/OCI8/OCI8StatementTest.php | 17 +++++-- .../Tests/DBAL/Driver/PDOExceptionTest.php | 2 + .../Tests/DBAL/Driver/PDOMySql/DriverTest.php | 2 + .../DBAL/Driver/PDOOracle/DriverTest.php | 2 + .../Tests/DBAL/Driver/PDOPgSql/DriverTest.php | 2 + .../DBAL/Driver/PDOSqlite/DriverTest.php | 2 + .../DBAL/Driver/PDOSqlsrv/DriverTest.php | 2 + .../DBAL/Driver/SQLAnywhere/DriverTest.php | 2 + .../SQLAnywhere/SQLAnywhereConnectionTest.php | 2 + .../Tests/DBAL/Driver/SQLSrv/DriverTest.php | 2 + .../Driver/SQLSrv/SQLSrvConnectionTest.php | 2 + .../DBAL/Driver/StatementIteratorTest.php | 2 + .../Doctrine/Tests/DBAL/DriverManagerTest.php | 2 + .../DBAL/Events/MysqlSessionInitTest.php | 2 + .../DBAL/Events/OracleSessionInitTest.php | 2 + .../Tests/DBAL/Events/SQLSessionInitTest.php | 2 + .../InvalidArgumentExceptionTest.php | 2 + .../Tests/DBAL/Functional/BlobTest.php | 2 + .../Tests/DBAL/Functional/ConnectionTest.php | 2 + .../Tests/DBAL/Functional/DataAccessTest.php | 10 +++-- .../Functional/Driver/AbstractDriverTest.php | 2 + .../Driver/IBMDB2/DB2DriverTest.php | 2 + .../Driver/Mysqli/ConnectionTest.php | 4 +- .../Functional/Driver/Mysqli/DriverTest.php | 2 + .../Functional/Driver/OCI8/DriverTest.php | 2 + .../Driver/OCI8/OCI8ConnectionTest.php | 2 + .../Functional/Driver/OCI8/StatementTest.php | 2 + .../Functional/Driver/PDOConnectionTest.php | 2 + .../Functional/Driver/PDOMySql/DriverTest.php | 2 + .../Driver/PDOOracle/DriverTest.php | 2 + .../Functional/Driver/PDOPgSql/DriverTest.php | 2 + .../Driver/PDOPgsqlConnectionTest.php | 2 + .../Driver/PDOSqlite/DriverTest.php | 2 + .../Driver/PDOSqlsrv/DriverTest.php | 2 + .../Driver/SQLAnywhere/ConnectionTest.php | 2 + .../Driver/SQLAnywhere/DriverTest.php | 2 + .../Driver/SQLAnywhere/StatementTest.php | 2 + .../Functional/Driver/SQLSrv/DriverTest.php | 2 + .../Driver/SQLSrv/StatementTest.php | 2 + .../Tests/DBAL/Functional/ExceptionTest.php | 2 + .../Functional/LikeWildcardsEscapingTest.php | 2 + .../Tests/DBAL/Functional/LoggingTest.php | 2 + .../Functional/MasterSlaveConnectionTest.php | 2 + .../DBAL/Functional/ModifyLimitQueryTest.php | 2 + .../DBAL/Functional/NamedParametersTest.php | 2 + .../DBAL/Functional/PDOStatementTest.php | 2 + .../Platform/DateExpressionTest.php | 2 + ...imaryKeyWithNewAutoIncrementColumnTest.php | 2 + .../DBAL/Functional/Platform/QuotingTest.php | 2 + .../Tests/DBAL/Functional/PortabilityTest.php | 2 + .../Tests/DBAL/Functional/ResultCacheTest.php | 2 + .../Schema/Db2SchemaManagerTest.php | 2 + .../Schema/MySqlSchemaManagerTest.php | 2 + .../Schema/OracleSchemaManagerTest.php | 2 + .../Schema/PostgreSqlSchemaManagerTest.php | 4 +- .../Schema/SQLAnywhereSchemaManagerTest.php | 2 + .../Schema/SQLServerSchemaManagerTest.php | 2 + .../SchemaManagerFunctionalTestCase.php | 2 + .../Schema/SqliteSchemaManagerTest.php | 4 +- .../Tests/DBAL/Functional/StatementTest.php | 4 +- .../DBAL/Functional/TableGeneratorTest.php | 2 + .../DBAL/Functional/TemporaryTableTest.php | 2 + .../DBAL/Functional/Ticket/DBAL168Test.php | 2 + .../DBAL/Functional/Ticket/DBAL202Test.php | 2 + .../DBAL/Functional/Ticket/DBAL461Test.php | 2 + .../DBAL/Functional/Ticket/DBAL510Test.php | 2 + .../DBAL/Functional/Ticket/DBAL630Test.php | 2 + .../DBAL/Functional/Ticket/DBAL752Test.php | 2 + .../DBAL/Functional/TypeConversionTest.php | 2 + .../Tests/DBAL/Functional/WriteTest.php | 2 + .../Tests/DBAL/Logging/DebugStackTest.php | 2 + .../TypeConversionPerformanceTest.php | 2 + .../AbstractMySQLPlatformTestCase.php | 2 + .../Platforms/AbstractPlatformTestCase.php | 14 +++--- .../AbstractPostgreSqlPlatformTestCase.php | 6 ++- .../AbstractSQLServerPlatformTestCase.php | 2 + .../Tests/DBAL/Platforms/DB2PlatformTest.php | 41 ++++++++--------- .../Platforms/MariaDb1027PlatformTest.php | 2 + .../DBAL/Platforms/MySQL57PlatformTest.php | 2 + .../DBAL/Platforms/MySqlPlatformTest.php | 2 + .../DBAL/Platforms/OraclePlatformTest.php | 2 + .../Platforms/PostgreSQL94PlatformTest.php | 2 + .../DBAL/Platforms/PostgreSqlPlatformTest.php | 2 + .../ReservedKeywordsValidatorTest.php | 2 + .../Platforms/SQLAnywherePlatformTest.php | 45 ++++++++++--------- .../DBAL/Platforms/SQLAzurePlatformTest.php | 2 + .../Platforms/SQLServer2012PlatformTest.php | 2 + .../DBAL/Platforms/SQLServerPlatformTest.php | 2 + .../DBAL/Platforms/SqlitePlatformTest.php | 8 ++-- .../Tests/DBAL/Portability/StatementTest.php | 2 + .../Expression/CompositeExpressionTest.php | 2 + .../Expression/ExpressionBuilderTest.php | 2 + .../Tests/DBAL/Query/QueryBuilderTest.php | 2 + .../Tests/DBAL/SQLParserUtilsTest.php | 2 + .../Tests/DBAL/Schema/ColumnDiffTest.php | 2 + .../Doctrine/Tests/DBAL/Schema/ColumnTest.php | 2 + .../Tests/DBAL/Schema/ComparatorTest.php | 2 + .../DBAL/Schema/DB2SchemaManagerTest.php | 2 + .../DBAL/Schema/ForeignKeyConstraintTest.php | 2 + .../Doctrine/Tests/DBAL/Schema/IndexTest.php | 2 + .../DBAL/Schema/MySqlSchemaManagerTest.php | 2 + .../DBAL/Schema/Platforms/MySQLSchemaTest.php | 2 + .../Tests/DBAL/Schema/SchemaDiffTest.php | 2 + .../Doctrine/Tests/DBAL/Schema/SchemaTest.php | 2 + .../Tests/DBAL/Schema/SequenceTest.php | 2 + .../DBAL/Schema/SqliteSchemaManagerTest.php | 2 + .../SingleDatabaseSynchronizerTest.php | 2 + .../Tests/DBAL/Schema/TableDiffTest.php | 2 + .../Doctrine/Tests/DBAL/Schema/TableTest.php | 2 + .../Visitor/CreateSchemaSqlCollectorTest.php | 2 + .../Visitor/DropSchemaSqlCollectorTest.php | 2 + .../Visitor/RemoveNamespacedAssetsTest.php | 2 + .../Schema/Visitor/SchemaSqlCollectorTest.php | 2 + .../Sharding/PoolingShardConnectionTest.php | 2 + .../DBAL/Sharding/PoolingShardManagerTest.php | 2 + .../Sharding/SQLAzure/AbstractTestCase.php | 2 + .../DBAL/Sharding/SQLAzure/FunctionalTest.php | 2 + .../SQLAzure/MultiTenantVisitorTest.php | 2 + .../SQLAzureFederationsSynchronizerTest.php | 2 + .../SQLAzure/SQLAzureShardManagerTest.php | 2 + .../MultiTenantShardChoserTest.php | 2 + tests/Doctrine/Tests/DBAL/StatementTest.php | 2 + .../DBAL/Tools/Console/RunSqlCommandTest.php | 2 + .../Doctrine/Tests/DBAL/Tools/DumperTest.php | 2 + .../Tests/DBAL/Tools/TestAsset/ChildClass.php | 2 + .../ChildWithSameAttributesClass.php | 2 + .../DBAL/Tools/TestAsset/ParentClass.php | 2 + tests/Doctrine/Tests/DBAL/Types/ArrayTest.php | 2 + .../Tests/DBAL/Types/BaseDateTypeTestCase.php | 2 + .../Doctrine/Tests/DBAL/Types/BinaryTest.php | 2 + tests/Doctrine/Tests/DBAL/Types/BlobTest.php | 2 + .../Doctrine/Tests/DBAL/Types/BooleanTest.php | 2 + .../DBAL/Types/ConversionExceptionTest.php | 2 + .../DBAL/Types/DateImmutableTypeTest.php | 2 + .../Tests/DBAL/Types/DateIntervalTest.php | 2 + tests/Doctrine/Tests/DBAL/Types/DateTest.php | 2 + .../DBAL/Types/DateTimeImmutableTypeTest.php | 4 ++ .../Tests/DBAL/Types/DateTimeTest.php | 2 + .../Types/DateTimeTzImmutableTypeTest.php | 4 ++ .../Tests/DBAL/Types/DateTimeTzTest.php | 2 + .../Doctrine/Tests/DBAL/Types/DecimalTest.php | 2 + tests/Doctrine/Tests/DBAL/Types/FloatTest.php | 2 + .../Tests/DBAL/Types/GuidTypeTest.php | 2 + .../Doctrine/Tests/DBAL/Types/IntegerTest.php | 2 + .../Tests/DBAL/Types/JsonArrayTest.php | 2 + tests/Doctrine/Tests/DBAL/Types/JsonTest.php | 2 + .../Doctrine/Tests/DBAL/Types/ObjectTest.php | 2 + .../Tests/DBAL/Types/SmallIntTest.php | 2 + .../Doctrine/Tests/DBAL/Types/StringTest.php | 2 + .../DBAL/Types/TimeImmutableTypeTest.php | 2 + tests/Doctrine/Tests/DBAL/Types/TimeTest.php | 2 + .../Types/VarDateTimeImmutableTypeTest.php | 2 + .../Tests/DBAL/Types/VarDateTimeTest.php | 8 +++- tests/Doctrine/Tests/DBAL/UtilTest.php | 2 + .../Doctrine/Tests/DbalFunctionalTestCase.php | 2 + .../Tests/DbalPerformanceTestCase.php | 2 + .../Tests/DbalPerformanceTestListener.php | 2 + tests/Doctrine/Tests/DbalTestCase.php | 2 + .../Tests/Mocks/DriverResultStatementMock.php | 2 + .../Tests/Mocks/DriverStatementMock.php | 2 + .../Mocks/ServerInfoAwareConnectionMock.php | 2 + .../Mocks/VersionAwarePlatformDriverMock.php | 2 + tests/Doctrine/Tests/TestUtil.php | 6 ++- tests/Doctrine/Tests/Types/CommentedType.php | 2 + tests/Doctrine/Tests/Types/MySqlPointType.php | 2 + 409 files changed, 945 insertions(+), 97 deletions(-) diff --git a/bin/doctrine-dbal.php b/bin/doctrine-dbal.php index f3e064ffd62..76bed1a6701 100644 --- a/bin/doctrine-dbal.php +++ b/bin/doctrine-dbal.php @@ -1,5 +1,7 @@ conn = mysqli_init(); diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php index 1fa0c900fbd..b779bc40457 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php @@ -1,5 +1,7 @@ dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; @@ -192,7 +194,7 @@ public function commit() : void public function rollBack() : void { if (! oci_rollback($this->dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php index af3a9d1a7a9..bdb64347a6a 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php @@ -1,5 +1,7 @@ convertParameterType($type) )) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->_sth)); } } @@ -388,7 +390,7 @@ public function execute($params = null) : void $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode()); if (! $ret) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->_sth)); } $this->result = true; diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index d9cbb681c8c..bc9128e1eb3 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -1,5 +1,7 @@ convertParamType($type); + $type = $this->convertParamType($type); + $extraParameters = array_slice(func_get_args(), 3); + + if (count($extraParameters) !== 0) { + $extraParameters[0] = $extraParameters[0] ?? 0; + } try { - $this->stmt->bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); + $this->stmt->bindParam($column, $variable, $type, ...$extraParameters); } catch (\PDOException $exception) { throw new PDOException($exception); } diff --git a/lib/Doctrine/DBAL/Driver/PingableConnection.php b/lib/Doctrine/DBAL/Driver/PingableConnection.php index 06bfb9a7f26..93e6168013e 100644 --- a/lib/Doctrine/DBAL/Driver/PingableConnection.php +++ b/lib/Doctrine/DBAL/Driver/PingableConnection.php @@ -1,5 +1,7 @@ booleanLiterals['false'], true)) { + if (in_array($item, $this->booleanLiterals['false'], true)) { return false; } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 36714143b85..691d72ea908 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1,5 +1,7 @@ _namespace . '.' . $this->_name; } - return $this->_name; + return $this->_name ?? ''; } /** diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 46fbff6da30..a3edcdb2206 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -1,5 +1,7 @@ _setName($indexName); + if ($indexName !== null) { + $this->_setName($indexName); + } $this->_isUnique = $isUnique; $this->_isPrimary = $isPrimary; diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index b39db01ffaa..ba140a6b4d7 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -1,5 +1,7 @@ _platform->hasDoctrineTypeMappingFor($tableColumn['type'])) { + if ($tableColumn['domain_type'] !== null + && strlen($tableColumn['domain_type']) + && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type']) + ) { $dbType = strtolower($tableColumn['domain_type']); $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; } @@ -473,7 +478,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) */ private function fixVersion94NegativeNumericDefaultValue($defaultValue) { - if (strpos($defaultValue, '(') === 0) { + if ($defaultValue !== null && strpos($defaultValue, '(') === 0) { return trim($defaultValue, '()'); } diff --git a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php index 0d875491167..b99d68429e0 100644 --- a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php @@ -1,5 +1,7 @@ 32 ? substr($value, 0, 20) . '...' : $value; + $value = is_string($value) && strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType); } @@ -37,7 +40,7 @@ public static function conversionFailed($value, $toType) * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement * about the expected format. * - * @param string $value + * @param mixed $value * @param string $toType * @param string $expectedFormat * @@ -45,7 +48,7 @@ public static function conversionFailed($value, $toType) */ public static function conversionFailedFormat($value, $toType, $expectedFormat, ?Throwable $previous = null) { - $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; + $value = is_string($value) && strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; return new self( 'Could not convert database value "' . $value . '" to Doctrine Type ' . diff --git a/lib/Doctrine/DBAL/Types/DateImmutableType.php b/lib/Doctrine/DBAL/Types/DateImmutableType.php index a4c5d266d92..e824513a5b7 100644 --- a/lib/Doctrine/DBAL/Types/DateImmutableType.php +++ b/lib/Doctrine/DBAL/Types/DateImmutableType.php @@ -1,5 +1,7 @@ tests - @@ -65,4 +64,10 @@ lib/Doctrine/DBAL/Schema/Comparator.php + + + + lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php + diff --git a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php index 2a8fe528c9d..6722f68c372 100644 --- a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php +++ b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php @@ -1,5 +1,7 @@ errorCode = $errorCode; $this->sqlState = $sqlState; diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php index cde381653a9..81140b97754 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php @@ -1,5 +1,7 @@ disableOriginalConstructor() ->getMock(); $conn->expects($this->once()) - ->method('getExecuteMode'); + ->method('getExecuteMode') + ->willReturn(OCI_NO_AUTO_COMMIT); + + $connectionReflection = new ReflectionProperty($statement, '_conn'); + $connectionReflection->setAccessible(true); + $connectionReflection->setValue($statement, $conn); - $reflProperty = new ReflectionProperty($statement, '_conn'); - $reflProperty->setAccessible(true); - $reflProperty->setValue($statement, $conn); + $handleReflection = new ReflectionProperty($statement, '_sth'); + $handleReflection->setAccessible(true); + $handleReflection->setValue($statement, fopen('php://temp', 'r')); $this->expectException(OCI8Exception::class); $statement->execute($params); diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php index c7564470252..08b69ee253d 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php @@ -1,5 +1,7 @@ getLocateExpression("'foo'", 'test_string') . ' AS locate5, '; $sql .= $platform->getLocateExpression("'barfoobaz'", 'test_string') . ' AS locate6, '; $sql .= $platform->getLocateExpression("'bar'", 'test_string') . ' AS locate7, '; - $sql .= $platform->getLocateExpression('test_string', "'oo'", 2) . ' AS locate8, '; - $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) . ' AS locate9 '; + $sql .= $platform->getLocateExpression('test_string', "'oo'", '2') . ' AS locate8, '; + $sql .= $platform->getLocateExpression('test_string', "'oo'", '3') . ' AS locate9 '; $sql .= 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); @@ -1012,8 +1014,8 @@ public function testBitComparisonExpressionSupport() $sql[] = 'SELECT '; $sql[] = 'test_int, '; $sql[] = 'test_string, '; - $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, '; - $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and '; + $sql[] = $platform->getBitOrComparisonExpression('test_int', '2') . ' AS bit_or, '; + $sql[] = $platform->getBitAndComparisonExpression('test_int', '2') . ' AS bit_and '; $sql[] = 'FROM fetch_table'; $stmt = $this->connection->executeQuery(implode(PHP_EOL, $sql)); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php index 2e145ca6c04..0770cf7f5ae 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php @@ -1,5 +1,7 @@ $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], - 'port' => $GLOBALS['db_port'], + 'port' => (int) $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php index a7b7338beed..ca0f5fd49c7 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php @@ -1,5 +1,7 @@ schemaManager->listTableColumns('test_jsonb'); self::assertSame($type, $columns['foo']->getType()->getName()); - self::assertTrue(true, $columns['foo']->getPlatformOption('jsonb')); + self::assertTrue($columns['foo']->getPlatformOption('jsonb')); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php index 73eb07ea178..b70a3d6cce4 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php @@ -1,5 +1,7 @@ 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false] ), diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php index 23119f734f0..58bd96db631 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php @@ -1,5 +1,7 @@ iniSet('error_reporting', 0); + $this->iniSet('error_reporting', '0'); self::expectException(DBALException::class); $stmt->execute([null]); diff --git a/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php b/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php index a6721b88f8d..7897572e84c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php @@ -1,5 +1,7 @@ platform->getBitAndComparisonExpression(2, 4); - self::assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql); + $sql = $this->platform->getBitAndComparisonExpression('2', '4'); + self::assertEquals($this->getBitAndComparisonExpressionSql('2', '4'), $sql); } - protected function getBitOrComparisonExpressionSql($value1, $value2) + protected function getBitOrComparisonExpressionSql(string $value1, string $value2) { return '(' . $value1 . ' | ' . $value2 . ')'; } @@ -297,8 +299,8 @@ protected function getBitOrComparisonExpressionSql($value1, $value2) */ public function testGeneratesBitOrComparisonExpressionSql() { - $sql = $this->platform->getBitOrComparisonExpression(2, 4); - self::assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql); + $sql = $this->platform->getBitOrComparisonExpression('2', '4'); + self::assertEquals($this->getBitOrComparisonExpressionSql('2', '4'), $sql); } public function getGenerateConstraintUniqueIndexSql() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php index 81d760e30b6..ed31a21fffc 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php @@ -1,5 +1,7 @@ platform->getRegexpExpression(), 'Regular expression operator is not correct'); self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); - self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); - self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', 1, 5), 'Substring expression with length is not correct'); + self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct'); + self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', '1', '5'), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index f06834913eb..214fc45e42e 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -1,5 +1,7 @@ platform->getDropDatabaseSQL('foobar')); self::assertEquals('DECLARE GLOBAL TEMPORARY TABLE', $this->platform->getCreateTemporaryTableSnippetSQL()); self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar')); - self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); @@ -314,28 +315,28 @@ public function testGeneratesSQLSnippets() self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); - self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); - self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); - self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' + (5 * 3) MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' + (3 * 7) DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); + self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", '4')); + self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", '12')); + self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", '102')); + self::assertEquals("'1987/05/02' + (5 * 3) MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("'1987/05/02' + (3 * 7) DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", '10')); self::assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); - self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); - self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); - self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' - (5 * 3) MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' - (3 * 7) DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); + self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", '4')); + self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", '12')); + self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", '102')); + self::assertEquals("'1987/05/02' - (5 * 3) MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("'1987/05/02' - (3 * 7) DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", '10')); self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); - self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5)); - self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); + self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', '1')); + self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', '5')); + self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', '5', '2')); } public function testModifiesLimitQuery() diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php index 0903a511612..508446e3107 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php @@ -1,5 +1,7 @@ platform->getStopDatabaseSQL('"foobar"')); self::assertEquals('STOP DATABASE "create" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('create')); self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar')); - self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); @@ -361,12 +362,12 @@ public function testGeneratesUniqueConstraintDeclarationSQL() 'CONSTRAINT unique_constraint UNIQUE CLUSTERED (a, b)', $this->platform->getUniqueConstraintDeclarationSQL( 'unique_constraint', - new UniqueConstraint(null, ['a', 'b'], ['clustered']) + new UniqueConstraint('', ['a', 'b'], ['clustered']) ) ); self::assertEquals( 'CONSTRAINT UNIQUE (a, b)', - $this->platform->getUniqueConstraintDeclarationSQL(null, new UniqueConstraint(null, ['a', 'b'])) + $this->platform->getUniqueConstraintDeclarationSQL('', new UniqueConstraint('', ['a', 'b'])) ); } @@ -615,31 +616,31 @@ public function testGeneratesSQLSnippets() self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); - self::assertEquals("DATEADD(DAY, 4, '1987/05/02')", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); - self::assertEquals("DATEADD(HOUR, 12, '1987/05/02')", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); - self::assertEquals("DATEADD(MINUTE, 2, '1987/05/02')", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("DATEADD(MONTH, 102, '1987/05/02')", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); - self::assertEquals("DATEADD(QUARTER, 5, '1987/05/02')", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("DATEADD(SECOND, 1, '1987/05/02')", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("DATEADD(WEEK, 3, '1987/05/02')", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("DATEADD(YEAR, 10, '1987/05/02')", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); + self::assertEquals("DATEADD(DAY, 4, '1987/05/02')", $this->platform->getDateAddDaysExpression("'1987/05/02'", '4')); + self::assertEquals("DATEADD(HOUR, 12, '1987/05/02')", $this->platform->getDateAddHourExpression("'1987/05/02'", '12')); + self::assertEquals("DATEADD(MINUTE, 2, '1987/05/02')", $this->platform->getDateAddMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("DATEADD(MONTH, 102, '1987/05/02')", $this->platform->getDateAddMonthExpression("'1987/05/02'", '102')); + self::assertEquals("DATEADD(QUARTER, 5, '1987/05/02')", $this->platform->getDateAddQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("DATEADD(SECOND, 1, '1987/05/02')", $this->platform->getDateAddSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("DATEADD(WEEK, 3, '1987/05/02')", $this->platform->getDateAddWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("DATEADD(YEAR, 10, '1987/05/02')", $this->platform->getDateAddYearsExpression("'1987/05/02'", '10')); self::assertEquals("DATEDIFF(day, '1987/04/01', '1987/05/02')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); - self::assertEquals("DATEADD(DAY, -1 * 4, '1987/05/02')", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); - self::assertEquals("DATEADD(HOUR, -1 * 12, '1987/05/02')", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); - self::assertEquals("DATEADD(MINUTE, -1 * 2, '1987/05/02')", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("DATEADD(MONTH, -1 * 102, '1987/05/02')", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); - self::assertEquals("DATEADD(QUARTER, -1 * 5, '1987/05/02')", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("DATEADD(SECOND, -1 * 1, '1987/05/02')", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("DATEADD(WEEK, -1 * 3, '1987/05/02')", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("DATEADD(YEAR, -1 * 10, '1987/05/02')", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); + self::assertEquals("DATEADD(DAY, -1 * 4, '1987/05/02')", $this->platform->getDateSubDaysExpression("'1987/05/02'", '4')); + self::assertEquals("DATEADD(HOUR, -1 * 12, '1987/05/02')", $this->platform->getDateSubHourExpression("'1987/05/02'", '12')); + self::assertEquals("DATEADD(MINUTE, -1 * 2, '1987/05/02')", $this->platform->getDateSubMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("DATEADD(MONTH, -1 * 102, '1987/05/02')", $this->platform->getDateSubMonthExpression("'1987/05/02'", '102')); + self::assertEquals("DATEADD(QUARTER, -1 * 5, '1987/05/02')", $this->platform->getDateSubQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("DATEADD(SECOND, -1 * 1, '1987/05/02')", $this->platform->getDateSubSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("DATEADD(WEEK, -1 * 3, '1987/05/02')", $this->platform->getDateSubWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("DATEADD(YEAR, -1 * 10, '1987/05/02')", $this->platform->getDateSubYearsExpression("'1987/05/02'", '10')); self::assertEquals('Y-m-d H:i:s.u', $this->platform->getDateTimeFormatString()); self::assertEquals('H:i:s.u', $this->platform->getTimeFormatString()); self::assertEquals('', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(string_column, substring_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); + self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', '1')); self::assertEquals("HASH(column, 'MD5')", $this->platform->getMd5Expression('column')); - self::assertEquals('SUBSTRING(column, 5)', $this->platform->getSubstringExpression('column', 5)); - self::assertEquals('SUBSTRING(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); + self::assertEquals('SUBSTRING(column, 5)', $this->platform->getSubstringExpression('column', '5')); + self::assertEquals('SUBSTRING(column, 5, 2)', $this->platform->getSubstringExpression('column', '5', '2')); self::assertEquals('GLOBAL TEMPORARY', $this->platform->getTemporaryTableSQL()); self::assertEquals( 'LTRIM(column)', diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php index 8aa6bc0cda3..ae993b67fd9 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php @@ -1,5 +1,7 @@ platform->getRegexpExpression(), 'Regular expression operator is not correct'); - self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); - self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); + self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct'); + self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', '0', '5'), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() @@ -766,7 +768,7 @@ public function testQuotesTableNameInListTableForeignKeysSQL() public function testDateAddStaticNumberOfDays() { - self::assertSame("DATETIME(rentalBeginsOn,'+' || 12 || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12)); + self::assertSame("DATETIME(rentalBeginsOn,'+' || 12 || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', '12')); } public function testDateAddNumberOfDaysFromColumn() diff --git a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php index 622e030c245..2477efcd4d3 100644 --- a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php @@ -1,5 +1,7 @@ platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); + $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid datetime string', $this->platform->reveal()); diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php index 615c14d584d..923f22151b4 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php @@ -1,5 +1,7 @@ platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); + $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform->reveal()); diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php index 419974c6b09..7407c70beb3 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php @@ -1,5 +1,7 @@ platform = $this->createMock(AbstractPlatform::class); + $this->platform->expects($this->any()) + ->method('getDateTimeFormatString') + ->will($this->returnValue('U')); + if (! Type::hasType('vardatetime')) { Type::addType('vardatetime', VarDateTimeType::class); } @@ -31,7 +37,7 @@ public function testDateTimeConvertsToDatabaseValue() { $date = new DateTime('1985-09-01 10:10:10'); - $expected = $date->format($this->platform->getDateTimeTzFormatString()); + $expected = $date->format($this->platform->getDateTimeFormatString()); $actual = $this->type->convertToDatabaseValue($date, $this->platform); self::assertEquals($expected, $actual); diff --git a/tests/Doctrine/Tests/DBAL/UtilTest.php b/tests/Doctrine/Tests/DBAL/UtilTest.php index e7800fceba3..6bec241c483 100644 --- a/tests/Doctrine/Tests/DBAL/UtilTest.php +++ b/tests/Doctrine/Tests/DBAL/UtilTest.php @@ -1,5 +1,7 @@ $GLOBALS['tmpdb_password'], 'host' => $GLOBALS['tmpdb_host'], 'dbname' => null, - 'port' => $GLOBALS['tmpdb_port'], + 'port' => (int) $GLOBALS['tmpdb_port'], ]; if (isset($GLOBALS['tmpdb_name'])) { @@ -177,7 +179,7 @@ private static function getParamsForMainConnection() 'password' => $GLOBALS['db_password'], 'host' => $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], - 'port' => $GLOBALS['db_port'], + 'port' => (int) $GLOBALS['db_port'], ]; if (isset($GLOBALS['db_server'])) { diff --git a/tests/Doctrine/Tests/Types/CommentedType.php b/tests/Doctrine/Tests/Types/CommentedType.php index cbe98b2324b..0b02bcef995 100644 --- a/tests/Doctrine/Tests/Types/CommentedType.php +++ b/tests/Doctrine/Tests/Types/CommentedType.php @@ -1,5 +1,7 @@ Date: Fri, 29 Mar 2019 19:19:06 -0700 Subject: [PATCH 62/66] Removed DB2SchemaManager::_getPortableForeignKeyRuleDef() --- UPGRADE.md | 4 ++++ lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 16 ---------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 1e2a9257f1e..8854436282e 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `DB2SchemaManager::_getPortableForeignKeyRuleDef()` removed + +The method was used internally and is no longer needed. + ## BC BREAK `AbstractPlatform::get*Expression()` methods no loner accept integer values as arguments The following methods' arguments do not longer accept integer value: diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index ba6048a092b..534e7d6dc66 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -175,22 +175,6 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) return parent::_getPortableTableForeignKeysList($foreignKeys); } - /** - * {@inheritdoc} - */ - protected function _getPortableForeignKeyRuleDef($def) - { - if ($def === 'C') { - return 'CASCADE'; - } - - if ($def === 'N') { - return 'SET NULL'; - } - - return null; - } - /** * {@inheritdoc} */ From b0a8ab0bed0a91e142e74144b00f7ede63f38b96 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 4 Apr 2019 18:34:27 -0700 Subject: [PATCH 63/66] Reworking driver exceptions --- UPGRADE.md | 8 ++ .../DBAL/Driver/AbstractDriverException.php | 32 ++---- .../DBAL/Driver/AbstractMySQLDriver.php | 106 +++++++++--------- .../DBAL/Driver/AbstractOracleDriver.php | 32 +++--- .../DBAL/Driver/AbstractPostgreSQLDriver.php | 15 +-- .../DBAL/Driver/AbstractSQLAnywhereDriver.php | 44 ++++---- lib/Doctrine/DBAL/Driver/DriverException.php | 21 +--- .../DBAL/Driver/IBMDB2/DB2Connection.php | 17 ++- .../DBAL/Driver/IBMDB2/DB2Exception.php | 27 +++++ .../DBAL/Driver/IBMDB2/DB2Statement.php | 4 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 19 +--- .../DBAL/Driver/Mysqli/MysqliException.php | 11 ++ .../DBAL/Driver/Mysqli/MysqliStatement.php | 14 +-- .../DBAL/Driver/OCI8/OCI8Exception.php | 4 +- lib/Doctrine/DBAL/Driver/PDOException.php | 46 ++------ lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php | 2 +- lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php | 2 +- lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 2 +- lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 2 +- .../SQLAnywhere/SQLAnywhereException.php | 7 +- .../DBAL/Driver/SQLSrv/SQLSrvException.php | 16 ++- .../DBAL/Exception/DriverException.php | 51 ++------- .../DBAL/Schema/OracleSchemaManager.php | 2 +- .../DBAL/Schema/SQLServerSchemaManager.php | 2 +- .../Doctrine/Tests/DBAL/DBALExceptionTest.php | 9 +- .../Tests/DBAL/Driver/AbstractDriverTest.php | 36 ++---- .../DBAL/Driver/AbstractMySQLDriverTest.php | 100 ++++++++--------- .../DBAL/Driver/AbstractOracleDriverTest.php | 26 ++--- .../Driver/AbstractPostgreSQLDriverTest.php | 22 ++-- .../Driver/AbstractSQLAnywhereDriverTest.php | 40 +++---- .../DBAL/Driver/AbstractSQLiteDriverTest.php | 24 ++-- .../Tests/DBAL/Driver/PDOExceptionTest.php | 11 +- .../Tests/DBAL/Functional/WriteTest.php | 2 +- 33 files changed, 330 insertions(+), 426 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 8854436282e..fe6b3ff1b1f 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,13 @@ # Upgrade to 3.0 +## BC BREAK Changes in driver exceptions + +1. The `Doctrine\DBAL\Driver\DriverException::getErrorCode()` method is removed. In order to obtain the driver error code, please use `::getCode()`. +2. `Doctrine\DBAL\Driver\PDOException` no longer extends `PDOException`. +3. The value returned by `Doctrine\DBAL\Driver\PDOException::getSQLState()` no longer falls back to the driver error code. + +The method was used internally and is no longer needed. + ## BC BREAK `DB2SchemaManager::_getPortableForeignKeyRuleDef()` removed The method was used internally and is no longer needed. diff --git a/lib/Doctrine/DBAL/Driver/AbstractDriverException.php b/lib/Doctrine/DBAL/Driver/AbstractDriverException.php index 59c08090a4c..5f217f22dc2 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractDriverException.php +++ b/lib/Doctrine/DBAL/Driver/AbstractDriverException.php @@ -5,19 +5,13 @@ namespace Doctrine\DBAL\Driver; use Exception; +use Throwable; /** * Abstract base implementation of the {@link DriverException} interface. */ abstract class AbstractDriverException extends Exception implements DriverException { - /** - * The driver specific error code. - * - * @var int|string|null - */ - private $errorCode; - /** * The SQLSTATE of the driver. * @@ -26,30 +20,22 @@ abstract class AbstractDriverException extends Exception implements DriverExcept private $sqlState; /** - * @param string $message The driver error message. - * @param string|null $sqlState The SQLSTATE the driver is in at the time the error occurred, if any. - * @param int|string|null $errorCode The driver specific error code if any. + * @param string $message The driver error message. + * @param string|null $sqlState The SQLSTATE the driver is in at the time the error occurred, if any. + * @param int $code The driver specific error code if any. + * @param Throwable|null $previous The previous throwable used for the exception chaining. */ - public function __construct($message, $sqlState = null, $errorCode = null) + public function __construct(string $message, ?string $sqlState = null, int $code = 0, ?Throwable $previous = null) { - parent::__construct($message); - - $this->errorCode = $errorCode; - $this->sqlState = $sqlState; - } + parent::__construct($message, $code, $previous); - /** - * {@inheritdoc} - */ - public function getErrorCode() - { - return $this->errorCode; + $this->sqlState = $sqlState; } /** * {@inheritdoc} */ - public function getSQLState() + public function getSQLState() : ?string { return $this->sqlState; } diff --git a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php index 9229b29bfef..c876723d7ab 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php @@ -31,77 +31,77 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver, */ public function convertException($message, DriverException $exception) { - switch ($exception->getErrorCode()) { - case '1213': + switch ($exception->getCode()) { + case 1213: return new Exception\DeadlockException($message, $exception); - case '1205': + case 1205: return new Exception\LockWaitTimeoutException($message, $exception); - case '1050': + case 1050: return new Exception\TableExistsException($message, $exception); - case '1051': - case '1146': + case 1051: + case 1146: return new Exception\TableNotFoundException($message, $exception); - case '1216': - case '1217': - case '1451': - case '1452': - case '1701': + case 1216: + case 1217: + case 1451: + case 1452: + case 1701: return new Exception\ForeignKeyConstraintViolationException($message, $exception); - case '1062': - case '1557': - case '1569': - case '1586': + case 1062: + case 1557: + case 1569: + case 1586: return new Exception\UniqueConstraintViolationException($message, $exception); - case '1054': - case '1166': - case '1611': + case 1054: + case 1166: + case 1611: return new Exception\InvalidFieldNameException($message, $exception); - case '1052': - case '1060': - case '1110': + case 1052: + case 1060: + case 1110: return new Exception\NonUniqueFieldNameException($message, $exception); - case '1064': - case '1149': - case '1287': - case '1341': - case '1342': - case '1343': - case '1344': - case '1382': - case '1479': - case '1541': - case '1554': - case '1626': + case 1064: + case 1149: + case 1287: + case 1341: + case 1342: + case 1343: + case 1344: + case 1382: + case 1479: + case 1541: + case 1554: + case 1626: return new Exception\SyntaxErrorException($message, $exception); - case '1044': - case '1045': - case '1046': - case '1049': - case '1095': - case '1142': - case '1143': - case '1227': - case '1370': - case '1429': - case '2002': - case '2005': + case 1044: + case 1045: + case 1046: + case 1049: + case 1095: + case 1142: + case 1143: + case 1227: + case 1370: + case 1429: + case 2002: + case 2005: return new Exception\ConnectionException($message, $exception); - case '1048': - case '1121': - case '1138': - case '1171': - case '1252': - case '1263': - case '1364': - case '1566': + case 1048: + case 1121: + case 1138: + case 1171: + case 1252: + case 1263: + case 1364: + case 1566: return new Exception\NotNullConstraintViolationException($message, $exception); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php b/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php index e9e1cce5382..00020139565 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php @@ -21,38 +21,38 @@ abstract class AbstractOracleDriver implements Driver, ExceptionConverterDriver */ public function convertException($message, DriverException $exception) { - switch ($exception->getErrorCode()) { - case '1': - case '2299': - case '38911': + switch ($exception->getCode()) { + case 1: + case 2299: + case 38911: return new Exception\UniqueConstraintViolationException($message, $exception); - case '904': + case 904: return new Exception\InvalidFieldNameException($message, $exception); - case '918': - case '960': + case 918: + case 960: return new Exception\NonUniqueFieldNameException($message, $exception); - case '923': + case 923: return new Exception\SyntaxErrorException($message, $exception); - case '942': + case 942: return new Exception\TableNotFoundException($message, $exception); - case '955': + case 955: return new Exception\TableExistsException($message, $exception); - case '1017': - case '12545': + case 1017: + case 12545: return new Exception\ConnectionException($message, $exception); - case '1400': + case 1400: return new Exception\NotNullConstraintViolationException($message, $exception); - case '2266': - case '2291': - case '2292': + case 2266: + case 2291: + case 2292: return new Exception\ForeignKeyConstraintViolationException($message, $exception); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php index 41a9f058e9a..ea62f8e3603 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -64,16 +64,13 @@ public function convertException($message, DriverException $exception) case '42P07': return new Exception\TableExistsException($message, $exception); + } - case '7': - // In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code. - // The exception code is always set to 7 here. - // We have to match against the SQLSTATE in the error message in these cases. - if (strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { - return new Exception\ConnectionException($message, $exception); - } - - break; + // In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code. + // The exception code is always set to 7 here. + // We have to match against the SQLSTATE in the error message in these cases. + if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { + return new Exception\ConnectionException($message, $exception); } return new Exception\DriverException($message, $exception); diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php index a4c45ccaa23..ebca7b1934e 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php @@ -25,38 +25,38 @@ abstract class AbstractSQLAnywhereDriver implements Driver, ExceptionConverterDr */ public function convertException($message, DriverException $exception) { - switch ($exception->getErrorCode()) { - case '-306': - case '-307': - case '-684': + switch ($exception->getCode()) { + case -306: + case -307: + case -684: return new Exception\DeadlockException($message, $exception); - case '-210': - case '-1175': - case '-1281': + case -210: + case -1175: + case -1281: return new Exception\LockWaitTimeoutException($message, $exception); - case '-100': - case '-103': - case '-832': + case -100: + case -103: + case -832: return new Exception\ConnectionException($message, $exception); - case '-143': + case -143: return new Exception\InvalidFieldNameException($message, $exception); - case '-193': - case '-196': + case -193: + case -196: return new Exception\UniqueConstraintViolationException($message, $exception); - case '-194': - case '-198': + case -194: + case -198: return new Exception\ForeignKeyConstraintViolationException($message, $exception); - case '-144': + case -144: return new Exception\NonUniqueFieldNameException($message, $exception); - case '-184': - case '-195': + case -184: + case -195: return new Exception\NotNullConstraintViolationException($message, $exception); - case '-131': + case -131: return new Exception\SyntaxErrorException($message, $exception); - case '-110': + case -110: return new Exception\TableExistsException($message, $exception); - case '-141': - case '-1041': + case -141: + case -1041: return new Exception\TableNotFoundException($message, $exception); } diff --git a/lib/Doctrine/DBAL/Driver/DriverException.php b/lib/Doctrine/DBAL/Driver/DriverException.php index c95609712bb..ca7f453ec46 100644 --- a/lib/Doctrine/DBAL/Driver/DriverException.php +++ b/lib/Doctrine/DBAL/Driver/DriverException.php @@ -14,29 +14,10 @@ */ interface DriverException extends Throwable { - /** - * Returns the driver specific error code if available. - * - * Returns null if no driver specific error code is available - * for the error raised by the driver. - * - * @return int|string|null - */ - public function getErrorCode(); - - /** - * Returns the driver error message. - * - * @return string - */ - public function getMessage(); - /** * Returns the SQLSTATE the driver was in at the time the error occurred. * * Returns null if the driver does not provide a SQLSTATE for the error occurred. - * - * @return string|null */ - public function getSQLState(); + public function getSQLState() : ?string; } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index ef4dd3546d9..9763a627c14 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -24,7 +24,6 @@ use function db2_prepare; use function db2_rollback; use function db2_server_info; -use function db2_stmt_errormsg; class DB2Connection implements Connection, ServerInfoAwareConnection { @@ -50,7 +49,7 @@ public function __construct(array $params, $username, $password, $driverOptions } if ($conn === false) { - throw new DB2Exception(db2_conn_errormsg()); + throw DB2Exception::fromConnectionError(); } $this->conn = $conn; @@ -82,7 +81,7 @@ public function prepare(string $sql) : DriverStatement { $stmt = @db2_prepare($this->conn, $sql); if (! $stmt) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError(); } return new DB2Statement($stmt); @@ -115,7 +114,7 @@ public function exec(string $statement) : int $stmt = @db2_exec($this->conn, $statement); if ($stmt === false) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError(); } return db2_num_rows($stmt); @@ -135,7 +134,7 @@ public function lastInsertId($name = null) public function beginTransaction() : void { if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } } @@ -145,11 +144,11 @@ public function beginTransaction() : void public function commit() : void { if (! db2_commit($this->conn)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } } @@ -159,11 +158,11 @@ public function commit() : void public function rollBack() : void { if (! db2_rollback($this->conn)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php index eea9cc1c9e2..bd8d5b298aa 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php @@ -5,7 +5,34 @@ namespace Doctrine\DBAL\Driver\IBMDB2; use Doctrine\DBAL\Driver\AbstractDriverException; +use function db2_conn_error; +use function db2_conn_errormsg; +use function db2_stmt_error; +use function db2_stmt_errormsg; class DB2Exception extends AbstractDriverException { + /** + * @param resource|null $connection + */ + public static function fromConnectionError($connection = null) : self + { + if ($connection !== null) { + return new self(db2_conn_errormsg($connection), db2_conn_error($connection)); + } + + return new self(db2_conn_errormsg(), db2_conn_error()); + } + + /** + * @param resource|null $statement + */ + public static function fromStatementError($statement = null) : self + { + if ($statement !== null) { + return new self(db2_stmt_errormsg($statement), db2_stmt_error($statement)); + } + + return new self(db2_stmt_errormsg(), db2_stmt_error()); + } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index 0096feff73c..dfe594d386c 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -137,7 +137,7 @@ private function bind($position, &$variable, int $parameterType, int $dataType) $this->bindParam[$position] =& $variable; if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError($this->stmt); } } @@ -218,7 +218,7 @@ public function execute($params = null) : void $this->lobs = []; if ($retval === false) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError($this->stmt); } $this->result = true; diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 0b28b2cae50..b377b79c711 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -20,8 +20,6 @@ use function floor; use function in_array; use function ini_get; -use function mysqli_errno; -use function mysqli_error; use function mysqli_init; use function mysqli_options; use function restore_error_handler; @@ -70,7 +68,7 @@ public function __construct(array $params, $username, $password, array $driverOp }); try { if (! $this->conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { - throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); + throw MysqliException::fromConnectionError($this->conn); } } finally { restore_error_handler(); @@ -158,7 +156,7 @@ public function quote(string $input) : string public function exec(string $statement) : int { if ($this->conn->query($statement) === false) { - throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + throw MysqliException::fromConnectionError($this->conn); } return $this->conn->affected_rows; @@ -186,7 +184,7 @@ public function beginTransaction() : void public function commit() : void { if (! $this->conn->commit()) { - throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + throw MysqliException::fromConnectionError($this->conn); } } @@ -196,7 +194,7 @@ public function commit() : void public function rollBack() : void { if (! $this->conn->rollback()) { - throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + throw MysqliException::fromConnectionError($this->conn); } } @@ -255,14 +253,7 @@ private function setDriverOptions(array $driverOptions = []) continue; } - $msg = sprintf($exceptionMsg, 'Failed to set', $option, $value); - $msg .= sprintf(', error: %s (%d)', mysqli_error($this->conn), mysqli_errno($this->conn)); - - throw new MysqliException( - $msg, - $this->conn->sqlstate, - $this->conn->errno - ); + throw MysqliException::fromConnectionError($this->conn); } } diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php index b779bc40457..3a47d317bcb 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php @@ -5,10 +5,21 @@ namespace Doctrine\DBAL\Driver\Mysqli; use Doctrine\DBAL\Driver\AbstractDriverException; +use mysqli; +use mysqli_stmt; /** * Exception thrown in case the mysqli driver errors. */ class MysqliException extends AbstractDriverException { + public static function fromConnectionError(mysqli $connection) : self + { + return new self($connection->error, $connection->sqlstate ?: null, $connection->errno); + } + + public static function fromStatementError(mysqli_stmt $statement) : self + { + return new self($statement->error, $statement->sqlstate ?: null, $statement->errno); + } } diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index fed098f3c09..156b2dd5835 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -87,7 +87,7 @@ public function __construct(mysqli $conn, $prepareString) $stmt = $conn->prepare($prepareString); if ($stmt === false) { - throw new MysqliException($this->_conn->error, $this->_conn->sqlstate, $this->_conn->errno); + throw MysqliException::fromConnectionError($this->_conn); } $this->_stmt = $stmt; @@ -139,14 +139,14 @@ public function execute($params = null) : void { if ($params !== null && count($params) > 0) { if (! $this->bindUntypedValues($params)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } } else { $this->bindTypedParameters(); } if (! $this->_stmt->execute()) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } if ($this->_columnNames === null) { @@ -193,7 +193,7 @@ public function execute($params = null) : void } if (! $this->_stmt->bind_result(...$refs)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } } @@ -232,7 +232,7 @@ private function bindTypedParameters() } if (count($values) > 0 && ! $this->_stmt->bind_param($types, ...$values)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } $this->sendLongData($streams); @@ -254,7 +254,7 @@ private function sendLongData($streams) } if (! $this->_stmt->send_long_data($paramNr - 1, $chunk)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } } } @@ -322,7 +322,7 @@ public function fetch($fetchMode = null, ...$args) } if ($values === false) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw MysqliException::fromStatementError($this->_stmt); } if ($fetchMode === FetchMode::NUMERIC) { diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php index bdb64347a6a..2e7f1693343 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php @@ -10,10 +10,8 @@ class OCI8Exception extends AbstractDriverException { /** * @param mixed[]|false $error - * - * @return \Doctrine\DBAL\Driver\OCI8\OCI8Exception */ - public static function fromErrorInfo($error) + public static function fromErrorInfo($error) : self { if ($error === false) { return new self('Database error occurred but no error information was retrieved from the driver.'); diff --git a/lib/Doctrine/DBAL/Driver/PDOException.php b/lib/Doctrine/DBAL/Driver/PDOException.php index 47f12e7834c..e25fcd461ab 100644 --- a/lib/Doctrine/DBAL/Driver/PDOException.php +++ b/lib/Doctrine/DBAL/Driver/PDOException.php @@ -7,48 +7,20 @@ /** * Tiny wrapper for PDOException instances to implement the {@link DriverException} interface. */ -class PDOException extends \PDOException implements DriverException +class PDOException extends AbstractDriverException { - /** - * The driver specific error code. - * - * @var int|string|null - */ - private $errorCode; - - /** - * The SQLSTATE of the driver. - * - * @var string|null - */ - private $sqlState; - /** * @param \PDOException $exception The PDO exception to wrap. */ public function __construct(\PDOException $exception) { - parent::__construct($exception->getMessage(), 0, $exception); - - $this->code = $exception->getCode(); - $this->errorInfo = $exception->errorInfo; - $this->errorCode = $exception->errorInfo[1] ?? $exception->getCode(); - $this->sqlState = $exception->errorInfo[0] ?? $exception->getCode(); - } - - /** - * {@inheritdoc} - */ - public function getErrorCode() - { - return $this->errorCode; - } - - /** - * {@inheritdoc} - */ - public function getSQLState() - { - return $this->sqlState; + if ($exception->errorInfo !== null) { + [$sqlState, $code] = $exception->errorInfo; + } else { + $code = $exception->getCode(); + $sqlState = null; + } + + parent::__construct($exception->getMessage(), $sqlState, $code, $exception); } } diff --git a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php index 0320585573a..3aa794c4a27 100644 --- a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php @@ -7,7 +7,7 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\AbstractMySQLDriver; use Doctrine\DBAL\Driver\PDOConnection; -use PDOException; +use Doctrine\DBAL\Driver\PDOException; /** * PDO MySql driver. diff --git a/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php b/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php index 79dd059a59f..06e726df84d 100644 --- a/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php @@ -7,7 +7,7 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\AbstractOracleDriver; use Doctrine\DBAL\Driver\PDOConnection; -use PDOException; +use Doctrine\DBAL\Driver\PDOException; /** * PDO Oracle driver. diff --git a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php index c081484c666..f2d8dde4a95 100644 --- a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -7,8 +7,8 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver; use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\Driver\PDOException; use PDO; -use PDOException; use function defined; /** diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php index 6af349aa721..ba86e3c8d92 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -7,8 +7,8 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\AbstractSQLiteDriver; use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\Driver\PDOException; use Doctrine\DBAL\Platforms\SqlitePlatform; -use PDOException; use function array_merge; /** diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php index 99e405585e3..5613acf9960 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php @@ -5,7 +5,6 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere; use Doctrine\DBAL\Driver\AbstractDriverException; -use InvalidArgumentException; use function sasql_error; use function sasql_errorcode; use function sasql_sqlstate; @@ -22,12 +21,8 @@ class SQLAnywhereException extends AbstractDriverException * * @param resource|null $conn The SQL Anywhere connection resource to retrieve the last error from. * @param resource|null $stmt The SQL Anywhere statement resource to retrieve the last error from. - * - * @return SQLAnywhereException - * - * @throws InvalidArgumentException */ - public static function fromSQLAnywhereError($conn = null, $stmt = null) + public static function fromSQLAnywhereError($conn = null, $stmt = null) : self { $state = $conn ? sasql_sqlstate($conn) : sasql_sqlstate(); $code = null; diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php index cbb4fa49e38..87e982c9d82 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php @@ -13,14 +13,12 @@ class SQLSrvException extends AbstractDriverException { /** * Helper method to turn sql server errors into exception. - * - * @return \Doctrine\DBAL\Driver\SQLSrv\SQLSrvException */ - public static function fromSqlSrvErrors() + public static function fromSqlSrvErrors() : self { - $message = ''; - $sqlState = null; - $errorCode = null; + $message = ''; + $sqlState = null; + $code = null; foreach ((array) sqlsrv_errors(SQLSRV_ERR_ERRORS) as $error) { $message .= 'SQLSTATE [' . $error['SQLSTATE'] . ', ' . $error['code'] . ']: ' . $error['message'] . "\n"; @@ -29,17 +27,17 @@ public static function fromSqlSrvErrors() $sqlState = $error['SQLSTATE']; } - if ($errorCode !== null) { + if ($code !== null) { continue; } - $errorCode = $error['code']; + $code = $error['code']; } if (! $message) { $message = 'SQL Server error occurred but no error message was retrieved from driver.'; } - return new self(rtrim($message), $sqlState, $errorCode); + return new self(rtrim($message), $sqlState, $code); } } diff --git a/lib/Doctrine/DBAL/Exception/DriverException.php b/lib/Doctrine/DBAL/Exception/DriverException.php index 831ddd08116..ed6ee082a06 100644 --- a/lib/Doctrine/DBAL/Exception/DriverException.php +++ b/lib/Doctrine/DBAL/Exception/DriverException.php @@ -5,58 +5,31 @@ namespace Doctrine\DBAL\Exception; use Doctrine\DBAL\DBALException; -use Exception; +use Doctrine\DBAL\Driver\DriverException as DriverExceptionInterface; +use function assert; /** * Base class for all errors detected in the driver. */ -class DriverException extends DBALException +class DriverException extends DBALException implements DriverExceptionInterface { /** - * The previous DBAL driver exception. - * - * @var \Doctrine\DBAL\Driver\DriverException + * @param string $message The exception message. + * @param DriverExceptionInterface $driverException The DBAL driver exception to chain. */ - private $driverException; - - /** - * @param string $message The exception message. - * @param \Doctrine\DBAL\Driver\DriverException $driverException The DBAL driver exception to chain. - */ - public function __construct($message, \Doctrine\DBAL\Driver\DriverException $driverException) + public function __construct(string $message, DriverExceptionInterface $driverException) { - $exception = null; - - if ($driverException instanceof Exception) { - $exception = $driverException; - } - - parent::__construct($message, 0, $exception); - - $this->driverException = $driverException; + parent::__construct($message, $driverException->getCode(), $driverException); } /** - * Returns the driver specific error code if given. - * - * Returns null if no error code was given by the driver. - * - * @return int|string|null + * {@inheritDoc} */ - public function getErrorCode() + public function getSQLState() : ?string { - return $this->driverException->getErrorCode(); - } + $previous = $this->getPrevious(); + assert($previous instanceof DriverExceptionInterface); - /** - * Returns the SQLSTATE the driver was in at the time the error occurred, if given. - * - * Returns null if no SQLSTATE was given by the driver. - * - * @return string|null - */ - public function getSQLState() - { - return $this->driverException->getSQLState(); + return $previous->getSQLState(); } } diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index 8acabf36642..4bf88abc1c9 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -44,7 +44,7 @@ public function dropDatabase($database) // because of active connections on the database. // To force dropping the database, we first have to close all active connections // on that database and issue the drop database operation again. - if ($exception->getErrorCode() !== 1940) { + if ($exception->getCode() !== 1940) { throw $exception; } diff --git a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php index 127f8587e01..08aa1d1e313 100644 --- a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -44,7 +44,7 @@ public function dropDatabase($database) // because of active connections on the database. // To force dropping the database, we first have to close all active connections // on that database and issue the drop database operation again. - if ($exception->getErrorCode() !== 3702) { + if ($exception->getCode() !== 3702) { throw $exception; } diff --git a/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php b/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php index e3aeead3e27..de251cdceac 100644 --- a/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php @@ -42,14 +42,7 @@ public function testAvoidOverWrappingOnDriverException() /** * {@inheritDoc} */ - public function getErrorCode() - { - } - - /** - * {@inheritDoc} - */ - public function getSQLState() + public function getSQLState() : ?string { } }; diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php index 47d04e03373..c86a75fab5b 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php @@ -97,15 +97,7 @@ public function __construct() /** * {@inheritDoc} */ - public function getErrorCode() - { - return 'foo'; - } - - /** - * {@inheritDoc} - */ - public function getSQLState() + public function getSQLState() : ?string { return 'bar'; } @@ -123,7 +115,7 @@ public function getSQLState() self::assertSame($convertedExceptionClassName, get_class($convertedException)); - self::assertSame($driverException->getErrorCode(), $convertedException->getErrorCode()); + self::assertSame($driverException->getCode(), $convertedException->getCode()); self::assertSame($driverException->getSQLState(), $convertedException->getSQLState()); self::assertSame($message, $convertedException->getMessage()); } @@ -259,36 +251,24 @@ private function getExceptionConversions() foreach ($this->getExceptionConversionData() as $convertedExceptionClassName => $errors) { foreach ($errors as $error) { - $driverException = new class ($error[0], $error[1], $error[2]) + $driverException = new class (...$error) extends Exception implements DriverExceptionInterface { - /** @var mixed */ - private $errorCode; - - /** @var mixed */ + /** @var string|null */ private $sqlState; - public function __construct($errorCode, $sqlState, $message) + public function __construct(int $code, ?string $sqlState = null, string $message = '') { - parent::__construct($message ?? ''); + parent::__construct($message, $code); - $this->errorCode = $errorCode; - $this->sqlState = $sqlState; - } - - /** - * {@inheritDoc} - */ - public function getErrorCode() - { - return $this->errorCode; + $this->sqlState = $sqlState; } /** * {@inheritDoc} */ - public function getSQLState() + public function getSQLState() : ?string { return $this->sqlState; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php index 81140b97754..775388bf7bd 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php @@ -89,76 +89,76 @@ protected function getExceptionConversionData() { return [ self::EXCEPTION_CONNECTION => [ - ['1044', null, null], - ['1045', null, null], - ['1046', null, null], - ['1049', null, null], - ['1095', null, null], - ['1142', null, null], - ['1143', null, null], - ['1227', null, null], - ['1370', null, null], - ['2002', null, null], - ['2005', null, null], + [1044], + [1045], + [1046], + [1049], + [1095], + [1142], + [1143], + [1227], + [1370], + [2002], + [2005], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['1216', null, null], - ['1217', null, null], - ['1451', null, null], - ['1452', null, null], + [1216], + [1217], + [1451], + [1452], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['1054', null, null], - ['1166', null, null], - ['1611', null, null], + [1054], + [1166], + [1611], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['1052', null, null], - ['1060', null, null], - ['1110', null, null], + [1052], + [1060], + [1110], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['1048', null, null], - ['1121', null, null], - ['1138', null, null], - ['1171', null, null], - ['1252', null, null], - ['1263', null, null], - ['1364', null, null], - ['1566', null, null], + [1048], + [1121], + [1138], + [1171], + [1252], + [1263], + [1364], + [1566], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['1064', null, null], - ['1149', null, null], - ['1287', null, null], - ['1341', null, null], - ['1342', null, null], - ['1343', null, null], - ['1344', null, null], - ['1382', null, null], - ['1479', null, null], - ['1541', null, null], - ['1554', null, null], - ['1626', null, null], + [1064], + [1149], + [1287], + [1341], + [1342], + [1343], + [1344], + [1382], + [1479], + [1541], + [1554], + [1626], ], self::EXCEPTION_TABLE_EXISTS => [ - ['1050', null, null], + [1050], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['1051', null, null], - ['1146', null, null], + [1051], + [1146], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['1062', null, null], - ['1557', null, null], - ['1569', null, null], - ['1586', null, null], + [1062], + [1557], + [1569], + [1586], ], self::EXCEPTION_DEADLOCK => [ - ['1213', null, null], + [1213], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - ['1205', null, null], + [1205], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php index fcf5bd6366e..f6348805102 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php @@ -66,35 +66,35 @@ protected function getExceptionConversionData() { return [ self::EXCEPTION_CONNECTION => [ - ['1017', null, null], - ['12545', null, null], + [1017], + [12545], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['2292', null, null], + [2292], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['904', null, null], + [904], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['918', null, null], - ['960', null, null], + [918], + [960], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['1400', null, null], + [1400], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['923', null, null], + [923], ], self::EXCEPTION_TABLE_EXISTS => [ - ['955', null, null], + [955], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['942', null, null], + [942], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['1', null, null], - ['2299', null, null], - ['38911', null, null], + [1], + [2299], + [38911], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php index f7f06b1423e..5b515ace2e8 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php @@ -75,35 +75,35 @@ protected function getExceptionConversionData() { return [ self::EXCEPTION_CONNECTION => [ - [null, '7', 'SQLSTATE[08006]'], + [7, null, 'SQLSTATE[08006]'], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - [null, '23503', null], + [0, '23503'], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - [null, '42703', null], + [0, '42703'], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - [null, '42702', null], + [0, '42702'], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - [null, '23502', null], + [0, '23502'], ], self::EXCEPTION_SYNTAX_ERROR => [ - [null, '42601', null], + [0, '42601'], ], self::EXCEPTION_TABLE_EXISTS => [ - [null, '42P07', null], + [0, '42P07'], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - [null, '42P01', null], + [0, '42P01'], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - [null, '23505', null], + [0, '23505'], ], self::EXCEPTION_DEADLOCK => [ - [null, '40001', null], - [null, '40P01', null], + [0, '40001'], + [0, '40P01'], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php index f3bdb4ebb23..9615e8beabf 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php @@ -43,46 +43,46 @@ protected function getExceptionConversionData() { return [ self::EXCEPTION_CONNECTION => [ - ['-100', null, null], - ['-103', null, null], - ['-832', null, null], + [-100], + [-103], + [-832], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['-198', null, null], + [-198], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['-143', null, null], + [-143], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['-144', null, null], + [-144], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['-184', null, null], - ['-195', null, null], + [-184], + [-195], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['-131', null, null], + [-131], ], self::EXCEPTION_TABLE_EXISTS => [ - ['-110', null, null], + [-110], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['-141', null, null], - ['-1041', null, null], + [-141], + [-1041], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['-193', null, null], - ['-196', null, null], + [-193], + [-196], ], self::EXCEPTION_DEADLOCK => [ - ['-306', null, null], - ['-307', null, null], - ['-684', null, null], + [-306], + [-307], + [-684], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - ['-210', null, null], - ['-1175', null, null], - ['-1281', null, null], + [-210], + [-1175], + [-1281], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php index a53229cd5b7..0dec1909014 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php @@ -48,36 +48,36 @@ protected function getExceptionConversionData() { return [ self::EXCEPTION_CONNECTION => [ - [null, null, 'unable to open database file'], + [0, null, 'unable to open database file'], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - [null, null, 'has no column named'], + [0, null, 'has no column named'], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - [null, null, 'ambiguous column name'], + [0, null, 'ambiguous column name'], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - [null, null, 'may not be NULL'], + [0, null, 'may not be NULL'], ], self::EXCEPTION_READ_ONLY => [ - [null, null, 'attempt to write a readonly database'], + [0, null, 'attempt to write a readonly database'], ], self::EXCEPTION_SYNTAX_ERROR => [ - [null, null, 'syntax error'], + [0, null, 'syntax error'], ], self::EXCEPTION_TABLE_EXISTS => [ - [null, null, 'already exists'], + [0, null, 'already exists'], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - [null, null, 'no such table:'], + [0, null, 'no such table:'], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - [null, null, 'must be unique'], - [null, null, 'is not unique'], - [null, null, 'are not unique'], + [0, null, 'must be unique'], + [0, null, 'is not unique'], + [0, null, 'are not unique'], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - [null, null, 'database is locked'], + [0, null, 'database is locked'], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php index 08b69ee253d..f8930233dc0 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php @@ -15,7 +15,7 @@ class PDOExceptionTest extends DbalTestCase public const MESSAGE = 'PDO Exception'; - public const SQLSTATE = 28000; + public const SQLSTATE = 'HY000'; /** * The PDO exception wrapper under test. @@ -39,7 +39,7 @@ protected function setUp() : void parent::setUp(); - $this->wrappedException = new \PDOException(self::MESSAGE, self::SQLSTATE); + $this->wrappedException = new \PDOException(self::MESSAGE); $this->wrappedException->errorInfo = [self::SQLSTATE, self::ERROR_CODE]; @@ -48,12 +48,7 @@ protected function setUp() : void public function testReturnsCode() { - self::assertSame(self::SQLSTATE, $this->exception->getCode()); - } - - public function testReturnsErrorCode() - { - self::assertSame(self::ERROR_CODE, $this->exception->getErrorCode()); + self::assertSame(self::ERROR_CODE, $this->exception->getCode()); } public function testReturnsMessage() diff --git a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php index 31d64b99044..a05ab7a948d 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php @@ -351,7 +351,7 @@ private function lastInsertId(?string $name = null) try { return $this->connection->lastInsertId($name); } catch (DriverException $e) { - if ($e->getCode() === 'IM001') { + if ($e->getSQLState() === 'IM001') { $this->markTestSkipped($e->getMessage()); } From 0f662c5d5e296e322ea4923587e936798c22eb48 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 5 Apr 2019 14:45:12 -0700 Subject: [PATCH 64/66] Removed errorCode() and errorInfo() methods from Connection and Statement APIs --- UPGRADE.md | 4 +++ lib/Doctrine/DBAL/Connection.php | 18 ------------- lib/Doctrine/DBAL/Driver/Connection.php | 14 ---------- .../DBAL/Driver/IBMDB2/DB2Connection.php | 21 --------------- .../DBAL/Driver/IBMDB2/DB2Statement.php | 21 --------------- .../DBAL/Driver/Mysqli/MysqliConnection.php | 16 ----------- .../DBAL/Driver/Mysqli/MysqliStatement.php | 16 ----------- .../DBAL/Driver/OCI8/OCI8Connection.php | 27 ------------------- .../DBAL/Driver/OCI8/OCI8Statement.php | 27 ------------------- lib/Doctrine/DBAL/Driver/PDOConnection.php | 16 ----------- lib/Doctrine/DBAL/Driver/PDOStatement.php | 16 ----------- .../SQLAnywhere/SQLAnywhereConnection.php | 18 ------------- .../SQLAnywhere/SQLAnywhereStatement.php | 18 ------------- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 23 ---------------- .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 23 ---------------- lib/Doctrine/DBAL/Driver/Statement.php | 16 ----------- lib/Doctrine/DBAL/Portability/Statement.php | 20 -------------- lib/Doctrine/DBAL/Statement.php | 18 ------------- phpstan.neon.dist | 1 - .../DBAL/Driver/OCI8/OCI8StatementTest.php | 9 +++---- .../Tests/DBAL/Portability/StatementTest.php | 24 +---------------- 21 files changed, 9 insertions(+), 357 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index fe6b3ff1b1f..96bd0870100 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `::errorCode()` and `::errorInfo()` removed from `Connection` and `Statement` APIs + +The error information is available in `DriverException` trown in case of an error. + ## BC BREAK Changes in driver exceptions 1. The `Doctrine\DBAL\Driver\DriverException::getErrorCode()` method is removed. In order to obtain the driver error code, please use `::getCode()`. diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 11fc857b936..746e463e436 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -1065,24 +1065,6 @@ public function getTransactionNestingLevel() return $this->transactionNestingLevel; } - /** - * Fetches the SQLSTATE associated with the last database operation. - * - * @return string|null The last error code. - */ - public function errorCode() - { - return $this->getWrappedConnection()->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->getWrappedConnection()->errorInfo(); - } - /** * Returns the ID of the last inserted row, or the last value from a sequence object, * depending on the underlying driver. diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index acae0b66f9a..8ee150ec4f7 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -67,18 +67,4 @@ public function commit() : void; * @throws DriverException */ public function rollBack() : void; - - /** - * Returns the error code associated with the last operation on the database handle. - * - * @return string|null The error code, or null if no operation has been run on the database handle. - */ - public function errorCode(); - - /** - * Returns extended error information associated with the last operation on the database handle. - * - * @return mixed[] - */ - public function errorInfo(); } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index 9763a627c14..c5a41d335b3 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -13,8 +13,6 @@ use const DB2_AUTOCOMMIT_ON; use function db2_autocommit; use function db2_commit; -use function db2_conn_error; -use function db2_conn_errormsg; use function db2_connect; use function db2_escape_string; use function db2_exec; @@ -165,23 +163,4 @@ public function rollBack() : void throw DB2Exception::fromConnectionError($this->conn); } } - - /** - * {@inheritdoc} - */ - public function errorCode() - { - return db2_conn_error($this->conn); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return [ - 0 => db2_conn_errormsg($this->conn), - 1 => $this->errorCode(), - ]; - } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index dfe594d386c..f2633d95d65 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -32,8 +32,6 @@ use function db2_free_result; use function db2_num_fields; use function db2_num_rows; -use function db2_stmt_error; -use function db2_stmt_errormsg; use function error_get_last; use function fclose; use function fwrite; @@ -165,25 +163,6 @@ public function columnCount() return db2_num_fields($this->stmt) ?: 0; } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return db2_stmt_error(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return [ - db2_stmt_errormsg(), - db2_stmt_error(), - ]; - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index b377b79c711..02697c96013 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -198,22 +198,6 @@ public function rollBack() : void } } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->conn->errno; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return $this->conn->error; - } - /** * Apply the driver options to the connection. * diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 156b2dd5835..bb07e5a9a95 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -388,22 +388,6 @@ public function fetchColumn($columnIndex = 0) return $row[$columnIndex]; } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->_stmt->errno; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return $this->_stmt->error; - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index 8a75d27f62e..d32ecd15317 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -199,31 +199,4 @@ public function rollBack() : void $this->executeMode = OCI_COMMIT_ON_SUCCESS; } - - /** - * {@inheritdoc} - */ - public function errorCode() - { - $error = oci_error($this->dbh); - if ($error !== false) { - $error = $error['code']; - } - - return $error; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - $error = oci_error($this->dbh); - - if ($error === false) { - return []; - } - - return $error; - } } diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index 00bf3abf36b..c4dfdddeacd 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -342,33 +342,6 @@ public function columnCount() return oci_num_fields($this->_sth) ?: 0; } - /** - * {@inheritdoc} - */ - public function errorCode() - { - $error = oci_error($this->_sth); - if ($error !== false) { - $error = $error['code']; - } - - return $error; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - $error = oci_error($this->_sth); - - if ($error === false) { - return []; - } - - return $error; - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index bc9128e1eb3..d9b40e923c9 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -148,22 +148,6 @@ public function rollBack() : void $this->connection->rollBack(); } - /** - * {@inheritDoc} - */ - public function errorCode() - { - return $this->connection->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->connection->errorInfo(); - } - public function getWrappedConnection() : PDO { return $this->connection; diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index b3b252a41f4..411cf8222c8 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -113,22 +113,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index d98cffcd9a8..7b2161a2e68 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -14,8 +14,6 @@ use function sasql_affected_rows; use function sasql_commit; use function sasql_connect; -use function sasql_error; -use function sasql_errorcode; use function sasql_escape_string; use function sasql_insert_id; use function sasql_pconnect; @@ -84,22 +82,6 @@ public function commit() : void $this->endTransaction(); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return sasql_errorcode($this->connection); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return sasql_error($this->connection); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index 415be465041..c8afb177f46 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -30,8 +30,6 @@ use function sasql_prepare; use function sasql_stmt_affected_rows; use function sasql_stmt_bind_param_ex; -use function sasql_stmt_errno; -use function sasql_stmt_error; use function sasql_stmt_execute; use function sasql_stmt_field_count; use function sasql_stmt_reset; @@ -144,22 +142,6 @@ public function columnCount() return sasql_stmt_field_count($this->stmt); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return sasql_stmt_errno($this->stmt); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return sasql_stmt_error($this->stmt); - } - /** * {@inheritdoc} * diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index 2e4ac7da767..4470c58cd6d 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -8,12 +8,10 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use const SQLSRV_ERR_ERRORS; use function sqlsrv_begin_transaction; use function sqlsrv_commit; use function sqlsrv_configure; use function sqlsrv_connect; -use function sqlsrv_errors; use function sqlsrv_query; use function sqlsrv_rollback; use function sqlsrv_rows_affected; @@ -162,25 +160,4 @@ public function rollBack() : void throw SQLSrvException::fromSqlSrvErrors(); } } - - /** - * {@inheritDoc} - */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index cb52aa44720..ad572e81e30 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -11,7 +11,6 @@ use Doctrine\DBAL\ParameterType; use IteratorAggregate; use const SQLSRV_ENC_BINARY; -use const SQLSRV_ERR_ERRORS; use const SQLSRV_FETCH_ASSOC; use const SQLSRV_FETCH_BOTH; use const SQLSRV_FETCH_NUMERIC; @@ -21,7 +20,6 @@ use function in_array; use function is_int; use function is_numeric; -use function sqlsrv_errors; use function sqlsrv_execute; use function sqlsrv_fetch; use function sqlsrv_fetch_array; @@ -207,27 +205,6 @@ public function columnCount() return sqlsrv_num_fields($this->stmt) ?: 0; } - /** - * {@inheritdoc} - */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index 8ad231fea10..dd7895d93d3 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -59,22 +59,6 @@ public function bindValue($param, $value, $type = ParameterType::STRING) : void; */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void; - /** - * Fetches the SQLSTATE associated with the last operation on the statement handle. - * - * @see Doctrine_Adapter_Interface::errorCode() - * - * @return string|int|bool The error code string. - */ - public function errorCode(); - - /** - * Fetches extended error information associated with the last operation on the statement handle. - * - * @return mixed[] The error info array. - */ - public function errorInfo(); - /** * Executes a prepared statement * diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index c2ab9534fd7..102c11d9268 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -80,26 +80,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index 7022c809b61..61e60f5e0ed 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -179,24 +179,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * Fetches the SQLSTATE associated with the last operation on the statement. - * - * @return string|int|bool - */ - public function errorCode() - { - return $this->stmt->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 428af1038d4..71305aa7c85 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -26,7 +26,6 @@ parameters: - '~^Method Doctrine\\DBAL\\Schema\\(Oracle|PostgreSql|SQLServer)SchemaManager::_getPortableTableDefinition\(\) should return array but returns string\.\z~' - '~^Method Doctrine\\DBAL\\Platforms\\(|SQLAnywhere|Sqlite)Platform::_getTransactionIsolationLevelSQL\(\) should return string but returns int\.\z~' - '~^Method Doctrine\\DBAL\\Driver\\OCI8\\OCI8Connection::lastInsertId\(\) should return string but returns (int|false)\.\z~' - - '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~' # http://php.net/manual/en/pdo.sqlitecreatefunction.php - '~^Call to an undefined method PDO::sqliteCreateFunction\(\)\.\z~' diff --git a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php index c0904d01797..dcca544efbb 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php @@ -8,6 +8,7 @@ use Doctrine\DBAL\Driver\OCI8\OCI8Exception; use Doctrine\DBAL\Driver\OCI8\OCI8Statement; use Doctrine\Tests\DbalTestCase; +use PHPUnit\Framework\MockObject\MockObject; use ReflectionProperty; use const OCI_NO_AUTO_COMMIT; use function extension_loaded; @@ -39,8 +40,9 @@ protected function setUp() : void */ public function testExecute(array $params) { + /** @var OCI8Statement|MockObject $statement */ $statement = $this->getMockBuilder(OCI8Statement::class) - ->setMethods(['bindValue', 'errorInfo']) + ->setMethods(['bindValue']) ->disableOriginalConstructor() ->getMock(); @@ -56,10 +58,7 @@ public function testExecute(array $params) // can't pass to constructor since we don't have a real database handle, // but execute must check the connection for the executeMode - $conn = $this->getMockBuilder(OCI8Connection::class) - ->setMethods(['getExecuteMode']) - ->disableOriginalConstructor() - ->getMock(); + $conn = $this->createMock(OCI8Connection::class); $conn->expects($this->once()) ->method('getExecuteMode') ->willReturn(OCI_NO_AUTO_COMMIT); diff --git a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php index 2477efcd4d3..bd14320921c 100644 --- a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php @@ -85,29 +85,7 @@ public function testColumnCount() self::assertSame($columnCount, $this->stmt->columnCount()); } - public function testErrorCode() - { - $errorCode = '666'; - - $this->wrappedStmt->expects($this->once()) - ->method('errorCode') - ->will($this->returnValue($errorCode)); - - self::assertSame($errorCode, $this->stmt->errorCode()); - } - - public function testErrorInfo() - { - $errorInfo = ['666', 'Evil error.']; - - $this->wrappedStmt->expects($this->once()) - ->method('errorInfo') - ->will($this->returnValue($errorInfo)); - - self::assertSame($errorInfo, $this->stmt->errorInfo()); - } - - public function testExecute() + public function testExecute() : void { $params = [ 'foo', From 6b5d226547f924f60c9630cfbf8ea82b15ca5410 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Thu, 28 Mar 2019 23:17:06 -0700 Subject: [PATCH 65/66] Reworked `AbstractSchemaManager::extractDoctrineTypeFromComment()` removed `::removeDoctrineTypeFromComment()` --- UPGRADE.md | 4 +++ .../DBAL/Schema/AbstractSchemaManager.php | 33 +++++-------------- lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 8 ++--- .../DBAL/Schema/MySqlSchemaManager.php | 9 ++--- .../DBAL/Schema/OracleSchemaManager.php | 5 ++- .../DBAL/Schema/PostgreSqlSchemaManager.php | 5 ++- .../DBAL/Schema/SQLAnywhereSchemaManager.php | 14 ++++---- .../DBAL/Schema/SQLServerSchemaManager.php | 5 ++- .../DBAL/Schema/SqliteSchemaManager.php | 10 ++---- .../SchemaManagerFunctionalTestCase.php | 26 +++++++-------- 10 files changed, 44 insertions(+), 75 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 96bd0870100..9cd98d20aff 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `AbstractSchemaManager::extractDoctrineTypeFromComment()` changed, `::removeDoctrineTypeFromComment()` removed + +`AbstractSchemaManager::extractDoctrineTypeFromComment()` made `protected`. It takes the comment by reference, removes the type annotation from it and returns the extracted Doctrine type. + ## BC BREAK `::errorCode()` and `::errorInfo()` removed from `Connection` and `Statement` APIs The error information is available in `DriverException` trown in case of an error. diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index a3edcdb2206..d3e38a3d161 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -23,7 +23,6 @@ use function is_array; use function is_callable; use function preg_match; -use function str_replace; use function strtolower; /** @@ -1099,35 +1098,19 @@ public function getSchemaSearchPaths() } /** - * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns - * the type given as default. + * Given a table comment this method tries to extract a type hint for Doctrine Type. If the type hint is found, + * it's removed from the comment. * - * @param string|null $comment - * @param string $currentType - * - * @return string - */ - public function extractDoctrineTypeFromComment($comment, $currentType) - { - if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) { - return $match[1]; - } - - return $currentType; - } - - /** - * @param string|null $comment - * @param string|null $type - * - * @return string|null + * @return string|null The extracted Doctrine type or NULL of the type hint was not found. */ - public function removeDoctrineTypeFromComment($comment, $type) + final protected function extractDoctrineTypeFromComment(?string &$comment) : ?string { - if ($comment === null) { + if ($comment === null || ! preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match)) { return null; } - return str_replace('(DC2Type:' . $type . ')', '', $comment); + $comment = $match[1] . $match[4]; + + return $match[2]; } } diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index 9b8488398c3..f6cce30df6c 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -56,12 +56,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $default = trim($tableColumn['default'], "'"); } - $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); - - if (isset($tableColumn['comment'])) { - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - } + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); switch (strtolower($tableColumn['typename'])) { case 'varchar': diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index ba140a6b4d7..6dd2caacc55 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -108,13 +108,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $scale = null; $precision = null; - $type = $this->_platform->getDoctrineTypeMapping($dbType); - - // In cases where not connected to a database DESCRIBE $table does not return 'Comment' - if (isset($tableColumn['comment'])) { - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - } + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'char': diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index 4bf88abc1c9..658a7e1be3e 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -160,9 +160,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $scale = (int) $tableColumn['data_scale']; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type); - $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comments']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'number': diff --git a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php index 05d887fe774..8f2e7526030 100644 --- a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -366,9 +366,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'smallint': diff --git a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php index b99d68429e0..df879a87ec4 100644 --- a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php @@ -88,13 +88,13 @@ protected function _getPortableSequenceDefinition($sequence) */ protected function _getPortableTableColumnDefinition($tableColumn) { - $type = $this->_platform->getDoctrineTypeMapping($tableColumn['type']); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - $precision = null; - $scale = null; - $fixed = false; - $default = null; + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($tableColumn['type']); + + $precision = null; + $scale = null; + $fixed = false; + $default = null; if ($tableColumn['default'] !== null) { // Strip quotes from default value. diff --git a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php index 08aa1d1e313..9591dc4636f 100644 --- a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -101,9 +101,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $fixed = true; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); $options = [ 'length' => $length === 0 || ! in_array($type, ['text', 'string']) ? null : $length, diff --git a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php index c975fb1783b..6640fd508bf 100644 --- a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -281,16 +281,10 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns) $comment = $this->parseColumnCommentFromSQL($columnName, $createSql); - if ($comment === null) { - continue; - } + $type = $this->extractDoctrineTypeFromComment($comment); - $type = $this->extractDoctrineTypeFromComment($comment, ''); - - if ($type !== '') { + if ($type !== null) { $column->setType(Type::getType($type)); - - $comment = $this->removeDoctrineTypeFromComment($comment, $type); } $column->setComment($comment); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 98995fa8ee3..07b0cb6b030 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -32,6 +32,7 @@ use Doctrine\DBAL\Types\TextType; use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalFunctionalTestCase; +use ReflectionMethod; use function array_filter; use function array_keys; use function array_map; @@ -1440,27 +1441,26 @@ public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNo * @dataProvider commentsProvider * @group 2596 */ - public function testExtractDoctrineTypeFromComment(string $comment, string $expected, string $currentType) : void + public function testExtractDoctrineTypeFromComment(?string $comment, ?string $expectedType) : void { - $result = $this->schemaManager->extractDoctrineTypeFromComment($comment, $currentType); + $re = new ReflectionMethod($this->schemaManager, 'extractDoctrineTypeFromComment'); + $re->setAccessible(true); - self::assertSame($expected, $result); + self::assertSame($expectedType, $re->invokeArgs($this->schemaManager, [&$comment])); } /** - * @return string[][] + * @return mixed[][] */ - public function commentsProvider() : array + public static function commentsProvider() : iterable { - $currentType = 'current type'; - return [ - 'invalid custom type comments' => ['should.return.current.type', $currentType, $currentType], - 'valid doctrine type' => ['(DC2Type:guid)', 'guid', $currentType], - 'valid with dots' => ['(DC2Type:type.should.return)', 'type.should.return', $currentType], - 'valid with namespace' => ['(DC2Type:Namespace\Class)', 'Namespace\Class', $currentType], - 'valid with extra closing bracket' => ['(DC2Type:should.stop)).before)', 'should.stop', $currentType], - 'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop', $currentType], + 'invalid custom type comments' => ['should.return.null', null], + 'valid doctrine type' => ['(DC2Type:guid)', 'guid'], + 'valid with dots' => ['(DC2Type:type.should.return)', 'type.should.return'], + 'valid with namespace' => ['(DC2Type:Namespace\Class)', 'Namespace\Class'], + 'valid with extra closing bracket' => ['(DC2Type:should.stop)).before)', 'should.stop'], + 'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop'], ]; } From 9742200fc3dce6b90e20b4bb4ad51ea3e13a1124 Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Sat, 18 Aug 2018 03:12:18 +0200 Subject: [PATCH 66/66] Enable PHPStan in tests --- composer.json | 1 + composer.lock | 63 +++++++++++++++++-- phpstan.neon.dist | 19 ++++++ .../DBAL/Cache/QueryCacheProfileTest.php | 2 +- .../Tests/DBAL/Driver/AbstractDriverTest.php | 2 +- .../Tests/DBAL/Driver/PDOExceptionTest.php | 2 +- .../Tests/DBAL/Driver/PDOPgSql/DriverTest.php | 4 +- .../Driver/IBMDB2/DB2StatementTest.php | 3 + .../Driver/OCI8/OCI8ConnectionTest.php | 6 +- .../Functional/Driver/PDOConnectionTest.php | 9 +-- .../Driver/SQLAnywhere/StatementTest.php | 4 +- .../Functional/MasterSlaveConnectionTest.php | 6 +- .../Schema/PostgreSqlSchemaManagerTest.php | 3 + .../SchemaManagerFunctionalTestCase.php | 6 ++ .../Schema/SqliteSchemaManagerTest.php | 4 ++ .../DBAL/Functional/Ticket/DBAL630Test.php | 29 +++++---- .../AbstractPostgreSqlPlatformTestCase.php | 9 +++ .../AbstractSQLServerPlatformTestCase.php | 3 + .../DBAL/Platforms/OraclePlatformTest.php | 3 + .../DBAL/Platforms/PostgreSqlPlatformTest.php | 3 + .../Platforms/SQLAnywherePlatformTest.php | 2 +- .../DBAL/Platforms/SqlitePlatformTest.php | 7 +++ .../DBAL/Schema/MySqlSchemaManagerTest.php | 3 +- .../Doctrine/Tests/DBAL/Schema/SchemaTest.php | 8 ++- .../Sharding/PoolingShardConnectionTest.php | 17 +++++ tests/Doctrine/Tests/DBAL/StatementTest.php | 8 +-- .../DBAL/Tools/Console/RunSqlCommandTest.php | 3 +- .../DBAL/Types/DateImmutableTypeTest.php | 42 ++++++++----- .../DBAL/Types/DateTimeImmutableTypeTest.php | 47 ++++++++------ .../Types/DateTimeTzImmutableTypeTest.php | 40 +++++++----- .../DBAL/Types/TimeImmutableTypeTest.php | 42 ++++++++----- .../Types/VarDateTimeImmutableTypeTest.php | 35 ++++++----- .../Doctrine/Tests/DbalFunctionalTestCase.php | 4 +- 33 files changed, 318 insertions(+), 121 deletions(-) diff --git a/composer.json b/composer.json index e500fadce6e..7461bede50d 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "doctrine/coding-standard": "^6.0", "jetbrains/phpstorm-stubs": "^2018.1.2", "phpstan/phpstan": "^0.11.3", + "phpstan/phpstan-phpunit": "^0.11.0", "phpunit/phpunit": "^8.0", "symfony/console": "^2.0.5|^3.0|^4.0", "symfony/phpunit-bridge": "^3.4.5|^4.0.5" diff --git a/composer.lock b/composer.lock index 0ebaf91a8a1..07bd8b3dd36 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d3d90c1610c13280a504da32dd4cff4a", + "content-hash": "7a54295261f37704a585b68b07b82487", "packages": [ { "name": "doctrine/cache", @@ -700,7 +700,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", + "description": "? Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", "homepage": "https://nette.org", "keywords": [ "compiled", @@ -765,7 +765,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "🔍 Nette Finder: find files and directories with an intuitive API.", + "description": "? Nette Finder: find files and directories with an intuitive API.", "homepage": "https://nette.org", "keywords": [ "filesystem", @@ -825,7 +825,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "🍸 Nette NEON: encodes and decodes NEON file format.", + "description": "? Nette NEON: encodes and decodes NEON file format.", "homepage": "http://ne-on.org", "keywords": [ "export", @@ -888,7 +888,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", + "description": "? Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", "homepage": "https://nette.org", "keywords": [ "code", @@ -952,7 +952,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", "homepage": "https://nette.org", "keywords": [ "autoload", @@ -1532,6 +1532,57 @@ "description": "PHPStan - PHP Static Analysis Tool", "time": "2019-03-10T16:25:30+00:00" }, + { + "name": "phpstan/phpstan-phpunit", + "version": "0.11", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "70c22d44b96a21a4952fc13021a5a63cc83f5c81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70c22d44b96a21a4952fc13021a5a63cc83f5c81", + "reference": "70c22d44b96a21a4952fc13021a5a63cc83f5c81", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.0", + "php": "~7.1", + "phpstan/phpdoc-parser": "^0.3", + "phpstan/phpstan": "^0.11" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "consistence/coding-standard": "^3.0.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.0", + "satooshi/php-coveralls": "^1.0", + "slevomat/coding-standard": "^4.5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.11-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "time": "2018-12-22T14:05:04+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "7.0.1", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 71305aa7c85..716e2c59a9a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,7 @@ parameters: level: 7 paths: - %currentWorkingDirectory%/lib + - %currentWorkingDirectory%/tests autoload_files: - %currentWorkingDirectory%/tests/phpstan-polyfill.php reportUnmatchedIgnoredErrors: false @@ -69,3 +70,21 @@ parameters: - message: '~^Strict comparison using === between string|false and null will always evaluate to false\.~' path: %currentWorkingDirectory%/lib/Doctrine/DBAL/Driver/PDOStatement.php + + # impossible inference for covariance + - '~^Property Doctrine\\Tests\\DBAL\\Types\\\S+Test::\$type \(Doctrine\\DBAL\\Types\\\S+Type\) does not accept Doctrine\\DBAL\\Types\\Type\.\z~' + - '~^Property Doctrine\\Tests\\DBAL\\Tools\\Console\\RunSqlCommandTest::\$command \(Doctrine\\DBAL\\Tools\\Console\\Command\\RunSqlCommand\) does not accept Symfony\\Component\\Console\\Command\\Command\.\z~' + + # https://github.com/phpstan/phpstan-phpunit/pull/28 + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/ConnectionTest.php + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php index 6722f68c372..00b5b1bc775 100644 --- a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php +++ b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php @@ -23,7 +23,7 @@ class QueryCacheProfileTest extends DbalTestCase /** @var int[] */ private $params = [666]; - /** @var string[] */ + /** @var int[] */ private $types = [ParameterType::INTEGER]; /** @var string[] */ diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php index c86a75fab5b..91627b70099 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php @@ -108,7 +108,7 @@ public function getSQLState() : ?string $message = 'DBAL exception message'; foreach ($data as $item) { - /** @var $driverException \Doctrine\DBAL\Driver\DriverException */ + /** @var DriverException $driverException */ [$driverException, $convertedExceptionClassName] = $item; $convertedException = $this->driver->convertException($message, $driverException); diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php index f8930233dc0..ea7fc9b1d3f 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php @@ -27,7 +27,7 @@ class PDOExceptionTest extends DbalTestCase /** * The wrapped PDO exception mock. * - * @var \PDOException|MockObject + * @var \PDOException */ private $wrappedException; diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php index 00d75b90cb0..d5dffbfb520 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php @@ -9,7 +9,7 @@ use Doctrine\Tests\DBAL\Driver\AbstractPostgreSQLDriverTest; use PDO; use PDOException; -use PHPUnit_Framework_SkippedTestError; +use PHPUnit\Framework\SkippedTestError; use function defined; class DriverTest extends AbstractPostgreSQLDriverTest @@ -111,7 +111,7 @@ protected function createDriver() } /** - * @throws PHPUnit_Framework_SkippedTestError + * @throws SkippedTestError */ private function skipWhenNotUsingPhp56AndPdoPgsql() { diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2StatementTest.php index 536c1093073..e1bb4dc8d31 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2StatementTest.php @@ -5,8 +5,10 @@ namespace Doctrine\Tests\DBAL\Functional\Driver\IBMDB2; use Doctrine\DBAL\Driver\IBMDB2\DB2Driver; +use Doctrine\DBAL\Statement; use Doctrine\Tests\DbalFunctionalTestCase; use PHPUnit\Framework\Error\Notice; +use function assert; use function extension_loaded; class DB2StatementTest extends DbalFunctionalTestCase @@ -29,6 +31,7 @@ protected function setUp() : void public function testExecutionErrorsAreNotSuppressed() { $stmt = $this->connection->prepare('SELECT * FROM SYSIBM.SYSDUMMY1 WHERE \'foo\' = ?'); + assert($stmt instanceof Statement); // unwrap the statement to prevent the wrapper from handling the PHPUnit-originated exception $wrappedStmt = $stmt->getWrappedStatement(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/OCI8ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/OCI8ConnectionTest.php index f127473123f..b5ce1aef799 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/OCI8ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/OCI8ConnectionTest.php @@ -8,6 +8,7 @@ use Doctrine\DBAL\Driver\OCI8\OCI8Connection; use Doctrine\DBAL\Schema\Table; use Doctrine\Tests\DbalFunctionalTestCase; +use function assert; use function extension_loaded; class OCI8ConnectionTest extends DbalFunctionalTestCase @@ -27,7 +28,10 @@ protected function setUp() : void $this->markTestSkipped('oci8 only test.'); } - $this->driverConnection = $this->connection->getWrappedConnection(); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof OCI8Connection); + + $this->driverConnection = $wrappedConnection; } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php index 318f285a818..187aec3c430 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php @@ -28,13 +28,14 @@ protected function setUp() : void parent::setUp(); - $this->driverConnection = $this->connection->getWrappedConnection(); - if ($this->driverConnection instanceof PDOConnection) { - return; + $wrappedConnection = $this->connection->getWrappedConnection(); + + if (! $wrappedConnection instanceof PDOConnection) { + $this->markTestSkipped('PDO connection only test.'); } - $this->markTestSkipped('PDO connection only test.'); + $this->driverConnection = $wrappedConnection; } protected function tearDown() : void diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/StatementTest.php index dec46c48350..bbee70ad800 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/StatementTest.php @@ -38,7 +38,7 @@ public function testNonPersistentStatement() self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); - self::assertTrue($prepStmt->execute(), ' Statement non-persistent failed'); + $prepStmt->execute(); } public function testPersistentStatement() @@ -53,6 +53,6 @@ public function testPersistentStatement() self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); - self::assertTrue($prepStmt->execute(), ' Statement persistent failed'); + $prepStmt->execute(); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php index 27a61ee101a..6a7fa25e09e 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php @@ -12,6 +12,7 @@ use Throwable; use const CASE_LOWER; use function array_change_key_case; +use function assert; use function sprintf; use function strlen; use function strtolower; @@ -49,7 +50,10 @@ protected function setUp() : void private function createMasterSlaveConnection(bool $keepSlave = false) : MasterSlaveConnection { - return DriverManager::getConnection($this->createMasterSlaveConnectionParams($keepSlave)); + $connection = DriverManager::getConnection($this->createMasterSlaveConnectionParams($keepSlave)); + assert($connection instanceof MasterSlaveConnection); + + return $connection; } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php index 83896380434..614be414b98 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php @@ -17,6 +17,7 @@ use Doctrine\DBAL\Types\Types; use function array_map; use function array_pop; +use function assert; use function count; use function strtolower; @@ -49,6 +50,8 @@ public function testGetSearchPath() */ public function testGetSchemaNames() { + assert($this->schemaManager instanceof Schema\PostgreSqlSchemaManager); + $names = $this->schemaManager->getSchemaNames(); self::assertIsArray($names); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 07b0cb6b030..5cc8a8037c9 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -4,9 +4,11 @@ namespace Doctrine\Tests\DBAL\Functional\Schema; +use function assert; use Doctrine\Common\EventManager; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Events; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Schema\AbstractAsset; @@ -1547,6 +1549,8 @@ public function testPrimaryKeyAutoIncrement() $this->connection->insert('test_pk_auto_increment', ['text' => '1']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'1\''); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdBeforeDelete = (int) $query->fetchColumn(); @@ -1555,6 +1559,8 @@ public function testPrimaryKeyAutoIncrement() $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'2\''); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php index e1305c6d0a3..7a3e1d6b1d0 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php @@ -4,8 +4,10 @@ namespace Doctrine\Tests\DBAL\Functional\Schema; +use function assert; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Schema; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\BlobType; @@ -274,6 +276,8 @@ public function testPrimaryKeyNoAutoIncrement() $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = "2"'); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php index 820261e5742..ad68c2d1907 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php @@ -4,6 +4,7 @@ namespace Doctrine\Tests\DBAL\Functional\Ticket; +use function assert; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\ParameterType; use Doctrine\Tests\DbalFunctionalTestCase; @@ -39,9 +40,10 @@ protected function setUp() : void protected function tearDown() : void { if ($this->running) { - $this->connection->getWrappedConnection() - ->getWrappedConnection() - ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof PDO); + + $wrappedConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } parent::tearDown(); @@ -75,9 +77,10 @@ public function testBooleanConversionBoolParamRealPrepares() public function testBooleanConversionBoolParamEmulatedPrepares() { - $this->connection->getWrappedConnection() - ->getWrappedConnection() - ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof PDO); + + $wrappedConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -101,9 +104,10 @@ public function testBooleanConversionNullParamEmulatedPrepares( $statementValue, $databaseConvertedValue ) { - $this->connection->getWrappedConnection() - ->getWrappedConnection() - ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof PDO); + + $wrappedConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -127,9 +131,10 @@ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInB $statementValue, $databaseConvertedValue ) { - $this->connection->getWrappedConnection() - ->getWrappedConnection() - ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof PDO); + + $wrappedConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php index ed31a21fffc..0480786c6e1 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php @@ -4,6 +4,7 @@ namespace Doctrine\Tests\DBAL\Platforms; +use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ColumnDiff; use Doctrine\DBAL\Schema\Comparator; @@ -15,6 +16,8 @@ use Doctrine\DBAL\Types\Type; use UnexpectedValueException; use function sprintf; +use function assert; + abstract class AbstractPostgreSqlPlatformTestCase extends AbstractPlatformTestCase { @@ -934,6 +937,8 @@ public function testInitializesTsvectorTypeMapping() */ public function testReturnsDisallowDatabaseConnectionsSQL() { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertSame( "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'", $this->platform->getDisallowDatabaseConnectionsSQL('foo') @@ -945,6 +950,8 @@ public function testReturnsDisallowDatabaseConnectionsSQL() */ public function testReturnsCloseActiveDatabaseConnectionsSQL() { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertSame( "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'", $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') @@ -1033,6 +1040,8 @@ public function testQuotesSchemaNameInListTableColumnsSQL() */ public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\") diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index 214fc45e42e..ed6bac4f2ce 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\DBAL\Platforms; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ColumnDiff; use Doctrine\DBAL\Schema\Index; @@ -12,6 +13,7 @@ use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; +use function assert; use function sprintf; abstract class AbstractSQLServerPlatformTestCase extends AbstractPlatformTestCase @@ -1118,6 +1120,7 @@ protected function getQuotesDropConstraintSQL() */ public function testGeneratesIdentifierNamesInDefaultConstraintDeclarationSQL($table, $column, $expectedSql) { + assert($this->platform instanceof SQLServerPlatform); self::assertSame($expectedSql, $this->platform->getDefaultConstraintDeclarationSQL($table, $column)); } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php index a49ecaf71d8..b82eb04d8c3 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php @@ -16,6 +16,7 @@ use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; use function array_walk; +use function assert; use function preg_replace; use function sprintf; use function strtoupper; @@ -638,6 +639,8 @@ public function getAlterTableRenameColumnSQL() */ public function testReturnsDropAutoincrementSQL($table, $expectedSql) { + assert($this->platform instanceof OraclePlatform); + self::assertSame($expectedSql, $this->platform->getDropAutoincrementSql($table)); } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php index c4ca74f3535..eec1c81ecd4 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Types\Type; +use function assert; class PostgreSqlPlatformTest extends AbstractPostgreSqlPlatformTestCase { @@ -75,6 +76,8 @@ public function testInitializesJsonTypeMapping() */ public function testReturnsCloseActiveDatabaseConnectionsSQL() { + assert($this->platform instanceof PostgreSqlPlatform); + 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/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index e3833d0ccc7..42c1fa3bda3 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -1145,7 +1145,7 @@ public function testQuotesSchemaNameInListTableColumnsSQL() */ public function testQuotesTableNameInListTableConstraintsSQL() { - self::assertStringContainsStringIgnoringCase("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), '', true); + self::assertStringContainsStringIgnoringCase("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), ''); } /** diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index a17dd3e66a0..8b76f6ce2f6 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -11,6 +11,7 @@ use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; +use function assert; class SqlitePlatformTest extends AbstractPlatformTestCase { @@ -78,6 +79,8 @@ public function testIgnoresUnsignedIntegerDeclarationForAutoIncrementalIntegers( */ public function testGeneratesTypeDeclarationForTinyIntegers() { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'TINYINT', $this->platform->getTinyIntTypeDeclarationSQL([]) @@ -108,6 +111,8 @@ public function testGeneratesTypeDeclarationForTinyIntegers() */ public function testGeneratesTypeDeclarationForSmallIntegers() { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([]) @@ -142,6 +147,8 @@ public function testGeneratesTypeDeclarationForSmallIntegers() */ public function testGeneratesTypeDeclarationForMediumIntegers() { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'MEDIUMINT', $this->platform->getMediumIntTypeDeclarationSQL([]) diff --git a/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php index 2b400afe78e..a748987464d 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\MySqlSchemaManager; use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\MockObject; use function array_map; class MySqlSchemaManagerTest extends TestCase @@ -20,7 +21,7 @@ class MySqlSchemaManagerTest extends TestCase /** @var AbstractSchemaManager */ private $manager; - /** @var Connection */ + /** @var Connection|MockObject */ private $conn; protected function setUp() : void diff --git a/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php b/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php index 19d991e7e9d..f5c085ccee7 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php @@ -401,7 +401,9 @@ public function testVisitsVisitor() $visitor->expects($this->exactly(2)) ->method('acceptSequence'); - self::assertNull($schema->visit($visitor)); + $schema->visit($visitor); + + self::doesNotPerformAssertions(); // FIXME } /** @@ -462,6 +464,8 @@ public function testVisitsNamespaceVisitor() $visitor->expects($this->exactly(2)) ->method('acceptSequence'); - self::assertNull($schema->visit($visitor)); + $schema->visit($visitor); + + self::doesNotPerformAssertions(); // FIXME } } diff --git a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php index d1dcf3938b2..6a9e17a2bf7 100644 --- a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Sharding\ShardingException; use PHPUnit\Framework\TestCase; use stdClass; +use function assert; /** * @requires extension pdo_sqlite @@ -29,6 +30,8 @@ public function testConnect() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertFalse($conn->isConnected(0)); $conn->connect(0); self::assertEquals(1, $conn->fetchColumn('SELECT 1')); @@ -173,6 +176,8 @@ public function testSwitchShardWithOpenTransactionException() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + $conn->beginTransaction(); $this->expectException(ShardingException::class); @@ -192,6 +197,8 @@ public function testGetActiveShardId() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertNull($conn->getActiveShardId()); $conn->connect(0); @@ -216,6 +223,8 @@ public function testGetParamsOverride() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', @@ -256,6 +265,8 @@ public function testGetHostOverride() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals('localhost', $conn->getHost()); $conn->connect(1); @@ -275,6 +286,8 @@ public function testGetPortOverride() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals(3306, $conn->getPort()); $conn->connect(1); @@ -294,6 +307,8 @@ public function testGetUsernameOverride() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals('foo', $conn->getUsername()); $conn->connect(1); @@ -313,6 +328,8 @@ public function testGetPasswordOverride() 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals('foo', $conn->getPassword()); $conn->connect(1); diff --git a/tests/Doctrine/Tests/DBAL/StatementTest.php b/tests/Doctrine/Tests/DBAL/StatementTest.php index d5c3b635dd6..e66cbaa9697 100644 --- a/tests/Doctrine/Tests/DBAL/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/StatementTest.php @@ -15,17 +15,17 @@ use Doctrine\DBAL\Statement; use Doctrine\Tests\DbalTestCase; use Exception; -use PDOStatement; +use PHPUnit\Framework\MockObject\MockObject; class StatementTest extends DbalTestCase { - /** @var Connection */ + /** @var Connection|MockObject */ private $conn; - /** @var Configuration */ + /** @var Configuration|MockObject */ private $configuration; - /** @var PDOStatement */ + /** @var DriverStatement|MockObject */ private $driverStatement; protected function setUp() : void diff --git a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php index 076ebd9084c..27575320fa4 100644 --- a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php +++ b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php @@ -10,6 +10,7 @@ use LogicException; use PHPUnit\Framework\TestCase; use RuntimeException; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; @@ -20,7 +21,7 @@ class RunSqlCommandTest extends TestCase /** @var RunSqlCommand */ private $command; - /** @var Connection */ + /** @var Connection|MockObject */ private $connectionMock; protected function setUp() : void diff --git a/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php index 6e8adc83884..619cf385711 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php @@ -13,11 +13,12 @@ use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\MockObject; use function get_class; class DateImmutableTypeTest extends TestCase { - /** @var AbstractPlatform|ObjectProphecy */ + /** @var AbstractPlatform|MockObject */ private $platform; /** @var DateImmutableType */ @@ -26,7 +27,7 @@ class DateImmutableTypeTest extends TestCase protected function setUp() : void { $this->type = Type::getType('date_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() @@ -46,46 +47,53 @@ public function testReturnsBindingType() public function testConvertsDateTimeImmutableInstanceToDatabaseValue() { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->createMock(DateTimeImmutable::class); - $this->platform->getDateFormatString()->willReturn('Y-m-d')->shouldBeCalled(); - $date->format('Y-m-d')->willReturn('2016-01-01')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d') + ->willReturn('2016-01-01'); self::assertSame( '2016-01-01', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateStringToPHPValue() { - $this->platform->getDateFormatString()->willReturn('Y-m-d')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); - $date = $this->type->convertToPHPValue('2016-01-01', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01', $date->format('Y-m-d')); @@ -93,9 +101,11 @@ public function testConvertsDateStringToPHPValue() public function testResetTimeFractionsWhenConvertingToPHPValue() { - $this->platform->getDateFormatString()->willReturn('Y-m-d'); + $this->platform->expects($this->any()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); - $date = $this->type->convertToPHPValue('2016-01-01', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertSame('2016-01-01 00:00:00.000000', $date->format('Y-m-d H:i:s.u')); } @@ -104,11 +114,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateStri { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid date string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid date string', $this->platform); } public function testRequiresSQLCommentHint() { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeImmutableTypeTest.php index 516317cee54..38864e7e914 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeImmutableTypeTest.php @@ -12,12 +12,12 @@ use Doctrine\DBAL\Types\DateTimeImmutableType; use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; -use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\MockObject; use function get_class; class DateTimeImmutableTypeTest extends TestCase { - /** @var AbstractPlatform|ObjectProphecy */ + /** @var AbstractPlatform|MockObject */ private $platform; /** @var DateTimeImmutableType */ @@ -26,7 +26,7 @@ class DateTimeImmutableTypeTest extends TestCase protected function setUp() : void { $this->type = Type::getType('datetime_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() @@ -46,46 +46,53 @@ public function testReturnsBindingType() public function testConvertsDateTimeImmutableInstanceToDatabaseValue() { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); - $date->format('Y-m-d H:i:s')->willReturn('2016-01-01 15:58:59')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s') + ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeStringToPHPValue() { - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); @@ -96,24 +103,28 @@ public function testConvertsDateTimeStringToPHPValue() */ public function testConvertsDateTimeStringWithMicrosecondsToPHPValue() { - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s'); + $this->platform->expects($this->any()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456', $this->platform); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeString() { - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); + $this->platform->expects($this->atLeastOnce()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid datetime string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid datetime string', $this->platform); } public function testRequiresSQLCommentHint() { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzImmutableTypeTest.php index 359d5b1b28c..7feaa5fa4c0 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzImmutableTypeTest.php @@ -13,11 +13,12 @@ use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\MockObject; use function get_class; class DateTimeTzImmutableTypeTest extends TestCase { - /** @var AbstractPlatform|ObjectProphecy */ + /** @var AbstractPlatform|MockObject */ private $platform; /** @var DateTimeTzImmutableType */ @@ -26,7 +27,7 @@ class DateTimeTzImmutableTypeTest extends TestCase protected function setUp() : void { $this->type = Type::getType('datetimetz_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() @@ -46,46 +47,53 @@ public function testReturnsBindingType() public function testConvertsDateTimeImmutableInstanceToDatabaseValue() { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->createMock(DateTimeImmutable::class); - $this->platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); - $date->format('Y-m-d H:i:s T')->willReturn('2016-01-01 15:58:59 UTC')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s T') + ->willReturn('2016-01-01 15:58:59 UTC'); self::assertSame( '2016-01-01 15:58:59 UTC', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeWithTimezoneStringToPHPValue() { - $this->platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59 UTC', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59 UTC', $date->format('Y-m-d H:i:s T')); @@ -93,15 +101,17 @@ public function testConvertsDateTimeWithTimezoneStringToPHPValue() public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeWithTimezoneString() { - $this->platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); + $this->platform->expects($this->atLeastOnce()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform); } public function testRequiresSQLCommentHint() { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php index 3e93f3a921b..d4d483b31fc 100644 --- a/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php @@ -13,11 +13,12 @@ use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\MockObject; use function get_class; class TimeImmutableTypeTest extends TestCase { - /** @var AbstractPlatform|ObjectProphecy */ + /** @var AbstractPlatform|MockObject */ private $platform; /** @var TimeImmutableType */ @@ -26,7 +27,7 @@ class TimeImmutableTypeTest extends TestCase protected function setUp() : void { $this->type = Type::getType('time_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() @@ -46,46 +47,53 @@ public function testReturnsBindingType() public function testConvertsDateTimeImmutableInstanceToDatabaseValue() { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getTimeFormatString()->willReturn('H:i:s')->shouldBeCalled(); - $date->format('H:i:s')->willReturn('15:58:59')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); + $date->expects($this->once()) + ->method('format') + ->with('H:i:s') + ->willReturn('15:58:59'); self::assertSame( '15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsTimeStringToPHPValue() { - $this->platform->getTimeFormatString()->willReturn('H:i:s')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); - $date = $this->type->convertToPHPValue('15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('15:58:59', $date->format('H:i:s')); @@ -93,9 +101,11 @@ public function testConvertsTimeStringToPHPValue() public function testResetDateFractionsWhenConvertingToPHPValue() { - $this->platform->getTimeFormatString()->willReturn('H:i:s'); + $this->platform->expects($this->any()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); - $date = $this->type->convertToPHPValue('15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertSame('1970-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } @@ -104,11 +114,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidTimeStri { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid time string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid time string', $this->platform); } public function testRequiresSQLCommentHint() { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php index f38fcef6e5f..abddf081b9e 100644 --- a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php @@ -13,10 +13,11 @@ use Doctrine\DBAL\Types\VarDateTimeImmutableType; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\MockObject; class VarDateTimeImmutableTypeTest extends TestCase { - /** @var AbstractPlatform|ObjectProphecy */ + /** @var AbstractPlatform|MockObject */ private $platform; /** @var VarDateTimeImmutableType */ @@ -29,7 +30,7 @@ protected function setUp() : void } $this->type = Type::getType('vardatetime_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testReturnsName() @@ -44,46 +45,52 @@ public function testReturnsBindingType() public function testConvertsDateTimeImmutableInstanceToDatabaseValue() { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); - $date->format('Y-m-d H:i:s')->willReturn('2016-01-01 15:58:59')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s') + ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateishStringToPHPValue() { - $this->platform->getDateTimeFormatString()->shouldNotBeCalled(); + $this->platform->expects($this->never()) + ->method('getDateTimeFormatString'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456 UTC', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59.123456 UTC', $date->format('Y-m-d H:i:s.u T')); @@ -93,11 +100,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateishS { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid date-ish string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid date-ish string', $this->platform); } public function testRequiresSQLCommentHint() { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DbalFunctionalTestCase.php b/tests/Doctrine/Tests/DbalFunctionalTestCase.php index f34a5fd0d0e..67e6bc37221 100644 --- a/tests/Doctrine/Tests/DbalFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DbalFunctionalTestCase.php @@ -25,7 +25,7 @@ abstract class DbalFunctionalTestCase extends DbalTestCase /** * Shared connection when a TestCase is run alone (outside of it's functional suite) * - * @var Connection + * @var Connection|null */ private static $sharedConnection; @@ -37,7 +37,7 @@ abstract class DbalFunctionalTestCase extends DbalTestCase protected function resetSharedConn() { - if (! self::$sharedConnection) { + if (self::$sharedConnection === null) { return; }