diff --git a/src/frontend/src/binder/bind_context.rs b/src/frontend/src/binder/bind_context.rs index cb81b445f96e0..309bf9b43c105 100644 --- a/src/frontend/src/binder/bind_context.rs +++ b/src/frontend/src/binder/bind_context.rs @@ -92,6 +92,13 @@ pub enum BindingCteState { Bound { query: BoundQuery }, } +#[derive(Clone, Debug)] +pub struct BindingCte { + pub share_id: ShareId, + pub state: BindingCteState, + pub alias: TableAlias, +} + #[derive(Default, Debug, Clone)] pub struct BindContext { // Columns of all tables. @@ -106,7 +113,7 @@ pub struct BindContext { pub column_group_context: ColumnGroupContext, /// Map the cte's name to its binding state. /// The `ShareId` of the value is used to help the planner identify the share plan. - pub cte_to_relation: HashMap>>, + pub cte_to_relation: HashMap>>, /// Current lambda functions's arguments pub lambda_args: Option>, } diff --git a/src/frontend/src/binder/query.rs b/src/frontend/src/binder/query.rs index c83d70cd9cf18..ef957225c7b47 100644 --- a/src/frontend/src/binder/query.rs +++ b/src/frontend/src/binder/query.rs @@ -27,6 +27,7 @@ use thiserror_ext::AsReport; use super::bind_context::BindingCteState; use super::statement::RewriteExprsRecursive; use super::BoundValues; +use crate::binder::bind_context::BindingCte; use crate::binder::{Binder, BoundSetExpr}; use crate::error::{ErrorCode, Result}; use crate::expr::{CorrelatedId, Depth, ExprImpl, ExprRewriter}; @@ -333,11 +334,11 @@ impl Binder { .context .cte_to_relation .entry(table_name) - .insert_entry(Rc::new(RefCell::new(( + .insert_entry(Rc::new(RefCell::new(BindingCte { share_id, - BindingCteState::Init, + state: BindingCteState::Init, alias, - )))) + }))) .get() .clone(); @@ -346,9 +347,11 @@ impl Binder { } // We assume `left` is base term, otherwise the implementation may be very hard. + // The behavior is same as PostgreSQL. + // https://www.postgresql.org/docs/16/sql-select.html#:~:text=the%20recursive%20self%2Dreference%20must%20appear%20on%20the%20right%2Dhand%20side%20of%20the%20UNION let bound_base = self.bind_set_expr(*left)?; - entry.borrow_mut().1 = BindingCteState::BaseResolved { + entry.borrow_mut().state = BindingCteState::BaseResolved { schema: bound_base.schema().clone(), }; @@ -366,16 +369,16 @@ impl Binder { extra_order_exprs: vec![], }; - entry.borrow_mut().1 = BindingCteState::Bound { query: bound_query }; + entry.borrow_mut().state = BindingCteState::Bound { query: bound_query }; } else { let bound_query = self.bind_query(query)?; self.context.cte_to_relation.insert( table_name, - Rc::new(RefCell::new(( + Rc::new(RefCell::new(BindingCte { share_id, - BindingCteState::Bound { query: bound_query }, + state: BindingCteState::Bound { query: bound_query }, alias, - ))), + })), ); } } diff --git a/src/frontend/src/binder/relation/mod.rs b/src/frontend/src/binder/relation/mod.rs index a70323add1322..d8d6ad7df08bc 100644 --- a/src/frontend/src/binder/relation/mod.rs +++ b/src/frontend/src/binder/relation/mod.rs @@ -28,7 +28,7 @@ use thiserror_ext::AsReport; use self::cte_ref::BoundBackCteRef; use super::bind_context::ColumnBinding; use super::statement::RewriteExprsRecursive; -use crate::binder::bind_context::BindingCteState; +use crate::binder::bind_context::{BindingCte, BindingCteState}; use crate::binder::Binder; use crate::error::{ErrorCode, Result, RwError}; use crate::expr::{ExprImpl, InputRef}; @@ -347,7 +347,11 @@ impl Binder { { // Handles CTE - let (share_id, cte_state, mut original_alias) = item.deref().borrow().clone(); + let BindingCte { + share_id, + state: cte_state, + alias: mut original_alias, + } = item.deref().borrow().clone(); debug_assert_eq!(original_alias.name.real_value(), table_name); // The original CTE alias ought to be its table name. if let Some(from_alias) = alias {