diff --git a/Classes/Core/DatabaseConnectionWrapper.php b/Classes/Core/DatabaseConnectionWrapper.php index d7738931..4be13c61 100644 --- a/Classes/Core/DatabaseConnectionWrapper.php +++ b/Classes/Core/DatabaseConnectionWrapper.php @@ -15,6 +15,8 @@ * The TYPO3 project - inspiring people to share! */ +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Platforms\SQLServerPlatform; use TYPO3\CMS\Core\Database\Connection; /** @@ -22,6 +24,24 @@ */ class DatabaseConnectionWrapper extends Connection { + /** + * @var null|bool + */ + private $allowIdentityInsert = null; + + /** + * Whether to allow modification of IDENTITY_INSERT for SQL Server platform. + * + null: unspecified, decided later during runtime (based on 'uid' & $TCA) + * + true: always allow, e.g. before actually importing data + * + false: always deny, e.g. when importing data is finished + * + * @param bool|null $allowIdentityInsert + */ + public function allowIdentityInsert(?bool $allowIdentityInsert) + { + $this->allowIdentityInsert = $allowIdentityInsert; + } + /** * Wraps insert execution in order to consider SQL Server IDENTITY_INSERT. * @@ -32,17 +52,30 @@ class DatabaseConnectionWrapper extends Connection */ public function insert($tableName, array $data, array $types = []): int { - $modified = $this->modifyServerIdentity($tableName, true); + $modified = $this->shallModifyIdentityInsert($tableName, $data) + && $this->modifyIdentityInsert($tableName, true); $result = parent::insert($tableName, $data, $types); if ($modified) { - $this->modifyServerIdentity($tableName, false); + $this->modifyIdentityInsert($tableName, false); } return $result; } + /** + * @param string $tableName + * @param array $data + * @return bool + */ + private function shallModifyIdentityInsert(string $tableName, array $data): bool + { + if ($this->allowIdentityInsert !== null) { + return $this->allowIdentityInsert; + } + return !empty($GLOBALS['TCA'][$tableName] && isset($data['uid'])); + } /** * In SQL Server (MSSQL), hard setting uid auto-increment primary keys is @@ -61,7 +94,7 @@ public function insert($tableName, array $data, array $types = []): int * @param bool $enable Whether to enable ('ON') or disable ('OFF') * @return bool Whether executed statement has be successful */ - private function modifyServerIdentity(string $tableName, bool $enable): bool + private function modifyIdentityInsert(string $tableName, bool $enable): bool { try { $platform = $this->getDatabasePlatform(); diff --git a/Classes/Core/Functional/FunctionalTestCase.php b/Classes/Core/Functional/FunctionalTestCase.php index 451ec005..93b7b123 100644 --- a/Classes/Core/Functional/FunctionalTestCase.php +++ b/Classes/Core/Functional/FunctionalTestCase.php @@ -869,4 +869,26 @@ protected function getFrontendResult($pageId, $languageId = 0, $backendUserId = false ); } + + /** + * Whether to allow modification of IDENTITY_INSERT for SQL Server platform. + * + null: unspecified, decided later during runtime (based on 'uid' & $TCA) + * + true: always allow, e.g. before actually importing data + * + false: always deny, e.g. when importing data is finished + * + * @param bool|null $allowIdentityInsert + * @param bool|null $allowIdentityInsert + * @throws DBALException + */ + protected function allowIdentityInsert(?bool $allowIdentityInsert) + { + $connection = GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME); + + if (!$connection instanceof DatabaseConnectionWrapper) { + return; + } + + $connection->allowIdentityInsert($allowIdentityInsert); + } }