@@ -1286,14 +1286,6 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
12861286 * SET_SYMBOL updateList whereClause? orderClause? simpleLimitClause?
12871287 */
12881288
1289- // Translate WITH clause.
1290- $ with = $ this ->translate ( $ node ->get_first_child_node ( 'withClause ' ) );
1291-
1292- // Translate "UPDATE IGNORE" to "UPDATE OR IGNORE".
1293- $ or_ignore = $ node ->has_child_token ( WP_MySQL_Lexer::IGNORE_SYMBOL )
1294- ? 'OR IGNORE '
1295- : null ;
1296-
12971289 // Collect all tables used in the UPDATE clause (e.g, UPDATE t1, t2 JOIN t3).
12981290 $ table_alias_map = $ this ->create_table_reference_map (
12991291 $ node ->get_first_child_node ( 'tableReferenceList ' )
@@ -1316,7 +1308,7 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
13161308 if ( null === $ table_or_alias ) {
13171309 $ persistent_table_names = array ();
13181310 $ temporary_table_names = array ();
1319- foreach ( array_column ( $ table_alias_map , 'table_name ' ) as $ table_name ) {
1311+ foreach ( array_filter ( array_column ( $ table_alias_map , 'table_name ' ) ) as $ table_name ) {
13201312 $ is_temporary = $ this ->information_schema_builder ->temporary_table_exists ( $ table_name );
13211313 $ quoted_table_name = $ this ->connection ->quote ( $ table_name );
13221314 if ( $ is_temporary ) {
@@ -1387,18 +1379,42 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
13871379 throw $ this ->new_not_supported_exception ( 'UPDATE statement modifying multiple tables ' );
13881380 }
13891381
1382+ // Translate WITH clause.
1383+ $ with = $ this ->translate ( $ node ->get_first_child_node ( 'withClause ' ) );
1384+
1385+ // Translate "UPDATE IGNORE" to "UPDATE OR IGNORE".
1386+ $ or_ignore = $ node ->has_child_token ( WP_MySQL_Lexer::IGNORE_SYMBOL )
1387+ ? 'OR IGNORE '
1388+ : null ;
1389+
1390+ // Compose the update target clause.
1391+ $ update_target = $ table_alias_map [ $ update_target ]['table_name ' ] ?? $ update_target ;
1392+ $ update_target_clause = $ this ->quote_sqlite_identifier ( $ update_target );
1393+ if ( $ update_target !== ( $ table_alias_map [ $ update_target ]['table_name ' ] ?? null ) ) {
1394+ $ update_target_clause .= ' AS ' . $ this ->quote_sqlite_identifier ( $ update_target );
1395+ }
1396+
13901397 // Compose the FROM clause using all tables except the one being updated.
13911398 // UPDATE with FROM in SQLite is equivalent to UPDATE with JOIN in MySQL.
13921399 $ from_items = array ();
13931400 foreach ( $ table_alias_map as $ alias => $ data ) {
1394- $ table_name = $ data ['table_name ' ];
13951401 if ( $ alias === $ update_target ) {
13961402 continue ;
13971403 }
13981404
1399- $ from_item = $ this ->quote_sqlite_identifier ( $ alias );
1405+ $ table_name = $ data ['table_name ' ];
1406+
1407+ // Derived table.
1408+ if ( null === $ table_name ) {
1409+ $ from_item = $ data ['table_expr ' ] . ' AS ' . $ this ->quote_sqlite_identifier ( $ alias );
1410+ $ from_items [] = $ from_item ;
1411+ continue ;
1412+ }
1413+
1414+ // Regular table.
1415+ $ from_item = $ this ->quote_sqlite_identifier ( $ table_name );
14001416 if ( $ alias !== $ table_name ) {
1401- $ from_item .= ' AS ' . $ this ->quote_sqlite_identifier ( $ table_name );
1417+ $ from_item .= ' AS ' . $ this ->quote_sqlite_identifier ( $ alias );
14021418 }
14031419 $ from_items [] = $ from_item ;
14041420 }
@@ -1449,7 +1465,7 @@ private function execute_update_statement( WP_Parser_Node $node ): void {
14491465 $ with ,
14501466 'UPDATE ' ,
14511467 $ or_ignore ,
1452- $ this -> quote_sqlite_identifier ( $ update_target ) ,
1468+ $ update_target_clause ,
14531469 'SET ' ,
14541470 $ update_list ,
14551471 $ from ,
@@ -4107,8 +4123,9 @@ private function create_select_item_disambiguation_map( WP_Parser_Node $select_i
41074123 * The returned array maps table aliases to table names and additional data:
41084124 * - key: table alias, or name if no alias is used
41094125 * - value: an array of table data
4110- * - table_name: the real name of the table
4111- * - join_expr: the join expression used for the table
4126+ * - table_name: the real name of the table (null for derived tables)
4127+ * - table_expr: the table expression for a derived table (null for regular tables)
4128+ * - join_expr: the join expression used for the table (null when no join is used)
41124129 *
41134130 * MySQL has a non-stand ardsyntax extension where a comma-separated list of
41144131 * table references is allowed as a table reference in itself, for instance:
@@ -4150,6 +4167,17 @@ private function create_table_reference_map( WP_Parser_Node $node ): array {
41504167
41514168 $ table_map [ $ this ->unquote_sqlite_identifier ( $ alias ?? $ name ) ] = array (
41524169 'table_name ' => $ this ->unquote_sqlite_identifier ( $ name ),
4170+ 'table_expr ' => null ,
4171+ 'join_expr ' => $ this ->translate ( $ join_expr ),
4172+ );
4173+ } elseif ( 'derivedTable ' === $ child ->rule_name ) {
4174+ // Extract data from the "derivedTable" node.
4175+ $ subquery = $ child ->get_first_descendant_node ( 'subquery ' );
4176+ $ alias = $ this ->translate ( $ child ->get_first_child_node ( 'tableAlias ' ) );
4177+
4178+ $ table_map [ $ this ->unquote_sqlite_identifier ( $ alias ) ] = array (
4179+ 'table_name ' => null ,
4180+ 'table_expr ' => $ this ->translate ( $ subquery ),
41534181 'join_expr ' => $ this ->translate ( $ join_expr ),
41544182 );
41554183 } elseif ( 'tableReferenceListParens ' === $ child ->rule_name ) {
0 commit comments