Repository navigation
fix(ddxdb): plan on DuckDB without the planner's empty-table statistics - #206
Merged
Merged
Conversation
DuckDB's backend plans on a second connection whose tables are empty copies of the caller's. DuckDB's statistics propagation proves a filter on such a table's column (`WHERE p.layer = 0`) matches no rows, and plans the scan as an empty result. ddx then differentiates a plan that never reads the table. A gradient through the join comes out 0, with no error, and a gradient with respect to the table is refused as unknown. The planner turns statistics propagation off. Its plans then read every table the query reads, under the query's filters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvszJhH8pn8H9G69wEPMU2
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Planner configuration and regression test python/ddxdb/ddxdb/duckdb.py, python/ddxdb/tests/test_duckdb.py |
DuckDBBackend disables statistics_propagation on the planner connection. The test checks gradients for joined w.val and registered p.w rows, including rows excluded by the filter or join. |
Priority:
Estimated code review effort: 2 (Simple) | ~8 minutes
Change: Bug fix
Possibly related issues
- Exit: xarray-sql's ML demos differentiate on DuckDB #150 — This planner fix addresses filtered-join gradient behavior relevant to differentiating on DuckDB.
- Tracking: ML in SQL as fast as JAX on CPU xarray-sql#285 — This planner fix addresses a DuckDB planning condition that can prevent gradient computation.
Possibly related PRs
- xqlsystems/ddx#192 — Adds the DuckDB backend that plans with an empty catalog mirror; this PR changes that planner’s optimizer configuration and tests the reported failure mode.
- xqlsystems/ddx#201 — Releases the DuckDB backend implementation that this PR modifies.
Merge Risk: 
Minimal · up to 0074b
-
No actionable issue was identified that should delay merging after normal checks.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed -
Finishing Touches: 💡 1
-
📝 Generate docstrings: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
This was referenced Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A silent wrong gradient on DuckDB, in ddxdb 0.4.2. Take a loss that filters a table on a column:
w.valcomes out0everywhere, with no error. The right answer isp.w.p.wis refused: ddx says the query does not readp.The GPT's step filters every parameter table this way (
WHERE p.layer = {layer}).DuckDB's backend plans on a second connection whose tables are empty copies of the caller's. DuckDB's statistics propagation proves that the filter matches no rows of an empty table, and plans the scan as an empty result. So ddx differentiates a plan that never reads
p.How
The planner sets
disabled_optimizers = 'statistics_propagation'. Nothing runs on the planner, so its plans gain nothing from statistics. They now read every table the query reads, under the query's filters. The caller's connection, where the steps run, is unchanged.Tests
test_a_filter_on_a_table_s_column_keeps_the_table_s_rowstakes both gradients of the loss above. Without the fix, it gets[0, 0, 0]forw.val.Next
#204's fix (the GPT on DuckDB) needs this too. Worth a patch release.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CvszJhH8pn8H9G69wEPMU2
Summary by CodeRabbit