From 01ed8eb792876f9915b6183482ef101080ad31d5 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Wed, 23 Sep 2020 00:37:07 +0200
Subject: [PATCH] [BUGFIX] Properly update reference index when deleting
 children

When deleting children in a relation, reference index rows
pointing to a child must be updated, otherwise dangling
reference index rows are left, leading to all kinds of trouble.

Change-Id: I8e8086846ae53c5a32aafc553b6ea66d4a17d7fb
Resolves: #67676
Releases: master, 10.4
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65809
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benni Mack <benni@typo3.org>
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 | 29 ++++++++++++++++-
 .../FAL/AbstractActionTestCase.php            | 21 ++++++++++++
 .../DataHandling/FAL/Modify/ActionTest.php    | 10 ++++++
 ...tentWFileReferenceNDeleteFileReference.csv | 17 ++++++++++
 .../modifyContentNDeleteAllFileReference.csv  |  2 --
 .../modifyContentNDeleteFileReference.csv     |  3 +-
 .../Group/DataSet/ReferenceIndex.csv          |  1 +
 .../DataSet/deleteElementOfRelation.csv       |  5 +--
 .../DataSet/modifyParentNDeleteHotelChild.csv |  1 -
 .../Select/DataSet/ReferenceIndex.csv         |  1 +
 .../DataSet/deleteElementOfRelation.csv       |  4 +--
 .../DataHandling/FAL/Discard/ActionTest.php   | 11 +++++++
 ...tentWFileReferenceNDeleteFileReference.csv | 30 +++++++++++++++++
 .../DataHandling/FAL/Modify/ActionTest.php    | 10 ++++++
 ...tentWFileReferenceNDeleteFileReference.csv | 32 +++++++++++++++++++
 .../DataHandling/FAL/Publish/ActionTest.php   | 11 +++++++
 ...tentWFileReferenceNDeleteFileReference.csv | 31 ++++++++++++++++++
 .../FAL/PublishAll/ActionTest.php             | 11 +++++++
 ...tentWFileReferenceNDeleteFileReference.csv | 31 ++++++++++++++++++
 19 files changed, 251 insertions(+), 10 deletions(-)
 create mode 100644 typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
 create mode 100644 typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/DataSet/createContentWFileReferenceNDeleteFileReference.csv
 create mode 100644 typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
 create mode 100644 typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/DataSet/createContentWFileReferenceNDeleteFileReference.csv
 create mode 100644 typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/DataSet/createContentWFileReferenceNDeleteFileReference.csv

diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index 769f5a2e7be9..b4a871a13591 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -4855,8 +4855,10 @@ class DataHandler implements LoggerAwareInterface
             $this->getRecordHistoryStore()->deleteRecord($table, $uid, $this->correlationId);
         }
 
-        // Update reference index:
+        // Update reference index with table/uid on left side (recuid)
         $this->updateRefIndex($table, $uid);
+        // Update reference index with table/uid on right side (ref_uid). Important if children of a relation are deleted / undeleted.
+        $this->registerReferenceUpdatesForReferencesToItem($table, $uid);
     }
 
     /**
@@ -7239,6 +7241,31 @@ class DataHandler implements LoggerAwareInterface
         $this->referenceIndexUpdater->registerForUpdate((string)$table, (int)$uid, (int)$this->BE_USER->workspace);
     }
 
+    /**
+     * Find reference index rows pointing to given table/uid combination and register them for update.
+     * Important in delete scenarios where a child is deleted to make sure any references to this child are dropped, too.
+     *
+     * @param string $table Table name, used as ref_table
+     * @param int $uid Record uid, used as ref_uid
+     */
+    protected function registerReferenceUpdatesForReferencesToItem(string $table, int $uid): void
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
+        $statement = $queryBuilder
+            ->select('tablename', 'recuid')
+            ->from('sys_refindex')
+            ->where(
+                $queryBuilder->expr()->eq('ref_table', $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)),
+                $queryBuilder->expr()->eq('ref_uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
+                $queryBuilder->expr()->eq('deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
+                $queryBuilder->expr()->eq('workspace', $queryBuilder->createNamedParameter((int)$this->BE_USER->workspace, \PDO::PARAM_INT))
+            )
+            ->execute();
+        while ($row = $statement->fetch()) {
+            $this->updateRefIndex($row['tablename'], (int)$row['recuid']);
+        }
+    }
+
     /*********************************************
      *
      * Misc functions
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/AbstractActionTestCase.php b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/AbstractActionTestCase.php
index 41e50f7dcb4f..5d71c41d1938 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/AbstractActionTestCase.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/AbstractActionTestCase.php
@@ -168,4 +168,25 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
             [self::TABLE_FileReference => [self::VALUE_FileReferenceContentLastFileFirst, self::VALUE_FileReferenceContentLastFileLast]]
         );
     }
+
+    protected function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        // Create content element with a file reference
+        $newTableIds = $this->actionService->createNewRecords(
+            self::VALUE_PageId,
+            [
+                self::TABLE_Content => ['header' => 'Testing #1', self::FIELD_ContentImage => '__nextUid'],
+                self::TABLE_FileReference => ['title' => 'Image #1', self::FIELD_FileReferenceImage => self::VALUE_FileIdFirst],
+            ]
+        );
+        $this->recordIds['newContentId'] = $newTableIds[self::TABLE_Content][0];
+        $this->recordIds['newSysFileReference'] = $newTableIds[self::TABLE_FileReference][0];
+        // Delete the file reference again, but keep the content element
+        $this->actionService->modifyRecord(
+            self::TABLE_Content,
+            $this->recordIds['newContentId'],
+            [self::FIELD_ContentImage => ''],
+            [self::TABLE_FileReference => [$this->recordIds['newSysFileReference']]]
+        );
+    }
 }
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
index e525e7f3a338..ebb6d477a419 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
@@ -272,4 +272,14 @@ class ActionTest extends AbstractActionTestCase
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField(self::FIELD_ContentImage)
             ->setTable(self::TABLE_FileReference)->setField('title')->setValues('Taken at T3BOARD', 'This is Kasper'));
     }
+
+    /**
+     * @test
+     */
+    public function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        parent::createContentWithFileReferenceAndDeleteFileReference();
+        $this->assertAssertionDataSet('createContentWFileReferenceNDeleteFileReference');
+        // No FE test: Create and delete scenarios have FE coverage, this test is only about DB state.
+    }
 }
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
new file mode 100644
index 000000000000..364350063b3f
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
@@ -0,0 +1,17 @@
+"sys_file_reference",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","uid_local","uid_foreign","tablenames","fieldname","sorting_foreign","table_local","title","description","alternative","link"
+,126,89,0,0,0,0,0,0,0,0,1,330,"tt_content","image",2,"sys_file","T3BOARD",,,
+,127,89,0,0,0,0,0,0,0,0,21,330,"tt_content","image",1,"sys_file","Kasper",,,
+,128,89,0,0,0,0,0,0,0,0,21,331,"tt_content","image",1,"sys_file","Taken at T3BOARD",,,
+,129,89,0,0,0,0,0,0,0,0,1,331,"tt_content","image",2,"sys_file","This is Kasper",,,
+,130,89,1,0,0,0,0,0,0,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+"tt_content",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image",,,,,,,
+,330,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,,,,,
+,331,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",2,,,,,,,
+,332,89,128,0,0,0,0,0,0,0,0,"Testing #1",0,,,,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
+,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
+,"788fed77d153954bc5cfd013f123e444","sys_file_reference",130,"uid_local",0,1,0,"sys_file",1,,,,,,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteAllFileReference.csv b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteAllFileReference.csv
index 766adc6c8a3c..c7bd75d6427a 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteAllFileReference.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteAllFileReference.csv
@@ -10,8 +10,6 @@
 ,331,89,512,0,0,0,0,0,0,0,0,0,"Regular Element #2",0,,,,,,
 "sys_refindex",,,,,,,,,,,,,,,,,,,,
 ,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
-,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
-,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
 ,"fb266d0b94cee39b87fe03b9b7875c25","sys_file_reference",129,"uid_local",0,1,0,"sys_file",1,,,,,,,,,,,
 ,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
 ,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteFileReference.csv b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteFileReference.csv
index 95b0162fbf3d..b11efab0644b 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteFileReference.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/FAL/Modify/DataSet/modifyContentNDeleteFileReference.csv
@@ -11,8 +11,7 @@
 "sys_refindex",,,,,,,,,,,,,,,,,,,,
 ,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
 ,"c08c2538c324b0a98b0957bc4bdf36ae","sys_file_reference",129,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
-,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
-,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
+,"997297edc2047a0fd48ffc237299a902","tt_content",331,"image",0,0,0,"sys_file_reference",129,,,,,,,,,,,
 ,"0b7edf2205371519698cdfbf6e0cc6e7","sys_file_reference",128,"uid_local",0,1,0,"sys_file",21,,,,,,,,,,,
 ,"6588728f1c2f2069b4b781ab1d102fff","sys_file",21,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
 ,"ff0a9ca5f364b75bccb699b74d167c83","sys_file",21,"metadata",0,0,0,"sys_file_metadata",21,,,,,,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Group/DataSet/ReferenceIndex.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Group/DataSet/ReferenceIndex.csv
index 1eb737c73f22..3df039d3a25f 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/Group/DataSet/ReferenceIndex.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/Group/DataSet/ReferenceIndex.csv
@@ -2,5 +2,6 @@
 ,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","deleted","ref_table","ref_uid","ref_string"
 ,"0c81d9b3f27460380a2e442fdfa0649d","tt_content",298,"tx_testdatahandler_group",,,,0,0,"tx_testdatahandler_element",2,
 ,"8f3d6a0de293045066188fc790f4805f","tt_content",298,"tx_testdatahandler_group",,,,1,0,"tx_testdatahandler_element",3,
+# @todo: The hash fields of next 2 rows are probably wrong
 ,"70386199b2e7d7e3be07ec7b501f411d","tt_content",297,"tx_testdatahandler_group",,,,0,0,"tx_testdatahandler_element",1,
 ,"3f113b20cdf1b3be96048a257872a178","tt_content",297,"tx_testdatahandler_group",,,,1,0,"tx_testdatahandler_element",2,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Group/Modify/DataSet/deleteElementOfRelation.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Group/Modify/DataSet/deleteElementOfRelation.csv
index b23201628755..0f1aedcc333f 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/Group/Modify/DataSet/deleteElementOfRelation.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/Group/Modify/DataSet/deleteElementOfRelation.csv
@@ -17,5 +17,6 @@
 ,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,
 ,"0c81d9b3f27460380a2e442fdfa0649d","tt_content",298,"tx_testdatahandler_group",0,0,0,"tx_testdatahandler_element",2,,,,,
 ,"8f3d6a0de293045066188fc790f4805f","tt_content",298,"tx_testdatahandler_group",1,0,0,"tx_testdatahandler_element",3,,,,,
-,"70386199b2e7d7e3be07ec7b501f411d","tt_content",297,"tx_testdatahandler_group",0,0,0,"tx_testdatahandler_element",1,,,,,
-,"3f113b20cdf1b3be96048a257872a178","tt_content",297,"tx_testdatahandler_group",1,0,0,"tx_testdatahandler_element",2,,,,,
+# @todo: Next row should be gone or deleted=1 - issue in ReferenceIndex group handling?
+,"67070566eb5b788c5edd02dbdbc63da1","tt_content",297,"tx_testdatahandler_group",0,0,0,"tx_testdatahandler_element",1,,,,,
+,"250d3cfe7e1d9944e5c1e3bd086390e9","tt_content",297,"tx_testdatahandler_group",1,0,0,"tx_testdatahandler_element",2,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/modifyParentNDeleteHotelChild.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/modifyParentNDeleteHotelChild.csv
index c993ecffa03b..3fb657b115c0 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/modifyParentNDeleteHotelChild.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/modifyParentNDeleteHotelChild.csv
@@ -28,4 +28,3 @@
 ,"991035e9a032ce5a95b3dbc7f2f31471","tx_irretutorial_1nff_hotel",3,"offers",0,0,0,"tx_irretutorial_1nff_offer",5,,,,,,,,
 ,"3a59a2c65f05196774ee38fad12b11a8","tx_irretutorial_1nff_hotel",3,"offers",1,0,0,"tx_irretutorial_1nff_offer",6,,,,,,,,
 ,"d445fd78a1e37837ce5cb8cfca3c3159","tt_content",297,"tx_irretutorial_1nff_hotels",0,0,0,"tx_irretutorial_1nff_hotel",3,,,,,,,,
-,"5925fc8c83fd2759d4dbb7d2e87b9e28","tt_content",297,"tx_irretutorial_1nff_hotels",1,0,0,"tx_irretutorial_1nff_hotel",4,,,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Select/DataSet/ReferenceIndex.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Select/DataSet/ReferenceIndex.csv
index 3c38b9e77b89..a2359e8738c3 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/Select/DataSet/ReferenceIndex.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/Select/DataSet/ReferenceIndex.csv
@@ -1,5 +1,6 @@
 "sys_refindex",,,,,,,,,,,,
 ,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","deleted","ref_table","ref_uid","ref_string"
+# @todo: The hash fields of next 2 rows are probably wrong
 ,"d7065184b2d510f3fada875169bc8c57","tt_content",297,"tx_testdatahandler_select",,,,0,0,"tx_testdatahandler_element",1,
 ,"d333521843e8774369e112581bd4643b","tt_content",297,"tx_testdatahandler_select",,,,1,0,"tx_testdatahandler_element",2,
 ,"fb9a4c46d91b175ee7503de71523c849","tt_content",298,"tx_testdatahandler_select",,,,0,0,"tx_testdatahandler_element",2,
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Select/Modify/DataSet/deleteElementOfRelation.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Select/Modify/DataSet/deleteElementOfRelation.csv
index 01578a2c3055..9c0667fea1b3 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/Select/Modify/DataSet/deleteElementOfRelation.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/Select/Modify/DataSet/deleteElementOfRelation.csv
@@ -15,7 +15,7 @@
 ,3,89,768,0,0,0,0,0,0,0,0,0,"Element #3",
 "sys_refindex",,,,,,,,,,,,,,
 ,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,
-,"d7065184b2d510f3fada875169bc8c57","tt_content",297,"tx_testdatahandler_select",0,0,0,"tx_testdatahandler_element",1,,,,,
-,"d333521843e8774369e112581bd4643b","tt_content",297,"tx_testdatahandler_select",1,0,0,"tx_testdatahandler_element",2,,,,,
+,"1d5f3ff5e2c46e921da27c6379578cbb","tt_content",297,"tx_testdatahandler_select",0,0,0,"tx_testdatahandler_element",1,,,,,
+,"e17fe872ae38f0fbce0763d3c54b3af3","tt_content",297,"tx_testdatahandler_select",1,0,0,"tx_testdatahandler_element",2,,,,,
 ,"fb9a4c46d91b175ee7503de71523c849","tt_content",298,"tx_testdatahandler_select",0,0,0,"tx_testdatahandler_element",2,,,,,
 ,"f54bf3a4ddc51685c0586b31015312cb","tt_content",298,"tx_testdatahandler_select",1,0,0,"tx_testdatahandler_element",3,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/ActionTest.php
index b3ce1eb989e4..365c9170407e 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/ActionTest.php
@@ -158,4 +158,15 @@ class ActionTest extends AbstractActionTestCase
         $this->actionService->clearWorkspaceRecord(self::TABLE_Content, self::VALUE_ContentIdLast);
         $this->assertAssertionDataSet('modifyContentNDeleteAllFileReference');
     }
+
+    /**
+     * @test
+     */
+    public function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        parent::createContentWithFileReferenceAndDeleteFileReference();
+        $this->actionService->clearWorkspaceRecord(self::TABLE_Content, $this->recordIds['newContentId']);
+        $this->assertAssertionDataSet('createContentWFileReferenceNDeleteFileReference');
+        // No FE test: Create and delete scenarios have FE coverage, this test is only about DB state.
+    }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/DataSet/createContentWFileReferenceNDeleteFileReference.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/DataSet/createContentWFileReferenceNDeleteFileReference.csv
new file mode 100644
index 000000000000..e5842742536a
--- /dev/null
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Discard/DataSet/createContentWFileReferenceNDeleteFileReference.csv
@@ -0,0 +1,30 @@
+"sys_file_reference",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","uid_local","uid_foreign","tablenames","fieldname","sorting_foreign","table_local","title","description","alternative","link"
+,126,89,0,0,0,0,0,0,0,0,1,330,"tt_content","image",2,"sys_file","T3BOARD",,,
+,127,89,0,0,0,0,0,0,0,0,21,330,"tt_content","image",1,"sys_file","Kasper",,,
+,128,89,0,0,0,0,0,0,0,0,21,331,"tt_content","image",1,"sys_file","Taken at T3BOARD",,,
+,129,89,0,0,0,0,0,0,0,0,1,331,"tt_content","image",2,"sys_file","This is Kasper",,,
+,130,89,1,0,0,1,1,0,0,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+,131,89,1,0,0,1,-1,0,130,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+"tt_content",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image",,,,,,,
+,330,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,,,,,
+,331,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",2,,,,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
+,"8765176f1ce58edcb5efdcabd59ca123","sys_category",31,"parent",0,0,0,"sys_category",28,,,,,,,,,,,
+,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
+,"6588728f1c2f2069b4b781ab1d102fff","sys_file",21,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"ff0a9ca5f364b75bccb699b74d167c83","sys_file",21,"metadata",0,0,0,"sys_file_metadata",21,,,,,,,,,,,
+,"557de1cd99f1b4d25f681d822c060598","sys_file_metadata",1,"file",0,0,0,"sys_file",1,,,,,,,,,,,
+,"4821da930346696406e3ccf3ec22d999","sys_file_metadata",21,"file",0,0,0,"sys_file",21,,,,,,,,,,,
+,"aa821da8cdc56afc736974735c9b1c1c","sys_file_reference",126,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"8e50f38980afa6f4e84530b12f9cd0b3","sys_file_reference",127,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"1f1d715dd5783cd50ecbda978e23dccb","sys_file_reference",128,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"c08c2538c324b0a98b0957bc4bdf36ae","sys_file_reference",129,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"a1f2ffdc6bf235cb5516c4bfdeec5552","tt_content",330,"image",0,0,0,"sys_file_reference",127,,,,,,,,,,,
+,"fc208fc9d55a71b2faa9f4e4d4fa941d","tt_content",330,"image",1,0,0,"sys_file_reference",126,,,,,,,,,,,
+,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
+,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
+,"eab0cafc17f8d63c1ebd4994d7ab7413","sys_file_reference",131,"uid_local",0,1,1,"sys_file",1,,,,,,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
index ba96ab5a8148..759de1f8bac2 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/ActionTest.php
@@ -238,4 +238,14 @@ class ActionTest extends AbstractActionTestCase
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField(self::FIELD_ContentImage)
             ->setTable(self::TABLE_FileReference)->setField('title')->setValues('Taken at T3BOARD', 'This is Kasper'));
     }
+
+    /**
+     * @test
+     */
+    public function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        parent::createContentWithFileReferenceAndDeleteFileReference();
+        $this->assertAssertionDataSet('createContentWFileReferenceNDeleteFileReference');
+        // No FE test: Create and delete scenarios have FE coverage, this test is only about DB state.
+    }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
new file mode 100644
index 000000000000..2afe4ae0db8d
--- /dev/null
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Modify/DataSet/createContentWFileReferenceNDeleteFileReference.csv
@@ -0,0 +1,32 @@
+"sys_file_reference",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","uid_local","uid_foreign","tablenames","fieldname","sorting_foreign","table_local","title","description","alternative","link"
+,126,89,0,0,0,0,0,0,0,0,1,330,"tt_content","image",2,"sys_file","T3BOARD",,,
+,127,89,0,0,0,0,0,0,0,0,21,330,"tt_content","image",1,"sys_file","Kasper",,,
+,128,89,0,0,0,0,0,0,0,0,21,331,"tt_content","image",1,"sys_file","Taken at T3BOARD",,,
+,129,89,0,0,0,0,0,0,0,0,1,331,"tt_content","image",2,"sys_file","This is Kasper",,,
+,130,89,1,0,0,1,1,0,0,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+,131,89,1,0,0,1,-1,0,130,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+"tt_content",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image",,,,,,,
+,330,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,,,,,
+,331,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",2,,,,,,,
+,332,89,128,0,0,0,1,1,0,0,0,"Testing #1",0,,,,,,,
+,333,89,128,0,0,0,1,-1,0,332,0,"Testing #1",0,,,,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
+,"8765176f1ce58edcb5efdcabd59ca123","sys_category",31,"parent",0,0,0,"sys_category",28,,,,,,,,,,,
+,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
+,"6588728f1c2f2069b4b781ab1d102fff","sys_file",21,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"ff0a9ca5f364b75bccb699b74d167c83","sys_file",21,"metadata",0,0,0,"sys_file_metadata",21,,,,,,,,,,,
+,"557de1cd99f1b4d25f681d822c060598","sys_file_metadata",1,"file",0,0,0,"sys_file",1,,,,,,,,,,,
+,"4821da930346696406e3ccf3ec22d999","sys_file_metadata",21,"file",0,0,0,"sys_file",21,,,,,,,,,,,
+,"aa821da8cdc56afc736974735c9b1c1c","sys_file_reference",126,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"8e50f38980afa6f4e84530b12f9cd0b3","sys_file_reference",127,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"1f1d715dd5783cd50ecbda978e23dccb","sys_file_reference",128,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"c08c2538c324b0a98b0957bc4bdf36ae","sys_file_reference",129,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"a1f2ffdc6bf235cb5516c4bfdeec5552","tt_content",330,"image",0,0,0,"sys_file_reference",127,,,,,,,,,,,
+,"fc208fc9d55a71b2faa9f4e4d4fa941d","tt_content",330,"image",1,0,0,"sys_file_reference",126,,,,,,,,,,,
+,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
+,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
+,"eab0cafc17f8d63c1ebd4994d7ab7413","sys_file_reference",131,"uid_local",0,1,1,"sys_file",1,,,,,,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/ActionTest.php
index b1b4d9472e20..b8010e729205 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/ActionTest.php
@@ -254,4 +254,15 @@ class ActionTest extends AbstractActionTestCase
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField(self::FIELD_ContentImage)
             ->setTable(self::TABLE_FileReference)->setField('title')->setValues('Taken at T3BOARD', 'This is Kasper'));
     }
+
+    /**
+     * @test
+     */
+    public function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        parent::createContentWithFileReferenceAndDeleteFileReference();
+        $this->actionService->publishRecord(self::TABLE_Content, $this->recordIds['newContentId']);
+        $this->assertAssertionDataSet('createContentWFileReferenceNDeleteFileReference');
+        // No FE test: Create and delete scenarios have FE coverage, this test is only about DB state.
+    }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/DataSet/createContentWFileReferenceNDeleteFileReference.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/DataSet/createContentWFileReferenceNDeleteFileReference.csv
new file mode 100644
index 000000000000..3b7fa6954f60
--- /dev/null
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/Publish/DataSet/createContentWFileReferenceNDeleteFileReference.csv
@@ -0,0 +1,31 @@
+"sys_file_reference",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","uid_local","uid_foreign","tablenames","fieldname","sorting_foreign","table_local","title","description","alternative","link"
+,126,89,0,0,0,0,0,0,0,0,1,330,"tt_content","image",2,"sys_file","T3BOARD",,,
+,127,89,0,0,0,0,0,0,0,0,21,330,"tt_content","image",1,"sys_file","Kasper",,,
+,128,89,0,0,0,0,0,0,0,0,21,331,"tt_content","image",1,"sys_file","Taken at T3BOARD",,,
+,129,89,0,0,0,0,0,0,0,0,1,331,"tt_content","image",2,"sys_file","This is Kasper",,,
+,130,89,1,0,0,1,1,0,0,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+,131,89,1,0,0,1,-1,0,130,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+"tt_content",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image",,,,,,,
+,330,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,,,,,
+,331,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",2,,,,,,,
+,332,89,128,0,0,0,0,0,0,0,0,"Testing #1",0,,,,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
+,"8765176f1ce58edcb5efdcabd59ca123","sys_category",31,"parent",0,0,0,"sys_category",28,,,,,,,,,,,
+,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
+,"6588728f1c2f2069b4b781ab1d102fff","sys_file",21,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"ff0a9ca5f364b75bccb699b74d167c83","sys_file",21,"metadata",0,0,0,"sys_file_metadata",21,,,,,,,,,,,
+,"557de1cd99f1b4d25f681d822c060598","sys_file_metadata",1,"file",0,0,0,"sys_file",1,,,,,,,,,,,
+,"4821da930346696406e3ccf3ec22d999","sys_file_metadata",21,"file",0,0,0,"sys_file",21,,,,,,,,,,,
+,"aa821da8cdc56afc736974735c9b1c1c","sys_file_reference",126,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"8e50f38980afa6f4e84530b12f9cd0b3","sys_file_reference",127,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"1f1d715dd5783cd50ecbda978e23dccb","sys_file_reference",128,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"c08c2538c324b0a98b0957bc4bdf36ae","sys_file_reference",129,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"a1f2ffdc6bf235cb5516c4bfdeec5552","tt_content",330,"image",0,0,0,"sys_file_reference",127,,,,,,,,,,,
+,"fc208fc9d55a71b2faa9f4e4d4fa941d","tt_content",330,"image",1,0,0,"sys_file_reference",126,,,,,,,,,,,
+,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
+,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
+,"eab0cafc17f8d63c1ebd4994d7ab7413","sys_file_reference",131,"uid_local",0,1,1,"sys_file",1,,,,,,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/ActionTest.php
index e6b72db176d7..0052c693bef9 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/ActionTest.php
@@ -249,4 +249,15 @@ class ActionTest extends AbstractActionTestCase
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField(self::FIELD_ContentImage)
             ->setTable(self::TABLE_FileReference)->setField('title')->setValues('Taken at T3BOARD', 'This is Kasper'));
     }
+
+    /**
+     * @test
+     */
+    public function createContentWithFileReferenceAndDeleteFileReference()
+    {
+        parent::createContentWithFileReferenceAndDeleteFileReference();
+        $this->actionService->publishWorkspace(self::VALUE_WorkspaceId);
+        $this->assertAssertionDataSet('createContentWFileReferenceNDeleteFileReference');
+        // No FE test: Create and delete scenarios have FE coverage, this test is only about DB state.
+    }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/DataSet/createContentWFileReferenceNDeleteFileReference.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/DataSet/createContentWFileReferenceNDeleteFileReference.csv
new file mode 100644
index 000000000000..3b7fa6954f60
--- /dev/null
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/FAL/PublishAll/DataSet/createContentWFileReferenceNDeleteFileReference.csv
@@ -0,0 +1,31 @@
+"sys_file_reference",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","uid_local","uid_foreign","tablenames","fieldname","sorting_foreign","table_local","title","description","alternative","link"
+,126,89,0,0,0,0,0,0,0,0,1,330,"tt_content","image",2,"sys_file","T3BOARD",,,
+,127,89,0,0,0,0,0,0,0,0,21,330,"tt_content","image",1,"sys_file","Kasper",,,
+,128,89,0,0,0,0,0,0,0,0,21,331,"tt_content","image",1,"sys_file","Taken at T3BOARD",,,
+,129,89,0,0,0,0,0,0,0,0,1,331,"tt_content","image",2,"sys_file","This is Kasper",,,
+,130,89,1,0,0,1,1,0,0,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+,131,89,1,0,0,1,-1,0,130,0,1,332,"tt_content","image",1,"sys_file","Image #1",,,
+"tt_content",,,,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image",,,,,,,
+,330,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,,,,,
+,331,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",2,,,,,,,
+,332,89,128,0,0,0,0,0,0,0,0,"Testing #1",0,,,,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","sorting","deleted","workspace","ref_table","ref_uid",,,,,,,,,,,
+,"8765176f1ce58edcb5efdcabd59ca123","sys_category",31,"parent",0,0,0,"sys_category",28,,,,,,,,,,,
+,"b1315f6a325027205050c81764294b72","sys_file",1,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"10034d14de6b8c87aa0096de9d029498","sys_file",1,"metadata",0,0,0,"sys_file_metadata",1,,,,,,,,,,,
+,"6588728f1c2f2069b4b781ab1d102fff","sys_file",21,"storage",0,0,0,"sys_file_storage",1,,,,,,,,,,,
+,"ff0a9ca5f364b75bccb699b74d167c83","sys_file",21,"metadata",0,0,0,"sys_file_metadata",21,,,,,,,,,,,
+,"557de1cd99f1b4d25f681d822c060598","sys_file_metadata",1,"file",0,0,0,"sys_file",1,,,,,,,,,,,
+,"4821da930346696406e3ccf3ec22d999","sys_file_metadata",21,"file",0,0,0,"sys_file",21,,,,,,,,,,,
+,"aa821da8cdc56afc736974735c9b1c1c","sys_file_reference",126,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"8e50f38980afa6f4e84530b12f9cd0b3","sys_file_reference",127,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"1f1d715dd5783cd50ecbda978e23dccb","sys_file_reference",128,"uid_local",0,0,0,"sys_file",21,,,,,,,,,,,
+,"c08c2538c324b0a98b0957bc4bdf36ae","sys_file_reference",129,"uid_local",0,0,0,"sys_file",1,,,,,,,,,,,
+,"a1f2ffdc6bf235cb5516c4bfdeec5552","tt_content",330,"image",0,0,0,"sys_file_reference",127,,,,,,,,,,,
+,"fc208fc9d55a71b2faa9f4e4d4fa941d","tt_content",330,"image",1,0,0,"sys_file_reference",126,,,,,,,,,,,
+,"48540de7710e3082f347bdd65ca340f2","tt_content",331,"image",0,0,0,"sys_file_reference",128,,,,,,,,,,,
+,"ceaebd2148901a6d7b0a52c546aa5218","tt_content",331,"image",1,0,0,"sys_file_reference",129,,,,,,,,,,,
+,"eab0cafc17f8d63c1ebd4994d7ab7413","sys_file_reference",131,"uid_local",0,1,1,"sys_file",1,,,,,,,,,,,
-- 
GitLab