diff --git a/Cargo.lock b/Cargo.lock index 78ee3a13fe687..f8380607cab29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3341,10 +3341,10 @@ dependencies = [ "percent-encoding", "pratt", "pretty_assertions", - "recursive", "rspack-codespan-reporting", "serde", "serde_json", + "stacksafe", "strsim 0.10.0", "strum 0.24.1", "strum_macros 0.24.3", @@ -3656,12 +3656,12 @@ dependencies = [ "proptest", "rand 0.8.5", "rand_distr", - "recursive", "roaring", "rust_decimal", "rustls 0.23.27", "serde", "serde_json", + "stacksafe", "strength_reduce", "terminal_size", "tonic 0.13.1", @@ -4488,7 +4488,6 @@ dependencies = [ "opendal", "parking_lot 0.12.3", "prqlc", - "recursive", "regex", "roaring", "serde", @@ -4496,6 +4495,7 @@ dependencies = [ "sha2", "similar", "simsearch", + "stacksafe", "tantivy-query-grammar", "unicase", "url", @@ -4717,8 +4717,8 @@ dependencies = [ "log", "opendal", "parquet 56.2.0", - "recursive", "serde", + "stacksafe", "typetag", "volo-thrift", ] @@ -5588,7 +5588,6 @@ dependencies = [ "proptest", "prost", "rand 0.8.5", - "recursive", "redis", "regex", "reqwest", @@ -5603,6 +5602,7 @@ dependencies = [ "sha2", "socket2 0.5.9", "sqlx", + "stacksafe", "sysinfo", "tantivy", "temp-env", @@ -5635,13 +5635,13 @@ dependencies = [ "futures-util", "mysql_async", "rand 0.8.5", - "recursive", "redis", "regex", "reqwest", "serde", "serde_json", "sqllogictest", + "stacksafe", "testcontainers", "testcontainers-modules", "thiserror 1.0.69", @@ -13199,7 +13199,8 @@ dependencies = [ [[package]] name = "recursive" version = "0.1.1" -source = "git+https://github.com/datafuse-extras/recursive.git?rev=16e433a#16e433ab3f291512b437206f7ce7b8d078e84195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0786a43debb760f491b1bc0269fe5e84155353c67482b9e60d0cfb596054b43e" dependencies = [ "recursive-proc-macro-impl", "stacker", @@ -13208,7 +13209,8 @@ dependencies = [ [[package]] name = "recursive-proc-macro-impl" version = "0.1.1" -source = "git+https://github.com/datafuse-extras/recursive.git?rev=16e433a#16e433ab3f291512b437206f7ce7b8d078e84195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", "syn 2.0.106", @@ -15032,6 +15034,27 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "stacksafe" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5481855df765c006135651b88e666edd4f08e176183052d2cb8628450873acb" +dependencies = [ + "stacker", + "stacksafe-macro", +] + +[[package]] +name = "stacksafe-macro" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4825bd5b513e9bc047a10ffc1680d1203ef548bdccd633d633a15630f01d126f" +dependencies = [ + "proc-macro-error2", + "quote", + "syn 2.0.106", +] + [[package]] name = "state" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index ef58215377668..58d7591eb3e54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -358,7 +358,6 @@ raft-log = { version = "0.2.11" } rand = { version = "0.8.5", features = ["small_rng", "serde1"] } rand_distr = "0.4.3" rayon = "1.9.0" -recursive = "0.1.1" redis = { version = "0.27.5", features = ["tokio-comp", "connection-manager"] } regex = "1.8.1" replace_with = "0.1.7" @@ -411,6 +410,7 @@ socket2 = "0.5.3" span-map = { version = "0.2.0" } sqlx = { version = "0.8", features = ["mysql", "runtime-tokio"] } stacker = "0.1" +stacksafe = "1" state = "0.6.0" state-machine-api = { version = "0.3.4" } stream-more = "0.1.3" @@ -575,7 +575,7 @@ jsonb = { git = "https://github.com/databendlabs/jsonb", rev = "1868abf" } map-api = { git = "https://github.com/databendlabs/map-api", tag = "v0.4.2" } openraft = { git = "https://github.com/databendlabs/openraft", tag = "v0.10.0-alpha.13" } orc-rust = { git = "https://github.com/datafuse-extras/orc-rust", rev = "fc812ad7010" } -recursive = { git = "https://github.com/datafuse-extras/recursive.git", rev = "16e433a" } + sled = { git = "https://github.com/datafuse-extras/sled", tag = "v0.34.7-datafuse.1" } state-machine-api = { git = "https://github.com/databendlabs/state-machine-api.git", tag = "v0.3.4" } sub-cache = { git = "https://github.com/databendlabs/sub-cache", tag = "v0.2.1" } diff --git a/src/binaries/query/entry.rs b/src/binaries/query/entry.rs index 3c11f30bb70af..3354a26b68117 100644 --- a/src/binaries/query/entry.rs +++ b/src/binaries/query/entry.rs @@ -46,9 +46,11 @@ use databend_query::servers::ShutdownHandle; use databend_query::servers::admin::AdminService; use databend_query::servers::flight::FlightService; use databend_query::servers::metrics::MetricService; -use databend_query::task::TaskService; +use databend_query::servers::task::TaskService; use log::info; +pub mod stack_management; + use super::cmd::Cmd; use super::cmd::Commands; @@ -72,15 +74,6 @@ pub async fn init_services(conf: &InnerConfig, ee_mode: bool) -> Result<(), Main let binary_version = DATABEND_COMMIT_VERSION.clone(); set_panic_hook(binary_version); set_alloc_error_hook(); - - #[cfg(target_arch = "x86_64")] - { - if !std::is_x86_feature_detected!("sse4.2") { - println!( - "Current pre-built binary is typically compiled for x86_64 and leverage SSE 4.2 instruction set, you can build your own binary from source" - ); - return Ok(()); - } } if conf.meta.is_embedded_meta().with_context(make_error)? { diff --git a/src/query/ast/Cargo.toml b/src/query/ast/Cargo.toml index 2fbab0490bed9..ded13a4e521c2 100644 --- a/src/query/ast/Cargo.toml +++ b/src/query/ast/Cargo.toml @@ -24,10 +24,10 @@ ordered-float = { workspace = true } percent-encoding = { workspace = true } pratt = { workspace = true } pretty_assertions = { workspace = true } -recursive = { workspace = true } rspack-codespan-reporting = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +stacksafe = { workspace = true } strsim = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } diff --git a/src/query/ast/src/ast/expr.rs b/src/query/ast/src/ast/expr.rs index fb5f907f523bb..1bc87efaaa476 100644 --- a/src/query/ast/src/ast/expr.rs +++ b/src/query/ast/src/ast/expr.rs @@ -37,12 +37,61 @@ use crate::ast::write_comma_separated_list; use crate::ast::write_dot_separated_list; use crate::span::merge_span; +/// Wrapper around StackSafe that implements Drive and DriveMut traits. +/// +/// This allows recursive data structures to use StackSafe while maintaining +/// compatibility with Databend's visitor pattern that requires Drive/DriveMut. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct StackWrapper(pub stacksafe::StackSafe); + +impl StackWrapper { + pub fn new(value: T) -> Self { + Self(stacksafe::StackSafe::new(value)) + } +} + +impl From for StackWrapper { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl std::ops::Deref for StackWrapper { + type Target = stacksafe::StackSafe; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for StackWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +// Implement Drive for StackWrapper if T implements Drive +impl Drive for StackWrapper { + #[stacksafe::stacksafe] + fn drive(&self, visitor: &mut V) { + visitor.visit(self, derive_visitor::Event::Enter); + (**self).drive(visitor); + visitor.visit(self, derive_visitor::Event::Exit); + } +} + +// Implement DriveMut for StackWrapper if T implements DriveMut +impl DriveMut for StackWrapper { + #[stacksafe::stacksafe] + fn drive_mut(&mut self, visitor: &mut V) { + visitor.visit_mut(self, derive_visitor::Event::Enter); + (**self).drive_mut(visitor); + visitor.visit_mut(self, derive_visitor::Event::Exit); + } +} + #[derive(Educe, Drive, DriveMut)] -#[educe( - PartialEq(bound = false, attrs = "#[recursive::recursive]"), - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") -)] +#[educe(PartialEq(bound = false), Clone(bound = false), Debug(bound = false))] pub enum Expr { /// Column reference, with indirection like `table.column` ColumnRef { @@ -52,127 +101,127 @@ pub enum Expr { /// `IS [ NOT ] NULL` expression IsNull { span: Span, - expr: Box, + expr: StackWrapper>, not: bool, }, /// `IS [NOT] DISTINCT` expression IsDistinctFrom { span: Span, - left: Box, - right: Box, + left: StackWrapper>, + right: StackWrapper>, not: bool, }, /// `[ NOT ] IN (expr, ...)` InList { span: Span, - expr: Box, + expr: StackWrapper>, list: Vec, not: bool, }, /// `[ NOT ] IN (SELECT ...)` InSubquery { span: Span, - expr: Box, - subquery: Box, + expr: StackWrapper>, + subquery: StackWrapper>, not: bool, }, /// `LIKE (SELECT ...) [ESCAPE '']` LikeSubquery { span: Span, - expr: Box, - subquery: Box, + expr: StackWrapper>, + subquery: StackWrapper>, modifier: SubqueryModifier, escape: Option, }, /// ` LIKE ANY ESCAPE ''` LikeAnyWithEscape { span: Span, - left: Box, - right: Box, + left: StackWrapper>, + right: StackWrapper>, escape: String, }, /// ` [NOT] LIKE ESCAPE ''` LikeWithEscape { span: Span, - left: Box, - right: Box, + left: StackWrapper>, + right: StackWrapper>, is_not: bool, escape: String, }, /// `BETWEEN ... AND ...` Between { span: Span, - expr: Box, - low: Box, - high: Box, + expr: StackWrapper>, + low: StackWrapper>, + high: StackWrapper>, not: bool, }, /// Binary operation BinaryOp { span: Span, op: BinaryOperator, - left: Box, - right: Box, + left: StackWrapper>, + right: StackWrapper>, }, /// JSON operation JsonOp { span: Span, op: JsonOperator, - left: Box, - right: Box, + left: StackWrapper>, + right: StackWrapper>, }, /// Unary operation UnaryOp { span: Span, op: UnaryOperator, - expr: Box, + expr: StackWrapper>, }, /// `CAST` expression, like `CAST(expr AS target_type)` Cast { span: Span, - expr: Box, + expr: StackWrapper>, target_type: TypeName, pg_style: bool, }, /// `TRY_CAST` expression` TryCast { span: Span, - expr: Box, + expr: StackWrapper>, target_type: TypeName, }, /// EXTRACT(IntervalKind FROM ) Extract { span: Span, kind: IntervalKind, - expr: Box, + expr: StackWrapper>, }, /// DATE_PART(IntervalKind, ) DatePart { span: Span, kind: IntervalKind, - expr: Box, + expr: StackWrapper>, }, /// POSITION( IN ) Position { span: Span, - substr_expr: Box, - str_expr: Box, + substr_expr: StackWrapper>, + str_expr: StackWrapper>, }, /// SUBSTRING( [FROM ] [FOR ]) Substring { span: Span, - expr: Box, - substring_from: Box, - substring_for: Option>, + expr: StackWrapper>, + substring_from: StackWrapper>, + substring_for: Option>>, }, /// TRIM([[BOTH | LEADING | TRAILING] FROM] ) /// Or /// TRIM() Trim { span: Span, - expr: Box, + expr: StackWrapper>, // ([BOTH | LEADING | TRAILING], ) - trim_where: Option<(TrimWhere, Box)>, + trim_where: Option<(TrimWhere, StackWrapper>)>, }, /// A literal value, such as string, number, date or NULL Literal { @@ -198,28 +247,28 @@ pub enum Expr { /// `CASE ... WHEN ... ELSE ...` expression Case { span: Span, - operand: Option>, + operand: Option>>, conditions: Vec, results: Vec, - else_result: Option>, + else_result: Option>>, }, /// `EXISTS` expression Exists { span: Span, /// Indicate if this is a `NOT EXISTS` not: bool, - subquery: Box, + subquery: StackWrapper>, }, /// Scalar/ANY/ALL/SOME subquery Subquery { span: Span, modifier: Option, - subquery: Box, + subquery: StackWrapper>, }, /// Access elements of `Array`, `Map` and `Variant` by index or key, like `arr[0]`, or `obj:k1` MapAccess { span: Span, - expr: Box, + expr: StackWrapper>, accessor: MapAccessor, }, /// The `Array` expr @@ -235,41 +284,41 @@ pub enum Expr { /// The `Interval 1 DAY` expr Interval { span: Span, - expr: Box, + expr: StackWrapper>, unit: IntervalKind, }, DateAdd { span: Span, unit: IntervalKind, - interval: Box, - date: Box, + interval: StackWrapper>, + date: StackWrapper>, }, DateDiff { span: Span, unit: IntervalKind, - date_start: Box, - date_end: Box, + date_start: StackWrapper>, + date_end: StackWrapper>, }, DateBetween { span: Span, unit: IntervalKind, - date_start: Box, - date_end: Box, + date_start: StackWrapper>, + date_end: StackWrapper>, }, DateSub { span: Span, unit: IntervalKind, - interval: Box, - date: Box, + interval: StackWrapper>, + date: StackWrapper>, }, DateTrunc { span: Span, unit: IntervalKind, - date: Box, + date: StackWrapper>, }, TimeSlice { span: Span, - date: Box, + date: StackWrapper>, slice_length: u64, unit: IntervalKind, start_or_end: String, @@ -277,17 +326,17 @@ pub enum Expr { LastDay { span: Span, unit: IntervalKind, - date: Box, + date: StackWrapper>, }, PreviousDay { span: Span, unit: Weekday, - date: Box, + date: StackWrapper>, }, NextDay { span: Span, unit: Weekday, - date: Box, + date: StackWrapper>, }, Hole { span: Span, @@ -571,7 +620,7 @@ impl Display for Expr { false } - #[recursive::recursive] + #[stacksafe::stacksafe] fn write_expr( expr: &Expr, parent: Option, @@ -1165,7 +1214,7 @@ impl Display for FunctionCall { #[derive(Debug, Clone, PartialEq, Drive, DriveMut)] pub enum MapAccessor { /// `[0][1]` - Bracket { key: Box }, + Bracket { key: StackWrapper> }, /// `.1` DotNumber { key: u64 }, /// `:a:b` @@ -1507,15 +1556,15 @@ pub enum WindowFrameBound { /// `CURRENT ROW` CurrentRow, /// ` PRECEDING` or `UNBOUNDED PRECEDING` - Preceding(Option>), + Preceding(Option>>), /// ` FOLLOWING` or `UNBOUNDED FOLLOWING`. - Following(Option>), + Following(Option>>), } #[derive(Debug, Clone, PartialEq, Drive, DriveMut)] pub struct Lambda { pub params: Vec, - pub expr: Box, + pub expr: StackWrapper>, } impl Display for Lambda { diff --git a/src/query/ast/src/ast/query.rs b/src/query/ast/src/ast/query.rs index 2825d55cec715..e2c35ce11a33c 100644 --- a/src/query/ast/src/ast/query.rs +++ b/src/query/ast/src/ast/query.rs @@ -24,6 +24,65 @@ use crate::ParseError; use crate::Result; use crate::Span; use crate::ast::Expr; + +/// Wrapper around StackSafe that implements Drive and DriveMut traits. +/// +/// This allows recursive data structures to use StackSafe while maintaining +/// compatibility with Databend's visitor pattern that requires Drive/DriveMut. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct StackWrapper(pub stacksafe::StackSafe); + +impl StackWrapper { + pub fn new(value: T) -> Self { + Self(stacksafe::StackSafe::new(value)) + } +} + +impl From for StackWrapper { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl std::ops::Deref for StackWrapper { + type Target = stacksafe::StackSafe; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for StackWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +// Implement Drive for StackWrapper if T implements Drive +impl derive_visitor::Drive for StackWrapper { + #[stacksafe::stacksafe] + fn drive(&self, visitor: &mut V) { + visitor.visit(self, derive_visitor::Event::Enter); + (**self).drive(visitor); + visitor.visit(self, derive_visitor::Event::Exit); + } +} + +// Implement DriveMut for StackWrapper if T implements DriveMut +impl derive_visitor::DriveMut for StackWrapper { + #[stacksafe::stacksafe] + fn drive_mut(&mut self, visitor: &mut V) { + visitor.visit_mut(self, derive_visitor::Event::Enter); + (**self).drive_mut(visitor); + visitor.visit_mut(self, derive_visitor::Event::Exit); + } +} + +impl std::fmt::Display for StackWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + (**self).fmt(f) + } +} use crate::ast::FileLocation; use crate::ast::Hint; use crate::ast::Identifier; @@ -100,7 +159,7 @@ pub struct With { } impl Display for With { - #[recursive::recursive] + #[stacksafe::stacksafe] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { if self.recursive { write!(f, "RECURSIVE ")?; @@ -117,11 +176,11 @@ pub struct CTE { pub alias: TableAlias, pub user_specified_materialized: bool, pub materialized: bool, - pub query: Box, + pub query: StackWrapper>, } impl Display for CTE { - #[recursive::recursive] + #[stacksafe::stacksafe] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "{} AS ", self.alias)?; if self.user_specified_materialized { @@ -134,9 +193,9 @@ impl Display for CTE { #[derive(Educe, Drive, DriveMut)] #[educe( - PartialEq(bound = false, attrs = "#[recursive::recursive]"), - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") + PartialEq(bound = false, attrs = "#[stacksafe::stacksafe]"), + Clone(bound = false, attrs = "#[stacksafe::stacksafe]"), + Debug(bound = false, attrs = "#[stacksafe::stacksafe]") )] pub struct SetOperation { pub span: Span, @@ -294,13 +353,13 @@ impl Display for GroupBy { /// A relational set expression, like `SELECT ... FROM ... {UNION|EXCEPT|INTERSECT} SELECT ... FROM ...` #[derive(Educe, Drive, DriveMut)] #[educe( - PartialEq(bound = false, attrs = "#[recursive::recursive]"), - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") + PartialEq(bound = false, attrs = "#[stacksafe::stacksafe]"), + Clone(bound = false, attrs = "#[stacksafe::stacksafe]"), + Debug(bound = false, attrs = "#[stacksafe::stacksafe]") )] pub enum SetExpr { Select(Box), - Query(Box), + Query(StackWrapper>), // UNION/EXCEPT/INTERSECT operator SetOperation(Box), // Values clause @@ -308,7 +367,7 @@ pub enum SetExpr { } impl Display for SetExpr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { match self { SetExpr::Select(select_stmt) => { @@ -614,7 +673,7 @@ impl Display for TimeTravelPoint { #[derive(Debug, Clone, PartialEq, Drive, DriveMut)] pub enum PivotValues { ColumnValues(Vec), - Subquery(Box), + Subquery(StackWrapper>), Any { order_by: Option> }, } @@ -877,7 +936,7 @@ pub enum TableReference { span: Span, /// Whether the subquery is a lateral subquery lateral: bool, - subquery: Box, + subquery: StackWrapper>, alias: Option, pivot: Option>, unpivot: Option>, @@ -927,7 +986,7 @@ impl TableReference { } impl Display for TableReference { - #[recursive::recursive] + #[stacksafe::stacksafe] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { match self { TableReference::Table { diff --git a/src/query/ast/src/parser/script.rs b/src/query/ast/src/parser/script.rs index 4506f655ded46..f0cc5c3753b95 100644 --- a/src/query/ast/src/parser/script.rs +++ b/src/query/ast/src/parser/script.rs @@ -158,7 +158,7 @@ pub fn script_stmts(i: Input) -> IResult> { semicolon_terminated_list1(script_stmt).parse(i) } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn script_stmt(i: Input) -> IResult { if let Some(token) = i.tokens.first() { let kind = token.kind; diff --git a/src/query/ast/src/parser/statement.rs b/src/query/ast/src/parser/statement.rs index 6d5f642f09b0d..dc9a7b6aedf7f 100644 --- a/src/query/ast/src/parser/statement.rs +++ b/src/query/ast/src/parser/statement.rs @@ -4466,7 +4466,7 @@ pub fn alter_database_action(i: Input) -> IResult { pub fn modify_column_type(i: Input) -> IResult { #[derive(Educe)] - #[educe(Clone(bound = false, attrs = "#[recursive::recursive]"))] + #[educe(Clone(bound = false, attrs = "#[stacksafe::stacksafe]"))] enum ColumnConstraint { Nullable(bool), DefaultExpr(Box), diff --git a/src/query/expression/Cargo.toml b/src/query/expression/Cargo.toml index f5bfe1178f388..e4822efd0365f 100644 --- a/src/query/expression/Cargo.toml +++ b/src/query/expression/Cargo.toml @@ -52,11 +52,11 @@ num-bigint = { workspace = true } num-traits = { workspace = true } rand = { workspace = true } rand_distr = { workspace = true } -recursive = { workspace = true } rust_decimal = { workspace = true } rustls = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +stacksafe = { workspace = true } strength_reduce = { workspace = true } terminal_size = { workspace = true } tonic = { workspace = true } diff --git a/src/query/expression/src/constant_folder.rs b/src/query/expression/src/constant_folder.rs index 2b278d9d9393b..ad5141fabccbf 100644 --- a/src/query/expression/src/constant_folder.rs +++ b/src/query/expression/src/constant_folder.rs @@ -119,7 +119,7 @@ impl<'a, Index: ColumnIndex> ConstantFolder<'a, Index> { /// Fold expression by one step, specifically, by reducing expression by domain calculation and then /// folding the function calls whose all arguments are constants. - #[recursive::recursive] + #[stacksafe::stacksafe] fn fold_once(&self, expr: &Expr) -> (Expr, Option) { let (new_expr, domain) = match expr { Expr::Constant(Constant { diff --git a/src/query/expression/src/expression.rs b/src/query/expression/src/expression.rs index 464057f7a4d94..65f2331b0c459 100644 --- a/src/query/expression/src/expression.rs +++ b/src/query/expression/src/expression.rs @@ -200,7 +200,7 @@ impl From> for Expr { } impl Clone for Expr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn clone(&self) -> Self { match self { Expr::Constant(x) => x.clone().into(), @@ -253,7 +253,7 @@ impl Clone for Expr { impl Eq for Expr {} impl PartialEq for Expr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn eq(&self, other: &Self) -> bool { match (self, other) { ( @@ -471,7 +471,7 @@ pub trait ExprVisitor: Sized { } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn visit_expr>( expr: &Expr, visitor: &mut V, @@ -536,7 +536,7 @@ pub enum RemoteExpr { impl RawExpr { pub fn column_refs(&self) -> HashMap { - #[recursive::recursive] + #[stacksafe::stacksafe] fn walk(expr: &RawExpr, buf: &mut HashMap) { match expr { RawExpr::ColumnRef { id, data_type, .. } => { @@ -667,7 +667,7 @@ impl Expr { visitor.0 } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn project_column_ref( &self, col_index_mapper: impl Fn(&Index) -> databend_common_exception::Result + Copy, diff --git a/src/query/expression/src/type_check.rs b/src/query/expression/src/type_check.rs index cee156b29d065..15bbb76b0e215 100755 --- a/src/query/expression/src/type_check.rs +++ b/src/query/expression/src/type_check.rs @@ -41,7 +41,7 @@ use crate::types::decimal::DecimalSize; use crate::types::i256; use crate::visit_expr; -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn check( expr: &RawExpr, fn_registry: &FunctionRegistry, @@ -203,7 +203,7 @@ pub fn check_cast( } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn wrap_nullable_for_try_cast(span: Span, ty: &DataType) -> Result { match ty { DataType::Null => Err(ErrorCode::from_string_no_backtrace( @@ -296,7 +296,7 @@ pub fn check_number( } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn check_function( span: Span, name: &str, diff --git a/src/query/expression/src/utils/display.rs b/src/query/expression/src/utils/display.rs index 6a649b3ed8379..c0617efe18a5f 100755 --- a/src/query/expression/src/utils/display.rs +++ b/src/query/expression/src/utils/display.rs @@ -983,7 +983,7 @@ impl Expr { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn write_expr(expr: &Expr, min_precedence: usize) -> String { match expr { Expr::Constant(Constant { scalar, .. }) => match scalar { diff --git a/src/query/service/Cargo.toml b/src/query/service/Cargo.toml index 25025e79d2f7d..5464bce0ed995 100644 --- a/src/query/service/Cargo.toml +++ b/src/query/service/Cargo.toml @@ -150,7 +150,6 @@ poem = { workspace = true } prometheus-client = { workspace = true } prost = { workspace = true } rand = { workspace = true } -recursive = { workspace = true } redis = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } @@ -164,6 +163,7 @@ serde_urlencoded = { workspace = true } sha2 = { workspace = true } socket2 = { workspace = true } sqlx = { workspace = true } +stacksafe = { workspace = true } sysinfo = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true } diff --git a/src/query/service/src/global_services.rs b/src/query/service/src/global_services.rs index 6447ff00a19ff..6d9e67c0814a9 100644 --- a/src/query/service/src/global_services.rs +++ b/src/query/service/src/global_services.rs @@ -76,6 +76,10 @@ impl GlobalServices { version: BuildInfoRef, ee_mode: bool, ) -> Result<()> { + // Initialize custom stack management for StackSafe crate + // This must be called before any recursive operations + crate::init_stack_management(); + StackTrace::pre_load_symbol(); // app name format: node_id[0..7]@cluster_id diff --git a/src/query/service/src/interpreters/access_log/access_logger.rs b/src/query/service/src/interpreters/access_log/access_logger.rs index 503dc0257f39f..d4b87dc34945c 100644 --- a/src/query/service/src/interpreters/access_log/access_logger.rs +++ b/src/query/service/src/interpreters/access_log/access_logger.rs @@ -51,7 +51,7 @@ impl AccessLogger { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn log(&mut self, plan: &Plan) { match plan { // DQL Operations diff --git a/src/query/service/src/lib.rs b/src/query/service/src/lib.rs index 88d51d9171d46..226c1e2f4d824 100644 --- a/src/query/service/src/lib.rs +++ b/src/query/service/src/lib.rs @@ -78,3 +78,48 @@ pub use databend_common_storages_factory as storages; pub use global_services::GlobalServices; pub use table_functions::get_fuse_table_snapshot; pub use table_functions::get_fuse_table_statistics; + +/// Initialize custom stack management for StackSafe crate. +/// +/// Stack size configuration: +/// - Debug mode: Uses larger stack sizes (10x) to catch stack overflow issues early +/// - Release mode: Uses normal stack sizes for production +/// +/// Default StackSafe thresholds: +/// - Red zone: 128 KiB +/// - Stack allocation: 2 MiB +/// +/// Our custom settings: +/// - Debug: 2.5 MiB red zone, 20 MiB allocation (10x default) +/// - Release: 256 KiB red zone, 2 MiB allocation (same as default) +pub fn init_stack_management() { + use std::sync::atomic::AtomicUsize; + + // The stack in debugging mode is 10x than in release + #[cfg(debug_assertions)] + let minimum_stack_size = AtomicUsize::new(256 * 1024 * 10); // 2.5 MiB for debug + #[cfg(debug_assertions)] + let stack_alloc_size = AtomicUsize::new(2 * 1024 * 1024 * 10); // 20 MiB for debug + + #[cfg(not(debug_assertions))] + let minimum_stack_size = AtomicUsize::new(256 * 1024); // 256 KiB for release + #[cfg(not(debug_assertions))] + let stack_alloc_size = AtomicUsize::new(2 * 1024 * 1024); // 2 MiB for release + + stacksafe::set_minimum_stack_size(minimum_stack_size); + stacksafe::set_stack_allocation_size(stack_alloc_size); + + #[cfg(debug_assertions)] + log::info!( + "StackSafe configured for debug: minimum_stack_size={} KiB, stack_alloc_size={} MiB", + minimum_stack_size.load(std::sync::atomic::Ordering::Relaxed) / 1024, + stack_alloc_size.load(std::sync::atomic::Ordering::Relaxed) / (1024 * 1024) + ); + + #[cfg(not(debug_assertions))] + log::info!( + "StackSafe configured for release: minimum_stack_size={} KiB, stack_alloc_size={} MiB", + minimum_stack_size.load(std::sync::atomic::Ordering::Relaxed) / 1024, + stack_alloc_size.load(std::sync::atomic::Ordering::Relaxed) / (1024 * 1024) + ); +} diff --git a/src/query/service/src/physical_plans/format/common.rs b/src/query/service/src/physical_plans/format/common.rs index 885e5a92217a2..fb4b4276acd31 100644 --- a/src/query/service/src/physical_plans/format/common.rs +++ b/src/query/service/src/physical_plans/format/common.rs @@ -268,7 +268,7 @@ impl<'a> PhysicalFormat for SimplePhysicalFormat<'a> { self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut children = vec![]; for child in self.children.iter() { @@ -281,7 +281,7 @@ impl<'a> PhysicalFormat for SimplePhysicalFormat<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.children.len() == 1 { return self.children[0].format_join(ctx); @@ -298,7 +298,7 @@ impl<'a> PhysicalFormat for SimplePhysicalFormat<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.children.len() == 1 { return self.children[0].partial_format(ctx); diff --git a/src/query/service/src/physical_plans/format/format_add_stream_column.rs b/src/query/service/src/physical_plans/format/format_add_stream_column.rs index 7ae54fa4a5271..ea85626a1cac6 100644 --- a/src/query/service/src/physical_plans/format/format_add_stream_column.rs +++ b/src/query/service/src/physical_plans/format/format_add_stream_column.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for AddStreamColumnFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_aggregate_expand.rs b/src/query/service/src/physical_plans/format/format_aggregate_expand.rs index b6e9f2389129e..bbf129fc52ced 100644 --- a/src/query/service/src/physical_plans/format/format_aggregate_expand.rs +++ b/src/query/service/src/physical_plans/format/format_aggregate_expand.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for AggregateExpandFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let sets = self .inner @@ -78,12 +78,12 @@ impl<'a> PhysicalFormat for AggregateExpandFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_aggregate_final.rs b/src/query/service/src/physical_plans/format/format_aggregate_final.rs index 46ea747b46374..af4f50680c442 100644 --- a/src/query/service/src/physical_plans/format/format_aggregate_final.rs +++ b/src/query/service/src/physical_plans/format/format_aggregate_final.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for AggregateFinalFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let group_by = self .inner @@ -83,12 +83,12 @@ impl<'a> PhysicalFormat for AggregateFinalFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_aggregate_partial.rs b/src/query/service/src/physical_plans/format/format_aggregate_partial.rs index 5a71bf5e480e2..e53566bf55194 100644 --- a/src/query/service/src/physical_plans/format/format_aggregate_partial.rs +++ b/src/query/service/src/physical_plans/format/format_aggregate_partial.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for AggregatePartialFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let group_by = self .inner @@ -78,12 +78,12 @@ impl<'a> PhysicalFormat for AggregatePartialFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_async_func.rs b/src/query/service/src/physical_plans/format/format_async_func.rs index a880251f3d4ac..b7a1f79c2f478 100644 --- a/src/query/service/src/physical_plans/format/format_async_func.rs +++ b/src/query/service/src/physical_plans/format/format_async_func.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for AsyncFunctionFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let output_schema = self.inner.output_schema()?; let mut children = vec![FormatTreeNode::new(format!( @@ -59,12 +59,12 @@ impl<'a> PhysicalFormat for AsyncFunctionFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_cache_scan.rs b/src/query/service/src/physical_plans/format/format_cache_scan.rs index 64acf5270921f..012ba4efcdd70 100644 --- a/src/query/service/src/physical_plans/format/format_cache_scan.rs +++ b/src/query/service/src/physical_plans/format/format_cache_scan.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for CacheScanFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut children = Vec::with_capacity(2); children.push(FormatTreeNode::new(format!( diff --git a/src/query/service/src/physical_plans/format/format_chunk_cast_schema.rs b/src/query/service/src/physical_plans/format/format_chunk_cast_schema.rs index 5cd2565a549c5..85ec39726f3b0 100644 --- a/src/query/service/src/physical_plans/format/format_chunk_cast_schema.rs +++ b/src/query/service/src/physical_plans/format/format_chunk_cast_schema.rs @@ -36,18 +36,18 @@ impl<'a> PhysicalFormat for ChunkCastSchemaFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_chunk_eval_scalar.rs b/src/query/service/src/physical_plans/format/format_chunk_eval_scalar.rs index e76f7d2a79751..858447d0b31c8 100644 --- a/src/query/service/src/physical_plans/format/format_chunk_eval_scalar.rs +++ b/src/query/service/src/physical_plans/format/format_chunk_eval_scalar.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for ChunkEvalScalarFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.eval_scalars.iter().all(|x| x.is_none()) { let input_formatter = self.inner.input.formatter()?; @@ -71,12 +71,12 @@ impl<'a> PhysicalFormat for ChunkEvalScalarFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_chunk_fill_and_reorder.rs b/src/query/service/src/physical_plans/format/format_chunk_fill_and_reorder.rs index 26877cb40d01e..bdc7cfe38b262 100644 --- a/src/query/service/src/physical_plans/format/format_chunk_fill_and_reorder.rs +++ b/src/query/service/src/physical_plans/format/format_chunk_fill_and_reorder.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for ChunkFillAndReorderFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_chunk_filter.rs b/src/query/service/src/physical_plans/format/format_chunk_filter.rs index 98745711d3726..d486e22d7616b 100644 --- a/src/query/service/src/physical_plans/format/format_chunk_filter.rs +++ b/src/query/service/src/physical_plans/format/format_chunk_filter.rs @@ -37,7 +37,7 @@ impl<'a> PhysicalFormat for ChunkFilterFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.predicates.iter().all(|x| x.is_none()) { let input_formatter = self.inner.input.formatter()?; @@ -66,12 +66,12 @@ impl<'a> PhysicalFormat for ChunkFilterFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_chunk_merge.rs b/src/query/service/src/physical_plans/format/format_chunk_merge.rs index 979b3bfba587a..b058135466def 100644 --- a/src/query/service/src/physical_plans/format/format_chunk_merge.rs +++ b/src/query/service/src/physical_plans/format/format_chunk_merge.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for ChunkMergeFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_column_mutation.rs b/src/query/service/src/physical_plans/format/format_column_mutation.rs index 2aac117fae45e..32b7ac9892b8b 100644 --- a/src/query/service/src/physical_plans/format/format_column_mutation.rs +++ b/src/query/service/src/physical_plans/format/format_column_mutation.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for ColumnMutationFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_constant_table_scan.rs b/src/query/service/src/physical_plans/format/format_constant_table_scan.rs index f50f53ec25ff4..79ec49ae9e571 100644 --- a/src/query/service/src/physical_plans/format/format_constant_table_scan.rs +++ b/src/query/service/src/physical_plans/format/format_constant_table_scan.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for ConstantTableScanFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.num_rows == 0 { return Ok(FormatTreeNode::new(self.inner.name().to_string())); diff --git a/src/query/service/src/physical_plans/format/format_copy_into_table.rs b/src/query/service/src/physical_plans/format/format_copy_into_table.rs index 0cd9f314c9657..5b28c6fad49d9 100644 --- a/src/query/service/src/physical_plans/format/format_copy_into_table.rs +++ b/src/query/service/src/physical_plans/format/format_copy_into_table.rs @@ -37,7 +37,7 @@ impl<'a> PhysicalFormat for CopyIntoTableFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut children = vec![]; @@ -59,7 +59,7 @@ impl<'a> PhysicalFormat for CopyIntoTableFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { match &self.inner.source { CopyIntoTableSource::Query(input) => { @@ -73,7 +73,7 @@ impl<'a> PhysicalFormat for CopyIntoTableFormatter<'a> { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { match &self.inner.source { CopyIntoTableSource::Query(input) => { diff --git a/src/query/service/src/physical_plans/format/format_cte_consumer.rs b/src/query/service/src/physical_plans/format/format_cte_consumer.rs index 27b8f9bfa2c28..410ea37427d7a 100644 --- a/src/query/service/src/physical_plans/format/format_cte_consumer.rs +++ b/src/query/service/src/physical_plans/format/format_cte_consumer.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for MaterializeCTERefFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut children = Vec::new(); children.push(FormatTreeNode::new(format!( @@ -61,7 +61,7 @@ impl<'a> PhysicalFormat for MaterializeCTERefFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { let children = vec![ FormatTreeNode::new(format!("cte_name: {}", self.inner.cte_name)), diff --git a/src/query/service/src/physical_plans/format/format_duplicate.rs b/src/query/service/src/physical_plans/format/format_duplicate.rs index dd2ea4a828fef..7d7d6b2c2d0c0 100644 --- a/src/query/service/src/physical_plans/format/format_duplicate.rs +++ b/src/query/service/src/physical_plans/format/format_duplicate.rs @@ -36,7 +36,7 @@ impl<'a> PhysicalFormat for DuplicateFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut node_children = vec![FormatTreeNode::new(format!( "Duplicate data to {} branch", @@ -52,12 +52,12 @@ impl<'a> PhysicalFormat for DuplicateFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_eval_scalar.rs b/src/query/service/src/physical_plans/format/format_eval_scalar.rs index 6cb7c0af0c976..375233ab12292 100644 --- a/src/query/service/src/physical_plans/format/format_eval_scalar.rs +++ b/src/query/service/src/physical_plans/format/format_eval_scalar.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for EvalScalarFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.exprs.is_empty() { let input_formatter = self.inner.input.formatter()?; @@ -75,12 +75,12 @@ impl<'a> PhysicalFormat for EvalScalarFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_exchange.rs b/src/query/service/src/physical_plans/format/format_exchange.rs index 32a9adde00108..2caec941520de 100644 --- a/src/query/service/src/physical_plans/format/format_exchange.rs +++ b/src/query/service/src/physical_plans/format/format_exchange.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for ExchangeFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut node_children = vec![ FormatTreeNode::new(format!( @@ -71,12 +71,12 @@ impl<'a> PhysicalFormat for ExchangeFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_exchange_sink.rs b/src/query/service/src/physical_plans/format/format_exchange_sink.rs index c9f718b5e9338..96620d37b8525 100644 --- a/src/query/service/src/physical_plans/format/format_exchange_sink.rs +++ b/src/query/service/src/physical_plans/format/format_exchange_sink.rs @@ -37,7 +37,7 @@ impl<'a> PhysicalFormat for ExchangeSinkFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let output_schema = self.inner.output_schema()?; let mut node_children = vec![FormatTreeNode::new(format!( @@ -59,12 +59,12 @@ impl<'a> PhysicalFormat for ExchangeSinkFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_exchange_source.rs b/src/query/service/src/physical_plans/format/format_exchange_source.rs index 46190e0b2eecf..03da63a8a0e13 100644 --- a/src/query/service/src/physical_plans/format/format_exchange_source.rs +++ b/src/query/service/src/physical_plans/format/format_exchange_source.rs @@ -37,7 +37,7 @@ impl<'a> PhysicalFormat for ExchangeSourceFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let output_schema = self.inner.output_schema()?; let mut node_children = vec![FormatTreeNode::new(format!( diff --git a/src/query/service/src/physical_plans/format/format_expression_scan.rs b/src/query/service/src/physical_plans/format/format_expression_scan.rs index 46594a119faef..e5b2e8809ee99 100644 --- a/src/query/service/src/physical_plans/format/format_expression_scan.rs +++ b/src/query/service/src/physical_plans/format/format_expression_scan.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for ExpressionScanFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut node_children = Vec::with_capacity(self.inner.values.len() + 1); let output_schema = self.inner.output_schema()?; @@ -65,12 +65,12 @@ impl<'a> PhysicalFormat for ExpressionScanFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_filter.rs b/src/query/service/src/physical_plans/format/format_filter.rs index 0a079c3d10716..7411d2cda3a48 100644 --- a/src/query/service/src/physical_plans/format/format_filter.rs +++ b/src/query/service/src/physical_plans/format/format_filter.rs @@ -41,7 +41,7 @@ impl<'a> PhysicalFormat for FilterFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let filter = self .inner @@ -71,12 +71,12 @@ impl<'a> PhysicalFormat for FilterFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let filter = self .inner diff --git a/src/query/service/src/physical_plans/format/format_hash_join.rs b/src/query/service/src/physical_plans/format/format_hash_join.rs index c902d3ae73988..788a27481ad23 100644 --- a/src/query/service/src/physical_plans/format/format_hash_join.rs +++ b/src/query/service/src/physical_plans/format/format_hash_join.rs @@ -41,7 +41,7 @@ impl<'a> PhysicalFormat for HashJoinFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // Register runtime filters for all probe targets for rf in self.inner.runtime_filter.filters.iter() { @@ -184,7 +184,7 @@ impl<'a> PhysicalFormat for HashJoinFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { let build_formatter = self.inner.build.formatter()?; let build_child = build_formatter.format_join(ctx)?; @@ -209,7 +209,7 @@ impl<'a> PhysicalFormat for HashJoinFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let build_child = self.inner.build.formatter()?.partial_format(ctx)?; let probe_child = self.inner.probe.formatter()?.partial_format(ctx)?; diff --git a/src/query/service/src/physical_plans/format/format_limit.rs b/src/query/service/src/physical_plans/format/format_limit.rs index 32d7bcda75df6..71b3a03b75647 100644 --- a/src/query/service/src/physical_plans/format/format_limit.rs +++ b/src/query/service/src/physical_plans/format/format_limit.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for LimitFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let output_schema = self.inner.output_schema()?; let mut node_children = vec![ @@ -68,12 +68,12 @@ impl<'a> PhysicalFormat for LimitFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_materialized_cte.rs b/src/query/service/src/physical_plans/format/format_materialized_cte.rs index 1e83915492632..cdd415115bdc7 100644 --- a/src/query/service/src/physical_plans/format/format_materialized_cte.rs +++ b/src/query/service/src/physical_plans/format/format_materialized_cte.rs @@ -36,7 +36,7 @@ impl<'a> PhysicalFormat for MaterializedCTEFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let input_formatter = self.inner.input.formatter()?; let input_payload = input_formatter.dispatch(ctx)?; @@ -47,7 +47,7 @@ impl<'a> PhysicalFormat for MaterializedCTEFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { let input = self.inner.input.formatter()?.format_join(ctx)?; let children = vec![ @@ -62,7 +62,7 @@ impl<'a> PhysicalFormat for MaterializedCTEFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_multi_table_insert.rs b/src/query/service/src/physical_plans/format/format_multi_table_insert.rs index 4f52555fe8d1f..23e68d631fdc8 100644 --- a/src/query/service/src/physical_plans/format/format_multi_table_insert.rs +++ b/src/query/service/src/physical_plans/format/format_multi_table_insert.rs @@ -36,7 +36,7 @@ impl<'a> PhysicalFormat for ChunkAppendDataFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let input_formatter = self.inner.input.formatter()?; let input_payload = input_formatter.dispatch(ctx)?; @@ -47,12 +47,12 @@ impl<'a> PhysicalFormat for ChunkAppendDataFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_mutation.rs b/src/query/service/src/physical_plans/format/format_mutation.rs index 5a10389b318a2..481e0ce34646e 100644 --- a/src/query/service/src/physical_plans/format/format_mutation.rs +++ b/src/query/service/src/physical_plans/format/format_mutation.rs @@ -36,7 +36,7 @@ impl<'a> PhysicalFormat for MutationFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let table_entry = ctx.metadata.table(self.inner.target_table_index).clone(); let mut node_children = vec![FormatTreeNode::new(format!( @@ -55,12 +55,12 @@ impl<'a> PhysicalFormat for MutationFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_mutation_into_organize.rs b/src/query/service/src/physical_plans/format/format_mutation_into_organize.rs index c0243e91a1f10..172562129f696 100644 --- a/src/query/service/src/physical_plans/format/format_mutation_into_organize.rs +++ b/src/query/service/src/physical_plans/format/format_mutation_into_organize.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for MutationOrganizeFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_mutation_into_split.rs b/src/query/service/src/physical_plans/format/format_mutation_into_split.rs index b55b8989107e4..14cb2ca6607cb 100644 --- a/src/query/service/src/physical_plans/format/format_mutation_into_split.rs +++ b/src/query/service/src/physical_plans/format/format_mutation_into_split.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for MutationSplitFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_mutation_manipulate.rs b/src/query/service/src/physical_plans/format/format_mutation_manipulate.rs index 1aaadf283d942..2ebd34b5bec71 100644 --- a/src/query/service/src/physical_plans/format/format_mutation_manipulate.rs +++ b/src/query/service/src/physical_plans/format/format_mutation_manipulate.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for MutationManipulateFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let table_entry = ctx.metadata.table(self.inner.target_table_index).clone(); let target_schema = table_entry.table().schema_with_stream(); @@ -131,12 +131,12 @@ impl<'a> PhysicalFormat for MutationManipulateFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_mutation_source.rs b/src/query/service/src/physical_plans/format/format_mutation_source.rs index 7b8ce92e9f9fe..2dbae25c19c83 100644 --- a/src/query/service/src/physical_plans/format/format_mutation_source.rs +++ b/src/query/service/src/physical_plans/format/format_mutation_source.rs @@ -41,7 +41,7 @@ impl<'a> PhysicalFormat for MutationSourceFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let table = ctx.metadata.table(self.inner.table_index); let table_name = format!("{}.{}.{}", table.catalog(), table.database(), table.name()); @@ -81,7 +81,7 @@ impl<'a> PhysicalFormat for MutationSourceFormatter<'a> { Ok(FormatTreeNode::with_children(self.inner.get_name(), vec![])) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let table = ctx.metadata.table(self.inner.table_index).clone(); let table_name = format!("{}.{}.{}", table.catalog(), table.database(), table.name()); diff --git a/src/query/service/src/physical_plans/format/format_project_set.rs b/src/query/service/src/physical_plans/format/format_project_set.rs index d0940fa1e9b03..11a0dfc98aee2 100644 --- a/src/query/service/src/physical_plans/format/format_project_set.rs +++ b/src/query/service/src/physical_plans/format/format_project_set.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for ProjectSetFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut node_children = vec![FormatTreeNode::new(format!( "output columns: [{}]", @@ -70,12 +70,12 @@ impl<'a> PhysicalFormat for ProjectSetFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_range_join.rs b/src/query/service/src/physical_plans/format/format_range_join.rs index 8ff2fafef0dd1..1e279e3083534 100644 --- a/src/query/service/src/physical_plans/format/format_range_join.rs +++ b/src/query/service/src/physical_plans/format/format_range_join.rs @@ -41,7 +41,7 @@ impl<'a> PhysicalFormat for RangeJoinFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let range_join_conditions = self .inner @@ -104,7 +104,7 @@ impl<'a> PhysicalFormat for RangeJoinFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { let left_child = self.inner.left.formatter()?.format_join(ctx)?; let right_child = self.inner.right.formatter()?.format_join(ctx)?; @@ -126,7 +126,7 @@ impl<'a> PhysicalFormat for RangeJoinFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let left_child = self.inner.left.formatter()?.partial_format(ctx)?; let right_child = self.inner.right.formatter()?.partial_format(ctx)?; diff --git a/src/query/service/src/physical_plans/format/format_replace_into.rs b/src/query/service/src/physical_plans/format/format_replace_into.rs index 23afd4cb7f0e6..74e65730c6e8b 100644 --- a/src/query/service/src/physical_plans/format/format_replace_into.rs +++ b/src/query/service/src/physical_plans/format/format_replace_into.rs @@ -36,7 +36,7 @@ impl<'a> PhysicalFormat for ReplaceIntoFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ReplaceInto uses default to_format_node implementation let mut children = vec![]; @@ -49,12 +49,12 @@ impl<'a> PhysicalFormat for ReplaceIntoFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_row_fetch.rs b/src/query/service/src/physical_plans/format/format_row_fetch.rs index d4db21fbf419a..d0ff058be7951 100644 --- a/src/query/service/src/physical_plans/format/format_row_fetch.rs +++ b/src/query/service/src/physical_plans/format/format_row_fetch.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for RowFetchFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let table_schema = self.inner.source.source_info.schema(); let projected_schema = self.inner.cols_to_fetch.project_schema(&table_schema); @@ -69,12 +69,12 @@ impl<'a> PhysicalFormat for RowFetchFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_secure_filter.rs b/src/query/service/src/physical_plans/format/format_secure_filter.rs index c19f3eeb2fe7a..abd5c2e5addf8 100644 --- a/src/query/service/src/physical_plans/format/format_secure_filter.rs +++ b/src/query/service/src/physical_plans/format/format_secure_filter.rs @@ -41,7 +41,7 @@ impl<'a> PhysicalFormat for SecureFilterFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let filter = self .inner @@ -71,12 +71,12 @@ impl<'a> PhysicalFormat for SecureFilterFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let filter = self .inner diff --git a/src/query/service/src/physical_plans/format/format_shuffle.rs b/src/query/service/src/physical_plans/format/format_shuffle.rs index f0bc3e10595e8..308dcc6cc339e 100644 --- a/src/query/service/src/physical_plans/format/format_shuffle.rs +++ b/src/query/service/src/physical_plans/format/format_shuffle.rs @@ -36,19 +36,19 @@ impl<'a> PhysicalFormat for ShuffleFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { // ignore self let input_formatter = self.inner.input.formatter()?; input_formatter.dispatch(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_sort.rs b/src/query/service/src/physical_plans/format/format_sort.rs index 633b68eeafa5d..66c492c68186d 100644 --- a/src/query/service/src/physical_plans/format/format_sort.rs +++ b/src/query/service/src/physical_plans/format/format_sort.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for SortFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let sort_keys = self .inner @@ -85,12 +85,12 @@ impl<'a> PhysicalFormat for SortFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_table_scan.rs b/src/query/service/src/physical_plans/format/format_table_scan.rs index 06db799713c28..d4954c19044c9 100644 --- a/src/query/service/src/physical_plans/format/format_table_scan.rs +++ b/src/query/service/src/physical_plans/format/format_table_scan.rs @@ -43,7 +43,7 @@ impl<'a> PhysicalFormat for TableScanFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.table_index == Some(DUMMY_TABLE_INDEX) { return Ok(FormatTreeNode::new("DummyTableScan".to_string())); @@ -176,7 +176,7 @@ impl<'a> PhysicalFormat for TableScanFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.table_index == Some(DUMMY_TABLE_INDEX) { return Ok(FormatTreeNode::with_children( @@ -214,7 +214,7 @@ impl<'a> PhysicalFormat for TableScanFormatter<'a> { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { if self.inner.table_index == Some(DUMMY_TABLE_INDEX) { return Ok(FormatTreeNode::new("DummyTableScan".to_string())); diff --git a/src/query/service/src/physical_plans/format/format_udf.rs b/src/query/service/src/physical_plans/format/format_udf.rs index 38775f727e64d..3c5a3e828ea26 100644 --- a/src/query/service/src/physical_plans/format/format_udf.rs +++ b/src/query/service/src/physical_plans/format/format_udf.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for UdfFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let output_schema = self.inner.output_schema()?; let mut node_children = vec![FormatTreeNode::new(format!( @@ -73,12 +73,12 @@ impl<'a> PhysicalFormat for UdfFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_union_all.rs b/src/query/service/src/physical_plans/format/format_union_all.rs index 9808c9c2c90b5..d570514b73d0a 100644 --- a/src/query/service/src/physical_plans/format/format_union_all.rs +++ b/src/query/service/src/physical_plans/format/format_union_all.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for UnionAllFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut node_children = vec![FormatTreeNode::new(format!( "output columns: [{}]", @@ -65,7 +65,7 @@ impl<'a> PhysicalFormat for UnionAllFormatter<'a> { Ok(FormatTreeNode::with_children(root, node_children)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { let left_child = self.inner.left.formatter()?.format_join(ctx)?; let right_child = self.inner.right.formatter()?.format_join(ctx)?; @@ -81,7 +81,7 @@ impl<'a> PhysicalFormat for UnionAllFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { let left_child = self.inner.left.formatter()?.partial_format(ctx)?; let right_child = self.inner.right.formatter()?.partial_format(ctx)?; diff --git a/src/query/service/src/physical_plans/format/format_window.rs b/src/query/service/src/physical_plans/format/format_window.rs index 274d8cd08d088..5288524b5ad58 100644 --- a/src/query/service/src/physical_plans/format/format_window.rs +++ b/src/query/service/src/physical_plans/format/format_window.rs @@ -39,7 +39,7 @@ impl<'a> PhysicalFormat for WindowFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let partition_by = self .inner @@ -86,12 +86,12 @@ impl<'a> PhysicalFormat for WindowFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/format_window_partition.rs b/src/query/service/src/physical_plans/format/format_window_partition.rs index 2e71a13fe97ec..910f1d9399809 100644 --- a/src/query/service/src/physical_plans/format/format_window_partition.rs +++ b/src/query/service/src/physical_plans/format/format_window_partition.rs @@ -38,7 +38,7 @@ impl<'a> PhysicalFormat for WindowPartitionFormatter<'a> { self.inner.get_meta() } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format(&self, ctx: &mut FormatContext<'_>) -> Result> { let partition_by = self .inner @@ -74,12 +74,12 @@ impl<'a> PhysicalFormat for WindowPartitionFormatter<'a> { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn format_join(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.format_join(ctx) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn partial_format(&self, ctx: &mut FormatContext<'_>) -> Result> { self.inner.input.formatter()?.partial_format(ctx) } diff --git a/src/query/service/src/physical_plans/format/physical_format.rs b/src/query/service/src/physical_plans/format/physical_format.rs index 0d96916898113..987c53d2b5d3d 100644 --- a/src/query/service/src/physical_plans/format/physical_format.rs +++ b/src/query/service/src/physical_plans/format/physical_format.rs @@ -20,7 +20,7 @@ use crate::physical_plans::PhysicalPlanMeta; use crate::physical_plans::format::FormatContext; pub trait PhysicalFormat { - #[recursive::recursive] + #[stacksafe::stacksafe] fn dispatch(&self, ctx: &mut FormatContext<'_>) -> Result> { let mut format_node = self.format(ctx)?; diff --git a/src/query/service/src/physical_plans/physical_aggregate_expand.rs b/src/query/service/src/physical_plans/physical_aggregate_expand.rs index 9f5a6ce5069d2..d3aca3208f438 100644 --- a/src/query/service/src/physical_plans/physical_aggregate_expand.rs +++ b/src/query/service/src/physical_plans/physical_aggregate_expand.rs @@ -58,7 +58,7 @@ impl IPhysicalPlan for AggregateExpand { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut output_fields = input_schema.fields().clone(); diff --git a/src/query/service/src/physical_plans/physical_aggregate_final.rs b/src/query/service/src/physical_plans/physical_aggregate_final.rs index a87b6b6b8cc6f..63e065952eed8 100644 --- a/src/query/service/src/physical_plans/physical_aggregate_final.rs +++ b/src/query/service/src/physical_plans/physical_aggregate_final.rs @@ -77,7 +77,7 @@ impl IPhysicalPlan for AggregateFinal { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let mut fields = Vec::with_capacity(self.agg_funcs.len() + self.group_by.len()); for agg in self.agg_funcs.iter() { diff --git a/src/query/service/src/physical_plans/physical_aggregate_partial.rs b/src/query/service/src/physical_plans/physical_aggregate_partial.rs index fbaeb0157d5a1..ae83d46beb114 100644 --- a/src/query/service/src/physical_plans/physical_aggregate_partial.rs +++ b/src/query/service/src/physical_plans/physical_aggregate_partial.rs @@ -80,7 +80,7 @@ impl IPhysicalPlan for AggregatePartial { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; diff --git a/src/query/service/src/physical_plans/physical_async_func.rs b/src/query/service/src/physical_plans/physical_async_func.rs index d3595c2436225..fc3e0b2230424 100644 --- a/src/query/service/src/physical_plans/physical_async_func.rs +++ b/src/query/service/src/physical_plans/physical_async_func.rs @@ -59,7 +59,7 @@ impl IPhysicalPlan for AsyncFunction { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = input_schema.fields().clone(); @@ -83,7 +83,7 @@ impl IPhysicalPlan for AsyncFunction { Ok(AsyncFunctionFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_broadcast.rs b/src/query/service/src/physical_plans/physical_broadcast.rs index 88f961c5103ed..40d2d6de9ba71 100644 --- a/src/query/service/src/physical_plans/physical_broadcast.rs +++ b/src/query/service/src/physical_plans/physical_broadcast.rs @@ -88,7 +88,7 @@ impl IPhysicalPlan for BroadcastSink { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_cache_scan.rs b/src/query/service/src/physical_plans/physical_cache_scan.rs index 6988ab483fbdf..8155318116f19 100644 --- a/src/query/service/src/physical_plans/physical_cache_scan.rs +++ b/src/query/service/src/physical_plans/physical_cache_scan.rs @@ -54,7 +54,7 @@ impl IPhysicalPlan for CacheScan { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_column_mutation.rs b/src/query/service/src/physical_plans/physical_column_mutation.rs index c1bb9b709ec8b..3aa758f5ef0d4 100644 --- a/src/query/service/src/physical_plans/physical_column_mutation.rs +++ b/src/query/service/src/physical_plans/physical_column_mutation.rs @@ -65,7 +65,7 @@ impl IPhysicalPlan for ColumnMutation { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_commit_sink.rs b/src/query/service/src/physical_plans/physical_commit_sink.rs index c8f584484b0f0..8cf20f2a8c72d 100644 --- a/src/query/service/src/physical_plans/physical_commit_sink.rs +++ b/src/query/service/src/physical_plans/physical_commit_sink.rs @@ -71,7 +71,7 @@ impl IPhysicalPlan for CommitSink { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_constant_table_scan.rs b/src/query/service/src/physical_plans/physical_constant_table_scan.rs index fd9865d9e3c8b..00745332d2fa9 100644 --- a/src/query/service/src/physical_plans/physical_constant_table_scan.rs +++ b/src/query/service/src/physical_plans/physical_constant_table_scan.rs @@ -51,7 +51,7 @@ impl IPhysicalPlan for ConstantTableScan { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_copy_into_location.rs b/src/query/service/src/physical_plans/physical_copy_into_location.rs index 982beaa49d70c..28fc2f95812fd 100644 --- a/src/query/service/src/physical_plans/physical_copy_into_location.rs +++ b/src/query/service/src/physical_plans/physical_copy_into_location.rs @@ -58,7 +58,7 @@ impl IPhysicalPlan for CopyIntoLocation { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRefExt::create(vec![ DataField::new("rows_unloaded", DataType::Number(NumberDataType::UInt64)), @@ -75,7 +75,7 @@ impl IPhysicalPlan for CopyIntoLocation { Box::new(std::iter::once(&mut self.input)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_copy_into_table.rs b/src/query/service/src/physical_plans/physical_copy_into_table.rs index a5b3bdaa34e3a..38e4c21096487 100644 --- a/src/query/service/src/physical_plans/physical_copy_into_table.rs +++ b/src/query/service/src/physical_plans/physical_copy_into_table.rs @@ -64,7 +64,7 @@ impl IPhysicalPlan for CopyIntoTable { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRefExt::create(vec![])) } diff --git a/src/query/service/src/physical_plans/physical_cte_consumer.rs b/src/query/service/src/physical_plans/physical_cte_consumer.rs index 9d221cf5fee05..0b5be00c12243 100644 --- a/src/query/service/src/physical_plans/physical_cte_consumer.rs +++ b/src/query/service/src/physical_plans/physical_cte_consumer.rs @@ -56,7 +56,7 @@ impl IPhysicalPlan for MaterializeCTERef { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.cte_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_distributed_insert_select.rs b/src/query/service/src/physical_plans/physical_distributed_insert_select.rs index 3c7280778f4a6..d8be60c1f8d1c 100644 --- a/src/query/service/src/physical_plans/physical_distributed_insert_select.rs +++ b/src/query/service/src/physical_plans/physical_distributed_insert_select.rs @@ -53,7 +53,7 @@ impl IPhysicalPlan for DistributedInsertSelect { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } @@ -66,7 +66,7 @@ impl IPhysicalPlan for DistributedInsertSelect { Box::new(std::iter::once(&mut self.input)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_eval_scalar.rs b/src/query/service/src/physical_plans/physical_eval_scalar.rs index dfa77296fbf31..35a2f799ef73d 100644 --- a/src/query/service/src/physical_plans/physical_eval_scalar.rs +++ b/src/query/service/src/physical_plans/physical_eval_scalar.rs @@ -78,7 +78,7 @@ impl IPhysicalPlan for EvalScalar { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { if self.exprs.is_empty() { return self.input.output_schema(); @@ -115,7 +115,7 @@ impl IPhysicalPlan for EvalScalar { Ok(EvalScalarFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_exchange.rs b/src/query/service/src/physical_plans/physical_exchange.rs index ba19faecbb359..692387d6f674a 100644 --- a/src/query/service/src/physical_plans/physical_exchange.rs +++ b/src/query/service/src/physical_plans/physical_exchange.rs @@ -66,7 +66,7 @@ impl IPhysicalPlan for Exchange { Ok(ExchangeFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_exchange_sink.rs b/src/query/service/src/physical_plans/physical_exchange_sink.rs index 17f2e3b51d9e5..197c522fc090b 100644 --- a/src/query/service/src/physical_plans/physical_exchange_sink.rs +++ b/src/query/service/src/physical_plans/physical_exchange_sink.rs @@ -58,7 +58,7 @@ impl IPhysicalPlan for ExchangeSink { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.schema.clone()) } @@ -75,7 +75,7 @@ impl IPhysicalPlan for ExchangeSink { Ok(ExchangeSinkFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_exchange_source.rs b/src/query/service/src/physical_plans/physical_exchange_source.rs index 79076f92fb2b4..6bd271b0d4cd8 100644 --- a/src/query/service/src/physical_plans/physical_exchange_source.rs +++ b/src/query/service/src/physical_plans/physical_exchange_source.rs @@ -50,7 +50,7 @@ impl IPhysicalPlan for ExchangeSource { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_expression_scan.rs b/src/query/service/src/physical_plans/physical_expression_scan.rs index 8d13ffbe9ed7f..149b55e23871a 100644 --- a/src/query/service/src/physical_plans/physical_expression_scan.rs +++ b/src/query/service/src/physical_plans/physical_expression_scan.rs @@ -54,7 +54,7 @@ impl IPhysicalPlan for ExpressionScan { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_filter.rs b/src/query/service/src/physical_plans/physical_filter.rs index d9d0f15d9edff..0265ee62d2ef2 100644 --- a/src/query/service/src/physical_plans/physical_filter.rs +++ b/src/query/service/src/physical_plans/physical_filter.rs @@ -61,7 +61,7 @@ impl IPhysicalPlan for Filter { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = Vec::with_capacity(self.projections.len()); @@ -85,7 +85,7 @@ impl IPhysicalPlan for Filter { Ok(FilterFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_hash_join.rs b/src/query/service/src/physical_plans/physical_hash_join.rs index 9a2e5802f105f..3d0fd4e695d8f 100644 --- a/src/query/service/src/physical_plans/physical_hash_join.rs +++ b/src/query/service/src/physical_plans/physical_hash_join.rs @@ -155,7 +155,7 @@ impl IPhysicalPlan for HashJoin { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_limit.rs b/src/query/service/src/physical_plans/physical_limit.rs index 33dd52a60d495..da59b7de0f849 100644 --- a/src/query/service/src/physical_plans/physical_limit.rs +++ b/src/query/service/src/physical_plans/physical_limit.rs @@ -72,7 +72,7 @@ impl IPhysicalPlan for Limit { Ok(LimitFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_materialized_cte.rs b/src/query/service/src/physical_plans/physical_materialized_cte.rs index fc6f6b476db38..fcce3c90d6da8 100644 --- a/src/query/service/src/physical_plans/physical_materialized_cte.rs +++ b/src/query/service/src/physical_plans/physical_materialized_cte.rs @@ -58,7 +58,7 @@ impl IPhysicalPlan for MaterializedCTE { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { self.input.output_schema() } diff --git a/src/query/service/src/physical_plans/physical_mutation.rs b/src/query/service/src/physical_plans/physical_mutation.rs index 8ce678a6d1c5a..fb9a6b4dbfb7d 100644 --- a/src/query/service/src/physical_plans/physical_mutation.rs +++ b/src/query/service/src/physical_plans/physical_mutation.rs @@ -121,7 +121,7 @@ impl IPhysicalPlan for Mutation { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_mutation_source.rs b/src/query/service/src/physical_plans/physical_mutation_source.rs index 68ab0c632f610..2a5712ce6565b 100644 --- a/src/query/service/src/physical_plans/physical_mutation_source.rs +++ b/src/query/service/src/physical_plans/physical_mutation_source.rs @@ -87,7 +87,7 @@ impl IPhysicalPlan for MutationSource { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_plan.rs b/src/query/service/src/physical_plans/physical_plan.rs index 27cc04c134d07..e371d3c5716a4 100644 --- a/src/query/service/src/physical_plans/physical_plan.rs +++ b/src/query/service/src/physical_plans/physical_plan.rs @@ -90,7 +90,7 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { /// Adjust the plan_id of the physical plan. /// This function will assign a unique plan_id to each physical plan node in a top-down manner. /// Which means the plan_id of a node is always greater than the plan_id of its parent node. - #[recursive::recursive] + #[stacksafe::stacksafe] fn adjust_plan_id(&mut self, next_id: &mut u32) { self.get_meta_mut().plan_id = *next_id; *next_id += 1; @@ -100,7 +100,7 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { match self.children().next() { None => Ok(DataSchemaRef::default()), @@ -116,7 +116,7 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { Box::new(std::iter::empty()) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn formatter(&self) -> Result> { let mut children = vec![]; for child in self.children() { @@ -127,12 +127,12 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { } /// Used to find data source info in a non-aggregation and single-table query plan. - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { None } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_mutation_source(&self) -> Option { for child in self.children() { if let Some(plan) = child.try_find_mutation_source() { @@ -143,26 +143,26 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { None } - #[recursive::recursive] + #[stacksafe::stacksafe] fn get_all_data_source(&self, sources: &mut Vec<(u32, Box)>) { for child in self.children() { child.get_all_data_source(sources); } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn set_pruning_stats(&mut self, stats: &mut HashMap) { for child in self.children_mut() { child.set_pruning_stats(stats) } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn is_distributed_plan(&self) -> bool { self.children().any(|child| child.is_distributed_plan()) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn is_warehouse_distributed_plan(&self) -> bool { self.children() .any(|child| child.is_warehouse_distributed_plan()) @@ -182,7 +182,7 @@ pub trait IPhysicalPlan: DynClone + Debug + Send + Sync + 'static { fn derive(&self, children: Vec) -> PhysicalPlan; - #[recursive::recursive] + #[stacksafe::stacksafe] fn build_pipeline(&self, builder: &mut PipelineBuilder) -> Result<()> { let is_exchange_sink = self.as_any().downcast_ref::().is_some(); builder.is_exchange_stack.push(is_exchange_sink); @@ -276,7 +276,7 @@ pub struct PhysicalPlan { dyn_clone::clone_trait_object!(IPhysicalPlan); impl Clone for PhysicalPlan { - #[recursive::recursive] + #[stacksafe::stacksafe] fn clone(&self) -> Self { PhysicalPlan { inner: self.inner.clone(), @@ -285,7 +285,7 @@ impl Clone for PhysicalPlan { } impl Debug for PhysicalPlan { - #[recursive::recursive] + #[stacksafe::stacksafe] fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) } @@ -306,14 +306,14 @@ impl DerefMut for PhysicalPlan { } impl serde::Serialize for PhysicalPlan { - #[recursive::recursive] + #[stacksafe::stacksafe] fn serialize(&self, serializer: S) -> std::result::Result { self.inner.serialize(serializer) } } impl<'de> serde::Deserialize<'de> for PhysicalPlan { - #[recursive::recursive] + #[stacksafe::stacksafe] fn deserialize>(deserializer: D) -> std::result::Result { Ok(PhysicalPlan { inner: Box::::deserialize(deserializer)?, @@ -328,7 +328,7 @@ impl PhysicalPlan { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn derive_with(&self, handle: &mut Box) -> PhysicalPlan { let mut children = vec![]; for child in self.children() { @@ -341,7 +341,7 @@ impl PhysicalPlan { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn visit(&self, visitor: &mut Box) -> Result<()> { for child in self.children() { child.visit(visitor)?; diff --git a/src/query/service/src/physical_plans/physical_plan_builder.rs b/src/query/service/src/physical_plans/physical_plan_builder.rs index 03469fc998ed5..9fb1cb0d7668a 100644 --- a/src/query/service/src/physical_plans/physical_plan_builder.rs +++ b/src/query/service/src/physical_plans/physical_plan_builder.rs @@ -69,7 +69,7 @@ impl PhysicalPlanBuilder { Ok(plan) } - #[async_recursion::async_recursion(#[recursive::recursive])] + #[async_recursion::async_recursion(#[stacksafe::stacksafe])] pub async fn build_physical_plan( &mut self, s_expr: &SExpr, diff --git a/src/query/service/src/physical_plans/physical_project_set.rs b/src/query/service/src/physical_plans/physical_project_set.rs index 7b3caf514ea24..964e233724264 100644 --- a/src/query/service/src/physical_plans/physical_project_set.rs +++ b/src/query/service/src/physical_plans/physical_project_set.rs @@ -63,7 +63,7 @@ impl IPhysicalPlan for ProjectSet { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = Vec::with_capacity(input_schema.num_fields() + self.srf_exprs.len()); @@ -93,7 +93,7 @@ impl IPhysicalPlan for ProjectSet { Ok(ProjectSetFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_r_cte_scan.rs b/src/query/service/src/physical_plans/physical_r_cte_scan.rs index 94d478dadb0c0..6f2e8152b03ea 100644 --- a/src/query/service/src/physical_plans/physical_r_cte_scan.rs +++ b/src/query/service/src/physical_plans/physical_r_cte_scan.rs @@ -48,7 +48,7 @@ impl IPhysicalPlan for RecursiveCteScan { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_range_join.rs b/src/query/service/src/physical_plans/physical_range_join.rs index b96091b477d84..fe6f0fad50739 100644 --- a/src/query/service/src/physical_plans/physical_range_join.rs +++ b/src/query/service/src/physical_plans/physical_range_join.rs @@ -79,7 +79,7 @@ impl IPhysicalPlan for RangeJoin { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.output_schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_recluster.rs b/src/query/service/src/physical_plans/physical_recluster.rs index f86247763f24c..6840bc9bf093e 100644 --- a/src/query/service/src/physical_plans/physical_recluster.rs +++ b/src/query/service/src/physical_plans/physical_recluster.rs @@ -279,7 +279,7 @@ impl IPhysicalPlan for HilbertPartition { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_replace_deduplicate.rs b/src/query/service/src/physical_plans/physical_replace_deduplicate.rs index 29f1ce6d2ec89..987e2d7193f63 100644 --- a/src/query/service/src/physical_plans/physical_replace_deduplicate.rs +++ b/src/query/service/src/physical_plans/physical_replace_deduplicate.rs @@ -70,7 +70,7 @@ impl IPhysicalPlan for ReplaceDeduplicate { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_replace_into.rs b/src/query/service/src/physical_plans/physical_replace_into.rs index 9e502fb467a81..646e085a71e41 100644 --- a/src/query/service/src/physical_plans/physical_replace_into.rs +++ b/src/query/service/src/physical_plans/physical_replace_into.rs @@ -70,7 +70,7 @@ impl IPhysicalPlan for ReplaceInto { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(DataSchemaRef::default()) } diff --git a/src/query/service/src/physical_plans/physical_row_fetch.rs b/src/query/service/src/physical_plans/physical_row_fetch.rs index 11fef083c340a..1d04cd78b4797 100644 --- a/src/query/service/src/physical_plans/physical_row_fetch.rs +++ b/src/query/service/src/physical_plans/physical_row_fetch.rs @@ -67,7 +67,7 @@ impl IPhysicalPlan for RowFetch { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let mut fields = self.input.output_schema()?.fields().clone(); fields.extend_from_slice(&self.fetched_fields); @@ -86,7 +86,7 @@ impl IPhysicalPlan for RowFetch { Ok(RowFetchFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_secure_filter.rs b/src/query/service/src/physical_plans/physical_secure_filter.rs index 851952279b83f..d2f3e7fce37fe 100644 --- a/src/query/service/src/physical_plans/physical_secure_filter.rs +++ b/src/query/service/src/physical_plans/physical_secure_filter.rs @@ -61,7 +61,7 @@ impl IPhysicalPlan for SecureFilter { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = Vec::with_capacity(self.projections.len()); @@ -81,12 +81,12 @@ impl IPhysicalPlan for SecureFilter { Box::new(std::iter::once(&mut self.input)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn formatter(&self) -> Result> { Ok(SecureFilterFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_sequence.rs b/src/query/service/src/physical_plans/physical_sequence.rs index 4642019c961f5..20c531bfed83d 100644 --- a/src/query/service/src/physical_plans/physical_sequence.rs +++ b/src/query/service/src/physical_plans/physical_sequence.rs @@ -53,7 +53,7 @@ impl IPhysicalPlan for Sequence { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { self.right.output_schema() } diff --git a/src/query/service/src/physical_plans/physical_sort.rs b/src/query/service/src/physical_plans/physical_sort.rs index 531e93b955b55..d29b7077ff738 100644 --- a/src/query/service/src/physical_plans/physical_sort.rs +++ b/src/query/service/src/physical_plans/physical_sort.rs @@ -112,7 +112,7 @@ impl IPhysicalPlan for Sort { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; match self.step { @@ -185,7 +185,7 @@ impl IPhysicalPlan for Sort { Ok(SortFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_table_scan.rs b/src/query/service/src/physical_plans/physical_table_scan.rs index 637157a17064f..fdfc866a25c1a 100644 --- a/src/query/service/src/physical_plans/physical_table_scan.rs +++ b/src/query/service/src/physical_plans/physical_table_scan.rs @@ -110,7 +110,7 @@ impl IPhysicalPlan for TableScan { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let schema = self.source.schema(); let mut fields = Vec::with_capacity(self.name_mapping.len()); diff --git a/src/query/service/src/physical_plans/physical_udf.rs b/src/query/service/src/physical_plans/physical_udf.rs index 89f75767e8acb..11f2c78b09015 100644 --- a/src/query/service/src/physical_plans/physical_udf.rs +++ b/src/query/service/src/physical_plans/physical_udf.rs @@ -65,7 +65,7 @@ impl IPhysicalPlan for Udf { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = input_schema.fields().clone(); @@ -89,7 +89,7 @@ impl IPhysicalPlan for Udf { Ok(UdfFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_union_all.rs b/src/query/service/src/physical_plans/physical_union_all.rs index c2f311951a588..0566b2236f5b7 100644 --- a/src/query/service/src/physical_plans/physical_union_all.rs +++ b/src/query/service/src/physical_plans/physical_union_all.rs @@ -68,7 +68,7 @@ impl IPhysicalPlan for UnionAll { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { Ok(self.schema.clone()) } diff --git a/src/query/service/src/physical_plans/physical_window.rs b/src/query/service/src/physical_plans/physical_window.rs index 6682adddbfcde..4460b71730d23 100644 --- a/src/query/service/src/physical_plans/physical_window.rs +++ b/src/query/service/src/physical_plans/physical_window.rs @@ -86,7 +86,7 @@ impl IPhysicalPlan for Window { &mut self.meta } - #[recursive::recursive] + #[stacksafe::stacksafe] fn output_schema(&self) -> Result { let input_schema = self.input.output_schema()?; let mut fields = Vec::with_capacity(input_schema.fields().len() + 1); @@ -110,7 +110,7 @@ impl IPhysicalPlan for Window { Ok(WindowFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/physical_plans/physical_window_partition.rs b/src/query/service/src/physical_plans/physical_window_partition.rs index e3c9f1f0228d4..11b832b111e25 100644 --- a/src/query/service/src/physical_plans/physical_window_partition.rs +++ b/src/query/service/src/physical_plans/physical_window_partition.rs @@ -79,7 +79,7 @@ impl IPhysicalPlan for WindowPartition { Ok(WindowPartitionFormatter::create(self)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn try_find_single_data_source(&self) -> Option<&DataSourcePlan> { self.input.try_find_single_data_source() } diff --git a/src/query/service/src/pipelines/pipeline_builder.rs b/src/query/service/src/pipelines/pipeline_builder.rs index d21e5498aadc8..82c18a0955336 100644 --- a/src/query/service/src/pipelines/pipeline_builder.rs +++ b/src/query/service/src/pipelines/pipeline_builder.rs @@ -122,7 +122,7 @@ impl PipelineBuilder { false } - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn build_pipeline(&mut self, plan: &PhysicalPlan) -> Result<()> { plan.build_pipeline(self) } diff --git a/src/query/service/src/servers/flight/v1/actions/flight_actions.rs b/src/query/service/src/servers/flight/v1/actions/flight_actions.rs index cf128a4dacd6b..d7236bb961431 100644 --- a/src/query/service/src/servers/flight/v1/actions/flight_actions.rs +++ b/src/query/service/src/servers/flight/v1/actions/flight_actions.rs @@ -74,8 +74,8 @@ impl FlightActions { let deserializer = serde_stacker::Deserializer { de: &mut deserializer, - red_zone: recursive::get_minimum_stack_size(), - stack_size: recursive::get_stack_allocation_size(), + red_zone: stacksafe::get_minimum_stack_size(), + stack_size: stacksafe::get_stack_allocation_size(), }; let request = Req::deserialize(deserializer).map_err(|cause| { @@ -103,8 +103,8 @@ impl FlightActions { let mut serializer = serde_json::Serializer::new(&mut out); let serializer = serde_stacker::Serializer { ser: &mut serializer, - red_zone: recursive::get_minimum_stack_size(), - stack_size: recursive::get_stack_allocation_size(), + red_zone: stacksafe::get_minimum_stack_size(), + stack_size: stacksafe::get_stack_allocation_size(), }; v.serialize(serializer).map_err(|cause| { diff --git a/src/query/service/src/servers/flight/v1/packets/packet_fragment.rs b/src/query/service/src/servers/flight/v1/packets/packet_fragment.rs index 963363e7267d1..28d54c5adea2f 100644 --- a/src/query/service/src/servers/flight/v1/packets/packet_fragment.rs +++ b/src/query/service/src/servers/flight/v1/packets/packet_fragment.rs @@ -79,7 +79,7 @@ struct SerializeQueryFragment { } impl serde::Serialize for QueryFragment { - #[recursive::recursive] + #[stacksafe::stacksafe] fn serialize(&self, serializer: S) -> Result { let mut flatten_queue = vec![self.physical_plan.clone()]; let mut flattened = VecDeque::new(); @@ -106,7 +106,7 @@ impl serde::Serialize for QueryFragment { } impl<'de> serde::Deserialize<'de> for QueryFragment { - #[recursive::recursive] + #[stacksafe::stacksafe] fn deserialize>(deserializer: D) -> Result { let mut fragment = SerializeQueryFragment::deserialize(deserializer)?; diff --git a/src/query/sql/Cargo.toml b/src/query/sql/Cargo.toml index 03317ba21d77e..0be2d388c0bc8 100644 --- a/src/query/sql/Cargo.toml +++ b/src/query/sql/Cargo.toml @@ -62,7 +62,6 @@ num-traits = { workspace = true } opendal = { workspace = true } parking_lot = { workspace = true } prqlc = { workspace = true } -recursive = { workspace = true } regex = { workspace = true } roaring = { workspace = true } serde = { workspace = true } @@ -70,6 +69,7 @@ serde_json = { workspace = true } sha2 = { workspace = true } similar = { workspace = true } simsearch = { workspace = true } +stacksafe = { workspace = true } tantivy-query-grammar = { workspace = true } unicase = { workspace = true } url = { workspace = true } diff --git a/src/query/sql/src/executor/format.rs b/src/query/sql/src/executor/format.rs index a7aaf9acaafbf..28bf6599874df 100644 --- a/src/query/sql/src/executor/format.rs +++ b/src/query/sql/src/executor/format.rs @@ -86,7 +86,7 @@ impl PhysicalPlan { to_format_tree(self, &metadata, &profs, &mut context) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn format_join(&self, metadata: &MetadataRef) -> Result> { match self { PhysicalPlan::TableScan(plan) => { @@ -234,7 +234,7 @@ impl PhysicalPlan { // The method will only collect scan,filter and join nodes // It's only used to debug cardinality estimator. -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn format_partial_tree( plan: &PhysicalPlan, metadata: &MetadataRef, @@ -380,7 +380,7 @@ struct FormatContext { scan_id_to_runtime_filters: HashMap>, } -#[recursive::recursive] +#[stacksafe::stacksafe] fn to_format_tree( plan: &PhysicalPlan, metadata: &Metadata, diff --git a/src/query/sql/src/planner/binder/bind_query/bind.rs b/src/query/sql/src/planner/binder/bind_query/bind.rs index 5690c16067b15..a964303aef7b9 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind.rs @@ -67,7 +67,7 @@ impl CTERefCounter { } impl Binder { - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn bind_query( &mut self, bind_context: &mut BindContext, @@ -122,7 +122,7 @@ impl Binder { Ok(()) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn compute_cte_ref_count( &self, with: &With, @@ -214,7 +214,7 @@ impl Binder { )) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn m_cte_to_temp_table( &mut self, cte: &CTE, @@ -354,7 +354,7 @@ impl TableNameReplacer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn enter_table_reference(&mut self, table_reference: &mut TableReference) { if let TableReference::Table { database, table, .. @@ -366,7 +366,7 @@ impl TableNameReplacer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn enter_expr(&mut self, expr: &mut Expr) { if let Expr::ColumnRef { column, .. } = expr { if column.database.is_none() || column.database.as_ref().unwrap().name == self.database diff --git a/src/query/sql/src/planner/binder/bind_query/bind_value.rs b/src/query/sql/src/planner/binder/bind_query/bind_value.rs index 6c06dbfc66676..4c9c6135272de 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind_value.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind_value.rs @@ -209,7 +209,7 @@ impl Binder { } // Remove unused cache columns and join conditions and construct ExpressionScan's child. - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn construct_expression_scan( &mut self, s_expr: &SExpr, diff --git a/src/query/sql/src/planner/binder/bind_table_reference/bind_cte.rs b/src/query/sql/src/planner/binder/bind_table_reference/bind_cte.rs index 5feb86f60be52..baa9e2372aaf1 100644 --- a/src/query/sql/src/planner/binder/bind_table_reference/bind_cte.rs +++ b/src/query/sql/src/planner/binder/bind_table_reference/bind_cte.rs @@ -169,7 +169,7 @@ impl Binder { Ok((s_expr, new_bind_context)) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn bind_cte_definition( &mut self, cte_name: &str, diff --git a/src/query/sql/src/planner/binder/bind_table_reference/bind_join.rs b/src/query/sql/src/planner/binder/bind_table_reference/bind_join.rs index a8e4e9c6bb53a..805f5dfef4afa 100644 --- a/src/query/sql/src/planner/binder/bind_table_reference/bind_join.rs +++ b/src/query/sql/src/planner/binder/bind_table_reference/bind_join.rs @@ -174,7 +174,7 @@ impl Binder { } // TODO: unify this function with bind_join - #[async_recursion(#[recursive::recursive])] + #[async_recursion(#[stacksafe::stacksafe])] pub(crate) async fn bind_merge_into_join( &mut self, bind_context: &mut BindContext, diff --git a/src/query/sql/src/planner/binder/binder.rs b/src/query/sql/src/planner/binder/binder.rs index b4096577651c3..91ad27508cce8 100644 --- a/src/query/sql/src/planner/binder/binder.rs +++ b/src/query/sql/src/planner/binder/binder.rs @@ -154,7 +154,7 @@ impl Binder { Ok(plan) } - #[async_recursion::async_recursion(#[recursive::recursive])] + #[async_recursion::async_recursion(#[stacksafe::stacksafe])] pub(crate) async fn bind_statement( &mut self, bind_context: &mut BindContext, diff --git a/src/query/sql/src/planner/binder/select.rs b/src/query/sql/src/planner/binder/select.rs index 2427a3ff67355..9bf64b67462a0 100644 --- a/src/query/sql/src/planner/binder/select.rs +++ b/src/query/sql/src/planner/binder/select.rs @@ -110,7 +110,7 @@ impl Binder { Ok((new_expr, scalar)) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub(super) fn bind_set_operator( &mut self, bind_context: &mut BindContext, diff --git a/src/query/sql/src/planner/optimizer/ir/expr/extract.rs b/src/query/sql/src/planner/optimizer/ir/expr/extract.rs index c3872b9b22374..f1002f16e64a4 100644 --- a/src/query/sql/src/planner/optimizer/ir/expr/extract.rs +++ b/src/query/sql/src/planner/optimizer/ir/expr/extract.rs @@ -45,7 +45,7 @@ pub enum Matcher { impl Matcher { /// Check if the `SExpr` can be matched by the `Matcher`. - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn matches(&self, s_expr: &SExpr) -> bool { match self { Matcher::MatchOp { op_type, children } => { @@ -170,7 +170,7 @@ impl PatternExtractor { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn extract_group( &mut self, memo: &Memo, @@ -256,7 +256,7 @@ impl PatternExtractor { /// Expand a `Pattern` node to an arbitrary `SExpr` with `m_expr` as the root. /// Since we don't care about the actual content of the `Pattern` node, we will /// choose the first `MExpr` in each group to construct the `SExpr`. - #[recursive::recursive] + #[stacksafe::stacksafe] fn expand_pattern(memo: &Memo, m_expr: &MExpr) -> Result { let mut children = Vec::with_capacity(m_expr.arity()); for child in m_expr.children.iter() { diff --git a/src/query/sql/src/planner/optimizer/ir/expr/s_expr.rs b/src/query/sql/src/planner/optimizer/ir/expr/s_expr.rs index 045e8f5fc78ad..39f7c10791605 100644 --- a/src/query/sql/src/planner/optimizer/ir/expr/s_expr.rs +++ b/src/query/sql/src/planner/optimizer/ir/expr/s_expr.rs @@ -38,11 +38,11 @@ use crate::plans::RelOperator; /// `SExpr` is abbreviation of single expression, which is a tree of relational operators. #[derive(Educe)] #[educe( - PartialEq(bound = false, attrs = "#[recursive::recursive]"), + PartialEq(bound = false, attrs = "#[stacksafe::stacksafe]"), Eq, - Hash(bound = false, attrs = "#[recursive::recursive]"), - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") + Hash(bound = false, attrs = "#[stacksafe::stacksafe]"), + Clone(bound = false, attrs = "#[stacksafe::stacksafe]"), + Debug(bound = false, attrs = "#[stacksafe::stacksafe]") )] pub struct SExpr { pub plan: Arc, @@ -251,12 +251,12 @@ impl SExpr { } /// Check if contain subquery - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn has_subquery(&self) -> bool { self.plan.has_subquery() || self.children.iter().any(|child| child.has_subquery()) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn support_lazy_materialize(&self) -> bool { self.plan.support_lazy_materialize() && self @@ -265,7 +265,7 @@ impl SExpr { .all(|child| child.support_lazy_materialize()) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn get_udfs(&self) -> Result> { let mut udfs = HashSet::new(); let iter = self.plan.scalar_expr_iter(); @@ -284,7 +284,7 @@ impl SExpr { Ok(udfs) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn get_udfs_col_ids(&self) -> Result> { let mut udf_ids = BTreeSet::new(); if let RelOperator::Udf(udf) = self.plan.as_ref() { @@ -350,7 +350,7 @@ impl SExpr { } // The method will clear the applied rules of current SExpr and its children. - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn clear_applied_rules(&mut self) { self.applied_rules.clear(); let children = self @@ -364,7 +364,7 @@ impl SExpr { self.children = children; } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn has_merge_exchange(&self) -> bool { if let RelOperator::Exchange(Exchange::Merge) = self.plan.as_ref() { return true; diff --git a/src/query/sql/src/planner/optimizer/ir/expr/visitor.rs b/src/query/sql/src/planner/optimizer/ir/expr/visitor.rs index 8261213c1467e..1dbeee87f3827 100644 --- a/src/query/sql/src/planner/optimizer/ir/expr/visitor.rs +++ b/src/query/sql/src/planner/optimizer/ir/expr/visitor.rs @@ -120,7 +120,7 @@ pub trait SExprVisitor { } /// Traverse an expression tree using a synchronous visitor -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn visit_sexpr(visitor: &mut V, expr: &SExpr) -> Result> { // Pre-order visit match visitor.visit(expr)? { @@ -185,7 +185,7 @@ pub trait AsyncSExprVisitor { /// Traverse an expression tree using an async visitor #[allow(clippy::multiple_bound_locations)] -#[async_recursion::async_recursion(# [recursive::recursive])] +#[async_recursion::async_recursion(# [stacksafe::stacksafe])] pub async fn visit_sexpr_async( visitor: &mut T, expr: &SExpr, diff --git a/src/query/sql/src/planner/optimizer/ir/memo.rs b/src/query/sql/src/planner/optimizer/ir/memo.rs index 7b4a81605da10..29450c38e4e60 100644 --- a/src/query/sql/src/planner/optimizer/ir/memo.rs +++ b/src/query/sql/src/planner/optimizer/ir/memo.rs @@ -75,7 +75,7 @@ impl Memo { Ok(()) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn insert(&mut self, target_group: Option, s_expr: SExpr) -> Result { let mut children_group = vec![]; for child in s_expr.children() { diff --git a/src/query/sql/src/planner/optimizer/ir/property/builder.rs b/src/query/sql/src/planner/optimizer/ir/property/builder.rs index 01af90a4c2551..58d3e2a26534a 100644 --- a/src/query/sql/src/planner/optimizer/ir/property/builder.rs +++ b/src/query/sql/src/planner/optimizer/ir/property/builder.rs @@ -66,7 +66,7 @@ impl<'a> RelExpr<'a> { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn derive_relational_prop(&self) -> Result> { match self { RelExpr::SExpr { expr } => expr.derive_relational_prop(), @@ -94,7 +94,7 @@ impl<'a> RelExpr<'a> { } // Derive cardinality and statistics - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn derive_cardinality(&self) -> Result> { match self { RelExpr::SExpr { expr } => { @@ -122,7 +122,7 @@ impl<'a> RelExpr<'a> { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn derive_physical_prop(&self) -> Result { let plan = match self { RelExpr::SExpr { expr } => expr.plan(), diff --git a/src/query/sql/src/planner/optimizer/ir/property/enforcer.rs b/src/query/sql/src/planner/optimizer/ir/property/enforcer.rs index 5892184a24826..fecdaa9b2476c 100644 --- a/src/query/sql/src/planner/optimizer/ir/property/enforcer.rs +++ b/src/query/sql/src/planner/optimizer/ir/property/enforcer.rs @@ -91,7 +91,7 @@ impl PropertyEnforcer { } /// Require and enforce physical property from a physical `SExpr` - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn require_property(&self, required: &RequiredProperty, s_expr: &SExpr) -> Result { // First, we will require the child SExpr with input `RequiredProperty`. let children = s_expr diff --git a/src/query/sql/src/planner/optimizer/optimizer.rs b/src/query/sql/src/planner/optimizer/optimizer.rs index 4c203d87cc902..8128d1bb177d7 100644 --- a/src/query/sql/src/planner/optimizer/optimizer.rs +++ b/src/query/sql/src/planner/optimizer/optimizer.rs @@ -59,7 +59,7 @@ use crate::plans::RelOperator; use crate::plans::SetScalarsOrQuery; #[fastrace::trace] -#[async_recursion(# [recursive::recursive])] +#[async_recursion(# [stacksafe::stacksafe])] pub async fn optimize(opt_ctx: Arc, plan: Plan) -> Result { match plan { Plan::Query { diff --git a/src/query/sql/src/planner/optimizer/optimizers/cascades/cascade.rs b/src/query/sql/src/planner/optimizer/optimizers/cascades/cascade.rs index 20c8eae11dde3..ade5b78f1775a 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/cascades/cascade.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/cascades/cascade.rs @@ -85,7 +85,7 @@ impl CascadesOptimizer { Ok(()) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize_sync(&mut self, s_expr: SExpr) -> Result { let opt_ctx = self.opt_ctx.clone(); @@ -261,7 +261,7 @@ impl CascadesOptimizer { Ok(()) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn find_best_plan( &self, group_index: IndexType, diff --git a/src/query/sql/src/planner/optimizer/optimizers/cte_filter_pushdown.rs b/src/query/sql/src/planner/optimizer/optimizers/cte_filter_pushdown.rs index 3a148253b9b71..0c047de80d013 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/cte_filter_pushdown.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/cte_filter_pushdown.rs @@ -62,7 +62,7 @@ impl CTEFilterPushdownOptimizer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn collect_filters(&mut self, s_expr: &SExpr) -> Result<()> { if let RelOperator::Filter(filter) = s_expr.plan() { let child = s_expr.child(0)?; @@ -116,7 +116,7 @@ impl CTEFilterPushdownOptimizer { Ok(()) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn add_filters_to_ctes(&self, s_expr: &SExpr) -> Result { let new_children = s_expr .children() diff --git a/src/query/sql/src/planner/optimizer/optimizers/distributed/distributed.rs b/src/query/sql/src/planner/optimizer/optimizers/distributed/distributed.rs index da6060d7c1e3c..42b116c171170 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/distributed/distributed.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/distributed/distributed.rs @@ -45,7 +45,7 @@ impl DistributedOptimizer { } /// Optimize the given SExpr for distributed execution - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize(&self, s_expr: &SExpr) -> Result { // Step 1: Set the initial distribution requirement (Any) let required = RequiredProperty { diff --git a/src/query/sql/src/planner/optimizer/optimizers/distributed/sort_and_limit.rs b/src/query/sql/src/planner/optimizer/optimizers/distributed/sort_and_limit.rs index aedcf40d245c4..4d7a81e533a13 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/distributed/sort_and_limit.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/distributed/sort_and_limit.rs @@ -87,7 +87,7 @@ impl SortAndLimitPushDownOptimizer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize(&self, s_expr: &SExpr) -> Result { let mut replaced_children = Vec::with_capacity(s_expr.arity()); for child in s_expr.children.iter() { diff --git a/src/query/sql/src/planner/optimizer/optimizers/hyper_dp/dphyp.rs b/src/query/sql/src/planner/optimizer/optimizers/hyper_dp/dphyp.rs index 5c479b2def710..a2017550ee8c3 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/hyper_dp/dphyp.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/hyper_dp/dphyp.rs @@ -371,7 +371,7 @@ impl DPhpyOptimizer { } /// Traverse the s_expr and get all base relations and join conditions - #[async_recursion::async_recursion(# [recursive::recursive])] + #[async_recursion::async_recursion(# [stacksafe::stacksafe])] async fn get_base_relations( &mut self, s_expr: &SExpr, @@ -914,7 +914,7 @@ impl DPhpyOptimizer { /// The second parameter is a set which is connected and must be extended until a valid csg-cmp-pair is reached. /// Therefore, it considers the neighborhood of right. - #[async_recursion::async_recursion(# [recursive::recursive])] + #[async_recursion::async_recursion(# [stacksafe::stacksafe])] async fn enumerate_cmp_rec( &mut self, left: &[IndexType], @@ -966,7 +966,7 @@ impl DPhpyOptimizer { /// EnumerateCsgRec will extend the given `nodes`. /// It'll consider each non-empty, proper subset of the neighborhood of nodes that are not forbidden. - #[async_recursion::async_recursion(# [recursive::recursive])] + #[async_recursion::async_recursion(# [stacksafe::stacksafe])] async fn enumerate_csg_rec( &mut self, nodes: &[IndexType], @@ -1068,7 +1068,7 @@ impl DPhpyOptimizer { /// Replace the join expression in the plan tree #[allow(clippy::only_used_in_recursion)] - #[recursive::recursive] + #[stacksafe::stacksafe] fn replace_join_expr(&self, join_expr: &SExpr, s_expr: &SExpr) -> Result { match s_expr.plan.as_ref() { RelOperator::Join(_) => { diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/normalize_aggregate.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/normalize_aggregate.rs index fda9b047ce8df..5deef9cd3a065 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/normalize_aggregate.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/normalize_aggregate.rs @@ -38,7 +38,7 @@ impl RuleNormalizeAggregateOptimizer { RuleNormalizeAggregateOptimizer {} } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize_sync(&self, s_expr: &SExpr) -> Result { let mut children = Vec::with_capacity(s_expr.arity()); for child in s_expr.children() { diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/stats_aggregate.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/stats_aggregate.rs index 21a24d3579d59..9c9b51f49adb9 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/stats_aggregate.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/aggregate/stats_aggregate.rs @@ -50,7 +50,7 @@ impl RuleStatsAggregateOptimizer { } } - #[async_recursion::async_recursion(#[recursive::recursive])] + #[async_recursion::async_recursion(#[stacksafe::stacksafe])] pub async fn optimize_async(&self, s_expr: &SExpr) -> Result { let mut children = Vec::with_capacity(s_expr.arity()); for child in s_expr.children() { diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/cte/cleanup_unused_cte.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/cte/cleanup_unused_cte.rs index a2e23c8dee34a..ed282493ab357 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/cte/cleanup_unused_cte.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/cte/cleanup_unused_cte.rs @@ -35,7 +35,7 @@ impl CleanupUnusedCTEOptimizer { } /// Recursively traverse the expression tree to find MaterializeCTERef nodes and count references - #[recursive::recursive] + #[stacksafe::stacksafe] fn collect_referenced_ctes_recursive( s_expr: &SExpr, referenced_ctes: &mut HashMap, @@ -56,7 +56,7 @@ impl CleanupUnusedCTEOptimizer { } /// Remove unused CTEs from the expression tree and update ref_count - #[recursive::recursive] + #[stacksafe::stacksafe] fn remove_unused_ctes( s_expr: &SExpr, referenced_ctes: &HashMap, diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs index e34d53ab76f62..33c293458d87c 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs @@ -53,7 +53,7 @@ use crate::plans::UnionAll; use crate::plans::Window; impl SubqueryDecorrelatorOptimizer { - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn flatten_plan( &mut self, outer: &SExpr, diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_scalar.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_scalar.rs index be1f09fae49c4..28f531bb658a0 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_scalar.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_scalar.rs @@ -27,7 +27,7 @@ use crate::plans::ScalarExpr; use crate::plans::UDFCall; impl SubqueryDecorrelatorOptimizer { - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn flatten_scalar( &mut self, scalar: &ScalarExpr, diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/subquery_decorrelator.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/subquery_decorrelator.rs index ce4b515e3affb..55fc4cb95aa51 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/subquery_decorrelator.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/subquery_decorrelator.rs @@ -169,7 +169,7 @@ impl SubqueryDecorrelatorOptimizer { /// Correlated exists subquery -> Marker join /// /// More information can be found in the paper: Unnesting Arbitrary Queries - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize_sync(&mut self, s_expr: &SExpr) -> Result { // If there is no subquery, return directly if !s_expr.has_subquery() { @@ -343,6 +343,7 @@ impl SubqueryDecorrelatorOptimizer { /// Try to extract subquery from a scalar expression. Returns replaced scalar expression /// and the outer s_expr. + #[stacksafe::stacksafe] fn try_rewrite_subquery( &mut self, scalar: &ScalarExpr, diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/deduplicate_join_condition.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/deduplicate_join_condition.rs index 6415b8d83f35a..29862484c9279 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/deduplicate_join_condition.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/deduplicate_join_condition.rs @@ -103,7 +103,7 @@ impl DeduplicateJoinConditionOptimizer { self.deduplicate(s_expr) } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn deduplicate(&mut self, s_expr: &SExpr) -> Result { match s_expr.plan.as_ref() { // Only optimize filtering joins that don't preserve nulls diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/infer_filter.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/infer_filter.rs index 1445c68387fe6..dee4132c21e94 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/infer_filter.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/infer_filter.rs @@ -169,7 +169,7 @@ impl<'a> InferFilterOptimizer<'a> { Ok(new_predicates) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn add_expr( &mut self, expr: &ScalarExpr, @@ -766,7 +766,7 @@ impl<'a> InferFilterOptimizer<'a> { } impl VisitorMut<'_> for ReplaceScalarExpr<'_> { - #[recursive::recursive] + #[stacksafe::stacksafe] fn visit(&mut self, expr: &mut ScalarExpr) -> Result<()> { if let Some(index) = self.expr_index.get(expr) { let equal_to = &self.expr_equal_to[*index]; diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/normalize_disjunctive_filter.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/normalize_disjunctive_filter.rs index c15f3dd01ba2f..bb4464fb01583 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/normalize_disjunctive_filter.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/normalize_disjunctive_filter.rs @@ -56,7 +56,7 @@ enum PredicateScalar { Other(Box), } -#[recursive::recursive] +#[stacksafe::stacksafe] fn predicate_scalar(scalar: &ScalarExpr) -> PredicateScalar { match scalar { ScalarExpr::FunctionCall(func) if func.func_name == "and" => { @@ -105,7 +105,7 @@ fn predicate_scalar(scalar: &ScalarExpr) -> PredicateScalar { } } -#[recursive::recursive] +#[stacksafe::stacksafe] fn normalize_predicate_scalar(predicate_scalar: PredicateScalar) -> ScalarExpr { match predicate_scalar { PredicateScalar::And(args) => { @@ -140,7 +140,7 @@ fn normalize_predicate_scalar(predicate_scalar: PredicateScalar) -> ScalarExpr { } } -#[recursive::recursive] +#[stacksafe::stacksafe] fn rewrite_predicate_ors(predicate: PredicateScalar) -> PredicateScalar { match predicate { PredicateScalar::Or(args) => { diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/pull_up_filter.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/pull_up_filter.rs index 73b6a89775e7c..80c9e66d11e7c 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/filter/pull_up_filter.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/filter/pull_up_filter.rs @@ -50,7 +50,7 @@ impl PullUpFilterOptimizer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize_sync(&mut self, s_expr: &SExpr) -> Result { let mut s_expr = self.pull_up(s_expr)?; s_expr = self.finish(s_expr)?; @@ -71,7 +71,7 @@ impl PullUpFilterOptimizer { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn pull_up(&mut self, s_expr: &SExpr) -> Result { match s_expr.plan.as_ref() { RelOperator::Filter(filter) => self.pull_up_filter(s_expr, filter), @@ -164,7 +164,7 @@ impl PullUpFilterOptimizer { Ok(s_expr.replace_children(children)) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn replace_predicate( predicate: &mut ScalarExpr, items: &mut Vec, diff --git a/src/query/sql/src/planner/optimizer/optimizers/operator/join/single_to_inner.rs b/src/query/sql/src/planner/optimizer/optimizers/operator/join/single_to_inner.rs index 43988f17b2099..4c17e6fe8a0ce 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/operator/join/single_to_inner.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/operator/join/single_to_inner.rs @@ -33,7 +33,7 @@ impl SingleToInnerOptimizer { Self::single_to_inner(s_expr) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn single_to_inner(s_expr: &SExpr) -> Result { let mut s_expr = if let RelOperator::Join(join) = s_expr.plan.as_ref() && join.single_to_inner.is_some() diff --git a/src/query/sql/src/planner/optimizer/optimizers/recursive/recursive.rs b/src/query/sql/src/planner/optimizer/optimizers/recursive/recursive.rs index 34409cacd1180..414fcd4657e88 100644 --- a/src/query/sql/src/planner/optimizer/optimizers/recursive/recursive.rs +++ b/src/query/sql/src/planner/optimizer/optimizers/recursive/recursive.rs @@ -44,12 +44,12 @@ impl RecursiveRuleOptimizer { } /// Run the optimizer on the given expression. - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn optimize_sync(&self, s_expr: &SExpr) -> Result { self.optimize_expression(s_expr) } - #[recursive::recursive] + #[stacksafe::stacksafe] fn optimize_expression(&self, s_expr: &SExpr) -> Result { let mut current = s_expr.clone(); diff --git a/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs b/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs index f00cffbba50c0..d9b2c702e203b 100644 --- a/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs +++ b/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs @@ -53,7 +53,7 @@ impl CollectStatisticsOptimizer { self.collect(s_expr).await } - #[async_recursion::async_recursion(#[recursive::recursive])] + #[async_recursion::async_recursion(#[stacksafe::stacksafe])] pub async fn collect(&mut self, s_expr: &SExpr) -> Result { match s_expr.plan.as_ref() { RelOperator::Scan(scan) => { diff --git a/src/query/sql/src/planner/plans/operator.rs b/src/query/sql/src/planner/plans/operator.rs index e2db3ed60eb05..6825b06793b38 100644 --- a/src/query/sql/src/planner/plans/operator.rs +++ b/src/query/sql/src/planner/plans/operator.rs @@ -140,11 +140,11 @@ pub enum RelOp { /// Relational operators #[derive(Educe, EnumAsInner)] #[educe( - PartialEq(bound = false, attrs = "#[recursive::recursive]"), + PartialEq(bound = false, attrs = "#[stacksafe::stacksafe]"), Eq, - Hash(bound = false, attrs = "#[recursive::recursive]"), - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") + Hash(bound = false, attrs = "#[stacksafe::stacksafe]"), + Clone(bound = false, attrs = "#[stacksafe::stacksafe]"), + Debug(bound = false, attrs = "#[stacksafe::stacksafe]") )] pub enum RelOperator { Scan(Scan), diff --git a/src/query/sql/src/planner/plans/plan.rs b/src/query/sql/src/planner/plans/plan.rs index b33500bf3124e..2292c6c6c2396 100644 --- a/src/query/sql/src/planner/plans/plan.rs +++ b/src/query/sql/src/planner/plans/plan.rs @@ -191,13 +191,13 @@ use crate::plans::row_access_policy::CreateRowAccessPolicyPlan; #[derive(Educe)] #[educe( - Clone(bound = false, attrs = "#[recursive::recursive]"), - Debug(bound = false, attrs = "#[recursive::recursive]") + Clone(bound = false, attrs = "#[stacksafe::stacksafe]"), + Debug(bound = false, attrs = "#[stacksafe::stacksafe]") )] pub enum Plan { // `SELECT` statement Query { - s_expr: Box, + s_expr: StackWrapper>, metadata: MetadataRef, bind_context: Box, rewrite_kind: Option, @@ -309,7 +309,7 @@ pub enum Plan { OptimizePurge(Box), OptimizeCompactSegment(Box), OptimizeCompactBlock { - s_expr: Box, + s_expr: StackWrapper>, need_purge: bool, }, @@ -318,7 +318,7 @@ pub enum Plan { InsertMultiTable(Box), Replace(Box), DataMutation { - s_expr: Box, + s_expr: StackWrapper>, schema: DataSchemaRef, metadata: MetadataRef, }, diff --git a/src/query/sql/src/planner/plans/recluster.rs b/src/query/sql/src/planner/plans/recluster.rs index 796520f0273bc..da2992ef44fb6 100644 --- a/src/query/sql/src/planner/plans/recluster.rs +++ b/src/query/sql/src/planner/plans/recluster.rs @@ -95,7 +95,7 @@ pub async fn plan_hilbert_sql( } pub fn replace_with_constant(expr: &SExpr, variables: &VecDeque, partitions: u16) -> SExpr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn visit_expr_column(expr: &mut ScalarExpr, variables: &mut VecDeque) { if let ScalarExpr::FunctionCall(call) = expr { match call.func_name.as_str() { @@ -119,7 +119,7 @@ pub fn replace_with_constant(expr: &SExpr, variables: &VecDeque, partiti } } - #[recursive::recursive] + #[stacksafe::stacksafe] fn replace_with_constant_into_child( s_expr: &SExpr, variables: &mut VecDeque, diff --git a/src/query/sql/src/planner/plans/scalar_expr.rs b/src/query/sql/src/planner/plans/scalar_expr.rs index 7a1fe6cd3147b..643ade4bfae84 100644 --- a/src/query/sql/src/planner/plans/scalar_expr.rs +++ b/src/query/sql/src/planner/plans/scalar_expr.rs @@ -77,7 +77,7 @@ pub enum ScalarExpr { } impl Clone for ScalarExpr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn clone(&self) -> Self { match self { ScalarExpr::BoundColumnRef(v) => ScalarExpr::BoundColumnRef(v.clone()), @@ -102,7 +102,7 @@ impl Clone for ScalarExpr { impl Eq for ScalarExpr {} impl PartialEq for ScalarExpr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn eq(&self, other: &Self) -> bool { match (self, other) { (ScalarExpr::BoundColumnRef(l), ScalarExpr::BoundColumnRef(r)) => { @@ -125,7 +125,7 @@ impl PartialEq for ScalarExpr { } impl Hash for ScalarExpr { - #[recursive::recursive] + #[stacksafe::stacksafe] fn hash(&self, state: &mut H) { match self { ScalarExpr::BoundColumnRef(v) => { @@ -1386,7 +1386,7 @@ pub trait Visitor<'a>: Sized { } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a ScalarExpr) -> Result<()> { match expr { ScalarExpr::BoundColumnRef(expr) => visitor.visit_bound_column_ref(expr), @@ -1405,7 +1405,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a ScalarExpr) -> R } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn walk_window<'a, V: Visitor<'a>>(visitor: &mut V, window: &'a WindowFunc) -> Result<()> { for expr in &window.partition_by { visitor.visit(expr)?; @@ -1499,7 +1499,7 @@ pub trait VisitorMut<'a>: Sized { } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn walk_expr_mut<'a, V: VisitorMut<'a>>( visitor: &mut V, expr: &'a mut ScalarExpr, @@ -1521,7 +1521,7 @@ pub fn walk_expr_mut<'a, V: VisitorMut<'a>>( } } -#[recursive::recursive] +#[stacksafe::stacksafe] pub fn walk_window_mut<'a, V: VisitorMut<'a>>( visitor: &mut V, window: &'a mut WindowFunc, diff --git a/src/query/sql/src/planner/semantic/async_function_rewriter.rs b/src/query/sql/src/planner/semantic/async_function_rewriter.rs index c8ae308128ced..fb088a5c95192 100644 --- a/src/query/sql/src/planner/semantic/async_function_rewriter.rs +++ b/src/query/sql/src/planner/semantic/async_function_rewriter.rs @@ -59,7 +59,7 @@ impl AsyncFunctionRewriter { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn rewrite(&mut self, s_expr: &SExpr) -> Result { let mut s_expr = s_expr.clone(); if !s_expr.children.is_empty() { diff --git a/src/query/sql/src/planner/semantic/lowering.rs b/src/query/sql/src/planner/semantic/lowering.rs index 763e08678435f..e7a7b190ad10c 100644 --- a/src/query/sql/src/planner/semantic/lowering.rs +++ b/src/query/sql/src/planner/semantic/lowering.rs @@ -172,7 +172,7 @@ impl TypeCheck for ScalarExpr { impl ScalarExpr { /// Lowering `Scalar` into `RawExpr` to utilize with `common_expression::types::type_check`. /// Specific variants will be replaced with a `RawExpr::ColumnRef` with a dummy name. - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn as_raw_expr(&self) -> RawExpr { match self { ScalarExpr::BoundColumnRef(column_ref) => RawExpr::ColumnRef { diff --git a/src/query/sql/src/planner/semantic/type_check.rs b/src/query/sql/src/planner/semantic/type_check.rs index 15522eeb02852..c55bb8189d877 100644 --- a/src/query/sql/src/planner/semantic/type_check.rs +++ b/src/query/sql/src/planner/semantic/type_check.rs @@ -282,7 +282,7 @@ impl<'a> TypeChecker<'a> { self.skip_sequence_check = skip; } - #[recursive::recursive] + #[stacksafe::stacksafe] pub fn resolve(&mut self, expr: &Expr) -> Result> { let box (scalar, data_type): Box<(ScalarExpr, DataType)> = match expr { Expr::ColumnRef { diff --git a/src/query/sql/src/planner/semantic/udf_rewriter.rs b/src/query/sql/src/planner/semantic/udf_rewriter.rs index 5ac7116509390..82c99e73d16e1 100644 --- a/src/query/sql/src/planner/semantic/udf_rewriter.rs +++ b/src/query/sql/src/planner/semantic/udf_rewriter.rs @@ -66,7 +66,7 @@ impl UdfRewriter { } } - #[recursive::recursive] + #[stacksafe::stacksafe] pub(crate) fn rewrite(&mut self, s_expr: &SExpr) -> Result { let mut s_expr = s_expr.clone(); if !s_expr.children.is_empty() { diff --git a/src/query/storages/hive/hive/Cargo.toml b/src/query/storages/hive/hive/Cargo.toml index 0f985c7c5add2..252f5201be6e6 100644 --- a/src/query/storages/hive/hive/Cargo.toml +++ b/src/query/storages/hive/hive/Cargo.toml @@ -32,8 +32,8 @@ hive_metastore = { workspace = true } log = { workspace = true } opendal = { workspace = true } parquet = { workspace = true } -recursive = { workspace = true } serde = { workspace = true } +stacksafe = { workspace = true } typetag = { workspace = true } volo-thrift = { workspace = true } diff --git a/src/query/storages/hive/hive/src/hive_table.rs b/src/query/storages/hive/hive/src/hive_table.rs index 197e6be5eb6bc..6af1ae8823102 100644 --- a/src/query/storages/hive/hive/src/hive_table.rs +++ b/src/query/storages/hive/hive/src/hive_table.rs @@ -566,7 +566,7 @@ pub fn convert_hdfs_path(hdfs_path: &str, is_dir: bool) -> String { format_path } -#[async_recursion(#[recursive::recursive])] +#[async_recursion(#[stacksafe::stacksafe])] async fn list_files_from_dir( operator: Operator, location: String, diff --git a/tests/sqllogictests/Cargo.toml b/tests/sqllogictests/Cargo.toml index 8da56c70f5ffe..6c51409909bec 100644 --- a/tests/sqllogictests/Cargo.toml +++ b/tests/sqllogictests/Cargo.toml @@ -25,13 +25,13 @@ env_logger = { workspace = true } futures-util = { workspace = true } mysql_async = { workspace = true } rand = { workspace = true } -recursive = { workspace = true } redis = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sqllogictest = { workspace = true } +stacksafe = { workspace = true } testcontainers = { workspace = true } testcontainers-modules = { workspace = true } thiserror = { workspace = true } diff --git a/tests/sqllogictests/src/main.rs b/tests/sqllogictests/src/main.rs index 9f78a09fcfbab..4afc760a82911 100644 --- a/tests/sqllogictests/src/main.rs +++ b/tests/sqllogictests/src/main.rs @@ -228,7 +228,7 @@ async fn run_hybrid_client( } // Create new databend with client type -#[async_recursion::async_recursion(#[recursive::recursive])] +#[async_recursion::async_recursion(#[stacksafe::stacksafe])] async fn create_databend(client_type: &ClientType, filename: &str) -> Result { let mut client: Client; let args = SqlLogicTestArgs::parse();