You are here

public function TransactionTest::testTransactionWithDdlStatement in Drupal 8

Same name and namespace in other branches
  1. 9 core/tests/Drupal/KernelTests/Core/Database/TransactionTest.php \Drupal\KernelTests\Core\Database\TransactionTest::testTransactionWithDdlStatement()
  2. 10 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 220

Class

TransactionTest
Tests the transaction abstraction system.

Namespace

Drupal\KernelTests\Core\Database

Code

public function testTransactionWithDdlStatement() {

  // First, test that a commit works normally, even with DDL statements.
  $transaction = $this->connection
    ->startTransaction();
  $this
    ->insertRow('row');
  $this
    ->executeDDLStatement();
  unset($transaction);
  $this
    ->assertRowPresent('row');

  // Even in different order.
  $this
    ->cleanUp();
  $transaction = $this->connection
    ->startTransaction();
  $this
    ->executeDDLStatement();
  $this
    ->insertRow('row');
  unset($transaction);
  $this
    ->assertRowPresent('row');

  // Even with stacking.
  $this
    ->cleanUp();
  $transaction = $this->connection
    ->startTransaction();
  $transaction2 = $this->connection
    ->startTransaction();
  $this
    ->executeDDLStatement();
  unset($transaction2);
  $transaction3 = $this->connection
    ->startTransaction();
  $this
    ->insertRow('row');
  unset($transaction3);
  unset($transaction);
  $this
    ->assertRowPresent('row');

  // A transaction after a DDL statement should still work the same.
  $this
    ->cleanUp();
  $transaction = $this->connection
    ->startTransaction();
  $transaction2 = $this->connection
    ->startTransaction();
  $this
    ->executeDDLStatement();
  unset($transaction2);
  $transaction3 = $this->connection
    ->startTransaction();
  $this
    ->insertRow('row');
  $transaction3
    ->rollBack();
  unset($transaction3);
  unset($transaction);
  $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->connection
      ->startTransaction();
    $this
      ->insertRow('row');
    $this
      ->executeDDLStatement();
    $transaction
      ->rollBack();
    unset($transaction);
    $this
      ->assertRowAbsent('row');

    // Including with stacking.
    $this
      ->cleanUp();
    $transaction = $this->connection
      ->startTransaction();
    $transaction2 = $this->connection
      ->startTransaction();
    $this
      ->executeDDLStatement();
    unset($transaction2);
    $transaction3 = $this->connection
      ->startTransaction();
    $this
      ->insertRow('row');
    unset($transaction3);
    $transaction
      ->rollBack();
    unset($transaction);
    $this
      ->assertRowAbsent('row');
  }
  else {

    // For database servers that do not support transactional DDL,
    // the DDL statement should commit the transaction stack.
    $this
      ->cleanUp();
    $transaction = $this->connection
      ->startTransaction();
    $this
      ->insertRow('row');
    $this
      ->executeDDLStatement();

    // Rollback the outer transaction.
    try {
      $transaction
        ->rollBack();
      unset($transaction);

      // @todo An exception should be triggered here, but is not because
      // "ROLLBACK" fails silently in MySQL if there is no transaction active.
      // @see https://www.drupal.org/project/drupal/issues/2736777
      // $this->fail('Rolling back a transaction containing DDL should fail.');
    } catch (TransactionNoActiveException $e) {

      // Expected exception; just continue testing.
    }
    $this
      ->assertRowPresent('row');
  }
}