Skip to content
This repository was archived by the owner on Jun 2, 2025. It is now read-only.

Commit 227e353

Browse files
committed
WIP
1 parent ff8afed commit 227e353

File tree

2 files changed

+84
-12
lines changed

2 files changed

+84
-12
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,6 @@ public function testShowCreateTable1() {
285285
'SHOW CREATE TABLE _tmp_table;'
286286
);
287287
$results = $this->engine->get_query_results();
288-
# TODO: Should we fix mismatch with original `option_value` text NOT NULL,` without default?
289288
$this->assertEquals(
290289
"CREATE TABLE `_tmp_table` (
291290
`ID` bigint NOT NULL AUTO_INCREMENT,
@@ -314,7 +313,6 @@ public function testShowCreateTableQuoted() {
314313
'SHOW CREATE TABLE `_tmp_table`;'
315314
);
316315
$results = $this->engine->get_query_results();
317-
# TODO: Should we fix mismatch with original `option_value` text NOT NULL,` without default?
318316
$this->assertEquals(
319317
"CREATE TABLE `_tmp_table` (
320318
`ID` bigint NOT NULL AUTO_INCREMENT,

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

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -905,24 +905,23 @@ private function execute_mysql_query( WP_Parser_Node $ast ) {
905905
$this->execute_select_statement( $ast );
906906
break;
907907
case 'insertStatement':
908+
$this->query_type = 'INSERT';
908909
$this->execute_insert_statement( $ast );
909910
break;
910911
case 'updateStatement':
912+
$this->query_type = 'UPDATE';
911913
$this->execute_update_statement( $ast );
912914
break;
913915
case 'replaceStatement':
914-
case 'deleteStatement':
915-
if ( 'insertStatement' === $ast->rule_name ) {
916-
$this->query_type = 'INSERT';
917-
} elseif ( 'replaceStatement' === $ast->rule_name ) {
918-
$this->query_type = 'REPLACE';
919-
} elseif ( 'deleteStatement' === $ast->rule_name ) {
920-
$this->query_type = 'DELETE';
921-
}
922-
$query = $this->translate( $ast );
916+
$this->query_type = 'REPLACE';
917+
$query = $this->translate( $ast );
923918
$this->execute_sqlite_query( $query );
924919
$this->set_result_from_affected_rows();
925920
break;
921+
case 'deleteStatement':
922+
$this->query_type = 'DELETE';
923+
$this->execute_delete_statement( $ast );
924+
break;
926925
case 'createStatement':
927926
$this->query_type = 'CREATE';
928927
$subtree = $ast->get_child_node();
@@ -1132,6 +1131,81 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
11321131
$this->set_result_from_affected_rows();
11331132
}
11341133

1134+
private function execute_delete_statement( WP_Parser_Node $node ): void {
1135+
/*
1136+
* Multi-table DELETE.
1137+
*
1138+
* MySQL supports multi-table DELETE statements that don't work in SQLite.
1139+
* These statements can have two flavours:
1140+
* 1. "DELETE t1, t2 FROM ... JOIN ... WHERE ..."
1141+
* 2. "DELETE FROM t1, t2 USING ... JOIN ... WHERE ..."
1142+
*
1143+
* We will rewrite such statements into a SELECT to fetch the ROWIDs of
1144+
* the rows to delete and the execute a DELETE statement for each table.
1145+
*/
1146+
$alias_ref_list = $node->get_child_node( 'tableAliasRefList' );
1147+
if ( null !== $alias_ref_list ) {
1148+
$tables = array();
1149+
foreach ( $alias_ref_list->get_child_nodes() as $table ) {
1150+
$tables[] = $this->unquote_sqlite_identifier(
1151+
$this->translate( $table )
1152+
);
1153+
}
1154+
1155+
$select_list = array();
1156+
foreach ( $tables as $table ) {
1157+
$select_list[] = "\"$table\".rowid AS \"{$table}_rowid\"";
1158+
}
1159+
1160+
$alias_map = array();
1161+
$table_ref_list = $node->get_child_node( 'tableReferenceList' );
1162+
foreach ( $table_ref_list->get_descendant_nodes( 'singleTable' ) as $single_table ) {
1163+
$alias = $this->unquote_sqlite_identifier(
1164+
$this->translate( $single_table->get_child_node( 'tableAlias' ) )
1165+
);
1166+
$ref = $this->unquote_sqlite_identifier(
1167+
$this->translate( $single_table->get_child_node( 'tableRef' ) )
1168+
);
1169+
$alias_map[ $alias ] = $ref;
1170+
}
1171+
1172+
$where_clause = $node->get_child_node( 'whereClause' );
1173+
if ( null !== $where_clause ) {
1174+
$where = $this->translate( $where_clause->get_child_node( 'expr' ) );
1175+
}
1176+
1177+
$result = $this->execute_sqlite_query(
1178+
sprintf(
1179+
'SELECT %s FROM %s %s',
1180+
implode( ', ', $select_list ),
1181+
$this->translate( $table_ref_list ),
1182+
isset( $where ) ? "WHERE $where" : ''
1183+
)
1184+
);
1185+
$ids = $result->fetchAll( PDO::FETCH_ASSOC );
1186+
1187+
$rows = 0;
1188+
foreach ( $tables as $table ) {
1189+
$this->execute_sqlite_query(
1190+
sprintf(
1191+
'DELETE FROM "%s" AS %s WHERE rowid IN ( %s )',
1192+
$alias_map[ $table ],
1193+
$table,
1194+
implode( ', ', array_column( $ids, "{$table}_rowid" ) )
1195+
)
1196+
);
1197+
$this->set_result_from_affected_rows();
1198+
$rows += $this->affected_rows;
1199+
}
1200+
$this->set_result_from_affected_rows( $rows );
1201+
return;
1202+
}
1203+
1204+
$query = $this->translate( $node );
1205+
$this->execute_sqlite_query( $query );
1206+
$this->set_result_from_affected_rows();
1207+
}
1208+
11351209
private function execute_create_table_statement( WP_Parser_Node $node ): void {
11361210
$is_temporary = $node->get_child_node()->has_child_token( WP_MySQL_Lexer::TEMPORARY_SYMBOL );
11371211
$element_list = $node->get_descendant_node( 'tableElementList' );
@@ -1784,7 +1858,7 @@ private function translate_like( WP_Parser_Node $node ): string {
17841858
* We'll probably need to overload the like() function:
17851859
* https://www.sqlite.org/lang_corefunc.html#like
17861860
*/
1787-
return $this->translate_sequence( $node->get_children() );
1861+
return $this->translate_sequence( $node->get_children() ) . " ESCAPE '\\'";
17881862
}
17891863

17901864
private function translate_regexp_functions( WP_Parser_Node $node ): string {

0 commit comments

Comments
 (0)