Skip to content

Commit 2c0e443

Browse files
authored
fix(cubesql): Break cost symmetry for (non)-push-to-Cube WrappedSelect (#9155)
Without this two different representations can have zero members, different push-to-Cube and same cost. It could be done in a single cost component, like zero_members_wrapper, but would require to have a complex dispatch instead of add_child
1 parent aba6430 commit 2c0e443

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

rust/cubesql/cubesql/src/compile/rewrite/cost.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
compile::rewrite::{
55
rules::utils::granularity_str_to_int_order, CubeScanUngrouped, CubeScanWrapped,
66
DimensionName, LogicalPlanLanguage, MemberErrorPriority, ScalarUDFExprFun,
7-
TimeDimensionGranularity, WrappedSelectUngroupedScan,
7+
TimeDimensionGranularity, WrappedSelectPushToCube, WrappedSelectUngroupedScan,
88
},
99
transport::{MetaContext, V1CubeMetaDimensionExt},
1010
};
@@ -189,6 +189,11 @@ impl BestCubePlan {
189189
_ => 0,
190190
};
191191

192+
let wrapped_select_non_push_to_cube = match enode {
193+
LogicalPlanLanguage::WrappedSelectPushToCube(WrappedSelectPushToCube(false)) => 1,
194+
_ => 0,
195+
};
196+
192197
let wrapped_select_ungrouped_scan = match enode {
193198
LogicalPlanLanguage::WrappedSelectUngroupedScan(WrappedSelectUngroupedScan(true)) => 1,
194199
_ => 0,
@@ -218,6 +223,7 @@ impl BestCubePlan {
218223
ungrouped_aggregates: 0,
219224
wrapper_nodes,
220225
joins,
226+
wrapped_select_non_push_to_cube,
221227
wrapped_select_ungrouped_scan,
222228
empty_wrappers: 0,
223229
ast_size_outside_wrapper: 0,
@@ -243,6 +249,7 @@ impl BestCubePlan {
243249
/// - `member_errors` > `wrapper_nodes` - use SQL push down where possible if cube scan can't be detected
244250
/// - `non_pushed_down_window` > `wrapper_nodes` - prefer to always push down window functions
245251
/// - `non_pushed_down_limit_sort` > `wrapper_nodes` - prefer to always push down limit-sort expressions
252+
/// - `wrapped_select_non_push_to_cube` > `wrapped_select_ungrouped_scan` - otherwise cost would prefer any aggregation, even non-push-to-Cube
246253
/// - match errors by priority - optimize for more specific errors
247254
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
248255
pub struct CubePlanCost {
@@ -260,6 +267,7 @@ pub struct CubePlanCost {
260267
joins: usize,
261268
wrapper_nodes: i64,
262269
ast_size_outside_wrapper: usize,
270+
wrapped_select_non_push_to_cube: usize,
263271
wrapped_select_ungrouped_scan: usize,
264272
filters: i64,
265273
structure_points: i64,
@@ -386,6 +394,8 @@ impl CubePlanCost {
386394
+ other.ast_size_outside_wrapper,
387395
ungrouped_aggregates: self.ungrouped_aggregates + other.ungrouped_aggregates,
388396
wrapper_nodes: self.wrapper_nodes + other.wrapper_nodes,
397+
wrapped_select_non_push_to_cube: self.wrapped_select_non_push_to_cube
398+
+ other.wrapped_select_non_push_to_cube,
389399
wrapped_select_ungrouped_scan: self.wrapped_select_ungrouped_scan
390400
+ other.wrapped_select_ungrouped_scan,
391401
cube_scan_nodes: self.cube_scan_nodes + other.cube_scan_nodes,
@@ -472,6 +482,7 @@ impl CubePlanCost {
472482
} + self.ungrouped_aggregates,
473483
unwrapped_subqueries: self.unwrapped_subqueries,
474484
wrapper_nodes: self.wrapper_nodes,
485+
wrapped_select_non_push_to_cube: self.wrapped_select_non_push_to_cube,
475486
wrapped_select_ungrouped_scan: self.wrapped_select_ungrouped_scan,
476487
cube_scan_nodes: self.cube_scan_nodes,
477488
ast_size_without_alias: self.ast_size_without_alias,

rust/cubesql/cubesql/src/compile/test/test_wrapper.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,3 +1521,41 @@ LIMIT 1
15211521
.sql
15221522
.contains(r#""foo" "bar""#));
15231523
}
1524+
1525+
/// Simple wrapper with cast should have explicit members, not zero
1526+
#[tokio::test]
1527+
async fn wrapper_cast_limit_explicit_members() {
1528+
if !Rewriter::sql_push_down_enabled() {
1529+
return;
1530+
}
1531+
init_testing_logger();
1532+
1533+
let query_plan = convert_select_to_query_plan(
1534+
// language=PostgreSQL
1535+
r#"
1536+
SELECT
1537+
CAST(dim_date0 AS DATE) AS "dim_date0"
1538+
FROM
1539+
MultiTypeCube
1540+
LIMIT 10
1541+
;
1542+
"#
1543+
.to_string(),
1544+
DatabaseProtocol::PostgreSQL,
1545+
)
1546+
.await;
1547+
1548+
let physical_plan = query_plan.as_physical_plan().await.unwrap();
1549+
println!(
1550+
"Physical plan: {}",
1551+
displayable(physical_plan.as_ref()).indent()
1552+
);
1553+
1554+
// Query should mention just a single member
1555+
let request = query_plan
1556+
.as_logical_plan()
1557+
.find_cube_scan_wrapped_sql()
1558+
.request;
1559+
assert_eq!(request.measures.unwrap().len(), 1);
1560+
assert_eq!(request.dimensions.unwrap().len(), 0);
1561+
}

0 commit comments

Comments
 (0)