From 4d69d8f1cc46e2dfee7e818b2679dc76b757af66 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Wed, 23 Sep 2020 18:17:48 +0200
Subject: [PATCH] [TASK] Drop reference index in workspace discard more
 effectively

Dealing with workspace-discard, where rows are always fully
dropped in DB, the expensive reference index operation does
not need to be performed at all. It can be substituted with
straight db-delete calls for affected sys_refindex rows.

Change-Id: Iaa61ef2345c63394fa3286cc9d5dabc5b1a4bb55
Resolves: #92392
Releases: master, 10.4
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65841
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../core/Classes/DataHandling/DataHandler.php | 32 ++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index 4d1872724fa4..1b4ff291be87 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -5395,7 +5395,7 @@ class DataHandler implements LoggerAwareInterface
         $this->discardRecordRelations($table, $versionRecord);
         $this->hardDeleteSingleRecord($table, (int)$versionRecord['uid']);
         $this->deletedRecords[$table][] = (int)$versionRecord['uid'];
-        $this->updateRefIndex($table, (int)$versionRecord['uid']);
+        $this->dropReferenceIndexRowsForRecord($table, (int)$versionRecord['uid']);
         $this->getRecordHistoryStore()->deleteRecord($table, (int)$versionRecord['uid'], $this->correlationId);
         $this->log(
             $table,
@@ -5516,6 +5516,7 @@ class DataHandler implements LoggerAwareInterface
                 $dbAnalysis->start($value, $allowedTables, $fieldConfig['MM'], (int)$record['uid'], $table, $fieldConfig);
                 foreach ($dbAnalysis->itemArray as $relationRecord) {
                     // @todo: Something should happen with these relations here ...
+                    // @todo: Can't use dropReferenceIndexRowsForRecord() here, this would drop sys_refindex entries we want to keep
                     $this->updateRefIndex($relationRecord['table'], (int)$relationRecord['id']);
                 }
             }
@@ -7277,6 +7278,35 @@ class DataHandler implements LoggerAwareInterface
         }
     }
 
+    /**
+     * Delete rows from sys_refindex a table / uid combination is involved in:
+     * Either on left side (tablename + recuid) OR right side (ref_table + ref_uid).
+     * Useful in scenarios like workspace-discard where parents or children are hard deleted: The
+     * expensive updateRefIndex() does not need to be called since we can just drop straight ahead.
+     *
+     * @param string $table Table name, used as tablename and ref_table
+     * @param int $uid Record uid, used as recuid and ref_uid
+     */
+    protected function dropReferenceIndexRowsForRecord(string $table, int $uid): void
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
+        $queryBuilder->delete('sys_refindex')
+            ->where(
+                $queryBuilder->expr()->eq('workspace', $queryBuilder->createNamedParameter((int)$this->BE_USER->workspace, \PDO::PARAM_INT)),
+                $queryBuilder->expr()->orX(
+                    $queryBuilder->expr()->andX(
+                        $queryBuilder->expr()->eq('tablename', $queryBuilder->createNamedParameter($table)),
+                        $queryBuilder->expr()->eq('recuid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                    ),
+                    $queryBuilder->expr()->andX(
+                        $queryBuilder->expr()->eq('ref_table', $queryBuilder->createNamedParameter($table)),
+                        $queryBuilder->expr()->eq('ref_uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                    )
+                )
+            )
+            ->execute();
+    }
+
     /*********************************************
      *
      * Misc functions
-- 
GitLab