From feffd5b1ac7f8b77b4c7a682eff5dd3ab890f202 Mon Sep 17 00:00:00 2001 From: Benjamin Owad Date: Mon, 12 Feb 2024 17:35:55 -0500 Subject: [PATCH] feat: Support limit operations (#58) --- Cargo.lock | 138 +++++++++--------- optd-datafusion-bridge/src/from_optd.rs | 44 +++++- optd-datafusion-bridge/src/into_optd.rs | 21 ++- optd-datafusion-repr/src/cost/base_cost.rs | 5 + optd-datafusion-repr/src/plan_nodes.rs | 15 +- optd-datafusion-repr/src/plan_nodes/limit.rs | 27 ++++ optd-datafusion-repr/src/rules/physical.rs | 10 ++ .../tests/basic_nodes.planner.sql | 32 ++++ optd-sqlplannertest/tests/basic_nodes.yml | 15 ++ 9 files changed, 233 insertions(+), 74 deletions(-) create mode 100644 optd-datafusion-repr/src/plan_nodes/limit.rs create mode 100644 optd-sqlplannertest/tests/basic_nodes.planner.sql create mode 100644 optd-sqlplannertest/tests/basic_nodes.yml diff --git a/Cargo.lock b/Cargo.lock index 81b3cd03..8364cecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,9 +396,9 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -407,9 +407,9 @@ version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -956,8 +956,8 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", ] @@ -1117,8 +1117,8 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ - "quote 1.0.33", - "syn 2.0.43", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -1654,9 +1654,9 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2723,9 +2723,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2802,8 +2802,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", "version_check", ] @@ -2814,8 +2814,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "version_check", ] @@ -2830,9 +2830,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2864,11 +2864,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.71", + "proc-macro2 1.0.78", ] [[package]] @@ -3068,8 +3068,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" dependencies = [ "cfg-if", - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "rustc_version", "syn 1.0.109", "unicode-ident", @@ -3264,22 +3264,22 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3382,8 +3382,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" dependencies = [ "heck", - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", ] @@ -3431,8 +3431,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55fe75cb4a364c7f7ae06c7dbbc8d84bddd85d6cdf9975963c3935bc1991761e" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", ] @@ -3487,10 +3487,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "rustversion", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -3516,19 +3516,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "unicode-ident", ] @@ -3602,9 +3602,9 @@ version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3713,9 +3713,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3810,9 +3810,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3881,9 +3881,9 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f03ca4cb38206e2bef0700092660bb74d696f808514dae47fa1467cbfe26e96e" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -4053,9 +4053,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -4077,7 +4077,7 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ - "quote 1.0.33", + "quote 1.0.35", "wasm-bindgen-macro-support", ] @@ -4087,9 +4087,9 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4417,9 +4417,9 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.71", - "quote 1.0.33", - "syn 2.0.43", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] diff --git a/optd-datafusion-bridge/src/from_optd.rs b/optd-datafusion-bridge/src/from_optd.rs index df521716..f61bc3ed 100644 --- a/optd-datafusion-bridge/src/from_optd.rs +++ b/optd-datafusion-bridge/src/from_optd.rs @@ -24,8 +24,9 @@ use optd_datafusion_repr::{ plan_nodes::{ BinOpExpr, BinOpType, ColumnRefExpr, ConstantExpr, ConstantType, Expr, FuncExpr, FuncType, JoinType, LogOpExpr, LogOpType, OptRelNode, OptRelNodeRef, OptRelNodeTyp, PhysicalAgg, - PhysicalEmptyRelation, PhysicalFilter, PhysicalHashJoin, PhysicalNestedLoopJoin, - PhysicalProjection, PhysicalScan, PhysicalSort, PlanNode, SortOrderExpr, SortOrderType, + PhysicalEmptyRelation, PhysicalFilter, PhysicalHashJoin, PhysicalLimit, + PhysicalNestedLoopJoin, PhysicalProjection, PhysicalScan, PhysicalSort, PlanNode, + SortOrderExpr, SortOrderType, }, properties::schema::Schema as OptdSchema, PhysicalCollector, @@ -271,6 +272,41 @@ impl OptdPlanContext<'_> { ) } + #[async_recursion] + async fn conv_from_optd_limit( + &mut self, + node: PhysicalLimit, + ) -> Result> { + let child = self.conv_from_optd_plan_node(node.child()).await?; + + // Limit skip/fetch expressions are only allowed to be constant int + assert!(node.skip().typ() == OptRelNodeTyp::Constant(ConstantType::UInt64)); + // Conversion from u64 -> usize could fail (also the case in into_optd) + let skip = ConstantExpr::from_rel_node(node.skip().into_rel_node()) + .unwrap() + .value() + .as_u64() + .try_into() + .unwrap(); + + assert!(node.fetch().typ() == OptRelNodeTyp::Constant(ConstantType::UInt64)); + let fetch = ConstantExpr::from_rel_node(node.fetch().into_rel_node()) + .unwrap() + .value() + .as_u64(); + let fetch_opt: Option = if fetch == u64::MAX { + None + } else { + Some(fetch.try_into().unwrap()) + }; + + Ok( + Arc::new(datafusion::physical_plan::limit::GlobalLimitExec::new( + child, skip, fetch_opt, + )) as Arc, + ) + } + #[async_recursion] async fn conv_from_optd_sort( &mut self, @@ -493,6 +529,10 @@ impl OptdPlanContext<'_> { Arc::new(datafusion_schema), )) as Arc) } + OptRelNodeTyp::PhysicalLimit => { + self.conv_from_optd_limit(PhysicalLimit::from_rel_node(rel_node).unwrap()) + .await + } typ => unimplemented!("{}", typ), }; result.with_context(|| format!("when processing {}", rel_node_dbg)) diff --git a/optd-datafusion-bridge/src/into_optd.rs b/optd-datafusion-bridge/src/into_optd.rs index 59896a41..a708b61d 100644 --- a/optd-datafusion-bridge/src/into_optd.rs +++ b/optd-datafusion-bridge/src/into_optd.rs @@ -9,8 +9,8 @@ use optd_core::rel_node::RelNode; use optd_datafusion_repr::plan_nodes::{ BinOpExpr, BinOpType, ColumnRefExpr, ConstantExpr, Expr, ExprList, FuncExpr, FuncType, JoinType, LogOpExpr, LogOpType, LogicalAgg, LogicalEmptyRelation, LogicalFilter, LogicalJoin, - LogicalProjection, LogicalScan, LogicalSort, OptRelNode, OptRelNodeRef, OptRelNodeTyp, - PlanNode, SortOrderExpr, SortOrderType, + LogicalLimit, LogicalProjection, LogicalScan, LogicalSort, OptRelNode, OptRelNodeRef, + OptRelNodeTyp, PlanNode, SortOrderExpr, SortOrderType, }; use crate::OptdPlanContext; @@ -301,6 +301,22 @@ impl OptdPlanContext<'_> { Ok(LogicalEmptyRelation::new(node.produce_one_row)) } + fn conv_into_optd_limit(&mut self, node: &logical_plan::Limit) -> Result { + let input = self.conv_into_optd_plan_node(node.input.as_ref())?; + // try_into guys are converting usize to u64. + let converted_skip = node.skip.try_into().unwrap(); + let converted_fetch = if let Some(x) = node.fetch { + x.try_into().unwrap() + } else { + u64::MAX // u64 MAX represents infinity (not the best way to do this) + }; + Ok(LogicalLimit::new( + input, + ConstantExpr::uint64(converted_skip).into_expr(), + ConstantExpr::uint64(converted_fetch).into_expr(), + )) + } + fn conv_into_optd_plan_node(&mut self, node: &LogicalPlan) -> Result { let node = match node { LogicalPlan::TableScan(node) => self.conv_into_optd_table_scan(node)?.into_plan_node(), @@ -316,6 +332,7 @@ impl OptdPlanContext<'_> { LogicalPlan::EmptyRelation(node) => { self.conv_into_optd_empty_relation(node)?.into_plan_node() } + LogicalPlan::Limit(node) => self.conv_into_optd_limit(node)?.into_plan_node(), _ => bail!( "unsupported plan node: {}", format!("{:?}", node).split('\n').next().unwrap() diff --git a/optd-datafusion-repr/src/cost/base_cost.rs b/optd-datafusion-repr/src/cost/base_cost.rs index a5ab4342..f5a8bb91 100644 --- a/optd-datafusion-repr/src/cost/base_cost.rs +++ b/optd-datafusion-repr/src/cost/base_cost.rs @@ -107,6 +107,11 @@ impl CostModel for OptCostModel { Self::cost(row_cnt, 0.0, row_cnt) } OptRelNodeTyp::PhysicalEmptyRelation => Self::cost(0.5, 0.01, 0.0), + OptRelNodeTyp::PhysicalLimit => { + let (row_cnt, compute_cost, _) = Self::cost_tuple(&children[0]); + let selectivity = 0.001; + Self::cost((row_cnt * selectivity).max(1.0), compute_cost, 0.0) + } OptRelNodeTyp::PhysicalFilter => { let (row_cnt, _, _) = Self::cost_tuple(&children[0]); let (_, compute_cost, _) = Self::cost_tuple(&children[1]); diff --git a/optd-datafusion-repr/src/plan_nodes.rs b/optd-datafusion-repr/src/plan_nodes.rs index f47fe342..04ccafbe 100644 --- a/optd-datafusion-repr/src/plan_nodes.rs +++ b/optd-datafusion-repr/src/plan_nodes.rs @@ -6,6 +6,7 @@ mod empty_relation; mod expr; mod filter; mod join; +mod limit; pub(super) mod macros; mod projection; mod scan; @@ -27,6 +28,7 @@ pub use expr::{ }; pub use filter::{LogicalFilter, PhysicalFilter}; pub use join::{JoinType, LogicalJoin, PhysicalHashJoin, PhysicalNestedLoopJoin}; +pub use limit::{LogicalLimit, PhysicalLimit}; use pretty_xmlish::{Pretty, PrettyConfig}; pub use projection::{LogicalProjection, PhysicalProjection}; pub use scan::{LogicalScan, PhysicalScan}; @@ -51,6 +53,7 @@ pub enum OptRelNodeTyp { Agg, Apply(ApplyType), EmptyRelation, + Limit, // Physical plan nodes PhysicalProjection, PhysicalFilter, @@ -60,6 +63,7 @@ pub enum OptRelNodeTyp { PhysicalHashJoin(JoinType), PhysicalNestedLoopJoin(JoinType), PhysicalEmptyRelation, + PhysicalLimit, PhysicalCollector(GroupId), // only produced after optimization is done // Expressions Constant(ConstantType), @@ -83,6 +87,7 @@ impl OptRelNodeTyp { | Self::Sort | Self::Agg | Self::EmptyRelation + | Self::Limit | Self::PhysicalProjection | Self::PhysicalFilter | Self::PhysicalNestedLoopJoin(_) @@ -91,6 +96,7 @@ impl OptRelNodeTyp { | Self::PhysicalAgg | Self::PhysicalHashJoin(_) | Self::PhysicalCollector(_) + | Self::PhysicalLimit | Self::PhysicalEmptyRelation ) } @@ -127,6 +133,7 @@ impl RelNodeTyp for OptRelNodeTyp { | Self::Sort | Self::Agg | Self::EmptyRelation + | Self::Limit ) } @@ -310,6 +317,9 @@ pub fn explain(rel_node: OptRelNodeRef) -> Pretty<'static> { OptRelNodeTyp::EmptyRelation => LogicalEmptyRelation::from_rel_node(rel_node) .unwrap() .dispatch_explain(), + OptRelNodeTyp::Limit => LogicalLimit::from_rel_node(rel_node) + .unwrap() + .dispatch_explain(), OptRelNodeTyp::PhysicalFilter => PhysicalFilter::from_rel_node(rel_node) .unwrap() .dispatch_explain(), @@ -352,12 +362,15 @@ pub fn explain(rel_node: OptRelNodeRef) -> Pretty<'static> { OptRelNodeTyp::LogOp(_) => LogOpExpr::from_rel_node(rel_node) .unwrap() .dispatch_explain(), - OptRelNodeTyp::PhysicalCollector(_group_id) => PhysicalCollector::from_rel_node(rel_node) + OptRelNodeTyp::PhysicalCollector(_) => PhysicalCollector::from_rel_node(rel_node) .unwrap() .dispatch_explain(), OptRelNodeTyp::PhysicalEmptyRelation => PhysicalEmptyRelation::from_rel_node(rel_node) .unwrap() .dispatch_explain(), + OptRelNodeTyp::PhysicalLimit => PhysicalLimit::from_rel_node(rel_node) + .unwrap() + .dispatch_explain(), } } diff --git a/optd-datafusion-repr/src/plan_nodes/limit.rs b/optd-datafusion-repr/src/plan_nodes/limit.rs new file mode 100644 index 00000000..9546e338 --- /dev/null +++ b/optd-datafusion-repr/src/plan_nodes/limit.rs @@ -0,0 +1,27 @@ +use super::{macros::define_plan_node, Expr, OptRelNode, OptRelNodeRef, OptRelNodeTyp, PlanNode}; + +#[derive(Clone, Debug)] +pub struct LogicalLimit(pub PlanNode); + +define_plan_node!( + LogicalLimit : PlanNode, + Limit, [ + { 0, child: PlanNode } + ], [ + { 1, skip: Expr }, + { 2, fetch: Expr } + ] +); + +#[derive(Clone, Debug)] +pub struct PhysicalLimit(pub PlanNode); + +define_plan_node!( + PhysicalLimit : PlanNode, + PhysicalLimit, [ + { 0, child: PlanNode } + ], [ + { 1, skip: Expr }, + { 2, fetch: Expr } + ] +); diff --git a/optd-datafusion-repr/src/rules/physical.rs b/optd-datafusion-repr/src/rules/physical.rs index c038f3fa..5c69baf5 100644 --- a/optd-datafusion-repr/src/rules/physical.rs +++ b/optd-datafusion-repr/src/rules/physical.rs @@ -25,6 +25,7 @@ impl PhysicalConversionRule { impl PhysicalConversionRule { pub fn all_conversions>() -> Vec>> { + // Define conversions below, and add them to this list! vec![ Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::Scan)), Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::Projection)), @@ -41,6 +42,7 @@ impl PhysicalConversionRule { Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::Sort)), Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::Agg)), Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::EmptyRelation)), + Arc::new(PhysicalConversionRule::new(OptRelNodeTyp::Limit)), ] } } @@ -126,6 +128,14 @@ impl> Rule for PhysicalConversionR }; vec![node] } + OptRelNodeTyp::Limit => { + let node = RelNode { + typ: OptRelNodeTyp::PhysicalLimit, + children, + data, + }; + vec![node] + } _ => vec![], } } diff --git a/optd-sqlplannertest/tests/basic_nodes.planner.sql b/optd-sqlplannertest/tests/basic_nodes.planner.sql new file mode 100644 index 00000000..32771db9 --- /dev/null +++ b/optd-sqlplannertest/tests/basic_nodes.planner.sql @@ -0,0 +1,32 @@ +-- (no id or description) +create table t1(t1v1 int, t1v2 int); +create table t2(t2v1 int, t2v3 int); +insert into t1 values (0, 0), (1, 1), (2, 2); +insert into t2 values (0, 200), (1, 201), (2, 202); + +/* +3 +3 +*/ + +-- Test limit nodes +select * from t1 limit 1; +select * from t1 limit 3; +select * from t1 limit 5; + +/* +LogicalLimit { skip: 0, fetch: 1 } +└── LogicalProjection { exprs: [ #0, #1 ] } + └── LogicalScan { table: t1 } +PhysicalLimit { skip: 0, fetch: 1 } +└── PhysicalProjection { exprs: [ #0, #1 ] } + └── PhysicalScan { table: t1 } +0 0 +0 0 +1 1 +2 2 +0 0 +1 1 +2 2 +*/ + diff --git a/optd-sqlplannertest/tests/basic_nodes.yml b/optd-sqlplannertest/tests/basic_nodes.yml new file mode 100644 index 00000000..63a64141 --- /dev/null +++ b/optd-sqlplannertest/tests/basic_nodes.yml @@ -0,0 +1,15 @@ +- sql: | + create table t1(t1v1 int, t1v2 int); + create table t2(t2v1 int, t2v3 int); + insert into t1 values (0, 0), (1, 1), (2, 2); + insert into t2 values (0, 200), (1, 201), (2, 202); + tasks: + - execute +- sql: | + select * from t1 limit 1; + select * from t1 limit 3; + select * from t1 limit 5; + desc: Test limit nodes + tasks: + - explain:logical_optd,physical_optd + - execute \ No newline at end of file