You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(specializer): LIKE / NOT LIKE / ILIKE with full ESCAPE semantics (TASK-48)
Byte-based matcher with codepoint _, leftmost-first two-pointer
backtracking: identical booleans AND identical error rows to DuckDB —
including the data-dependent dangling-escape (plain false when the
string is exhausted, per-row SyntaxException only when the matcher
examines it with bytes remaining) — at O(n*m) where DuckDB's own
column-pattern path is naive-recursive (measured 23s on one
pathological row). ESCAPE: any single byte, doubled = literal, the
escape char never matches itself unescaped, '' = none, NULL = NULL,
multi-byte operand traps with DuckDB's message. ILIKE folds both
sides with the measured simple casemap (== DuckDB lower(), exhaustive
sweep). The corpus replay caught a genuine oracle divergence: ILIKE
on NUL-containing rows is COLUMN-STATISTICS-dependent in DuckDB
(sibling rows change the result) — irreproducible row-locally, now
the repo's first documented divergence with the measurement attached.
SIMILAR TO rejects by name (binds to regexp_full_match in DuckDB).
Corpus: 240 -> 265 of 678, zero FAILs; gate green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: backlog/tasks/task-48 - Specializer-SQL-support-LIKE-alias-comma-join-wave-2.md
+11-5Lines changed: 11 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,15 +24,21 @@ The dual-axis rung plus two structural cheap wins, ~120 corpus first-blockers in
24
24
25
25
## Acceptance Criteria
26
26
<!-- AC:BEGIN -->
27
-
-[]#1 LIKE semantics pinned by measurement (duck_check tests recorded before implementation: wildcards, ESCAPE, unicode, NULL, degenerate patterns) and both backends agree via a shared matcher (differential extended)
28
-
-[]#2 Dynamic-table alias binds (qualified refs via alias, original name behavior measured and mirrored)
27
+
-[x]#1 LIKE semantics pinned by measurement (duck_check tests recorded before implementation: wildcards, ESCAPE, unicode, NULL, degenerate patterns) and both backends agree via a shared matcher (differential extended)
28
+
-[x]#2 Dynamic-table alias binds (qualified refs via alias, original name behavior measured and mirrored)
29
29
-[x]#3 RE-SCOPED by census (recorded below): the corpus comma-join cases are SELF-joins of the dynamic table (FROM integers i1, integers i2 ...), not dynamic-x-static shapes — a rewrite would flip ~0 cases. Comma-join stays cleanly unsupported; dynamic self-join is a distinct future feature (needs row-table-as-static materialization).
30
-
-[]#4 Corpus replay: wave-2 first-blocker cases flip to match or a named deeper blocker; zero FAILs; tally recorded here
31
-
-[]#5 mise gate-specializer green
30
+
-[x]#4 Corpus replay: wave-2 first-blocker cases flip to match or a named deeper blocker; zero FAILs; tally recorded here
31
+
-[x]#5 mise gate-specializer green
32
32
<!-- AC:END -->
33
33
34
34
## Implementation Notes
35
35
36
36
<!-- SECTION:NOTES:BEGIN -->
37
-
Census before code (2026-07-26): the 30 alias-first-blocker cases are mostly alias + a DEEPER blocker (self-joins, USING, rowid, column-renaming aliases); the ~30 comma-join cases are nearly all SELF cross-products of the dynamic table — the planned equi-WHERE rewrite would flip approximately zero, so it was dropped from scope honestly rather than shipped as dead code. Alias landed: the alias REPLACES the original name (measured: qualified refs through the original are DuckDB binder errors) — implemented by making the alias the binder's this_name, which yields exactly that scoping for qualified refs, star expansion, and error messages; AS/bare forms identical; column-renaming alias t(a,b) rejects by name. LIKE pins fleet running; matcher lands next.
37
+
Census before code (2026-07-26): the 30 alias-first-blocker cases are mostly alias + a DEEPER blocker (self-joins, USING, rowid, column-renaming aliases); the ~30 comma-join cases are nearly all SELF cross-products of the dynamic table — the planned equi-WHERE rewrite would flip approximately zero, so it was dropped from scope honestly rather than shipped as dead code. Alias landed: the alias REPLACES the original name (measured: qualified refs through the original are DuckDB binder errors) — implemented by making the alias the binder's this_name, which yields exactly that scoping for qualified refs, star expansion, and error messages; AS/bare forms identical; column-renaming alias t(a,b) rejects by name. LIKE landed: byte-based O(n*m) two-pointer matcher with codepoint _, leftmost-first backtracking reproducing the DATA-DEPENDENT dangling-escape error rows, full ESCAPE semantics (any single byte, doubled = literal, never self-matching, '' = none, NULL = NULL), NOT LIKE, and ILIKE via double simple-casemap fold (exhaustively verified vs DuckDB lower()). The corpus caught a live divergence during replay: DuckDB's ILIKE result for NUL-containing rows depends on SIBLING rows (stats-selected kernels; the generic one NUL-truncates) — irreproducible row-locally, recorded as the repo's first documented oracle divergence (_KNOWN_DIVERGENT_SOURCES) with the measurement in the pins. SIMILAR TO rejects by name (DuckDB binds it to regexp_full_match). CORPUS: 240 -> 265 match of 678, zero FAILs, gate green.
38
38
<!-- SECTION:NOTES:END -->
39
+
40
+
## Final Summary
41
+
42
+
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
43
+
Wave 2 complete: LIKE/NOT LIKE/ILIKE with full ESCAPE semantics on both backends (pins-first; the matcher reproduces even DuckDB's data-dependent error rows while avoiding its measured O(n^k) blowup), dynamic-table alias (alias replaces the original name), comma-join honestly descoped by census (corpus cases are self-joins). Corpus 240 -> 265/678, zero FAILs; first documented oracle divergence recorded with proof of row-local irreproducibility (stats-dependent ILIKE kernels).
0 commit comments