Skip to content

Commit cab0a18

Browse files
authored
fix(tesseract): wrap composed expressions before timestamptz cast in convert_tz (#10859)
1 parent 7ffc6d2 commit cab0a18

4 files changed

Lines changed: 71 additions & 1 deletion

File tree

rust/cube/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::cube_bridge::driver_tools::DriverTools;
33
use crate::cube_bridge::sql_templates_render::SqlTemplatesRender;
44
use crate::physical_plan::join::JoinType;
55
use crate::planner::sql_templates::structs::TemplateCalcGroup;
6+
use crate::utils::sql_expression_scanner::is_top_level_compound;
67
use convert_case::{Boundary, Case, Casing};
78
use cubenativeutils::CubeError;
89
use minijinja::context;
@@ -53,7 +54,12 @@ impl PlanSqlTemplates {
5354
}
5455

5556
pub fn convert_tz(&self, field: String) -> Result<String, CubeError> {
56-
self.driver_tools.convert_tz(field)
57+
let safe = if is_top_level_compound(&field) {
58+
format!("({field})")
59+
} else {
60+
field
61+
};
62+
self.driver_tools.convert_tz(safe)
5763
}
5864

5965
pub fn is_external(&self) -> bool {

rust/cube/cubesqlplanner/cubesqlplanner/src/test_fixtures/schemas/yaml_files/common/integration_custom_granularity.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ cubes:
2525
- name: fiscal_year
2626
interval: "1 year"
2727
offset: "1 month"
28+
29+
- name: fiscal_year_alias
30+
type: time
31+
sql: "{created_at.fiscal_year}"
32+
33+
- name: created_at_minus_one_day
34+
type: time
35+
sql: "{CUBE}.created_at - interval '1 day'"
2836
measures:
2937
- name: count
3038
type: count

rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/custom_granularities.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,40 @@ async fn test_half_year_with_sum_measure() {
133133
}
134134
}
135135

136+
#[tokio::test(flavor = "multi_thread")]
137+
async fn test_type_time_alias_wraps_compound_exprs_before_tz_cast() {
138+
let ctx = create_context();
139+
140+
let query = indoc! {"
141+
measures:
142+
- orders.count
143+
dimensions:
144+
- orders.fiscal_year_alias
145+
- orders.created_at_minus_one_day
146+
order:
147+
- id: orders.fiscal_year_alias
148+
convert_tz_for_raw_time_dimension: true
149+
"};
150+
151+
let sql = ctx.build_sql(query).unwrap();
152+
153+
// Two independent precedence-trap fingerprints — `::` latching onto a
154+
// trailing interval literal instead of the wrapped composed expression.
155+
for bad in [
156+
"interval '1 month'::timestamptz",
157+
"interval '1 day'::timestamptz",
158+
] {
159+
assert!(
160+
!sql.contains(bad),
161+
"cast-precedence trap detected: {bad}\nFull SQL:\n{sql}"
162+
);
163+
}
164+
165+
if let Some(result) = ctx.try_execute_pg(query, SEED).await {
166+
insta::assert_snapshot!(result);
167+
}
168+
}
169+
136170
#[tokio::test(flavor = "multi_thread")]
137171
async fn test_custom_granularity_with_daterange_filter() {
138172
let ctx = create_context();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
source: cubesqlplanner/cubesqlplanner/src/tests/integration/custom_granularities.rs
3+
assertion_line: 166
4+
expression: result
5+
---
6+
orders__fiscal_year_alias | orders__created_at_minus_one_day | orders__count
7+
--------------------------+----------------------------------+--------------
8+
2023-02-01 00:00:00 | 2024-01-14 10:00:00 | 1
9+
2024-02-01 00:00:00 | 2024-04-30 14:00:00 | 1
10+
2024-02-01 00:00:00 | 2024-06-14 08:00:00 | 1
11+
2024-02-01 00:00:00 | 2024-03-19 09:00:00 | 1
12+
2024-02-01 00:00:00 | 2025-01-19 10:00:00 | 1
13+
2024-02-01 00:00:00 | 2024-09-19 11:00:00 | 1
14+
2024-02-01 00:00:00 | 2024-11-14 14:00:00 | 1
15+
2024-02-01 00:00:00 | 2024-10-04 09:00:00 | 1
16+
2024-02-01 00:00:00 | 2024-08-09 10:00:00 | 1
17+
2024-02-01 00:00:00 | 2024-11-30 08:00:00 | 1
18+
2024-02-01 00:00:00 | 2024-02-09 11:00:00 | 1
19+
2025-02-01 00:00:00 | 2025-11-19 08:00:00 | 1
20+
2025-02-01 00:00:00 | 2025-07-14 09:00:00 | 1
21+
2025-02-01 00:00:00 | 2025-04-09 11:00:00 | 1
22+
2025-02-01 00:00:00 | 2025-08-31 14:00:00 | 1

0 commit comments

Comments
 (0)