Skip to content

Commit 4fd0e21

Browse files
committed
[WIP] feat(cubesql): Add extraction with forced SQL pushdown
1 parent 29970e1 commit 4fd0e21

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ impl BestCubePlan {
206206

207207
CubePlanCost {
208208
replacers: this_replacers,
209+
// Will be filled in finalize
210+
penalized_ast_size_outside_wrapper: 0,
209211
table_scans,
210212
filters,
211213
filter_members,
@@ -239,6 +241,7 @@ impl BestCubePlan {
239241

240242
/// This cost struct maintains following structural relationships:
241243
/// - `replacers` > other nodes - having replacers in structure means not finished processing
244+
/// - `penalized_ast_size_outside_wrapper` > other nodes - this is used to force "no post processing" mode, only CubeScan and CubeScanWrapped are expected as result
242245
/// - `table_scans` > other nodes - having table scan means not detected cube scan
243246
/// - `empty_wrappers` > `non_detected_cube_scans` - we don't want empty wrapper to hide non detected cube scan errors
244247
/// - `non_detected_cube_scans` > other nodes - minimize cube scans without members
@@ -254,6 +257,7 @@ impl BestCubePlan {
254257
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
255258
pub struct CubePlanCost {
256259
replacers: i64,
260+
penalized_ast_size_outside_wrapper: usize,
257261
table_scans: i64,
258262
empty_wrappers: i64,
259263
non_detected_cube_scans: i64,
@@ -366,6 +370,8 @@ impl CubePlanCost {
366370
pub fn add_child(&self, other: &Self) -> Self {
367371
Self {
368372
replacers: self.replacers + other.replacers,
373+
// Will be filled in finalize
374+
penalized_ast_size_outside_wrapper: 0,
369375
table_scans: self.table_scans + other.table_scans,
370376
filters: self.filters + other.filters,
371377
non_detected_cube_scans: (if other.cube_members == 0 {
@@ -419,8 +425,23 @@ impl CubePlanCost {
419425
enode: &LogicalPlanLanguage,
420426
top_down: bool,
421427
) -> Self {
428+
let ast_size_outside_wrapper = match state {
429+
CubePlanState::Wrapped => 0,
430+
CubePlanState::Unwrapped(size) => *size,
431+
CubePlanState::Wrapper => 0,
432+
} + self.ast_size_outside_wrapper;
433+
let penalize_post_processing = std::env::var_os("CUBESQL_DISABLE_POST_PROCESSING")
434+
.map(|v| v.eq_ignore_ascii_case("true"))
435+
.unwrap_or(false);
436+
let penalized_ast_size_outside_wrapper = if penalize_post_processing {
437+
ast_size_outside_wrapper
438+
} else {
439+
0
440+
};
441+
422442
Self {
423443
replacers: self.replacers,
444+
penalized_ast_size_outside_wrapper,
424445
table_scans: self.table_scans,
425446
filters: self.filters,
426447
non_detected_cube_scans: match state {
@@ -447,11 +468,7 @@ impl CubePlanCost {
447468
errors: self.errors,
448469
structure_points: self.structure_points,
449470
joins: self.joins,
450-
ast_size_outside_wrapper: match state {
451-
CubePlanState::Wrapped => 0,
452-
CubePlanState::Unwrapped(size) => *size,
453-
CubePlanState::Wrapper => 0,
454-
} + self.ast_size_outside_wrapper,
471+
ast_size_outside_wrapper,
455472
empty_wrappers: match state {
456473
CubePlanState::Wrapped => 0,
457474
CubePlanState::Unwrapped(_) => 0,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ impl Rewriter {
349349
let (runner, qtrace_egraph_iterations) =
350350
Self::run_rewrites(&cube_context, egraph, rules, "final")?;
351351

352+
// TODO maybe check replacers and penalized_ast_size_outside_wrapper right after extraction?
352353
let best = if top_down_extractor {
353354
let mut extractor = TopDownExtractor::new(
354355
&runner.egraph,
@@ -376,6 +377,7 @@ impl Rewriter {
376377
};
377378
let new_root = Id::from(best.as_ref().len() - 1);
378379
log::debug!("Best: {}", best.pretty(120));
380+
// TODO maybe pass CUBESQL_DISABLE_POST_PROCESSING here as well, to break with sane error
379381
let converter = LanguageToLogicalPlanConverter::new(
380382
best,
381383
cube_context.clone(),

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,3 +1598,34 @@ async fn wrapper_typed_null() {
15981598
.sql
15991599
.contains("SUM(CAST(NULL AS DOUBLE))"));
16001600
}
1601+
1602+
#[tokio::test]
1603+
async fn test_force_sql_pushdown() {
1604+
if !Rewriter::sql_push_down_enabled() {
1605+
return;
1606+
}
1607+
init_testing_logger();
1608+
1609+
let query_plan = convert_select_to_query_plan(
1610+
// language=PostgreSQL
1611+
r#"
1612+
SELECT
1613+
CAST("KibanaSampleDataEcommerce"."customer_gender" AS TEXT) AS "CUSTOMER_GENDER",
1614+
SUM("KibanaSampleDataEcommerce"."sumPrice") AS "sum:SUM_PRICE:ok"
1615+
FROM
1616+
"public"."KibanaSampleDataEcommerce" "KibanaSampleDataEcommerce"
1617+
GROUP BY 1
1618+
;"#
1619+
.to_string(),
1620+
DatabaseProtocol::PostgreSQL,
1621+
)
1622+
.await;
1623+
1624+
let physical_plan = query_plan.as_physical_plan().await.unwrap();
1625+
println!(
1626+
"Physical plan: {}",
1627+
displayable(physical_plan.as_ref()).indent()
1628+
);
1629+
1630+
todo!()
1631+
}

0 commit comments

Comments
 (0)