Browse Source

Refinements to MSSQL driver classes.

tags/2.0.0-beta
resurtm 12 years ago
parent
commit
90395b5df2
  1. 61
      framework/yii/db/mssql/PDO.php
  2. 4
      framework/yii/db/mssql/QueryBuilder.php
  3. 203
      framework/yii/db/mssql/Schema.php
  4. 14
      framework/yii/db/mssql/SqlsrvPDO.php
  5. 12
      tests/unit/framework/db/mssql/MssqlActiveRecordTest.php
  6. 68
      yii/db/mssql/PDO.php

61
framework/yii/db/mssql/PDO.php

@ -0,0 +1,61 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mssql;
/**
* This is an extension of the default PDO class of MSSQL and DBLIB drivers.
* It provides workarounds for improperly implemented functionalities of the MSSQL and DBLIB drivers.
*
* @author Timur Ruziev <resurtm@gmail.com>
* @since 2.0
*/
class PDO extends \PDO
{
/**
* Returns value of the last inserted ID.
* @param string|null $sequence the sequence name. Defaults to null.
* @return integer last inserted ID value.
*/
public function lastInsertId($sequence = null)
{
return $this->query('SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS bigint)')->fetchColumn();
}
/**
* Starts a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not
* natively support transactions.
* @return boolean the result of a transaction start.
*/
public function beginTransaction()
{
$this->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commits a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not
* natively support transactions.
* @return boolean the result of a transaction commit.
*/
public function commit()
{
$this->exec('COMMIT TRANSACTION');
return true;
}
/**
* Rollbacks a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not
* natively support transactions.
* @return boolean the result of a transaction rollback.
*/
public function rollBack()
{
$this->exec('ROLLBACK TRANSACTION');
return true;
}
}

4
yii/db/mssql/QueryBuilder.php → framework/yii/db/mssql/QueryBuilder.php

@ -8,10 +8,8 @@
namespace yii\db\mssql; namespace yii\db\mssql;
/** /**
* QueryBuilder is the query builder for MS SQL database (version 2008 and above). * QueryBuilder is the query builder for MS SQL Server databases (version 2008 and above).
* *
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Christophe Boulain <Christophe.Boulain@gmail.com>
* @author Timur Ruziev <resurtm@gmail.com> * @author Timur Ruziev <resurtm@gmail.com>
* @since 2.0 * @since 2.0
*/ */

203
yii/db/mssql/Schema.php → framework/yii/db/mssql/Schema.php

@ -11,10 +11,8 @@ use yii\db\TableSchema;
use yii\db\ColumnSchema; use yii\db\ColumnSchema;
/** /**
* Schema is the class for retrieving metadata from a MS SQL database (version 2008 and above). * Schema is the class for retrieving metadata from a MS SQL Server databases (version 2008 and above).
* *
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Christophe Boulain <Christophe.Boulain@gmail.com>
* @author Timur Ruziev <resurtm@gmail.com> * @author Timur Ruziev <resurtm@gmail.com>
* @since 2.0 * @since 2.0
*/ */
@ -29,31 +27,52 @@ class Schema extends \yii\db\Schema
* @var array mapping from physical column types (keys) to abstract column types (values) * @var array mapping from physical column types (keys) to abstract column types (values)
*/ */
public $typeMap = array( public $typeMap = array(
'tinyint' => self::TYPE_SMALLINT, // exact numerics
'bigint' => self::TYPE_BIGINT,
'numeric' => self::TYPE_DECIMAL,
'bit' => self::TYPE_SMALLINT, 'bit' => self::TYPE_SMALLINT,
'smallint' => self::TYPE_SMALLINT, 'smallint' => self::TYPE_SMALLINT,
'mediumint' => self::TYPE_INTEGER, 'decimal' => self::TYPE_DECIMAL,
'smallmoney' => self::TYPE_MONEY,
'int' => self::TYPE_INTEGER, 'int' => self::TYPE_INTEGER,
'integer' => self::TYPE_INTEGER, 'tinyint' => self::TYPE_SMALLINT,
'bigint' => self::TYPE_BIGINT, 'money' => self::TYPE_MONEY,
// approximate numerics
'float' => self::TYPE_FLOAT, 'float' => self::TYPE_FLOAT,
'double' => self::TYPE_FLOAT,
'real' => self::TYPE_FLOAT, 'real' => self::TYPE_FLOAT,
'decimal' => self::TYPE_DECIMAL,
'numeric' => self::TYPE_DECIMAL, // date and time
'tinytext' => self::TYPE_TEXT,
'mediumtext' => self::TYPE_TEXT,
'longtext' => self::TYPE_TEXT,
'text' => self::TYPE_TEXT,
'varchar' => self::TYPE_STRING,
'string' => self::TYPE_STRING,
'char' => self::TYPE_STRING,
'datetime' => self::TYPE_DATETIME,
'year' => self::TYPE_DATE,
'date' => self::TYPE_DATE, 'date' => self::TYPE_DATE,
'datetimeoffset' => self::TYPE_DATETIME,
'datetime2' => self::TYPE_DATETIME,
'smalldatetime' => self::TYPE_DATETIME,
'datetime' => self::TYPE_DATETIME,
'time' => self::TYPE_TIME, 'time' => self::TYPE_TIME,
// character strings
'char' => self::TYPE_STRING,
'varchar' => self::TYPE_STRING,
'text' => self::TYPE_TEXT,
// unicode character strings
'nchar' => self::TYPE_STRING,
'nvarchar' => self::TYPE_STRING,
'ntext' => self::TYPE_TEXT,
// binary strings
'binary' => self::TYPE_BINARY,
'varbinary' => self::TYPE_BINARY,
'image' => self::TYPE_BINARY,
// other data types
// 'cursor' type cannot be used with tables
'timestamp' => self::TYPE_TIMESTAMP, 'timestamp' => self::TYPE_TIMESTAMP,
'enum' => self::TYPE_STRING, 'hierarchyid' => self::TYPE_STRING,
'uniqueidentifier' => self::TYPE_STRING,
'sql_variant' => self::TYPE_STRING,
'xml' => self::TYPE_STRING,
'table' => self::TYPE_STRING,
); );
/** /**
@ -64,7 +83,7 @@ class Schema extends \yii\db\Schema
*/ */
public function quoteSimpleTableName($name) public function quoteSimpleTableName($name)
{ {
return strpos($name, '[') !== false ? $name : '[' . $name . ']'; return strpos($name, '[') === false ? "[{$name}]" : $name;
} }
/** /**
@ -75,7 +94,7 @@ class Schema extends \yii\db\Schema
*/ */
public function quoteSimpleColumnName($name) public function quoteSimpleColumnName($name)
{ {
return strpos($name, '[') !== false || $name === '*' ? $name : '[' . $name . ']'; return strpos($name, '[') === false && $name !== '*' ? "[{$name}]" : $name;
} }
/** /**
@ -90,19 +109,16 @@ class Schema extends \yii\db\Schema
/** /**
* Loads the metadata for the specified table. * Loads the metadata for the specified table.
* @param string $name table name * @param string $name table name
* @return TableSchema driver dependent table metadata. Null if the table does not exist. * @return TableSchema|null driver dependent table metadata. Null if the table does not exist.
*/ */
public function loadTableSchema($name) public function loadTableSchema($name)
{ {
$table = new TableSchema(); $table = new TableSchema();
$this->resolveTableNames($table, $name); $this->resolveTableNames($table, $name);
$this->findPrimaryKeys($table); $this->findPrimaryKeys($table);
if ($this->findColumns($table)) { if ($this->findColumns($table)) {
$this->findForeignKeys($table); $this->findForeignKeys($table);
return $table; return $table;
} else {
return null;
} }
} }
@ -116,16 +132,16 @@ class Schema extends \yii\db\Schema
$parts = explode('.', str_replace(array('[', ']'), '', $name)); $parts = explode('.', str_replace(array('[', ']'), '', $name));
$partCount = count($parts); $partCount = count($parts);
if ($partCount == 3) { if ($partCount == 3) {
// catalog name, schema name and table name provided // catalog name, schema name and table name passed
$table->catalogName = $parts[0]; $table->catalogName = $parts[0];
$table->schemaName = $parts[1]; $table->schemaName = $parts[1];
$table->name = $parts[2]; $table->name = $parts[2];
} elseif ($partCount == 2) { } elseif ($partCount == 2) {
// only schema name and table name provided // only schema name and table name passed
$table->schemaName = $parts[0]; $table->schemaName = $parts[0];
$table->name = $parts[1]; $table->name = $parts[1];
} else { } else {
// only schema name provided // only schema name passed
$table->schemaName = static::DEFAULT_SCHEMA; $table->schemaName = static::DEFAULT_SCHEMA;
$table->name = $parts[0]; $table->name = $parts[0];
} }
@ -141,17 +157,15 @@ class Schema extends \yii\db\Schema
$column = new ColumnSchema(); $column = new ColumnSchema();
$column->name = $info['COLUMN_NAME']; $column->name = $info['COLUMN_NAME'];
$column->comment = $info['Comment'] === null ? '' : $column['Comment'];
$column->dbType = $info['DATA_TYPE'];
$column->unsigned = stripos($column->dbType, 'unsigned') !== false;
$column->allowNull = $info['IS_NULLABLE'] == 'YES'; $column->allowNull = $info['IS_NULLABLE'] == 'YES';
$column->dbType = $info['DATA_TYPE'];
$column->isPrimaryKey = null; // primary key is determined in findColumns() method $column->enumValues = array(); // mssql has only vague equivalents to enum
$column->isPrimaryKey = null; // primary key will be determined in findColumns() method
$column->autoIncrement = $info['IsIdentity'] == 1; $column->autoIncrement = $info['IsIdentity'] == 1;
$column->unsigned = stripos($column->dbType, 'unsigned') !== false;
$column->comment = $info['Comment'] === null ? '' : $column['Comment'];
$column->type = self::TYPE_STRING; $column->type = self::TYPE_STRING;
$matches = array();
if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
$type = $matches[1]; $type = $matches[1];
if (isset($this->typeMap[$type])) { if (isset($this->typeMap[$type])) {
@ -178,7 +192,10 @@ class Schema extends \yii\db\Schema
$column->phpType = $this->getColumnPhpType($column); $column->phpType = $this->getColumnPhpType($column);
if ($info['COLUMN_DEFAULT'] == '(NULL)') { if ($info['COLUMN_DEFAULT'] == '(NULL)') {
$column->defaultValue = null; $info['COLUMN_DEFAULT'] = null;
}
if ($column->type !== 'timestamp' || $info['COLUMN_DEFAULT'] !== 'CURRENT_TIMESTAMP') {
$column->defaultValue = $column->typecast($info['COLUMN_DEFAULT']);
} }
return $column; return $column;
@ -191,29 +208,29 @@ class Schema extends \yii\db\Schema
*/ */
protected function findColumns($table) protected function findColumns($table)
{ {
$columnsTableName = 'INFORMATION_SCHEMA.COLUMNS'; $columnsTableName = 'information_schema.columns';
$whereSql = "t1.TABLE_NAME = '" . $table->name . "'"; $whereSql = "[t1].[table_name] = '{$table->name}'";
if ($table->catalogName !== null) { if ($table->catalogName !== null) {
$columnsTableName = $table->catalogName . '.' . $columnsTableName; $columnsTableName = "{$table->catalogName}.{$columnsTableName}";
$whereSql .= " AND t1.TABLE_CATALOG = '" . $table->catalogName . "'"; $whereSql .= " AND [t1].[table_catalog] = '{$table->catalogName}'";
} }
if ($table->schemaName !== null) { if ($table->schemaName !== null) {
$whereSql .= " AND t1.TABLE_SCHEMA = '" . $table->schemaName . "'"; $whereSql .= " AND [t1].[table_schema] = '{$table->schemaName}'";
} }
$columnsTableName = $this->quoteTableName($columnsTableName); $columnsTableName = $this->quoteTableName($columnsTableName);
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
t1.*, [t1].*,
columnproperty(object_id(t1.table_schema + '.' + t1.table_name), t1.column_name, 'IsIdentity') AS IsIdentity, COLUMNPROPERTY(OBJECT_ID([t1].[table_schema] + '.' + [t1].[table_name]), [t1].[column_name], 'IsIdentity') AS IsIdentity,
CONVERT(VARCHAR, t2.value) AS Comment CONVERT(VARCHAR, [t2].[value]) AS Comment
FROM {$columnsTableName} AS t1 FROM {$columnsTableName} AS [t1]
LEFT OUTER JOIN sys.extended_properties AS t2 ON LEFT OUTER JOIN [sys].[extended_properties] AS [t2] ON
t1.ORDINAL_POSITION = t2.minor_id AND [t1].[ordinal_position] = [t2].[minor_id] AND
object_name(t2.major_id) = t1.TABLE_NAME AND OBJECT_NAME([t2].[major_id]) = [t1].[table_name] AND
t2.class = 1 AND [t2].[class] = 1 AND
t2.class_desc = 'OBJECT_OR_COLUMN' AND [t2].[class_desc] = 'OBJECT_OR_COLUMN' AND
t2.name = 'MS_Description' [t2].[name] = 'MS_Description'
WHERE {$whereSql} WHERE {$whereSql}
SQL; SQL;
@ -225,14 +242,19 @@ SQL;
foreach ($columns as $column) { foreach ($columns as $column) {
$column = $this->loadColumnSchema($column); $column = $this->loadColumnSchema($column);
if (is_array($table->primaryKey)) { if (is_array($table->primaryKey)) {
$column->isPrimaryKey = count(preg_grep('/' . preg_quote($column->name) . '/i', $table->primaryKey)) > 0; foreach ($table->primaryKey as $primaryKeyColumn) {
if (strcasecmp($column->name, $primaryKeyColumn) === 0) {
$column->isPrimaryKey = true;
break;
}
}
} else { } else {
$column->isPrimaryKey = strcasecmp($column->name, $table->primaryKey) === 0; $column->isPrimaryKey = strcasecmp($column->name, $table->primaryKey) === 0;
} }
$table->columns[$column->name] = $column;
if ($column->isPrimaryKey && $column->autoIncrement) { if ($column->isPrimaryKey && $column->autoIncrement) {
$table->sequenceName = ''; $table->sequenceName = '';
} }
$table->columns[$column->name] = $column;
} }
return true; return true;
} }
@ -243,8 +265,8 @@ SQL;
*/ */
protected function findPrimaryKeys($table) protected function findPrimaryKeys($table)
{ {
$keyColumnUsageTableName = 'INFORMATION_SCHEMA.KEY_COLUMN_USAGE'; $keyColumnUsageTableName = 'information_schema.key_column_usage';
$tableConstraintsTableName = 'INFORMATION_SCHEMA.TABLE_CONSTRAINTS'; $tableConstraintsTableName = 'information_schema.table_constraints';
if ($table->catalogName !== null) { if ($table->catalogName !== null) {
$keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName;
$tableConstraintsTableName = $table->catalogName . '.' . $tableConstraintsTableName; $tableConstraintsTableName = $table->catalogName . '.' . $tableConstraintsTableName;
@ -254,15 +276,15 @@ SQL;
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
kcu.column_name AS field_name [kcu].[column_name] AS [field_name]
FROM {$keyColumnUsageTableName} AS kcu FROM {$keyColumnUsageTableName} AS [kcu]
LEFT JOIN {$tableConstraintsTableName} AS tc ON LEFT JOIN {$tableConstraintsTableName} AS [tc] ON
kcu.table_name = tc.table_name AND [kcu].[table_name] = [tc].[table_name] AND
kcu.constraint_name = tc.constraint_name [kcu].[constraint_name] = [tc].[constraint_name]
WHERE WHERE
tc.constraint_type = 'PRIMARY KEY' AND [tc].[constraint_type] = 'PRIMARY KEY' AND
kcu.table_name = :tableName AND [kcu].[table_name] = :tableName AND
kcu.table_schema = :schemaName [kcu].[table_schema] = :schemaName
SQL; SQL;
$table->primaryKey = $this->db $table->primaryKey = $this->db
@ -272,7 +294,7 @@ SQL;
// table does not have primary key // table does not have primary key
$table->primaryKey = null; $table->primaryKey = null;
} elseif (count($table->primaryKey) == 1) { } elseif (count($table->primaryKey) == 1) {
// table have one primary key // table has one primary key
$table->primaryKey = $table->primaryKey[0]; $table->primaryKey = $table->primaryKey[0];
} }
} }
@ -283,8 +305,8 @@ SQL;
*/ */
protected function findForeignKeys($table) protected function findForeignKeys($table)
{ {
$referentialConstraintsTableName = 'INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS'; $referentialConstraintsTableName = 'information_schema.referential_constraints';
$keyColumnUsageTableName = 'INFORMATION_SCHEMA.KEY_COLUMN_USAGE'; $keyColumnUsageTableName = 'information_schema.key_column_usage';
if ($table->catalogName !== null) { if ($table->catalogName !== null) {
$referentialConstraintsTableName = $table->catalogName . '.' . $referentialConstraintsTableName; $referentialConstraintsTableName = $table->catalogName . '.' . $referentialConstraintsTableName;
$keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName;
@ -296,20 +318,20 @@ SQL;
// http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx // http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
kcu1.COLUMN_NAME AS fk_column_name, [kcu1].[column_name] AS [fk_column_name],
kcu2.TABLE_NAME AS uq_table_name, [kcu2].[table_name] AS [uq_table_name],
kcu2.COLUMN_NAME AS uq_column_name [kcu2].[column_name] AS [uq_column_name]
FROM {$referentialConstraintsTableName} AS rc FROM {$referentialConstraintsTableName} AS [rc]
JOIN {$keyColumnUsageTableName} AS kcu1 ON JOIN {$keyColumnUsageTableName} AS [kcu1] ON
kcu1.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG AND [kcu1].[constraint_catalog] = [rc].[constraint_catalog] AND
kcu1.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA AND [kcu1].[constraint_schema] = [rc].[constraint_schema] AND
kcu1.CONSTRAINT_NAME = rc.CONSTRAINT_NAME [kcu1].[constraint_name] = [rc].[constraint_name]
JOIN {$keyColumnUsageTableName} AS kcu2 ON JOIN {$keyColumnUsageTableName} AS [kcu2] ON
kcu2.CONSTRAINT_CATALOG = rc.UNIQUE_CONSTRAINT_CATALOG AND [kcu2].[constraint_catalog] = [rc].[constraint_catalog] AND
kcu2.CONSTRAINT_SCHEMA = rc.UNIQUE_CONSTRAINT_SCHEMA AND [kcu2].[constraint_schema] = [rc].[constraint_schema] AND
kcu2.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME AND [kcu2].[constraint_name] = [rc].[constraint_name] AND
kcu2.ORDINAL_POSITION = kcu1.ORDINAL_POSITION [kcu2].[ordinal_position] = [kcu1].[ordinal_position]
WHERE kcu1.TABLE_NAME = :tableName WHERE [kcu1].[table_name] = :tableName
SQL; SQL;
$rows = $this->db->createCommand($sql, array(':tableName' => $table->name))->queryAll(); $rows = $this->db->createCommand($sql, array(':tableName' => $table->name))->queryAll();
@ -328,23 +350,20 @@ SQL;
*/ */
protected function findTableNames($schema = '') protected function findTableNames($schema = '')
{ {
if ('' === $schema) { if ($schema === '') {
$schema = self::DEFAULT_SCHEMA; $schema = static::DEFAULT_SCHEMA;
} }
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT [t].[table]
TABLE_NAME FROM [information_schema].[tables] AS [t]
FROM [INFORMATION_SCHEMA].[TABLES] WHERE [t].[table_schema] = :schema AND [t].[table_type] = 'BASE TABLE'
WHERE
TABLE_SCHEMA = :schema AND
TABLE_TYPE = 'BASE TABLE'
SQL; SQL;
$names = $this->db->createCommand($sql, array(':schema' => $schema))->queryColumn(); $names = $this->db->createCommand($sql, array(':schema' => $schema))->queryColumn();
if (static::DEFAULT_SCHEMA !== $schema) { if ($schema !== static::DEFAULT_SCHEMA) {
foreach ($names as $i => $name) { foreach ($names as $index => $name) {
$names[$i] = $schema . '.' . $name; $names[$index] = $schema . '.' . $name;
} }
} }
return $names; return $names;

14
yii/db/mssql/SqlsrvPDO.php → framework/yii/db/mssql/SqlsrvPDO.php

@ -8,8 +8,8 @@
namespace yii\db\mssql; namespace yii\db\mssql;
/** /**
* This is an extension of default PDO class for MSSQL SQLSRV driver. It provides workaround for improperly * This is an extension of the default PDO class of SQLSRV driver.
* implemented functionalities of the PDO SQLSRV driver. * It provides workarounds for improperly implemented functionalities of the SQLSRV driver.
* *
* @author Timur Ruziev <resurtm@gmail.com> * @author Timur Ruziev <resurtm@gmail.com>
* @since 2.0 * @since 2.0
@ -17,12 +17,12 @@ namespace yii\db\mssql;
class SqlsrvPDO extends \PDO class SqlsrvPDO extends \PDO
{ {
/** /**
* Returns last inserted ID value. * Returns value of the last inserted ID.
*
* SQLSRV driver supports PDO::lastInsertId() with one peculiarity: when $sequence value is null
* or empty string it returns empty string. But when parameter is not specified it's working
* as expected and returns actual last inserted ID (like the other PDO drivers).
* *
* SQLSRV driver implements [[PDO::lastInsertId()]] method but with a single peculiarity:
* when `$sequence` value is a null or an empty string it returns an empty string.
* But when parameter is not specified it works as expected and returns actual
* last inserted ID (like the other PDO drivers).
* @param string|null $sequence the sequence name. Defaults to null. * @param string|null $sequence the sequence name. Defaults to null.
* @return integer last inserted ID value. * @return integer last inserted ID value.
*/ */

12
tests/unit/framework/db/mssql/MssqlActiveRecordTest.php

@ -1,12 +0,0 @@
<?php
namespace yiiunit\framework\db\mssql;
class MssqlActiveRecordTest extends \yiiunit\framework\db\ActiveRecordTest
{
public function setUp()
{
$this->driverName = 'sqlsrv';
parent::setUp();
}
}

68
yii/db/mssql/PDO.php

@ -1,68 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mssql;
/**
* This is an extension of default PDO class for MSSQL and DBLIB drivers. It provides workaround for improperly
* implemented functionalities of the drivers.
*
* @author Timur Ruziev <qiang.xue@gmail.com>
* @since 2.0
*/
class PDO extends \PDO
{
/**
* Returns last inserted ID value.
*
* @param string|null sequence the sequence name. Defaults to null.
* @return integer last inserted ID value.
*/
public function lastInsertId($sequence = null)
{
return $this->query('SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS bigint)')->fetchColumn();
}
/**
* Begin a transaction.
*
* Is is necessary to override PDO's method as MSSQL PDO drivers does not support transactions.
*
* @return boolean
*/
public function beginTransaction()
{
$this->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* Is is necessary to override PDO's method as MSSQL PDO drivers does not support transactions.
*
* @return boolean
*/
public function commit()
{
$this->exec('COMMIT TRANSACTION');
return true;
}
/**
* Rollback a transaction.
*
* Is is necessary to override PDO's method as MSSQL PDO drivers does not support transaction.
*
* @return boolean
*/
public function rollBack()
{
$this->exec('ROLLBACK TRANSACTION');
return true;
}
}
Loading…
Cancel
Save