Skip to content

Commit

Permalink
Merge pull request #221 from nextras/sequence-casing
Browse files Browse the repository at this point in the history
Fix sequence casing escaping & add support for FQN for last inserted id (BC break!)
  • Loading branch information
hrach authored Oct 15, 2023
2 parents 0718360 + 5475de2 commit 510e6b7
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 52 deletions.
3 changes: 2 additions & 1 deletion src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 5 additions & 4 deletions src/Drivers/IDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;


/**
Expand Down Expand Up @@ -135,23 +136,23 @@ public function rollbackTransaction(): void;
* @throws DriverException
* @internal
*/
public function createSavepoint(string $name): void;
public function createSavepoint(string|Fqn $name): void;


/**
* Releases the savepoint.
* @throws DriverException
* @internal
*/
public function releaseSavepoint(string $name): void;
public function releaseSavepoint(string|Fqn $name): void;


/**
* Rollbacks the savepoint.
* @throws DriverException
* @internal
*/
public function rollbackSavepoint(string $name): void;
public function rollbackSavepoint(string|Fqn $name): void;


/**
Expand Down
35 changes: 22 additions & 13 deletions src/Drivers/Mysqli/MysqliDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -95,7 +96,7 @@ public function connect(array $params, ILogger $logger): void
throw $this->createException(
$this->connection->connect_error ?? $this->connection->error, // @phpstan-ignore-line
$this->connection->connect_errno,
'HY000'
'HY000',
);
}

Expand Down Expand Up @@ -147,7 +148,7 @@ public function query(string $query): Result
$this->connection->error,
$this->connection->errno,
$this->connection->sqlstate,
$query
$query,
);
}

Expand All @@ -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);
Expand Down Expand Up @@ -249,27 +250,24 @@ public function rollbackTransaction(): void
}


public function createSavepoint(string $name): void
public function createSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = str_replace(['`', '.'], ['``', '`.`'], $name);
$this->loggedQuery("SAVEPOINT $identifier");
$this->loggedQuery('SAVEPOINT ' . $this->convertIdentifierToSql($name));
}


public function releaseSavepoint(string $name): void
public function releaseSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = str_replace(['`', '.'], ['``', '`.`'], $name);
$this->loggedQuery("RELEASE SAVEPOINT $identifier");
$this->loggedQuery('RELEASE SAVEPOINT ' . $this->convertIdentifierToSql($name));
}


public function rollbackSavepoint(string $name): void
public function rollbackSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = str_replace(['`', '.'], ['``', '`.`'], $name);
$this->loggedQuery("ROLLBACK TO SAVEPOINT $identifier");
$this->loggedQuery('ROLLBACK TO SAVEPOINT ' . $this->convertIdentifierToSql($name));
}


Expand All @@ -296,7 +294,7 @@ protected function setupSsl(array $params): void
$params['sslCert'] ?? '',
$params['sslCa'] ?? '',
$params['sslCapath'] ?? '',
$params['sslCipher'] ?? ''
$params['sslCipher'] ?? '',
);
}

Expand Down Expand Up @@ -345,6 +343,17 @@ public function convertStringToSql(string $value): string
}


protected function convertIdentifierToSql(string|Fqn $identifier): string
{
$escaped = match (true) {
$identifier instanceof Fqn => str_replace('`', '``', $identifier->schema) . '.'
. str_replace('`', '``', $identifier->name),
default => str_replace('`', '``', $identifier),
};
return '`' . $escaped . '`';
}


/**
* This method is based on Doctrine\DBAL project.
* @link www.doctrine-project.org
Expand Down
11 changes: 6 additions & 5 deletions src/Drivers/Pdo/PdoDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -207,23 +208,23 @@ public function rollbackTransaction(): void
}


public function createSavepoint(string $name): void
public function createSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = $this->convertIdentifierToSql($name);
$this->loggedQuery("SAVEPOINT $identifier");
}


public function releaseSavepoint(string $name): void
public function releaseSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = $this->convertIdentifierToSql($name);
$this->loggedQuery("RELEASE SAVEPOINT $identifier");
}


public function rollbackSavepoint(string $name): void
public function rollbackSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$identifier = $this->convertIdentifierToSql($name);
Expand All @@ -245,7 +246,7 @@ public function convertStringToSql(string $value): string
abstract protected function createResultAdapter(PDOStatement $statement): IResultAdapter;


abstract protected function convertIdentifierToSql(string $identifier): string;
abstract protected function convertIdentifierToSql(string|Fqn $identifier): string;


abstract protected function createException(
Expand Down
11 changes: 8 additions & 3 deletions src/Drivers/PdoMysql/PdoMysqlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -128,9 +129,13 @@ protected function createResultAdapter(PDOStatement $statement): IResultAdapter
}


protected function convertIdentifierToSql(string $identifier): string
protected function convertIdentifierToSql(string|Fqn $identifier): string
{
return str_replace(['`', '.'], ['``', '`.`'], $identifier);
return match (true) {
$identifier instanceof Fqn => str_replace('`', '``', $identifier->schema) . '.'
. str_replace('`', '``', $identifier->name),
default => str_replace('`', '``', $identifier),
};
}


Expand Down
20 changes: 16 additions & 4 deletions src/Drivers/PdoPgsql/PdoPgsqlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,15 +73,21 @@ 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.');
}

$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();
}

Expand Down Expand Up @@ -108,9 +115,14 @@ protected function createResultAdapter(PDOStatement $statement): IResultAdapter
}


protected function convertIdentifierToSql(string $identifier): string
protected function convertIdentifierToSql(string|Fqn $identifier): string
{
return '"' . str_replace(['"', '.'], ['""', '"."'], $identifier) . '"';
$escaped = match (true) {
$identifier instanceof Fqn => str_replace('"', '""', $identifier->schema) . '.'
. str_replace('"', '""', $identifier->name),
default => str_replace('"', '""', $identifier),
};
return '"' . $escaped . '"';
}


Expand Down
18 changes: 12 additions & 6 deletions src/Drivers/PdoSqlsrv/PdoSqlsrvDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -117,21 +118,21 @@ public function setTransactionIsolationLevel(int $level): void
}


public function createSavepoint(string $name): void
public function createSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$this->loggedQuery('SAVE TRANSACTION ' . $this->convertIdentifierToSql($name));
}


public function releaseSavepoint(string $name): void
public function releaseSavepoint(string|Fqn $name): void
{
// transaction are released automatically
// http://stackoverflow.com/questions/3101312/sql-server-2008-no-release-savepoint-for-current-transaction
}


public function rollbackSavepoint(string $name): void
public function rollbackSavepoint(string|Fqn $name): void
{
$this->checkConnection();
$this->loggedQuery('ROLLBACK TRANSACTION ' . $this->convertIdentifierToSql($name));
Expand All @@ -145,9 +146,14 @@ protected function createResultAdapter(PDOStatement $statement): IResultAdapter
}


protected function convertIdentifierToSql(string $identifier): string
protected function convertIdentifierToSql(string|Fqn $identifier): string
{
return '[' . str_replace([']', '.'], [']]', '].['], $identifier) . ']';
$escaped = match (true) {
$identifier instanceof Fqn => str_replace(']', ']]', $identifier->schema) . '.'
. str_replace(']', ']]', $identifier->name),
default => str_replace(']', ']]', $identifier),
};
return '[' . $escaped . ']';
}


Expand Down
Loading

0 comments on commit 510e6b7

Please sign in to comment.