@@ -905,24 +905,23 @@ private function execute_mysql_query( WP_Parser_Node $ast ) {
905
905
$ this ->execute_select_statement ( $ ast );
906
906
break ;
907
907
case 'insertStatement ' :
908
+ $ this ->query_type = 'INSERT ' ;
908
909
$ this ->execute_insert_statement ( $ ast );
909
910
break ;
910
911
case 'updateStatement ' :
912
+ $ this ->query_type = 'UPDATE ' ;
911
913
$ this ->execute_update_statement ( $ ast );
912
914
break ;
913
915
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 );
923
918
$ this ->execute_sqlite_query ( $ query );
924
919
$ this ->set_result_from_affected_rows ();
925
920
break ;
921
+ case 'deleteStatement ' :
922
+ $ this ->query_type = 'DELETE ' ;
923
+ $ this ->execute_delete_statement ( $ ast );
924
+ break ;
926
925
case 'createStatement ' :
927
926
$ this ->query_type = 'CREATE ' ;
928
927
$ subtree = $ ast ->get_child_node ();
@@ -1132,6 +1131,81 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
1132
1131
$ this ->set_result_from_affected_rows ();
1133
1132
}
1134
1133
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
+
1135
1209
private function execute_create_table_statement ( WP_Parser_Node $ node ): void {
1136
1210
$ is_temporary = $ node ->get_child_node ()->has_child_token ( WP_MySQL_Lexer::TEMPORARY_SYMBOL );
1137
1211
$ element_list = $ node ->get_descendant_node ( 'tableElementList ' );
@@ -1784,7 +1858,7 @@ private function translate_like( WP_Parser_Node $node ): string {
1784
1858
* We'll probably need to overload the like() function:
1785
1859
* https://www.sqlite.org/lang_corefunc.html#like
1786
1860
*/
1787
- return $ this ->translate_sequence ( $ node ->get_children () );
1861
+ return $ this ->translate_sequence ( $ node ->get_children () ) . " ESCAPE ' \\ ' " ;
1788
1862
}
1789
1863
1790
1864
private function translate_regexp_functions ( WP_Parser_Node $ node ): string {
0 commit comments