diff --git a/tests/WP_SQLite_Driver_Tests.php b/tests/WP_SQLite_Driver_Tests.php index c3251708..0f9b8eaa 100644 --- a/tests/WP_SQLite_Driver_Tests.php +++ b/tests/WP_SQLite_Driver_Tests.php @@ -7380,6 +7380,22 @@ public function testUpdateWithJoinComplexQuery(): void { ); } + public function testLockingClauses() { + $this->engine->query( "INSERT INTO _options (option_name, option_value) VALUES ('test_lock', '1')" ); + + // Test FOR UPDATE + $res = $this->engine->query( "SELECT option_value FROM _options WHERE option_name = 'test_lock' FOR UPDATE" ); + $this->assertEquals( '1', $res[0]->option_value ); + + // Test LOCK IN SHARE MODE + $res = $this->engine->query( "SELECT option_value FROM _options WHERE option_name = 'test_lock' LOCK IN SHARE MODE" ); + $this->assertEquals( '1', $res[0]->option_value ); + + // Test multiple clauses + $res = $this->engine->query( "SELECT option_value FROM _options WHERE option_name = 'test_lock' FOR UPDATE SKIP LOCKED" ); + $this->assertEquals( '1', $res[0]->option_value ); + } + public function testBinaryLiterals(): void { $result = $this->assertQuery( 'SELECT 0b0100000101111010' ); $this->assertEquals( array( (object) array( '0b0100000101111010' => 'Az' ) ), $result ); diff --git a/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php b/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php index b70a0dd6..ab44e89e 100644 --- a/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php +++ b/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php @@ -3808,8 +3808,10 @@ private function translate( $node ): ?string { case 'indexHintList': return null; case 'lockingClause': - // SQLite doesn't support locking clauses (SELECT ... FOR UPDATE). - // They are not needed in SQLite due to the database file locking. + // MySQL locking clauses (e.g., SELECT ... FOR UPDATE) are not supported in SQLite. + // We omit them for syntax compatibility. While this doesn't preserve row-level + // locking semantics, SQLite's database-level locking is sufficient for + // typical WordPress workloads. return null; default: return $this->translate_sequence( $node->get_children() );