@@ -1275,6 +1275,78 @@ jobs:
12751275 open(path, 'w').write(src.replace(old, new, 1))
12761276 print('patched DEFAULT_GENERATED simple-identifier unwrap')
12771277
1278+ # 16. Turso doesn't implement UPDATE ... FROM. The driver uses it to
1279+ # translate MySQL multi-table UPDATE (UPDATE t1, t2 JOIN t3 SET
1280+ # ... WHERE ...). Rewrite as UPDATE t SET ... WHERE rowid IN
1281+ # (SELECT t.rowid FROM tableRefList WHERE <orig where>).
1282+ old = (
1283+ "\t\t// Compose the FROM clause using all tables except the one being updated.\n"
1284+ "\t\t// UPDATE with FROM in SQLite is equivalent to UPDATE with JOIN in MySQL.\n"
1285+ "\t\t$from_items = array();\n"
1286+ )
1287+ new = (
1288+ "\t\t// For multi-table UPDATE, Turso doesn't support UPDATE ... FROM.\n"
1289+ "\t\t// Build a rowid-IN subquery that selects target rowids via the\n"
1290+ "\t\t// full tableReferenceList, then do a plain single-table UPDATE.\n"
1291+ "\t\tif ( count( $table_alias_map ) > 1 && null === $where_subquery ) {\n"
1292+ "\t\t\t$where_subquery = 'SELECT ' . $this->quote_sqlite_identifier( $update_target ) . '.rowid FROM '\n"
1293+ "\t\t\t\t. $this->translate_sequence(\n"
1294+ "\t\t\t\t\tarray(\n"
1295+ "\t\t\t\t\t\t$node->get_first_child_node( 'tableReferenceList' ),\n"
1296+ "\t\t\t\t\t\t$node->get_first_child_node( 'whereClause' ),\n"
1297+ "\t\t\t\t\t)\n"
1298+ "\t\t\t\t);\n"
1299+ "\t\t}\n"
1300+ "\n"
1301+ "\t\t// Compose the FROM clause using all tables except the one being updated.\n"
1302+ "\t\t// UPDATE with FROM in SQLite is equivalent to UPDATE with JOIN in MySQL.\n"
1303+ "\t\t$from_items = array();\n"
1304+ )
1305+ assert old in src, 'UPDATE from-clause preamble not found'
1306+ src = src.replace(old, new, 1)
1307+
1308+ # Also: when where_subquery is in play (either from ORDER/LIMIT or
1309+ # our multi-table rewrite), skip $from entirely — rowid-IN subquery
1310+ # contains all the JOIN info.
1311+ old2 = (
1312+ "\t\t$from = null;\n"
1313+ "\t\tif ( count( $from_items ) > 0 ) {\n"
1314+ "\t\t\t$from = 'FROM ' . implode( ', ', $from_items );\n"
1315+ "\t\t}\n"
1316+ )
1317+ new2 = (
1318+ "\t\t$from = null;\n"
1319+ "\t\tif ( count( $from_items ) > 0 && null === $where_subquery ) {\n"
1320+ "\t\t\t$from = 'FROM ' . implode( ', ', $from_items );\n"
1321+ "\t\t}\n"
1322+ )
1323+ assert old2 in src, 'UPDATE from-clause block not found'
1324+ src = src.replace(old2, new2, 1)
1325+
1326+ # Also skip the join_exprs re-append when where_subquery is in play:
1327+ # JOIN ON conditions are already inside the rowid-IN subquery.
1328+ old3 = (
1329+ "\t\t// With JOINs, we need to use the JOIN expressions in the WHERE clause.\n"
1330+ "\t\t$join_exprs = array_filter( array_column( $table_alias_map, 'join_expr' ) );\n"
1331+ "\t\tif ( count( $join_exprs ) > 0 ) {\n"
1332+ "\t\t\t$where_clause .= $where_clause ? ' AND ' : ' WHERE ';\n"
1333+ "\t\t\t$where_clause .= implode( ' AND ', $join_exprs );\n"
1334+ "\t\t}\n"
1335+ )
1336+ new3 = (
1337+ "\t\t// With JOINs, we need to use the JOIN expressions in the WHERE clause.\n"
1338+ "\t\t// Skip when $where_subquery holds the conditions already.\n"
1339+ "\t\t$join_exprs = array_filter( array_column( $table_alias_map, 'join_expr' ) );\n"
1340+ "\t\tif ( count( $join_exprs ) > 0 && null === $where_subquery ) {\n"
1341+ "\t\t\t$where_clause .= $where_clause ? ' AND ' : ' WHERE ';\n"
1342+ "\t\t\t$where_clause .= implode( ' AND ', $join_exprs );\n"
1343+ "\t\t}\n"
1344+ )
1345+ assert old3 in src, 'UPDATE join_exprs block not found'
1346+ src = src.replace(old3, new3, 1)
1347+ open(path, 'w').write(src)
1348+ print('patched UPDATE multi-table to rowid-IN subquery')
1349+
12781350 # 14. Update Translation_Tests::testHexadecimalLiterals to match
12791351 # the hex-literal alias force patch (which needs to stay so
12801352 # Turso doesn't mangle x'417a' into 17a' at runtime).
0 commit comments