function TransactionTest::testTransactionWithDdlStatement

Same name and namespace in other branches
  1. 9 core/tests/Drupal/KernelTests/Core/Database/TransactionTest.php \Drupal\KernelTests\Core\Database\TransactionTest::testTransactionWithDdlStatement()
  2. 8.9.x core/tests/Drupal/KernelTests/Core/Database/TransactionTest.php \Drupal\KernelTests\Core\Database\TransactionTest::testTransactionWithDdlStatement()

Tests the compatibility of transactions with DDL statements.

File

core/tests/Drupal/KernelTests/Core/Database/TransactionTest.php, line 489

Class

TransactionTest
Tests the transactions, using the explicit ::commitOrRelease method.

Namespace

Drupal\KernelTests\Core\Database

Code

public function testTransactionWithDdlStatement() : void {
  // First, test that a commit works normally, even with DDL statements.
  $transaction = $this->createRootTransaction('', FALSE);
  $this->insertRow('row');
  $this->executeDDLStatement();
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction->commitOrRelease();
  }
  else {
    set_error_handler(static function (int $errno, string $errstr) : bool {
      throw new \ErrorException($errstr);
    });
    try {
      $transaction->commitOrRelease();
    } catch (\ErrorException $e) {
      $this->assertSame('Transaction::commitOrRelease() was not processed because a prior execution of a DDL statement already committed the transaction.', $e->getMessage());
    } finally {
      restore_error_handler();
    }
  }
  $this->assertRowPresent('row');
  // Even in different order.
  $this->cleanUp();
  $transaction = $this->createRootTransaction('', FALSE);
  $this->executeDDLStatement();
  $this->insertRow('row');
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction->commitOrRelease();
  }
  else {
    set_error_handler(static function (int $errno, string $errstr) : bool {
      throw new \ErrorException($errstr);
    });
    try {
      $transaction->commitOrRelease();
    } catch (\ErrorException $e) {
      $this->assertSame('Transaction::commitOrRelease() was not processed because a prior execution of a DDL statement already committed the transaction.', $e->getMessage());
    } finally {
      restore_error_handler();
    }
  }
  $this->assertRowPresent('row');
  // Even with stacking.
  $this->cleanUp();
  $transaction = $this->createRootTransaction('', FALSE);
  $transaction2 = $this->createFirstSavepointTransaction('', FALSE);
  $this->executeDDLStatement();
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction2->commitOrRelease();
  }
  else {
    set_error_handler(static function (int $errno, string $errstr) : bool {
      throw new \ErrorException($errstr);
    });
    try {
      $transaction2->commitOrRelease();
    } catch (\ErrorException $e) {
      $this->assertSame('Transaction::commitOrRelease() was not processed because a prior execution of a DDL statement already committed the transaction.', $e->getMessage());
    } finally {
      restore_error_handler();
    }
  }
  $transaction3 = $this->connection
    ->startTransaction();
  $this->insertRow('row');
  $transaction3->commitOrRelease();
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction->commitOrRelease();
  }
  else {
    try {
      $transaction->commitOrRelease();
      $this->fail('TransactionOutOfOrderException was expected, but did not throw.');
    } catch (TransactionOutOfOrderException) {
      // Just continue, this is out or order since $transaction3 started a
      // new root.
    }
  }
  $this->assertRowPresent('row');
  // A transaction after a DDL statement should still work the same.
  $this->cleanUp();
  $transaction = $this->createRootTransaction('', FALSE);
  $transaction2 = $this->createFirstSavepointTransaction('', FALSE);
  $this->executeDDLStatement();
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction2->commitOrRelease();
  }
  else {
    set_error_handler(static function (int $errno, string $errstr) : bool {
      throw new \ErrorException($errstr);
    });
    try {
      $transaction2->commitOrRelease();
    } catch (\ErrorException $e) {
      $this->assertSame('Transaction::commitOrRelease() was not processed because a prior execution of a DDL statement already committed the transaction.', $e->getMessage());
    } finally {
      restore_error_handler();
    }
  }
  $transaction3 = $this->connection
    ->startTransaction();
  $this->insertRow('row');
  $transaction3->rollBack();
  if ($this->connection
    ->supportsTransactionalDDL()) {
    $transaction->commitOrRelease();
  }
  else {
    try {
      $transaction->commitOrRelease();
      $this->fail('TransactionOutOfOrderException was expected, but did not throw.');
    } catch (TransactionOutOfOrderException) {
      // Just continue, this is out or order since $transaction3 started a
      // new root.
    }
  }
  $this->assertRowAbsent('row');
  // The behavior of a rollback depends on the type of database server.
  if ($this->connection
    ->supportsTransactionalDDL()) {
    // For database servers that support transactional DDL, a rollback
    // of a transaction including DDL statements should be possible.
    $this->cleanUp();
    $transaction = $this->createRootTransaction('', FALSE);
    $this->insertRow('row');
    $this->executeDDLStatement();
    $transaction->rollBack();
    $this->assertRowAbsent('row');
    // Including with stacking.
    $this->cleanUp();
    $transaction = $this->createRootTransaction('', FALSE);
    $transaction2 = $this->createFirstSavepointTransaction('', FALSE);
    $this->executeDDLStatement();
    $transaction2->commitOrRelease();
    $transaction3 = $this->connection
      ->startTransaction();
    $this->insertRow('row');
    $transaction3->commitOrRelease();
    $this->assertRowPresent('row');
    $transaction->rollBack();
    $this->assertRowAbsent('row');
  }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.