Skip to content

Commit 98ee736

Browse files
committed
Patch Turso hash-join planner for correlated subqueries
The join planner picks hash-join for tables inside a correlated subquery (current query block has non-empty outer_query_refs). The hash build runs once before outer-column refs are bound, so equality predicates against outer columns evaluate against NULL and produce 0 rows in the hash table. Every probe then misses, the scalar subquery returns NULL, and an outer WHERE filter on the alias discards everything. Repro: testInformationSchemaTablesFilterByAutoIncrement — the cols x sqlite_sequence join inside the AUTO_INCREMENT correlated subquery. Refuse hash-join when the current query block is itself correlated. Falls back to nested-loop, which re-evaluates per outer row. Worth reporting upstream — independent of mysql-on-sqlite.
1 parent 2ef2068 commit 98ee736

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,44 @@ jobs:
638638
print('patched translate_drop_table to use correct database schema for sqlite_sequence')
639639
PY_FIX_TEMP_DROP_SEQ
640640
641+
# 18. The join planner picks hash-join for tables inside a correlated
642+
# subquery (current block has non-empty outer_query_refs).
643+
# Hash-build runs once before outer column refs are bound, so
644+
# equality predicates against outer columns evaluate against
645+
# NULL, producing 0 rows in the hash table. Every probe then
646+
# misses, the scalar subquery returns NULL, and an outer
647+
# `WHERE alias > N` filter discards everything.
648+
# Repro: testInformationSchemaTablesFilterByAutoIncrement —
649+
# the cols × sqlite_sequence join inside the AUTO_INCREMENT
650+
# correlated subquery.
651+
# Fix: refuse hash-join when the current query block is
652+
# itself correlated (has outer_query_refs). Falls back to
653+
# nested-loop, which re-evaluates per outer row.
654+
python3 - <<'PY_FIX_HASH_JOIN_CORRELATED'
655+
p = 'core/translate/optimizer/join.rs'
656+
s = open(p).read()
657+
old = (
658+
" let allow_hash_join = !rhs_has_selective_seek\n"
659+
" && !probe_table_is_prior_build\n"
660+
" && (!build_has_prior_constraints || build_has_rowid)\n"
661+
" && !chaining_across_outer;\n"
662+
)
663+
new = (
664+
" // Refuse hash-join when the current query block is itself a\n"
665+
" // correlated subquery (has outer_query_refs). The hash build\n"
666+
" // would materialize once with outer column refs unbound,\n"
667+
" // yielding 0 rows for any predicate against an outer column.\n"
668+
" let allow_hash_join = !rhs_has_selective_seek\n"
669+
" && !probe_table_is_prior_build\n"
670+
" && (!build_has_prior_constraints || build_has_rowid)\n"
671+
" && !chaining_across_outer\n"
672+
" && table_references.outer_query_refs().is_empty();\n"
673+
)
674+
assert old in s, 'hash-join allow_hash_join block not found'
675+
open(p, 'w').write(s.replace(old, new, 1))
676+
print('patched join.rs to refuse hash-join in correlated query blocks')
677+
PY_FIX_HASH_JOIN_CORRELATED
678+
641679
echo '--- Patched stub! macro ---'
642680
sed -n '/macro_rules! stub/,/^}$/p' sqlite3/src/lib.rs
643681

0 commit comments

Comments
 (0)