diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index d9b40e923c9..8877b92bc1d 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -62,7 +62,8 @@ public function prepare(string $sql) : Statement { try { return $this->createStatement( - $this->connection->prepare($sql) + $this->connection->prepare($sql), + $sql ); } catch (\PDOException $exception) { throw new PDOException($exception); @@ -78,7 +79,7 @@ public function query(string $sql) : ResultStatement $stmt = $this->connection->query($sql); assert($stmt instanceof \PDOStatement); - return $this->createStatement($stmt); + return $this->createStatement($stmt, $sql); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -119,7 +120,7 @@ public function requiresQueryForServerVersion() /** * Creates a wrapped statement */ - protected function createStatement(\PDOStatement $stmt) : PDOStatement + protected function createStatement(\PDOStatement $stmt, string $sql) : PDOStatement { return new PDOStatement($stmt); } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php new file mode 100644 index 00000000000..977cf8125ca --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -0,0 +1,102 @@ +lastInsertId && $this->lastInsertId->getId()) { + return $this->lastInsertId->getId(); + } + + if ($name === null) { + return parent::lastInsertId(); + } + + $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); + $stmt->execute([$name]); + + return (string) $stmt->fetchColumn(); + } + + /** + * {@inheritDoc} + */ + public function quote(string $input) : string + { + $val = parent::quote($input); + + // Fix for a driver version terminating all values with null byte + if (strpos($val, "\0") !== false) { + $val = substr($val, 0, -1); + } + + return $val; + } + + /** + * {@inheritdoc} + */ + public function prepare(string $sql) : Statement + { + return parent::prepare($this->prepareSql($sql)); + } + + /** + * {@inheritdoc} + */ + public function query(string $sql) : ResultStatement + { + return parent::query($this->prepareSql($sql)); + } + + /** + * {@inheritDoc} + */ + protected function createStatement(\PDOStatement $stmt, string $sql) : PDOStatement + { + $this->lastInsertId = static::isInsertStatement($sql) ? new LastInsertId() : null; + + return new PDOSqlSrvStatement($stmt, $this->lastInsertId); + } + + protected function prepareSql(string $sql) : string + { + if (static::isInsertStatement($sql)) { + $sql .= self::LAST_INSERT_ID_SQL; + } + + return $sql; + } + + protected static function isInsertStatement(string $sql) : bool + { + return stripos($sql, 'INSERT INTO ') === 0; + } +} diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php index eb7e5f11d12..3b1b90345c4 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -33,7 +33,7 @@ public function connect(array $params, $username = null, $password = null, array $pdoOptions[PDO::ATTR_PERSISTENT] = true; } - return new PDOSqlsrvConnection( + return new Connection( $this->_constructPdoDsn($params, $dsnOptions), $username, $password, diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvConnection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvConnection.php deleted file mode 100644 index 21bf5f72f8b..00000000000 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvConnection.php +++ /dev/null @@ -1,146 +0,0 @@ -conn = new PDOConnection($dsn, $user, $password, $options); - $this->lastInsertId = new LastInsertId(); - } - - /** - * {@inheritDoc} - */ - public function prepare($sql) : Statement - { - $this->lastInsertId = new LastInsertId(); - - try { - return new PDOSqlsrvStatement($this->conn, $sql, $this->lastInsertId); - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - } - - /** - * {@inheritDoc} - */ - public function query(string $sql) : ResultStatement - { - try { - $stmt = $this->prepare($sql); - $stmt->execute(); - - return $stmt; - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - } - - /** - * {@inheritDoc} - */ - public function exec($statement) : int - { - return $this->conn->exec($statement); - } - - /** - * {@inheritDoc} - */ - public function quote(string $input) : string - { - $val = $this->conn->quote($input); - - // Fix for a driver version terminating all values with null byte - if (strpos($val, "\0") !== false) { - $val = substr($val, 0, -1); - } - - return $val; - } - - /** - * {@inheritDoc} - */ - public function lastInsertId($name = null) - { - if ($this->lastInsertId->getId()) { - return $this->lastInsertId->getId(); - } - - if ($name === null) { - return $this->conn->lastInsertId(); - } - - $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); - $stmt->execute([$name]); - - return (string) $stmt->fetchColumn(); - } - - /** - * {@inheritDoc} - */ - public function beginTransaction() : void - { - $this->conn->beginTransaction(); - } - - /** - * {@inheritDoc} - */ - public function commit() : void - { - $this->conn->commit(); - } - - /** - * {@inheritDoc} - */ - public function rollBack() : void - { - $this->conn->rollBack(); - } - - /** - * {@inheritdoc} - */ - public function getServerVersion() - { - return $this->conn->getServerVersion(); - } - - /** - * {@inheritdoc} - */ - public function requiresQueryForServerVersion() - { - return $this->conn->requiresQueryForServerVersion(); - } -} diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvStatement.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvStatement.php deleted file mode 100644 index e2d7d1bc7f8..00000000000 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/PDOSqlsrvStatement.php +++ /dev/null @@ -1,208 +0,0 @@ -conn = $conn; - $this->sql = $sql; - - if (stripos($sql, 'INSERT INTO ') === 0) { - $this->sql .= self::LAST_INSERT_ID_SQL; - $this->lastInsertId = $lastInsertId; - } - - $this->stmt = $this->prepare(); - } - - /** - * {@inheritdoc} - */ - public function bindValue($param, $value, $type = ParameterType::STRING) : void - { - $this->bindParam($param, $value, $type); - } - - /** - * {@inheritdoc} - */ - public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void - { - $driverOptions = null; - - if ($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY) { - $driverOptions = PDO::SQLSRV_ENCODING_BINARY; - } - - $this->stmt->bindParam($param, $variable, $type, $length, $driverOptions); - } - - /** - * {@inheritdoc} - */ - public function closeCursor() : void - { - $this->stmt->closeCursor(); - } - - /** - * {@inheritdoc} - */ - public function columnCount() : int - { - return $this->stmt->columnCount(); - } - - /** - * {@inheritdoc} - */ - public function execute(?array $params = null) : void - { - $this->stmt->execute($params); - $this->rowCount = $this->rowCount(); - - if (! $this->lastInsertId) { - return; - } - - $id = null; - $this->stmt->nextRowset(); - - if ($this->columnCount() > 0) { - $id = $this->fetchColumn(); - } - - if (! $id) { - while ($this->stmt->nextRowset()) { - if ($this->columnCount() === 0) { - continue; - } - - $id = $this->fetchColumn(); - } - } - - $this->lastInsertId->setId($id); - } - - /** - * Prepares PDO statement resource - * - * @return PDOStatement - */ - private function prepare() - { - /** @var PDOStatement $stmt */ - $stmt = $this->conn->prepare($this->sql); - - return $stmt; - } - - /** - * {@inheritdoc} - */ - public function setFetchMode($fetchMode, ...$args) : void - { - $this->stmt->setFetchMode($fetchMode, ...$args); - } - - /** - * {@inheritdoc} - */ - public function getIterator() - { - yield from $this->stmt; - } - - /** - * {@inheritdoc} - */ - public function fetch(?int $fetchMode = null, ...$args) - { - return $this->stmt->fetch($fetchMode, ...$args); - } - - /** - * {@inheritdoc} - */ - public function fetchAll(?int $fetchMode = null, ...$args) : array - { - return $this->stmt->fetchAll($fetchMode, ...$args); - } - - /** - * {@inheritdoc} - */ - public function fetchColumn($columnIndex = 0) - { - return $this->stmt->fetchColumn($columnIndex); - } - - /** - * {@inheritdoc} - */ - public function rowCount() : int - { - return $this->rowCount ?: $this->stmt->rowCount(); - } - - public function nextRowset() : bool - { - return $this->stmt->nextRowset(); - } -} diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php new file mode 100644 index 00000000000..56af63c4f77 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php @@ -0,0 +1,97 @@ +lastInsertId = $lastInsertId; + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null) : void + { + if (($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY) + && $driverOptions === null + ) { + $driverOptions = PDO::SQLSRV_ENCODING_BINARY; + } + + parent::bindParam($param, $variable, $type, $length, $driverOptions); + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, int $type = ParameterType::STRING) : void + { + $this->bindParam($param, $value, $type); + } + + /** + * {@inheritdoc} + */ + public function execute(?array $params = null) : void + { + parent::execute($params); + $this->rowCount = $this->rowCount(); + + if (! $this->lastInsertId) { + return; + } + + $id = null; + $this->nextRowset(); + + if ($this->columnCount() > 0) { + $id = $this->fetchColumn(); + } + + if (! $id) { + while ($this->nextRowset()) { + if ($this->columnCount() === 0) { + continue; + } + + $id = $this->fetchColumn(); + } + } + + $this->lastInsertId->setId($id); + } + + /** + * {@inheritdoc} + */ + public function rowCount() : int + { + return $this->rowCount ?: parent::rowCount(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php index 4e2a36d3de4..93bbaad9ef8 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php @@ -12,7 +12,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Platforms\SQLServerPlatform; -use Doctrine\DBAL\Schema\Table; use Doctrine\Tests\DbalFunctionalTestCase; use Doctrine\Tests\TestUtil; use Error;