diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php index f2ae94c..46288a2 100644 --- a/framework/yii/db/Schema.php +++ b/framework/yii/db/Schema.php @@ -248,6 +248,28 @@ abstract class Schema extends Object } /** + * Returns all unique indexes for the given table. + * Each array element is of the following structure: + * + * ~~~ + * [ + * 'IndexName1' => ['col1' [, ...]], + * 'IndexName2' => ['col2' [, ...]], + * ] + * ~~~ + * + * This method should be overridden by child classes in order to support this feature + * because the default implementation simply throws an exception + * @param TableSchema $table the table metadata + * @return array all unique indexes for the given table. + * @throws NotSupportedException if this method is called + */ + public function findUniqueIndexes($schema = '') + { + throw new NotSupportedException(get_class($this) . ' does not support getting unique indexes information.'); + } + + /** * Returns the ID of the last inserted row or sequence value. * @param string $sequenceName name of the sequence object (required by some DBMS) * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object diff --git a/framework/yii/db/mysql/Schema.php b/framework/yii/db/mysql/Schema.php index f55d38f..075389e 100644 --- a/framework/yii/db/mysql/Schema.php +++ b/framework/yii/db/mysql/Schema.php @@ -207,10 +207,11 @@ class Schema extends \yii\db\Schema } /** - * Collects the foreign key column details for the given table. + * Gets the CREATE TABLE sql string. * @param TableSchema $table the table metadata + * @return string $sql the result of 'SHOW CREATE TABLE' */ - protected function findConstraints($table) + protected function getCreateTableSql($table) { $row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteSimpleTableName($table->name))->queryOne(); if (isset($row['Create Table'])) { @@ -219,6 +220,16 @@ class Schema extends \yii\db\Schema $row = array_values($row); $sql = $row[1]; } + return $sql; + } + + /** + * Collects the foreign key column details for the given table. + * @param TableSchema $table the table metadata + */ + protected function findConstraints($table) + { + $sql = $this->getCreateTableSql($table); $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi'; if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) { @@ -235,6 +246,36 @@ class Schema extends \yii\db\Schema } /** + * Returns all unique indexes for the given table. + * Each array element is of the following structure: + * + * ~~~ + * [ + * 'IndexName1' => ['col1' [, ...]], + * 'IndexName2' => ['col2' [, ...]], + * ] + * ~~~ + * + * @param TableSchema $table the table metadata + * @return array all unique indexes for the given table. + */ + public function findUniqueIndexes($table) + { + $sql = $this->getCreateTableSql($table); + $uniqueIndexes = []; + + $regexp = '/UNIQUE KEY\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi'; + if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $indexName = str_replace('`', '', $match[2]); + $indexColumns = array_map('trim', explode(',', str_replace('`', '', $match[3]))); + $uniqueIndexes[$indexName] = $indexColumns; + } + } + return $uniqueIndexes; + } + + /** * Returns all table names in the database. * @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 schema name prefix. diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index eb7de37..96889ab 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -227,6 +227,74 @@ SQL; } /** + * Gets information about given table unique indexes. + * @param TableSchema $table the table metadata + * @return array with index names, columns and if it is an expression tree + */ + protected function getUniqueIndexInformation($table) + { + $tableName = $this->quoteValue($table->name); + $tableSchema = $this->quoteValue($table->schemaName); + + $sql = <<db->createCommand($sql)->queryAll(); + } + + /** + * Returns all unique indexes for the given table. + * Each array element is of the following structure: + * + * ~~~ + * [ + * 'IndexName1' => ['col1' [, ...]], + * 'IndexName2' => ['col2' [, ...]], + * ] + * ~~~ + * + * @param TableSchema $table the table metadata + * @return array all unique indexes for the given table. + */ + public function findUniqueIndexes($table) + { + $indexes = $this->getUniqueIndexInformation($table); + $uniqueIndexes = []; + + foreach ($indexes as $index) { + $indexName = $index['indexname']; + + if ($index['indexprs']) { + // Index is an expression like "lower(colname::text)" + $indexColumns = preg_replace("/.*\(([^\:]+).*/mi", "$1", $index['indexcolumns']); + } else { + $indexColumns = array_map('trim', explode(',', str_replace(['{', '}'], '', $index['indexcolumns']))); + } + + $uniqueIndexes[$indexName] = $indexColumns; + + } + return $uniqueIndexes; + } + + /** * Collects the metadata of table columns. * @param TableSchema $table the table metadata * @return boolean whether the table exists in the database diff --git a/framework/yii/db/sqlite/Schema.php b/framework/yii/db/sqlite/Schema.php index 8633650..9f410b4 100644 --- a/framework/yii/db/sqlite/Schema.php +++ b/framework/yii/db/sqlite/Schema.php @@ -159,6 +159,40 @@ class Schema extends \yii\db\Schema } /** + * Returns all unique indexes for the given table. + * Each array element is of the following structure: + * + * ~~~ + * [ + * 'IndexName1' => ['col1' [, ...]], + * 'IndexName2' => ['col2' [, ...]], + * ] + * ~~~ + * + * @param TableSchema $table the table metadata + * @return array all unique indexes for the given table. + */ + public function findUniqueIndexes($table) + { + $sql = "PRAGMA index_list(" . $this->quoteSimpleTableName($table->name) . ')'; + $indexes = $this->db->createCommand($sql)->queryAll(); + $uniqueIndexes = []; + + foreach ($indexes as $index) { + $indexName = $index['name']; + $indexInfo = $this->db->createCommand("PRAGMA index_info(" . $this->quoteValue($index['name']) . ")")->queryAll(); + + if ($index['unique']) { + $uniqueIndexes[$indexName] = []; + foreach ($indexInfo as $row) { + $uniqueIndexes[$indexName][] = $row['name']; + } + } + } + return $uniqueIndexes; + } + + /** * Loads the column information into a [[ColumnSchema]] object. * @param array $info column information * @return ColumnSchema the column schema object