Skip to content

Commit 517eca6

Browse files
committed
Robust PR 2: Support INSERT without INTO with modifier handling
1 parent 0e0dc86 commit 517eca6

2 files changed

Lines changed: 69 additions & 20 deletions

File tree

tests/WP_SQLite_Driver_Tests.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ public function testInsertDateNow() {
117117
}
118118

119119
public function testLockingClauses() {
120-
$this->assertQuery( "SELECT * FROM _options FOR UPDATE" );
121-
$this->assertQuery( "SELECT * FROM _options FOR UPDATE SKIP LOCKED" );
122-
$this->assertQuery( "SELECT * FROM _options FOR UPDATE NOWAIT" );
123-
$this->assertQuery( "SELECT * FROM _options LOCK IN SHARE MODE" );
120+
$this->assertQuery( 'SELECT * FROM _options FOR UPDATE' );
121+
$this->assertQuery( 'SELECT * FROM _options FOR UPDATE SKIP LOCKED' );
122+
$this->assertQuery( 'SELECT * FROM _options FOR UPDATE NOWAIT' );
123+
$this->assertQuery( 'SELECT * FROM _options LOCK IN SHARE MODE' );
124124

125125
// Complex queries.
126-
$this->assertQuery( "SELECT * FROM _options WHERE ID IN (SELECT ID FROM _options FOR UPDATE)" );
127-
$this->assertQuery( "SELECT * FROM _options UNION SELECT * FROM _options FOR UPDATE" );
126+
$this->assertQuery( 'SELECT * FROM _options WHERE ID IN (SELECT ID FROM _options FOR UPDATE)' );
127+
$this->assertQuery( 'SELECT * FROM _options UNION SELECT * FROM _options FOR UPDATE' );
128128
}
129129

130130
public function testInsertWithoutInto() {
@@ -11916,4 +11916,25 @@ public function testCreateTableWithDefaultExpressions(): void {
1191611916
$this->assertSame( "DATETIME(CURRENT_TIMESTAMP, '+' || 1 || ' YEAR')", $result[2]['dflt_value'] );
1191711917
$this->assertSame( "('a' || 'b')", $result[3]['dflt_value'] );
1191811918
}
11919+
11920+
public function testInsertIgnoreWithoutInto() {
11921+
$this->engine->query( 'CREATE TABLE test_ignore_no_into ( id INTEGER PRIMARY KEY, val TEXT )' );
11922+
$this->engine->query( "INSERT INTO test_ignore_no_into (id, val) VALUES (1, 'a')" );
11923+
11924+
// Test INSERT IGNORE without INTO
11925+
// This should be translated to "INSERT OR IGNORE INTO test_ignore_no_into ..."
11926+
$this->engine->query( "INSERT IGNORE test_ignore_no_into (id, val) VALUES (1, 'b')" );
11927+
$results = $this->engine->query( 'SELECT val FROM test_ignore_no_into WHERE id = 1' );
11928+
$this->assertEquals( 'a', $results[0]->val );
11929+
}
11930+
11931+
public function testInsertLowPriorityWithoutInto() {
11932+
$this->engine->query( 'CREATE TABLE test_low_priority_no_into ( id INTEGER PRIMARY KEY, val TEXT )' );
11933+
11934+
// Test INSERT LOW_PRIORITY without INTO
11935+
// This should be translated to "INSERT INTO test_low_priority_no_into ..." (dropping LOW_PRIORITY)
11936+
$this->engine->query( "INSERT LOW_PRIORITY test_low_priority_no_into (id, val) VALUES (1, 'a')" );
11937+
$results = $this->engine->query( 'SELECT val FROM test_low_priority_no_into WHERE id = 1' );
11938+
$this->assertEquals( 'a', $results[0]->val );
11939+
}
1191911940
}

wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,35 +1830,56 @@ private function execute_select_statement( WP_Parser_Node $node ): void {
18301830
private function execute_insert_or_replace_statement( WP_Parser_Node $node ): void {
18311831
$parts = array();
18321832
$on_conflict_update_list = null;
1833-
$has_into = false;
1833+
$seen_into = false;
1834+
$last_modifier_index = -1;
1835+
$is_insert = false;
1836+
18341837
foreach ( $node->get_children() as $child ) {
18351838
$is_token = $child instanceof WP_MySQL_Token;
18361839
$is_node = $child instanceof WP_Parser_Node;
18371840

1838-
if ( $is_token && WP_MySQL_Lexer::INTO_SYMBOL === $child->id ) {
1839-
$has_into = true;
1840-
}
1841-
1842-
if ( $child instanceof WP_Parser_Node && 'tableRef' === $child->rule_name ) {
1843-
if ( ! $has_into ) {
1844-
$parts[] = 'INTO';
1845-
$has_into = true;
1846-
}
1841+
if ( $is_node && 'tableRef' === $child->rule_name ) {
18471842
$database = $this->get_database_name( $child );
18481843
if ( 'information_schema' === strtolower( $database ) ) {
18491844
throw $this->new_access_denied_to_information_schema_exception();
18501845
}
18511846
}
18521847

1848+
if ( $is_node && in_array( $child->rule_name, array( 'insertLockOption', 'delayedOption' ), true ) ) {
1849+
// SQLite doesn't support these priority modifiers; skip them.
1850+
continue;
1851+
}
1852+
18531853
// Skip the SET keyword in "INSERT INTO ... SET ..." syntax.
18541854
if ( $is_token && WP_MySQL_Lexer::SET_SYMBOL === $child->id ) {
18551855
continue;
18561856
}
18571857

1858+
if ( $is_token && ( WP_MySQL_Lexer::INSERT_SYMBOL === $child->id || WP_MySQL_Lexer::REPLACE_SYMBOL === $child->id ) ) {
1859+
$is_insert = WP_MySQL_Lexer::INSERT_SYMBOL === $child->id;
1860+
$parts[] = $this->translate( $child );
1861+
$last_modifier_index = count( $parts ) - 1;
1862+
continue;
1863+
}
1864+
18581865
if ( $is_token && WP_MySQL_Lexer::IGNORE_SYMBOL === $child->id ) {
1859-
// Translate "UPDATE IGNORE" to "UPDATE OR IGNORE".
1860-
$parts[] = 'OR IGNORE';
1861-
} elseif (
1866+
// Translate MySQL "INSERT IGNORE" to SQLite "INSERT OR IGNORE".
1867+
$parts[] = $is_insert ? 'OR IGNORE' : 'IGNORE';
1868+
$last_modifier_index = count( $parts ) - 1;
1869+
continue;
1870+
}
1871+
1872+
if ( $is_token && WP_MySQL_Lexer::INTO_SYMBOL === $child->id ) {
1873+
$seen_into = true;
1874+
$part = $this->translate( $child );
1875+
if ( null !== $part ) {
1876+
$parts[] = $part;
1877+
$last_modifier_index = count( $parts ) - 1;
1878+
}
1879+
continue;
1880+
}
1881+
1882+
if (
18621883
$is_node
18631884
&& (
18641885
'insertFromConstructor' === $child->rule_name
@@ -1887,10 +1908,17 @@ private function execute_insert_or_replace_statement( WP_Parser_Node $node ): vo
18871908
$parts[] = $this->translate_update_list( $table_name, $child );
18881909
}
18891910
} else {
1890-
$parts[] = $this->translate( $child );
1911+
$part = $this->translate( $child );
1912+
if ( null !== $part ) {
1913+
$parts[] = $part;
1914+
}
18911915
}
18921916
}
18931917

1918+
if ( ! $seen_into && -1 !== $last_modifier_index ) {
1919+
array_splice( $parts, $last_modifier_index + 1, 0, array( 'INTO' ) );
1920+
}
1921+
18941922
$query = implode( ' ', $parts );
18951923

18961924
/*

0 commit comments

Comments
 (0)