Commit eddf9937 by Qiang Xue

...

parent 1dd651df
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace yii\db\dao; namespace yii\db\dao;
/** /**
* ColumnSchema class describes the meta data of a column in a database table. * ColumnSchema class describes the metadata of a column in a database table.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
......
...@@ -464,7 +464,7 @@ class Connection extends \yii\base\ApplicationComponent ...@@ -464,7 +464,7 @@ class Connection extends \yii\base\ApplicationComponent
if (isset($this->driverMap[$driver])) { if (isset($this->driverMap[$driver])) {
return $this->_driver = \Yii::createObject($this->driverMap[$driver], $this); return $this->_driver = \Yii::createObject($this->driverMap[$driver], $this);
} else { } else {
throw new Exception("Connection does not support reading meta data for '$driver' database."); throw new Exception("Connection does not support reading metadata for '$driver' database.");
} }
} }
} }
......
...@@ -15,11 +15,11 @@ use yii\db\Exception; ...@@ -15,11 +15,11 @@ use yii\db\Exception;
/** /**
* Driver is the base class for all database driver classes. * Driver is the base class for all database driver classes.
* *
* Driver implements the DBMS-specific methods to support retrieving meta data of a database. * Driver implements the DBMS-specific methods to support retrieving metadata of a database.
* *
* @property QueryBuilder $queryBuilder the query builder for this connection. * @property QueryBuilder $queryBuilder the query builder for this connection.
* @property array $tableNames the names of all tables in this database. * @property array $tableNames the names of all tables in this database.
* @property array $tableSchemas the meta data for all tables in this database. * @property array $tableSchemas the metadata for all tables in this database.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -54,7 +54,7 @@ abstract class Driver extends \yii\base\Object ...@@ -54,7 +54,7 @@ abstract class Driver extends \yii\base\Object
*/ */
private $_tableNames = array(); private $_tableNames = array();
/** /**
* @var array list of loaded table meta data (table name => TableSchema) * @var array list of loaded table metadata (table name => TableSchema)
*/ */
private $_tables = array(); private $_tables = array();
/** /**
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace yii\db\dao; namespace yii\db\dao;
/** /**
* TableSchema represents the meta data of a database table. * TableSchema represents the metadata of a database table.
* *
* @property array $columnNames list of column names * @property array $columnNames list of column names
* *
......
...@@ -14,7 +14,7 @@ use yii\db\dao\TableSchema; ...@@ -14,7 +14,7 @@ use yii\db\dao\TableSchema;
use yii\db\dao\ColumnSchema; use yii\db\dao\ColumnSchema;
/** /**
* Driver is the class for retrieving meta data from a MySQL database (version 4.1.x and 5.x). * Driver is the class for retrieving metadata from a MySQL database (version 4.1.x and 5.x).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -24,7 +24,7 @@ class Driver extends \yii\db\dao\Driver ...@@ -24,7 +24,7 @@ class Driver extends \yii\db\dao\Driver
/** /**
* @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( // dbType => type public $typeMap = array(
'tinyint' => self::TYPE_SMALLINT, 'tinyint' => self::TYPE_SMALLINT,
'bit' => self::TYPE_SMALLINT, 'bit' => self::TYPE_SMALLINT,
'smallint' => self::TYPE_SMALLINT, 'smallint' => self::TYPE_SMALLINT,
...@@ -75,6 +75,16 @@ class Driver extends \yii\db\dao\Driver ...@@ -75,6 +75,16 @@ class Driver extends \yii\db\dao\Driver
} }
/** /**
* Creates a query builder for the database.
* This method may be overridden by child classes to create a DBMS-specific query builder.
* @return QueryBuilder query builder instance
*/
public function createQueryBuilder()
{
return new QueryBuilder($this->connection);
}
/**
* 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 \yii\db\dao\TableSchema driver dependent table metadata. Null if the table does not exist. * @return \yii\db\dao\TableSchema driver dependent table metadata. Null if the table does not exist.
...@@ -91,9 +101,9 @@ class Driver extends \yii\db\dao\Driver ...@@ -91,9 +101,9 @@ class Driver extends \yii\db\dao\Driver
} }
/** /**
* Generates various kinds of table names. * Resolves the table name and schema name (if any).
* @param \yii\db\dao\TableSchema $table the table instance * @param \yii\db\dao\TableSchema $table the table metadata object
* @param string $name the unquoted table name * @param string $name the table name
*/ */
protected function resolveTableNames($table, $name) protected function resolveTableNames($table, $name)
{ {
...@@ -127,16 +137,17 @@ class Driver extends \yii\db\dao\Driver ...@@ -127,16 +137,17 @@ class Driver extends \yii\db\dao\Driver
$this->resolveColumnType($c); $this->resolveColumnType($c);
$c->resolvePhpType(); $c->resolvePhpType();
$this->resolveDefaultValue($c, $column['Default']); $this->resolveColumnDefault($c, $column['Default']);
return $c; return $c;
} }
/** /**
* @param \yii\db\dao\ColumnSchema $column * Resolves the default value for the column.
* @param string $value * @param \yii\db\dao\ColumnSchema $column the column metadata object
* @param string $value the default value fetched from database
*/ */
protected function resolveDefaultValue($column, $value) protected function resolveColumnDefault($column, $value)
{ {
if ($column->type !== 'timestamp' || $value !== 'CURRENT_TIMESTAMP') { if ($column->type !== 'timestamp' || $value !== 'CURRENT_TIMESTAMP') {
$column->defaultValue = $column->typecast($value); $column->defaultValue = $column->typecast($value);
...@@ -144,8 +155,8 @@ class Driver extends \yii\db\dao\Driver ...@@ -144,8 +155,8 @@ class Driver extends \yii\db\dao\Driver
} }
/** /**
* Extracts the PHP type from DB type. * Resolves the abstract data type for the column.
* @param \yii\db\dao\ColumnSchema $column the column * @param \yii\db\dao\ColumnSchema $column the column metadata object
*/ */
public function resolveColumnType($column) public function resolveColumnType($column)
{ {
...@@ -186,7 +197,7 @@ class Driver extends \yii\db\dao\Driver ...@@ -186,7 +197,7 @@ class Driver extends \yii\db\dao\Driver
} }
/** /**
* Collects the table column metadata. * Collects the metadata of table columns.
* @param \yii\db\dao\TableSchema $table the table metadata * @param \yii\db\dao\TableSchema $table the table metadata
* @return boolean whether the table exists in the database * @return boolean whether the table exists in the database
*/ */
...@@ -195,21 +206,21 @@ class Driver extends \yii\db\dao\Driver ...@@ -195,21 +206,21 @@ class Driver extends \yii\db\dao\Driver
$sql = 'SHOW COLUMNS FROM ' . $table->quotedName; $sql = 'SHOW COLUMNS FROM ' . $table->quotedName;
try { try {
$columns = $this->connection->createCommand($sql)->queryAll(); $columns = $this->connection->createCommand($sql)->queryAll();
} } catch (\Exception $e) {
catch (\Exception $e) {
return false; return false;
} }
foreach ($columns as $column) { foreach ($columns as $column) {
$table->columns[$c->name] = $c = $this->createColumn($column); $column = $this->createColumn($column);
if ($c->isPrimaryKey) { $table->columns[$column->name] = $column;
if ($column->isPrimaryKey) {
if ($table->primaryKey === null) { if ($table->primaryKey === null) {
$table->primaryKey = $c->name; $table->primaryKey = $column->name;
} elseif (is_string($table->primaryKey)) { } elseif (is_string($table->primaryKey)) {
$table->primaryKey = array($table->primaryKey, $c->name); $table->primaryKey = array($table->primaryKey, $column->name);
} else { } else {
$table->primaryKey[] = $c->name; $table->primaryKey[] = $column->name;
} }
if ($c->autoIncrement) { if ($column->autoIncrement) {
$table->sequenceName = ''; $table->sequenceName = '';
} }
} }
...@@ -224,20 +235,23 @@ class Driver extends \yii\db\dao\Driver ...@@ -224,20 +235,23 @@ class Driver extends \yii\db\dao\Driver
protected function findConstraints($table) protected function findConstraints($table)
{ {
$row = $this->connection->createCommand('SHOW CREATE TABLE ' . $table->quotedName)->queryRow(); $row = $this->connection->createCommand('SHOW CREATE TABLE ' . $table->quotedName)->queryRow();
$matches = array(); if (isset($row['Create Table'])) {
$sql = $row['Create Table'];
} else {
$row = array_values($row);
$sql = $row[1];
}
$regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi'; $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi';
foreach ($row as $sql) { if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) {
if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) {
foreach ($matches as $match) { $fks = array_map('trim', explode(',', str_replace('`', '', $match[1])));
$fks = array_map('trim', explode(',', str_replace('`', '', $match[1]))); $pks = array_map('trim', explode(',', str_replace('`', '', $match[3])));
$pks = array_map('trim', explode(',', str_replace('`', '', $match[3]))); $constraint = array(str_replace('`', '', $match[2]));
$constraint = array(str_replace('`', '', $match[2])); foreach ($fks as $k => $name) {
foreach ($fks as $k => $name) { $constraint[$name] = $pks[$k];
$constraint[$name] = $pks[$k];
}
$table->foreignKeys[] = $constraint;
} }
break; $table->foreignKeys[] = $constraint;
} }
} }
} }
...@@ -255,19 +269,9 @@ class Driver extends \yii\db\dao\Driver ...@@ -255,19 +269,9 @@ class Driver extends \yii\db\dao\Driver
} }
$sql = 'SHOW TABLES FROM ' . $this->quoteSimpleTableName($schema); $sql = 'SHOW TABLES FROM ' . $this->quoteSimpleTableName($schema);
$names = $this->connection->createCommand($sql)->queryColumn(); $names = $this->connection->createCommand($sql)->queryColumn();
foreach ($names as &$name) { foreach ($names as $i => $name) {
$name = $schema . '.' . $name; $names[$i] = $schema . '.' . $name;
} }
return $names; return $names;
} }
/**
* Creates a query builder for the database.
* This method may be overridden by child classes to create a DBMS-specific query builder.
* @return QueryBuilder query builder instance
*/
public function createQueryBuilder()
{
return new QueryBuilder($this->connection);
}
} }
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
namespace yii\db\dao\mysql; namespace yii\db\dao\mysql;
use yii\db\Exception;
/** /**
* QueryBuilder builds a SQL statement based on the specification given as a [[Query]] object. * QueryBuilder builds a SQL statement based on the specification given as a [[Query]] object.
* *
...@@ -42,16 +44,17 @@ class QueryBuilder extends \yii\db\dao\QueryBuilder ...@@ -42,16 +44,17 @@ class QueryBuilder extends \yii\db\dao\QueryBuilder
/** /**
* Builds a SQL statement for renaming a column. * Builds a SQL statement for renaming a column.
* @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method.
* @param string $name the old name of the column. The name will be properly quoted by the method. * @param string $oldName the old name of the column. The name will be properly quoted by the method.
* @param string $newName the new name of the column. The name will be properly quoted by the method. * @param string $newName the new name of the column. The name will be properly quoted by the method.
* @return string the SQL statement for renaming a DB column. * @return string the SQL statement for renaming a DB column.
*/ */
public function renameColumn($table, $name, $newName) public function renameColumn($table, $oldName, $newName)
{ {
$quotedTable = $this->driver->quoteTableName($table); $quotedTable = $this->driver->quoteTableName($table);
$row = $this->connection->createCommand('SHOW CREATE TABLE ' . $quotedTable)->queryRow(); $row = $this->connection->createCommand('SHOW CREATE TABLE ' . $quotedTable)->queryRow();
if ($row === false) if ($row === false) {
throw new CDbException(Yii::t('yii', 'Unable to find "{column}" in table "{table}".', array('{column}' => $name, '{table}' => $table))); throw new Exception("Unable to find '$oldName' in table '$table'.");
}
if (isset($row['Create Table'])) { if (isset($row['Create Table'])) {
$sql = $row['Create Table']; $sql = $row['Create Table'];
} else { } else {
...@@ -60,14 +63,14 @@ class QueryBuilder extends \yii\db\dao\QueryBuilder ...@@ -60,14 +63,14 @@ class QueryBuilder extends \yii\db\dao\QueryBuilder
} }
if (preg_match_all('/^\s*`(.*?)`\s+(.*?),?$/m', $sql, $matches)) { if (preg_match_all('/^\s*`(.*?)`\s+(.*?),?$/m', $sql, $matches)) {
foreach ($matches[1] as $i => $c) { foreach ($matches[1] as $i => $c) {
if ($c === $name) { if ($c === $oldName) {
return "ALTER TABLE $quotedTable CHANGE " . $this->driver->quoteColumnName($name) return "ALTER TABLE $quotedTable CHANGE " . $this->driver->quoteColumnName($oldName)
. ' ' . $this->driver->quoteColumnName($newName) . ' ' . $matches[2][$i]; . ' ' . $this->driver->quoteColumnName($newName) . ' ' . $matches[2][$i];
} }
} }
} }
// try to give back a SQL anyway // try to give back a SQL anyway
return "ALTER TABLE $quotedTable CHANGE " . $this->driver->quoteColumnName($name) . ' ' . $newName; return "ALTER TABLE $quotedTable CHANGE " . $this->driver->quoteColumnName($oldName) . ' ' . $newName;
} }
/** /**
......
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