Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions tests/WP_SQLite_Driver_PDO_API_Tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

use PHPUnit\Framework\TestCase;

class WP_SQLite_Driver_PDO_API_Tests extends TestCase {
/** @var WP_SQLite_Driver */
private $driver;

public function setUp(): void {
$connection = new WP_SQLite_Connection( array( 'path' => ':memory:' ) );
$this->driver = new WP_SQLite_Driver( $connection, 'wp' );
}

public function test_begin_transaction(): void {
$result = $this->driver->beginTransaction();
$this->assertTrue( $result );
}

public function test_begin_transaction_already_active(): void {
$this->driver->beginTransaction();

$this->expectException( PDOException::class );
$this->expectExceptionMessage( 'There is already an active transaction' );
$this->expectExceptionCode( 0 );
$this->driver->beginTransaction();
}

public function test_commit(): void {
$this->driver->beginTransaction();
$result = $this->driver->commit();
$this->assertTrue( $result );
}

public function test_commit_no_active_transaction(): void {
$this->expectException( PDOException::class );
$this->expectExceptionMessage( 'There is no active transaction' );
$this->expectExceptionCode( 0 );
$this->driver->commit();
}

public function test_rollback(): void {
$this->driver->beginTransaction();
$result = $this->driver->rollBack();
$this->assertTrue( $result );
}

public function test_rollback_no_active_transaction(): void {
$this->expectException( PDOException::class );
$this->expectExceptionMessage( 'There is no active transaction' );
$this->expectExceptionCode( 0 );
$this->driver->rollBack();
}
}
91 changes: 15 additions & 76 deletions tests/WP_SQLite_Driver_Tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -2490,87 +2490,26 @@ public function testStartTransactionCommand() {
$this->assertCount( 0, $this->engine->get_query_results() );
}

public function testNestedTransactionWork() {
$this->assertQuery( 'BEGIN' );
$this->assertQuery( "INSERT INTO _options (option_name) VALUES ('first');" );
$this->assertQuery( 'START TRANSACTION' );
$this->assertQuery( "INSERT INTO _options (option_name) VALUES ('second');" );
$this->assertQuery( 'START TRANSACTION' );
$this->assertQuery( "INSERT INTO _options (option_name) VALUES ('third');" );
$this->assertQuery( 'SELECT * FROM _options;' );
$this->assertCount( 3, $this->engine->get_query_results() );

$this->assertQuery( 'ROLLBACK' );
$this->assertQuery( 'SELECT * FROM _options;' );
$this->assertCount( 2, $this->engine->get_query_results() );

$this->assertQuery( 'ROLLBACK' );
$this->assertQuery( 'SELECT * FROM _options;' );
$this->assertCount( 1, $this->engine->get_query_results() );

$this->assertQuery( 'COMMIT' );
$this->assertQuery( 'SELECT * FROM _options;' );
$this->assertCount( 1, $this->engine->get_query_results() );
}
public function testRepeatedTransactionCommands(): void {
$this->assertQuery( 'CREATE TABLE t (id INT)' );

public function testNestedTransactionWorkComplexModify() {
// 1st BEGIN starts a transaction.
$this->assertQuery( 'BEGIN' );
// Create a complex ALTER Table query where the first
// column is added successfully, but the second fails.
// Behind the scenes, this single MySQL query is split
// into multiple SQLite queries – some of them will
// succeed, some will fail.
$error = '';
try {
$this->engine->query(
'
ALTER TABLE _options
ADD COLUMN test varchar(20),
ADD COLUMN test varchar(20)
'
);
} catch ( Throwable $e ) {
$error = $e->getMessage();
}
$this->assertStringContainsString( "Duplicate column name 'test'", $error );
$this->assertQuery( 'INSERT INTO t (id) VALUES (1);' );

// Commit the transaction.
$this->assertQuery( 'COMMIT' );
// 2nd BEGIN commits the previous transaction and starts a new one.
$this->assertQuery( 'BEGIN' );
$this->assertQuery( 'INSERT INTO t (id) VALUES (2);' );

// Confirm the entire query failed atomically and no column was
// added to the table.
$this->assertQuery( 'DESCRIBE _options;' );
$fields = $this->engine->get_query_results();
// ROLLBACK rolls back the 2nd transaction.
$this->assertQuery( 'ROLLBACK' );
$results = $this->assertQuery( 'SELECT * FROM t;' );
$this->assertEquals( array( (object) array( 'id' => '1' ) ), $results );

$this->assertEquals(
array(
(object) array(
'Field' => 'ID',
'Type' => 'int',
'Null' => 'NO',
'Key' => 'PRI',
'Default' => null,
'Extra' => 'auto_increment',
),
(object) array(
'Field' => 'option_name',
'Type' => 'text',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
),
(object) array(
'Field' => 'option_value',
'Type' => 'text',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
),
),
$fields
);
// Repeated ROLLBACK should do nothing.
$this->assertQuery( 'ROLLBACK' );
$results = $this->assertQuery( 'SELECT * FROM t;' );
$this->assertEquals( array( (object) array( 'id' => '1' ) ), $results );
}

public function testCount() {
Expand Down
14 changes: 14 additions & 0 deletions wp-includes/sqlite-ast/class-wp-sqlite-connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ public function query( string $sql, array $params = array() ): PDOStatement {
return $stmt;
}

/**
* Prepare a SQLite query for execution.
*
* @param string $sql The query to prepare.
* @return PDOStatement The prepared statement.
* @throws PDOException When the query preparation fails.
*/
public function prepare( string $sql ): PDOStatement {
if ( $this->query_logger ) {
( $this->query_logger )( $sql, array() );
}
return $this->pdo->prepare( $sql );
}

/**
* Returns the ID of the last inserted row.
*
Expand Down
Loading
Loading