Repository navigation
fix(engine): CONSTRUCT and DESCRIBE go through PreparedQuery and honour BASE - #6677
Conversation
The graph-valued entry point used by the CLI, server, wheel and MCP parsed the query directly, so CONSTRUCT / DESCRIBE never saw the algebra-rewrite pass while EXPLAIN did. Parse through PreparedQuery and delegate to the prepared CONSTRUCT / DESCRIBE paths. The pass rewrites only the WHERE pattern and is bag-equivalent on its solutions, so output is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
The CONSTRUCT / DESCRIBE entry points never set the query's BASE IRI,
so IRI("rel") in their WHERE clause errored (an unbound template slot)
instead of resolving against the BASE. Install it with the same scoped
guard as the SELECT / ASK entry points.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
🔎 Codex reviewer —
|
… path endpoint ?s ex:p* ?o FILTER(?s = ex:missing) has no matches on a graph without ex:missing, but the substituted ex:missing ex:p* ?o matches the zero-length pair. Equality substitution now declines when the variable is an endpoint of a path that can match zero steps. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
🔎 Codex reviewer —
|
…mpty IRI()/URI() on rayon workers saw an empty QUERY_BASE, so above the parallel threshold relative IRIs went unbound. Every parallel evaluation site now snapshots the base and re-installs it per item, like NOW(). OneOrMore(q) can match zero steps when q can, so equality substitution declines it too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
🔎 Codex reviewer —
|
🔎 Codex reviewer —
|
…arallel feature Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
🔎 Codex reviewer —
|
|
This failure is not from this PR. The check fails the same way on main at 126a92e, and this PR does not touch workflows. The fix is #6688, which adds the Generated by Claude Code |
Before:
construct_or_describe(the graph-valued entry point the CLI, server, Python wheel and MCP use) parsed the query directly. CONSTRUCT and DESCRIBE never went through the algebra-rewrite pass that EXPLAIN shows (#4748). They also never installed the query's BASE, soIRI("rel")in a CONSTRUCT WHERE clause errored and left the template slot unbound.After:
construct_or_describeparses throughPreparedQuery::parseand delegates to the prepared CONSTRUCT/DESCRIBE paths, so it sees the same rewrites as EXPLAIN. Those prepared paths install the query BASE with the same scoped guard as SELECT and ASK, so relative IRIs resolve.The rewrite pass only touches the WHERE pattern and keeps the same solutions, so CONSTRUCT and DESCRIBE output is unchanged.
How: one function in
construct.rsnow delegates instead of duplicating the evaluation.set_query_baseis called in the prepared CONSTRUCT/DESCRIBE functions. New tests:rewrite_seam_testsin construct.rs and a CONSTRUCT BASE case intests/query_base_scope.rs.Closes #4748.
Benchmark
Local
sparq-cli bench, operators suite (2,000 entities, 16k triples), release-fast binaries of maina6ce3785b4and this PR. Best of 5 iterations per round, minimum over 5 interleaved rounds; row counts match on every query. Geomean ratio 0.998. The one query over 1.05 (q13_bind 1.053) was 0.995 on a second run, which instead showed q01_bgp at 1.156 (0.98-1.02 in the first run); neither repeats, so both are noise. q27_construct and q28_describe, the paths this PR touches, are 1.007 and 0.984.🤖 Generated with Claude Code
https://claude.ai/code/session_01C1gMf8RJim1LzuKapZNpZR
Generated by Claude Code
Generated by Claude Code