Skip to content

Commit a74dd39

Browse files
committed
Revert VALUES-to-SELECT rewrite (persistent segfault in reconstructor)
The VALUES → SELECT-AS-columnN rewrite emitted INSERT ... SELECT ... FROM (SELECT <expr> AS column1 ...) which Turso could parse but segfaulted in 3/3 subsequent runs at testReconstructTable start. Unclear whether the crash is from the nested SELECT-in-FROM form, Turso's reconstructor-path memory handling, or an interaction — but reverting restores the stable 571/596 state. Keep the hex-literal expectation update (it's independent of the VALUES change).
1 parent e7cf0cf commit a74dd39

1 file changed

Lines changed: 1 addition & 104 deletions

File tree

.github/workflows/phpunit-tests-turso.yml

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,113 +1057,10 @@ jobs:
10571057
open(path, 'w').write(src.replace(old, new, 1))
10581058
print('patched CHECK TABLE missing-table check')
10591059
1060-
# 12. Turso doesn't propagate VALUES row-column aliases (column1,
1061-
# column2, ...) through `INSERT ... SELECT ... FROM (VALUES ...)`
1062-
# subqueries — outer reference to `column1` fails with
1063-
# "no such column". Replace the VALUES subquery with a
1064-
# UNION ALL of SELECTs carrying explicit `expr AS columnN`
1065-
# aliases (single-row case collapses to a single SELECT).
1066-
path = 'src/sqlite/class-wp-pdo-mysql-on-sqlite.php'
1067-
src = open(path).read()
1068-
old = (
1069-
"\t\tif ( 'insertFromConstructor' === $node->rule_name ) {\n"
1070-
"\t\t\t// VALUES (...)\n"
1071-
"\t\t\t$insert_values = $node->get_first_child_node( 'insertValues' );\n"
1072-
"\t\t\t$from = $this->translate( $insert_values );\n"
1073-
"\n"
1074-
"\t\t\t/**\n"
1075-
"\t\t\t * The automatic \"columnN\" naming for VALUES lists is supported only\n"
1076-
"\t\t\t * from SQLite 3.33.0. For older versions, we need to emulate it by\n"
1077-
"\t\t\t * prepending a dummy VALUES list header via the UNION ALL operator:\n"
1078-
"\t\t\t *\n"
1079-
"\t\t\t * SELECT\n"
1080-
"\t\t\t * NULL AS `column1`, NULL AS `column2`, ... WHERE FALSE\n"
1081-
"\t\t\t * UNION ALL\n"
1082-
"\t\t\t * VALUES (value1, value2, ...)\n"
1083-
"\t\t\t */\n"
1084-
"\t\t\t$is_values_naming_supported = version_compare( $this->get_sqlite_version(), '3.33.0', '>=' );\n"
1085-
"\t\t\tif ( ! $is_values_naming_supported ) {\n"
1086-
"\t\t\t\t$values_list = $insert_values->get_first_child_node( 'valueList' );\n"
1087-
"\t\t\t\t$values = $values_list->get_first_child_node( 'values' );\n"
1088-
"\t\t\t\t$value_count = (\n"
1089-
"\t\t\t\t\tcount( $values->get_child_nodes( 'expr' ) )\n"
1090-
"\t\t\t\t\t+ count( $values->get_child_nodes( WP_MySQL_Lexer::DEFAULT_SYMBOL ) )\n"
1091-
"\t\t\t\t);\n"
1092-
"\n"
1093-
"\t\t\t\t$columns_list = '';\n"
1094-
"\t\t\t\tfor ( $i = 1; $i <= $value_count; $i++ ) {\n"
1095-
"\t\t\t\t\t$columns_list .= $i > 1 ? ', ' : '';\n"
1096-
"\t\t\t\t\t$columns_list .= 'NULL AS ' . $this->quote_sqlite_identifier( 'column' . $i );\n"
1097-
"\t\t\t\t}\n"
1098-
"\t\t\t\t$from = 'SELECT ' . $columns_list . ' WHERE FALSE UNION ALL ' . $from;\n"
1099-
"\t\t\t}\n"
1100-
"\t\t}"
1101-
)
1102-
new = (
1103-
"\t\tif ( 'insertFromConstructor' === $node->rule_name ) {\n"
1104-
"\t\t\t// Build a UNION ALL of SELECT rows with explicit `expr AS columnN`\n"
1105-
"\t\t\t// aliases. Turso doesn't propagate implicit VALUES column names\n"
1106-
"\t\t\t// through INSERT...SELECT subqueries.\n"
1107-
"\t\t\t$insert_values = $node->get_first_child_node( 'insertValues' );\n"
1108-
"\t\t\t$value_list = $insert_values->get_first_child_node( 'valueList' );\n"
1109-
"\t\t\t$values_nodes = $value_list->get_child_nodes( 'values' );\n"
1110-
"\t\t\t$select_rows = array();\n"
1111-
"\t\t\tforeach ( $values_nodes as $values_node ) {\n"
1112-
"\t\t\t\t$position = 0;\n"
1113-
"\t\t\t\t$row_parts = array();\n"
1114-
"\t\t\t\tforeach ( $values_node->get_children() as $child ) {\n"
1115-
"\t\t\t\t\tif ( $child instanceof WP_Parser_Node && 'expr' === $child->rule_name ) {\n"
1116-
"\t\t\t\t\t\t$expr_sql = $this->translate( $child );\n"
1117-
"\t\t\t\t\t\t$row_parts[] = $expr_sql . ' AS ' . $this->quote_sqlite_identifier( 'column' . ( $position + 1 ) );\n"
1118-
"\t\t\t\t\t\t$position++;\n"
1119-
"\t\t\t\t\t} elseif ( $child instanceof WP_Parser_Token && WP_MySQL_Lexer::DEFAULT_SYMBOL === $child->id ) {\n"
1120-
"\t\t\t\t\t\t$row_parts[] = 'NULL AS ' . $this->quote_sqlite_identifier( 'column' . ( $position + 1 ) );\n"
1121-
"\t\t\t\t\t\t$position++;\n"
1122-
"\t\t\t\t\t}\n"
1123-
"\t\t\t\t}\n"
1124-
"\t\t\t\t$select_rows[] = 'SELECT ' . implode( ', ', $row_parts );\n"
1125-
"\t\t\t}\n"
1126-
"\t\t\t$from = implode( ' UNION ALL ', $select_rows );\n"
1127-
"\t\t}"
1128-
)
1129-
assert old in src, 'insertFromConstructor VALUES block not found'
1130-
open(path, 'w').write(src.replace(old, new, 1))
1131-
print('patched insertFromConstructor to emit SELECT-with-aliases form')
1132-
1133-
# 13. Update Translation_Tests expectations to match the new
1134-
# SELECT-AS-columnN form emitted by insertFromConstructor.
1135-
import re
1136-
path = 'tests/WP_SQLite_Driver_Translation_Tests.php'
1137-
src = open(path).read()
1138-
# Match `FROM (VALUES ( v1 [, v2 ...] ) [, ( ... ) ...])`
1139-
# where values are simple literals (no nested parens or strings
1140-
# containing parens — good enough for all hits in this file).
1141-
values_pattern = re.compile(
1142-
r"\(VALUES "
1143-
r"\( ([^()]+) \)"
1144-
r"((?: , \( [^()]+ \))*)"
1145-
r"\)"
1146-
)
1147-
def rewrite_values(m):
1148-
first_row = m.group(1).strip()
1149-
extra_rows_text = m.group(2)
1150-
rows = [first_row]
1151-
for row_match in re.finditer(r"\( ([^()]+) \)", extra_rows_text):
1152-
rows.append(row_match.group(1).strip())
1153-
selects = []
1154-
for row in rows:
1155-
values = [v.strip() for v in row.split(',')]
1156-
parts = [f"{v} AS `column{i+1}`" for i, v in enumerate(values)]
1157-
selects.append("SELECT " + ", ".join(parts))
1158-
return "(" + " UNION ALL ".join(selects) + ")"
1159-
new_src, n = values_pattern.subn(rewrite_values, src)
1160-
assert n >= 10, f'expected 10+ VALUES expectations, matched {n}'
1161-
open(path, 'w').write(new_src)
1162-
print(f'patched {n} Translation_Tests VALUES expectations to SELECT form')
1163-
11641060
# 14. Update Translation_Tests::testHexadecimalLiterals to match
11651061
# the hex-literal alias force patch (which needs to stay so
11661062
# Turso doesn't mangle x'417a' into 17a' at runtime).
1063+
path = 'tests/WP_SQLite_Driver_Translation_Tests.php'
11671064
src = open(path).read()
11681065
for old_q, new_q in [
11691066
("\"SELECT x'417a'\",\n\t\t\t\"SELECT x'417a'\"",

0 commit comments

Comments
 (0)