From d6a075f9c7f600e2ede80cc0d02b7e4f9e9ef6a3 Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Mon, 7 Jan 2013 16:25:31 +1300 Subject: [PATCH] Fixing MSSQLDatabase to conform to dev/build change detection This involves changing a few things around so that it's closer to how the MySQLDatabase adapter works. indexList() should return an array in the same format instead of using arbitrary "indexname" and "spec". indexNames() has also been introduced to MSSQLDatabase so that we can drop all indexes (except for fulltext and primary key indexes) on a table when altering the table columns, this helps when constraints not directly related to a modified column refuse to allow changes. --- code/MSSQLDatabase.php | 53 ++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/code/MSSQLDatabase.php b/code/MSSQLDatabase.php index fad8a4e..ba536e3 100644 --- a/code/MSSQLDatabase.php +++ b/code/MSSQLDatabase.php @@ -613,8 +613,11 @@ class MSSQLDatabase extends SS_Database { // drop the index if it exists $alterCol=''; - $indexName = isset($indexList[$colName]['indexname']) ? $indexList[$colName]['indexname'] : null; - if($indexName && $colName != 'ID') { + + // drop *ALL* indexes on a table before proceeding + // this won't drop primary keys, though + $indexes = $this->indexNames($tableName); + foreach($indexes as $indexName) { $alterCol = "\nDROP INDEX \"$indexName\" ON \"$tableName\";"; } @@ -815,10 +818,10 @@ class MSSQLDatabase extends SS_Database { * Some indexes may be arrays, such as fulltext and unique indexes, and this allows database-specific * arrays to be created. */ - public function convertIndexSpec($indexSpec){ - if(is_array($indexSpec)){ + public function convertIndexSpec($indexSpec) { + if(is_array($indexSpec)) { //Here we create a db-specific version of whatever index we need to create. - switch($indexSpec['type']){ + switch($indexSpec['type']) { case 'fulltext': $indexSpec='fulltext (' . str_replace(' ', '', $indexSpec['value']) . ')'; break; @@ -906,34 +909,50 @@ class MSSQLDatabase extends SS_Database { foreach($indexes as $index) { if(strpos($index['index_description'], 'unique') !== false) { - $prefix='unique '; + $prefix = 'unique '; } - $key = str_replace(', ', ',', $index['index_keys']); - $indexList[$key]['indexname'] = $index['index_name']; - $indexList[$key]['spec'] = $prefix . '(' . $key . ')'; + $name = str_replace(', ', ',', $index['index_keys']); + + // ensure each piece of the index name is quoted, e.g. RecordID,Version + // should be "RecordID","Version" + $fields = explode(',', $name); + if(!$fields) $fields = array($name); + ksort($fields); + + $indexList[$name] = $prefix . '("' . implode('","', $fields) . '")'; } - // Now we need to check to see if we have any fulltext indexes attached to this table: + // separately build up a list of the fulltext indexes for this table + // as MSSQL doesn't return fulltext indexes in sp_helpindex if($this->fullTextEnabled()) { $result = DB::query('EXEC sp_help_fulltext_columns;'); - $columns = ''; + $columns = array(); + foreach($result as $row) { if($row['TABLE_NAME'] == $table) { - $columns .= $row['FULLTEXT_COLUMN_NAME'] . ','; + $columns[] = $row['FULLTEXT_COLUMN_NAME']; } } - if($columns!=''){ - $columns=trim($columns, ','); - $indexList['SearchFields']['indexname'] = 'SearchFields'; - $indexList['SearchFields']['spec'] = 'fulltext (' . $columns . ')'; - } + $indexList['SearchFields'] = 'fulltext ("' . implode('","', $columns) . '")'; } return $indexList; } + /** + * For a given table name, get all the internal index names, + * except for those that are primary keys and fulltext indexes. + * + * @return array + */ + public function indexNames($tableName) { + return $this->query(sprintf('SELECT ind.name FROM sys.indexes ind + INNER JOIN sys.tables t ON ind.object_id = t.object_id + WHERE is_primary_key = 0 AND t.name = \'%s\'', $tableName))->column(); + } + /** * Returns a list of all the tables in the database. * Table names will all be in lowercase.