Ensure explicit database INDEX names
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 30 Sep 2021 14:27:38 +0000 (16:27 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 30 Sep 2021 14:36:25 +0000 (16:36 +0200)
Checking all revisions of all `.sql` files returned that a INDEX was never
added to an existing table using `ALTER TABLE`. Thus this update script should
not result in changes in *any* installation out there, making this process
quite fast even in large communities. It is added and should be execute
nonetheless for full correctness.

The following fish script was used to check the revisions:

    for file in (g log 2bf40f755228eeae2902562471acf14177777eb6..HEAD --diff-filter=D --no-renames --summary |awk '/delete mode/{print $NF}' |grep '.sql$')
     for rev in (git rev-list --all -- $file)
     git show $rev:$file
     end
    end 2>&1 |grep -v '^fatal:' |grep '^ALTER' |sort -u

see WoltLab/WCF#4505

files/acp/database/update_com.woltlab.wcf.conversation_5.5_step1.php [new file with mode: 0644]
files/acp/database/update_com.woltlab.wcf.conversation_5.5_step2.php [new file with mode: 0644]

diff --git a/files/acp/database/update_com.woltlab.wcf.conversation_5.5_step1.php b/files/acp/database/update_com.woltlab.wcf.conversation_5.5_step1.php
new file mode 100644 (file)
index 0000000..650db8d
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @author  Tim Duesterhus
+ * @copyright   2001-2020 WoltLab GmbH
+ * @license WoltLab License <http://www.woltlab.com/license-agreement.html>
+ */
+
+// Reuse the install script to create the indices with the correct names.
+
+return require(__DIR__ . '/install_com.woltlab.wcf.conversation.php');
diff --git a/files/acp/database/update_com.woltlab.wcf.conversation_5.5_step2.php b/files/acp/database/update_com.woltlab.wcf.conversation_5.5_step2.php
new file mode 100644 (file)
index 0000000..3ecc7ec
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @author  Tim Duesterhus
+ * @copyright   2001-2021 WoltLab GmbH
+ * @license WoltLab License <http://www.woltlab.com/license-agreement.html>
+ */
+
+use wcf\system\database\table\index\DatabaseTableIndex;
+use wcf\system\database\table\index\DatabaseTablePrimaryIndex;
+use wcf\system\database\table\PartialDatabaseTable;
+
+// 1) Generate a blueprint to fill in the generated index names.
+
+$blueprint = [
+    PartialDatabaseTable::create('wcf1_conversation')
+        ->indices([
+            // DatabaseTablePrimaryIndex::create()
+            //    ->columns(['conversationID']),
+            DatabaseTableIndex::create()
+                ->columns(['userID', 'isDraft']),
+        ]),
+    PartialDatabaseTable::create('wcf1_conversation_to_user')
+        ->indices([
+            DatabaseTableIndex::create()
+                ->columns(['participantID', 'conversationID'])
+                ->type(DatabaseTableIndex::UNIQUE_TYPE),
+            // DatabaseTableIndex::create()
+            //    ->columns(['participantID', 'hideConversation']),
+        ]),
+    PartialDatabaseTable::create('wcf1_conversation_message')
+        ->indices([
+            // DatabaseTablePrimaryIndex::create()
+            //    ->columns(['messageID']),
+            DatabaseTableIndex::create()
+                ->columns(['conversationID', 'userID']),
+            DatabaseTableIndex::create()
+                ->columns(['ipAddress']),
+        ]),
+    PartialDatabaseTable::create('wcf1_conversation_label')
+        ->indices([
+            // DatabaseTablePrimaryIndex::create()
+            //    ->columns(['labelID']),
+        ]),
+    PartialDatabaseTable::create('wcf1_conversation_label_to_object')
+        ->indices([
+            DatabaseTableIndex::create()
+                ->columns(['labelID', 'conversationID'])
+                ->type(DatabaseTableIndex::UNIQUE_TYPE),
+        ]),
+];
+
+// 2) Use this blueprint to recreate the index objects with ->generatedName() set to false.
+// Simply dropping the indices with ->generatedName() set to true does not work, because it will
+// also remove named indices as the fact that a name was generated does not persist to the database.
+
+$data = [];
+foreach ($blueprint as $blueprintTable) {
+    $data[] = PartialDatabaseTable::create($blueprintTable->getName())
+        ->indices(\array_map(static function ($index) {
+            \assert($index instanceof DatabaseTableIndex);
+
+            return DatabaseTableIndex::create($index->getName())
+                ->columns($index->getColumns())
+                ->type($index->getType())
+                ->drop();
+        }, $blueprintTable->getIndices()));
+}
+
+return $data;