Repository navigation
v0.12.1
v0.12.1 (2026-08-11)
Fix
- fix: escaped identifiers, unaliased projections, procedural BFS guardrails
Three parser-phase defects and a set of procedural-BFS correctness
guardrails, all found while diagnosing a "Failed to bind entity" error
on a real MATCH ... MATCH (root)-[*1..2]-(d) RETURN count(DISTINCT d)
query.
Parser (visitor.py):
- Backtick-escaped identifiers (
Label,prop,variable) leaked
their delimiters into entity_name/alias, so a correctly-registered
node type likecnpj_raizfailed to bind because the lookup used
the literal string with backticks still attached. Added
unescape_symbolic_name()/split_escaped_labels() and applied them at
every identifier extraction site: node labels, relationship types
(OR-joined), variables, property lookups, map literal keys, UNWIND/
path/REDUCE/list-comprehension variables. Table names (which come
from schema config, not the Cypher text) are untouched. - Unaliased projections (RETURN count(*), RETURN n.age + 1, ...) via
the live visit_oC_ProjectionItem path emitted an empty AS alias,
producing a SQL syntax error only at execution time. Added
sanitize_expression_alias() to derive a column name from the raw
Cypher expression text, matching the fallback the legacy (dead)
visit_oC_ReturnItem path already had.
Planner (data_source.py):
- Binding failure on an unknown node type now lists the registered
types and flags a case-insensitive near-match, instead of a bare
"Failed to bind entity" with no actionable next step.
Renderer (procedural_bfs_renderer.py, sql_renderer.py):
- Procedural BFS's single-source architecture (one global visited set
- CROSS JOIN frontier attribution) silently produced wrong results
for constructs CTE mode handles correctly: unfiltered/chained VLP
sources fabricated (start, end) pairs or returned empty, *0..N
omitted the start node, and length(p)/nodes(p) evaluated to NULL.
Added transpile-time NotSupportedException for all three (pointing
callers at vlp_rendering_mode="cte"), plus a runtime seed-cardinality
guard (RAISE_ERROR) since a start filter can still match >1 node.
relationships(p) and ALL(n IN nodes(p) WHERE ...) pushdown remain
supported in procedural mode.
- CROSS JOIN frontier attribution) silently produced wrong results
Verified: pyright/mypy 0 errors; 1738 passed (was 1694) + 7 skipped +
1 xfailed on the non-PySpark suite; 220 passed + 5 xfailed on PySpark.
Dual-mode (CTE vs procedural) A/B executed on real PySpark data across
~30 query variations with hand-computed expected results — no
divergence or wrong result survives after these fixes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (3b948d9)