Fix column logs if renaming database column that was added later
authorMatthias Schmidt <gravatronics@live.com>
Sun, 6 Dec 2020 13:09:21 +0000 (14:09 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 6 Dec 2020 13:09:21 +0000 (14:09 +0100)
wcfsetup/install/files/lib/system/database/table/DatabaseTableChangeProcessor.class.php

index 329cc79eec37971733c95d445e88d8c35849f660..54436c8eca908eb43f3d3a94c9f9899a9265e3a3 100644 (file)
@@ -249,6 +249,14 @@ class DatabaseTableChangeProcessor {
                                $this->prepareColumnLog($tableName, $column);
                        }
                        
+                       $renamedColumnsWithLog = [];
+                       foreach ($columnsToAlter as $column) {
+                               if ($column->getNewName() && $this->getColumnLog($tableName, $column) !== null) {
+                                       $this->prepareColumnLog($tableName, $column, true);
+                                       $renamedColumnsWithLog[] = $column;
+                               }
+                       }
+                       
                        $this->applyColumnChanges(
                                $tableName,
                                $columnsToAdd,
@@ -260,6 +268,11 @@ class DatabaseTableChangeProcessor {
                                $this->finalizeColumnLog($tableName, $column);
                        }
                        
+                       foreach ($renamedColumnsWithLog as $column) {
+                               $this->finalizeColumnLog($tableName, $column, true);
+                               $this->deleteColumnLog($tableName, $column);
+                       }
+                       
                        foreach ($columnsToDrop as $column) {
                                $this->deleteColumnLog($tableName, $column);
                        }
@@ -324,7 +337,7 @@ class DatabaseTableChangeProcessor {
                $columnData = [];
                foreach ($droppedColumns as $droppedColumn) {
                        $columnData[$droppedColumn->getName()] = [
-                               'action' => 'drop'
+                               'action' => 'drop',
                        ];
                        
                        foreach ($this->getExistingTable($tableName)->getForeignKeys() as $foreignKey) {
@@ -336,14 +349,14 @@ class DatabaseTableChangeProcessor {
                foreach ($addedColumns as $addedColumn) {
                        $columnData[$addedColumn->getName()] = [
                                'action' => 'add',
-                               'data' => $addedColumn->getData()
+                               'data' => $addedColumn->getData(),
                        ];
                }
                foreach ($alteredColumns as $alteredColumn) {
                        $columnData[$alteredColumn->getName()] = [
                                'action' => 'alter',
                                'data' => $alteredColumn->getData(),
-                               'newColumnName' => $alteredColumn->getNewName() ?? $alteredColumn->getName()
+                               'newColumnName' => $alteredColumn->getNewName() ?? $alteredColumn->getName(),
                        ];
                }
                
@@ -816,9 +829,13 @@ class DatabaseTableChangeProcessor {
         * 
         * @param       string                  $tableName
         * @param       IDatabaseTableColumn    $column
+        * @param       bool                    $useNewName
         */
-       protected function finalizeColumnLog($tableName, IDatabaseTableColumn $column) {
-               $this->finalizeLog(['sqlTable' => $tableName, 'sqlColumn' => $column->getName()]);
+       protected function finalizeColumnLog($tableName, IDatabaseTableColumn $column, bool $useNewName = false) {
+               $this->finalizeLog([
+                       'sqlTable' => $tableName,
+                       'sqlColumn' => $useNewName ? $column->getNewName() : $column->getName(),
+               ]);
        }
        
        /**
@@ -873,6 +890,37 @@ class DatabaseTableChangeProcessor {
                $this->finalizeLog(['sqlTable' => $table->getName()]);
        }
        
+       /**
+        * Returns the log entry for the given column or `null` if there is no explicit entry for
+        * this column.
+        * 
+        * @param       string                  $tableName
+        * @param       IDatabaseTableColumn    $column
+        * @return      array|null
+        * @since       5.4
+        */
+       protected function getColumnLog(string $tableName, IDatabaseTableColumn $column): ?array {
+               $sql = "SELECT  *
+                       FROM    wcf" . WCF_N . "_package_installation_sql_log
+                       WHERE   packageID = ?
+                               AND sqlTable = ?
+                               AND sqlColumn = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               
+               $statement->execute([
+                       $this->package->packageID,
+                       $tableName,
+                       $column->getName(),
+               ]);
+               
+               $row = $statement->fetchSingleRow();
+               if ($row === false) {
+                       return null;
+               }
+               
+               return $row;
+       }
+       
        /**
         * Returns the id of the package to with the given column belongs to. If there is no specific
         * log entry for the given column, the table log is checked and the relevant package id of
@@ -952,9 +1000,13 @@ class DatabaseTableChangeProcessor {
         * 
         * @param       string                  $tableName
         * @param       IDatabaseTableColumn    $column
+        * @param       bool                    $useNewName
         */
-       protected function prepareColumnLog($tableName, IDatabaseTableColumn $column) {
-               $this->prepareLog(['sqlTable' => $tableName, 'sqlColumn' => $column->getName()]);
+       protected function prepareColumnLog($tableName, IDatabaseTableColumn $column, bool $useNewName = false) {
+               $this->prepareLog([
+                       'sqlTable' => $tableName,
+                       'sqlColumn' => $useNewName ? $column->getNewName() : $column->getName(),
+               ]);
        }
        
        /**