Commit 1b4d41c1 authored by Benjamin Eberlei's avatar Benjamin Eberlei

[DBAL-216] Bugfixes and CS. Fixed LastInsertId and added test.

parent 4c300758
......@@ -29,16 +29,18 @@ class Driver implements \Doctrine\DBAL\Driver
if (!isset($params['host'])) {
throw new SQLSrvException("Missing 'host' in configuration for sqlsrv driver.");
}
if (!isset($params['dbname'])) {
throw new SQLSrvException("Missing 'dbname' in configuration for sqlsrv driver.");
}
$serverName = $params['host'];
if (isset($params['port'])) {
$serverName .= ', ' . $params['port'];
}
if (!isset($params['dbname'])) {
throw new SQLSrvException("Missing 'dbname' in configuration for sqlsrv driver.");
}
$driverOptions['Database'] = $params['dbname'];
$driverOptions['UID'] = $username;
$driverOptions['PWD'] = $password;
if (!isset($driverOptions['ReturnDatesAsStrings'])) {
$driverOptions['ReturnDatesAsStrings'] = 1;
}
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver\SQLSrv;
/**
* Last Id Data Container
*
* @since 2.3
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class LastInsertId
{
private $id;
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
}
......@@ -27,14 +27,24 @@ namespace Doctrine\DBAL\Driver\SQLSrv;
*/
class SQLSrvConnection implements \Doctrine\DBAL\Driver\Connection
{
/**
* @var resource
*/
protected $conn;
/**
* @var LastInsertId
*/
protected $lastInsertId;
public function __construct($serverName, $connectionOptions)
{
$this->conn = sqlsrv_connect($serverName, $connectionOptions);
if (!$this->conn) {
throw SQLSrvException::fromSqlSrvErrors();
}
$this->lastInsertId = new LastInsertId();
}
/**
......@@ -42,7 +52,7 @@ class SQLSrvConnection implements \Doctrine\DBAL\Driver\Connection
*/
public function prepare($sql)
{
return new SQLSrvStatement($this->conn, $sql);
return new SQLSrvStatement($this->conn, $sql, $lastInsertId);
}
/**
......@@ -87,17 +97,17 @@ class SQLSrvConnection implements \Doctrine\DBAL\Driver\Connection
*/
public function lastInsertId($name = null)
{
if ($name === null) {
$sql = "SELECT SCOPE_IDENTITY() AS LastInsertId";
} else {
if ($name !== null) {
$sql = "SELECT IDENT_CURRENT(".$this->quote($name).") AS LastInsertId";
}
$stmt = $this->prepare($sql);
$stmt->execute();
return $stmt->fetchColumn();
}
return $this->lastInsertId->getId();
}
/**
* {@inheritDoc}
*/
......
......@@ -23,6 +23,12 @@ use PDO;
use IteratorAggregate;
use Doctrine\DBAL\Driver\Statement;
/**
* SQL Server Statement
*
* @since 2.3
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class SQLSrvStatement implements IteratorAggregate, Statement
{
/**
......@@ -71,10 +77,27 @@ class SQLSrvStatement implements IteratorAggregate, Statement
*/
private $defaultFetchStyle = PDO::FETCH_BOTH;
public function __construct($conn, $sql)
/**
* @var int|null
*/
private $lastInsertId;
/**
* Append to any INSERT query to retrieve the last insert id.
*
* @var string
*/
const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;';
public function __construct($conn, $sql, $lastInsertId = null)
{
$this->conn = $conn;
$this->sql = $sql;
if (stripos($sql, 'INSERT INTO ') === 0) {
$this->sql .= self::LAST_INSERT_ID_SQL;
$this->lastInsertId = $lastInsertId;
}
}
public function bindValue($param, $value, $type = null)
......@@ -135,18 +158,21 @@ class SQLSrvStatement implements IteratorAggregate, Statement
if ($params) {
$hasZeroIndex = array_key_exists(0, $params);
foreach ($params as $key => $val) {
if ($hasZeroIndex && is_numeric($key)) {
$this->bindValue($key + 1, $val);
} else {
$key = ($hasZeroIndex && is_numeric($key)) ? $key + 1 : $key;
$this->bindValue($key, $val);
}
}
}
$this->stmt = sqlsrv_query($this->conn, $this->sql, $this->params);
if (!$this->stmt) {
throw SQLSrvException::fromSqlSrvErrors();
}
if ($this->lastInsertId) {
sqlsrv_next_result($this->stmt);
sqlsrv_fetch($this->stmt);
$this->lastInsertId->setId( sqlsrv_get_field($this->stmt, 0) );
}
}
public function setFetchMode($fetchStyle = PDO::FETCH_BOTH)
......@@ -180,9 +206,9 @@ class SQLSrvStatement implements IteratorAggregate, Statement
$ctorArgs = (isset($args[2])) ? $args[2] : array();
}
return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs);
} else {
throw new SQLSrvException("Fetch mode is not supported!");
}
throw new SQLSrvException("Fetch mode is not supported!");
}
/**
......
......@@ -65,7 +65,7 @@ class Connection extends \Doctrine\DBAL\Connection
} else if ($this->_platform->getName() === "drizzle") {
$params['portability'] = self::PORTABILITY_DRIZZLE;
} else if ($this->_platform->getName() === 'sqlsrv') {
$params['portaility'] = $params['portabililty'] & self::PORTABILITY_SQLSRV;
$params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV;
} else {
$params['portability'] = $params['portability'] & self::PORTABILITY_OTHERVENDORS;
}
......
......@@ -15,7 +15,7 @@ class WriteTest extends \Doctrine\Tests\DbalFunctionalTestCase
try {
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
$table = new \Doctrine\DBAL\Schema\Table("write_table");
$table->addColumn('test_int', 'integer');
$table->addColumn('test_int', 'integer', array('autoincrement' => true));
$table->addColumn('test_string', 'string', array('notnull' => false));
$table->setPrimaryKey(array('test_int'));
......@@ -134,4 +134,17 @@ class WriteTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertEquals(2, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar')));
$this->assertEquals(0, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar')));
}
public function testLastInsertId()
{
if ( ! $this->_conn->getDatabasePlatform()->prefersIdentityColumns()) {
$this->markTestSkipped('Test only works on platforms with identity columns.');
}
$this->assertEquals(1, $this->_conn->insert('write_table', array('test_int' => 2, 'test_string' => 'bar')));
$num = $this->_conn->lastInsertId();
$this->assertNotNull($num, "LastInsertId() should not be null.");
$this->assertTrue($num > 0, "LastInsertId() should be non-negative number.");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment