From 5d2282389438138b91b31742f7b7f4779e1a2122 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 20 Sep 2020 16:53:37 -0700 Subject: [PATCH 01/10] Bump version to 2.11.1-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 cc4069ee9d2..0acc959aeaf 100644 --- a/lib/Doctrine/DBAL/Version.php +++ b/lib/Doctrine/DBAL/Version.php @@ -17,7 +17,7 @@ class Version /** * Current Doctrine Version. */ - public const VERSION = '2.11.0'; + public const VERSION = '2.11.1-DEV'; /** * Compares a Doctrine version with the current one. From 7ca934c979d9cf8908084d40958b1130d9583a63 Mon Sep 17 00:00:00 2001 From: Quentin Dequippe Date: Tue, 22 Sep 2020 17:34:28 +0200 Subject: [PATCH 02/10] Fix phpdoc of deprecated Remove "All" for some deprecated phpdoc --- lib/Doctrine/DBAL/Connection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 82ef5d80170..af803e5db26 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -541,7 +541,7 @@ public function setFetchMode($fetchMode) * Prepares and executes an SQL query and returns the first row of the result * as an associative array. * - * @deprecated Use fetchAllAssociative() + * @deprecated Use fetchAssociative() * * @param string $sql The query SQL * @param mixed[] $params The query parameters @@ -560,7 +560,7 @@ public function fetchAssoc($sql, array $params = [], array $types = []) * Prepares and executes an SQL query and returns the first row of the result * as a numerically indexed array. * - * @deprecated Use fetchAllNumeric() + * @deprecated Use fetchNumeric() * * @param string $sql The query SQL * @param mixed[] $params The query parameters From 8557a3227a5ecdfee613671040048e3a91e9b140 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Tue, 22 Sep 2020 15:06:04 -0700 Subject: [PATCH 03/10] Restore PDOStatement::quote() for backward compatibility --- lib/Doctrine/DBAL/Driver/PDOConnection.php | 9 +++++++++ phpcs.xml.dist | 5 +++++ .../DBAL/Functional/Driver/PDO/ConnectionTest.php | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 43b8280ef70..8409952cb4e 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -5,6 +5,7 @@ use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\PDO\Exception; use Doctrine\DBAL\Driver\PDO\Statement; +use Doctrine\DBAL\ParameterType; use PDO; use PDOException; use PDOStatement; @@ -101,6 +102,14 @@ public function query() } } + /** + * {@inheritdoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + return parent::quote($value, $type); + } + /** * {@inheritdoc} */ diff --git a/phpcs.xml.dist b/phpcs.xml.dist index c82ca439eca..8c6b82da6b0 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -110,6 +110,11 @@ lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php + + + lib/Doctrine/DBAL/Driver/PDOConnection.php + + lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDO/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDO/ConnectionTest.php index f54cb07b06a..c9f748fbce6 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDO/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDO/ConnectionTest.php @@ -1,5 +1,7 @@ driverConnection->query('foo'); } + + /** + * This test ensures backward compatibility with DBAL 2.x and should be removed in 3.0. + */ + public function testQuoteInteger(): void + { + self::assertSame("'1'", $this->connection->getWrappedConnection()->quote(1)); + } } From 0325f424ae9d85d5085b6ebe13bae13c84bea9cb Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 22 Sep 2020 23:51:37 +0200 Subject: [PATCH 04/10] Fix BC break Ignore empty strings in QueryBuilder::and/orWhere() & and/orHaving(). --- lib/Doctrine/DBAL/Query/QueryBuilder.php | 5 + .../Tests/DBAL/Query/QueryBuilderTest.php | 100 ++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/lib/Doctrine/DBAL/Query/QueryBuilder.php b/lib/Doctrine/DBAL/Query/QueryBuilder.php index 6c4aa6ef029..a1306754836 100644 --- a/lib/Doctrine/DBAL/Query/QueryBuilder.php +++ b/lib/Doctrine/DBAL/Query/QueryBuilder.php @@ -8,6 +8,7 @@ use Doctrine\DBAL\Query\Expression\CompositeExpression; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; +use function array_filter; use function array_key_exists; use function array_keys; use function array_unshift; @@ -829,6 +830,7 @@ public function where($predicates) public function andWhere($where) { $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 $where = $this->getQueryPart('where'); if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_AND) { @@ -862,6 +864,7 @@ public function andWhere($where) public function orWhere($where) { $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 $where = $this->getQueryPart('where'); if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_OR) { @@ -1010,6 +1013,7 @@ public function having($having) public function andHaving($having) { $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 $having = $this->getQueryPart('having'); if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_AND) { @@ -1033,6 +1037,7 @@ public function andHaving($having) public function orHaving($having) { $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 $having = $this->getQueryPart('having'); if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_OR) { diff --git a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php index bc671787877..038097c8910 100644 --- a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php @@ -949,4 +949,104 @@ public function testJoinWithNonUniqueAliasThrowsException(): void $qb->getSQL(); } + + public function testAndWhereEmptyStringStartingWithEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo'); + + $qb->andWhere('', 'a = b'); + + self::assertSame('SELECT id FROM foo WHERE a = b', $qb->getSQL()); + } + + public function testAndWhereEmptyStringStartingWithNonEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo') + ->where('a = b'); + + $qb->andWhere('', 'c = d'); + + self::assertSame('SELECT id FROM foo WHERE (a = b) AND (c = d)', $qb->getSQL()); + } + + public function testOrWhereEmptyStringStartingWithEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo'); + + $qb->orWhere('', 'a = b'); + + self::assertSame('SELECT id FROM foo WHERE a = b', $qb->getSQL()); + } + + public function testOrWhereEmptyStringStartingWithNonEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo') + ->where('a = b'); + + $qb->orWhere('', 'c = d'); + + self::assertSame('SELECT id FROM foo WHERE (a = b) OR (c = d)', $qb->getSQL()); + } + + public function testAndHavingEmptyStringStartingWithEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo'); + + $qb->andHaving('', 'a = b'); + + self::assertSame('SELECT id FROM foo HAVING a = b', $qb->getSQL()); + } + + public function testAndHavingEmptyStringStartingWithNonEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo') + ->having('a = b'); + + $qb->andHaving('', 'c = d'); + + self::assertSame('SELECT id FROM foo HAVING (a = b) AND (c = d)', $qb->getSQL()); + } + + public function testOrHavingEmptyStringStartingWithEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo'); + + $qb->orHaving('', 'a = b'); + + self::assertSame('SELECT id FROM foo HAVING a = b', $qb->getSQL()); + } + + public function testOrHavingEmptyStringStartingWithNonEmptyExpression(): void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('foo') + ->having('a = b'); + + $qb->orHaving('', 'c = d'); + + self::assertSame('SELECT id FROM foo HAVING (a = b) OR (c = d)', $qb->getSQL()); + } } From e90de0cdefa9791cb19a91e3d9e77785c251713b Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 23 Sep 2020 12:15:09 -0700 Subject: [PATCH 05/10] Deprecated the Abstraction\Result interface --- UPGRADE.md | 4 ++++ lib/Doctrine/DBAL/Abstraction/Result.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 9eb98d764a3..e8c8997dc67 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 2.11 +## Deprecated `Abstraction\Result` + +The usage of the `Doctrine\DBAL\Abstraction\Result` interface is deprecated. In DBAL 3.0, the statement result at the wrapper level will be represented by the `Doctrine\DBAL\Result` class. + ## Deprecated the functionality of dropping client connections when dropping a database The corresponding `getDisallowDatabaseConnectionsSQL()` and `getCloseActiveDatabaseConnectionsSQL` methods diff --git a/lib/Doctrine/DBAL/Abstraction/Result.php b/lib/Doctrine/DBAL/Abstraction/Result.php index 42ff3419e37..2b1f8e69f3f 100644 --- a/lib/Doctrine/DBAL/Abstraction/Result.php +++ b/lib/Doctrine/DBAL/Abstraction/Result.php @@ -11,6 +11,8 @@ /** * Abstraction-level result statement execution result. Provides additional methods on top * of the driver-level interface. + * + * @deprecated */ interface Result extends DriverResult { From 35c778bcfdf743c9bee88348e4c09fbe200536f0 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Mon, 20 Jul 2020 00:58:01 +0200 Subject: [PATCH 06/10] Fix 2nd/3rd parameter not allowed for PDO::FETCH_COLUMN --- lib/Doctrine/DBAL/Statement.php | 10 ++- .../Functional/ExternalPDOInstanceTest.php | 70 +++++++++++++++++++ .../DBAL/Functional/StatementTestModel.php | 24 +++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/Doctrine/Tests/DBAL/Functional/ExternalPDOInstanceTest.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/StatementTestModel.php diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index 0e47e09303c..294866921ec 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -264,7 +264,15 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { - return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + if ($ctorArgs !== null) { + return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + } + + if ($fetchArgument !== null) { + return $this->stmt->fetchAll($fetchMode, $fetchArgument); + } + + return $this->stmt->fetchAll($fetchMode); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/ExternalPDOInstanceTest.php b/tests/Doctrine/Tests/DBAL/Functional/ExternalPDOInstanceTest.php new file mode 100644 index 00000000000..42af9d29ea5 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/ExternalPDOInstanceTest.php @@ -0,0 +1,70 @@ +getDriver() instanceof PDOSqliteDriver) { + $this->markTestSkipped('External PDO instance tests are only run on PDO SQLite for now'); + } + + $pdo = new PDO('sqlite::memory:'); + + $this->connection = new Connection(['pdo' => $pdo], new PDOSqliteDriver()); + + $table = new Table('stmt_fetch_all'); + $table->addColumn('a', 'integer'); + $table->addColumn('b', 'integer'); + + $this->connection->getSchemaManager()->createTable($table); + + $this->connection->insert('stmt_fetch_all', [ + 'a' => 1, + 'b' => 2, + ]); + } + + public function testFetchAllWithOneArgument(): void + { + $stmt = $this->connection->prepare('SELECT a, b FROM stmt_fetch_all'); + $stmt->execute(); + + self::assertEquals([[1, 2]], $stmt->fetchAll(FetchMode::NUMERIC)); + } + + public function testFetchAllWithTwoArguments(): void + { + $stmt = $this->connection->prepare('SELECT a, b FROM stmt_fetch_all'); + $stmt->execute(); + + self::assertEquals([2], $stmt->fetchAll(FetchMode::COLUMN, 1)); + } + + public function testFetchAllWithThreeArguments(): void + { + $stmt = $this->connection->prepare('SELECT a, b FROM stmt_fetch_all'); + $stmt->execute(); + + [$obj] = $stmt->fetchAll(FetchMode::CUSTOM_OBJECT, StatementTestModel::class, ['foo', 'bar']); + + $this->assertInstanceOf(StatementTestModel::class, $obj); + + self::assertEquals(1, $obj->a); + self::assertEquals(2, $obj->b); + self::assertEquals('foo', $obj->x); + self::assertEquals('bar', $obj->y); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTestModel.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTestModel.php new file mode 100644 index 00000000000..16bb6e1e1a3 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTestModel.php @@ -0,0 +1,24 @@ +x = $x; + $this->y = $y; + } + + /** @var int */ + public $a; + + /** @var int */ + public $b; + + /** @var string */ + public $x; + + /** @var string */ + public $y; +} From 9346bbd16d0fdb6c9d821bfa6e8b41bd8f5581c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 25 Sep 2020 23:40:56 +0200 Subject: [PATCH 07/10] Increase indent in definition lists Although the official docs [1] show examples of definition list with an indent of 2 spaces, it seems that doctrine/rst-parser has been written with an indent of 4 spaces in mind. [2] This should ensure the definition lists are properly parsed as such, right now they are parsed as paragraphs. [1] https://docutils.sourceforge.io/docs/user/rst/quickref.html#definition-lists [2] https://github.com/doctrine/rst-parser/blob/d97da75a8a2cab33453711f01b90303f5c3845db/lib/Parser/LineDataParser.php#L154 --- docs/en/explanation/implicit-indexes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/explanation/implicit-indexes.rst b/docs/en/explanation/implicit-indexes.rst index f68edbe3ffb..9f96e8a34cb 100644 --- a/docs/en/explanation/implicit-indexes.rst +++ b/docs/en/explanation/implicit-indexes.rst @@ -6,13 +6,13 @@ with names such as ``IDX_885DBAFAA76ED395``? In this document, we will distinguish three types of indexes: user-defined indexes - indexes you did ask for + indexes you did ask for DBAL-defined indexes - indexes you did not ask for, created on your behalf by the DBAL + indexes you did not ask for, created on your behalf by the DBAL RDBMS-defined indexes - indexes you did not ask for, created on your behalf by the RDBMS + indexes you did not ask for, created on your behalf by the RDBMS RDBMS-defined indexes can be created by some database platforms when you create a foreign key: they will create an index on the referencing From e06d0bb64fff1bd0d8c1f184c593762eaa956ff7 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 25 Sep 2020 17:53:20 -0700 Subject: [PATCH 08/10] Fix ExceptionTest::testConnectionExceptionSqLite() on macOS --- tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php index f5136c66c47..338d3a7aee4 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php @@ -29,6 +29,7 @@ use function version_compare; use const PHP_OS; +use const PHP_OS_FAMILY; class ExceptionTest extends DbalFunctionalTestCase { @@ -303,7 +304,7 @@ public function testConnectionExceptionSqLite(): void } // mode 0 is considered read-only on Windows - $mode = PHP_OS === 'Linux' ? 0444 : 0000; + $mode = PHP_OS_FAMILY === 'Windows' ? 0000 : 0444; $filename = sprintf('%s/%s', sys_get_temp_dir(), 'doctrine_failed_connection_' . $mode . '.db'); From 2cb3417138cd6476f97d7635084101b8e25ee290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 26 Sep 2020 13:51:31 +0200 Subject: [PATCH 09/10] Link to contributing guide --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..c2555ebbd46 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Doctrine has [general contributing guidelines][contributor workflow], make +sure you follow them. + +[contributor workflow]: https://www.doctrine-project.org/contribute/index.html From 6e6903cd5e3a5be60a79439e3ee8fe126f78fe86 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sat, 26 Sep 2020 21:09:41 -0700 Subject: [PATCH 10/10] Release 2.11.1 --- 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 0acc959aeaf..044b85e54aa 100644 --- a/lib/Doctrine/DBAL/Version.php +++ b/lib/Doctrine/DBAL/Version.php @@ -17,7 +17,7 @@ class Version /** * Current Doctrine Version. */ - public const VERSION = '2.11.1-DEV'; + public const VERSION = '2.11.1'; /** * Compares a Doctrine version with the current one.