Skip to content

Commit

Permalink
POC but we cannot convert error to UCViolation again
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod committed Apr 30, 2022
1 parent d2b49c4 commit bf790e6
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 46 deletions.
8 changes: 5 additions & 3 deletions src/Driver/OCI8/Exception/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ public static function new($resource): self
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
[$firstMessage, $secondMessage] = explode("\n", $message, 2);

[$code, $message] = explode(': ', $secondMessage, 2);
$code = (int) str_replace('ORA-', '', $code);
[$causeCode, $causeMessage] = explode(': ', $secondMessage, 2);
$causeCode = (int) str_replace('ORA-', '', $causeCode);

$cause = new self($causeMessage, null, $causeCode);
}

return new self($message, null, $code);
return new self($message, null, $code, $cause ?? null);
}
}
8 changes: 5 additions & 3 deletions src/Driver/PDO/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ public static function new(PDOException $exception): self
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
[$firstMessage, $secondMessage] = explode("\n", $message, 2);

[$code, $message] = explode(': ', $secondMessage, 2);
$code = (int) str_replace('ORA-', '', $code);
[$causeCode, $causeMessage] = explode(': ', $secondMessage, 2);
$causeCode = (int) str_replace('ORA-', '', $causeCode);

$cause = new self($causeMessage, null, $causeCode, $exception);
}

return new self($message, $sqlState, $code, $exception);
return new self($message, $sqlState, $code, $cause ?? $exception);
}
}
12 changes: 7 additions & 5 deletions tests/Driver/PDO/ExceptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ public function testExposesUnderlyingErrorOnOracle(): void

$exception = Exception::new($pdoException);

self::assertSame(1, $exception->getCode());
self::assertStringContainsString(
'unique constraint (DOCTRINE.C1_UNIQUE) violated',
$exception->getMessage()
);
self::assertSame(2091, $exception->getCode());
self::assertStringContainsString('transaction rolled back', $exception->getMessage());

$previous = $exception->getPrevious();
self::assertNotNull($previous);
self::assertSame(1, $previous->getCode());
self::assertStringContainsString('unique constraint (DOCTRINE.C1_UNIQUE) violated', $previous->getMessage());
}
}
88 changes: 53 additions & 35 deletions tests/Functional/UniqueConstraintViolationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,25 @@ public function testTransactionalViolatesDeferredConstraint(): void
{
$this->skipIfDeferrableIsNotSupported();

$this->connection->transactional(function (Connection $connection): void {
$connection->executeStatement(sprintf('SET CONSTRAINTS "%s" DEFERRED', $this->constraintName));

$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
try {
$this->connection->transactional(function (Connection $connection): void {
$connection->executeStatement(sprintf('SET CONSTRAINTS "%s" DEFERRED', $this->constraintName));

$this->expectUniqueConstraintViolation();
});
$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
});
} catch (Throwable $throwable) {
$this->expectUniqueConstraintViolation($throwable);
}
}

public function testTransactionalViolatesConstraint(): void
{
$this->connection->transactional(function (Connection $connection): void {
$this->expectUniqueConstraintViolation();
$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
try {
$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
} catch (Throwable $throwable) {
$this->expectUniqueConstraintViolation($throwable);
}
});
}

Expand All @@ -107,14 +112,16 @@ public function testTransactionalViolatesDeferredConstraintWhileUsingTransaction

$this->connection->setNestTransactionsWithSavepoints(true);

$this->connection->transactional(function (Connection $connection): void {
$connection->executeStatement(sprintf('SET CONSTRAINTS "%s" DEFERRED', $this->constraintName));
$connection->beginTransaction();
$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
$connection->commit();

$this->expectUniqueConstraintViolation();
});
try {
$this->connection->transactional(function (Connection $connection): void {
$connection->executeStatement(sprintf('SET CONSTRAINTS "%s" DEFERRED', $this->constraintName));
$connection->beginTransaction();
$connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
$connection->commit();
});
} catch (Throwable $throwable) {
$this->expectUniqueConstraintViolation($throwable);
}
}

public function testTransactionalViolatesConstraintWhileUsingTransactionNesting(): void
Expand All @@ -130,12 +137,10 @@ public function testTransactionalViolatesConstraintWhileUsingTransactionNesting(

try {
$this->connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
} catch (Throwable $t) {
} catch (Throwable $throwable) {
$this->connection->rollBack();

$this->expectUniqueConstraintViolation();

throw $t;
$this->expectUniqueConstraintViolation($throwable);
}
});
}
Expand All @@ -148,8 +153,11 @@ public function testCommitViolatesDeferredConstraint(): void
$this->connection->executeStatement(sprintf('SET CONSTRAINTS "%s" DEFERRED', $this->constraintName));
$this->connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');

$this->expectUniqueConstraintViolation();
$this->connection->commit();
try {
$this->connection->commit();
} catch (Throwable $throwable) {
$this->expectUniqueConstraintViolation($throwable);
}
}

public function testInsertViolatesConstraint(): void
Expand All @@ -161,9 +169,7 @@ public function testInsertViolatesConstraint(): void
} catch (Throwable $t) {
$this->connection->rollBack();

$this->expectUniqueConstraintViolation();

throw $t;
$this->expectUniqueConstraintViolation($t);
}
}

Expand All @@ -183,9 +189,11 @@ public function testCommitViolatesDeferredConstraintWhileUsingTransactionNesting
$this->connection->executeStatement('INSERT INTO unique_constraint_violations VALUES (1)');
$this->connection->commit();

$this->expectUniqueConstraintViolation();

$this->connection->commit();
try {
$this->connection->commit();
} catch (Throwable $throwable) {
$this->expectUniqueConstraintViolation($throwable);
}
}

public function testCommitViolatesConstraintWhileUsingTransactionNesting(): void
Expand All @@ -206,9 +214,7 @@ public function testCommitViolatesConstraintWhileUsingTransactionNesting(): void
} catch (Throwable $t) {
$this->connection->rollBack();

$this->expectUniqueConstraintViolation();

throw $t;
$this->expectUniqueConstraintViolation($t);
}
}

Expand All @@ -228,22 +234,34 @@ private function skipIfDeferrableIsNotSupported(): void
self::markTestSkipped('Only databases supporting deferrable constraints are eligible for this test.');
}

private function expectUniqueConstraintViolation(): void
private function expectUniqueConstraintViolation(Throwable $throwable): void
{
if ($this->connection->getDatabasePlatform() instanceof SQLServerPlatform) {
$this->expectExceptionMessage(sprintf("Violation of UNIQUE KEY constraint '%s'", $this->constraintName));
self::assertStringContainsString(
sprintf("Violation of UNIQUE KEY constraint '%s'", $this->constraintName),
$throwable->getMessage()
);

return;
}

if ($this->connection->getDatabasePlatform() instanceof DB2Platform) {
// No concrete message is provided
$this->expectException(DriverException::class);
self::assertInstanceOf(DriverException::class, $throwable);

return;
}

if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
self::assertInstanceOf(DriverException::class, $throwable);
$previous = $throwable->getPrevious();
$this->assertNotNull($previous);
self::assertInstanceOf(UniqueConstraintViolationException::class, $previous);

return;
}

$this->expectException(UniqueConstraintViolationException::class);
self::assertInstanceOf(UniqueConstraintViolationException::class, $throwable);
}

protected function tearDown(): void
Expand Down

0 comments on commit bf790e6

Please sign in to comment.