Skip to content

Commit 3366e9d

Browse files
committed
Implement INSERT INTO ... SET ... syntax in non-strict mode
1 parent ca02b66 commit 3366e9d

2 files changed

Lines changed: 78 additions & 7 deletions

File tree

tests/WP_SQLite_Driver_Tests.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9475,4 +9475,50 @@ public function testInsertIntoSetSyntax(): void {
94759475
$result
94769476
);
94779477
}
9478+
9479+
public function testInsertIntoSetSyntaxInNonStrictMode(): void {
9480+
$this->assertQuery( "SET SESSION sql_mode = ''" );
9481+
9482+
$this->assertQuery(
9483+
'CREATE TABLE t (
9484+
id INT PRIMARY KEY AUTO_INCREMENT,
9485+
created_at DATETIME NOT NULL,
9486+
name VARCHAR(255) NOT NULL,
9487+
value TEXT,
9488+
score INT NOT NULL
9489+
)'
9490+
);
9491+
9492+
$this->assertQuery( "INSERT INTO t SET name = 'one'" );
9493+
$this->assertQuery( "INSERT INTO t SET name = 'two', value = 'two-value'" );
9494+
$this->assertQuery( "INSERT INTO t SET value = 'three-value', name = 'three'" );
9495+
9496+
$result = $this->assertQuery( 'SELECT * FROM t' );
9497+
$this->assertEquals(
9498+
array(
9499+
(object) array(
9500+
'id' => '1',
9501+
'created_at' => '0000-00-00 00:00:00',
9502+
'name' => 'one',
9503+
'value' => null,
9504+
'score' => '0',
9505+
),
9506+
(object) array(
9507+
'id' => '2',
9508+
'created_at' => '0000-00-00 00:00:00',
9509+
'name' => 'two',
9510+
'value' => 'two-value',
9511+
'score' => '0',
9512+
),
9513+
(object) array(
9514+
'id' => '3',
9515+
'created_at' => '0000-00-00 00:00:00',
9516+
'name' => 'three',
9517+
'value' => 'three-value',
9518+
'score' => '0',
9519+
),
9520+
),
9521+
$result
9522+
);
9523+
}
94789524
}

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

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,8 +1542,12 @@ private function execute_insert_or_replace_statement( WP_Parser_Node $node ): vo
15421542
$parts[] = 'OR IGNORE';
15431543
} elseif (
15441544
$is_non_strict_mode
1545-
&& $child instanceof WP_Parser_Node
1546-
&& ( 'insertFromConstructor' === $child->rule_name || 'insertQueryExpression' === $child->rule_name )
1545+
&& $is_node
1546+
&& (
1547+
'insertFromConstructor' === $child->rule_name
1548+
|| 'insertQueryExpression' === $child->rule_name
1549+
|| 'updateList' === $child->rule_name
1550+
)
15471551
) {
15481552
$table_ref = $node->get_first_child_node( 'tableRef' );
15491553
$table_name = $this->unquote_sqlite_identifier( $this->translate( $table_ref ) );
@@ -4322,6 +4326,12 @@ private function translate_insert_or_replace_body_in_non_strict_mode(
43224326
foreach ( $fields_node->get_child_nodes() as $field ) {
43234327
$insert_list[] = $this->unquote_sqlite_identifier( $this->translate( $field ) );
43244328
}
4329+
} elseif ( 'updateList' === $node->rule_name ) {
4330+
// This is the "INSERT INTO ... SET c1 = v1, c2 = v2, ... " syntax.
4331+
foreach ( $node->get_child_nodes( 'updateElement' ) as $update_element ) {
4332+
$column_ref = $update_element->get_first_child_node( 'columnRef' );
4333+
$insert_list[] = $this->unquote_sqlite_identifier( $this->translate( $column_ref ) );
4334+
}
43254335
} else {
43264336
// When no explicit field list is provided, all columns are required.
43274337
foreach ( array_column( $columns, 'COLUMN_NAME' ) as $column_name ) {
@@ -4402,10 +4412,25 @@ function ( $column ) use ( $insert_list ) {
44024412
}
44034413
}
44044414

4405-
// 6. Wrap the original insert VALUES or SELECT expression in a FROM clause.
4406-
$values = 'insertFromConstructor' === $node->rule_name
4407-
? $node->get_first_child_node( 'insertValues' )
4408-
: $node->get_first_child_node( 'queryExpressionOrParens' );
4415+
// 6. Wrap the original insert VALUES, SELECT, or SET list in a FROM clause.
4416+
if ( 'insertFromConstructor' === $node->rule_name ) {
4417+
// VALUES (...)
4418+
$from = $this->translate(
4419+
$node->get_first_child_node( 'insertValues' )
4420+
);
4421+
} elseif ( 'insertQueryExpression' === $node->rule_name ) {
4422+
// SELECT ...
4423+
$from = $this->translate(
4424+
$node->get_first_child_node( 'queryExpressionOrParens' )
4425+
);
4426+
} else {
4427+
// SET c1 = v1, c2 = v2, ...
4428+
$values = array();
4429+
foreach ( $node->get_child_nodes( 'updateElement' ) as $update_element ) {
4430+
$values[] = $this->translate( $update_element->get_first_child_node( 'expr' ) );
4431+
}
4432+
$from = 'VALUES (' . implode( ', ', $values ) . ')';
4433+
}
44094434

44104435
/*
44114436
* The "WHERE true" suffix is used to avoid parsing ambiguity in SQLite.
@@ -4414,7 +4439,7 @@ function ( $column ) use ( $insert_list ) {
44144439
*
44154440
* See: https://www.sqlite.org/lang_insert.html
44164441
*/
4417-
$fragment .= ' FROM (' . $this->translate( $values ) . ') WHERE true';
4442+
$fragment .= ' FROM (' . $from . ') WHERE true';
44184443

44194444
return $fragment;
44204445
}

0 commit comments

Comments
 (0)