From 1e7fc2649f7e21f8bafb66109f8d275833951876 Mon Sep 17 00:00:00 2001 From: Jan Skrasek Date: Sun, 15 Oct 2023 15:58:38 +0200 Subject: [PATCH] fix sequence casing escaping & add support for FQN for last inserted id (BC break!) --- src/Connection.php | 3 ++- src/Drivers/IDriver.php | 3 ++- src/Drivers/Mysqli/MysqliDriver.php | 3 ++- src/Drivers/Pdo/PdoDriver.php | 3 ++- src/Drivers/PdoMysql/PdoMysqlDriver.php | 3 ++- src/Drivers/PdoPgsql/PdoPgsqlDriver.php | 11 +++++++++-- src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php | 3 ++- src/Drivers/Pgsql/PgsqlDriver.php | 11 +++++++++-- src/Drivers/Sqlsrv/SqlsrvDriver.php | 3 ++- src/IConnection.php | 3 ++- tests/cases/integration/connection.postgres.phpt | 14 ++++++++++++-- 11 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/Connection.php b/src/Connection.php index deac2e7d..547cfbbb 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -6,6 +6,7 @@ use Exception; use Nextras\Dbal\Drivers\IDriver; use Nextras\Dbal\Exception\InvalidArgumentException; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\QueryBuilder\QueryBuilder; use Nextras\Dbal\Result\Result; @@ -144,7 +145,7 @@ public function queryByQueryBuilder(QueryBuilder $queryBuilder): Result /** @inheritdoc */ - public function getLastInsertedId(?string $sequenceName = null) + public function getLastInsertedId(string|Fqn|null $sequenceName = null) { if (!$this->connected) { $this->connect(); diff --git a/src/Drivers/IDriver.php b/src/Drivers/IDriver.php index 2bcc7ff0..0dd179b4 100644 --- a/src/Drivers/IDriver.php +++ b/src/Drivers/IDriver.php @@ -8,6 +8,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Result\Result; @@ -64,7 +65,7 @@ public function query(string $query): Result; * Returns the last inserted id. * @internal */ - public function getLastInsertedId(?string $sequenceName = null): mixed; + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed; /** diff --git a/src/Drivers/Mysqli/MysqliDriver.php b/src/Drivers/Mysqli/MysqliDriver.php index 1d9a0ec0..56cc66d3 100644 --- a/src/Drivers/Mysqli/MysqliDriver.php +++ b/src/Drivers/Mysqli/MysqliDriver.php @@ -17,6 +17,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\MySqlPlatform; use Nextras\Dbal\Result\Result; @@ -159,7 +160,7 @@ public function query(string $query): Result } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { $this->checkConnection(); assert($this->connection !== null); diff --git a/src/Drivers/Pdo/PdoDriver.php b/src/Drivers/Pdo/PdoDriver.php index 06f6b523..18566628 100644 --- a/src/Drivers/Pdo/PdoDriver.php +++ b/src/Drivers/Pdo/PdoDriver.php @@ -9,6 +9,7 @@ use Nextras\Dbal\Drivers\IDriver; use Nextras\Dbal\Exception\InvalidStateException; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Result\IResultAdapter; use Nextras\Dbal\Result\Result; use Nextras\Dbal\Utils\LoggerHelper; @@ -108,7 +109,7 @@ public function query(string $query): Result } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { $this->checkConnection(); assert($this->connection !== null); diff --git a/src/Drivers/PdoMysql/PdoMysqlDriver.php b/src/Drivers/PdoMysql/PdoMysqlDriver.php index cde1e7c5..138d29e3 100644 --- a/src/Drivers/PdoMysql/PdoMysqlDriver.php +++ b/src/Drivers/PdoMysql/PdoMysqlDriver.php @@ -17,6 +17,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\MySqlPlatform; use Nextras\Dbal\Result\IResultAdapter; @@ -100,7 +101,7 @@ public function createPlatform(IConnection $connection): IPlatform } - public function getLastInsertedId(?string $sequenceName = null): int + public function getLastInsertedId(string|Fqn|null $sequenceName = null): int { return (int) parent::getLastInsertedId($sequenceName); } diff --git a/src/Drivers/PdoPgsql/PdoPgsqlDriver.php b/src/Drivers/PdoPgsql/PdoPgsqlDriver.php index afc7738c..48922f51 100644 --- a/src/Drivers/PdoPgsql/PdoPgsqlDriver.php +++ b/src/Drivers/PdoPgsql/PdoPgsqlDriver.php @@ -17,6 +17,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\PostgreSqlPlatform; use Nextras\Dbal\Result\IResultAdapter; @@ -72,7 +73,7 @@ public function createPlatform(IConnection $connection): IPlatform } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { if ($sequenceName === null) { throw new InvalidArgumentException('PgsqlDriver requires to pass sequence name for getLastInsertedId() method.'); @@ -80,7 +81,13 @@ public function getLastInsertedId(?string $sequenceName = null): mixed $this->checkConnection(); assert($this->connection !== null); - $sql = 'SELECT CURRVAL(' . $this->convertStringToSql($sequenceName) . ')'; + + $sequenceName = match (true) { + $sequenceName instanceOf Fqn => $this->convertIdentifierToSql($sequenceName->schema) . '.' . + $this->convertIdentifierToSql($sequenceName->name), + default => $this->convertIdentifierToSql($sequenceName), + }; + $sql = 'SELECT CURRVAL(\'' . $sequenceName . '\')'; return $this->loggedQuery($sql)->fetchField(); } diff --git a/src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php b/src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php index a44d036e..672e809a 100644 --- a/src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php +++ b/src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php @@ -14,6 +14,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\SqlServerPlatform; use Nextras\Dbal\Result\IResultAdapter; @@ -94,7 +95,7 @@ public function createPlatform(IConnection $connection): IPlatform } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { $this->checkConnection(); return $this->loggedQuery('SELECT SCOPE_IDENTITY()')->fetchField(); diff --git a/src/Drivers/Pgsql/PgsqlDriver.php b/src/Drivers/Pgsql/PgsqlDriver.php index 04b1c3e2..595529f4 100644 --- a/src/Drivers/Pgsql/PgsqlDriver.php +++ b/src/Drivers/Pgsql/PgsqlDriver.php @@ -17,6 +17,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\PostgreSqlPlatform; use Nextras\Dbal\Result\Result; @@ -178,14 +179,20 @@ public function query(string $query): Result } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { if ($sequenceName === null) { throw new InvalidArgumentException('PgsqlDriver requires to pass sequence name for getLastInsertedId() method.'); } $this->checkConnection(); assert($this->connection !== null); - $sql = 'SELECT CURRVAL(' . pg_escape_literal($this->connection, $sequenceName) . ')'; + + $sequenceName = match (true) { + $sequenceName instanceOf Fqn => pg_escape_identifier($this->connection, $sequenceName->schema) . '.' . + pg_escape_identifier($this->connection, $sequenceName->name), + default => pg_escape_identifier($this->connection, $sequenceName), + }; + $sql = 'SELECT CURRVAL(\'' . $sequenceName . '\')'; return $this->loggedQuery($sql)->fetchField(); } diff --git a/src/Drivers/Sqlsrv/SqlsrvDriver.php b/src/Drivers/Sqlsrv/SqlsrvDriver.php index 064f8a1b..7d6fba52 100644 --- a/src/Drivers/Sqlsrv/SqlsrvDriver.php +++ b/src/Drivers/Sqlsrv/SqlsrvDriver.php @@ -17,6 +17,7 @@ use Nextras\Dbal\Exception\NotSupportedException; use Nextras\Dbal\IConnection; use Nextras\Dbal\ILogger; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\Platforms\SqlServerPlatform; use Nextras\Dbal\Result\Result; @@ -183,7 +184,7 @@ public function query(string $query): Result } - public function getLastInsertedId(?string $sequenceName = null): mixed + public function getLastInsertedId(string|Fqn|null $sequenceName = null): mixed { $this->checkConnection(); return $this->loggedQuery('SELECT SCOPE_IDENTITY()')->fetchField(); diff --git a/src/IConnection.php b/src/IConnection.php index fb7241b4..889ab77d 100644 --- a/src/IConnection.php +++ b/src/IConnection.php @@ -7,6 +7,7 @@ use Nextras\Dbal\Drivers\Exception\DriverException; use Nextras\Dbal\Drivers\Exception\QueryException; use Nextras\Dbal\Drivers\IDriver; +use Nextras\Dbal\Platforms\Data\Fqn; use Nextras\Dbal\Platforms\IPlatform; use Nextras\Dbal\QueryBuilder\QueryBuilder; use Nextras\Dbal\Result\Result; @@ -88,7 +89,7 @@ public function queryByQueryBuilder(QueryBuilder $queryBuilder): Result; * Returns last inserted ID. * @return int|string|null */ - public function getLastInsertedId(?string $sequenceName = null); + public function getLastInsertedId(string|Fqn|null $sequenceName = null); /** diff --git a/tests/cases/integration/connection.postgres.phpt b/tests/cases/integration/connection.postgres.phpt index 8794a5d9..e97ec9c0 100644 --- a/tests/cases/integration/connection.postgres.phpt +++ b/tests/cases/integration/connection.postgres.phpt @@ -9,6 +9,7 @@ namespace NextrasTests\Dbal; use Nextras\Dbal\Exception\InvalidArgumentException; +use Nextras\Dbal\Platforms\Data\Fqn; use Tester\Assert; @@ -32,12 +33,21 @@ class ConnectionPostgresTest extends IntegrationTestCase $this->connection->query('INSERT INTO publishers %values', ['name' => 'FOO']); Assert::same(2, $this->connection->getLastInsertedId('publishers_id_seq')); - Assert::same(2, $this->connection->getLastInsertedId('public.publishers_id_seq')); + Assert::same(2, $this->connection->getLastInsertedId(new Fqn(name: 'publishers_id_seq', schema: 'public'))); - Assert::exception(function () { + Assert::exception(function() { $this->connection->getLastInsertedId(); }, InvalidArgumentException::class, 'PgsqlDriver requires to pass sequence name for getLastInsertedId() method.'); } + + + public function testSequenceCasing() + { + $this->lockConnection($this->connection); + $this->connection->query('CREATE SEQUENCE %column INCREMENT 5 START 10;', "MySequence"); + $this->connection->query('SELECT NEXTVAL(\'%column\')', "MySequence"); + Assert::same(10, $this->connection->getLastInsertedId("MySequence")); + } }