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
Spec v0.102.0 states three rules for a RANGE window frame whose bounds are Preceding/Following. core enforces one of them (bounds_type must be set — added in #1156 as a @Value.Check on both invocation types) and none of the other two. Plans that violate them are constructible through the POJO builders and round-trip through proto unchallenged.
From algebra.proto at v0.102.0, on bounds_type (the same paragraph appears on Expression.WindowFunction and on ConsistentPartitionWindowRel.WindowRelFunction):
For RANGE with a Preceding or Following bound, sorts on the enclosing ConsistentPartitionWindowRel must contain exactly one ordering expression and must not use SORT_DIRECTION_CLUSTERED or a custom comparison function.
BOUNDS_TYPE_RANGE's own comment repeats the first half — "This bounds type requires exactly one ordering expression if Preceding or Following is used" — and the offset_expr comment adds the type rule:
Its type D must be compatible with the type T of the single ordering expression, i.e. add(T, D) -> T and subtract(T, D) -> T must be defined (e.g. timestamp/interval_day, decimal/decimal, i64/i64).
Sort direction / comparison function.SortDirection includes CLUSTERED, and nothing excludes it from a RANGE frame's sorts. The "custom comparison function" half is currently moot for a different reason: Expression.SortField models only expr() and direction(), so the proto's comparison_function_reference has no POJO representation at all — worth a separate issue if that's news.
Offset/ordering type compatibility.add(T, D) -> T is unchecked, so an i64 offset against an i32 or decimal ordering column is accepted. isthmus's producer side now derives the offset type from the ordering column (feat(core)!: support offset_expr on window bounds (spec v0.102.0) #1156), but a plan built directly, or read from proto, has no such guarantee.
Suggested shape
The two window kinds need the check in different places, which is the interesting part:
Expression.WindowFunctionInvocation carries sort(), the bounds, and boundsType() itself, so its existing @Value.Check can cover this.
ConsistentPartitionWindow keeps getSorts() on the relation while boundsType()/bounds live on each WindowRelFunctionInvocation, so the invocation-level check added in feat(core)!: support offset_expr on window bounds (spec v0.102.0) #1156 structurally cannot see the sorts. The sort-count and direction rules have to be a @Value.Check on ConsistentPartitionWindow iterating getWindowFunctions().
IllegalArgumentException, not assert — see the reasoning in #1047.
Open questions
Type compatibility is a different weight class. Checking add(T, D) -> T means resolving a function against an extension collection from inside POJO validation, which the model does not otherwise do. Options: check only the easy structural rules here and leave type compatibility to a plan-level validator, approximate it with a same-type-family rule, or skip it entirely and document the gap.
CLUSTERED reachability. Worth confirming whether any producer in the repo can currently emit a CLUSTERED sort under a RANGE frame, since that would make the check a live fix rather than a guard.
Context
Surfaced while reviewing #1156, which added the bounds_type rule from this same spec paragraph and left the rest. Two of that PR's RANGE fixtures were spec-invalid until review; they were fixed, but only by hand, since nothing fails. #1199 is the isthmus-side counterpart: its producer now derives the offset type from the ordering column, but falls back silently to a mismatched one when it cannot.
Description
Spec v0.102.0 states three rules for a RANGE window frame whose bounds are
Preceding/Following.coreenforces one of them (bounds_typemust be set — added in #1156 as a@Value.Checkon both invocation types) and none of the other two. Plans that violate them are constructible through the POJO builders and round-trip through proto unchallenged.From
algebra.protoat v0.102.0, onbounds_type(the same paragraph appears onExpression.WindowFunctionand onConsistentPartitionWindowRel.WindowRelFunction):BOUNDS_TYPE_RANGE's own comment repeats the first half — "This bounds type requires exactly one ordering expression if Preceding or Following is used" — and theoffset_exprcomment adds the type rule:What core does today
Nothing checks any of the three. Concretely:
SortDirectionincludesCLUSTERED, and nothing excludes it from a RANGE frame's sorts. The "custom comparison function" half is currently moot for a different reason:Expression.SortFieldmodels onlyexpr()anddirection(), so the proto'scomparison_function_referencehas no POJO representation at all — worth a separate issue if that's news.add(T, D) -> Tis unchecked, so an i64 offset against an i32 or decimal ordering column is accepted. isthmus's producer side now derives the offset type from the ordering column (feat(core)!: support offset_expr on window bounds (spec v0.102.0) #1156), but a plan built directly, or read from proto, has no such guarantee.Suggested shape
The two window kinds need the check in different places, which is the interesting part:
Expression.WindowFunctionInvocationcarriessort(), the bounds, andboundsType()itself, so its existing@Value.Checkcan cover this.ConsistentPartitionWindowkeepsgetSorts()on the relation whileboundsType()/bounds live on eachWindowRelFunctionInvocation, so the invocation-level check added in feat(core)!: support offset_expr on window bounds (spec v0.102.0) #1156 structurally cannot see the sorts. The sort-count and direction rules have to be a@Value.CheckonConsistentPartitionWindowiteratinggetWindowFunctions().IllegalArgumentException, notassert— see the reasoning in #1047.Open questions
add(T, D) -> Tmeans resolving a function against an extension collection from inside POJO validation, which the model does not otherwise do. Options: check only the easy structural rules here and leave type compatibility to a plan-level validator, approximate it with a same-type-family rule, or skip it entirely and document the gap.CLUSTEREDreachability. Worth confirming whether any producer in the repo can currently emit a CLUSTERED sort under a RANGE frame, since that would make the check a live fix rather than a guard.Context
Surfaced while reviewing #1156, which added the
bounds_typerule from this same spec paragraph and left the rest. Two of that PR's RANGE fixtures were spec-invalid until review; they were fixed, but only by hand, since nothing fails. #1199 is the isthmus-side counterpart: its producer now derives the offset type from the ordering column, but falls back silently to a mismatched one when it cannot.🤖 Generated with AI