From a8663d87380d92d3c069ea3a16faa221b8100a09 Mon Sep 17 00:00:00 2001 From: Benni Mack Date: Mon, 14 Dec 2020 18:07:06 +0100 Subject: [PATCH] [TASK] DBAL: Extend custom drivers from abstract drivers TYPO3 Core has its own implementation of driver classes for database abstraction by effectively overriding e.g. the PDO Statement class with TYPO3's Statment class to ensure that resources are strings to be completely transparent with Database abstraction. Doctrine DBAL 3.0 will force Drivers to either switch to composition or extend from the Abstract Driver classes. This change switches TYPO3's native implementation to extend from Abstract Driver classes, ensuring forward-compatibility with Doctrine DBAL 3.0 for TYPO3 v11 with Drivers. Resolves: #93076 Releases: master Change-Id: I32b886fe13bc7b5c759c1d127b31fe6d3ba94141 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/67115 Tested-by: TYPO3com Tested-by: Oliver Bartsch Tested-by: Georg Ringer Reviewed-by: Oliver Bartsch Reviewed-by: Georg Ringer --- .../Classes/Database/Driver/PDOConnection.php | 2 +- .../Database/Driver/PDOMySql/Driver.php | 47 ++++++++++++++++++- .../Database/Driver/PDOPgSql/Driver.php | 20 ++++++-- .../Database/Driver/PDOSqlite/Driver.php | 43 ++++++++++++++++- .../Database/Driver/PDOSqlsrv/Connection.php | 24 +++++++++- .../Database/Driver/PDOSqlsrv/Driver.php | 31 ++++++++---- 6 files changed, 148 insertions(+), 19 deletions(-) diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOConnection.php b/typo3/sysext/core/Classes/Database/Driver/PDOConnection.php index 6d0b3a2d200e..aee45f6ace5c 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOConnection.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOConnection.php @@ -17,8 +17,8 @@ namespace TYPO3\CMS\Core\Database\Driver; +use Doctrine\DBAL\Driver\PDO\Connection as DoctrineDbalPDOConnection; use Doctrine\DBAL\Driver\PDO\Exception as PDOException; -use Doctrine\DBAL\Driver\PDOConnection as DoctrineDbalPDOConnection; use PDO; /** diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOMySql/Driver.php b/typo3/sysext/core/Classes/Database/Driver/PDOMySql/Driver.php index 0b4e56ffcbd0..c9d6edca6c69 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOMySql/Driver.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOMySql/Driver.php @@ -17,7 +17,7 @@ namespace TYPO3\CMS\Core\Database\Driver\PDOMySql; -use Doctrine\DBAL\Driver\PDOMySql\Driver as DoctrinePDOMySqlDriver; +use Doctrine\DBAL\Driver\AbstractMySQLDriver; use Doctrine\DBAL\Exception as DBALException; use PDOException; use TYPO3\CMS\Core\Database\Driver\PDOConnection; @@ -26,7 +26,7 @@ * This is a full "clone" of the class of package doctrine/dbal. Scope is to use the PDOConnection of TYPO3. * All private methods have to be checked on every release of doctrine/dbal. */ -class Driver extends DoctrinePDOMySqlDriver +class Driver extends AbstractMySQLDriver { /** * {@inheritdoc} @@ -51,4 +51,47 @@ public function connect(array $params, $username = null, $password = null, array return $conn; } + + /** + * Constructs the MySql PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + protected function constructPdoDsn(array $params) + { + $dsn = 'mysql:'; + if (isset($params['host']) && $params['host'] !== '') { + $dsn .= 'host=' . $params['host'] . ';'; + } + + if (isset($params['port'])) { + $dsn .= 'port=' . $params['port'] . ';'; + } + + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ';'; + } + + if (isset($params['unix_socket'])) { + $dsn .= 'unix_socket=' . $params['unix_socket'] . ';'; + } + + if (isset($params['charset'])) { + $dsn .= 'charset=' . $params['charset'] . ';'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + return 'pdo_mysql'; + } } diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOPgSql/Driver.php b/typo3/sysext/core/Classes/Database/Driver/PDOPgSql/Driver.php index 06dfecbff716..4a6e19c6f836 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOPgSql/Driver.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOPgSql/Driver.php @@ -17,7 +17,7 @@ namespace TYPO3\CMS\Core\Database\Driver\PDOPgSql; -use Doctrine\DBAL\Driver\PDOPgSql\Driver as DoctrineDbalPDOPgSqlDriver; +use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver; use Doctrine\DBAL\Exception as DBALException; use PDO; use PDOException; @@ -27,7 +27,7 @@ * This is a full "clone" of the class of package doctrine/dbal. Scope is to use the PDOConnection of TYPO3. * All private methods have to be checked on every release of doctrine/dbal. */ -class Driver extends DoctrineDbalPDOPgSqlDriver +class Driver extends AbstractPostgreSQLDriver { /** * {@inheritdoc} @@ -66,7 +66,11 @@ public function connect(array $params, $username = null, $password = null, array } /** - * {@inheritdoc} + * Constructs the Postgres PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. */ private function _constructPdoDsn(array $params) { @@ -117,4 +121,14 @@ private function _constructPdoDsn(array $params) return $dsn; } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + return 'pdo_pgsql'; + } } diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOSqlite/Driver.php b/typo3/sysext/core/Classes/Database/Driver/PDOSqlite/Driver.php index 660d10e8c9f7..12f6593fc2f4 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOSqlite/Driver.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOSqlite/Driver.php @@ -17,8 +17,9 @@ namespace TYPO3\CMS\Core\Database\Driver\PDOSqlite; -use Doctrine\DBAL\Driver\PDOSqlite\Driver as DoctrinePDOSqliteDriver; +use Doctrine\DBAL\Driver\AbstractSQLiteDriver; use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Platforms\SqlitePlatform; use PDOException; use TYPO3\CMS\Core\Database\Driver\PDOConnection; @@ -26,8 +27,17 @@ * This is a full "clone" of the class of package doctrine/dbal. Scope is to use the PDOConnection of TYPO3. * All private methods have to be checked on every release of doctrine/dbal. */ -class Driver extends DoctrinePDOSqliteDriver +class Driver extends AbstractSQLiteDriver { + /** + * @var mixed[] + */ + protected $_userDefinedFunctions = [ + 'sqrt' => ['callback' => [SqlitePlatform::class, 'udfSqrt'], 'numArgs' => 1], + 'mod' => ['callback' => [SqlitePlatform::class, 'udfMod'], 'numArgs' => 2], + 'locate' => ['callback' => [SqlitePlatform::class, 'udfLocate'], 'numArgs' => -1], + ]; + /** * {@inheritdoc} */ @@ -58,4 +68,33 @@ public function connect(array $params, $username = null, $password = null, array return $pdo; } + + /** + * Constructs the Sqlite PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + protected function _constructPdoDsn(array $params) + { + $dsn = 'sqlite:'; + if (isset($params['path'])) { + $dsn .= $params['path']; + } elseif (isset($params['memory'])) { + $dsn .= ':memory:'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + return 'pdo_sqlite'; + } } diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Connection.php b/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Connection.php index 84527fbd30ac..61c674cdb019 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Connection.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Connection.php @@ -17,15 +17,18 @@ namespace TYPO3\CMS\Core\Database\Driver\PDOSqlsrv; +use Doctrine\DBAL\Driver\Result; use PDO; /** * This is a full "clone" of the class of package doctrine/dbal. Scope is to use the PDOConnection of TYPO3. * All private methods have to be checked on every release of doctrine/dbal. */ -class Connection extends \Doctrine\DBAL\Driver\PDOSqlsrv\Connection +class Connection extends \Doctrine\DBAL\Driver\PDO\Connection { /** + * @internal The connection can be only instantiated by its driver. + * * {@inheritdoc} */ public function __construct($dsn, $user = null, $password = null, ?array $options = null) @@ -33,4 +36,23 @@ public function __construct($dsn, $user = null, $password = null, ?array $option parent::__construct($dsn, $user, $password, $options); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]); } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + if ($name === null) { + return parent::lastInsertId($name); + } + + $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); + $stmt->execute([$name]); + + if ($stmt instanceof Result) { + return $stmt->fetchOne(); + } + + return $stmt->fetchColumn(); + } } diff --git a/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Driver.php b/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Driver.php index ba1ae1c63edb..4e2220a885db 100644 --- a/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Driver.php +++ b/typo3/sysext/core/Classes/Database/Driver/PDOSqlsrv/Driver.php @@ -17,11 +17,14 @@ namespace TYPO3\CMS\Core\Database\Driver\PDOSqlsrv; +use Doctrine\DBAL\Driver\AbstractSQLServerDriver; +use Doctrine\DBAL\Driver\AbstractSQLServerDriver\Exception\PortWithoutHost; + /** * This is a full "clone" of the class of package doctrine/dbal. Scope is to use the PDOConnection of TYPO3. * All private methods have to be checked on every release of doctrine/dbal. */ -class Driver extends \Doctrine\DBAL\Driver\PDOSqlsrv\Driver +class Driver extends AbstractSQLServerDriver { /** * {@inheritdoc} @@ -39,7 +42,12 @@ public function connect(array $params, $username = null, $password = null, array } /** - * {@inheritdoc} + * Constructs the Sqlsrv PDO DSN. + * + * @param mixed[] $params + * @param string[] $connectionOptions + * + * @return string The DSN. */ private function _constructPdoDsn(array $params, array $connectionOptions) { @@ -47,10 +55,12 @@ private function _constructPdoDsn(array $params, array $connectionOptions) if (isset($params['host'])) { $dsn .= $params['host']; - } - if (isset($params['port']) && ! empty($params['port'])) { - $dsn .= ',' . $params['port']; + if (isset($params['port'])) { + $dsn .= ',' . $params['port']; + } + } elseif (isset($params['port'])) { + throw PortWithoutHost::new(); } if (isset($params['dbname'])) { @@ -64,9 +74,6 @@ private function _constructPdoDsn(array $params, array $connectionOptions) return $dsn . $this->getConnectionOptionsDsn($connectionOptions); } - /** - * {@inheritdoc} - */ private function splitOptions(array $options): array { $driverOptions = []; @@ -84,7 +91,9 @@ private function splitOptions(array $options): array } /** - * {@inheritdoc} + * Converts a connection options array to the DSN + * + * @param string[] $connectionOptions */ private function getConnectionOptionsDsn(array $connectionOptions): string { @@ -99,9 +108,11 @@ private function getConnectionOptionsDsn(array $connectionOptions): string /** * {@inheritdoc} + * + * @deprecated */ public function getName() { - return parent::getName(); + return 'pdo_sqlsrv'; } }