From 90395b5df2cf02d5d20f72581f5b5f6d8d236907 Mon Sep 17 00:00:00 2001 From: resurtm Date: Wed, 22 May 2013 21:34:41 +0600 Subject: [PATCH] Refinements to MSSQL driver classes. --- framework/yii/db/mssql/PDO.php | 61 ++++ framework/yii/db/mssql/QueryBuilder.php | 38 +++ framework/yii/db/mssql/Schema.php | 371 +++++++++++++++++++++ framework/yii/db/mssql/SqlsrvPDO.php | 33 ++ .../framework/db/mssql/MssqlActiveRecordTest.php | 12 - yii/db/mssql/PDO.php | 68 ---- yii/db/mssql/QueryBuilder.php | 40 --- yii/db/mssql/Schema.php | 352 ------------------- yii/db/mssql/SqlsrvPDO.php | 33 -- 9 files changed, 503 insertions(+), 505 deletions(-) create mode 100644 framework/yii/db/mssql/PDO.php create mode 100644 framework/yii/db/mssql/QueryBuilder.php create mode 100644 framework/yii/db/mssql/Schema.php create mode 100644 framework/yii/db/mssql/SqlsrvPDO.php delete mode 100644 tests/unit/framework/db/mssql/MssqlActiveRecordTest.php delete mode 100644 yii/db/mssql/PDO.php delete mode 100644 yii/db/mssql/QueryBuilder.php delete mode 100644 yii/db/mssql/Schema.php delete mode 100644 yii/db/mssql/SqlsrvPDO.php diff --git a/framework/yii/db/mssql/PDO.php b/framework/yii/db/mssql/PDO.php new file mode 100644 index 0000000..c29cd4c --- /dev/null +++ b/framework/yii/db/mssql/PDO.php @@ -0,0 +1,61 @@ + + * @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; + } +} diff --git a/framework/yii/db/mssql/QueryBuilder.php b/framework/yii/db/mssql/QueryBuilder.php new file mode 100644 index 0000000..9ba27b2 --- /dev/null +++ b/framework/yii/db/mssql/QueryBuilder.php @@ -0,0 +1,38 @@ + + * @since 2.0 + */ +class QueryBuilder extends \yii\db\QueryBuilder +{ + /** + * @var array mapping from abstract column types (keys) to physical column types (values). + */ + public $typeMap = array( + Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY', + Schema::TYPE_STRING => 'varchar(255)', + Schema::TYPE_TEXT => 'text', + Schema::TYPE_SMALLINT => 'smallint(6)', + Schema::TYPE_INTEGER => 'int(11)', + Schema::TYPE_BIGINT => 'bigint(20)', + Schema::TYPE_FLOAT => 'float', + Schema::TYPE_DECIMAL => 'decimal', + Schema::TYPE_DATETIME => 'datetime', + Schema::TYPE_TIMESTAMP => 'timestamp', + Schema::TYPE_TIME => 'time', + Schema::TYPE_DATE => 'date', + Schema::TYPE_BINARY => 'binary', + Schema::TYPE_BOOLEAN => 'tinyint(1)', + Schema::TYPE_MONEY => 'decimal(19,4)', + ); +} diff --git a/framework/yii/db/mssql/Schema.php b/framework/yii/db/mssql/Schema.php new file mode 100644 index 0000000..f37ae8f --- /dev/null +++ b/framework/yii/db/mssql/Schema.php @@ -0,0 +1,371 @@ + + * @since 2.0 + */ +class Schema extends \yii\db\Schema +{ + /** + * Default schema name to be used. + */ + const DEFAULT_SCHEMA = 'dbo'; + + /** + * @var array mapping from physical column types (keys) to abstract column types (values) + */ + public $typeMap = array( + // exact numerics + 'bigint' => self::TYPE_BIGINT, + 'numeric' => self::TYPE_DECIMAL, + 'bit' => self::TYPE_SMALLINT, + 'smallint' => self::TYPE_SMALLINT, + 'decimal' => self::TYPE_DECIMAL, + 'smallmoney' => self::TYPE_MONEY, + 'int' => self::TYPE_INTEGER, + 'tinyint' => self::TYPE_SMALLINT, + 'money' => self::TYPE_MONEY, + + // approximate numerics + 'float' => self::TYPE_FLOAT, + 'real' => self::TYPE_FLOAT, + + // date and time + 'date' => self::TYPE_DATE, + 'datetimeoffset' => self::TYPE_DATETIME, + 'datetime2' => self::TYPE_DATETIME, + 'smalldatetime' => self::TYPE_DATETIME, + 'datetime' => self::TYPE_DATETIME, + '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, + 'hierarchyid' => self::TYPE_STRING, + 'uniqueidentifier' => self::TYPE_STRING, + 'sql_variant' => self::TYPE_STRING, + 'xml' => self::TYPE_STRING, + 'table' => self::TYPE_STRING, + ); + + /** + * Quotes a table name for use in a query. + * A simple table name has no schema prefix. + * @param string $name table name. + * @return string the properly quoted table name. + */ + public function quoteSimpleTableName($name) + { + return strpos($name, '[') === false ? "[{$name}]" : $name; + } + + /** + * Quotes a column name for use in a query. + * A simple column name has no prefix. + * @param string $name column name. + * @return string the properly quoted column name. + */ + public function quoteSimpleColumnName($name) + { + return strpos($name, '[') === false && $name !== '*' ? "[{$name}]" : $name; + } + + /** + * Creates a query builder for the MSSQL database. + * @return QueryBuilder query builder interface. + */ + public function createQueryBuilder() + { + return new QueryBuilder($this->db); + } + + /** + * Loads the metadata for the specified table. + * @param string $name table name + * @return TableSchema|null driver dependent table metadata. Null if the table does not exist. + */ + public function loadTableSchema($name) + { + $table = new TableSchema(); + $this->resolveTableNames($table, $name); + $this->findPrimaryKeys($table); + if ($this->findColumns($table)) { + $this->findForeignKeys($table); + return $table; + } + } + + /** + * Resolves the table name and schema name (if any). + * @param TableSchema $table the table metadata object + * @param string $name the table name + */ + protected function resolveTableNames($table, $name) + { + $parts = explode('.', str_replace(array('[', ']'), '', $name)); + $partCount = count($parts); + if ($partCount == 3) { + // catalog name, schema name and table name passed + $table->catalogName = $parts[0]; + $table->schemaName = $parts[1]; + $table->name = $parts[2]; + } elseif ($partCount == 2) { + // only schema name and table name passed + $table->schemaName = $parts[0]; + $table->name = $parts[1]; + } else { + // only schema name passed + $table->schemaName = static::DEFAULT_SCHEMA; + $table->name = $parts[0]; + } + } + + /** + * Loads the column information into a [[ColumnSchema]] object. + * @param array $info column information + * @return ColumnSchema the column schema object + */ + protected function loadColumnSchema($info) + { + $column = new ColumnSchema(); + + $column->name = $info['COLUMN_NAME']; + $column->allowNull = $info['IS_NULLABLE'] == 'YES'; + $column->dbType = $info['DATA_TYPE']; + $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->unsigned = stripos($column->dbType, 'unsigned') !== false; + $column->comment = $info['Comment'] === null ? '' : $column['Comment']; + + $column->type = self::TYPE_STRING; + if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { + $type = $matches[1]; + if (isset($this->typeMap[$type])) { + $column->type = $this->typeMap[$type]; + } + if (!empty($matches[2])) { + $values = explode(',', $matches[2]); + $column->size = $column->precision = (int)$values[0]; + if (isset($values[1])) { + $column->scale = (int)$values[1]; + } + if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { + $column->type = 'boolean'; + } elseif ($type === 'bit') { + if ($column->size > 32) { + $column->type = 'bigint'; + } elseif ($column->size === 32) { + $column->type = 'integer'; + } + } + } + } + + $column->phpType = $this->getColumnPhpType($column); + + if ($info['COLUMN_DEFAULT'] == '(NULL)') { + $info['COLUMN_DEFAULT'] = null; + } + if ($column->type !== 'timestamp' || $info['COLUMN_DEFAULT'] !== 'CURRENT_TIMESTAMP') { + $column->defaultValue = $column->typecast($info['COLUMN_DEFAULT']); + } + + return $column; + } + + /** + * Collects the metadata of table columns. + * @param TableSchema $table the table metadata + * @return boolean whether the table exists in the database + */ + protected function findColumns($table) + { + $columnsTableName = 'information_schema.columns'; + $whereSql = "[t1].[table_name] = '{$table->name}'"; + if ($table->catalogName !== null) { + $columnsTableName = "{$table->catalogName}.{$columnsTableName}"; + $whereSql .= " AND [t1].[table_catalog] = '{$table->catalogName}'"; + } + if ($table->schemaName !== null) { + $whereSql .= " AND [t1].[table_schema] = '{$table->schemaName}'"; + } + $columnsTableName = $this->quoteTableName($columnsTableName); + + $sql = <<db->createCommand($sql)->queryAll(); + } catch (\Exception $e) { + return false; + } + foreach ($columns as $column) { + $column = $this->loadColumnSchema($column); + if (is_array($table->primaryKey)) { + foreach ($table->primaryKey as $primaryKeyColumn) { + if (strcasecmp($column->name, $primaryKeyColumn) === 0) { + $column->isPrimaryKey = true; + break; + } + } + } else { + $column->isPrimaryKey = strcasecmp($column->name, $table->primaryKey) === 0; + } + if ($column->isPrimaryKey && $column->autoIncrement) { + $table->sequenceName = ''; + } + $table->columns[$column->name] = $column; + } + return true; + } + + /** + * Collects the primary key column details for the given table. + * @param TableSchema $table the table metadata + */ + protected function findPrimaryKeys($table) + { + $keyColumnUsageTableName = 'information_schema.key_column_usage'; + $tableConstraintsTableName = 'information_schema.table_constraints'; + if ($table->catalogName !== null) { + $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; + $tableConstraintsTableName = $table->catalogName . '.' . $tableConstraintsTableName; + } + $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); + $tableConstraintsTableName = $this->quoteTableName($tableConstraintsTableName); + + $sql = <<primaryKey = $this->db + ->createCommand($sql, array(':tableName' => $table->name, ':schemaName' => $table->schemaName)) + ->queryColumn(); + if (count($table->primaryKey) == 0) { + // table does not have primary key + $table->primaryKey = null; + } elseif (count($table->primaryKey) == 1) { + // table has one primary key + $table->primaryKey = $table->primaryKey[0]; + } + } + + /** + * Collects the foreign key column details for the given table. + * @param TableSchema $table the table metadata + */ + protected function findForeignKeys($table) + { + $referentialConstraintsTableName = 'information_schema.referential_constraints'; + $keyColumnUsageTableName = 'information_schema.key_column_usage'; + if ($table->catalogName !== null) { + $referentialConstraintsTableName = $table->catalogName . '.' . $referentialConstraintsTableName; + $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; + } + $referentialConstraintsTableName = $this->quoteTableName($referentialConstraintsTableName); + $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); + + // please refer to the following page for more details: + // http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx + $sql = <<db->createCommand($sql, array(':tableName' => $table->name))->queryAll(); + $table->foreignKeys = array(); + foreach ($rows as $row) { + $table->foreignKeys[] = array($row['uq_table_name'], $row['fk_column_name'] => $row['uq_column_name']); + } + } + + /** + * Returns all table names in the database. + * This method should be overridden by child classes in order to support this feature + * because the default implementation simply throws an exception. + * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. + * @return array all table names in the database. The names have NO the schema name prefix. + */ + protected function findTableNames($schema = '') + { + if ($schema === '') { + $schema = static::DEFAULT_SCHEMA; + } + + $sql = <<db->createCommand($sql, array(':schema' => $schema))->queryColumn(); + if ($schema !== static::DEFAULT_SCHEMA) { + foreach ($names as $index => $name) { + $names[$index] = $schema . '.' . $name; + } + } + return $names; + } +} diff --git a/framework/yii/db/mssql/SqlsrvPDO.php b/framework/yii/db/mssql/SqlsrvPDO.php new file mode 100644 index 0000000..29444c5 --- /dev/null +++ b/framework/yii/db/mssql/SqlsrvPDO.php @@ -0,0 +1,33 @@ + + * @since 2.0 + */ +class SqlsrvPDO extends \PDO +{ + /** + * Returns value of the last inserted ID. + * + * 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. + * @return integer last inserted ID value. + */ + public function lastInsertId($sequence = null) + { + return !$sequence ? parent::lastInsertId() : parent::lastInsertId($sequence); + } +} diff --git a/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php b/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php deleted file mode 100644 index 4a41663..0000000 --- a/tests/unit/framework/db/mssql/MssqlActiveRecordTest.php +++ /dev/null @@ -1,12 +0,0 @@ -driverName = 'sqlsrv'; - parent::setUp(); - } -} diff --git a/yii/db/mssql/PDO.php b/yii/db/mssql/PDO.php deleted file mode 100644 index e045d68..0000000 --- a/yii/db/mssql/PDO.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @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; - } -} diff --git a/yii/db/mssql/QueryBuilder.php b/yii/db/mssql/QueryBuilder.php deleted file mode 100644 index f4f2088..0000000 --- a/yii/db/mssql/QueryBuilder.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @author Christophe Boulain - * @author Timur Ruziev - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = array( - Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'text', - Schema::TYPE_SMALLINT => 'smallint(6)', - Schema::TYPE_INTEGER => 'int(11)', - Schema::TYPE_BIGINT => 'bigint(20)', - Schema::TYPE_FLOAT => 'float', - Schema::TYPE_DECIMAL => 'decimal', - Schema::TYPE_DATETIME => 'datetime', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'binary', - Schema::TYPE_BOOLEAN => 'tinyint(1)', - Schema::TYPE_MONEY => 'decimal(19,4)', - ); -} diff --git a/yii/db/mssql/Schema.php b/yii/db/mssql/Schema.php deleted file mode 100644 index a737070..0000000 --- a/yii/db/mssql/Schema.php +++ /dev/null @@ -1,352 +0,0 @@ - - * @author Christophe Boulain - * @author Timur Ruziev - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - /** - * Default schema name to be used. - */ - const DEFAULT_SCHEMA = 'dbo'; - - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - */ - public $typeMap = array( - 'tinyint' => self::TYPE_SMALLINT, - 'bit' => self::TYPE_SMALLINT, - 'smallint' => self::TYPE_SMALLINT, - 'mediumint' => self::TYPE_INTEGER, - 'int' => self::TYPE_INTEGER, - 'integer' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'float' => self::TYPE_FLOAT, - 'double' => self::TYPE_FLOAT, - 'real' => self::TYPE_FLOAT, - 'decimal' => self::TYPE_DECIMAL, - 'numeric' => self::TYPE_DECIMAL, - '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, - 'time' => self::TYPE_TIME, - 'timestamp' => self::TYPE_TIMESTAMP, - 'enum' => self::TYPE_STRING, - ); - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name. - * @return string the properly quoted table name. - */ - public function quoteSimpleTableName($name) - { - return strpos($name, '[') !== false ? $name : '[' . $name . ']'; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name. - * @return string the properly quoted column name. - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '[') !== false || $name === '*' ? $name : '[' . $name . ']'; - } - - /** - * Creates a query builder for the MSSQL database. - * @return QueryBuilder query builder interface. - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema driver dependent table metadata. Null if the table does not exist. - */ - public function loadTableSchema($name) - { - $table = new TableSchema(); - $this->resolveTableNames($table, $name); - $this->findPrimaryKeys($table); - - if ($this->findColumns($table)) { - $this->findForeignKeys($table); - return $table; - } else { - return null; - } - } - - /** - * Resolves the table name and schema name (if any). - * @param TableSchema $table the table metadata object - * @param string $name the table name - */ - protected function resolveTableNames($table, $name) - { - $parts = explode('.', str_replace(array('[', ']'), '', $name)); - $partCount = count($parts); - if ($partCount == 3) { - // catalog name, schema name and table name provided - $table->catalogName = $parts[0]; - $table->schemaName = $parts[1]; - $table->name = $parts[2]; - } elseif ($partCount == 2) { - // only schema name and table name provided - $table->schemaName = $parts[0]; - $table->name = $parts[1]; - } else { - // only schema name provided - $table->schemaName = static::DEFAULT_SCHEMA; - $table->name = $parts[0]; - } - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema(); - - $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->isPrimaryKey = null; // primary key is determined in findColumns() method - $column->autoIncrement = $info['IsIdentity'] == 1; - - $column->type = self::TYPE_STRING; - $matches = array(); - if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { - $type = $matches[1]; - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } - if (!empty($matches[2])) { - $values = explode(',', $matches[2]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { - $column->type = 'boolean'; - } elseif ($type === 'bit') { - if ($column->size > 32) { - $column->type = 'bigint'; - } elseif ($column->size === 32) { - $column->type = 'integer'; - } - } - } - } - - $column->phpType = $this->getColumnPhpType($column); - - if ($info['COLUMN_DEFAULT'] == '(NULL)') { - $column->defaultValue = null; - } - - return $column; - } - - /** - * Collects the metadata of table columns. - * @param TableSchema $table the table metadata - * @return boolean whether the table exists in the database - */ - protected function findColumns($table) - { - $columnsTableName = 'INFORMATION_SCHEMA.COLUMNS'; - $whereSql = "t1.TABLE_NAME = '" . $table->name . "'"; - if ($table->catalogName !== null) { - $columnsTableName = $table->catalogName . '.' . $columnsTableName; - $whereSql .= " AND t1.TABLE_CATALOG = '" . $table->catalogName . "'"; - } - if ($table->schemaName !== null) { - $whereSql .= " AND t1.TABLE_SCHEMA = '" . $table->schemaName . "'"; - } - $columnsTableName = $this->quoteTableName($columnsTableName); - - $sql = <<db->createCommand($sql)->queryAll(); - } catch (\Exception $e) { - return false; - } - foreach ($columns as $column) { - $column = $this->loadColumnSchema($column); - if (is_array($table->primaryKey)) { - $column->isPrimaryKey = count(preg_grep('/' . preg_quote($column->name) . '/i', $table->primaryKey)) > 0; - } else { - $column->isPrimaryKey = strcasecmp($column->name, $table->primaryKey) === 0; - } - $table->columns[$column->name] = $column; - if ($column->isPrimaryKey && $column->autoIncrement) { - $table->sequenceName = ''; - } - } - return true; - } - - /** - * Collects the primary key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findPrimaryKeys($table) - { - $keyColumnUsageTableName = 'INFORMATION_SCHEMA.KEY_COLUMN_USAGE'; - $tableConstraintsTableName = 'INFORMATION_SCHEMA.TABLE_CONSTRAINTS'; - if ($table->catalogName !== null) { - $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; - $tableConstraintsTableName = $table->catalogName . '.' . $tableConstraintsTableName; - } - $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); - $tableConstraintsTableName = $this->quoteTableName($tableConstraintsTableName); - - $sql = <<primaryKey = $this->db - ->createCommand($sql, array(':tableName' => $table->name, ':schemaName' => $table->schemaName)) - ->queryColumn(); - if (count($table->primaryKey) == 0) { - // table does not have primary key - $table->primaryKey = null; - } elseif (count($table->primaryKey) == 1) { - // table have one primary key - $table->primaryKey = $table->primaryKey[0]; - } - } - - /** - * Collects the foreign key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findForeignKeys($table) - { - $referentialConstraintsTableName = 'INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS'; - $keyColumnUsageTableName = 'INFORMATION_SCHEMA.KEY_COLUMN_USAGE'; - if ($table->catalogName !== null) { - $referentialConstraintsTableName = $table->catalogName . '.' . $referentialConstraintsTableName; - $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; - } - $referentialConstraintsTableName = $this->quoteTableName($referentialConstraintsTableName); - $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); - - // please refer to the following page for more details: - // http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx - $sql = <<db->createCommand($sql, array(':tableName' => $table->name))->queryAll(); - $table->foreignKeys = array(); - foreach ($rows as $row) { - $table->foreignKeys[] = array($row['uq_table_name'], $row['fk_column_name'] => $row['uq_column_name']); - } - } - - /** - * Returns all table names in the database. - * This method should be overridden by child classes in order to support this feature - * because the default implementation simply throws an exception. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO the schema name prefix. - */ - protected function findTableNames($schema = '') - { - if ('' === $schema) { - $schema = self::DEFAULT_SCHEMA; - } - - $sql = <<db->createCommand($sql, array(':schema' => $schema))->queryColumn(); - if (static::DEFAULT_SCHEMA !== $schema) { - foreach ($names as $i => $name) { - $names[$i] = $schema . '.' . $name; - } - } - return $names; - } -} diff --git a/yii/db/mssql/SqlsrvPDO.php b/yii/db/mssql/SqlsrvPDO.php deleted file mode 100644 index 607d0e4..0000000 --- a/yii/db/mssql/SqlsrvPDO.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @since 2.0 - */ -class SqlsrvPDO extends \PDO -{ - /** - * Returns last inserted ID value. - * - * 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). - * - * @param string|null $sequence the sequence name. Defaults to null. - * @return integer last inserted ID value. - */ - public function lastInsertId($sequence = null) - { - return !$sequence ? parent::lastInsertId() : parent::lastInsertId($sequence); - } -}