fix(tesseract): parenthesize compound exprs before ::timestamptz cast#10859
Conversation
…convert_tz
`PlanSqlTemplates::convert_tz` passed `field` straight into the driver
template (`{}::timestamptz AT TIME ZONE 'UTC'`). For composed inputs
like a granularity-expanded `date_trunc(...) + interval '1 month'`,
`::` bound to the trailing interval literal instead of the full
expression — Postgres reported `cannot cast type interval to timestamp
with time zone`.
Wrap `field` in parentheses when `is_top_level_compound` reports a
top-level operator; atomic and already-parenthesized forms pass through
unchanged. Filter pipeline picks the fix up via `convert_tz` delegation.
Repro covered by `test_type_time_alias_wraps_compound_exprs_before_tz_cast`
(both `+` and `-` compound shapes, with PG execution snapshot).
|
Claude finished @waralexrom's task in 2m 3s —— View job PR #10859 — Code Review
Overall AssessmentThis is a clean, well-scoped fix. The bug is real — Postgres's Code QualityThe fix itself ( let safe = if is_top_level_compound(&field) {
format!("({field})")
} else {
field
};
self.driver_tools.convert_tz(safe)Wrapping only when needed avoids unnecessary parentheses in the common case (plain column references). The Minor observation: The parenthesization is correct even for the edge case where Fix PlacementThe fix in
All three paths are covered by the single fix point. SecurityNo concerns. The fix adds parentheses around an already-constructed SQL expression — it doesn't introduce any new string interpolation or user-input handling. The PerformanceNegligible. TestingThe test is well-designed:
One suggestion (non-blocking): The scanner's own unit tests don't include an interval-arithmetic expression like SummaryClean, minimal fix at the right abstraction layer. Reuses existing infrastructure without introducing new complexity. Test coverage is solid with both assertion-based regression checks and real Postgres execution. Looks good to merge. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #10859 +/- ##
===========================================
+ Coverage 58.36% 78.86% +20.49%
===========================================
Files 216 470 +254
Lines 16939 92289 +75350
Branches 3435 3435
===========================================
+ Hits 9887 72783 +62896
- Misses 6550 19004 +12454
Partials 502 502
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
Fix a
::precedence trap inPlanSqlTemplates::convert_tz: whenfieldis a composed expression (e.g. a granularity-expandeddate_trunc(...) + interval '1 month', or a user dimension like{CUBE}.created_at - interval '1 day'), the driver template${field}::timestamptz AT TIME ZONE 'UTC'binds::to the trailing operand instead of the full expression. Postgres then errors out withcannot cast type interval to timestamp with time zone.Changes
PlanSqlTemplates::convert_tznow wrapsfieldin(...)whenis_top_level_compound(&field)reports a top-level operator/operator-keyword. Atomic and already-parenthesized forms pass through unchanged.FilterSqlContext::convert_tzdelegation.sql_expression_scanner::is_top_level_compoundclassifier — no new tokenizer work.Testing
test_type_time_alias_wraps_compound_exprs_before_tz_cast(covers both+and-compound shapes via two dimensions: afiscal_year_aliastime-typed alias over a custom granularity, and acreated_at - interval '1 day'expression).interval 'X'::timestamptz) are absent from the rendered SQL.try_execute_pgand snapshots the result.