-
Notifications
You must be signed in to change notification settings - Fork 0
A dimensionless parameter joins ON TRUE with no single-row guard #166
Copy link
Copy link
Closed
Labels
area:engineLowering, IR, relational executor, sinksLowering, IR, relational executor, sinksbug:silentPlausible wrong answer or unearned green light; the user gets no signalPlausible wrong answer or unearned green light; the user gets no signalengine:duckdbSpecific to the duckdb executor — invalidated if the polars path winsSpecific to the duckdb executor — invalidated if the polars path winsperfWall time, memory, or I/O cost — not a wrong answerWall time, memory, or I/O cost — not a wrong answer
Description
Metadata
Metadata
Assignees
Labels
area:engineLowering, IR, relational executor, sinksLowering, IR, relational executor, sinksbug:silentPlausible wrong answer or unearned green light; the user gets no signalPlausible wrong answer or unearned green light; the user gets no signalengine:duckdbSpecific to the duckdb executor — invalidated if the polars path winsSpecific to the duckdb executor — invalidated if the polars path winsperfWall time, memory, or I/O cost — not a wrong answerWall time, memory, or I/O cost — not a wrong answer
Not primarily a performance issue — filed alongside the SQL performance batch because it was found reading the same statement, and because the failure mode is a silent row multiplication that also blows up the runtime.
The statement
compiler.py::parameter_join:For a parameter with no dims,
onisTRUEand the statement isLEFT JOIN p_x b ON TRUE— a cross join against the whole parameter table.That is correct broadcast semantics if
p_xhas exactly one row. Nothing checks that it does._create_param_tableaccepts whatever the source relation contains:A two-row scalar source therefore doubles every row of the frame it is joined into. In a bound (
compiler.py::bound, aliasb_*) that means duplicatecolsentries for the samevar_label, which the solver ingests as repeated columns. In a where-mask (aliasw_*) it duplicates mask rows. Both build and solve without a word.Why it is worth stopping at load time
The engine's whole error posture is load-time and specific — coordinate containment is checked precisely because a mistyped label would otherwise vanish silently (
_check_coordinate_containment, #135). A scalar parameter with two rows is the same class of bug, on a path with no check at all.The fix
In
_create_param_table, whenp.dimsis empty:and raise
DataErrorunless it is exactly 1, naming the parameter and the count. The message should say what a dimensionless parameter means — one row, one value, broadcast everywhere — since a user who got here probably passed a column they thought was indexed.Cost is one metadata-level
count(*)per scalar parameter, so this is free in practice.