Support updating explicitly named database table indices
authorMatthias Schmidt <gravatronics@live.com>
Sat, 7 Dec 2019 09:19:56 +0000 (10:19 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Sat, 7 Dec 2019 09:19:56 +0000 (10:19 +0100)
Close #3116

wcfsetup/install/files/lib/system/database/table/DatabaseTable.class.php
wcfsetup/install/files/lib/system/database/table/DatabaseTableChangeProcessor.class.php
wcfsetup/install/files/lib/system/database/table/index/DatabaseTableIndex.class.php

index 9ef900887de78721de4c92fbc698decfeaa10f96..21b96c55a3240a0c050a3cad22979ccf3f379dba 100644 (file)
@@ -211,7 +211,7 @@ class DatabaseTable {
                        }
                        
                        if ($index->getName() === '') {
-                               $index->name(md5($this->getName() . '_' . $index->getColumns()[0]));
+                               $index->generatedName(md5($this->getName() . '_' . $index->getColumns()[0]));
                        }
                        
                        if (isset($this->foreignKeys[$index->getName()])) {
index 43e4b88010b87064885562f350810e1019fd7947..b0897945cecab5043c559f8520d6640832773a23 100644 (file)
@@ -282,22 +282,22 @@ class DatabaseTableChangeProcessor {
                        }
                }
                
-               foreach ($this->indicesToAdd as $tableName => $indices) {
+               foreach ($this->indicesToDrop as $tableName => $indices) {
                        foreach ($indices as $index) {
                                $appliedAnyChange = true;
                                
-                               $this->prepareIndexLog($tableName, $index);
-                               $this->addIndex($tableName, $index);
-                               $this->finalizeIndexLog($tableName, $index);
+                               $this->dropIndex($tableName, $index);
+                               $this->deleteIndexLog($tableName, $index);
                        }
                }
                
-               foreach ($this->indicesToDrop as $tableName => $indices) {
+               foreach ($this->indicesToAdd as $tableName => $indices) {
                        foreach ($indices as $index) {
                                $appliedAnyChange = true;
                                
-                               $this->dropIndex($tableName, $index);
-                               $this->deleteIndexLog($tableName, $index);
+                               $this->prepareIndexLog($tableName, $index);
+                               $this->addIndex($tableName, $index);
+                               $this->finalizeIndexLog($tableName, $index);
                        }
                }
                
@@ -459,7 +459,7 @@ class DatabaseTableChangeProcessor {
                                foreach ($table->getIndices() as $index) {
                                        $matchingExistingIndex = null;
                                        foreach ($existingIndices as $existingIndex) {
-                                               if (empty(array_diff($index->getData(), $existingIndex->getData()))) {
+                                               if (!$this->diffIndices($existingIndex, $index)) {
                                                        $matchingExistingIndex = $existingIndex;
                                                        break;
                                                }
@@ -479,7 +479,23 @@ class DatabaseTableChangeProcessor {
                                                        $this->deleteIndexLog($tableName, $index);
                                                }
                                        }
-                                       else if ($matchingExistingIndex === null) {
+                                       else if ($matchingExistingIndex !== null) {
+                                               // updating index type and index columns is supported with an
+                                               // explicit index name is given (automatically generated index
+                                               // names are not deterministic)
+                                               if (!$index->hasGeneratedName() && !empty(array_diff($matchingExistingIndex->getData(), $index->getData()))) {
+                                                       if (!isset($this->indicesToDrop[$tableName])) {
+                                                               $this->indicesToDrop[$tableName] = [];
+                                                       }
+                                                       $this->indicesToDrop[$tableName][] = $matchingExistingIndex;
+                                                       
+                                                       if (!isset($this->indicesToAdd[$tableName])) {
+                                                               $this->indicesToAdd[$tableName] = [];
+                                                       }
+                                                       $this->indicesToAdd[$tableName][] = $index;
+                                               }
+                                       }
+                                       else {
                                                if (!isset($this->indicesToAdd[$tableName])) {
                                                        $this->indicesToAdd[$tableName] = [];
                                                }
@@ -678,6 +694,21 @@ class DatabaseTableChangeProcessor {
                return $oldColumn->getDefaultValue() != $newColumn->getDefaultValue();
        }
        
+       /**
+        * Returns `true` if the two indices differ.
+        * 
+        * @param       DatabaseTableIndex      $oldIndex
+        * @param       DatabaseTableIndex      $newIndex
+        * @return      bool
+        */
+       protected function diffIndices(DatabaseTableIndex $oldIndex, DatabaseTableIndex $newIndex) {
+               if ($newIndex->hasGeneratedName()) {
+                       return !empty(array_diff($oldIndex->getData(), $newIndex->getData()));
+               }
+               
+               return $oldIndex->getName() !== $newIndex->getName();
+       }
+       
        /**
         * Drops the given foreign key.
         * 
index 747001eb5cb9ae89652672700e42019c4c3bd3ce..746d7e8c20def535210b17a6bfd5cebf810e4294 100644 (file)
@@ -20,6 +20,12 @@ class DatabaseTableIndex {
         */
        protected $columns;
        
+       /**
+        * is `true` if index name has been automatically generated
+        * @var bool
+        */
+       protected $generatedName = false;
+       
        /**
         * name of index
         * @var string
@@ -57,6 +63,19 @@ class DatabaseTableIndex {
                
                return $this;
        }
+
+       /**
+        * Sets the automatically generated name of the index.
+        * 
+        * @param       string          $name           index name
+        * @return      $this                           this index
+        */
+       public function generatedName($name) {
+               $this->name($name);
+               $this->generatedName = true;
+               
+               return $this;
+       }
        
        /**
         * Returns the index columns.
@@ -97,6 +116,15 @@ class DatabaseTableIndex {
                return $this->type;
        }
        
+       /**
+        * Returns `true` if the name of the index has been automatically generated.
+        * 
+        * @return      bool
+        */
+       public function hasGeneratedName() {
+               return $this->generatedName;
+       }
+       
        /**
         * Sets the name of the index.
         *