From 4a03d6f244bfbd5429716b7068a55bef67ea139e Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 24 Nov 2022 20:27:04 +0100 Subject: [PATCH 01/29] DBAL3: Update to `doctrine/dbal` version 3 --- CHANGES.txt | 2 ++ composer.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index d70514a..f162325 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,6 +5,8 @@ CHANGES for crate-dbal Unreleased ========== +- Added support for Doctrine 3 + 2025/11/13 4.0.3 ================ diff --git a/composer.json b/composer.json index 3b7f755..2e8b29d 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "prefer-stable": true, "require": { "php": "^8.0|^8.1|^8.2|^8.3|^8.4|^8.5", - "doctrine/dbal": "^2", + "doctrine/dbal": "^3", "crate/crate-pdo": "^2", "ext-pdo": "*" }, From cf2ca7986e7363ed1c0f33873ec004710670a02e Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 5 May 2023 18:49:52 +0200 Subject: [PATCH 02/29] DBAL3: Adjust interfaces and autoloading to match implementation --- composer.json | 6 ++++-- src/Crate/DBAL/Driver/PDOCrate/Driver.php | 14 +++++++++++++- src/Crate/DBAL/Platforms/CratePlatform.php | 9 +++++++++ .../Test/DBAL/Platforms/CratePlatformTest.php | 2 +- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 2e8b29d..38b1272 100644 --- a/composer.json +++ b/composer.json @@ -31,8 +31,10 @@ }, "autoload-dev": { "psr-0": { - "Crate\\Test": "test", - "Doctrine\\Tests": "vendor/doctrine/dbal/tests" + "Crate\\Test": "test" + }, + "psr-4": { + "Doctrine\\DBAL\\Tests\\": "vendor/doctrine/dbal/tests" } }, "config": { diff --git a/src/Crate/DBAL/Driver/PDOCrate/Driver.php b/src/Crate/DBAL/Driver/PDOCrate/Driver.php index 4734406..10561fc 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Driver.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Driver.php @@ -26,6 +26,8 @@ use Crate\DBAL\Platforms\CratePlatform4; use Crate\DBAL\Schema\CrateSchemaManager; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\API\ExceptionConverter; +use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\VersionAwarePlatformDriver; class Driver implements \Doctrine\DBAL\Driver, VersionAwarePlatformDriver @@ -74,8 +76,9 @@ public function getDatabasePlatform() /** * {@inheritDoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn, AbstractPlatform $platform) { + // TODO: `$platform` added when upgrading to Doctrine3 - what to do with it? return new CrateSchemaManager($conn); } @@ -108,4 +111,13 @@ public function createDatabasePlatformForVersion($version) return new CratePlatform4(); } } + + /** + * {@inheritDoc} + */ + public function getExceptionConverter(): ExceptionConverter + { + // TODO: Implement getExceptionConverter() method. + // Added when upgrading to Doctrine3. + } } diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index a18e5ce..40c275d 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -858,4 +858,13 @@ public function getTableOptionsSQL(string $table) : string "FROM information_schema.tables c " . "WHERE " . $this->getTableWhereClause($table); } + + /** + * {@inheritDoc} + */ + public function getCurrentDatabaseExpression(): string + { + // TODO: Implement getCurrentDatabaseExpression() method. + // Added when upgrading to Doctrine3. + } } diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index f34f9c5..e593fa6 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -35,7 +35,7 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Types\Type; -use Doctrine\Tests\DBAL\Platforms\AbstractPlatformTestCase; +use Doctrine\DBAL\Tests\Platforms\AbstractPlatformTestCase; class CratePlatformTest extends AbstractPlatformTestCase { From 5bfc3062f70a27ce90d94d8e1207dbb92aa99495 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 5 May 2023 19:18:34 +0200 Subject: [PATCH 03/29] DBAL3: Start populating PDOConnection, detouring from PDOCrateDB --- .../DBAL/Driver/PDOCrate/PDOConnection.php | 40 +++++++++++++++++++ .../Test/DBAL/Functional/ConnectionTest.php | 6 +++ 2 files changed, 46 insertions(+) diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 38840ab..6bec1d0 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -23,7 +23,10 @@ namespace Crate\DBAL\Driver\PDOCrate; use Crate\PDO\PDOCrateDB; +use Doctrine\DBAL\Driver\PDO\Exception; +use Doctrine\DBAL\Driver\PDO\Statement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Driver\Statement as StatementInterface; class PDOConnection extends PDOCrateDB implements ServerInfoAwareConnection { @@ -49,4 +52,41 @@ public function requiresQueryForServerVersion() { return false; } + + /** + * {@inheritDoc} + * + * References: + * - https://github.com/doctrine/dbal/issues/2025 + * - https://github.com/doctrine/dbal/pull/517 + * - https://github.com/doctrine/dbal/pull/373 + */ + public function prepare($sql, $options = null): StatementInterface + { + try { + $stmt = $this->connection->prepare($sql, $options); + assert($stmt instanceof PDOStatement); + + return new Statement($stmt); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritDoc} + */ + public function exec($sql): int + { + try { + $result = $this->connection->exec($sql); + + assert($result !== false); + + return $result; + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + } diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index 94955fd..7930417 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -66,6 +66,12 @@ public function testGetDriver() $this->assertInstanceOf('Crate\DBAL\Driver\PDOCrate\Driver', $this->_conn->getDriver()); } + /** + * @var \Doctrine\DBAL\Statement $stmt + * + * @return void + * @throws \Doctrine\DBAL\Exception + */ public function testStatement() { $sql = 'SELECT * FROM sys.cluster'; From 9cf0a19176da0dd5f8102d31a26690ec9c577456 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 5 May 2023 19:44:50 +0200 Subject: [PATCH 04/29] DBAL3: Code-style fixes --- composer.json | 2 +- src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php | 1 - src/Crate/DBAL/Platforms/CratePlatform.php | 2 ++ src/Crate/DBAL/Schema/CrateSchemaManager.php | 3 +++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 38b1272..4f987a1 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ }, "scripts": { "test": "XDEBUG_MODE=coverage phpunit --coverage-clover build/logs/clover.xml", - "check-style": "phpcs", + "check-style": "phpcs -s", "fix-style": "phpcbf" } } diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 6bec1d0..fd84b54 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -88,5 +88,4 @@ public function exec($sql): int throw Exception::new($exception); } } - } diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index 40c275d..72d5a7d 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -433,6 +433,7 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ + // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { return ''; @@ -671,6 +672,7 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE /** * {@inheritDoc} */ + // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore protected function _getCreateTableSQL($name, array $columns, array $options = array()) { $columnListSql = $this->getColumnDeclarationListSQL($columns); diff --git a/src/Crate/DBAL/Schema/CrateSchemaManager.php b/src/Crate/DBAL/Schema/CrateSchemaManager.php index a7bb5f6..cac516b 100644 --- a/src/Crate/DBAL/Schema/CrateSchemaManager.php +++ b/src/Crate/DBAL/Schema/CrateSchemaManager.php @@ -32,6 +32,7 @@ class CrateSchemaManager extends AbstractSchemaManager * {@inheritdoc} * */ + // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { $buffer = []; @@ -51,6 +52,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null /** * {@inheritDoc} */ + // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore protected function _getPortableTableColumnDefinition($tableColumn) { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); @@ -88,6 +90,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) /** * {@inheritDoc} */ + // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore protected function _getPortableTablesList($tables) { $tableNames = array(); From 832226c72b6f826c6a9d349fe366504a2a4c67c5 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 14 Nov 2025 07:33:10 +0100 Subject: [PATCH 05/29] DBAL3: Making actual progress --- CHANGES.txt | 2 +- docs/appendices/data-types.rst | 4 +- docs/appendices/table-options.rst | 4 +- examples/objects.php | 61 ++++++++ .../DBAL/Driver/PDOCrate/CrateStatement.php | 120 +++++++++++++++- src/Crate/DBAL/Driver/PDOCrate/Driver.php | 11 +- src/Crate/DBAL/Driver/PDOCrate/Exception.php | 26 ++++ .../Driver/PDOCrate/ExceptionConverter.php | 58 ++++++++ .../DBAL/Driver/PDOCrate/PDOConnection.php | 92 ++++++++++--- src/Crate/DBAL/Driver/PDOCrate/Result.php | 108 +++++++++++++++ src/Crate/DBAL/Platforms/CratePlatform.php | 13 +- src/Crate/DBAL/Schema/CrateSchemaManager.php | 8 +- src/Crate/DBAL/Types/ArrayType.php | 3 +- .../Test/DBAL/DBALFunctionalTestCase.php | 2 +- .../Test/DBAL/Functional/BindingTest.php | 19 +-- .../Test/DBAL/Functional/ConnectionTest.php | 16 ++- .../Test/DBAL/Functional/DataAccessTest.php | 130 +++++++----------- .../DBAL/Functional/ModifyLimitQueryTest.php | 9 +- .../DBAL/Functional/NamedParametersTest.php | 2 +- .../Functional/Schema/SchemaManagerTest.php | 17 +-- .../Test/DBAL/Functional/TableOptionsTest.php | 10 +- .../DBAL/Functional/TypeConversionTest.php | 19 +-- .../DBAL/Functional/Types/MapTypeTest.php | 5 +- test/Crate/Test/DBAL/Functional/WriteTest.php | 49 +++---- .../Test/DBAL/Platforms/CratePlatformTest.php | 78 ++++++++++- 25 files changed, 664 insertions(+), 202 deletions(-) create mode 100644 examples/objects.php create mode 100644 src/Crate/DBAL/Driver/PDOCrate/Exception.php create mode 100644 src/Crate/DBAL/Driver/PDOCrate/ExceptionConverter.php create mode 100644 src/Crate/DBAL/Driver/PDOCrate/Result.php diff --git a/CHANGES.txt b/CHANGES.txt index f162325..85187c9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,7 +5,7 @@ CHANGES for crate-dbal Unreleased ========== -- Added support for Doctrine 3 +- Added support for Doctrine 3, dropped support for Doctrine 2. 2025/11/13 4.0.3 ================ diff --git a/docs/appendices/data-types.rst b/docs/appendices/data-types.rst index e5786b4..bef578d 100644 --- a/docs/appendices/data-types.rst +++ b/docs/appendices/data-types.rst @@ -89,8 +89,8 @@ Here's an example of how the ``MapType`` can be used: $objDefinition = array( 'type' => MapType::STRICT, 'fields' => array( - new Column('id', Type::getType('integer'), array()), - new Column('name', Type::getType('string'), array()), + new Column('id', Type::getType('integer'), array()), + new Column('name', Type::getType('string'), array()), ), ); $table->addColumn( diff --git a/docs/appendices/table-options.rst b/docs/appendices/table-options.rst index 87471e0..0bb0c25 100644 --- a/docs/appendices/table-options.rst +++ b/docs/appendices/table-options.rst @@ -18,7 +18,7 @@ Example: $options = []; $options['sharding_shards'] = 5; - $myTable = new Table('my_table', [], [], [], 0, $options); + $myTable = new Table('my_table', [], [], [], [], $options); Sharding Options @@ -66,7 +66,7 @@ Example on how to adjust the replicas: $options = []; $options['table_options'] = []; $options['table_options']['number_of_replicas'] = '2'; - $myTable = new Table('my_table', [], [], [], 0, $options); + $myTable = new Table('my_table', [], [], [], [], $options); .. _CrateDB CREATE TABLE Documentation: https://cratedb.com/docs/crate/reference/en/latest/sql/statements/create-table.html diff --git a/examples/objects.php b/examples/objects.php new file mode 100644 index 0000000..71e3544 --- /dev/null +++ b/examples/objects.php @@ -0,0 +1,61 @@ + MapType::STRICT, + 'fields' => array( + new Column('id', Type::getType('integer'), array()), + new Column('name', Type::getType('string'), array()), + ), +); +$table->addColumn( + 'data', + MapType::NAME, + array('platformOptions' => $objDefinition), +); + +// Register driver. +$dsnParser = new DsnParser(array('crate' => 'Crate\DBAL\Driver\PDOCrate\Driver')); + +// Connect to database. +$connectionParams = $dsnParser->parse('crate://crate:crate@localhost:4200/'); +$connection = DriverManager::getConnection($connectionParams); +$schemaManager = $connection->createSchemaManager(); + +// Provision database table. +try { + $schemaManager->dropTable($table); +} catch (TableNotFoundException) { +} +$schemaManager->createTable($table); + +// Insert data. +$connection->insert('example', array('data' => array('id' => 42, 'name' => 'foo')), array('data' => 'map')); +$connection->insert('example', array('data' => array('id' => 43, 'name' => 'bar')), array('data' => 'map')); +$connection->executeStatement('REFRESH TABLE example'); + +// Query data. +$result = $connection->executeQuery('SELECT * FROM example'); +print_r($result->fetchAllAssociative()); + +?> diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index fb26dac..14fc244 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -22,14 +22,128 @@ namespace Crate\DBAL\Driver\PDOCrate; +use Crate\PDO\PDOStatement; +use Crate\PDO\PDOInterface; +use Doctrine\DBAL\Driver\PDO\Exception; use Doctrine\DBAL\Driver\PDOStatementImplementations; use Doctrine\DBAL\Driver\Statement as StatementInterface; -use Crate\PDO\PDOStatement; +use Doctrine\DBAL\Driver\Result as ResultInterface; +use Doctrine\DBAL\ParameterType; +use Doctrine\Deprecations\Deprecation; +use PDO; /** * @internal */ -class CrateStatement extends PDOStatement implements StatementInterface +final class CrateStatement implements StatementInterface { - use PDOStatementImplementations; + + /** + * @var PDOInterface + */ + private $pdo; + + private PDOStatement $stmt; + + public function __construct(PDOInterface $pdo, $sql) + { + $this->pdo = $pdo; + $this->stmt = $pdo->prepare($sql); + } + + /** + * {@inheritDoc} + */ + public function execute($params = null): ResultInterface + { + + if ($params !== null) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/5556', + 'Passing $params to Statement::execute() is deprecated. Bind parameters using' + . ' Statement::bindParam() or Statement::bindValue() instead.', + ); + } + $this->stmt->execute($params); + return new Result($this); + } + + /** + * {@inheritDoc} + */ + public function columnCount(): int + { + return $this->stmt->columnCount(); + } + + /** + * {@inheritDoc} + */ + public function rowCount(): int + { + return $this->stmt->rowCount(); + } + + /** + * {@inheritDoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + $this->stmt->bindValue($param, $value, $type); + } + + /** + * {@inheritDoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + return $this->stmt->bindParam($param, $variable, $type, $length); + } + + /** + * {@inheritDoc} + */ + public function fetch( + $fetch_style = PDO::FETCH_ASSOC, + $cursor_orientation = PDO::FETCH_ORI_NEXT, + $cursor_offset = 0, + ) { + return $this->stmt->fetch($fetch_style, $cursor_orientation, $cursor_offset); + } + + /** + * @phpstan-param PDO::FETCH_* $mode + * + * @return list + * + * @throws Exception + */ + public function fetchAll(int $mode): array + { + return $this->stmt->fetchAll($mode); + } + + public function fetchColumn($column_number = 0) + { + return $this->stmt->fetchColumn($column_number); + } + + /** + * {@inheritDoc} + */ + public function closeCursor(): int + { + return $this->stmt->closeCursor(); + } + + /** + * Gets the wrapped driver statement. + * + * @return Driver\Statement + */ + public function getWrappedStatement() + { + return $this->stmt; + } } diff --git a/src/Crate/DBAL/Driver/PDOCrate/Driver.php b/src/Crate/DBAL/Driver/PDOCrate/Driver.php index 10561fc..441918d 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Driver.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Driver.php @@ -26,7 +26,6 @@ use Crate\DBAL\Platforms\CratePlatform4; use Crate\DBAL\Schema\CrateSchemaManager; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Driver\API\ExceptionConverter; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\VersionAwarePlatformDriver; @@ -70,7 +69,7 @@ private function constructPdoDsn(array $params) */ public function getDatabasePlatform() { - return new CratePlatform(); + return new CratePlatform4(); } /** @@ -78,8 +77,8 @@ public function getDatabasePlatform() */ public function getSchemaManager(Connection $conn, AbstractPlatform $platform) { - // TODO: `$platform` added when upgrading to Doctrine3 - what to do with it? - return new CrateSchemaManager($conn); + // Added by Doctrine 3. + return new CrateSchemaManager($conn, $conn->getDatabasePlatform()); } /** @@ -117,7 +116,7 @@ public function createDatabasePlatformForVersion($version) */ public function getExceptionConverter(): ExceptionConverter { - // TODO: Implement getExceptionConverter() method. - // Added when upgrading to Doctrine3. + // Added by Doctrine 3. + return new ExceptionConverter(); } } diff --git a/src/Crate/DBAL/Driver/PDOCrate/Exception.php b/src/Crate/DBAL/Driver/PDOCrate/Exception.php new file mode 100644 index 0000000..a29a717 --- /dev/null +++ b/src/Crate/DBAL/Driver/PDOCrate/Exception.php @@ -0,0 +1,26 @@ +errorInfo !== null) { + [$sqlState, $code] = $exception->errorInfo; + + $code ??= 0; + } else { + $code = $exception->getCode(); + $sqlState = null; + } + + return new self($exception->getMessage(), $sqlState, $code, $exception); + } +} diff --git a/src/Crate/DBAL/Driver/PDOCrate/ExceptionConverter.php b/src/Crate/DBAL/Driver/PDOCrate/ExceptionConverter.php new file mode 100644 index 0000000..2a8471e --- /dev/null +++ b/src/Crate/DBAL/Driver/PDOCrate/ExceptionConverter.php @@ -0,0 +1,58 @@ +getCode()) { + case '4000': + return new SyntaxErrorException($exception, $query); + + case '4008': + case '4043': + return new InvalidFieldNameException($exception, $query); + + case '4041': + return new TableNotFoundException($exception, $query); + + case '4045': + return new SchemaDoesNotExist($exception, $query); + + case '4091': + return new UniqueConstraintViolationException($exception, $query); + + case '4093': + return new TableExistsException($exception, $query); + } + + // Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.4.10), + // in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code. + // 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 ConnectionException($exception, $query); + } + + return new DriverException($exception, $query); + } +} diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index fd84b54..6a0d90f 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -23,13 +23,19 @@ namespace Crate\DBAL\Driver\PDOCrate; use Crate\PDO\PDOCrateDB; +use Crate\PDO\PDOStatement; use Doctrine\DBAL\Driver\PDO\Exception; -use Doctrine\DBAL\Driver\PDO\Statement; -use Doctrine\DBAL\Driver\ServerInfoAwareConnection; -use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Doctrine\DBAL\Driver\Result as ResultInterface; +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; +use Doctrine\DBAL\ParameterType; +use PDO; +use PDOException; -class PDOConnection extends PDOCrateDB implements ServerInfoAwareConnection +class PDOConnection implements ConnectionInterface { + + private PDOCrateDB $connection; + /** * @param string $dsn * @param string $user @@ -38,19 +44,20 @@ class PDOConnection extends PDOCrateDB implements ServerInfoAwareConnection */ public function __construct($dsn, $user = null, $password = null, ?array $options = null) { - parent::__construct($dsn, $user, $password, $options); - $this->setAttribute(\PDO::ATTR_STATEMENT_CLASS, CrateStatement::class); - $this->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $this->connection = new PDOCrateDB($dsn, $user, $password, $options); + $this->connection->setAttribute(PDO::ATTR_STATEMENT_CLASS, PDOStatement::class); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } - /** - * Checks whether a query is required to retrieve the database server version. - * - * @return boolean True if a query is required to retrieve the database server version, false otherwise. - */ - public function requiresQueryForServerVersion() + public function getServerVersion() { - return false; + // Unable to detect platform version. + return null; + } + + public function getNativeConnection(): PDOCrateDB + { + return $this->connection; } /** @@ -61,13 +68,10 @@ public function requiresQueryForServerVersion() * - https://github.com/doctrine/dbal/pull/517 * - https://github.com/doctrine/dbal/pull/373 */ - public function prepare($sql, $options = null): StatementInterface + public function prepare($sql, $options = []): CrateStatement { try { - $stmt = $this->connection->prepare($sql, $options); - assert($stmt instanceof PDOStatement); - - return new Statement($stmt); + return new CrateStatement($this->connection, $sql, $options); } catch (PDOException $exception) { throw Exception::new($exception); } @@ -80,12 +84,60 @@ public function exec($sql): int { try { $result = $this->connection->exec($sql); + assert($result !== false); + return $result; + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + /** + * {@inheritDoc} + */ + public function quer2y(string $sql): Result + { + try { + $result = $this->connection->query($sql); assert($result !== false); + return new Result($result); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } - return $result; + public function query(string $sql): ResultInterface + { + try { + $stmt = $this->prepare($sql); + $stmt->execute(); + return new Result($stmt); } catch (PDOException $exception) { throw Exception::new($exception); } } + + public function quote($value, $type = ParameterType::STRING): string + { + return $this->connection->quote($value, $type); + } + + public function lastInsertId($name = null): string + { + return $this->connection->lastInsertId($name); + } + + public function beginTransaction(): bool + { + return true; + } + + public function commit(): bool + { + return true; + } + + public function rollBack(): bool + { + return true; + } } diff --git a/src/Crate/DBAL/Driver/PDOCrate/Result.php b/src/Crate/DBAL/Driver/PDOCrate/Result.php new file mode 100644 index 0000000..5d07444 --- /dev/null +++ b/src/Crate/DBAL/Driver/PDOCrate/Result.php @@ -0,0 +1,108 @@ +statement = $statement; + } + + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + return $this->fetch(PDO::FETCH_NUM); + } + + /** + * {@inheritDoc} + */ + public function fetchAssociative() + { + return $this->fetch(PDO::FETCH_ASSOC); + } + + /** + * {@inheritDoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritDoc} + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritDoc} + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritDoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + public function rowCount(): int + { + try { + return $this->statement->rowCount(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + public function columnCount(): int + { + try { + return $this->statement->columnCount(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + public function free(): void + { + $this->statement->closeCursor(); + } + + /** + * @phpstan-param PDO::FETCH_* $mode + * + * @return mixed + * + * @throws Exception + */ + private function fetch(int $mode) + { + try { + return $this->statement->fetch($mode); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } +} diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index 72d5a7d..07c4973 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -23,10 +23,10 @@ use Crate\DBAL\Types\MapType; use Crate\DBAL\Types\TimestampType; -use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs; use Doctrine\DBAL\Event\SchemaCreateTableEventArgs; use Doctrine\DBAL\Events; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\Identifier; use Doctrine\DBAL\Schema\Index; @@ -48,7 +48,6 @@ class CratePlatform extends AbstractPlatform */ public function __construct() { - parent::__construct(); $this->initializeDoctrineTypeMappings(); if (!Type::hasType(MapType::NAME)) { Type::addType(MapType::NAME, 'Crate\DBAL\Types\MapType'); @@ -286,7 +285,7 @@ public function getAlterTableSQL(TableDiff $diff) throw DBALException::notSupported("Alter Table: rename table"); } - $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL); + $sql = array_merge($sql, $this->getPreAlterTableIndexForeignKeySQL($diff), $commentsSQL); } return array_merge($sql, $tableSql, $columnSql); @@ -321,7 +320,7 @@ public function getIndexDeclarationSQL($name, Index $index) } return 'INDEX ' . $name->getQuotedName($this) . - ' USING FULLTEXT ('. $this->getIndexFieldDeclarationListSQL($columns) . ')'; + ' USING FULLTEXT ('. $this->getIndexFieldDeclarationListSQL($index) . ')'; } /** @@ -796,7 +795,7 @@ public static function prepareColumnData(AbstractPlatform $platform, $column, $p $columnData['unique'] = false; $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption("version") : false; - if (strtolower($columnData['type']) == $platform->getVarcharTypeDeclarationSQLSnippet(0, false) + if (strtolower($columnData['type']->getName()) == $platform->getVarcharTypeDeclarationSQLSnippet(0, false) && $columnData['length'] === null) { $columnData['length'] = 255; } @@ -866,7 +865,7 @@ public function getTableOptionsSQL(string $table) : string */ public function getCurrentDatabaseExpression(): string { - // TODO: Implement getCurrentDatabaseExpression() method. - // Added when upgrading to Doctrine3. + // Added by Doctrine 3. + return 'CURRENT_DATABASE()'; } } diff --git a/src/Crate/DBAL/Schema/CrateSchemaManager.php b/src/Crate/DBAL/Schema/CrateSchemaManager.php index cac516b..44c9795 100644 --- a/src/Crate/DBAL/Schema/CrateSchemaManager.php +++ b/src/Crate/DBAL/Schema/CrateSchemaManager.php @@ -21,11 +21,17 @@ */ namespace Crate\DBAL\Schema; +use Crate\DBAL\Platforms\CratePlatform4; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Schema\Table; +/** + * Schema manager for the CrateDB RDBMS. + * + * @extends AbstractSchemaManager + */ class CrateSchemaManager extends AbstractSchemaManager { /** @@ -130,7 +136,7 @@ public function listTableDetails($tableName) : Table $indexes = $this->listTableIndexes($tableName); $options = []; - $s = $this->_conn->fetchAssoc($this->_platform->getTableOptionsSQL($tableName)); + $s = $this->_conn->fetchAssociative($this->_platform->getTableOptionsSQL($tableName)); $options['sharding_routing_column'] = $s['clustered_by']; $options['sharding_num_shards'] = $s['number_of_shards']; diff --git a/src/Crate/DBAL/Types/ArrayType.php b/src/Crate/DBAL/Types/ArrayType.php index cd279c7..c4c40cf 100644 --- a/src/Crate/DBAL/Types/ArrayType.php +++ b/src/Crate/DBAL/Types/ArrayType.php @@ -25,6 +25,7 @@ use Crate\PDO\PDOCrateDB; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Types\Types; /** * Type that maps a PHP sequential array to an array SQL type. @@ -96,7 +97,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla */ public function getArrayTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options) { - $type = array_key_exists('type', $options) ? $options['type'] : Type::STRING; + $type = array_key_exists('type', $options) ? $options['type'] : Types::STRING; return 'ARRAY ( ' . Type::getType($type)->getSQLDeclaration($field, $platform) . ' )'; } } diff --git a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php b/test/Crate/Test/DBAL/DBALFunctionalTestCase.php index 435eacb..9501a76 100644 --- a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php +++ b/test/Crate/Test/DBAL/DBALFunctionalTestCase.php @@ -112,7 +112,7 @@ public function execute($stmt) public function refresh($table_name) { - $this->_conn->query('REFRESH TABLE ' . $table_name); + $this->_conn->executeStatement('REFRESH TABLE ' . $table_name); } public function prepareStatement($sql) diff --git a/test/Crate/Test/DBAL/Functional/BindingTest.php b/test/Crate/Test/DBAL/Functional/BindingTest.php index 819b151..0bb5fb0 100644 --- a/test/Crate/Test/DBAL/Functional/BindingTest.php +++ b/test/Crate/Test/DBAL/Functional/BindingTest.php @@ -22,7 +22,6 @@ namespace Crate\Test\DBAL\Functional; use Crate\Test\DBAL\DBALFunctionalTestCase; -use Doctrine\DBAL\DBALException; class BindingTestCase extends DBALFunctionalTestCase { @@ -40,7 +39,8 @@ public function testBindPositionalParam() $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?'); $stmt->bindParam(1, $name); $stmt->bindParam(2, $noName); - $this->assertTrue($stmt->execute()); + $result = $stmt->execute(); + self::assertEquals(1, $result->rowCount()); } public function testBindPositionalValue() @@ -52,7 +52,8 @@ public function testBindPositionalValue() $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?'); $stmt->bindValue(1, 'crate'); $stmt->bindValue(2, 'i0ejfNlzSFCloGYtSzddTw'); - $this->assertTrue($stmt->execute()); + $result = $stmt->execute(); + self::assertEquals(1, $result->rowCount()); } public function testBindNamedParam() @@ -68,7 +69,8 @@ public function testBindNamedParam() $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node'); $stmt->bindParam('name', $name); $stmt->bindParam('master_node', $noName); - $this->assertTrue($stmt->execute()); + $result = $stmt->execute(); + self::assertEquals(1, $result->rowCount()); } public function testBindNamedValue() @@ -80,7 +82,8 @@ public function testBindNamedValue() $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node'); $stmt->bindValue('name', 'crate'); $stmt->bindValue('master_node', 'i0ejfNlzSFCloGYtSzddTw'); - $this->assertTrue($stmt->execute()); + $result = $stmt->execute(); + self::assertEquals(1, $result->rowCount()); } public function testBindTimestamp() @@ -99,15 +102,13 @@ public function testBindTimestamp() $stmt = $this->prepareStatement('SELECT * FROM foo WHERE ts > ?'); $stmt->bindValue(1, $date, 'datetimetz'); - $stmt->execute(); - $row = $stmt->fetchAll(); + $row = $stmt->executeQuery()->fetchAllAssociative(); $this->assertEquals($row[0]['id'], 3); $this->assertEquals($row[0]['ts'], 1413901593000); $stmt = $this->prepareStatement('SELECT * FROM foo WHERE ts < ?'); $stmt->bindValue(1, $date, 'datetime'); - $stmt->execute(); - $row = $stmt->fetchAll(); + $row = $stmt->executeQuery()->fetchAllAssociative(); $this->assertEquals($row[0]['id'], 1); $this->assertEquals($row[0]['ts'], 1413901591000); diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index 7930417..a284142 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -43,16 +43,19 @@ public function testBasicAuthConnection() $auth = ['crate', 'secret']; $params = array( 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver', + // TODO: Could work by inheriting. + // 'wrapperClass' => 'Crate\DBAL\Driver\PDOCrate\PDOConnection', 'host' => 'localhost', 'port' => 4200, 'user' => $auth[0], 'password' => $auth[1], ); $conn = \Doctrine\DBAL\DriverManager::getConnection($params); - $this->assertEquals($auth[0], $conn->getUsername()); - $this->assertEquals($auth[1], $conn->getPassword()); - $auth_attr = $conn->getWrappedConnection()->getAttribute(PDOCrateDB::CRATE_ATTR_HTTP_BASIC_AUTH); - $this->assertEquals($auth_attr, $auth); + $conn->connect(); + $credentials = $conn->getNativeConnection()->getAttribute(PDOCrateDB::CRATE_ATTR_HTTP_BASIC_AUTH); + + // No leaks any longer: Any empty array is all we got. + $this->assertEquals($credentials, array()); } public function testGetConnection() @@ -76,8 +79,11 @@ public function testStatement() { $sql = 'SELECT * FROM sys.cluster'; $stmt = $this->_conn->prepare($sql); + + // Well, it's three layers of Statement objects now. $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $this->assertInstanceOf('Crate\PDO\PDOStatement', $stmt->getWrappedStatement()); + $this->assertInstanceOf('Crate\DBAL\Driver\PDOCrate\CrateStatement', $stmt->getWrappedStatement()); + $this->assertInstanceOf('Crate\PDO\PDOStatement', $stmt->getWrappedStatement()->getWrappedStatement()); } diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index 4a3cfbe..b6d48da 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -24,11 +24,12 @@ use Crate\DBAL\Types\MapType; use Crate\Test\DBAL\DBALFunctionalTestCase; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Types; use PDO; @@ -90,9 +91,9 @@ public function testPrepareWithBindValue() $stmt->bindValue(1, 1, PDO::PARAM_INT); $stmt->bindValue(2, 'foo', PDO::PARAM_STR); - $stmt->execute(); + $result = $stmt->executeQuery(); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = $result->fetch(PDO::FETCH_ASSOC); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); } @@ -108,9 +109,9 @@ public function testPrepareWithBindParam() $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); + $result = $stmt->executeQuery(); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = $result->fetch(PDO::FETCH_ASSOC); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); } @@ -126,9 +127,9 @@ public function testPrepareWithFetchAll() $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); + $result = $stmt->executeQuery(); - $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $rows = $result->fetchAllAssociative(); $rows[0] = array_change_key_case($rows[0], \CASE_LOWER); $this->assertEquals(array( 'test_int' => 1, @@ -146,27 +147,6 @@ public function testPrepareWithFetchAll() array('foo','bar')); } - /** - * @group DBAL-228 - */ - public function testPrepareWithFetchAllBoth() - { - $paramInt = 1; - $paramStr = 'foo'; - - $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $stmt = $this->_conn->prepare($sql); - $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - - $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); - $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); - - $rows = $stmt->fetchAll(\PDO::FETCH_BOTH); - $rows[0] = array_change_key_case($rows[0], \CASE_LOWER); - $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'), $rows[0]); - } - public function testPrepareWithFetchColumn() { $paramInt = 1; @@ -178,9 +158,8 @@ public function testPrepareWithFetchColumn() $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); + $column = $stmt->getWrappedStatement()->fetchColumn(); - $column = $stmt->fetchColumn(); $this->assertEquals(1, $column); } @@ -195,11 +174,10 @@ public function testPrepareWithIterator() $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); + $result = $stmt->executeQuery(); $rows = array(); - $stmt->setFetchMode(\PDO::FETCH_ASSOC); - foreach ($stmt as $row) { + foreach ($result->iterateAssociative() as $row) { $rows[] = array_change_key_case($row, \CASE_LOWER); } @@ -226,9 +204,9 @@ public function testPrepareWithExecuteParams() $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $stmt->execute(array($paramInt, $paramStr)); + $result = $stmt->execute(array($paramInt, $paramStr)); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = $result->fetch(PDO::FETCH_ASSOC); $this->assertTrue($row !== false); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); @@ -237,7 +215,7 @@ public function testPrepareWithExecuteParams() public function testFetchAll() { $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $data = $this->_conn->fetchAll($sql, array(1, 'foo')); + $data = $this->_conn->fetchAllAssociative($sql, array(1, 'foo')); $this->assertEquals(1, count($data)); @@ -249,25 +227,10 @@ public function testFetchAll() $this->assertEquals('foo', $row['test_string']); } - public function testFetchBoth() - { - $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $row = $this->_conn->executeQuery($sql, array(1, 'foo'))->fetch(\PDO::FETCH_BOTH); - - $this->assertTrue($row !== false); - - $row = array_change_key_case($row, \CASE_LOWER); - - $this->assertEquals(1, $row['test_int']); - $this->assertEquals('foo', $row['test_string']); - $this->assertEquals(1, $row[0]); - $this->assertEquals('foo', $row[1]); - } - public function testFetchRow() { $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $row = $this->_conn->fetchAssoc($sql, array(1, 'foo')); + $row = $this->_conn->fetchAssociative($sql, array(1, 'foo')); $this->assertTrue($row !== false); @@ -280,7 +243,7 @@ public function testFetchRow() public function testFetchArray() { $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $row = $this->_conn->fetchArray($sql, array(1, 'foo')); + $row = $this->_conn->fetchNumeric($sql, array(1, 'foo')); $this->assertEquals(1, $row[0]); $this->assertEquals('foo', $row[1]); @@ -289,13 +252,14 @@ public function testFetchArray() public function testFetchColumn() { $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $testInt = $this->_conn->fetchColumn($sql, array(1, 'foo'), 0); + $stmt = $this->_conn->prepare($sql); + $stmt->executeQuery(array(1, 'foo')); + $testInt = $stmt->getWrappedStatement()->fetchColumn(0); $this->assertEquals(1, $testInt); - $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $testString = $this->_conn->fetchColumn($sql, array(1, 'foo'), 1); - + $stmt->executeQuery(array(1, 'foo')); + $testString = $stmt->getWrappedStatement()->fetchColumn(1); $this->assertEquals('foo', $testString); } @@ -307,10 +271,10 @@ public function testExecuteQueryBindDateTimeType() $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; $stmt = $this->_conn->executeQuery($sql, array(1 => new \DateTime('2010-01-01 10:10:10')), - array(1 => Type::DATETIME) + array(1 => Types::DATETIME_MUTABLE) ); - $this->assertEquals(1, $stmt->fetchColumn()); + $this->assertEquals(1, $stmt->fetchOne()); } /** @@ -323,7 +287,7 @@ public function testExecuteUpdateBindDateTimeType() $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)'; $affectedRows = $this->_conn->executeUpdate($sql, array(1 => 50, 2 => 'foo', 3 => $datetime), - array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Type::DATETIME) + array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Types::DATETIME_MUTABLE) ); $this->assertEquals(1, $affectedRows); $this->refresh('fetch_table'); @@ -331,8 +295,8 @@ public function testExecuteUpdateBindDateTimeType() $this->assertEquals(1, $this->_conn->executeQuery( 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?', array(1 => $datetime), - array(1 => Type::DATETIME) - )->fetchColumn()); + array(1 => Types::DATETIME_MUTABLE) + )->fetchOne()); } /** @@ -342,10 +306,10 @@ public function testPrepareQueryBindValueDateTimeType() { $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; $stmt = $this->_conn->prepare($sql); - $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Type::DATETIME); - $stmt->execute(); + $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Types::DATETIME_MUTABLE); + $result = $stmt->executeQuery(); - $this->assertEquals(1, $stmt->fetchColumn()); + $this->assertEquals(1, $result->fetchOne()); } /** @@ -378,7 +342,7 @@ public function testNativeArrayListSupport() */ public function testDateArithmetics() { - $this->markTestSkipped('Data add day expression not supported by crate platform'); + $this->markTestSkipped('Date arithmetics not supported by CrateDB platform'); $p = $this->_conn->getDatabasePlatform(); $sql = 'SELECT '; @@ -405,7 +369,7 @@ public function testQuoteSQLInjection() $this->expectException(DBALException::class); $sql = "SELECT * FROM fetch_table WHERE test_string = bar' OR '1'='1"; - $this->_conn->fetchAll($sql); + $this->_conn->executeQuery($sql); } /** @@ -413,7 +377,7 @@ public function testQuoteSQLInjection() */ public function testBitComparisonExpressionSupport() { - $this->markTestSkipped("Bit comparison expression not supported by crate"); + $this->markTestSkipped("Bit comparison expressions not supported by CrateDB"); $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); $platform = $this->_conn->getDatabasePlatform(); @@ -464,10 +428,8 @@ public function testBitComparisonExpressionSupport() public function testSetDefaultFetchMode() { - $stmt = $this->_conn->query("SELECT * FROM fetch_table"); - $stmt->setFetchMode(\PDO::FETCH_NUM); - - $row = array_keys($stmt->fetch()); + $result = $this->_conn->executeQuery("SELECT * FROM fetch_table"); + $row = array_keys($result->fetchAllNumeric()); $this->assertEquals(0, count( array_filter($row, function($v) { return ! is_numeric($v); })), "should be no non-numerical elements in the result."); } @@ -476,7 +438,7 @@ public function testSetDefaultFetchMode() */ public function testFetchAllSupportFetchClass() { - $this->markTestSkipped("PDO::FETCH_CLASS not supported by crate PDO"); + $this->markTestSkipped("PDO::FETCH_CLASS is not supported by the CrateDB PDO driver"); $this->setupFixture(); @@ -485,7 +447,7 @@ public function testFetchAllSupportFetchClass() $stmt->execute(); $results = $stmt->fetchAll( - \PDO::FETCH_CLASS, + PDO::FETCH_CLASS, __NAMESPACE__.'\\MyFetchClass' ); @@ -510,7 +472,7 @@ public function testFetchAllStyleColumn() $this->refresh("fetch_table"); $sql = "SELECT test_int FROM fetch_table ORDER BY test_int ASC"; - $rows = $this->_conn->query($sql)->fetchAll(\PDO::FETCH_COLUMN); + $rows = $this->_conn->query($sql)->fetchAll(PDO::FETCH_COLUMN); $this->assertEquals(array(1, 10), $rows); } @@ -520,12 +482,13 @@ public function testFetchAllStyleColumn() */ public function testSetFetchModeClassFetchAll() { - $this->markTestSkipped("PDO::FETCH_CLASS not supported crate PDO"); + $this->markTestSkipped("PDO::FETCH_CLASS is not supported by the CrateDB PDO driver"); + $this->setupFixture(); $sql = "SELECT * FROM fetch_table"; $stmt = $this->_conn->query($sql); - $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); + $stmt->setFetchMode(PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); $results = $stmt->fetchAll(); @@ -542,13 +505,13 @@ public function testSetFetchModeClassFetchAll() */ public function testSetFetchModeClassFetch() { - $this->markTestSkipped("PDO::FETCH_CLASS not supported by crate PDO"); + $this->markTestSkipped("PDO::FETCH_CLASS is not supported by the CrateDB PDO driver"); $this->setupFixture(); $sql = "SELECT * FROM fetch_table"; $stmt = $this->_conn->query($sql); - $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); + $stmt->setFetchMode(PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); $results = array(); while ($row = $stmt->fetch()) { @@ -568,10 +531,10 @@ public function testSetFetchModeClassFetch() */ public function testEmptyFetchColumnReturnsFalse() { - $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $this->_conn->executeStatement('DELETE FROM fetch_table'); $this->refresh("fetch_table"); - $this->assertFalse($this->_conn->fetchColumn('SELECT test_int FROM fetch_table')); - $this->assertFalse($this->_conn->query('SELECT test_int FROM fetch_table')->fetchColumn()); + $this->assertFalse($this->_conn->prepare('SELECT test_int FROM fetch_table')->getWrappedStatement()->fetchColumn()); + $this->assertFalse($this->_conn->prepare('SELECT test_int FROM fetch_table')->getWrappedStatement()->fetchColumn()); } /** @@ -581,9 +544,8 @@ public function testSetFetchModeOnDbalStatement() { $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; $stmt = $this->_conn->executeQuery($sql, array(1, "foo")); - $stmt->setFetchMode(\PDO::FETCH_NUM); - while ($row = $stmt->fetch()) { + foreach ($stmt->iterateNumeric() as $row) { $this->assertTrue(isset($row[0])); $this->assertTrue(isset($row[1])); } diff --git a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php index a0eb173..6e6568d 100644 --- a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php +++ b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php @@ -23,8 +23,7 @@ namespace Crate\Test\DBAL\Functional; use Crate\Test\DBAL\DBALFunctionalTestCase; -use Doctrine\DBAL\DBALException; - +use Doctrine\DBAL\Exception as DBALException; class ModifyLimitQueryTest extends DBALFunctionalTestCase { @@ -65,7 +64,7 @@ public function tearDown() : void } } - public function testModifyLimitQuerySimpleQuery() + public function testModifyLimitQuerySimpleQuery(): void { $this->_conn->insert('modify_limit_table', array('test_int' => 1)); $this->_conn->insert('modify_limit_table', array('test_int' => 2)); @@ -97,7 +96,7 @@ public function testModifyLimitQueryOrderBy() $this->assertLimitResult(array(2, 1), $sql, 2, 2); } - public function testModifyLimitQueryGroupBy() + public function testModifyLimitQueryGroupBy(): void { $this->_conn->insert('modify_limit_table2', array('test_int' => 1, 'id' => 1)); $this->_conn->insert('modify_limit_table2', array('test_int' => 1, 'id' => 2)); @@ -117,7 +116,7 @@ public function assertLimitResult($expectedResults, $sql, $limit, $offset) { $p = $this->_conn->getDatabasePlatform(); $data = array(); - foreach ($this->_conn->fetchAll($p->modifyLimitQuery($sql, $limit, $offset)) AS $row) { + foreach ($this->_conn->executeQuery($p->modifyLimitQuery($sql, $limit, $offset))->fetchAllAssociative() as $row) { $row = array_change_key_case($row, CASE_LOWER); $data[] = $row['test_int']; } diff --git a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php index a2c4de6..ddee033 100644 --- a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php +++ b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php @@ -4,7 +4,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\Connection; -use \PDO; +use PDO; /** * @group DDC-1372 diff --git a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php index 00988d9..3d9bf1f 100644 --- a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php +++ b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php @@ -28,6 +28,7 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\IntegerType; use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; class SchemaManagerTest extends DBALFunctionalTestCase { @@ -75,12 +76,12 @@ public function testListTables() public function createListTableColumns() { $table = new Table('list_table_columns'); - $table->addColumn('text', Type::STRING); + $table->addColumn('text', Types::STRING); $table->addColumn('ts', TimestampType::NAME); - $table->addColumn('num_float_double', Type::FLOAT); - $table->addColumn('num_short', Type::SMALLINT); - $table->addColumn('num_int', Type::INTEGER); - $table->addColumn('num_long', Type::BIGINT); + $table->addColumn('num_float_double', Types::FLOAT); + $table->addColumn('num_short', Types::SMALLINT); + $table->addColumn('num_int', Types::INTEGER); + $table->addColumn('num_long', Types::BIGINT); $table->addColumn('id', 'integer', array('notnull' => true)); $table->setPrimaryKey(array('id')); @@ -101,7 +102,7 @@ public function createListTableColumns() // ARRAY schema definition via platform options $arrOpts = array( - 'type' => Type::FLOAT, + 'type' => Types::FLOAT, ); $table->addColumn('arr_float', 'array', array('platformOptions'=>$arrOpts)); @@ -209,7 +210,7 @@ protected function createTestTable($name = 'test_table', $data = array()) protected function getTestTable($name, $options=array()) { - $table = new Table($name, array(), array(), array(), false, $options); + $table = new Table($name, array(), array(), array(), array(), $options); $table->setSchemaConfig($this->_sm->createSchemaConfig()); $table->addColumn('id', 'integer', array('notnull' => true)); $table->setPrimaryKey(array('id')); @@ -220,7 +221,7 @@ protected function getTestTable($name, $options=array()) protected function getTestCompositeTable($name) { - $table = new Table($name, array(), array(), array(), false, array()); + $table = new Table($name, array(), array(), array(), array(), array()); $table->setSchemaConfig($this->_sm->createSchemaConfig()); $table->addColumn('id', 'integer', array('notnull' => true)); $table->addColumn('other_id', 'integer', array('notnull' => true)); diff --git a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php index 9f545b7..c8b7679 100644 --- a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php +++ b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php @@ -23,9 +23,7 @@ namespace Crate\Test\DBAL\Functional; -use Crate\DBAL\Platforms\CratePlatform; use Crate\Test\DBAL\DBALFunctionalTestCase; -use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Schema\Table; use InvalidArgumentException; @@ -34,7 +32,7 @@ class TableOptionsTest extends DBALFunctionalTestCase { public function tearDown() : void { parent::tearDown(); - if ($this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) { + if ($this->_conn->getSchemaManager()->tablesExist("table_option_testf")) { try { $sm = $this->_conn->getSchemaManager(); $sm->dropTable('table_option_test'); @@ -56,7 +54,7 @@ public function testAdditionalTableOptions() $options['table_options']['number_of_replicas'] = '0-2'; $options['table_options']['write.wait_for_active_shards'] = 'ALL'; - $table = new Table('t1', [], [], [], 0, $options); + $table = new Table('t1', [], [], [], [], $options); $table->addColumn('id', 'integer'); $table->addColumn('parted', 'integer'); $table->addColumn('date', 'timestamp'); @@ -80,7 +78,7 @@ public function testGetAdditionalTableOptions() $options['table_options']['number_of_replicas'] = '0-2'; $options['table_options']['write.wait_for_active_shards'] = 'ALL'; - $table = new Table('table_option_test', [], [], [], 0, $options); + $table = new Table('table_option_test', [], [], [], [], $options); $table->addColumn('id', 'integer'); $table->addColumn('parted', 'integer'); $table->addColumn('date', 'timestamp'); @@ -106,7 +104,7 @@ public function testPartitionColumnsNotArray() $options = []; $options['partition_columns'] = 'parted'; - $table = new Table('t1', [], [], [], 0, $options); + $table = new Table('t1', [], [], [], [], $options); $table->addColumn('parted', 'integer'); $this->expectException(InvalidArgumentException::class); diff --git a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php index 7ae5f6e..a0f0783 100644 --- a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php +++ b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php @@ -24,10 +24,10 @@ use Crate\DBAL\Platforms\CratePlatform; use Crate\DBAL\Types\TimestampType; -use Crate\Test\DBAL\DBALFunctionalTestCase; use Crate\DBAL\Types\ArrayType; use Crate\DBAL\Types\MapType; use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use PHPUnit\Framework\TestCase; class TypeConversionTestCase extends TestCase { @@ -44,7 +44,7 @@ public function testTimestampType() $input = new \DateTime("2014-10-21 15:23:38"); // datetimetz - $type = Type::getType(Type::DATETIMETZ); + $type = Type::getType(Types::DATETIMETZ_MUTABLE); $expected = $input->format('Y-m-d\TH:i:sO'); $output = $type->convertToDatabaseValue($input, $this->platform); $this->assertEquals($output, $expected); @@ -54,7 +54,7 @@ public function testTimestampType() $this->assertEquals($inputRestored, $input); // datetime - $type = Type::getType(Type::DATETIME); + $type = Type::getType(Types::DATETIME_MUTABLE); $expected = $input->format('Y-m-d\TH:i:s'); $output = $type->convertToDatabaseValue($input, $this->platform); $this->assertEquals($output, $expected); @@ -64,7 +64,7 @@ public function testTimestampType() $this->assertEquals($inputRestored, $input); // date - $type = Type::getType(Type::DATE); + $type = Type::getType(Types::DATE_MUTABLE); $expected = $input->format('Y-m-d\TH:i:s'); $output = $type->convertToDatabaseValue($input, $this->platform); $this->assertEquals($output, $expected); @@ -74,7 +74,7 @@ public function testTimestampType() $this->assertEquals($inputRestored, $input); // time - $type = Type::getType(Type::TIME); + $type = Type::getType(Types::TIME_MUTABLE); $expected = $input->format('Y-m-d\TH:i:s'); $output = $type->convertToDatabaseValue($input, $this->platform); $this->assertEquals($output, $expected); @@ -96,10 +96,11 @@ public function testTimestampType() public function testTimestampTypeNull() { - $types = array(Type::getType(Type::DATETIMETZ), - Type::getType(Type::DATETIME), - Type::getType(Type::DATE), - Type::getType(Type::TIME), + $types = array( + Type::getType(Types::DATETIMETZ_MUTABLE), + Type::getType(Types::DATETIME_MUTABLE), + Type::getType(Types::DATE_MUTABLE), + Type::getType(Types::TIME_MUTABLE), Type::getType(TimestampType::NAME) ); foreach ($types as $type) { diff --git a/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php b/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php index 83a5f71..fce0a47 100644 --- a/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php +++ b/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php @@ -29,6 +29,7 @@ use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; class MapTypeTest extends DBALFunctionalTestCase { @@ -39,8 +40,8 @@ public function testStrictMapTableCreationWithSchemaManager() { $objDefinition = array( 'type' => MapType::STRICT, 'fields' => array( - new Column('id', Type::getType(Type::INTEGER), array()), - new Column('name', Type::getType(Type::STRING), array()), + new Column('id', Type::getType(Types::INTEGER), array()), + new Column('name', Type::getType(Types::STRING), array()), ), ); $table->addColumn( diff --git a/test/Crate/Test/DBAL/Functional/WriteTest.php b/test/Crate/Test/DBAL/Functional/WriteTest.php index 635a4ff..a7a41a6 100644 --- a/test/Crate/Test/DBAL/Functional/WriteTest.php +++ b/test/Crate/Test/DBAL/Functional/WriteTest.php @@ -26,6 +26,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use PDO; class WriteTest extends DBALFunctionalTestCase @@ -40,19 +41,19 @@ public function setUp() : void self::$generated = true; /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ $table = new \Doctrine\DBAL\Schema\Table("write_table"); - $table->addColumn('test_int', Type::INTEGER); - $table->addColumn('test_string', Type::STRING); - $table->addColumn('test_float', Type::FLOAT); - $table->addColumn('test_array', Type::TARRAY, array('columnDefinition'=>'ARRAY(STRING)')); + $table->addColumn('test_int', Types::INTEGER); + $table->addColumn('test_string', Types::STRING); + $table->addColumn('test_float', Types::FLOAT); + $table->addColumn('test_array', Types::ARRAY, array('columnDefinition'=>'ARRAY(STRING)')); $table->addColumn("test_map", MapType::NAME); - $table->addColumn("test_bool", Type::BOOLEAN); + $table->addColumn("test_bool", Types::BOOLEAN); $platformOptions = array( 'type' => MapType::STRICT, 'fields' => array( - new Column('id', Type::getType(Type::INTEGER), array()), - new Column('name', Type::getType(Type::STRING), array()), - new Column('value', Type::getType(Type::FLOAT), array()), + new Column('id', Type::getType(Types::INTEGER), array()), + new Column('name', Type::getType(Types::STRING), array()), + new Column('value', Type::getType(Types::FLOAT), array()), ), ); $table->addColumn('test_obj', MapType::NAME, array('platformOptions'=>$platformOptions)); @@ -81,9 +82,9 @@ public function testExecuteUpdateFirstTypeIsNull() $this->refresh('write_table'); $sql = "SELECT test_obj, test_string, test_int FROM write_table WHERE test_string = ? AND test_int = ?"; - $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111)), null); - $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111), 1), "text"); - $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111), 2), 1111); + $this->assertEquals($this->_conn->fetchOne($sql, array("text", 1111), []), null); + $this->assertEquals($this->_conn->fetchNumeric($sql, array("text", 1111), [])[1], "text"); + $this->assertEquals($this->_conn->fetchNumeric($sql, array("text", 1111), [])[2], 1111); } public function testExecuteUpdate() @@ -97,7 +98,7 @@ public function testExecuteUpdate() public function testExecuteUpdateWithTypes() { $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; - $affected = $this->_conn->executeUpdate($sql, array(1, 'foo'), array(\PDO::PARAM_INT, \PDO::PARAM_STR)); + $affected = $this->_conn->executeUpdate($sql, array(1, 'foo'), array(PDO::PARAM_INT, PDO::PARAM_STR)); $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!"); } @@ -109,9 +110,9 @@ public function testPrepareRowCountReturnsAffectedRows() $stmt->bindValue(1, 1); $stmt->bindValue(2, "foo"); - $stmt->execute(); + $result = $stmt->executeQuery(); - $this->assertEquals(1, $stmt->rowCount()); + $this->assertEquals(1, $result->rowCount()); } public function testPrepareWithPdoTypes() @@ -119,11 +120,11 @@ public function testPrepareWithPdoTypes() $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; $stmt = $this->_conn->prepare($sql); - $stmt->bindValue(1, 1, \PDO::PARAM_INT); - $stmt->bindValue(2, "foo", \PDO::PARAM_STR); - $stmt->execute(); + $stmt->bindValue(1, 1, PDO::PARAM_INT); + $stmt->bindValue(2, "foo", PDO::PARAM_STR); + $result = $stmt->executeQuery(); - $this->assertEquals(1, $stmt->rowCount()); + $this->assertEquals(1, $result->rowCount()); } public function testPrepareWithDbalTypes() @@ -135,9 +136,9 @@ public function testPrepareWithDbalTypes() $stmt->bindValue(2, "foo", Type::getType('string')); $stmt->bindValue(3, 3.141592, Type::getType('float')); $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), Type::getType('map')); - $stmt->execute(); + $result = $stmt->executeQuery(); - $this->assertEquals(1, $stmt->rowCount()); + $this->assertEquals(1, $result->rowCount()); } public function testPrepareWithDbalTypeNames() @@ -150,9 +151,9 @@ public function testPrepareWithDbalTypeNames() $stmt->bindValue(3, 3.141592, 'float'); $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), 'map'); $stmt->bindValue(5, true, 'boolean'); - $stmt->execute(); + $result = $stmt->executeQuery(); - $this->assertEquals(1, $stmt->rowCount()); + $this->assertEquals(1, $result->rowCount()); } public function insertRows() @@ -186,11 +187,11 @@ public function testDelete() $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 2))); $this->refresh('write_table'); - $this->assertEquals(1, count($this->_conn->fetchAll('SELECT * FROM write_table'))); + $this->assertEquals(1, count($this->_conn->fetchAllAssociative('SELECT * FROM write_table'))); $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 1))); $this->refresh('write_table'); - $this->assertEquals(0, count($this->_conn->fetchAll('SELECT * FROM write_table'))); + $this->assertEquals(0, count($this->_conn->fetchAllAssociative('SELECT * FROM write_table'))); } public function testUpdate() diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index e593fa6..a167293 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -28,7 +28,7 @@ use Crate\DBAL\Types\ArrayType; use Crate\DBAL\Types\MapType; use Doctrine\Common\EventManager; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Events; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\Column; @@ -36,6 +36,7 @@ use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Tests\Platforms\AbstractPlatformTestCase; +use Doctrine\DBAL\Types\Types; class CratePlatformTest extends AbstractPlatformTestCase { @@ -170,6 +171,11 @@ public function testQuotesAlterTableChangeColumnLength() : void protected function getQuotedAlterTableChangeColumnLengthSQL() : array {} + public function testQuotesAlterTableRenameIndex() : void + { + $this->markTestSkipped('Platform does not support ALTER TABLE.'); + } + /** * @group DBAL-807 */ @@ -455,8 +461,8 @@ public function testGenerateObjectSQLDeclaration() array('platformOptions'=>array( 'type'=>MapType::STRICT, 'fields'=>array( - new Column('num', Type::getType(Type::INTEGER)), - new Column('text', Type::getType(Type::STRING)), + new Column('num', Type::getType(Types::INTEGER)), + new Column('text', Type::getType(Types::STRING)), new Column('arr', Type::getType(ArrayType::NAME)), new Column('obj', Type::getType(MapType::NAME)), ), @@ -471,7 +477,7 @@ public function testGenerateArraySQLDeclaration() $this->assertEquals($this->getSQLDeclaration($column), 'arr ARRAY ( TEXT )'); $column = new Column('arr', Type::getType(ArrayType::NAME), - array('platformOptions'=> array('type'=>Type::INTEGER))); + array('platformOptions'=> array('type'=>Types::INTEGER))); $this->assertEquals($this->getSQLDeclaration($column), 'arr ARRAY ( INTEGER )'); } @@ -499,11 +505,73 @@ protected function getQuotesReservedKeywordInTruncateTableSQL() : string /** * @return array}> */ - public function asciiStringSqlDeclarationDataProvider() : array + public static function asciiStringSqlDeclarationDataProvider() : array { return [ ['TEXT', ['length' => 12]], ['TEXT', ['length' => 12, 'fixed' => true]], ]; } + + /** @return string[] */ + protected function getAlterTableRenameIndexSQL(): array + { + return [ + 'DROP INDEX idx_foo', + 'CREATE INDEX idx_bar ON mytable (id)', + ]; + } + + public function testAlterTableRenameIndex(): void + { + $this->markTestSkipped('Platform does not support renaming indexes.'); + } + + public function testAlterTableRenameIndexInSchema(): void + { + $this->markTestSkipped('Platform does not support renaming indexes.'); + } + + public function testRegistersCommentedDoctrineMappingTypeImplicitly(): void + { + $type = Type::getType(Types::ARRAY); + $this->platform->registerDoctrineTypeMapping('foo', Types::ARRAY); + + self::assertFalse($this->platform->isCommentedDoctrineType($type)); + } + + public function testCaseInsensitiveDoctrineTypeMappingFromType(): void + { + $type = new class () extends Type { + /** + * {@inheritDoc} + */ + public function getMappedDatabaseTypes(AbstractPlatform $platform): array + { + return ['OBJECT']; + } + + public function getName(): string + { + return 'map'; + } + + /** + * {@inheritDoc} + */ + public function getSQLDeclaration(array $column, AbstractPlatform $platform): string + { + return $platform->getDecimalTypeDeclarationSQL($column); + } + }; + + if (Type::hasType($type->getName())) { + Type::overrideType($type->getName(), get_class($type)); + } else { + Type::addType($type->getName(), get_class($type)); + } + + self::assertSame($type->getName(), $this->platform->getDoctrineTypeMapping('ObJecT')); + } + } From dbc307de80a36ef64c5506d764bdb5cbb15793e8 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 14 Nov 2025 11:20:38 +0100 Subject: [PATCH 06/29] DBAL3: Apply suggestions by CodeRabbit, and more copy editing --- docs/connect.rst | 2 +- .../DBAL/Driver/PDOCrate/CrateStatement.php | 25 +++++++------ src/Crate/DBAL/Driver/PDOCrate/Driver.php | 26 ++++++++------ .../DBAL/Driver/PDOCrate/PDOConnection.php | 16 +-------- src/Crate/DBAL/Schema/CrateSchemaManager.php | 14 ++++---- .../Test/DBAL/Functional/BindingTest.php | 2 +- .../Test/DBAL/Functional/ConnectionTest.php | 2 +- .../Test/DBAL/Functional/DataAccessTest.php | 18 ++++++---- .../DBAL/Functional/ModifyLimitQueryTest.php | 9 ++--- .../DBAL/Functional/NamedParametersTest.php | 11 +++--- .../Functional/Schema/SchemaManagerTest.php | 3 +- .../Test/DBAL/Functional/TableOptionsTest.php | 6 ++-- test/Crate/Test/DBAL/Functional/WriteTest.php | 36 ++++++++++++------- .../Test/DBAL/Platforms/CratePlatformTest.php | 4 +-- 14 files changed, 90 insertions(+), 84 deletions(-) diff --git a/docs/connect.rst b/docs/connect.rst index 119deac..f005bd4 100644 --- a/docs/connect.rst +++ b/docs/connect.rst @@ -36,7 +36,7 @@ If you plan to query CrateDB via DBAL, you can get a connection from the 'port' => 4200 ); $connection = \Doctrine\DBAL\DriverManager::getConnection($params); - $schemaManager = $connection->getSchemaManager(); + $schemaManager = $connection->createSchemaManager(); With these connection parameters, the ``DriverManager`` will attempt to authenticate as ``crate`` with a CrateDB node listening on ``localhost:4200``. diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index 14fc244..5c3ef27 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -37,18 +37,17 @@ */ final class CrateStatement implements StatementInterface { + private PDOInterface $pdo; + private PDOStatement $stmt; /** - * @var PDOInterface + * @param string $sql + * @param array $options */ - private $pdo; - - private PDOStatement $stmt; - - public function __construct(PDOInterface $pdo, $sql) + public function __construct(PDOInterface $pdo, $sql, $options = []) { - $this->pdo = $pdo; - $this->stmt = $pdo->prepare($sql); + $this->pdo = $pdo; + $this->stmt = $pdo->prepare($sql, $options); } /** @@ -90,7 +89,7 @@ public function rowCount(): int */ public function bindValue($param, $value, $type = ParameterType::STRING) { - $this->stmt->bindValue($param, $value, $type); + return $this->stmt->bindValue($param, $value, $type); } /** @@ -132,17 +131,17 @@ public function fetchColumn($column_number = 0) /** * {@inheritDoc} */ - public function closeCursor(): int + public function closeCursor(): bool { return $this->stmt->closeCursor(); } /** - * Gets the wrapped driver statement. + * Gets the wrapped CrateDB PDOStatement. * - * @return Driver\Statement + * @return PDOStatement */ - public function getWrappedStatement() + public function getWrappedStatement(): PDOStatement { return $this->stmt; } diff --git a/src/Crate/DBAL/Driver/PDOCrate/Driver.php b/src/Crate/DBAL/Driver/PDOCrate/Driver.php index 441918d..79b10ff 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Driver.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Driver.php @@ -27,9 +27,9 @@ use Crate\DBAL\Schema\CrateSchemaManager; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\VersionAwarePlatformDriver; +use Doctrine\DBAL\Schema\AbstractSchemaManager; -class Driver implements \Doctrine\DBAL\Driver, VersionAwarePlatformDriver +class Driver implements \Doctrine\DBAL\Driver { const VERSION = '4.0.3'; const NAME = 'crate'; @@ -41,8 +41,12 @@ class Driver implements \Doctrine\DBAL\Driver, VersionAwarePlatformDriver * {@inheritDoc} * @return PDOConnection The database connection. */ - public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) - { + public function connect( + array $params, + $username = null, + $password = null, + array $driverOptions = array(), + ): PDOConnection { return new PDOConnection($this->constructPdoDsn($params), $username, $password, $driverOptions); } @@ -51,7 +55,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - private function constructPdoDsn(array $params) + private function constructPdoDsn(array $params): string { $dsn = self::NAME . ':'; if (isset($params['host']) && $params['host'] != '') { @@ -67,7 +71,7 @@ private function constructPdoDsn(array $params) /** * {@inheritDoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform(): AbstractPlatform { return new CratePlatform4(); } @@ -75,16 +79,16 @@ public function getDatabasePlatform() /** * {@inheritDoc} */ - public function getSchemaManager(Connection $conn, AbstractPlatform $platform) + public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager { // Added by Doctrine 3. - return new CrateSchemaManager($conn, $conn->getDatabasePlatform()); + return new CrateSchemaManager($conn, $platform); } /** * {@inheritDoc} */ - public function getName() + public function getName(): string { return self::NAME; } @@ -92,7 +96,7 @@ public function getName() /** * {@inheritDoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn): string|null { return null; } @@ -100,7 +104,7 @@ public function getDatabase(Connection $conn) /** * {@inheritDoc} */ - public function createDatabasePlatformForVersion($version) + public function createDatabasePlatformForVersion($version): AbstractPlatform { if (version_compare($version, self::VERSION_057, "<")) { return new CratePlatform(); diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 6a0d90f..62da8cb 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -91,20 +91,6 @@ public function exec($sql): int } } - /** - * {@inheritDoc} - */ - public function quer2y(string $sql): Result - { - try { - $result = $this->connection->query($sql); - assert($result !== false); - return new Result($result); - } catch (PDOException $exception) { - throw Exception::new($exception); - } - } - public function query(string $sql): ResultInterface { try { @@ -121,7 +107,7 @@ public function quote($value, $type = ParameterType::STRING): string return $this->connection->quote($value, $type); } - public function lastInsertId($name = null): string + public function lastInsertId($name = null): string|false { return $this->connection->lastInsertId($name); } diff --git a/src/Crate/DBAL/Schema/CrateSchemaManager.php b/src/Crate/DBAL/Schema/CrateSchemaManager.php index 44c9795..4b2a961 100644 --- a/src/Crate/DBAL/Schema/CrateSchemaManager.php +++ b/src/Crate/DBAL/Schema/CrateSchemaManager.php @@ -21,7 +21,7 @@ */ namespace Crate\DBAL\Schema; -use Crate\DBAL\Platforms\CratePlatform4; +use Crate\DBAL\Platforms\CratePlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Types\Type; @@ -30,7 +30,7 @@ /** * Schema manager for the CrateDB RDBMS. * - * @extends AbstractSchemaManager + * @extends AbstractSchemaManager */ class CrateSchemaManager extends AbstractSchemaManager { @@ -130,13 +130,13 @@ private function flatten(array $array, string $prefix = '') : array /** * {@inheritDoc} */ - public function listTableDetails($tableName) : Table + public function listTableDetails($name) : Table { - $columns = $this->listTableColumns($tableName); - $indexes = $this->listTableIndexes($tableName); + $columns = $this->listTableColumns($name); + $indexes = $this->listTableIndexes($name); $options = []; - $s = $this->_conn->fetchAssociative($this->_platform->getTableOptionsSQL($tableName)); + $s = $this->_conn->fetchAssociative($this->_platform->getTableOptionsSQL($name)); $options['sharding_routing_column'] = $s['clustered_by']; $options['sharding_num_shards'] = $s['number_of_shards']; @@ -144,6 +144,6 @@ public function listTableDetails($tableName) : Table $options['table_options'] = self::flatten($s['settings']); $options['table_options']['number_of_replicas'] = $s['number_of_replicas']; $options['table_options']['column_policy'] = $s['column_policy']; - return new Table($tableName, $columns, $indexes, [], [], $options); + return new Table($name, $columns, $indexes, [], [], $options); } } diff --git a/test/Crate/Test/DBAL/Functional/BindingTest.php b/test/Crate/Test/DBAL/Functional/BindingTest.php index 0bb5fb0..cd177b8 100644 --- a/test/Crate/Test/DBAL/Functional/BindingTest.php +++ b/test/Crate/Test/DBAL/Functional/BindingTest.php @@ -88,7 +88,7 @@ public function testBindNamedValue() public function testBindTimestamp() { - if ($this->_conn->getSchemaManager()->tablesExist("foo")) { + if ($this->_conn->createSchemaManager()->tablesExist("foo")) { $this->execute("DROP TABLE foo"); } diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index a284142..fca9163 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -55,7 +55,7 @@ public function testBasicAuthConnection() $credentials = $conn->getNativeConnection()->getAttribute(PDOCrateDB::CRATE_ATTR_HTTP_BASIC_AUTH); // No leaks any longer: Any empty array is all we got. - $this->assertEquals($credentials, array()); + $this->assertEquals(array(), $credentials); } public function testGetConnection() diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index b6d48da..db6f673 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -27,8 +27,9 @@ use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Column; -use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use PDO; @@ -44,8 +45,8 @@ public function setUp() : void if (self::$generated === false) { self::$generated = true; /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ - $sm = $this->_conn->getSchemaManager(); - $table = new \Doctrine\DBAL\Schema\Table("fetch_table"); + $sm = $this->_conn->createSchemaManager(); + $table = new Table("fetch_table"); $table->addColumn('test_int', 'integer'); $table->addColumn('test_string', 'string'); $table->addColumn('test_datetime', 'timestamp', array('notnull' => false)); @@ -53,6 +54,7 @@ public function setUp() : void $platformOptions = array( 'type' => MapType::STRICT, 'fields' => array( + // Those intentionally use DBAL types. new Column('id', Type::getType('integer'), array()), new Column('name', Type::getType('string'), array()), new Column('value', Type::getType('float'), array()), @@ -78,7 +80,7 @@ public function setUp() : void public function tearDown() : void { if (self::$generated === true) { - $this->_conn->getSchemaManager()->dropTable('fetch_table'); + $this->_conn->createSchemaManager()->dropTable('fetch_table'); self::$generated = false; } } @@ -93,7 +95,7 @@ public function testPrepareWithBindValue() $stmt->bindValue(2, 'foo', PDO::PARAM_STR); $result = $stmt->executeQuery(); - $row = $result->fetch(PDO::FETCH_ASSOC); + $row = $result->fetchAssociative(); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); } @@ -158,6 +160,7 @@ public function testPrepareWithFetchColumn() $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); + $stmt->execute(); $column = $stmt->getWrappedStatement()->fetchColumn(); $this->assertEquals(1, $column); @@ -533,8 +536,9 @@ public function testEmptyFetchColumnReturnsFalse() { $this->_conn->executeStatement('DELETE FROM fetch_table'); $this->refresh("fetch_table"); - $this->assertFalse($this->_conn->prepare('SELECT test_int FROM fetch_table')->getWrappedStatement()->fetchColumn()); - $this->assertFalse($this->_conn->prepare('SELECT test_int FROM fetch_table')->getWrappedStatement()->fetchColumn()); + $stmt = $this->_conn->prepare('SELECT test_int FROM fetch_table'); + $stmt->execute(); + $this->assertFalse($stmt->getWrappedStatement()->fetchColumn()); } /** diff --git a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php index 6e6568d..4b4039c 100644 --- a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php +++ b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php @@ -24,6 +24,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Schema\Table; class ModifyLimitQueryTest extends DBALFunctionalTestCase { @@ -35,16 +36,16 @@ public function setUp() : void if (!self::$tableCreated) { /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ - $table = new \Doctrine\DBAL\Schema\Table("modify_limit_table"); + $table = new Table("modify_limit_table"); $table->addColumn('test_int', 'integer'); $table->setPrimaryKey(array('test_int')); - $table2 = new \Doctrine\DBAL\Schema\Table("modify_limit_table2"); + $table2 = new Table("modify_limit_table2"); $table2->addColumn('id', 'integer', array('autoincrement' => true)); $table2->addColumn('test_int', 'integer'); $table2->setPrimaryKey(array('id')); - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->createTable($table); $sm->createTable($table2); self::$tableCreated = true; @@ -55,7 +56,7 @@ public function tearDown() : void { parent::tearDown(); if (self::$tableCreated) { - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); try { $sm->dropTable('modify_limit_table'); $sm->dropTable('modify_limit_table2'); diff --git a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php index ddee033..d122366 100644 --- a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php +++ b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php @@ -4,6 +4,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\Table; use PDO; /** @@ -106,16 +107,16 @@ public function setUp() : void { parent::setUp(); - if (!$this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) { + if (!$this->_conn->createSchemaManager()->tablesExist("ddc1372_foobar")) { try { - $table = new \Doctrine\DBAL\Schema\Table("ddc1372_foobar"); + $table = new Table("ddc1372_foobar"); $table->addColumn('id', 'integer'); $table->addColumn('foo','string'); $table->addColumn('bar','string'); $table->setPrimaryKey(array('id')); - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->createTable($table); $this->_conn->insert('ddc1372_foobar', array( @@ -147,9 +148,9 @@ public function setUp() : void public function tearDown() : void { parent::tearDown(); - if ($this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) { + if ($this->_conn->createSchemaManager()->tablesExist("ddc1372_foobar")) { try { - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->dropTable('ddc1372_foobar'); } catch(\Exception $e) { $this->fail($e->getMessage()); diff --git a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php index 3d9bf1f..cd6ca73 100644 --- a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php +++ b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php @@ -40,7 +40,7 @@ class SchemaManagerTest extends DBALFunctionalTestCase public function setUp() : void { parent::setUp(); - $this->_sm = $this->_conn->getSchemaManager(); + $this->_sm = $this->_conn->createSchemaManager(); } public function tearDown() : void @@ -86,6 +86,7 @@ public function createListTableColumns() $table->setPrimaryKey(array('id')); // OBJECT schema definition via platform options + // Those intentionally use the `Type::getType()` notation and resolve to DBAL types. $mapOpts = array( 'type' => MapType::STRICT, 'fields' => array( diff --git a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php index c8b7679..34fc081 100644 --- a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php +++ b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php @@ -32,9 +32,9 @@ class TableOptionsTest extends DBALFunctionalTestCase { public function tearDown() : void { parent::tearDown(); - if ($this->_conn->getSchemaManager()->tablesExist("table_option_testf")) { + if ($this->_conn->createSchemaManager()->tablesExist("table_option_test")) { try { - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->dropTable('table_option_test'); } catch(\Exception $e) { $this->fail($e->getMessage()); @@ -83,7 +83,7 @@ public function testGetAdditionalTableOptions() $table->addColumn('parted', 'integer'); $table->addColumn('date', 'timestamp'); - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->createTable($table); $schema = $sm->createSchema(); diff --git a/test/Crate/Test/DBAL/Functional/WriteTest.php b/test/Crate/Test/DBAL/Functional/WriteTest.php index a7a41a6..b9197fa 100644 --- a/test/Crate/Test/DBAL/Functional/WriteTest.php +++ b/test/Crate/Test/DBAL/Functional/WriteTest.php @@ -25,6 +25,7 @@ use Crate\DBAL\Types\MapType; use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use PDO; @@ -40,7 +41,7 @@ public function setUp() : void if (self::$generated === false) { self::$generated = true; /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ - $table = new \Doctrine\DBAL\Schema\Table("write_table"); + $table = new Table("write_table"); $table->addColumn('test_int', Types::INTEGER); $table->addColumn('test_string', Types::STRING); $table->addColumn('test_float', Types::FLOAT); @@ -58,7 +59,7 @@ public function setUp() : void ); $table->addColumn('test_obj', MapType::NAME, array('platformOptions'=>$platformOptions)); - $sm = $this->_conn->getSchemaManager(); + $sm = $this->_conn->createSchemaManager(); $sm->createTable($table); } } @@ -82,9 +83,17 @@ public function testExecuteUpdateFirstTypeIsNull() $this->refresh('write_table'); $sql = "SELECT test_obj, test_string, test_int FROM write_table WHERE test_string = ? AND test_int = ?"; - $this->assertEquals($this->_conn->fetchOne($sql, array("text", 1111), []), null); - $this->assertEquals($this->_conn->fetchNumeric($sql, array("text", 1111), [])[1], "text"); - $this->assertEquals($this->_conn->fetchNumeric($sql, array("text", 1111), [])[2], 1111); + $stmt = $this->_conn->prepare($sql); + $nstmt = $stmt->getWrappedStatement(); + + $stmt->execute(array("text", 1111)); + $this->assertEquals(null, $nstmt->fetchColumn(0)); + + $stmt->execute(array("text", 1111)); + $this->assertEquals("text", $nstmt->fetchColumn(1)); + + $stmt->execute(array("text", 1111)); + $this->assertEquals(1111, $nstmt->fetchColumn(2)); } public function testExecuteUpdate() @@ -110,9 +119,9 @@ public function testPrepareRowCountReturnsAffectedRows() $stmt->bindValue(1, 1); $stmt->bindValue(2, "foo"); - $result = $stmt->executeQuery(); + $rowcount = $stmt->executeStatement(); - $this->assertEquals(1, $result->rowCount()); + $this->assertEquals(1, $rowcount); } public function testPrepareWithPdoTypes() @@ -122,9 +131,9 @@ public function testPrepareWithPdoTypes() $stmt->bindValue(1, 1, PDO::PARAM_INT); $stmt->bindValue(2, "foo", PDO::PARAM_STR); - $result = $stmt->executeQuery(); + $rowcount = $stmt->executeStatement(); - $this->assertEquals(1, $result->rowCount()); + $this->assertEquals(1, $rowcount); } public function testPrepareWithDbalTypes() @@ -132,13 +141,14 @@ public function testPrepareWithDbalTypes() $sql = "INSERT INTO write_table (test_int, test_string, test_float, test_obj) VALUES (?, ?, ?, ?)"; $stmt = $this->_conn->prepare($sql); + // Those intentionally use the `Type::getType()` notation, and resolve to DBAL type objects. $stmt->bindValue(1, 1, Type::getType('integer')); $stmt->bindValue(2, "foo", Type::getType('string')); $stmt->bindValue(3, 3.141592, Type::getType('float')); $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), Type::getType('map')); - $result = $stmt->executeQuery(); + $rowcount = $stmt->executeStatement(); - $this->assertEquals(1, $result->rowCount()); + $this->assertEquals(1, $rowcount); } public function testPrepareWithDbalTypeNames() @@ -151,9 +161,9 @@ public function testPrepareWithDbalTypeNames() $stmt->bindValue(3, 3.141592, 'float'); $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), 'map'); $stmt->bindValue(5, true, 'boolean'); - $result = $stmt->executeQuery(); + $rowcount = $stmt->executeStatement(); - $this->assertEquals(1, $result->rowCount()); + $this->assertEquals(1, $rowcount); } public function insertRows() diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index a167293..48ed691 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -376,7 +376,7 @@ public function testGeneratesTableAlterationSql() : void $expectedSql = $this->getGenerateAlterTableSql(); $tableDiff = new TableDiff('mytable'); - $tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('notnull' => false)); + $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), array('notnull' => false)); $sql = $this->platform->getAlterTableSQL($tableDiff); @@ -405,7 +405,7 @@ public function testGetAlterTableSqlDispatchEvent() : void $this->platform->setEventManager($eventManager); $tableDiff = new TableDiff('mytable'); - $tableDiff->addedColumns['added'] = new \Doctrine\DBAL\Schema\Column('added', \Doctrine\DBAL\Types\Type::getType('integer'), array()); + $tableDiff->addedColumns['added'] = new Column('added', Type::getType('integer'), array()); $this->platform->getAlterTableSQL($tableDiff); } From 8d8e25fb1f3d81f5e464972e283292c27c849bdb Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 14 Nov 2025 11:38:13 +0100 Subject: [PATCH 07/29] DBAL3: Minor wording updates --- test/Crate/Test/DBAL/Functional/ConnectionTest.php | 2 +- test/Crate/Test/DBAL/Platforms/CratePlatformTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index fca9163..b01de38 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -54,7 +54,7 @@ public function testBasicAuthConnection() $conn->connect(); $credentials = $conn->getNativeConnection()->getAttribute(PDOCrateDB::CRATE_ATTR_HTTP_BASIC_AUTH); - // No leaks any longer: Any empty array is all we got. + // No credential leaks any longer: Any empty array is all we got. $this->assertEquals(array(), $credentials); } diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index 48ed691..b2cc099 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -105,7 +105,7 @@ public function getGenerateAlterTableSql() : array public function testAlterTableChangeQuotedColumn() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming indexes.'); } protected function getQuotedColumnInPrimaryKeySQL() : array From 40283de3bcfb546ea3e62064d8e8ceae4826ca35 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 14 Nov 2025 12:02:28 +0100 Subject: [PATCH 08/29] DBAL3: More copy editing with CodeRabbit --- docs/connect.rst | 4 +++- examples/objects.php | 3 ++- src/Crate/DBAL/Driver/PDOCrate/Driver.php | 10 ++++++---- src/Crate/DBAL/Platforms/CratePlatform.php | 3 ++- test/Crate/Test/DBAL/Functional/ConnectionTest.php | 6 +++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/connect.rst b/docs/connect.rst index f005bd4..3a4cfe8 100644 --- a/docs/connect.rst +++ b/docs/connect.rst @@ -29,13 +29,15 @@ If you plan to query CrateDB via DBAL, you can get a connection from the .. code-block:: php + use Doctrine\DBAL\DriverManager; + $params = array( 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver', 'user' => 'crate', 'host' => 'localhost', 'port' => 4200 ); - $connection = \Doctrine\DBAL\DriverManager::getConnection($params); + $connection = DriverManager::getConnection($params); $schemaManager = $connection->createSchemaManager(); With these connection parameters, the ``DriverManager`` will attempt to diff --git a/examples/objects.php b/examples/objects.php index 71e3544..724b557 100644 --- a/examples/objects.php +++ b/examples/objects.php @@ -17,6 +17,7 @@ use Crate\DBAL\Types\MapType; // Initialize machinery. +// This ensures that the 'map' type is registered in the type system from the beginning. $platform = new CratePlatform4(); // Define table schema. @@ -44,7 +45,7 @@ // Provision database table. try { - $schemaManager->dropTable($table); + $schemaManager->dropTable($table->getName()); } catch (TableNotFoundException) { } $schemaManager->createTable($table); diff --git a/src/Crate/DBAL/Driver/PDOCrate/Driver.php b/src/Crate/DBAL/Driver/PDOCrate/Driver.php index 79b10ff..d8ed67f 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Driver.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Driver.php @@ -28,6 +28,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use SensitiveParameter; class Driver implements \Doctrine\DBAL\Driver { @@ -42,11 +43,12 @@ class Driver implements \Doctrine\DBAL\Driver * @return PDOConnection The database connection. */ public function connect( - array $params, - $username = null, - $password = null, - array $driverOptions = array(), + #[SensitiveParameter] + array $params ): PDOConnection { + $username = $params['user'] ?? null; + $password = $params['password'] ?? null; + $driverOptions = $params['driver_options'] ?? []; return new PDOConnection($this->constructPdoDsn($params), $username, $password, $driverOptions); } diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index 07c4973..97bf4c0 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -795,7 +795,8 @@ public static function prepareColumnData(AbstractPlatform $platform, $column, $p $columnData['unique'] = false; $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption("version") : false; - if (strtolower($columnData['type']->getName()) == $platform->getVarcharTypeDeclarationSQLSnippet(0, false) + if (strtolower($columnData['type']->getName()) == + strtolower($platform->getVarcharTypeDeclarationSQLSnippet(0, false)) && $columnData['length'] === null) { $columnData['length'] = 255; } diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index b01de38..611ce61 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -23,6 +23,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; use Crate\PDO\PDOCrateDB; +use Doctrine\DBAL\DriverManager; class ConnectionTestCase extends DBALFunctionalTestCase { @@ -50,12 +51,11 @@ public function testBasicAuthConnection() 'user' => $auth[0], 'password' => $auth[1], ); - $conn = \Doctrine\DBAL\DriverManager::getConnection($params); + $conn = DriverManager::getConnection($params); $conn->connect(); $credentials = $conn->getNativeConnection()->getAttribute(PDOCrateDB::CRATE_ATTR_HTTP_BASIC_AUTH); - // No credential leaks any longer: Any empty array is all we got. - $this->assertEquals(array(), $credentials); + $this->assertEquals(array("crate", "secret"), $credentials); } public function testGetConnection() From 1038d0686262ea2c6dda49900d7210b5ac58bb28 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 14 Nov 2025 14:11:05 +0100 Subject: [PATCH 09/29] Chore: Switch linter/formatter to PHP Coding Standards Fixer It also has a ruleset to order `use` statements. - https://github.com/PHP-CS-Fixer/PHP-CS-Fixer - https://cs.symfony.com/doc/rules/import/ordered_imports.html Before: PHP_CodeSniffer - https://github.com/PHPCSStandards/PHP_CodeSniffer --- .gitignore | 1 + .php-cs-fixer.php | 26 +++++++++++++++++++ composer.json | 6 ++--- examples/objects.php | 8 +++--- .../DBAL/Driver/PDOCrate/CrateStatement.php | 5 ++-- src/Crate/DBAL/Driver/PDOCrate/Driver.php | 8 +++--- .../Driver/PDOCrate/ExceptionConverter.php | 2 +- .../DBAL/Driver/PDOCrate/PDOConnection.php | 4 +-- src/Crate/DBAL/Platforms/CratePlatform.php | 21 ++++++++------- src/Crate/DBAL/Platforms/CratePlatform1.php | 3 ++- src/Crate/DBAL/Platforms/CratePlatform4.php | 1 + .../DBAL/Platforms/Keywords/CrateKeywords.php | 2 ++ src/Crate/DBAL/Schema/CrateSchemaManager.php | 8 +++--- src/Crate/DBAL/Types/ArrayType.php | 6 ++--- src/Crate/DBAL/Types/MapType.php | 12 ++++----- src/Crate/DBAL/Types/TimestampType.php | 12 +++++---- .../Test/DBAL/Functional/ConnectionTest.php | 2 +- .../Test/DBAL/Functional/DataAccessTest.php | 2 +- .../DBAL/Functional/TypeConversionTest.php | 2 +- .../Test/DBAL/Platforms/CratePlatformTest.php | 4 +-- 20 files changed, 87 insertions(+), 48 deletions(-) create mode 100644 .php-cs-fixer.php diff --git a/.gitignore b/.gitignore index 53b0f71..5a913a0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .project .vagrant .phpunit.result.cache +*.cache *-console.log .crate-docs /composer.lock diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..73504cb --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,26 @@ +in(__DIR__) +; + +return (new PhpCsFixer\Config()) + ->setUnsupportedPhpVersionAllowed(true) + ->setRules([ + // '@auto' => true, + // '@PHP7x3Migration' => true, + // '@PSR1' => true, + // '@PSR2' => true, + // '@PSR12' => true, + // '@Symfony' => true, + // 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => true, + // 'strict_param' => true, + ]) + ->setFinder($finder) + ; + +?> diff --git a/composer.json b/composer.json index 4f987a1..7b7da2f 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ }, "require-dev": { "phpunit/phpunit": "^9.0", - "squizlabs/php_codesniffer": "^3.5" + "friendsofphp/php-cs-fixer": "^3.89" }, "autoload-dev": { "psr-0": { @@ -44,7 +44,7 @@ }, "scripts": { "test": "XDEBUG_MODE=coverage phpunit --coverage-clover build/logs/clover.xml", - "check-style": "phpcs -s", - "fix-style": "phpcbf" + "check-style": "php-cs-fixer check", + "fix-style": "php-cs-fixer fix" } } diff --git a/examples/objects.php b/examples/objects.php index 724b557..4c4f61e 100644 --- a/examples/objects.php +++ b/examples/objects.php @@ -6,15 +6,15 @@ */ require __DIR__ . '/../vendor/autoload.php'; +use Crate\DBAL\Platforms\CratePlatform4; +use Crate\DBAL\Types\MapType; +use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; + use Doctrine\DBAL\Tools\DsnParser; use Doctrine\DBAL\Types\Type; -use Doctrine\DBAL\DriverManager; - -use Crate\DBAL\Platforms\CratePlatform4; -use Crate\DBAL\Types\MapType; // Initialize machinery. // This ensures that the 'map' type is registered in the type system from the beginning. diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index 5c3ef27..9cb1445 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -1,4 +1,5 @@ 0) { + if (($createFlags & self::CREATE_INDEXES) > 0) { foreach ($table->getIndexes() as $index) { /* @var $index Index */ if ($index->isPrimary()) { @@ -686,7 +687,7 @@ protected function _getCreateTableSQL($name, array $columns, array $options = ar $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition); } } - + if (isset($options['foreignKeys'])) { throw DBALException::notSupported("Create Table: foreign keys"); } @@ -831,7 +832,7 @@ public function getDropDatabaseSQL($database) { throw DBALException::notSupported(__METHOD__); } - + /** * {@inheritDoc} */ @@ -839,7 +840,7 @@ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) { throw DBALException::notSupported(__METHOD__); } - + /** * {@inheritDoc} */ @@ -854,7 +855,7 @@ public function getGuidTypeDeclarationSQL(array $field) * * @return string */ - public function getTableOptionsSQL(string $table) : string + public function getTableOptionsSQL(string $table): string { return "SELECT clustered_by, number_of_shards, partitioned_by, number_of_replicas, column_policy, settings " . "FROM information_schema.tables c " . diff --git a/src/Crate/DBAL/Platforms/CratePlatform1.php b/src/Crate/DBAL/Platforms/CratePlatform1.php index 924a76e..e0e0b75 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform1.php +++ b/src/Crate/DBAL/Platforms/CratePlatform1.php @@ -1,4 +1,5 @@ $value) { @@ -130,7 +132,7 @@ private function flatten(array $array, string $prefix = '') : array /** * {@inheritDoc} */ - public function listTableDetails($name) : Table + public function listTableDetails($name): Table { $columns = $this->listTableColumns($name); $indexes = $this->listTableIndexes($name); diff --git a/src/Crate/DBAL/Types/ArrayType.php b/src/Crate/DBAL/Types/ArrayType.php index c4c40cf..df98fef 100644 --- a/src/Crate/DBAL/Types/ArrayType.php +++ b/src/Crate/DBAL/Types/ArrayType.php @@ -1,4 +1,5 @@ getTimestamp()*self::S_TO_MS : null; + ? $value->getTimestamp() * self::S_TO_MS : null; } public function convertToPHPValue($value, AbstractPlatform $platform) @@ -61,7 +63,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) } $val = new DateTime(); - $val->setTimestamp($value/self::S_TO_MS); + $val->setTimestamp($value / self::S_TO_MS); return $val; } diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index 611ce61..a45d56c 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -21,8 +21,8 @@ */ namespace Crate\Test\DBAL\Functional; -use Crate\Test\DBAL\DBALFunctionalTestCase; use Crate\PDO\PDOCrateDB; +use Crate\Test\DBAL\DBALFunctionalTestCase; use Doctrine\DBAL\DriverManager; class ConnectionTestCase extends DBALFunctionalTestCase diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index db6f673..3a98aac 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -24,10 +24,10 @@ use Crate\DBAL\Types\MapType; use Crate\Test\DBAL\DBALFunctionalTestCase; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Column; -use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; diff --git a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php index a0f0783..4563b80 100644 --- a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php +++ b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php @@ -23,9 +23,9 @@ namespace Crate\Test\DBAL\Functional; use Crate\DBAL\Platforms\CratePlatform; -use Crate\DBAL\Types\TimestampType; use Crate\DBAL\Types\ArrayType; use Crate\DBAL\Types\MapType; +use Crate\DBAL\Types\TimestampType; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use PHPUnit\Framework\TestCase; diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index b2cc099..9426384 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -28,14 +28,14 @@ use Crate\DBAL\Types\ArrayType; use Crate\DBAL\Types\MapType; use Doctrine\Common\EventManager; -use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Events; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; -use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Tests\Platforms\AbstractPlatformTestCase; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; class CratePlatformTest extends AbstractPlatformTestCase { From 40429d1b554dab3ef1a88e50b866d2fe522062de Mon Sep 17 00:00:00 2001 From: Julian Martin Date: Sun, 16 Nov 2025 17:06:39 +0100 Subject: [PATCH 10/29] DBAL3: Rename more symbols --- .../DBAL/Driver/PDOCrate/CrateStatement.php | 22 +++------ src/Crate/DBAL/Types/ArrayType.php | 4 +- src/Crate/DBAL/Types/MapType.php | 4 +- .../Test/DBAL/DBALFunctionalTestCase.php | 10 ++-- .../Test/DBAL/Functional/BindingTest.php | 44 ++++++++--------- .../Test/DBAL/Functional/DataAccessTest.php | 47 +++++++++---------- .../DBAL/Functional/NamedParametersTest.php | 2 +- .../DBAL/Functional/TypeConversionTest.php | 2 +- test/Crate/Test/DBAL/Functional/WriteTest.php | 14 +++--- 9 files changed, 71 insertions(+), 78 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index 9cb1445..84c587c 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -25,8 +25,6 @@ use Crate\PDO\PDOInterface; use Crate\PDO\PDOStatement; -use Doctrine\DBAL\Driver\PDO\Exception; -use Doctrine\DBAL\Driver\PDOStatementImplementations; use Doctrine\DBAL\Driver\Result as ResultInterface; use Doctrine\DBAL\Driver\Statement as StatementInterface; use Doctrine\DBAL\ParameterType; @@ -62,7 +60,7 @@ public function execute($params = null): ResultInterface 'doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5556', 'Passing $params to Statement::execute() is deprecated. Bind parameters using' - . ' Statement::bindParam() or Statement::bindValue() instead.', + . ' Statement::bindValue() instead.', ); } $this->stmt->execute($params); @@ -94,10 +92,16 @@ public function bindValue($param, $value, $type = ParameterType::STRING) } /** + * @deprecated Use bindValue() instead. * {@inheritDoc} */ public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/5563', + 'Statement::bindParam() was deprecated. Please use Statement::bindValue() instead.', + ); return $this->stmt->bindParam($param, $variable, $type, $length); } @@ -112,18 +116,6 @@ public function fetch( return $this->stmt->fetch($fetch_style, $cursor_orientation, $cursor_offset); } - /** - * @phpstan-param PDO::FETCH_* $mode - * - * @return list - * - * @throws Exception - */ - public function fetchAll(int $mode): array - { - return $this->stmt->fetchAll($mode); - } - public function fetchColumn($column_number = 0) { return $this->stmt->fetchColumn($column_number); diff --git a/src/Crate/DBAL/Types/ArrayType.php b/src/Crate/DBAL/Types/ArrayType.php index df98fef..a3adfd6 100644 --- a/src/Crate/DBAL/Types/ArrayType.php +++ b/src/Crate/DBAL/Types/ArrayType.php @@ -76,7 +76,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) * @param array $fieldDeclaration The field declaration. * @param AbstractPlatform $platform The currently used database platform. * @return string - * @throws \Doctrine\DBAL\DBALException + * @throws \Doctrine\DBAL\Exception */ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { @@ -93,7 +93,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla * * @param array $options * @return string - * @throws \Doctrine\DBAL\DBALException + * @throws \Doctrine\DBAL\Exception */ public function getArrayTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options) { diff --git a/src/Crate/DBAL/Types/MapType.php b/src/Crate/DBAL/Types/MapType.php index 2a49090..d279e47 100644 --- a/src/Crate/DBAL/Types/MapType.php +++ b/src/Crate/DBAL/Types/MapType.php @@ -82,7 +82,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) * @param array $fieldDeclaration The field declaration. * @param AbstractPlatform $platform The currently used database platform. * @return string - * @throws \Doctrine\DBAL\DBALException + * @throws \Doctrine\DBAL\Exception */ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { @@ -98,7 +98,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla * @param array $field * * @return string - * @throws \Doctrine\DBAL\DBALException + * @throws \Doctrine\DBAL\Exception */ public function getMapTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options) { diff --git a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php b/test/Crate/Test/DBAL/DBALFunctionalTestCase.php index 9501a76..0ff9c96 100644 --- a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php +++ b/test/Crate/Test/DBAL/DBALFunctionalTestCase.php @@ -23,6 +23,8 @@ use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Logging\DebugStack; +use Doctrine\DBAL\Result; +use Doctrine\DBAL\Statement; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use Throwable; @@ -105,17 +107,17 @@ protected function onNotSuccessfulTest(Throwable $e) : void throw $e; } - public function execute($stmt) + public function run_sql($stmt): Result { - return $this->_conn->query($stmt); + return $this->_conn->executeQuery($stmt); } - public function refresh($table_name) + public function refresh($table_name): void { $this->_conn->executeStatement('REFRESH TABLE ' . $table_name); } - public function prepareStatement($sql) + public function prepareStatement($sql): Statement { return $this->_conn->prepare($sql); } diff --git a/test/Crate/Test/DBAL/Functional/BindingTest.php b/test/Crate/Test/DBAL/Functional/BindingTest.php index cd177b8..31afbd0 100644 --- a/test/Crate/Test/DBAL/Functional/BindingTest.php +++ b/test/Crate/Test/DBAL/Functional/BindingTest.php @@ -23,7 +23,7 @@ use Crate\Test\DBAL\DBALFunctionalTestCase; -class BindingTestCase extends DBALFunctionalTestCase +class BindingTest extends DBALFunctionalTestCase { public function testBindPositionalParam() @@ -31,15 +31,15 @@ public function testBindPositionalParam() $name = 'crate'; $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ?'); - $stmt->bindParam(1, $name); - $stmt->execute(); + $stmt->bindValue(1, $name); + $stmt->executeQuery(); $noName = 'i0ejfNlzSFCloGYtSzddTw'; $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?'); - $stmt->bindParam(1, $name); - $stmt->bindParam(2, $noName); - $result = $stmt->execute(); + $stmt->bindValue(1, $name); + $stmt->bindValue(2, $noName); + $result = $stmt->executeQuery(); self::assertEquals(1, $result->rowCount()); } @@ -47,12 +47,12 @@ public function testBindPositionalValue() { $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ?'); $stmt->bindValue(1, 'crate'); - $stmt->execute(); + $stmt->executeQuery(); $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?'); $stmt->bindValue(1, 'crate'); $stmt->bindValue(2, 'i0ejfNlzSFCloGYtSzddTw'); - $result = $stmt->execute(); + $result = $stmt->executeQuery(); self::assertEquals(1, $result->rowCount()); } @@ -61,15 +61,15 @@ public function testBindNamedParam() $name = 'crate'; $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name'); - $stmt->bindParam('name', $name); - $stmt->execute(); + $stmt->bindValue('name', $name); + $stmt->executeQuery(); $noName = 'i0ejfNlzSFCloGYtSzddTw'; $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node'); - $stmt->bindParam('name', $name); - $stmt->bindParam('master_node', $noName); - $result = $stmt->execute(); + $stmt->bindValue('name', $name); + $stmt->bindValue('master_node', $noName); + $result = $stmt->executeQuery(); self::assertEquals(1, $result->rowCount()); } @@ -77,26 +77,26 @@ public function testBindNamedValue() { $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name'); $stmt->bindValue('name', 'crate'); - $stmt->execute(); + $stmt->executeQuery(); $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node'); $stmt->bindValue('name', 'crate'); $stmt->bindValue('master_node', 'i0ejfNlzSFCloGYtSzddTw'); - $result = $stmt->execute(); + $result = $stmt->executeQuery(); self::assertEquals(1, $result->rowCount()); } public function testBindTimestamp() { if ($this->_conn->createSchemaManager()->tablesExist("foo")) { - $this->execute("DROP TABLE foo"); + $this->run_sql("DROP TABLE foo"); } - $this->execute("CREATE TABLE foo (id int, ts timestamp) with (number_of_replicas=0)"); - $this->execute("INSERT INTO foo (id, ts) VALUES (1, 1413901591000)"); - $this->execute("INSERT INTO foo (id, ts) VALUES (2, 1413901592000)"); - $this->execute("INSERT INTO foo (id, ts) VALUES (3, 1413901593000)"); - $this->execute("REFRESH TABLE foo"); + $this->run_sql("CREATE TABLE foo (id int, ts timestamp) with (number_of_replicas=0)"); + $this->run_sql("INSERT INTO foo (id, ts) VALUES (1, 1413901591000)"); + $this->run_sql("INSERT INTO foo (id, ts) VALUES (2, 1413901592000)"); + $this->run_sql("INSERT INTO foo (id, ts) VALUES (3, 1413901593000)"); + $this->run_sql("REFRESH TABLE foo"); $date = new \DateTime("2014-10-21 14:26:32"); // => 1413901592000 @@ -112,6 +112,6 @@ public function testBindTimestamp() $this->assertEquals($row[0]['id'], 1); $this->assertEquals($row[0]['ts'], 1413901591000); - $this->execute("DROP TABLE foo"); + $this->run_sql("DROP TABLE foo"); } } diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index 3a98aac..a407bd5 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -34,7 +34,7 @@ use PDO; -class DataAccessTestCase extends DBALFunctionalTestCase +class DataAccessTest extends DBALFunctionalTestCase { static private $generated = false; @@ -109,8 +109,8 @@ public function testPrepareWithBindParam() $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); - $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); + $stmt->bindValue(1, $paramInt, PDO::PARAM_INT); + $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); $result = $stmt->executeQuery(); $row = $result->fetch(PDO::FETCH_ASSOC); @@ -127,8 +127,8 @@ public function testPrepareWithFetchAll() $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); - $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); + $stmt->bindValue(1, $paramInt, PDO::PARAM_INT); + $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); $result = $stmt->executeQuery(); $rows = $result->fetchAllAssociative(); @@ -158,9 +158,9 @@ public function testPrepareWithFetchColumn() $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); - $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); - $stmt->execute(); + $stmt->bindValue(1, $paramInt, PDO::PARAM_INT); + $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); + $stmt->executeStatement(); $column = $stmt->getWrappedStatement()->fetchColumn(); $this->assertEquals(1, $column); @@ -175,8 +175,8 @@ public function testPrepareWithIterator() $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $stmt->bindParam(1, $paramInt, PDO::PARAM_INT); - $stmt->bindParam(2, $paramStr, PDO::PARAM_STR); + $stmt->bindValue(1, $paramInt, PDO::PARAM_INT); + $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); $result = $stmt->executeQuery(); $rows = array(); @@ -207,7 +207,7 @@ public function testPrepareWithExecuteParams() $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; $stmt = $this->_conn->prepare($sql); $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - $result = $stmt->execute(array($paramInt, $paramStr)); + $result = $stmt->executeQuery(array($paramInt, $paramStr)); $row = $result->fetch(PDO::FETCH_ASSOC); $this->assertTrue($row !== false); @@ -288,7 +288,7 @@ public function testExecuteUpdateBindDateTimeType() $datetime = new \DateTime('2010-02-02 20:20:20'); $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)'; - $affectedRows = $this->_conn->executeUpdate($sql, + $affectedRows = $this->_conn->executeStatement($sql, array(1 => 50, 2 => 'foo', 3 => $datetime), array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Types::DATETIME_MUTABLE) ); @@ -328,14 +328,14 @@ public function testNativeArrayListSupport() $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int IN (?) ORDER BY test_int', array(array(100, 101, 102, 103, 104)), array(Connection::PARAM_INT_ARRAY)); - $data = $stmt->fetchAll(PDO::FETCH_NUM); + $data = $stmt->fetchAllNumeric(); $this->assertEquals(5, count($data)); $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data); $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_string IN (?) ORDER BY test_int', array(array('foo100', 'foo101', 'foo102', 'foo103', 'foo104')), array(Connection::PARAM_STR_ARRAY)); - $data = $stmt->fetchAll(PDO::FETCH_NUM); + $data = $stmt->fetchAllNumeric(); $this->assertEquals(5, count($data)); $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data); } @@ -382,7 +382,7 @@ public function testBitComparisonExpressionSupport() { $this->markTestSkipped("Bit comparison expressions not supported by CrateDB"); - $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $this->_conn->executeStatement('DELETE FROM fetch_table'); $platform = $this->_conn->getDatabasePlatform(); $bitmap = array(); @@ -406,7 +406,7 @@ public function testBitComparisonExpressionSupport() $sql[] = 'FROM fetch_table'; $stmt = $this->_conn->executeQuery(implode(PHP_EOL, $sql)); - $data = $stmt->fetchAll(PDO::FETCH_ASSOC); + $data = $stmt->fetchAllAssociative(); $this->assertEquals(4, count($data)); @@ -447,9 +447,9 @@ public function testFetchAllSupportFetchClass() $sql = "SELECT test_int, test_string, test_datetime FROM fetch_table"; $stmt = $this->_conn->prepare($sql); - $stmt->execute(); + $result = $stmt->executeQuery(); - $results = $stmt->fetchAll( + $results = $result->fetch( PDO::FETCH_CLASS, __NAMESPACE__.'\\MyFetchClass' ); @@ -468,14 +468,14 @@ public function testFetchAllSupportFetchClass() public function testFetchAllStyleColumn() { $sql = "DELETE FROM fetch_table"; - $this->_conn->executeUpdate($sql); + $this->_conn->executeStatement($sql); $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo')); $this->_conn->insert('fetch_table', array('test_int' => 10, 'test_string' => 'foo')); $this->refresh("fetch_table"); $sql = "SELECT test_int FROM fetch_table ORDER BY test_int ASC"; - $rows = $this->_conn->query($sql)->fetchAll(PDO::FETCH_COLUMN); + $rows = $this->_conn->query($sql)->fetchFirstColumn(); $this->assertEquals(array(1, 10), $rows); } @@ -536,9 +536,8 @@ public function testEmptyFetchColumnReturnsFalse() { $this->_conn->executeStatement('DELETE FROM fetch_table'); $this->refresh("fetch_table"); - $stmt = $this->_conn->prepare('SELECT test_int FROM fetch_table'); - $stmt->execute(); - $this->assertFalse($stmt->getWrappedStatement()->fetchColumn()); + $this->assertFalse($this->_conn->fetchOne('SELECT test_int FROM fetch_table')); + $this->assertFalse($this->_conn->executeQuery('SELECT test_int FROM fetch_table')->fetchOne()); } /** @@ -557,7 +556,7 @@ public function testSetFetchModeOnDbalStatement() private function setupFixture() { - $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $this->_conn->executeStatement('DELETE FROM fetch_table'); $this->_conn->insert('fetch_table', array( 'test_int' => 1, 'test_string' => 'foo', diff --git a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php index d122366..22e3661 100644 --- a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php +++ b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php @@ -168,7 +168,7 @@ public function tearDown() : void public function testTicket($query,$params,$types,$expected) { $stmt = $this->_conn->executeQuery($query, $params, $types); - $result = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $result = $stmt->fetchAllAssociative(); foreach ($result as $k => $v) { $result[$k] = array_change_key_case($v, CASE_LOWER); diff --git a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php index 4563b80..ddc6c45 100644 --- a/test/Crate/Test/DBAL/Functional/TypeConversionTest.php +++ b/test/Crate/Test/DBAL/Functional/TypeConversionTest.php @@ -30,7 +30,7 @@ use Doctrine\DBAL\Types\Types; use PHPUnit\Framework\TestCase; -class TypeConversionTestCase extends TestCase { +class TypeConversionTest extends TestCase { private $platform; diff --git a/test/Crate/Test/DBAL/Functional/WriteTest.php b/test/Crate/Test/DBAL/Functional/WriteTest.php index b9197fa..25b5c81 100644 --- a/test/Crate/Test/DBAL/Functional/WriteTest.php +++ b/test/Crate/Test/DBAL/Functional/WriteTest.php @@ -67,7 +67,7 @@ public function setUp() : void public function tearDown() : void { if (self::$generated === true) { - $this->execute('drop table write_table'); + $this->run_sql('drop table write_table'); self::$generated = false; } } @@ -79,27 +79,27 @@ public function tearDown() : void public function testExecuteUpdateFirstTypeIsNull() { $sql = "INSERT INTO write_table (test_string, test_int) VALUES (?, ?)"; - $this->_conn->executeUpdate($sql, array("text", 1111), array(null, PDO::PARAM_INT)); + $this->_conn->executeStatement($sql, array("text", 1111), array(null, PDO::PARAM_INT)); $this->refresh('write_table'); $sql = "SELECT test_obj, test_string, test_int FROM write_table WHERE test_string = ? AND test_int = ?"; $stmt = $this->_conn->prepare($sql); $nstmt = $stmt->getWrappedStatement(); - $stmt->execute(array("text", 1111)); + $stmt->executeQuery(array("text", 1111)); $this->assertEquals(null, $nstmt->fetchColumn(0)); - $stmt->execute(array("text", 1111)); + $stmt->executeQuery(array("text", 1111)); $this->assertEquals("text", $nstmt->fetchColumn(1)); - $stmt->execute(array("text", 1111)); + $stmt->executeQuery(array("text", 1111)); $this->assertEquals(1111, $nstmt->fetchColumn(2)); } public function testExecuteUpdate() { $sql = "INSERT INTO write_table (test_int) VALUES ( " . $this->_conn->quote(1, PDO::PARAM_INT) . ")"; - $affected = $this->_conn->executeUpdate($sql); + $affected = $this->_conn->executeStatement($sql); $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!"); } @@ -107,7 +107,7 @@ public function testExecuteUpdate() public function testExecuteUpdateWithTypes() { $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; - $affected = $this->_conn->executeUpdate($sql, array(1, 'foo'), array(PDO::PARAM_INT, PDO::PARAM_STR)); + $affected = $this->_conn->executeStatement($sql, array(1, 'foo'), array(PDO::PARAM_INT, PDO::PARAM_STR)); $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!"); } From fe34cf7fd7b8750e8df2bd3c76f61e01e21046cc Mon Sep 17 00:00:00 2001 From: Julian Martin Date: Sun, 16 Nov 2025 17:30:34 +0100 Subject: [PATCH 11/29] DBAL3: Towards DBAL4 --- .../DBAL/Driver/PDOCrate/CrateStatement.php | 4 +- .../DBAL/Driver/PDOCrate/PDOConnection.php | 16 ++-- src/Crate/DBAL/Platforms/CratePlatform.php | 82 ++++++++++--------- src/Crate/DBAL/Platforms/CratePlatform4.php | 12 +-- 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index 84c587c..60dda35 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -86,9 +86,9 @@ public function rowCount(): int /** * {@inheritDoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING): void { - return $this->stmt->bindValue($param, $value, $type); + $this->stmt->bindValue($param, $value, $type); } /** diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 625eb10..22d03e0 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -49,10 +49,11 @@ public function __construct($dsn, $user = null, $password = null, ?array $option $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } - public function getServerVersion() + public function getServerVersion(): string { // Unable to detect platform version. - return null; + // TODO: Need to retrieve and propagate CrateDB server version here? + return "0.0.0"; } public function getNativeConnection(): PDOCrateDB @@ -107,23 +108,20 @@ public function quote($value, $type = ParameterType::STRING): string return $this->connection->quote($value, $type); } - public function lastInsertId($name = null): string|false + public function lastInsertId($name = null): string { return $this->connection->lastInsertId($name); } - public function beginTransaction(): bool + public function beginTransaction(): void { - return true; } - public function commit(): bool + public function commit(): void { - return true; } - public function rollBack(): bool + public function rollBack(): void { - return true; } } diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index e355d6a..9b32f94 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -62,7 +62,7 @@ public function __construct() /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from = 0, $length = null) + public function getSubstringExpression($value, $from = 0, $length = null): string { if ($length === null) { return 'SUBSTR(' . $value . ', ' . $from . ')'; @@ -82,7 +82,7 @@ public function getNowExpression() /** * {@inheritDoc} */ - public function getRegexpExpression() + public function getRegexpExpression(): string { return 'LIKE'; } @@ -90,7 +90,7 @@ public function getRegexpExpression() /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression($date1, $date2): string { throw DBALException::notSupported(__METHOD__); } @@ -98,7 +98,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - public function supportsSequences() + public function supportsSequences(): bool { return false; } @@ -109,7 +109,7 @@ public function supportsSequences() * * {@inheritDoc} */ - public function supportsSchemas() + public function supportsSchemas(): bool { return false; } @@ -117,7 +117,7 @@ public function supportsSchemas() /** * {@inheritDoc} */ - public function supportsIdentityColumns() + public function supportsIdentityColumns(): bool { return true; } @@ -133,7 +133,7 @@ public function supportsIndexes() /** * {@inheritDoc} */ - public function supportsCommentOnStatement() + public function supportsCommentOnStatement(): bool { return false; } @@ -173,7 +173,7 @@ public function prefersSequences() /** * {@inheritDoc} */ - public function getListDatabasesSQL() + public function getListDatabasesSQL(): string { throw DBALException::notSupported(__METHOD__); } @@ -251,7 +251,7 @@ protected function getTableWhereClauseFormat() /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff): array { $sql = array(); $commentsSQL = array(); @@ -295,7 +295,7 @@ public function getAlterTableSQL(TableDiff $diff) /** * {@inheritDoc} */ - public function getColumnDeclarationSQL($name, array $column) + public function getColumnDeclarationSQL($name, array $column): string { if (isset($column['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($column); @@ -309,9 +309,11 @@ public function getColumnDeclarationSQL($name, array $column) /** * Generate table index column declaration + * @param string $name + * @param Index $index * @codeCoverageIgnore */ - public function getIndexDeclarationSQL($name, Index $index) + public function getIndexDeclarationSQL($name, Index $index): string { $columns = $index->getQuotedColumns($this); $name = new Identifier($name); @@ -329,7 +331,7 @@ public function getIndexDeclarationSQL($name, Index $index) * * Crate wants boolean values converted to the strings 'true'/'false'. */ - public function convertBooleans($item) + public function convertBooleans($item): mixed { if (is_array($item)) { foreach ($item as $key => $value) { @@ -353,7 +355,7 @@ public function convertBooleans($item) /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $field): string { return 'BOOLEAN'; } @@ -361,7 +363,7 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $field): string { return 'INTEGER'; } @@ -369,7 +371,7 @@ public function getIntegerTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $field): string { return 'LONG'; } @@ -377,7 +379,7 @@ public function getBigIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $field): string { return 'SHORT'; } @@ -385,7 +387,7 @@ public function getSmallIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getFloatDeclarationSQL(array $field) + public function getFloatDeclarationSQL(array $field): string { return 'DOUBLE'; } @@ -393,7 +395,7 @@ public function getFloatDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getDecimalTypeDeclarationSQL(array $columnDef) + public function getDecimalTypeDeclarationSQL(array $columnDef): string { return 'DOUBLE'; } @@ -401,7 +403,7 @@ public function getDecimalTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration): string { return 'TIMESTAMP'; } @@ -409,7 +411,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration): string { return 'TIMESTAMP'; } @@ -417,7 +419,7 @@ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration): string { return 'TIMESTAMP'; } @@ -425,7 +427,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration): string { return 'TIMESTAMP'; } @@ -434,15 +436,17 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) * {@inheritDoc} */ // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef): string { return ''; } /** * {@inheritDoc} + * @param false|int $length + * @param $fixed */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed): string { return 'STRING'; } @@ -450,7 +454,7 @@ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field): string { return 'STRING'; } @@ -476,7 +480,7 @@ public function getSQLResultCasing($column) /** * {@inheritDoc} */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString(): string { return self::TIMESTAMP_FORMAT_TZ; } @@ -484,7 +488,7 @@ public function getDateTimeTzFormatString() /** * {@inheritDoc} */ - public function getDateTimeFormatString() + public function getDateTimeFormatString(): string { return self::TIMESTAMP_FORMAT; } @@ -492,7 +496,7 @@ public function getDateTimeFormatString() /** * {@inheritDoc} */ - public function getDateFormatString() + public function getDateFormatString(): string { return self::TIMESTAMP_FORMAT; } @@ -500,7 +504,7 @@ public function getDateFormatString() /** * {@inheritDoc} */ - public function getTimeFormatString() + public function getTimeFormatString(): string { return self::TIMESTAMP_FORMAT; } @@ -508,7 +512,7 @@ public function getTimeFormatString() /** * {@inheritDoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL($tableName, $cascade = false): string { throw DBALException::notSupported(__METHOD__); } @@ -524,7 +528,7 @@ public function getReadLockSQL() /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings(): void { $this->doctrineTypeMapping = array( 'short' => 'smallint', @@ -545,7 +549,7 @@ protected function initializeDoctrineTypeMappings() /** * {@inheritDoc} */ - public function getDoctrineTypeMapping($dbType) + public function getDoctrineTypeMapping($dbType): string { // typed arrays will always end up in the same generic php array type if (substr_compare($dbType, 'array', -5) === 0) { @@ -574,7 +578,7 @@ protected function getReservedKeywordsClass() /** * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field): string { throw DBALException::notSupported(__METHOD__); } @@ -589,7 +593,7 @@ public function getBlobTypeDeclarationSQL(array $field) * * @return array The sequence of SQL statements. */ - public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES) + public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES): array { if (!is_int($createFlags)) { $msg = "Second argument of CratePlatform::getCreateTableSQL() has to be integer."; @@ -673,7 +677,7 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE * {@inheritDoc} */ // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore - protected function _getCreateTableSQL($name, array $columns, array $options = array()) + protected function _getCreateTableSQL($name, array $columns, array $options = array()): array { $columnListSql = $this->getColumnDeclarationListSQL($columns); @@ -820,7 +824,7 @@ public static function prepareColumnData(AbstractPlatform $platform, $column, $p /** * {@inheritDoc} */ - public function getCreateDatabaseSQL($database) + public function getCreateDatabaseSQL($database): string { throw DBALException::notSupported(__METHOD__); } @@ -828,7 +832,7 @@ public function getCreateDatabaseSQL($database) /** * {@inheritDoc} */ - public function getDropDatabaseSQL($database) + public function getDropDatabaseSQL($database): string { throw DBALException::notSupported(__METHOD__); } @@ -836,7 +840,7 @@ public function getDropDatabaseSQL($database) /** * {@inheritDoc} */ - public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table): string { throw DBALException::notSupported(__METHOD__); } @@ -844,7 +848,7 @@ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) /** * {@inheritDoc} */ - public function getGuidTypeDeclarationSQL(array $field) + public function getGuidTypeDeclarationSQL(array $field): string { throw DBALException::notSupported(__METHOD__); } diff --git a/src/Crate/DBAL/Platforms/CratePlatform4.php b/src/Crate/DBAL/Platforms/CratePlatform4.php index cdb51a3..d2a6c23 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform4.php +++ b/src/Crate/DBAL/Platforms/CratePlatform4.php @@ -28,7 +28,7 @@ class CratePlatform4 extends CratePlatform1 /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings(): void { $this->doctrineTypeMapping = array( 'integer' => 'integer', @@ -55,7 +55,7 @@ protected function initializeDoctrineTypeMappings() /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $field): string { return 'BIGINT'; } @@ -63,7 +63,7 @@ public function getBigIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $field): string { return 'SMALLINT'; } @@ -71,7 +71,7 @@ public function getSmallIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getFloatDeclarationSQL(array $field) + public function getFloatDeclarationSQL(array $field): string { return 'DOUBLE PRECISION'; } @@ -79,7 +79,7 @@ public function getFloatDeclarationSQL(array $field) /** * {@inheritDoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed): string { return 'TEXT'; } @@ -87,7 +87,7 @@ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field): string { return 'TEXT'; } From 4b721378d1e6e0bc9bc9de24c7baca1ed366edac Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Sun, 16 Nov 2025 17:58:48 +0100 Subject: [PATCH 12/29] DBAL3: Implement suggestions by CodeRabbit --- .php-cs-fixer.php | 2 ++ CHANGES.txt | 2 +- src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php | 7 ++++++- src/Crate/DBAL/Schema/CrateSchemaManager.php | 2 +- test/Crate/Test/DBAL/Functional/DataAccessTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php | 2 +- test/Crate/Test/DBAL/Functional/WriteTest.php | 4 ++-- 7 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 73504cb..94aaa75 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -5,6 +5,8 @@ $finder = (new PhpCsFixer\Finder()) ->in(__DIR__) + ->exclude('build') + ->exclude('vendor') ; return (new PhpCsFixer\Config()) diff --git a/CHANGES.txt b/CHANGES.txt index 85187c9..99dd0b2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,7 +5,7 @@ CHANGES for crate-dbal Unreleased ========== -- Added support for Doctrine 3, dropped support for Doctrine 2. +- Added support for Doctrine DBAL 3, dropped support for Doctrine DBAL 2. 2025/11/13 4.0.3 ================ diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index 60dda35..b46a15b 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -30,6 +30,7 @@ use Doctrine\DBAL\ParameterType; use Doctrine\Deprecations\Deprecation; use PDO; +use PDOException; /** * @internal @@ -63,7 +64,11 @@ public function execute($params = null): ResultInterface . ' Statement::bindValue() instead.', ); } - $this->stmt->execute($params); + try { + $this->stmt->execute($params); + } catch (PDOException $exception) { + throw Exception::new($exception); + } return new Result($this); } diff --git a/src/Crate/DBAL/Schema/CrateSchemaManager.php b/src/Crate/DBAL/Schema/CrateSchemaManager.php index 3029cc4..d1d241e 100644 --- a/src/Crate/DBAL/Schema/CrateSchemaManager.php +++ b/src/Crate/DBAL/Schema/CrateSchemaManager.php @@ -116,7 +116,7 @@ protected function _getPortableTablesList($tables) * * @return array */ - private function flatten(array $array, string $prefix = ''): array + private static function flatten(array $array, string $prefix = ''): array { $result = array(); foreach ($array as $key => $value) { diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index a407bd5..e3004d4 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -113,7 +113,7 @@ public function testPrepareWithBindParam() $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); $result = $stmt->executeQuery(); - $row = $result->fetch(PDO::FETCH_ASSOC); + $row = $result->fetchAssociative(); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); } @@ -209,7 +209,7 @@ public function testPrepareWithExecuteParams() $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); $result = $stmt->executeQuery(array($paramInt, $paramStr)); - $row = $result->fetch(PDO::FETCH_ASSOC); + $row = $result->fetchAssociative(); $this->assertTrue($row !== false); $row = array_change_key_case($row, \CASE_LOWER); $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); diff --git a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php index 4b4039c..6a0ec19 100644 --- a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php +++ b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php @@ -81,7 +81,7 @@ public function testModifyLimitQuerySimpleQuery(): void $this->assertLimitResult(array(3, 4), $sql, 2, 2); } - public function testModifyLimitQueryOrderBy() + public function testModifyLimitQueryOrderBy(): void { $this->_conn->insert('modify_limit_table', array('test_int' => 1)); $this->_conn->insert('modify_limit_table', array('test_int' => 2)); diff --git a/test/Crate/Test/DBAL/Functional/WriteTest.php b/test/Crate/Test/DBAL/Functional/WriteTest.php index 25b5c81..471593b 100644 --- a/test/Crate/Test/DBAL/Functional/WriteTest.php +++ b/test/Crate/Test/DBAL/Functional/WriteTest.php @@ -197,11 +197,11 @@ public function testDelete() $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 2))); $this->refresh('write_table'); - $this->assertEquals(1, count($this->_conn->fetchAllAssociative('SELECT * FROM write_table'))); + $this->assertCount(1, $this->_conn->fetchAllAssociative('SELECT * FROM write_table')); $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 1))); $this->refresh('write_table'); - $this->assertEquals(0, count($this->_conn->fetchAllAssociative('SELECT * FROM write_table'))); + $this->assertCount(0, $this->_conn->fetchAllAssociative('SELECT * FROM write_table')); } public function testUpdate() From 32c556a3d408bd49dc4b90b363c4381ddcc9f798 Mon Sep 17 00:00:00 2001 From: Julian Martin Date: Sun, 16 Nov 2025 19:39:30 +0100 Subject: [PATCH 13/29] DBAL3: More generic type hinting --- src/Crate/DBAL/Driver/PDOCrate/Result.php | 6 +++--- src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php | 2 +- src/Crate/DBAL/Schema/CrateSchemaManager.php | 4 ++-- src/Crate/DBAL/Types/ArrayType.php | 6 +++--- src/Crate/DBAL/Types/MapType.php | 6 +++--- src/Crate/DBAL/Types/TimestampType.php | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/Result.php b/src/Crate/DBAL/Driver/PDOCrate/Result.php index 5d07444..b371dec 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Result.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Result.php @@ -22,7 +22,7 @@ public function __construct(CrateStatement $statement) /** * {@inheritDoc} */ - public function fetchNumeric() + public function fetchNumeric(): false|array { return $this->fetch(PDO::FETCH_NUM); } @@ -30,7 +30,7 @@ public function fetchNumeric() /** * {@inheritDoc} */ - public function fetchAssociative() + public function fetchAssociative(): false|array { return $this->fetch(PDO::FETCH_ASSOC); } @@ -38,7 +38,7 @@ public function fetchAssociative() /** * {@inheritDoc} */ - public function fetchOne() + public function fetchOne(): mixed { return FetchUtils::fetchOne($this); } diff --git a/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php b/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php index 748e3dd..c6e9c34 100644 --- a/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php +++ b/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php @@ -32,7 +32,7 @@ public function getName() return 'Crate'; } - protected function getKeywords() + protected function getKeywords(): array { return array( 'ALL', diff --git a/src/Crate/DBAL/Schema/CrateSchemaManager.php b/src/Crate/DBAL/Schema/CrateSchemaManager.php index d1d241e..7293c05 100644 --- a/src/Crate/DBAL/Schema/CrateSchemaManager.php +++ b/src/Crate/DBAL/Schema/CrateSchemaManager.php @@ -41,7 +41,7 @@ class CrateSchemaManager extends AbstractSchemaManager * */ // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null): array { $buffer = []; foreach ($tableIndexes as $row) { @@ -61,7 +61,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null * {@inheritDoc} */ // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition($tableColumn): Column { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); diff --git a/src/Crate/DBAL/Types/ArrayType.php b/src/Crate/DBAL/Types/ArrayType.php index a3adfd6..879d681 100644 --- a/src/Crate/DBAL/Types/ArrayType.php +++ b/src/Crate/DBAL/Types/ArrayType.php @@ -57,7 +57,7 @@ public function getBindingType() return PDOCrateDB::PARAM_ARRAY; } - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed { if (!is_array($value) || (count($value) > 0 && !(array_keys($value) === range(0, count($value) - 1)))) { return null; @@ -65,7 +65,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value; } - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): mixed { return $value; } @@ -78,7 +78,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) * @return string * @throws \Doctrine\DBAL\Exception */ - public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { $options = !array_key_exists('platformOptions', $fieldDeclaration) ? array() : $fieldDeclaration['platformOptions']; diff --git a/src/Crate/DBAL/Types/MapType.php b/src/Crate/DBAL/Types/MapType.php index d279e47..e4127d7 100644 --- a/src/Crate/DBAL/Types/MapType.php +++ b/src/Crate/DBAL/Types/MapType.php @@ -62,7 +62,7 @@ public function getBindingType() return PDOCrateDB::PARAM_OBJECT; } - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed { if (!is_array($value) || (count($value) > 0 && !(array_keys($value) !== range(0, count($value) - 1)))) { return null; @@ -71,7 +71,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value; } - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): mixed { return $value == null ?: (array) $value; } @@ -84,7 +84,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) * @return string * @throws \Doctrine\DBAL\Exception */ - public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { $options = !array_key_exists('platformOptions', $fieldDeclaration) ? array() : $fieldDeclaration['platformOptions']; diff --git a/src/Crate/DBAL/Types/TimestampType.php b/src/Crate/DBAL/Types/TimestampType.php index b1d5523..0ffbe73 100644 --- a/src/Crate/DBAL/Types/TimestampType.php +++ b/src/Crate/DBAL/Types/TimestampType.php @@ -46,13 +46,13 @@ public function getName() return self::NAME; } - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed { return ($value !== null && $value instanceof DateTime) ? $value->getTimestamp() * self::S_TO_MS : null; } - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): mixed { if ($value === null || $value instanceof DateTime) { return $value; @@ -75,7 +75,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) * @param array $fieldDeclaration The field declaration. * @param AbstractPlatform $platform The currently used database platform. */ - public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { return $platform->getDateTimeTypeDeclarationSQL($fieldDeclaration); } From 8bf6a9503506f1c935d2edfad9c7f533a31a7676 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Sun, 16 Nov 2025 22:56:35 +0100 Subject: [PATCH 14/29] Chore: Naming things `s/TestCase/Test/` --- .../{DBALFunctionalTestCase.php => DBALFunctionalTest.php} | 4 ++-- test/Crate/Test/DBAL/Functional/BindingTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/ConnectionTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/DataAccessTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/NamedParametersTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/TableOptionsTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php | 4 ++-- test/Crate/Test/DBAL/Functional/WriteTest.php | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) rename test/Crate/Test/DBAL/{DBALFunctionalTestCase.php => DBALFunctionalTest.php} (96%) diff --git a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php b/test/Crate/Test/DBAL/DBALFunctionalTest.php similarity index 96% rename from test/Crate/Test/DBAL/DBALFunctionalTestCase.php rename to test/Crate/Test/DBAL/DBALFunctionalTest.php index 0ff9c96..ce5380c 100644 --- a/test/Crate/Test/DBAL/DBALFunctionalTestCase.php +++ b/test/Crate/Test/DBAL/DBALFunctionalTest.php @@ -29,10 +29,10 @@ use PHPUnit\Framework\TestCase; use Throwable; -abstract class DBALFunctionalTestCase extends TestCase +abstract class DBALFunctionalTest extends TestCase { /** - * Shared connection when a TestCase is run alone (outside of it's functional suite) + * Shared connection when a TestCase is run alone (outside its functional suite) * * @var \Doctrine\DBAL\Connection */ diff --git a/test/Crate/Test/DBAL/Functional/BindingTest.php b/test/Crate/Test/DBAL/Functional/BindingTest.php index 31afbd0..e6075f2 100644 --- a/test/Crate/Test/DBAL/Functional/BindingTest.php +++ b/test/Crate/Test/DBAL/Functional/BindingTest.php @@ -21,9 +21,9 @@ */ namespace Crate\Test\DBAL\Functional; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; -class BindingTest extends DBALFunctionalTestCase +class BindingTest extends DBALFunctionalTest { public function testBindPositionalParam() diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index a45d56c..b903467 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -22,10 +22,10 @@ namespace Crate\Test\DBAL\Functional; use Crate\PDO\PDOCrateDB; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\DriverManager; -class ConnectionTestCase extends DBALFunctionalTestCase +class ConnectionTest extends DBALFunctionalTest { public function setUp() : void { diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index e3004d4..edd09c2 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -23,7 +23,7 @@ namespace Crate\Test\DBAL\Functional; use Crate\DBAL\Types\MapType; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\ParameterType; @@ -34,7 +34,7 @@ use PDO; -class DataAccessTest extends DBALFunctionalTestCase +class DataAccessTest extends DBALFunctionalTest { static private $generated = false; diff --git a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php index 6a0ec19..df67d8c 100644 --- a/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php +++ b/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php @@ -22,11 +22,11 @@ namespace Crate\Test\DBAL\Functional; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Schema\Table; -class ModifyLimitQueryTest extends DBALFunctionalTestCase +class ModifyLimitQueryTest extends DBALFunctionalTest { private static $tableCreated = false; diff --git a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php index 22e3661..6abe52d 100644 --- a/test/Crate/Test/DBAL/Functional/NamedParametersTest.php +++ b/test/Crate/Test/DBAL/Functional/NamedParametersTest.php @@ -2,7 +2,7 @@ namespace Crate\Test\DBAL\Functional; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Table; use PDO; @@ -10,7 +10,7 @@ /** * @group DDC-1372 */ -class NamedParametersTest extends DBALFunctionalTestCase +class NamedParametersTest extends DBALFunctionalTest { public function ticketProvider() diff --git a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php index cd6ca73..aa89428 100644 --- a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php +++ b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php @@ -23,14 +23,14 @@ use Crate\DBAL\Types\MapType; use Crate\DBAL\Types\TimestampType; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\IntegerType; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; -class SchemaManagerTest extends DBALFunctionalTestCase +class SchemaManagerTest extends DBALFunctionalTest { /** * @var \Doctrine\DBAL\Schema\AbstractSchemaManager diff --git a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php index 34fc081..4dbced8 100644 --- a/test/Crate/Test/DBAL/Functional/TableOptionsTest.php +++ b/test/Crate/Test/DBAL/Functional/TableOptionsTest.php @@ -23,11 +23,11 @@ namespace Crate\Test\DBAL\Functional; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Schema\Table; use InvalidArgumentException; -class TableOptionsTest extends DBALFunctionalTestCase { +class TableOptionsTest extends DBALFunctionalTest { public function tearDown() : void { diff --git a/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php b/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php index fce0a47..693b000 100644 --- a/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php +++ b/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php @@ -25,13 +25,13 @@ use Crate\DBAL\Platforms\CratePlatform; use Crate\DBAL\Types\MapType; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; -class MapTypeTest extends DBALFunctionalTestCase { +class MapTypeTest extends DBALFunctionalTest { public function testStrictMapTableCreationWithSchemaManager() { $platform = $this->_conn->getDatabasePlatform(); diff --git a/test/Crate/Test/DBAL/Functional/WriteTest.php b/test/Crate/Test/DBAL/Functional/WriteTest.php index 471593b..d5adb8c 100644 --- a/test/Crate/Test/DBAL/Functional/WriteTest.php +++ b/test/Crate/Test/DBAL/Functional/WriteTest.php @@ -23,14 +23,14 @@ namespace Crate\Test\DBAL\Functional; use Crate\DBAL\Types\MapType; -use Crate\Test\DBAL\DBALFunctionalTestCase; +use Crate\Test\DBAL\DBALFunctionalTest; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use PDO; -class WriteTest extends DBALFunctionalTestCase +class WriteTest extends DBALFunctionalTest { static private $generated = false; From e15924c505dfb0ed6a6eee8619a2d71d41bf6de9 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Tue, 18 Nov 2025 15:39:29 +0100 Subject: [PATCH 15/29] Chore: Implement suggestions by CodeRabbit - Remove redundant test function `testPrepareWithBindParam` - Remove deprecated test function about `PDO::FETCH_CLASS` - Complete function signature type hinting - Improve MapType::convertToPHPValue about accounting for `null` values --- src/Crate/DBAL/Types/ArrayType.php | 2 +- src/Crate/DBAL/Types/MapType.php | 9 ++-- .../Test/DBAL/Functional/DataAccessTest.php | 44 ------------------- 3 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/Crate/DBAL/Types/ArrayType.php b/src/Crate/DBAL/Types/ArrayType.php index 879d681..702e343 100644 --- a/src/Crate/DBAL/Types/ArrayType.php +++ b/src/Crate/DBAL/Types/ArrayType.php @@ -95,7 +95,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla * @return string * @throws \Doctrine\DBAL\Exception */ - public function getArrayTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options) + public function getArrayTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options): string { $type = array_key_exists('type', $options) ? $options['type'] : Types::STRING; return 'ARRAY ( ' . Type::getType($type)->getSQLDeclaration($field, $platform) . ' )'; diff --git a/src/Crate/DBAL/Types/MapType.php b/src/Crate/DBAL/Types/MapType.php index e4127d7..f7edb97 100644 --- a/src/Crate/DBAL/Types/MapType.php +++ b/src/Crate/DBAL/Types/MapType.php @@ -64,7 +64,7 @@ public function getBindingType() public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed { - if (!is_array($value) || (count($value) > 0 && !(array_keys($value) !== range(0, count($value) - 1)))) { + if (!is_array($value) || (count($value) > 0 && array_keys($value) === range(0, count($value) - 1))) { return null; } @@ -73,7 +73,10 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): mixe public function convertToPHPValue($value, AbstractPlatform $platform): mixed { - return $value == null ?: (array) $value; + if ($value === null) { + return null; + } + return (array) $value; } /** @@ -100,7 +103,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla * @return string * @throws \Doctrine\DBAL\Exception */ - public function getMapTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options) + public function getMapTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options): string { $type = array_key_exists('type', $options) ? $options['type'] : MapType::DYNAMIC; diff --git a/test/Crate/Test/DBAL/Functional/DataAccessTest.php b/test/Crate/Test/DBAL/Functional/DataAccessTest.php index edd09c2..ae8175f 100644 --- a/test/Crate/Test/DBAL/Functional/DataAccessTest.php +++ b/test/Crate/Test/DBAL/Functional/DataAccessTest.php @@ -100,24 +100,6 @@ public function testPrepareWithBindValue() $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); } - public function testPrepareWithBindParam() - { - $paramInt = 1; - $paramStr = 'foo'; - - $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; - $stmt = $this->_conn->prepare($sql); - $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); - - $stmt->bindValue(1, $paramInt, PDO::PARAM_INT); - $stmt->bindValue(2, $paramStr, PDO::PARAM_STR); - $result = $stmt->executeQuery(); - - $row = $result->fetchAssociative(); - $row = array_change_key_case($row, \CASE_LOWER); - $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); - } - public function testPrepareWithFetchAll() { $paramInt = 1; @@ -436,32 +418,6 @@ public function testSetDefaultFetchMode() $this->assertEquals(0, count( array_filter($row, function($v) { return ! is_numeric($v); })), "should be no non-numerical elements in the result."); } - /** - * @group DBAL-196 - */ - public function testFetchAllSupportFetchClass() - { - $this->markTestSkipped("PDO::FETCH_CLASS is not supported by the CrateDB PDO driver"); - - $this->setupFixture(); - - $sql = "SELECT test_int, test_string, test_datetime FROM fetch_table"; - $stmt = $this->_conn->prepare($sql); - $result = $stmt->executeQuery(); - - $results = $result->fetch( - PDO::FETCH_CLASS, - __NAMESPACE__.'\\MyFetchClass' - ); - - $this->assertEquals(1, count($results)); - $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]); - - $this->assertEquals(1, $results[0]->test_int); - $this->assertEquals('foo', $results[0]->test_string); - $this->assertStringStartsWith('2010-01-01T10:10:10', $results[0]->test_datetime); - } - /** * @group DBAL-241 */ From ec6eef90807ade0949776fa57eb540909a708c2d Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 19 Nov 2025 19:23:16 +0100 Subject: [PATCH 16/29] DBAL3: Use `Doctrine\DBAL\Driver\PDO\Exception` instead of copying --- .../DBAL/Driver/PDOCrate/CrateStatement.php | 1 + src/Crate/DBAL/Driver/PDOCrate/Exception.php | 26 ------------------- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 src/Crate/DBAL/Driver/PDOCrate/Exception.php diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index b46a15b..d88e407 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -25,6 +25,7 @@ use Crate\PDO\PDOInterface; use Crate\PDO\PDOStatement; +use Doctrine\DBAL\Driver\PDO\Exception; use Doctrine\DBAL\Driver\Result as ResultInterface; use Doctrine\DBAL\Driver\Statement as StatementInterface; use Doctrine\DBAL\ParameterType; diff --git a/src/Crate/DBAL/Driver/PDOCrate/Exception.php b/src/Crate/DBAL/Driver/PDOCrate/Exception.php deleted file mode 100644 index a29a717..0000000 --- a/src/Crate/DBAL/Driver/PDOCrate/Exception.php +++ /dev/null @@ -1,26 +0,0 @@ -errorInfo !== null) { - [$sqlState, $code] = $exception->errorInfo; - - $code ??= 0; - } else { - $code = $exception->getCode(); - $sqlState = null; - } - - return new self($exception->getMessage(), $sqlState, $code, $exception); - } -} From 05f85d596bbd3c12b97ac2d6fd6944ee40db77c9 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 19 Nov 2025 19:25:26 +0100 Subject: [PATCH 17/29] DBAL3: At `lastInsertId`, catch `PDOException` and wrap into `DBAL` one --- src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 22d03e0..7d9ec7d 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -110,7 +110,11 @@ public function quote($value, $type = ParameterType::STRING): string public function lastInsertId($name = null): string { - return $this->connection->lastInsertId($name); + try { + return $this->connection->lastInsertId($name); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } public function beginTransaction(): void From 24d176700e738e573bf652ed2d1704dfef4b5283 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 19 Nov 2025 19:33:46 +0100 Subject: [PATCH 18/29] DBAL3: Clarify remark about differences of the new DBAL3 Type API --- .../Test/DBAL/Functional/Schema/SchemaManagerTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php index aa89428..8f7fef0 100644 --- a/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php +++ b/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php @@ -75,6 +75,11 @@ public function testListTables() public function createListTableColumns() { + // Note that DBAL3 no longer accepts string constants on its `Column` ctor, + // so use the `Type::getType()` notation instead when defining columns + // using `new Column(...)`. Also note that the `addColumn` method still DOES + // accept type names. + $table = new Table('list_table_columns'); $table->addColumn('text', Types::STRING); $table->addColumn('ts', TimestampType::NAME); @@ -85,8 +90,7 @@ public function createListTableColumns() $table->addColumn('id', 'integer', array('notnull' => true)); $table->setPrimaryKey(array('id')); - // OBJECT schema definition via platform options - // Those intentionally use the `Type::getType()` notation and resolve to DBAL types. + // OBJECT schema definition via platform options. $mapOpts = array( 'type' => MapType::STRICT, 'fields' => array( From b07a4a46756fc28b0ae93ce937cf787387b0ed89 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 19 Nov 2025 19:35:38 +0100 Subject: [PATCH 19/29] DBAL3: Remove comment about `wrapperClass` --- test/Crate/Test/DBAL/Functional/ConnectionTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index b903467..2e9121f 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -44,8 +44,6 @@ public function testBasicAuthConnection() $auth = ['crate', 'secret']; $params = array( 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver', - // TODO: Could work by inheriting. - // 'wrapperClass' => 'Crate\DBAL\Driver\PDOCrate\PDOConnection', 'host' => 'localhost', 'port' => 4200, 'user' => $auth[0], From ee38c2ff842fa7e71a53cb3939ad4a550c2f2972 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 19 Nov 2025 19:51:00 +0100 Subject: [PATCH 20/29] Tests: Adjust skip messages instead of blatantly using `ALTER TABLE` --- test/Crate/Test/DBAL/Platforms/CratePlatformTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index 9426384..d21f938 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -156,7 +156,7 @@ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string */ public function testQuotesAlterTableRenameColumn() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming columns.'); } protected function getQuotedAlterTableRenameColumnSQL() : array {} @@ -166,14 +166,14 @@ protected function getQuotedAlterTableRenameColumnSQL() : array {} */ public function testQuotesAlterTableChangeColumnLength() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support changing column lengths.'); } protected function getQuotedAlterTableChangeColumnLengthSQL() : array {} public function testQuotesAlterTableRenameIndex() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming indexes.'); } /** @@ -181,7 +181,7 @@ public function testQuotesAlterTableRenameIndex() : void */ public function testQuotesAlterTableRenameIndexInSchema() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming indexes.'); } protected function getCommentOnColumnSQL() : array @@ -198,7 +198,7 @@ protected function getCommentOnColumnSQL() : array */ public function testGeneratesAlterTableRenameColumnSQL() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming columns.'); } public function getAlterTableRenameColumnSQL() : array {} @@ -218,7 +218,7 @@ protected function getQuotesTableIdentifiersInAlterTableSQL() : array {} */ public function testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : void { - $this->markTestSkipped('Platform does not support ALTER TABLE.'); + $this->markTestSkipped('Platform does not support renaming indexes.'); } protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array {} From 425f4ee88d814d584f7cf92907bbc3c2ae8b5b10 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 00:40:22 +0100 Subject: [PATCH 21/29] DBAL3: Implement suggestions by CodeRabbit --- .../DBAL/Driver/PDOCrate/CrateStatement.php | 8 ++--- .../DBAL/Driver/PDOCrate/PDOConnection.php | 1 + .../DBAL/Platforms/Keywords/CrateKeywords.php | 2 +- src/Crate/DBAL/Types/TimestampType.php | 2 +- .../Test/DBAL/Platforms/CratePlatformTest.php | 32 +++++++++++-------- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index d88e407..d1c76ce 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -92,23 +92,23 @@ public function rowCount(): int /** * {@inheritDoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING): void + public function bindValue($param, $value, $type = ParameterType::STRING): bool { - $this->stmt->bindValue($param, $value, $type); + return $this->stmt->bindValue($param, $value, $type); } /** * @deprecated Use bindValue() instead. * {@inheritDoc} */ - public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): void { Deprecation::trigger( 'doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5563', 'Statement::bindParam() was deprecated. Please use Statement::bindValue() instead.', ); - return $this->stmt->bindParam($param, $variable, $type, $length); + $this->stmt->bindParam($param, $variable, $type, $length); } /** diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 7d9ec7d..5749e6a 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -45,6 +45,7 @@ class PDOConnection implements ConnectionInterface public function __construct($dsn, $user = null, $password = null, ?array $options = null) { $this->connection = new PDOCrateDB($dsn, $user, $password, $options); + // FIXME: `[PDOStatement::class, []]` might be correct, but fails in `crate-pdo`. $this->connection->setAttribute(PDO::ATTR_STATEMENT_CLASS, PDOStatement::class); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } diff --git a/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php b/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php index c6e9c34..830fbbe 100644 --- a/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php +++ b/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php @@ -27,7 +27,7 @@ class CrateKeywords extends KeywordList { - public function getName() + public function getName(): string { return 'Crate'; } diff --git a/src/Crate/DBAL/Types/TimestampType.php b/src/Crate/DBAL/Types/TimestampType.php index 0ffbe73..eb8c269 100644 --- a/src/Crate/DBAL/Types/TimestampType.php +++ b/src/Crate/DBAL/Types/TimestampType.php @@ -63,7 +63,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform): mixed } $val = new DateTime(); - $val->setTimestamp($value / self::S_TO_MS); + $val->setTimestamp((int) ($value / self::S_TO_MS)); return $val; } diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index d21f938..1a124f6 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -105,7 +105,7 @@ public function getGenerateAlterTableSql() : array public function testAlterTableChangeQuotedColumn() : void { - $this->markTestSkipped('Platform does not support renaming indexes.'); + $this->markTestSkipped('Platform does not support renaming columns.'); } protected function getQuotedColumnInPrimaryKeySQL() : array @@ -356,7 +356,7 @@ public function testUnsupportedUniqueIndexConstraint() $this->expectExceptionMessage("Unique constraints are not supported. Use `primary key` instead"); $table = new Table("foo"); - $table->addColumn("unique_string", "string"); + $table->addColumn("unique_string", Types::STRING); $table->addUniqueIndex(array("unique_string")); $this->platform->getCreateTableSQL($table); } @@ -367,7 +367,7 @@ public function testUniqueConstraintInCustomSchemaOptions() $this->expectExceptionMessage("Unique constraints are not supported. Use `primary key` instead"); $table = new Table("foo"); - $table->addColumn("unique_string", "string")->setCustomSchemaOption("unique", true); + $table->addColumn("unique_string", Types::STRING)->setCustomSchemaOption("unique", true); $this->platform->getCreateTableSQL($table); } @@ -376,7 +376,7 @@ public function testGeneratesTableAlterationSql() : void $expectedSql = $this->getGenerateAlterTableSql(); $tableDiff = new TableDiff('mytable'); - $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), array('notnull' => false)); + $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType(Types::INTEGER), array('notnull' => false)); $sql = $this->platform->getAlterTableSQL($tableDiff); @@ -405,7 +405,7 @@ public function testGetAlterTableSqlDispatchEvent() : void $this->platform->setEventManager($eventManager); $tableDiff = new TableDiff('mytable'); - $tableDiff->addedColumns['added'] = new Column('added', Type::getType('integer'), array()); + $tableDiff->addedColumns['added'] = new Column('added', Type::getType(Types::INTEGER), array()); $this->platform->getAlterTableSQL($tableDiff); } @@ -413,8 +413,8 @@ public function testGetAlterTableSqlDispatchEvent() : void public function testGenerateTableWithMultiColumnUniqueIndex() : void { $table = new Table('test'); - $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255)); - $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255)); + $table->addColumn('foo', Types::STRING, array('notnull' => false, 'length' => 255)); + $table->addColumn('bar', Types::STRING, array('notnull' => false, 'length' => 255)); $table->addUniqueIndex(array("foo", "bar")); $this->expectException(DBALException::class); @@ -426,8 +426,8 @@ public function testGenerateTableWithMultiColumnUniqueIndex() : void public function testGenerateTableWithMultiColumnIndex() { $table = new Table('test'); - $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255)); - $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255)); + $table->addColumn('foo', Types::STRING, array('notnull' => false, 'length' => 255)); + $table->addColumn('bar', Types::STRING, array('notnull' => false, 'length' => 255)); $table->addIndex(array("foo", "bar")); $sql = $this->platform->getCreateTableSQL($table); @@ -565,13 +565,17 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st } }; - if (Type::hasType($type->getName())) { - Type::overrideType($type->getName(), get_class($type)); - } else { - Type::addType($type->getName(), get_class($type)); + $typeName = $type->getName(); + $originalType = Type::getType($typeName); + + Type::overrideType($typeName, get_class($type)); + + try { + self::assertSame($typeName, $this->platform->getDoctrineTypeMapping('ObJecT')); + } finally { + Type::overrideType($typeName, get_class($originalType)); } - self::assertSame($type->getName(), $this->platform->getDoctrineTypeMapping('ObJecT')); } } From 9732bf685c0fe6dd01128b98098e53464d2a3ddf Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 00:41:08 +0100 Subject: [PATCH 22/29] DBAL3: Use CrateDB 5.0.0 in `getServerVersion` to select modern dialect --- src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 5749e6a..7e50693 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -54,7 +54,7 @@ public function getServerVersion(): string { // Unable to detect platform version. // TODO: Need to retrieve and propagate CrateDB server version here? - return "0.0.0"; + return "5.0.0"; } public function getNativeConnection(): PDOCrateDB From b8a9929aa4e7d28453ed212781621265b9de0072 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 00:54:33 +0100 Subject: [PATCH 23/29] DBAL3: Implement suggestions by CodeRabbit --- src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php | 10 +++++++--- src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php index d1c76ce..54c384e 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php +++ b/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php @@ -101,14 +101,14 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool * @deprecated Use bindValue() instead. * {@inheritDoc} */ - public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): void + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool { Deprecation::trigger( 'doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5563', 'Statement::bindParam() was deprecated. Please use Statement::bindValue() instead.', ); - $this->stmt->bindParam($param, $variable, $type, $length); + return $this->stmt->bindParam($param, $variable, $type, $length); } /** @@ -132,7 +132,11 @@ public function fetchColumn($column_number = 0) */ public function closeCursor(): bool { - return $this->stmt->closeCursor(); + try { + return $this->stmt->closeCursor(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } /** diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 7e50693..051ff4f 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -106,7 +106,11 @@ public function query(string $sql): ResultInterface public function quote($value, $type = ParameterType::STRING): string { - return $this->connection->quote($value, $type); + try { + return $this->connection->quote($value, $type); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } public function lastInsertId($name = null): string From 2e7eb41fa388e36775383655f74772cb59b06de4 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 17:04:36 +0100 Subject: [PATCH 24/29] Connection: Make statement class registration more compliant with PDO --- composer.json | 2 +- src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 7b7da2f..fe19918 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "require": { "php": "^8.0|^8.1|^8.2|^8.3|^8.4|^8.5", "doctrine/dbal": "^3", - "crate/crate-pdo": "^2", + "crate/crate-pdo": "^2.2.4", "ext-pdo": "*" }, "autoload": { diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index 051ff4f..e36d93b 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -45,8 +45,7 @@ class PDOConnection implements ConnectionInterface public function __construct($dsn, $user = null, $password = null, ?array $options = null) { $this->connection = new PDOCrateDB($dsn, $user, $password, $options); - // FIXME: `[PDOStatement::class, []]` might be correct, but fails in `crate-pdo`. - $this->connection->setAttribute(PDO::ATTR_STATEMENT_CLASS, PDOStatement::class); + $this->connection->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } From b4b6870906e626a2ac584e3cba17139431c1fd5f Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 16:28:42 +0100 Subject: [PATCH 25/29] Use `TransactionIsolationLevel::READ_UNCOMMITTED` as new default https://www.doctrine-project.org/projects/doctrine-dbal/en/3.10/reference/transactions.html https://github.com/crate/crate/blob/master/server/src/main/java/io/crate/analyze/ShowStatementAnalyzer.java#L69-L85 --- CHANGES.txt | 1 + src/Crate/DBAL/Platforms/CratePlatform.php | 11 +++++++++++ test/Crate/Test/DBAL/Platforms/CratePlatformTest.php | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 99dd0b2..0358210 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,7 @@ Unreleased ========== - Added support for Doctrine DBAL 3, dropped support for Doctrine DBAL 2. +- Made `TransactionIsolationLevel::READ_UNCOMMITTED` the new default. 2025/11/13 4.0.3 ================ diff --git a/src/Crate/DBAL/Platforms/CratePlatform.php b/src/Crate/DBAL/Platforms/CratePlatform.php index 9b32f94..0a6d554 100644 --- a/src/Crate/DBAL/Platforms/CratePlatform.php +++ b/src/Crate/DBAL/Platforms/CratePlatform.php @@ -35,6 +35,7 @@ use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; use InvalidArgumentException; @@ -59,6 +60,16 @@ public function __construct() Type::overrideType('array', 'Crate\DBAL\Types\ArrayType'); } + /** + * {@inheritDoc} + */ + public function getDefaultTransactionIsolationLevel() + { + // CrateDB provides `READ_UNCOMMITTED` isolation levels. + // https://github.com/crate/crate/blob/master/server/src/main/java/io/crate/analyze/ShowStatementAnalyzer.java#L69-L85 + return TransactionIsolationLevel::READ_UNCOMMITTED; + } + /** * {@inheritDoc} */ diff --git a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php index 1a124f6..c3ab7ed 100644 --- a/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php +++ b/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php @@ -35,6 +35,7 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Tests\Platforms\AbstractPlatformTestCase; +use Doctrine\DBAL\TransactionIsolationLevel; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; @@ -75,6 +76,14 @@ public function getGenerateUniqueIndexSql() : string $this->markTestSkipped('Platform does not support CREATE UNIQUE INDEX.'); } + public function testGetDefaultTransactionIsolationLevel() + { + $this->assertEquals( + TransactionIsolationLevel::READ_UNCOMMITTED, + $this->platform->getDefaultTransactionIsolationLevel(), + ); + } + public function testGeneratesForeignKeyCreationSql() : void { $this->markTestSkipped('Platform does not support FOREIGN KEY constraints.'); From d920f6939ef33b678addfe7962b703c9d7d147f3 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 14:28:35 +0100 Subject: [PATCH 26/29] Forward beginTransaction, commit, rollBack to PDO driver --- .../DBAL/Driver/PDOCrate/PDOConnection.php | 21 ++++++++-- .../Test/DBAL/Functional/ConnectionTest.php | 40 ++++++++++++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index e36d93b..e5eb3f7 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -121,15 +121,30 @@ public function lastInsertId($name = null): string } } - public function beginTransaction(): void + public function beginTransaction() { + try { + return $this->connection->beginTransaction(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } - public function commit(): void + public function commit() { + try { + return $this->connection->commit(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } - public function rollBack(): void + public function rollBack() { + try { + return $this->connection->rollBack(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } } diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index 2e9121f..a659856 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -21,12 +21,18 @@ */ namespace Crate\Test\DBAL\Functional; +use Crate\PDO\Exception\UnsupportedException; use Crate\PDO\PDOCrateDB; use Crate\Test\DBAL\DBALFunctionalTest; +use Doctrine\DBAL\ConnectionException; +use Doctrine\DBAL\Driver\Exception; use Doctrine\DBAL\DriverManager; +use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; class ConnectionTest extends DBALFunctionalTest { + use VerifyDeprecations; + public function setUp() : void { $this->resetSharedConn(); @@ -96,5 +102,37 @@ public function testConnect() $this->assertEquals('crate', $row['name']); } -} + public function testBeginTransaction() + { + $this->assertTrue($this->_conn->beginTransaction()); + } + public function testCommitWithBeginTransaction() + { + $this->_conn->beginTransaction(); + $this->assertTrue($this->_conn->commit()); + } + + public function testCommitWithoutBeginTransaction() + { + $this->expectException(ConnectionException::class); + $this->expectExceptionMessage('There is no active transaction.'); + $this->_conn->commit(); + } + + public function testRollbackWithBeginTransaction() + { + $this->_conn->beginTransaction(); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Unsupported functionality'); + $this->_conn->rollBack(); + } + + public function testRollbackWithoutBeginTransaction() + { + $this->expectException(ConnectionException::class); + $this->expectExceptionMessage('There is no active transaction.'); + $this->_conn->rollBack(); + } + +} From 27efef8204f1ea472df60b491e268f29beb30724 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 19:34:05 +0100 Subject: [PATCH 27/29] DBAL3: Implement `getServerVersion()`, forwarding to `PDOCrateDB` --- src/Crate/DBAL/Driver/PDOCrate/Driver.php | 3 ++- .../DBAL/Driver/PDOCrate/PDOConnection.php | 8 +++--- .../Test/DBAL/Functional/ConnectionTest.php | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/Crate/DBAL/Driver/PDOCrate/Driver.php b/src/Crate/DBAL/Driver/PDOCrate/Driver.php index 445e0e8..0c4dddb 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/Driver.php +++ b/src/Crate/DBAL/Driver/PDOCrate/Driver.php @@ -30,9 +30,10 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\VersionAwarePlatformDriver; use SensitiveParameter; -class Driver implements \Doctrine\DBAL\Driver +class Driver implements VersionAwarePlatformDriver { public const VERSION = '4.0.3'; public const NAME = 'crate'; diff --git a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php index e5eb3f7..875aefc 100644 --- a/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php +++ b/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php @@ -51,9 +51,11 @@ public function __construct($dsn, $user = null, $password = null, ?array $option public function getServerVersion(): string { - // Unable to detect platform version. - // TODO: Need to retrieve and propagate CrateDB server version here? - return "5.0.0"; + try { + return $this->connection->getServerVersion(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } public function getNativeConnection(): PDOCrateDB diff --git a/test/Crate/Test/DBAL/Functional/ConnectionTest.php b/test/Crate/Test/DBAL/Functional/ConnectionTest.php index a659856..dd15fcf 100644 --- a/test/Crate/Test/DBAL/Functional/ConnectionTest.php +++ b/test/Crate/Test/DBAL/Functional/ConnectionTest.php @@ -135,4 +135,30 @@ public function testRollbackWithoutBeginTransaction() $this->_conn->rollBack(); } + public function testGetServerVersionNativeConnection() + { + // Retrieve server version. + $serverVersion = $this->_conn->getNativeConnection()->getServerVersion(); + $this->assertNotNull($serverVersion, 'Server version should not be null'); + $this->assertNotEquals('0.0.0', $serverVersion, 'Server version should not be 0.0.0'); + $this->assertMatchesRegularExpression( + '/^\d+\.\d+\.\d+/', + $serverVersion, + 'Server version should follow semantic versioning' + ); + } + + public function testGetServerVersionWrappedConnection() + { + // Retrieve server version. + $serverVersion = $this->_conn->getWrappedConnection()->getServerVersion(); + $this->assertNotNull($serverVersion, 'Server version should not be null'); + $this->assertNotEquals('0.0.0', $serverVersion, 'Server version should not be 0.0.0'); + $this->assertMatchesRegularExpression( + '/^\d+\.\d+\.\d+/', + $serverVersion, + 'Server version should follow semantic versioning' + ); + } + } From cf373708969634cd248a4916028c7eafdace98bb Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 20 Nov 2025 19:35:08 +0100 Subject: [PATCH 28/29] Example: Update procedure how to properly select the platform --- examples/objects.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/objects.php b/examples/objects.php index 4c4f61e..a35d287 100644 --- a/examples/objects.php +++ b/examples/objects.php @@ -16,9 +16,19 @@ use Doctrine\DBAL\Tools\DsnParser; use Doctrine\DBAL\Types\Type; -// Initialize machinery. -// This ensures that the 'map' type is registered in the type system from the beginning. -$platform = new CratePlatform4(); +// Register driver. +$dsnParser = new DsnParser(array('crate' => 'Crate\DBAL\Driver\PDOCrate\Driver')); + +// Compute connection options. +$options = $dsnParser->parse('crate://crate:crate@localhost:4200/'); + +// Select platform. It is highly encouraged to use the platform +// class that matches your database vendor and version best. +// https://www.doctrine-project.org/projects/doctrine-dbal/en/3.10/reference/platforms.html +$options['platform'] = new CratePlatform4(); + +// Connect to database. +$connection = DriverManager::getConnection($options); // Define table schema. $table = new Table('example'); @@ -35,15 +45,8 @@ array('platformOptions' => $objDefinition), ); -// Register driver. -$dsnParser = new DsnParser(array('crate' => 'Crate\DBAL\Driver\PDOCrate\Driver')); - -// Connect to database. -$connectionParams = $dsnParser->parse('crate://crate:crate@localhost:4200/'); -$connection = DriverManager::getConnection($connectionParams); -$schemaManager = $connection->createSchemaManager(); - // Provision database table. +$schemaManager = $connection->createSchemaManager(); try { $schemaManager->dropTable($table->getName()); } catch (TableNotFoundException) { From 171116851500990fcfbf6a0688d987fa4b09e02d Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 21 Nov 2025 19:12:04 +0100 Subject: [PATCH 29/29] Documentation: Educate about CrateDB and eventual consistency vs. ACID --- docs/index.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index c1e7d01..9f15a38 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,6 +11,10 @@ introspection, schema management, and `PDO`_ support. This driver also works with `Doctrine ORM`_, an `Object-Relational Mapper`_. +Note that CrateDB is primarily an analytical database for big data, so it +implements `eventual consistency`_ and does not support traditional ACID +transactions. + .. NOTE:: This is a basic CrateDB driver reference. @@ -38,6 +42,7 @@ This driver also works with `Doctrine ORM`_, an `Object-Relational Mapper`_. .. _DBAL: https://www.doctrine-project.org/projects/dbal.html .. _Doctrine ORM: https://www.doctrine-project.org/projects/orm.html .. _Doctrine ORM documentation: https://www.doctrine-project.org/projects/doctrine-orm/en/3.0/index.html +.. _eventual consistency: https://community.cratedb.com/t/fundamentals-of-eventual-consistency-in-cratedb/1235 .. _hosted on GitHub: https://github.com/crate/crate-dbal .. _Object-Relational Mapper: https://www.doctrine-project.org/projects/orm.html .. _open source: https://en.wikipedia.org/wiki/Open-source_software