Skip to content

Commit 2408bd6

Browse files
committed
Unify transactional statement implementation with other statements
1 parent 1dc9eec commit 2408bd6

1 file changed

Lines changed: 71 additions & 50 deletions

File tree

wp-includes/sqlite-ast/class-wp-sqlite-driver.php

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -666,64 +666,34 @@ public function query( string $query, $fetch_mode = PDO::FETCH_OBJ, ...$fetch_mo
666666
throw $this->new_driver_exception( 'Multi-query is not supported.' );
667667
}
668668

669-
// Handle transaction commands.
670-
671669
/*
670+
* Determine if we need to wrap the translated queries in a transaction.
671+
*
672672
* [GRAMMAR]
673-
* beginWork: BEGIN_SYMBOL WORK_SYMBOL?
673+
* query:
674+
* EOF
675+
* | (simpleStatement | beginWork) (SEMICOLON_SYMBOL EOF? | EOF)
674676
*/
675-
$child = $ast->get_first_child();
676-
if ( $child instanceof WP_Parser_Node && 'beginWork' === $child->rule_name ) {
677-
$this->begin_transaction();
678-
return true;
677+
$child_node = $ast->get_first_child_node();
678+
if (
679+
null === $child_node
680+
|| 'beginWork' === $child_node->rule_name
681+
|| $child_node->has_child_node( 'transactionOrLockingStatement' )
682+
) {
683+
$wrap_in_transaction = false;
684+
} else {
685+
$wrap_in_transaction = true;
679686
}
680687

681-
if ( $child instanceof WP_Parser_Node && 'simpleStatement' === $child->rule_name ) {
682-
/*
683-
* [GRAMMAR]
684-
* transactionOrLockingStatement:
685-
* transactionStatement | savepointStatement | lockStatement | xaStatement
686-
*/
687-
$subchild = $child->get_first_child_node( 'transactionOrLockingStatement' );
688-
if ( null !== $subchild ) {
689-
$tokens = $subchild->get_descendant_tokens();
690-
$token1 = $tokens[0];
691-
$token2 = $tokens[1] ?? null;
692-
if (
693-
WP_MySQL_Lexer::START_SYMBOL === $token1->id
694-
&& WP_MySQL_Lexer::TRANSACTION_SYMBOL === $token2->id
695-
) {
696-
$this->begin_transaction();
697-
return true;
698-
}
699-
700-
if (
701-
WP_MySQL_Lexer::BEGIN_SYMBOL === $token1->id
702-
) {
703-
$this->begin_transaction();
704-
return true;
705-
}
706-
707-
if (
708-
WP_MySQL_Lexer::COMMIT_SYMBOL === $token1->id
709-
) {
710-
$this->commit();
711-
return true;
712-
}
713-
714-
if (
715-
WP_MySQL_Lexer::ROLLBACK_SYMBOL === $token1->id
716-
) {
717-
$this->rollback();
718-
return true;
719-
}
720-
}
688+
if ( $wrap_in_transaction ) {
689+
$this->begin_transaction();
721690
}
722691

723-
// Perform all the queries in a nested transaction.
724-
$this->begin_transaction();
725692
$this->execute_mysql_query( $ast );
726-
$this->commit();
693+
694+
if ( $wrap_in_transaction ) {
695+
$this->commit();
696+
}
727697
return $this->last_return_value;
728698
} catch ( Throwable $e ) {
729699
try {
@@ -895,6 +865,11 @@ private function execute_mysql_query( WP_Parser_Node $node ): void {
895865
);
896866
}
897867

868+
if ( 'beginWork' === $children[0]->rule_name ) {
869+
$this->begin_transaction();
870+
return;
871+
}
872+
898873
if ( 'simpleStatement' !== $children[0]->rule_name ) {
899874
throw $this->new_driver_exception(
900875
sprintf( 'Expected "simpleStatement" node, got: "%s"', $children[0]->rule_name )
@@ -904,6 +879,9 @@ private function execute_mysql_query( WP_Parser_Node $node ): void {
904879
// Process the "simpleStatement" AST node.
905880
$node = $children[0]->get_first_child_node();
906881
switch ( $node->rule_name ) {
882+
case 'transactionOrLockingStatement':
883+
$this->execute_transaction_or_locking_statement( $node );
884+
break;
907885
case 'selectStatement':
908886
$this->is_readonly = true;
909887
$this->execute_select_statement( $node );
@@ -1017,6 +995,49 @@ private function execute_mysql_query( WP_Parser_Node $node ): void {
1017995
}
1018996
}
1019997

998+
/**
999+
* Execute a MySQL transaction or locking statement in SQLite.
1000+
*
1001+
* @param WP_Parser_Node $node The "transactionOrLockingStatement" AST node.
1002+
* @throws WP_SQLite_Driver_Exception When the query execution fails.
1003+
*/
1004+
private function execute_transaction_or_locking_statement( WP_Parser_Node $node ): void {
1005+
$subnode = $node->get_first_child_node();
1006+
$token = $node->get_first_descendant_token();
1007+
switch ( $subnode->rule_name ) {
1008+
case 'transactionStatement':
1009+
// START TRANSACTION.
1010+
if ( WP_MySQL_Lexer::START_SYMBOL === $token->id ) {
1011+
$this->begin_transaction();
1012+
break;
1013+
}
1014+
1015+
// COMMIT.
1016+
if ( WP_MySQL_Lexer::COMMIT_SYMBOL === $token->id ) {
1017+
$this->commit();
1018+
break;
1019+
}
1020+
1021+
// Unknown statement. Fall through to the default case.
1022+
case 'savepointStatement':
1023+
// ROLLBACK.
1024+
if ( WP_MySQL_Lexer::ROLLBACK_SYMBOL === $token->id ) {
1025+
$this->rollback();
1026+
break;
1027+
}
1028+
1029+
// Unknown statement. Fall through to the default case.
1030+
default:
1031+
throw $this->new_not_supported_exception(
1032+
sprintf(
1033+
'statement type: "%s" > "%s"',
1034+
$node->rule_name,
1035+
$subnode->rule_name
1036+
)
1037+
);
1038+
}
1039+
}
1040+
10201041
/**
10211042
* Translate and execute a MySQL SELECT statement in SQLite.
10221043
*

0 commit comments

Comments
 (0)