From d376da57e49ecb142e67311b567b548381a32108 Mon Sep 17 00:00:00 2001 From: Luciano Baraglia Date: Wed, 25 Dec 2013 18:08:50 -0300 Subject: [PATCH 1/2] Get DB unique indexes information --- framework/yii/db/Schema.php | 22 ++++++++++ framework/yii/db/mysql/Schema.php | 45 +++++++++++++++++++- framework/yii/db/pgsql/Schema.php | 68 ++++++++++++++++++++++++++++++ framework/yii/db/sqlite/Schema.php | 34 +++++++++++++++ 4 files changed, 167 insertions(+), 2 deletions(-) diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php index f2ae94c5f2..4730ec2ad4 100644 --- a/framework/yii/db/Schema.php +++ b/framework/yii/db/Schema.php @@ -247,6 +247,28 @@ abstract class Schema extends Object throw new NotSupportedException(get_class($this) . ' does not support fetching all table names.'); } + /** + * 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 + */ + protected 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) diff --git a/framework/yii/db/mysql/Schema.php b/framework/yii/db/mysql/Schema.php index f55d38fc17..5e8412276e 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)) { @@ -234,6 +245,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. + */ + protected 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. diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index eb7de372af..d18ca46630 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -226,6 +226,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. + */ + protected 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 diff --git a/framework/yii/db/sqlite/Schema.php b/framework/yii/db/sqlite/Schema.php index 8633650f07..164feb300b 100644 --- a/framework/yii/db/sqlite/Schema.php +++ b/framework/yii/db/sqlite/Schema.php @@ -158,6 +158,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. + */ + protected 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 From 89f0bfe1002985cf351792ae366f6f56ee5e3bb0 Mon Sep 17 00:00:00 2001 From: Luciano Baraglia Date: Wed, 25 Dec 2013 18:27:54 -0300 Subject: [PATCH 2/2] Making accesors public --- framework/yii/db/Schema.php | 2 +- framework/yii/db/mysql/Schema.php | 2 +- framework/yii/db/pgsql/Schema.php | 2 +- framework/yii/db/sqlite/Schema.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php index 4730ec2ad4..46288a2ebc 100644 --- a/framework/yii/db/Schema.php +++ b/framework/yii/db/Schema.php @@ -264,7 +264,7 @@ abstract class Schema extends Object * @return array all unique indexes for the given table. * @throws NotSupportedException if this method is called */ - protected function findUniqueIndexes($schema = '') + public function findUniqueIndexes($schema = '') { throw new NotSupportedException(get_class($this) . ' does not support getting unique indexes information.'); } diff --git a/framework/yii/db/mysql/Schema.php b/framework/yii/db/mysql/Schema.php index 5e8412276e..075389eb8c 100644 --- a/framework/yii/db/mysql/Schema.php +++ b/framework/yii/db/mysql/Schema.php @@ -259,7 +259,7 @@ class Schema extends \yii\db\Schema * @param TableSchema $table the table metadata * @return array all unique indexes for the given table. */ - protected function findUniqueIndexes($table) + public function findUniqueIndexes($table) { $sql = $this->getCreateTableSql($table); $uniqueIndexes = []; diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php index d18ca46630..96889ab3b0 100644 --- a/framework/yii/db/pgsql/Schema.php +++ b/framework/yii/db/pgsql/Schema.php @@ -273,7 +273,7 @@ SQL; * @param TableSchema $table the table metadata * @return array all unique indexes for the given table. */ - protected function findUniqueIndexes($table) + public function findUniqueIndexes($table) { $indexes = $this->getUniqueIndexInformation($table); $uniqueIndexes = []; diff --git a/framework/yii/db/sqlite/Schema.php b/framework/yii/db/sqlite/Schema.php index 164feb300b..9f410b4d41 100644 --- a/framework/yii/db/sqlite/Schema.php +++ b/framework/yii/db/sqlite/Schema.php @@ -172,7 +172,7 @@ class Schema extends \yii\db\Schema * @param TableSchema $table the table metadata * @return array all unique indexes for the given table. */ - protected function findUniqueIndexes($table) + public function findUniqueIndexes($table) { $sql = "PRAGMA index_list(" . $this->quoteSimpleTableName($table->name) . ')'; $indexes = $this->db->createCommand($sql)->queryAll();