Skip to content

Commit

Permalink
Merge pull request #89 from ohader/bugfix/sql-server
Browse files Browse the repository at this point in the history
[BUGFIX] Modify SQL Server IDENTITY_INSERT when creating records
  • Loading branch information
ohader authored Aug 12, 2018
2 parents 4a15d2c + 56df56b commit 745260e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
39 changes: 36 additions & 3 deletions Classes/Core/DatabaseConnectionWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,33 @@
* The TYPO3 project - inspiring people to share!
*/

use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use TYPO3\CMS\Core\Database\Connection;

/**
* Wrapper for database connections in order to intercept statement executions.
*/
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.
*
Expand All @@ -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
Expand All @@ -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();
Expand Down
22 changes: 22 additions & 0 deletions Classes/Core/Functional/FunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit 745260e

Please sign in to comment.