diff --git a/rust/cubesql/cubesql/src/compile/engine/df/scan.rs b/rust/cubesql/cubesql/src/compile/engine/df/scan.rs index 63c7bc3e7a9d5..9f8c4aabe4e59 100644 --- a/rust/cubesql/cubesql/src/compile/engine/df/scan.rs +++ b/rust/cubesql/cubesql/src/compile/engine/df/scan.rs @@ -162,7 +162,15 @@ pub struct WrappedSelectNode { pub order_expr: Vec, pub alias: Option, pub distinct: bool, - pub ungrouped: bool, + + /// States if this node actually a query to Cube or not. + /// When `false` this node will generate SQL on its own, using its fields and templates. + /// When `true` this node will generate SQL with load query to JS side of Cube. + /// It expects to be flattened: `from` is expected to be ungrouped CubeScan. + /// There's no point in doing this for grouped CubeScan, we can just use load query from that CubeScan and SQL API generation on top. + /// Load query generated for this case can be grouped when this node is an aggregation. + /// Most fields will be rendered as a member expressions in generated load query. + pub push_to_cube: bool, } impl WrappedSelectNode { @@ -183,7 +191,7 @@ impl WrappedSelectNode { order_expr: Vec, alias: Option, distinct: bool, - ungrouped: bool, + push_to_cube: bool, ) -> Self { Self { schema, @@ -202,7 +210,7 @@ impl WrappedSelectNode { order_expr, alias, distinct, - ungrouped, + push_to_cube, } } } @@ -344,7 +352,7 @@ impl UserDefinedLogicalNode for WrappedSelectNode { order_expr, alias, self.distinct, - self.ungrouped, + self.push_to_cube, )) } } diff --git a/rust/cubesql/cubesql/src/compile/engine/df/wrapper.rs b/rust/cubesql/cubesql/src/compile/engine/df/wrapper.rs index e1e6bfb632e6a..109728f0df430 100644 --- a/rust/cubesql/cubesql/src/compile/engine/df/wrapper.rs +++ b/rust/cubesql/cubesql/src/compile/engine/df/wrapper.rs @@ -518,11 +518,11 @@ impl CubeScanWrapperNode { order_expr, alias, distinct, - ungrouped, + push_to_cube, }) = wrapped_select_node { // TODO support joins - let ungrouped_scan_node = if ungrouped { + let ungrouped_scan_node = if push_to_cube { if let LogicalPlan::Extension(Extension { node }) = from.as_ref() { if let Some(cube_scan_node) = node.as_any().downcast_ref::() diff --git a/rust/cubesql/cubesql/src/compile/mod.rs b/rust/cubesql/cubesql/src/compile/mod.rs index 7b2ac97e5b4f0..e0b4974a99166 100644 --- a/rust/cubesql/cubesql/src/compile/mod.rs +++ b/rust/cubesql/cubesql/src/compile/mod.rs @@ -7242,49 +7242,88 @@ ORDER BY displayable(physical_plan.as_ref()).indent() ); + fn trivial_member_expr(cube: &str, member: &str, alias: &str) -> String { + json!({ + "cube_name": cube, + "alias": alias, + "cube_params": [cube], + "expr": format!("${{{cube}.{member}}}"), + "grouping_set": null, + }) + .to_string() + } + assert_eq!( - query_plan.as_logical_plan().find_cube_scan().request, + query_plan + .as_logical_plan() + .find_cube_scan_wrapper() + .request + .unwrap(), V1LoadRequestQuery { measures: Some(vec![ - "WideCube.measure1".to_string(), - "WideCube.measure2".to_string(), - "WideCube.measure3".to_string(), - "WideCube.measure4".to_string(), + json!({ + "cube_name": "WideCube", + "alias": "max_source_measu", + "cube_params": ["WideCube"], + "expr": "${WideCube.measure1}", + "grouping_set": null, + }) + .to_string(), + json!({ + "cube_name": "WideCube", + "alias": "max_source_measu_1", + "cube_params": ["WideCube"], + "expr": "${WideCube.measure2}", + "grouping_set": null, + }) + .to_string(), + json!({ + "cube_name": "WideCube", + "alias": "sum_source_measu", + "cube_params": ["WideCube"], + "expr": "${WideCube.measure3}", + "grouping_set": null, + }) + .to_string(), + json!({ + "cube_name": "WideCube", + "alias": "max_source_measu_2", + "cube_params": ["WideCube"], + "expr": "${WideCube.measure4}", + "grouping_set": null, + }) + .to_string(), ]), dimensions: Some(vec![ - "WideCube.dim1".to_string(), - "WideCube.dim2".to_string(), - "WideCube.dim3".to_string(), - "WideCube.dim4".to_string(), + trivial_member_expr("WideCube", "dim2", "dim2"), + trivial_member_expr("WideCube", "dim3", "dim3"), + trivial_member_expr("WideCube", "dim4", "dim4"), + json!({ + "cube_name": "WideCube", + "alias": "pivot_grouping", + "cube_params": ["WideCube"], + "expr": "0", + "grouping_set": null, + }) + .to_string() ]), segments: Some(vec![]), - order: Some(vec![]), + order: Some(vec![ + vec!["dim2".to_string(), "asc".to_string(),], + vec!["dim3".to_string(), "asc".to_string(),], + vec!["dim4".to_string(), "asc".to_string(),], + vec!["pivot_grouping".to_string(), "asc".to_string(),], + ]), filters: Some(vec![V1LoadRequestQueryFilterItem { member: Some("WideCube.dim1".to_string()), operator: Some("equals".to_string()), values: Some(vec!["foo".to_string()]), or: None, and: None, - }]), - ungrouped: Some(true), + },]), ..Default::default() } ); - assert!(!query_plan - .as_logical_plan() - .find_cube_scan_wrapper() - .wrapped_sql - .unwrap() - .sql - .contains("ungrouped")); - - assert!(query_plan - .as_logical_plan() - .find_cube_scan_wrapper() - .wrapped_sql - .unwrap() - .sql - .contains("[\"dim2\",\"asc\"]")); } #[tokio::test] @@ -11609,15 +11648,39 @@ ORDER BY "source"."str0" ASC .await .as_logical_plan(); - let sql = logical_plan - .find_cube_scan_wrapper() - .wrapped_sql - .unwrap() - .sql; - - assert!(sql.contains("LOWER(")); - assert!(sql.contains("GROUP BY ")); - assert!(sql.contains("ORDER BY ")); + assert_eq!( + logical_plan + .find_cube_scan_wrapper() + .request + .unwrap(), + V1LoadRequestQuery { + measures: Some(vec![]), + dimensions: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "ta_1_order_date_", + "cube_params": ["KibanaSampleDataEcommerce", "Logs"], + "expr": "((${KibanaSampleDataEcommerce.order_date} = DATE('1994-05-01')) OR (${KibanaSampleDataEcommerce.order_date} = DATE('1996-05-03')))", + "grouping_set": null, + }).to_string(), + ]), + segments: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "lower_ta_2_conte", + "cube_params": ["KibanaSampleDataEcommerce", "Logs"], + "expr": "(LOWER(${Logs.content}) = $0$)", + "grouping_set": null, + }).to_string(), + ]), + time_dimensions: None, + order: Some(vec![]), + limit: None, + offset: None, + filters: None, + ungrouped: None, + } + ); } #[tokio::test] @@ -11871,20 +11934,46 @@ ORDER BY "source"."str0" ASC ); assert_eq!( - query_plan.as_logical_plan().find_cube_scan().request, + query_plan + .as_logical_plan() + .find_cube_scan_wrapper() + .request + .unwrap(), V1LoadRequestQuery { measures: Some(vec![]), - dimensions: Some(vec![]), - segments: Some(vec![]), + dimensions: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "customer_gender", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "${KibanaSampleDataEcommerce.customer_gender}", + "grouping_set": null, + }).to_string(), + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "cast_dateadd_utf", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "CAST(DATE_ADD(${KibanaSampleDataEcommerce.order_date}, INTERVAL '2 DAY') AS DATE)", + "grouping_set": null, + }).to_string(), + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "dateadd_utf8__se", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "DATE_ADD(${KibanaSampleDataEcommerce.order_date}, INTERVAL '2000000 MILLISECOND')", + "grouping_set": null, + }).to_string(), + ]), + segments: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "dateadd_utf8__da", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "(DATE_ADD(${KibanaSampleDataEcommerce.order_date}, INTERVAL '2 DAY') < DATE('2014-06-02'))", + "grouping_set": null, + }).to_string(), + ]), order: Some(vec![]), - filters: Some(vec![V1LoadRequestQueryFilterItem { - member: Some("KibanaSampleDataEcommerce.order_date".to_string(),), - operator: Some("beforeDate".to_string(),), - values: Some(vec!["2014-05-31T00:00:00.000Z".to_string()]), - or: None, - and: None, - }]), - ungrouped: Some(true), ..Default::default() } ) @@ -12669,53 +12758,39 @@ ORDER BY "source"."str0" ASC .await .as_logical_plan(); - let end_date = chrono::Utc::now().date_naive() - chrono::Duration::days(1); - let start_date = end_date - chrono::Duration::days(29); + let end_date = chrono::Utc::now().date_naive(); + let start_date = end_date - chrono::Duration::days(30); assert_eq!( - logical_plan.find_cube_scan().request, + logical_plan.find_cube_scan_wrapper().request.unwrap(), V1LoadRequestQuery { - measures: Some(vec![]), - dimensions: Some(vec![]), - segments: Some(vec![]), - time_dimensions: Some(vec![V1LoadRequestQueryTimeDimension { - dimension: "KibanaSampleDataEcommerce.order_date".to_string(), - granularity: None, - date_range: Some(json!(vec![ - format!("{}T00:00:00.000Z", start_date), - format!("{}T23:59:59.999Z", end_date), - ])) - }]), + measures: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "avg_kibanasample", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "${KibanaSampleDataEcommerce.avgPrice}", + "grouping_set": null, + }).to_string(), + ]), + dimensions: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "cast_kibanasampl", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "CAST(${KibanaSampleDataEcommerce.order_date} AS DATE)", + "grouping_set": null, + }).to_string(), + ]), + segments: Some(vec![ + json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "kibanasampledata", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": format!("(((${{KibanaSampleDataEcommerce.order_date}} >= DATE('{start_date}')) AND (${{KibanaSampleDataEcommerce.order_date}} < DATE('{end_date}'))) AND (((${{KibanaSampleDataEcommerce.notes}} = $0$) OR (${{KibanaSampleDataEcommerce.notes}} = $1$)) OR (${{KibanaSampleDataEcommerce.notes}} = $2$)))"), + "grouping_set": null, + }).to_string(), + ]), order: Some(vec![]), - filters: Some(vec![V1LoadRequestQueryFilterItem { - member: None, - operator: None, - values: None, - or: Some(vec![ - json!(V1LoadRequestQueryFilterItem { - member: Some("KibanaSampleDataEcommerce.notes".to_string()), - operator: Some("equals".to_string()), - values: Some(vec!["note1".to_string()]), - or: None, - and: None, - }), - json!(V1LoadRequestQueryFilterItem { - member: Some("KibanaSampleDataEcommerce.notes".to_string()), - operator: Some("equals".to_string()), - values: Some(vec!["note2".to_string()]), - or: None, - and: None, - }), - json!(V1LoadRequestQueryFilterItem { - member: Some("KibanaSampleDataEcommerce.notes".to_string()), - operator: Some("equals".to_string()), - values: Some(vec!["note3".to_string()]), - or: None, - and: None, - }), - ]), - and: None - }]), - ungrouped: Some(true), ..Default::default() } ) @@ -13732,7 +13807,7 @@ ORDER BY "source"."str0" ASC if Rewriter::top_down_extractor_enabled() { assert!(sql.contains("LIMIT 1000")); } else { - assert!(sql.contains("\"limit\":1000")); + assert!(sql.contains("\"limit\": 1000")); } assert!(sql.contains("% 7")); diff --git a/rust/cubesql/cubesql/src/compile/rewrite/converter.rs b/rust/cubesql/cubesql/src/compile/rewrite/converter.rs index e97dc4e7dbea4..d1944d123c908 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/converter.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/converter.rs @@ -28,8 +28,8 @@ use crate::{ TimeDimensionGranularity, TimeDimensionName, TryCastExprDataType, UnionAlias, WindowFunctionExprFun, WindowFunctionExprWindowFrame, WrappedSelectAlias, WrappedSelectDistinct, WrappedSelectJoinJoinType, WrappedSelectLimit, - WrappedSelectOffset, WrappedSelectSelectType, WrappedSelectType, - WrappedSelectUngrouped, + WrappedSelectOffset, WrappedSelectPushToCube, WrappedSelectSelectType, + WrappedSelectType, }, CubeContext, }, @@ -2146,7 +2146,8 @@ impl LanguageToLogicalPlanConverter { match_expr_list_node!(node_by_id, to_expr, params[12], WrappedSelectOrderExpr); let alias = match_data_node!(node_by_id, params[13], WrappedSelectAlias); let distinct = match_data_node!(node_by_id, params[14], WrappedSelectDistinct); - let ungrouped = match_data_node!(node_by_id, params[15], WrappedSelectUngrouped); + let push_to_cube = + match_data_node!(node_by_id, params[15], WrappedSelectPushToCube); let filter_expr = normalize_cols( replace_qualified_col_with_flat_name_if_missing( @@ -2312,7 +2313,7 @@ impl LanguageToLogicalPlanConverter { order_expr_rebased, alias, distinct, - ungrouped, + push_to_cube, )), }) } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/mod.rs b/rust/cubesql/cubesql/src/compile/rewrite/mod.rs index 2f2445a52d640..7b67cc2042bd6 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/mod.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/mod.rs @@ -283,7 +283,7 @@ crate::plan_to_language! { order_expr: Vec, alias: Option, distinct: bool, - ungrouped: bool, + push_to_cube: bool, ungrouped_scan: bool, }, WrappedSelectJoin { @@ -457,14 +457,29 @@ crate::plan_to_language! { WrapperPushdownReplacer { member: Arc, alias_to_cube: Vec<(String, String)>, - ungrouped: bool, + // This means that result of this replacer would be used as member expression in load query to Cube. + // This flag should be passed from top, by the rule that starts wrapping new logical plan node. + // Important caveat: it means that result would be used for push to cube *and only there*. + // So it's more like "must push to Cube" than "can push to Cube" + // This part is important for rewrites like SUM(sumMeasure) => sumMeasure + // We can use sumMeasure instead of SUM(sumMeasure) ONLY in with push to Cube + // An vice versa, we can't use SUM(sumMeasure) in grouped query to Cube, so it can be allowed ONLY without push to grouped Cube query + push_to_cube: bool, in_projection: bool, cube_members: Vec, }, WrapperPullupReplacer { member: Arc, alias_to_cube: Vec<(String, String)>, - ungrouped: bool, + // When `member` is expression this means that result of this replacer should be used as member expression in load query to Cube. + // When `member` is logical plan node this means that logical plan inside allows to push to Cube + // This flag should make roundtrip from top to bottom and back. + // Important caveat: it means that result should be used for push to cube *and only there*. + // So it's more like "must push to Cube" than "can push to Cube" + // This part is important for rewrites like SUM(sumMeasure) => sumMeasure + // We can use sumMeasure instead of SUM(sumMeasure) ONLY in with push to Cube + // An vice versa, we can't use SUM(sumMeasure) in grouped query to Cube, so it can be allowed ONLY without push to grouped Cube query + push_to_cube: bool, in_projection: bool, cube_members: Vec, }, @@ -500,7 +515,9 @@ crate::plan_to_language! { macro_rules! var_iter { ($eclass:expr, $field_variant:ident) => {{ $eclass.nodes.iter().filter_map(|node| match node { - LogicalPlanLanguage::$field_variant($field_variant(v)) => Some(v), + $crate::compile::rewrite::LogicalPlanLanguage::$field_variant($field_variant(v)) => { + Some(v) + } _ => None, }) }}; @@ -510,7 +527,7 @@ macro_rules! var_iter { macro_rules! var_list_iter { ($eclass:expr, $field_variant:ident) => {{ $eclass.nodes.iter().filter_map(|node| match node { - LogicalPlanLanguage::$field_variant(v) => Some(v), + $crate::compile::rewrite::LogicalPlanLanguage::$field_variant(v) => Some(v), _ => None, }) }}; @@ -523,6 +540,27 @@ macro_rules! var { }; } +#[macro_export] +macro_rules! copy_flag { + ($egraph:expr, $subst:expr, $in_var:expr, $in_kind:ident, $out_var:expr, $out_kind:ident) => {{ + let mut found = false; + for in_value in $crate::var_iter!($egraph[$subst[$in_var]], $in_kind) { + // Typechecking for $in_kind, only booleans are supported for now + let in_value: bool = *in_value; + $subst.insert( + $out_var, + $egraph.add($crate::compile::rewrite::LogicalPlanLanguage::$out_kind( + $out_kind(in_value), + )), + ); + found = true; + // This is safe, because we expect only enode with one child, with boolena inside, and expect that they would never unify + break; + } + found + }}; +} + pub struct WithColumnRelation(Option); impl ExprRewriter for WithColumnRelation { @@ -1384,7 +1422,7 @@ fn wrapped_select( order_expr: impl Display, alias: impl Display, distinct: impl Display, - ungrouped: impl Display, + push_to_cube: impl Display, ungrouped_scan: impl Display, ) -> String { format!( @@ -1404,7 +1442,7 @@ fn wrapped_select( order_expr, alias, distinct, - ungrouped, + push_to_cube, ungrouped_scan ) } @@ -1906,26 +1944,26 @@ fn case_expr_replacer(members: impl Display, alias_to_cube: impl Display) -> Str fn wrapper_pushdown_replacer( members: impl Display, alias_to_cube: impl Display, - ungrouped: impl Display, + push_to_cube: impl Display, in_projection: impl Display, cube_members: impl Display, ) -> String { format!( "(WrapperPushdownReplacer {} {} {} {} {})", - members, alias_to_cube, ungrouped, in_projection, cube_members + members, alias_to_cube, push_to_cube, in_projection, cube_members ) } fn wrapper_pullup_replacer( members: impl Display, alias_to_cube: impl Display, - ungrouped: impl Display, + push_to_cube: impl Display, in_projection: impl Display, cube_members: impl Display, ) -> String { format!( "(WrapperPullupReplacer {} {} {} {} {})", - members, alias_to_cube, ungrouped, in_projection, cube_members + members, alias_to_cube, push_to_cube, in_projection, cube_members ) } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate.rs index dea6d2b1a9564..64f02744fb7dd 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate.rs @@ -6,14 +6,16 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::{members::MemberRules, wrapper::WrapperRules}, subquery, transforming_chain_rewrite, transforming_rewrite, wrapped_select, - wrapped_select_filter_expr_empty_tail, wrapped_select_having_expr_empty_tail, + wrapped_select_aggr_expr_empty_tail, wrapped_select_filter_expr_empty_tail, + wrapped_select_group_expr_empty_tail, wrapped_select_having_expr_empty_tail, wrapped_select_joins_empty_tail, wrapped_select_order_expr_empty_tail, wrapped_select_projection_expr_empty_tail, wrapped_select_subqueries_empty_tail, wrapped_select_window_expr_empty_tail, wrapper_pullup_replacer, wrapper_pushdown_replacer, AggregateFunctionExprDistinct, AggregateFunctionExprFun, AliasExprAlias, ColumnExprColumn, - ListType, LogicalPlanLanguage, WrappedSelectUngrouped, WrapperPullupReplacerAliasToCube, - WrapperPullupReplacerUngrouped, + ListType, LogicalPlanLanguage, WrappedSelectPushToCube, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, }, + copy_flag, transport::V1CubeMetaMeasureExt, var, var_iter, }; @@ -31,7 +33,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -47,42 +49,42 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_projection_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_subqueries_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pushdown_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pushdown_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -90,7 +92,7 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -100,13 +102,13 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), "WrappedSelectAlias:None", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "WrappedSelectUngroupedScan:false", ), "CubeScanWrapperFinalized:false", @@ -114,8 +116,9 @@ impl WrapperRules { self.transform_aggregate( "?group_expr", "?aggr_expr", - "?ungrouped", - "?select_ungrouped", + "?push_to_cube", + "?pushdown_push_to_cube", + "?select_push_to_cube", ), ), transforming_rewrite( @@ -123,7 +126,7 @@ impl WrapperRules { wrapper_pushdown_replacer( grouping_set_expr("?rollout_members", "?type"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -131,7 +134,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?rollout_members", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -145,7 +148,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?rollout_members", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -154,7 +157,7 @@ impl WrapperRules { wrapper_pullup_replacer( grouping_set_expr("?rollout_members", "?type"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -176,7 +179,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?aggr_expr", "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPushdownReplacerPushToCube:true", "?in_projection", "?cube_members", ), @@ -184,7 +187,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?measure", "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPullupReplacerPushToCube:true", "?in_projection", "?cube_members", ), @@ -253,7 +256,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -272,42 +275,42 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_projection_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pushdown_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pushdown_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pushdown_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -315,7 +318,7 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), @@ -325,13 +328,13 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:false", "?cube_members", ), "WrappedSelectAlias:None", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "WrappedSelectUngroupedScan:false", ), "CubeScanWrapperFinalized:false", @@ -340,8 +343,165 @@ impl WrapperRules { "?alias_to_cube", "?group_expr", "?aggr_expr", - "?ungrouped", - "?select_ungrouped", + "?push_to_cube", + "?pushdown_push_to_cube", + "?select_push_to_cube", + ), + )]); + } + + pub fn aggregate_merge_rules(&self, rules: &mut Vec) { + rules.extend(vec![rewrite( + "wrapper-merge-aggregation-with-inner-wrapped-select", + // Input is not a finished wrapper_pullup_replacer, but WrappedSelect just before pullup + // After pullup replacer would disable push to cube, because any node on top would have WrappedSelect in `from` + // So there would be no CubeScan to push to + // Instead, this rule tries to catch `from` before pulling up, and merge outer Aggregate into inner WrappedSelect + aggregate( + cube_scan_wrapper( + wrapped_select( + "WrappedSelectSelectType:Projection", + wrapper_pullup_replacer( + wrapped_select_projection_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_subqueries_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_group_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_aggr_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_window_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + "?inner_from", + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapped_select_joins_empty_tail(), + wrapper_pullup_replacer( + "?inner_filters", + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapped_select_having_expr_empty_tail(), + // Inner must not have limit and offset, because they are not commutative with aggregation + "WrappedSelectLimit:None", + "WrappedSelectOffset:None", + wrapper_pullup_replacer( + wrapped_select_order_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + "WrappedSelectAlias:None", + "WrappedSelectDistinct:false", + "WrappedSelectPushToCube:true", + "WrappedSelectUngroupedScan:true", + ), + "CubeScanWrapperFinalized:false", + ), + "?group_expr", + "?aggr_expr", + "AggregateSplit:false", + ), + cube_scan_wrapper( + wrapped_select( + "WrappedSelectSelectType:Aggregate", + wrapper_pullup_replacer( + wrapped_select_projection_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_subqueries_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pushdown_replacer( + "?group_expr", + "?alias_to_cube", + "WrapperPushdownReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pushdown_replacer( + "?aggr_expr", + "?alias_to_cube", + "WrapperPushdownReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + wrapped_select_window_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapper_pullup_replacer( + "?inner_from", + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapped_select_joins_empty_tail(), + wrapper_pullup_replacer( + "?inner_filters", + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + wrapped_select_having_expr_empty_tail(), + "WrappedSelectLimit:None", + "WrappedSelectOffset:None", + wrapper_pullup_replacer( + wrapped_select_order_expr_empty_tail(), + "?alias_to_cube", + "WrapperPullupReplacerPushToCube:true", + "WrapperPullupReplacerInProjection:false", + "?cube_members", + ), + "WrappedSelectAlias:None", + "WrappedSelectDistinct:false", + "WrappedSelectPushToCube:true", + "WrappedSelectUngroupedScan:false", + ), + "CubeScanWrapperFinalized:false", ), )]); } @@ -350,21 +510,24 @@ impl WrapperRules { &self, group_expr_var: &'static str, aggr_expr_var: &'static str, - ungrouped_var: &'static str, - select_ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + select_push_to_cube_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let group_expr_var = var!(group_expr_var); let aggr_expr_var = var!(aggr_expr_var); - let ungrouped_var = var!(ungrouped_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); move |egraph, subst| { Self::transform_aggregate_impl( egraph, subst, group_expr_var, aggr_expr_var, - ungrouped_var, - select_ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, + select_push_to_cube_var, ) } } @@ -374,14 +537,16 @@ impl WrapperRules { alias_to_cube_var: &'static str, group_expr_var: &'static str, aggr_expr_var: &'static str, - ungrouped_var: &'static str, - select_ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + select_push_to_cube_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let alias_to_cube_var = var!(alias_to_cube_var); let group_expr_var = var!(group_expr_var); let aggr_expr_var = var!(aggr_expr_var); - let ungrouped_var = var!(ungrouped_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); let meta = self.meta_context.clone(); move |egraph, subst| { if Self::transform_check_subquery_allowed( @@ -395,8 +560,9 @@ impl WrapperRules { subst, group_expr_var, aggr_expr_var, - ungrouped_var, - select_ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, + select_push_to_cube_var, ) } else { false @@ -409,8 +575,9 @@ impl WrapperRules { subst: &mut Subst, group_expr_var: Var, aggr_expr_var: Var, - ungrouped_var: Var, - select_ungrouped_var: Var, + push_to_cube_var: Var, + pushdown_push_to_cube_var: Var, + select_push_to_cube_var: Var, ) -> bool { if egraph[subst[group_expr_var]].data.referenced_expr.is_none() { return false; @@ -418,13 +585,28 @@ impl WrapperRules { if egraph[subst[aggr_expr_var]].data.referenced_expr.is_none() { return false; } - for ungrouped in - var_iter!(egraph[subst[ungrouped_var]], WrapperPullupReplacerUngrouped).cloned() + + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPullupReplacerPushToCube, + pushdown_push_to_cube_var, + WrapperPushdownReplacerPushToCube + ) { + return false; + } + + for push_to_cube in var_iter!( + egraph[subst[push_to_cube_var]], + WrapperPullupReplacerPushToCube + ) + .cloned() { subst.insert( - select_ungrouped_var, - egraph.add(LogicalPlanLanguage::WrappedSelectUngrouped( - WrappedSelectUngrouped(ungrouped), + select_push_to_cube_var, + egraph.add(LogicalPlanLanguage::WrappedSelectPushToCube( + WrappedSelectPushToCube(push_to_cube), )), ); return true; diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate_function.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate_function.rs index b398f77221d94..827132fb01df5 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate_function.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/aggregate_function.rs @@ -4,8 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - AggregateFunctionExprDistinct, AggregateFunctionExprFun, LogicalPlanLanguage, - WrapperPullupReplacerAliasToCube, + AggregateFunctionExprDistinct, AggregateFunctionExprFun, WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -20,7 +19,7 @@ impl WrapperRules { wrapper_pushdown_replacer( agg_fun_expr("?fun", vec!["?expr"], "?distinct"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -29,7 +28,7 @@ impl WrapperRules { vec![wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )], @@ -43,7 +42,7 @@ impl WrapperRules { vec![wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )], @@ -52,7 +51,7 @@ impl WrapperRules { wrapper_pullup_replacer( agg_fun_expr("?fun", vec!["?expr"], "?distinct"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/alias.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/alias.rs index 61914129452af..521c4f8d7578c 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/alias.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/alias.rs @@ -11,7 +11,7 @@ impl WrapperRules { wrapper_pushdown_replacer( alias_expr("?expr", "?alias"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -19,7 +19,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -32,7 +32,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -41,7 +41,7 @@ impl WrapperRules { wrapper_pullup_replacer( alias_expr("?expr", "?alias"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/binary_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/binary_expr.rs index d39c897fa76aa..226e7608b5490 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/binary_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/binary_expr.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -18,7 +18,7 @@ impl WrapperRules { wrapper_pushdown_replacer( binary_expr("?left", "?op", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -26,7 +26,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -34,7 +34,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -46,7 +46,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -54,7 +54,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -62,7 +62,7 @@ impl WrapperRules { wrapper_pullup_replacer( binary_expr("?left", "?op", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/case.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/case.rs index 4ffa6de10d6dc..b64ddea965a58 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/case.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/case.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -18,7 +18,7 @@ impl WrapperRules { wrapper_pushdown_replacer( case_expr_var_arg("?when", "?then", "?else"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -26,21 +26,21 @@ impl WrapperRules { wrapper_pushdown_replacer( "?when", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?then", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?else", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -52,21 +52,21 @@ impl WrapperRules { wrapper_pullup_replacer( "?when", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?then", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?else", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -74,7 +74,7 @@ impl WrapperRules { wrapper_pullup_replacer( case_expr_var_arg("?when", "?then", "?else"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cast.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cast.rs index 8aabbe4e4f944..22f8f3945972d 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cast.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cast.rs @@ -11,7 +11,7 @@ impl WrapperRules { wrapper_pushdown_replacer( cast_expr("?expr", "?data_type"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -19,7 +19,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -32,7 +32,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -41,7 +41,7 @@ impl WrapperRules { wrapper_pullup_replacer( cast_expr("?expr", "?data_type"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/column.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/column.rs index 822cf1e9fc510..be57c4b7f743c 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/column.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/column.rs @@ -19,14 +19,14 @@ impl WrapperRules { wrapper_pushdown_replacer( column_expr("?name"), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:false", + "WrapperPushdownReplacerPushToCube:false", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( column_expr("?name"), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:false", + "WrapperPullupReplacerPushToCube:false", "?in_projection", "?cube_members", ), @@ -38,14 +38,14 @@ impl WrapperRules { wrapper_pushdown_replacer( column_expr("?name"), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPushdownReplacerPushToCube:true", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( column_expr("?name"), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPullupReplacerPushToCube:true", "WrapperPullupReplacerInProjection:true", "?cube_members", ), @@ -57,14 +57,14 @@ impl WrapperRules { wrapper_pushdown_replacer( column_expr("?name"), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPushdownReplacerPushToCube:true", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?dimension", "?alias_to_cube", - "WrapperPullupReplacerUngrouped:true", + "WrapperPullupReplacerPushToCube:true", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cube_scan_wrapper.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cube_scan_wrapper.rs index b439f71f191fe..29ae2e2328df2 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cube_scan_wrapper.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/cube_scan_wrapper.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, CubeScanAliasToCube, CubeScanUngrouped, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, WrapperPullupReplacerUngrouped, + LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, WrapperPullupReplacerPushToCube, }, var, var_iter, }; @@ -42,7 +42,7 @@ impl WrapperRules { "?ungrouped", ), "?alias_to_cube_out", - "?ungrouped_out", + "?push_to_cube_out", "WrapperPullupReplacerInProjection:false", "?members", ), @@ -53,7 +53,7 @@ impl WrapperRules { "?alias_to_cube", "?ungrouped", "?alias_to_cube_out", - "?ungrouped_out", + "?push_to_cube_out", ), ), rewrite( @@ -62,7 +62,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -79,13 +79,13 @@ impl WrapperRules { alias_to_cube_var: &'static str, ungrouped_cube_var: &'static str, alias_to_cube_var_out: &'static str, - ungrouped_cube_var_out: &'static str, + push_to_cube_out_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let members_var = var!(members_var); let alias_to_cube_var = var!(alias_to_cube_var); let ungrouped_cube_var = var!(ungrouped_cube_var); let alias_to_cube_var_out = var!(alias_to_cube_var_out); - let ungrouped_cube_var_out = var!(ungrouped_cube_var_out); + let push_to_cube_out_var = var!(push_to_cube_out_var); move |egraph, subst| { if let Some(_) = egraph[subst[members_var]].data.member_name_to_expr { for alias_to_cube in @@ -95,9 +95,9 @@ impl WrapperRules { var_iter!(egraph[subst[ungrouped_cube_var]], CubeScanUngrouped).cloned() { subst.insert( - ungrouped_cube_var_out, - egraph.add(LogicalPlanLanguage::WrapperPullupReplacerUngrouped( - WrapperPullupReplacerUngrouped(ungrouped), + push_to_cube_out_var, + egraph.add(LogicalPlanLanguage::WrapperPullupReplacerPushToCube( + WrapperPullupReplacerPushToCube(ungrouped), )), ); subst.insert( diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/distinct.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/distinct.rs index 2dc8707697014..ab959f80444a3 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/distinct.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/distinct.rs @@ -25,11 +25,11 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "WrappedSelectUngrouped:false", + "WrappedSelectPushToCube:false", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -53,11 +53,11 @@ impl WrapperRules { "?order_expr", "?select_alias", "WrappedSelectDistinct:true", - "WrappedSelectUngrouped:false", + "WrappedSelectPushToCube:false", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/extract.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/extract.rs index c1d3072cd13f1..230aaaa8c17a6 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/extract.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/extract.rs @@ -3,8 +3,7 @@ use crate::{ literal_expr, rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, - transforming_rewrite, wrapper_pullup_replacer, LogicalPlanLanguage, - WrapperPullupReplacerAliasToCube, + transforming_rewrite, wrapper_pullup_replacer, WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -20,14 +19,14 @@ impl WrapperRules { wrapper_pullup_replacer( literal_expr("?date_part"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?date", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -39,7 +38,7 @@ impl WrapperRules { vec![literal_expr("?date_part"), "?date".to_string()], ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/filter.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/filter.rs index 2af376fadfdcc..2f75b8b59cf6f 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/filter.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/filter.rs @@ -9,10 +9,10 @@ use crate::{ wrapped_select_joins_empty_tail, wrapped_select_order_expr_empty_tail, wrapped_select_projection_expr_empty_tail, wrapped_select_subqueries_empty_tail, wrapped_select_window_expr_empty_tail, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrappedSelectUngrouped, WrappedSelectUngroupedScan, - WrapperPullupReplacerUngrouped, + LogicalPlanLanguage, WrappedSelectPushToCube, WrappedSelectUngroupedScan, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use egg::{Subst, Var}; @@ -120,7 +120,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -133,42 +133,42 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_projection_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_subqueries_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_group_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_aggr_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -177,14 +177,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -195,18 +195,23 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), "WrappedSelectAlias:None", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", ), - self.transform_filter("?ungrouped", "?select_ungrouped", "?select_ungrouped_scan"), + self.transform_filter( + "?push_to_cube", + "?pushdown_push_to_cube", + "?select_push_to_cube", + "?select_ungrouped_scan", + ), )]); Self::list_pushdown_pullup_rules( @@ -227,7 +232,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -243,42 +248,42 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_projection_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_group_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_aggr_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -287,14 +292,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -305,21 +310,22 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), "WrappedSelectAlias:None", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", ), self.transform_filter_subquery( "?alias_to_cube", - "?ungrouped", - "?select_ungrouped", + "?push_to_cube", + "?pushdown_push_to_cube", + "?select_push_to_cube", "?select_ungrouped_scan", ), )]); @@ -327,19 +333,22 @@ impl WrapperRules { fn transform_filter( &self, - ungrouped_var: &'static str, - select_ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + select_push_to_cube_var: &'static str, select_ungrouped_scan_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { - let ungrouped_var = var!(ungrouped_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); let select_ungrouped_scan_var = var!(select_ungrouped_scan_var); move |egraph, subst| { Self::transform_filter_impl( egraph, subst, - ungrouped_var, - select_ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, + select_push_to_cube_var, select_ungrouped_scan_var, ) } @@ -348,13 +357,15 @@ impl WrapperRules { fn transform_filter_subquery( &self, alias_to_cube_var: &'static str, - ungrouped_var: &'static str, - select_ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + select_push_to_cube_var: &'static str, select_ungrouped_scan_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let alias_to_cube_var = var!(alias_to_cube_var); - let ungrouped_var = var!(ungrouped_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); let select_ungrouped_scan_var = var!(select_ungrouped_scan_var); let meta = self.meta_context.clone(); move |egraph, subst| { @@ -367,8 +378,9 @@ impl WrapperRules { Self::transform_filter_impl( egraph, subst, - ungrouped_var, - select_ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, + select_push_to_cube_var, select_ungrouped_scan_var, ) } else { @@ -380,24 +392,39 @@ impl WrapperRules { fn transform_filter_impl( egraph: &mut CubeEGraph, subst: &mut Subst, - ungrouped_var: Var, - select_ungrouped_var: Var, + push_to_cube_var: Var, + pushdown_push_to_cube_var: Var, + select_push_to_cube_var: Var, select_ungrouped_scan_var: Var, ) -> bool { - for ungrouped in - var_iter!(egraph[subst[ungrouped_var]], WrapperPullupReplacerUngrouped).cloned() + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPullupReplacerPushToCube, + pushdown_push_to_cube_var, + WrapperPushdownReplacerPushToCube + ) { + return false; + } + + for push_to_cube in var_iter!( + egraph[subst[push_to_cube_var]], + WrapperPullupReplacerPushToCube + ) + .cloned() { subst.insert( - select_ungrouped_var, - egraph.add(LogicalPlanLanguage::WrappedSelectUngrouped( - WrappedSelectUngrouped(ungrouped), + select_push_to_cube_var, + egraph.add(LogicalPlanLanguage::WrappedSelectPushToCube( + WrappedSelectPushToCube(push_to_cube), )), ); subst.insert( select_ungrouped_scan_var, egraph.add(LogicalPlanLanguage::WrappedSelectUngroupedScan( - WrappedSelectUngroupedScan(ungrouped), + WrappedSelectUngroupedScan(push_to_cube), )), ); return true; diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_list_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_list_expr.rs index 01a9c42957789..d2d37c4899bb3 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_list_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_list_expr.rs @@ -4,9 +4,10 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use egg::Subst; @@ -18,7 +19,7 @@ impl WrapperRules { wrapper_pushdown_replacer( inlist_expr("?expr", "?list", "?negated"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -26,27 +27,31 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?list", "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), "?negated", ), - self.transform_in_list_only_consts("?list"), + self.transform_in_list_only_consts( + "?list", + "?push_to_cube", + "?pullup_push_to_cube", + ), ), rewrite( "wrapper-in-list-push-down", wrapper_pushdown_replacer( inlist_expr("?expr", "?list", "?negated"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -54,14 +59,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?list", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -74,14 +79,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?list", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -90,7 +95,7 @@ impl WrapperRules { wrapper_pullup_replacer( inlist_expr("?expr", "?list", "?negated"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -132,9 +137,23 @@ impl WrapperRules { fn transform_in_list_only_consts( &self, list_var: &'static str, + push_to_cube_var: &'static str, + pullup_push_to_cube_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let list_var = var!(list_var); + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); move |egraph: &mut CubeEGraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } return egraph[subst[list_var]].data.constant_in_list.is_some(); } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_subquery_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_subquery_expr.rs index 5c577c4706d3b..d6699eac3dbd4 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_subquery_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/in_subquery_expr.rs @@ -1,17 +1,24 @@ -use crate::compile::rewrite::{ - insubquery_expr, rewrite, rewriter::CubeRewrite, rules::wrapper::WrapperRules, - wrapper_pullup_replacer, wrapper_pushdown_replacer, +use crate::{ + compile::rewrite::{ + insubquery_expr, rewrite, + rewriter::{CubeEGraph, CubeRewrite}, + rules::wrapper::WrapperRules, + transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, + }, + copy_flag, var, }; +use egg::Subst; impl WrapperRules { pub fn in_subquery_expr_rules(&self, rules: &mut Vec) { rules.extend(vec![ - rewrite( + transforming_rewrite( "wrapper-in-subquery-push-down", wrapper_pushdown_replacer( insubquery_expr("?expr", "?subquery", "?negated"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -19,19 +26,20 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subquery", "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), "?negated", ), + self.transform_in_subquery_pushdown("?push_to_cube", "?pullup_push_to_cube"), ), rewrite( "wrapper-in-subquery-pull-up", @@ -39,14 +47,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subquery", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -55,11 +63,33 @@ impl WrapperRules { wrapper_pullup_replacer( insubquery_expr("?expr", "?subquery", "?negated"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), ), ]); } + + fn transform_in_subquery_pushdown( + &self, + push_to_cube_var: &'static str, + pullup_push_to_cube_var: &'static str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph: &mut CubeEGraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + true + } + } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/is_null_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/is_null_expr.rs index 6c84953ddc211..8239eb0aa34e8 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/is_null_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/is_null_expr.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -18,14 +18,14 @@ impl WrapperRules { wrapper_pushdown_replacer( is_null_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), is_null_expr(wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), @@ -35,14 +35,14 @@ impl WrapperRules { is_null_expr(wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), wrapper_pullup_replacer( is_null_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -53,14 +53,14 @@ impl WrapperRules { wrapper_pushdown_replacer( is_not_null_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), is_not_null_expr(wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), @@ -70,14 +70,14 @@ impl WrapperRules { is_not_null_expr(wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), wrapper_pullup_replacer( is_not_null_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/like_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/like_expr.rs index 41b38376b8f2f..98a8f85379a0b 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/like_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/like_expr.rs @@ -4,8 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LikeExprEscapeChar, LikeExprLikeType, LikeType, LogicalPlanLanguage, - WrapperPullupReplacerAliasToCube, + LikeExprEscapeChar, LikeExprLikeType, LikeType, WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -25,7 +24,7 @@ impl WrapperRules { "?escape_char", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -35,14 +34,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?pattern", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -57,14 +56,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?pattern", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -79,7 +78,7 @@ impl WrapperRules { "?escape_char", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/limit.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/limit.rs index b4404bc9232ed..d46cb971541a3 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/limit.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/limit.rs @@ -35,11 +35,11 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -64,11 +64,11 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/literal.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/literal.rs index 4f2d7531e3ac0..91cab261e8c98 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/literal.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/literal.rs @@ -2,9 +2,10 @@ use crate::{ compile::rewrite::{ literal_expr, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, LiteralExprValue, LogicalPlanLanguage, - WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use crate::compile::rewrite::{ @@ -22,36 +23,47 @@ impl WrapperRules { wrapper_pushdown_replacer( literal_expr("?value"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( literal_expr("?value"), "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), - self.transform_literal("?alias_to_cube", "?value"), + self.transform_literal( + "?alias_to_cube", + "?value", + "?push_to_cube", + "?pullup_push_to_cube", + ), ), transforming_rewrite( "wrapper-push-down-interval-literal", wrapper_pushdown_replacer( literal_expr("?value"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?new_value", "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), - self.transform_interval_literal("?alias_to_cube", "?value", "?new_value"), + self.transform_interval_literal( + "?alias_to_cube", + "?value", + "?new_value", + "?push_to_cube", + "?pullup_push_to_cube", + ), ), ]); } @@ -60,11 +72,26 @@ impl WrapperRules { &self, alias_to_cube_var: &str, value_var: &str, + push_to_cube_var: &str, + pullup_push_to_cube_var: &str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let alias_to_cube_var = var!(alias_to_cube_var); let value_var = var!(value_var); + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); let meta = self.meta_context.clone(); move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + for alias_to_cube in var_iter!( egraph[subst[alias_to_cube_var]], WrapperPullupReplacerAliasToCube @@ -100,12 +127,27 @@ impl WrapperRules { alias_to_cube_var: &str, value_var: &str, new_value_var: &str, + push_to_cube_var: &str, + pullup_push_to_cube_var: &str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let alias_to_cube_var = var!(alias_to_cube_var); let value_var = var!(value_var); let new_value_var = var!(new_value_var); + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); let meta = self.meta_context.clone(); move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + for alias_to_cube in var_iter!( egraph[subst[alias_to_cube_var]], WrapperPullupReplacerAliasToCube diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/mod.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/mod.rs index 65966c4b9ae14..5624d3a201134 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/mod.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/mod.rs @@ -29,17 +29,21 @@ mod wrapper_pull_up; use crate::{ compile::rewrite::{ - fun_expr, rewrite, - rewriter::{CubeRewrite, RewriteRules}, + fun_expr, + rewriter::{CubeEGraph, CubeRewrite, RewriteRules}, rules::{ replacer_flat_pull_up_node, replacer_flat_push_down_node, replacer_pull_up_node, replacer_push_down_node, }, - wrapper_pullup_replacer, wrapper_pushdown_replacer, ListType, + transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, ListType, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, }, config::ConfigObj, + copy_flag, transport::MetaContext, + var, }; +use egg::Subst; use std::{fmt::Display, sync::Arc}; pub struct WrapperRules { @@ -55,6 +59,7 @@ impl RewriteRules for WrapperRules { self.wrapper_pull_up_rules(&mut rules); self.aggregate_rules(&mut rules); self.aggregate_rules_subquery(&mut rules); + self.aggregate_merge_rules(&mut rules); self.projection_rules(&mut rules); self.projection_rules_subquery(&mut rules); self.limit_rules(&mut rules); @@ -112,7 +117,7 @@ impl WrapperRules { wrapper_pushdown_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) @@ -128,32 +133,54 @@ impl WrapperRules { wrapper_pullup_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) }, )); - rules.extend(vec![rewrite( + rules.extend(vec![transforming_rewrite( &format!("{}-tail", rule_name), wrapper_pushdown_replacer( list_node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( substitute_list_node, "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), + Self::transform_list_tail("?push_to_cube", "?pullup_push_to_cube"), )]); } + fn transform_list_tail( + push_to_cube_var: &str, + pullup_push_to_cube_var: &str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + true + } + } + fn flat_list_pushdown_pullup_rules( rules: &mut Vec, rule_name: &str, @@ -167,7 +194,7 @@ impl WrapperRules { wrapper_pushdown_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) @@ -183,38 +210,60 @@ impl WrapperRules { wrapper_pullup_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) }, &[ "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ], )); - rules.extend(vec![rewrite( + rules.extend(vec![transforming_rewrite( &format!("{}-tail", rule_name), wrapper_pushdown_replacer( list_type.empty_list(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( substitute_list_type.empty_list(), "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), + Self::transform_flat_list_tail("?push_to_cube", "?pullup_push_to_cube"), )]); } + fn transform_flat_list_tail( + push_to_cube_var: &str, + pullup_push_to_cube_var: &str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + true + } + } + fn expr_list_pushdown_pullup_rules( rules: &mut Vec, rule_name: &str, @@ -227,7 +276,7 @@ impl WrapperRules { wrapper_pushdown_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) @@ -243,29 +292,51 @@ impl WrapperRules { wrapper_pullup_replacer( node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ) }, )); - rules.extend(vec![rewrite( + rules.extend(vec![transforming_rewrite( rule_name, wrapper_pushdown_replacer( list_node, "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( list_node, "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), + Self::transform_expr_list_tail("?push_to_cube", "?pullup_push_to_cube"), )]); } + + fn transform_expr_list_tail( + push_to_cube_var: &str, + pullup_push_to_cube_var: &str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + true + } + } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/negative_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/negative_expr.rs index 20ef82810d1ce..52c303ce32aa3 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/negative_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/negative_expr.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -18,14 +18,14 @@ impl WrapperRules { wrapper_pushdown_replacer( negative_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), negative_expr(wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), @@ -35,14 +35,14 @@ impl WrapperRules { negative_expr(wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), wrapper_pullup_replacer( negative_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/not_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/not_expr.rs index 79d1b114fcb90..82572f59d97e4 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/not_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/not_expr.rs @@ -4,7 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, - LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -18,14 +18,14 @@ impl WrapperRules { wrapper_pushdown_replacer( not_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), not_expr(wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), @@ -35,14 +35,14 @@ impl WrapperRules { not_expr(wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", )), wrapper_pullup_replacer( not_expr("?expr"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/order.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/order.rs index 35b58940d28d3..98f9718d4f8f4 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/order.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/order.rs @@ -1,12 +1,19 @@ -use crate::compile::rewrite::{ - cube_scan_wrapper, rewrite, rewriter::CubeRewrite, rules::wrapper::WrapperRules, sort, - wrapped_select, wrapped_select_order_expr_empty_tail, wrapper_pullup_replacer, - wrapper_pushdown_replacer, +use crate::{ + compile::rewrite::{ + cube_scan_wrapper, + rewriter::{CubeEGraph, CubeRewrite}, + rules::wrapper::WrapperRules, + sort, transforming_rewrite, wrapped_select, wrapped_select_order_expr_empty_tail, + wrapper_pullup_replacer, wrapper_pushdown_replacer, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, + }, + copy_flag, var, }; +use egg::Subst; impl WrapperRules { pub fn order_rules(&self, rules: &mut Vec) { - rules.extend(vec![rewrite( + rules.extend(vec![transforming_rewrite( "wrapper-push-down-order-to-cube-scan", sort( "?order_expr", @@ -28,11 +35,11 @@ impl WrapperRules { wrapped_select_order_expr_empty_tail(), "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -45,42 +52,42 @@ impl WrapperRules { wrapper_pullup_replacer( "?projection_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?window_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -88,7 +95,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -98,17 +105,18 @@ impl WrapperRules { wrapper_pushdown_replacer( "?order_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "?in_projection", "?cube_members", ), "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", ), + self.transform_order("?push_to_cube", "?pushdown_push_to_cube"), )]); Self::list_pushdown_pullup_rules( @@ -118,4 +126,26 @@ impl WrapperRules { "WrappedSelectOrderExpr", ); } + + fn transform_order( + &self, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPullupReplacerPushToCube, + pushdown_push_to_cube_var, + WrapperPushdownReplacerPushToCube + ) { + return false; + } + true + } + } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/projection.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/projection.rs index 42aaee98d8498..473c5b04fef16 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/projection.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/projection.rs @@ -8,10 +8,11 @@ use crate::{ wrapped_select_having_expr_empty_tail, wrapped_select_joins_empty_tail, wrapped_select_order_expr_empty_tail, wrapped_select_subqueries_empty_tail, wrapped_select_window_expr_empty_tail, wrapper_pullup_replacer, wrapper_pushdown_replacer, - ListType, LogicalPlanLanguage, ProjectionAlias, WrappedSelectAlias, WrappedSelectUngrouped, - WrappedSelectUngroupedScan, WrapperPullupReplacerUngrouped, + ListType, LogicalPlanLanguage, ProjectionAlias, WrappedSelectAlias, + WrappedSelectPushToCube, WrappedSelectUngroupedScan, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use egg::{Subst, Var}; @@ -25,7 +26,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -40,42 +41,42 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_subqueries_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_group_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_aggr_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), @@ -83,7 +84,7 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), @@ -93,13 +94,13 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), "?select_alias", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", @@ -107,9 +108,10 @@ impl WrapperRules { self.transform_projection( "?expr", "?projection_alias", - "?ungrouped", + "?push_to_cube", + "?pushdown_push_to_cube", "?select_alias", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), )]); @@ -141,7 +143,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -159,42 +161,42 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pushdown_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_group_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_aggr_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( wrapped_select_window_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), @@ -202,7 +204,7 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_filter_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), @@ -212,13 +214,13 @@ impl WrapperRules { wrapper_pullup_replacer( wrapped_select_order_expr_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "WrapperPullupReplacerInProjection:true", "?cube_members", ), "?select_alias", "WrappedSelectDistinct:false", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", @@ -227,9 +229,10 @@ impl WrapperRules { "?alias_to_cube", "?expr", "?projection_alias", - "?ungrouped", + "?push_to_cube", + "?pushdown_push_to_cube", "?select_alias", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), )]); @@ -238,16 +241,18 @@ impl WrapperRules { &self, expr_var: &'static str, projection_alias_var: &'static str, - ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, select_alias_var: &'static str, - select_ungrouped_var: &'static str, + select_push_to_cube_var: &'static str, select_ungrouped_scan_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let expr_var = var!(expr_var); let projection_alias_var = var!(projection_alias_var); - let ungrouped_var = var!(ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); let select_alias_var = var!(select_alias_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); let select_ungrouped_scan_var = var!(select_ungrouped_scan_var); move |egraph, subst| { Self::transform_projection_impl( @@ -255,9 +260,10 @@ impl WrapperRules { subst, expr_var, projection_alias_var, - ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, select_alias_var, - select_ungrouped_var, + select_push_to_cube_var, select_ungrouped_scan_var, ) } @@ -268,17 +274,19 @@ impl WrapperRules { alias_to_cube_var: &'static str, expr_var: &'static str, projection_alias_var: &'static str, - ungrouped_var: &'static str, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, select_alias_var: &'static str, - select_ungrouped_var: &'static str, + select_push_to_cube_var: &'static str, select_ungrouped_scan_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let alias_to_cube_var = var!(alias_to_cube_var); let expr_var = var!(expr_var); let projection_alias_var = var!(projection_alias_var); - let ungrouped_var = var!(ungrouped_var); + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); let select_alias_var = var!(select_alias_var); - let select_ungrouped_var = var!(select_ungrouped_var); + let select_push_to_cube_var = var!(select_push_to_cube_var); let select_ungrouped_scan_var = var!(select_ungrouped_scan_var); let meta = self.meta_context.clone(); move |egraph, subst| { @@ -293,9 +301,10 @@ impl WrapperRules { subst, expr_var, projection_alias_var, - ungrouped_var, + push_to_cube_var, + pushdown_push_to_cube_var, select_alias_var, - select_ungrouped_var, + select_push_to_cube_var, select_ungrouped_scan_var, ) } else { @@ -309,28 +318,43 @@ impl WrapperRules { subst: &mut Subst, expr_var: Var, projection_alias_var: Var, - ungrouped_var: Var, + push_to_cube_var: Var, + pushdown_push_to_cube_var: Var, select_alias_var: Var, - select_ungrouped_var: Var, + select_push_to_cube_var: Var, select_ungrouped_scan_var: Var, ) -> bool { if let Some(_) = &egraph[subst[expr_var]].data.referenced_expr { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPullupReplacerPushToCube, + pushdown_push_to_cube_var, + WrapperPushdownReplacerPushToCube + ) { + return false; + } + for projection_alias in var_iter!(egraph[subst[projection_alias_var]], ProjectionAlias).cloned() { - for ungrouped in - var_iter!(egraph[subst[ungrouped_var]], WrapperPullupReplacerUngrouped).cloned() + for push_to_cube in var_iter!( + egraph[subst[push_to_cube_var]], + WrapperPullupReplacerPushToCube + ) + .cloned() { subst.insert( - select_ungrouped_var, - egraph.add(LogicalPlanLanguage::WrappedSelectUngrouped( - WrappedSelectUngrouped(ungrouped), + select_push_to_cube_var, + egraph.add(LogicalPlanLanguage::WrappedSelectPushToCube( + WrappedSelectPushToCube(push_to_cube), )), ); subst.insert( select_ungrouped_scan_var, egraph.add(LogicalPlanLanguage::WrappedSelectUngroupedScan( - WrappedSelectUngroupedScan(ungrouped), + WrappedSelectUngroupedScan(push_to_cube), )), ); subst.insert( diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/scalar_function.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/scalar_function.rs index b6cd4883c8c54..a888fa8ab9e70 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/scalar_function.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/scalar_function.rs @@ -5,9 +5,10 @@ use crate::{ rules::wrapper::WrapperRules, scalar_fun_expr_args_empty_tail, scalar_fun_expr_args_legacy, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, ListPattern, ListType, - LogicalPlanLanguage, ScalarFunctionExprFun, WrapperPullupReplacerAliasToCube, + ScalarFunctionExprFun, WrapperPullupReplacerAliasToCube, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use egg::Subst; @@ -19,7 +20,7 @@ impl WrapperRules { wrapper_pushdown_replacer( fun_expr_var_arg("?fun", "?args"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -28,7 +29,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -41,7 +42,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -49,28 +50,29 @@ impl WrapperRules { wrapper_pullup_replacer( fun_expr_var_arg("?fun", "?args"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), self.transform_fun_expr("?fun", "?alias_to_cube"), ), - rewrite( + transforming_rewrite( "wrapper-push-down-scalar-function-empty-tail", wrapper_pushdown_replacer( scalar_fun_expr_args_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( scalar_fun_expr_args_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), + self.transform_scalar_function_empty_tail("?push_to_cube", "?pullup_push_to_cube"), ), ]); @@ -83,7 +85,7 @@ impl WrapperRules { pattern: wrapper_pushdown_replacer( "?args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -96,7 +98,7 @@ impl WrapperRules { elem: wrapper_pushdown_replacer( "?arg", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -111,7 +113,7 @@ impl WrapperRules { elem: wrapper_pullup_replacer( "?arg", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -120,7 +122,7 @@ impl WrapperRules { pattern: wrapper_pullup_replacer( "?new_args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -129,7 +131,7 @@ impl WrapperRules { }, &[ "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ], @@ -142,7 +144,7 @@ impl WrapperRules { wrapper_pushdown_replacer( scalar_fun_expr_args_legacy("?left", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -150,14 +152,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -169,14 +171,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -184,7 +186,7 @@ impl WrapperRules { wrapper_pullup_replacer( scalar_fun_expr_args_legacy("?left", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -193,6 +195,29 @@ impl WrapperRules { } } + fn transform_scalar_function_empty_tail( + &self, + push_to_cube_var: &'static str, + pullup_push_to_cube_var: &'static str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + + true + } + } + fn transform_fun_expr( &self, fun_var: &'static str, diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/sort_expr.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/sort_expr.rs index 1c4a8d652354e..1e5262fdd4133 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/sort_expr.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/sort_expr.rs @@ -11,7 +11,7 @@ impl WrapperRules { wrapper_pushdown_replacer( sort_expr("?expr", "?asc", "?nulls_first"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -19,7 +19,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -33,7 +33,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -43,7 +43,7 @@ impl WrapperRules { wrapper_pullup_replacer( sort_expr("?expr", "?asc", "?nulls_first"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/subquery.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/subquery.rs index 48629fdbab7b6..686499b1b5093 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/subquery.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/subquery.rs @@ -5,7 +5,9 @@ use crate::{ rules::wrapper::WrapperRules, transforming_rewrite, wrapper_pullup_replacer, wrapper_pushdown_replacer, EmptyRelationDerivedSourceTableName, LogicalPlanLanguage, WrapperPullupReplacerAliasToCube, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, }, + copy_flag, transport::MetaContext, var, var_iter, var_list_iter, }; @@ -22,25 +24,29 @@ impl WrapperRules { wrapper_pullup_replacer( "?cube_scan_input", "?inner_alias_to_cube", - "?nner_ungrouped", + "?nner_push_to_cube", "?inner_in_projection", "?inner_cube_members", ), "CubeScanWrapperFinalized:false", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), - self.transform_check_subquery_wrapped("?cube_scan_input"), + self.transform_check_subquery_wrapped( + "?cube_scan_input", + "?push_to_cube", + "?pullup_push_to_cube", + ), ), transforming_rewrite( "wrapper-subqueries-wrap-empty-rel", @@ -57,7 +63,7 @@ impl WrapperRules { "EmptyRelationIsWrappable:true", ), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:false", + "WrapperPullupReplacerPushToCube:false", "WrapperPullupReplacerInProjection:true", "CubeScanMembers", ), @@ -138,9 +144,24 @@ impl WrapperRules { fn transform_check_subquery_wrapped( &self, cube_scan_input_var: &'static str, + push_to_cube_var: &'static str, + pullup_push_to_cube_var: &'static str, ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { let cube_scan_input_var = var!(cube_scan_input_var); + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + for _ in var_list_iter!(egraph[subst[cube_scan_input_var]], WrappedSelect).cloned() { return true; } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/udf_function.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/udf_function.rs index 25bd9f7aa4e48..5505b1f467281 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/udf_function.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/udf_function.rs @@ -4,10 +4,11 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, udf_expr_var_arg, udf_fun_expr_args, udf_fun_expr_args_empty_tail, - wrapper_pullup_replacer, wrapper_pushdown_replacer, LogicalPlanLanguage, ScalarUDFExprFun, - WrapperPullupReplacerAliasToCube, + wrapper_pullup_replacer, wrapper_pushdown_replacer, ScalarUDFExprFun, + WrapperPullupReplacerAliasToCube, WrapperPullupReplacerPushToCube, + WrapperPushdownReplacerPushToCube, }, - var, var_iter, + copy_flag, var, var_iter, }; use egg::Subst; @@ -19,7 +20,7 @@ impl WrapperRules { wrapper_pushdown_replacer( udf_expr_var_arg("?fun", "?args"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -28,7 +29,7 @@ impl WrapperRules { wrapper_pushdown_replacer( "?args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -41,7 +42,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?args", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -49,7 +50,7 @@ impl WrapperRules { wrapper_pullup_replacer( udf_expr_var_arg("?fun", "?args"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -60,7 +61,7 @@ impl WrapperRules { wrapper_pushdown_replacer( udf_fun_expr_args("?left", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -68,14 +69,14 @@ impl WrapperRules { wrapper_pushdown_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -87,14 +88,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?left", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?right", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -102,27 +103,28 @@ impl WrapperRules { wrapper_pullup_replacer( udf_fun_expr_args("?left", "?right"), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), ), - rewrite( + transforming_rewrite( "wrapper-push-down-udf-empty-tail", wrapper_pushdown_replacer( udf_fun_expr_args_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( udf_fun_expr_args_empty_tail(), "?alias_to_cube", - "?ungrouped", + "?pullup_push_to_cube", "?in_projection", "?cube_members", ), + self.transform_udf_expr_tail("?push_to_cube", "?pullup_push_to_cube"), ), ]); } @@ -157,4 +159,26 @@ impl WrapperRules { false } } + + fn transform_udf_expr_tail( + &self, + push_to_cube_var: &'static str, + pullup_push_to_cube_var: &'static str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pullup_push_to_cube_var = var!(pullup_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPushdownReplacerPushToCube, + pullup_push_to_cube_var, + WrapperPullupReplacerPushToCube + ) { + return false; + } + true + } + } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window.rs index 9ca83c4807dea..928a1dd388cc4 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window.rs @@ -1,12 +1,19 @@ -use crate::compile::rewrite::{ - cube_scan_wrapper, rewrite, rewriter::CubeRewrite, rules::wrapper::WrapperRules, window, - wrapped_select, wrapped_select_window_expr_empty_tail, wrapper_pullup_replacer, - wrapper_pushdown_replacer, ListType, +use crate::{ + compile::rewrite::{ + cube_scan_wrapper, + rewriter::{CubeEGraph, CubeRewrite}, + rules::wrapper::WrapperRules, + transforming_rewrite, window, wrapped_select, wrapped_select_window_expr_empty_tail, + wrapper_pullup_replacer, wrapper_pushdown_replacer, ListType, + WrapperPullupReplacerPushToCube, WrapperPushdownReplacerPushToCube, + }, + copy_flag, var, }; +use egg::Subst; impl WrapperRules { pub fn window_rules(&self, rules: &mut Vec) { - rules.extend(vec![rewrite( + rules.extend(vec![transforming_rewrite( "wrapper-push-down-window-to-cube-scan", window( cube_scan_wrapper( @@ -27,11 +34,11 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -45,42 +52,42 @@ impl WrapperRules { wrapper_pullup_replacer( "?projection_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?window_expr", "?alias_to_cube", - "?ungrouped", + "?pushdown_push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -88,7 +95,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -98,17 +105,18 @@ impl WrapperRules { wrapper_pullup_replacer( "?order_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", ), + self.transform_window_pushdown("?push_to_cube", "?pushdown_push_to_cube"), )]); if self.config_obj.push_down_pull_up_split() { @@ -127,4 +135,26 @@ impl WrapperRules { ); } } + + fn transform_window_pushdown( + &self, + push_to_cube_var: &'static str, + pushdown_push_to_cube_var: &'static str, + ) -> impl Fn(&mut CubeEGraph, &mut Subst) -> bool { + let push_to_cube_var = var!(push_to_cube_var); + let pushdown_push_to_cube_var = var!(pushdown_push_to_cube_var); + move |egraph, subst| { + if !copy_flag!( + egraph, + subst, + push_to_cube_var, + WrapperPullupReplacerPushToCube, + pushdown_push_to_cube_var, + WrapperPushdownReplacerPushToCube + ) { + return false; + } + true + } + } } diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window_function.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window_function.rs index de89203ff4321..c2fe257d4130a 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window_function.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/window_function.rs @@ -4,8 +4,7 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, window_fun_expr_var_arg, wrapper_pullup_replacer, - wrapper_pushdown_replacer, LogicalPlanLanguage, WindowFunctionExprFun, - WrapperPullupReplacerAliasToCube, + wrapper_pushdown_replacer, WindowFunctionExprFun, WrapperPullupReplacerAliasToCube, }, var, var_iter, }; @@ -26,7 +25,7 @@ impl WrapperRules { "?window_frame", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -35,21 +34,21 @@ impl WrapperRules { wrapper_pushdown_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?partition_by", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pushdown_replacer( "?order_by", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -63,21 +62,21 @@ impl WrapperRules { wrapper_pullup_replacer( "?expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?partition_by", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?order_by", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -92,7 +91,7 @@ impl WrapperRules { "?window_frame", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/wrapper_pull_up.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/wrapper_pull_up.rs index cb59a308fc48f..be7c228d321b7 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/wrapper_pull_up.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/wrapper_pull_up.rs @@ -4,8 +4,8 @@ use crate::{ rewriter::{CubeEGraph, CubeRewrite}, rules::wrapper::WrapperRules, transforming_rewrite, wrapped_select, wrapped_select_having_expr_empty_tail, - wrapped_select_joins_empty_tail, wrapper_pullup_replacer, LogicalPlanLanguage, - WrappedSelectSelectType, WrappedSelectType, + wrapped_select_joins_empty_tail, wrapper_pullup_replacer, WrappedSelectSelectType, + WrappedSelectType, }, var, var_iter, var_list_iter, }; @@ -22,42 +22,42 @@ impl WrapperRules { wrapper_pullup_replacer( "?projection_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?window_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?cube_scan_input", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -65,7 +65,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -75,13 +75,13 @@ impl WrapperRules { wrapper_pullup_replacer( "?order_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", @@ -104,12 +104,14 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "?select_ungrouped", + "?select_push_to_cube", "?select_ungrouped_scan", ), "?alias_to_cube", // TODO in fact ungrouped flag is being used not only to indicate that underlying query is ungrouped however to indicate that WrappedSelect won't push down Cube members. Do we need separate flags? - "WrapperPullupReplacerUngrouped:false", + // This is fixed to false for any LHS because we should only allow to push to Cube when from is ungrouped CubeScan + // And after pulling replacer over this node it will be WrappedSelect(from=CubeScan), so it should not allow to push for whatever LP is on top of it + "WrapperPullupReplacerPushToCube:false", "?in_projection", "?cube_members", ), @@ -125,35 +127,35 @@ impl WrapperRules { wrapper_pullup_replacer( "?projection_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?subqueries", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?group_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?aggr_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), wrapper_pullup_replacer( "?window_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -174,11 +176,11 @@ impl WrapperRules { "?inner_order_expr", "?inner_alias", "?inner_distinct", - "?inner_ungrouped", + "?inner_push_to_cube", "?inner_ungrouped_scan", ), "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -186,7 +188,7 @@ impl WrapperRules { wrapper_pullup_replacer( "?filter_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), @@ -196,13 +198,14 @@ impl WrapperRules { wrapper_pullup_replacer( "?order_expr", "?alias_to_cube", - "?ungrouped", + "?push_to_cube", "?in_projection", "?cube_members", ), "?select_alias", "?select_distinct", - "?select_ungrouped", + // This node has a WrappedSelect in from, so it's not allowed to use push to Cube + "WrappedSelectPushToCube:false", "?select_ungrouped_scan", ), "CubeScanWrapperFinalized:false", @@ -232,7 +235,7 @@ impl WrapperRules { "?inner_order_expr", "?inner_alias", "?inner_distinct", - "?inner_ungrouped", + "?inner_push_to_cube", "?inner_ungrouped_scan", ), wrapped_select_joins_empty_tail(), @@ -243,11 +246,13 @@ impl WrapperRules { "?order_expr", "?select_alias", "?select_distinct", - "?select_ungrouped", + "WrappedSelectPushToCube:false", "?select_ungrouped_scan", ), "?alias_to_cube", - "WrapperPullupReplacerUngrouped:false", + // This is fixed to false for any LHS because we should only allow to push to Cube when from is ungrouped CubeSCan + // And after pulling replacer over this node it will be WrappedSelect(from=WrappedSelect), so it should not allow to push for whatever LP is on top of it + "WrapperPullupReplacerPushToCube:false", "?inner_projection_expr", "?cube_members", ), diff --git a/rust/cubesql/cubesql/src/compile/test/mod.rs b/rust/cubesql/cubesql/src/compile/test/mod.rs index 7fb8672fe856f..d2737c53bb164 100644 --- a/rust/cubesql/cubesql/src/compile/test/mod.rs +++ b/rust/cubesql/cubesql/src/compile/test/mod.rs @@ -785,16 +785,20 @@ impl TransportService for TestConnectionTransport { query: TransportLoadRequestQuery, _ctx: AuthContextRef, meta: LoadRequestMeta, - _member_to_alias: Option>, + member_to_alias: Option>, expression_params: Option>>, ) -> Result { let inputs = serde_json::json!({ "query": query, "meta": meta, + "member_to_alias": member_to_alias, }); Ok(SqlResponse { sql: SqlQuery::new( - format!("SELECT * FROM {}", serde_json::to_string(&inputs).unwrap()), + format!( + "SELECT * FROM {}", + serde_json::to_string_pretty(&inputs).unwrap() + ), expression_params.unwrap_or(Vec::new()), ), }) diff --git a/rust/cubesql/cubesql/src/compile/test/test_user_change.rs b/rust/cubesql/cubesql/src/compile/test/test_user_change.rs index 47f0164a5fba3..ae2a8b2e171ef 100644 --- a/rust/cubesql/cubesql/src/compile/test/test_user_change.rs +++ b/rust/cubesql/cubesql/src/compile/test/test_user_change.rs @@ -271,6 +271,6 @@ GROUP BY 1 let sql_query = load_calls[0].sql_query.as_ref().unwrap(); // This should be placed from load meta to query by TestConnectionTransport::sql // It would mean that SQL generation used changed user - assert!(sql_query.sql.contains(r#""changeUser":"gopher""#)); + assert!(sql_query.sql.contains(r#""changeUser": "gopher""#)); assert_eq!(load_calls[0].meta.change_user(), Some("gopher".to_string())); } diff --git a/rust/cubesql/cubesql/src/compile/test/test_wrapper.rs b/rust/cubesql/cubesql/src/compile/test/test_wrapper.rs index a133391646e65..b899760160c2d 100644 --- a/rust/cubesql/cubesql/src/compile/test/test_wrapper.rs +++ b/rust/cubesql/cubesql/src/compile/test/test_wrapper.rs @@ -1,4 +1,6 @@ use datafusion::physical_plan::displayable; +use pretty_assertions::assert_eq; +use serde_json::json; use std::sync::Arc; use crate::{ @@ -11,6 +13,7 @@ use crate::{ DatabaseProtocol, }, config::ConfigObjImpl, + transport::TransportLoadRequestQuery, }; #[tokio::test] @@ -426,7 +429,7 @@ async fn test_simple_subquery_wrapper_projection() { .wrapped_sql .unwrap() .sql - .contains("\\\\\\\"limit\\\\\\\":1")); + .contains("\\\\\\\"limit\\\\\\\": 1")); let _physical_plan = query_plan.as_physical_plan().await.unwrap(); } @@ -482,7 +485,7 @@ async fn test_simple_subquery_wrapper_filter_equal() { .wrapped_sql .unwrap() .sql - .contains("\\\\\\\"limit\\\\\\\":1")); + .contains("\\\\\\\"limit\\\\\\\": 1")); let _physical_plan = query_plan.as_physical_plan().await.unwrap(); } @@ -1001,3 +1004,79 @@ async fn test_wrapper_limit_zero() { let _physical_plan = query_plan.as_physical_plan().await.unwrap(); } + +/// Tests that Aggregation(Filter(CubeScan(ungrouped=true))) with expresions in filter +/// can be executed as a single ungrouped=false load query +#[tokio::test] +async fn test_wrapper_filter_flatten() { + if !Rewriter::sql_push_down_enabled() { + return; + } + init_testing_logger(); + + let query_plan = convert_select_to_query_plan( + // language=PostgreSQL + r#" + SELECT + customer_gender, + SUM(sumPrice) + FROM + KibanaSampleDataEcommerce + WHERE + LOWER(customer_gender) = 'male' + GROUP BY + 1 + "# + .to_string(), + DatabaseProtocol::PostgreSQL, + ) + .await; + + let physical_plan = query_plan.as_physical_plan().await.unwrap(); + println!( + "Physical plan: {}", + displayable(physical_plan.as_ref()).indent() + ); + + assert_eq!( + query_plan + .as_logical_plan() + .find_cube_scan_wrapper() + .request + .unwrap(), + TransportLoadRequestQuery { + measures: Some(vec![json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "sum_kibanasample", + "cube_params": ["KibanaSampleDataEcommerce"], + // This is grouped query, KibanaSampleDataEcommerce.sumPrice is correct in this context + // SUM(sumPrice) will be incrrect here, it would lead to SUM(SUM(sql)) in generated query + "expr": "${KibanaSampleDataEcommerce.sumPrice}", + "grouping_set": null, + }) + .to_string(),]), + dimensions: Some(vec![json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "customer_gender", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "${KibanaSampleDataEcommerce.customer_gender}", + "grouping_set": null, + }) + .to_string(),]), + segments: Some(vec![json!({ + "cube_name": "KibanaSampleDataEcommerce", + "alias": "lower_kibanasamp", + "cube_params": ["KibanaSampleDataEcommerce"], + "expr": "(LOWER(${KibanaSampleDataEcommerce.customer_gender}) = $0$)", + "grouping_set": null, + }) + .to_string(),]), + time_dimensions: None, + order: Some(vec![]), + limit: Some(50000), + offset: None, + filters: None, + ungrouped: None, + } + ); +}