@@ -16,7 +16,7 @@ use super::select::{
1616 BindPlanAggregated , BindPlanComplete , BindPlanDistinct , BindPlanFiltered , BindPlanFrom ,
1717 BindPlanProjected , BindPlanSelectList , BindPlanStart , JoinConstraintInput , TableAliasInput ,
1818} ;
19- use super :: { is_valid_identifier, with_query_bind_step , Binder , QueryBindStep , SetOperatorKind } ;
19+ use super :: { is_valid_identifier, Binder , CteBinding , QueryBindStep , SetOperatorKind } ;
2020#[ cfg( feature = "copy" ) ]
2121use crate :: binder:: copy:: { ExtSource , FileFormat } ;
2222use crate :: catalog:: { ColumnCatalog , ColumnDesc , ColumnRef , TableName } ;
@@ -34,6 +34,7 @@ use crate::planner::operator::alter_table::change_column::{DefaultChange, NotNul
3434use crate :: planner:: operator:: join:: { JoinCondition , JoinOperator as LJoinOperator , JoinType } ;
3535use crate :: planner:: operator:: mark_apply:: MarkApplyQuantifier ;
3636use crate :: planner:: operator:: project:: ProjectOperator ;
37+ use crate :: planner:: operator:: recursive_cte:: { RecursiveCteOperator , RecursiveScanOperator } ;
3738use crate :: planner:: operator:: sort:: SortField ;
3839use crate :: planner:: operator:: Operator ;
3940use crate :: planner:: { Childrens , LogicalPlan , PlanArena } ;
@@ -2832,15 +2833,171 @@ impl<'a, 'parent, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<
28322833 Ok ( select_items)
28332834 }
28342835
2836+ fn bind_cte_plan (
2837+ & mut self ,
2838+ cte : & sqlparser:: ast:: Cte ,
2839+ alias : & TableAliasInput ,
2840+ arena : & mut PlanArena ,
2841+ ) -> Result < LogicalPlan , DatabaseError > {
2842+ let mut binder = Binder :: new ( self . context . fork ( ) , self . args , Some ( & self . context ) ) ;
2843+ let plan = binder. bind_query ( & cte. query , arena) ?;
2844+ let source_name = arena. temp_table ( ) ;
2845+ binder. bind_alias ( plan, & alias. columns , alias. name . clone ( ) , source_name, arena)
2846+ }
2847+
2848+ fn add_cte_plan (
2849+ & mut self ,
2850+ table_name : TableName ,
2851+ plan : LogicalPlan ,
2852+ arena : & mut PlanArena ,
2853+ ) -> Result < ( ) , DatabaseError > {
2854+ let plan_ref = arena. alloc_plan ( plan) ;
2855+ self . context . add_cte ( CteBinding {
2856+ table_name,
2857+ depth : self . context . cte_depth ,
2858+ plan_ref,
2859+ } )
2860+ }
2861+
2862+ fn bind_recursive_cte_plan (
2863+ & mut self ,
2864+ cte : & sqlparser:: ast:: Cte ,
2865+ alias : & TableAliasInput ,
2866+ arena : & mut PlanArena ,
2867+ ) -> Result < LogicalPlan , DatabaseError > {
2868+ if cte. query . with . is_some ( )
2869+ || cte. query . order_by . is_some ( )
2870+ || cte. query . limit_clause . is_some ( )
2871+ {
2872+ return Err ( DatabaseError :: UnsupportedStmt (
2873+ "recursive CTE query clauses are not supported" . to_string ( ) ,
2874+ ) ) ;
2875+ }
2876+
2877+ let SetExpr :: SetOperation {
2878+ op : SetOperator :: Union ,
2879+ set_quantifier : SetQuantifier :: All ,
2880+ left,
2881+ right,
2882+ } = cte. query . body . as_ref ( )
2883+ else {
2884+ return Err ( DatabaseError :: UnsupportedStmt (
2885+ "recursive CTEs require a top-level UNION ALL" . to_string ( ) ,
2886+ ) ) ;
2887+ } ;
2888+
2889+ let mut anchor_binder = Binder :: new ( self . context . fork ( ) , self . args , Some ( & self . context ) ) ;
2890+ let anchor = anchor_binder. bind_set_expr ( left, arena) ?;
2891+ if anchor
2892+ . referenced_table ( )
2893+ . iter ( )
2894+ . any ( |table| table == & alias. name )
2895+ {
2896+ return Err ( DatabaseError :: UnsupportedStmt (
2897+ "the recursive CTE cannot be referenced by its anchor" . to_string ( ) ,
2898+ ) ) ;
2899+ }
2900+
2901+ let source_name = arena. temp_table ( ) ;
2902+ let mut anchor = anchor_binder. bind_alias (
2903+ anchor,
2904+ & alias. columns ,
2905+ alias. name . clone ( ) ,
2906+ source_name,
2907+ arena,
2908+ ) ?;
2909+ let schema = anchor. output_schema ( arena) . clone ( ) ;
2910+ let scan = LogicalPlan :: new (
2911+ Operator :: RecursiveScan ( RecursiveScanOperator {
2912+ schema_ref : schema. clone ( ) ,
2913+ } ) ,
2914+ Childrens :: None ,
2915+ ) ;
2916+
2917+ let cte_checkpoint = self . context . cte_checkpoint ( ) ;
2918+ self . add_cte_plan ( alias. name . clone ( ) , scan, arena) ?;
2919+ let recursive = {
2920+ let mut binder = Binder :: new ( self . context . fork ( ) , self . args , Some ( & self . context ) ) ;
2921+ binder. bind_set_expr ( right, arena)
2922+ } ;
2923+ self . context . restore_ctes ( cte_checkpoint) ;
2924+ let mut recursive = recursive?;
2925+
2926+ fn recursive_scan_count ( plan : & LogicalPlan ) -> usize {
2927+ usize:: from ( matches ! ( & plan. operator, Operator :: RecursiveScan ( _) ) )
2928+ + plan
2929+ . childrens
2930+ . iter ( )
2931+ . map ( recursive_scan_count)
2932+ . sum :: < usize > ( )
2933+ }
2934+
2935+ if recursive_scan_count ( & recursive) != 1 {
2936+ return Err ( DatabaseError :: UnsupportedStmt (
2937+ "the recursive term must reference its CTE exactly once" . to_string ( ) ,
2938+ ) ) ;
2939+ }
2940+
2941+ let recursive_schema = recursive. output_schema ( arena) ;
2942+ if schema. len ( ) != recursive_schema. len ( ) {
2943+ return Err ( DatabaseError :: MisMatch (
2944+ "the anchor column count" ,
2945+ "the recursive column count" ,
2946+ ) ) ;
2947+ }
2948+ if !schema
2949+ . iter ( )
2950+ . zip ( recursive_schema)
2951+ . all ( |( anchor, recursive) | {
2952+ arena. column ( * anchor) . datatype ( ) == arena. column ( * recursive) . datatype ( )
2953+ } )
2954+ {
2955+ return Err ( DatabaseError :: UnsupportedStmt (
2956+ "recursive CTE column types must match the anchor" . to_string ( ) ,
2957+ ) ) ;
2958+ }
2959+
2960+ Ok ( RecursiveCteOperator :: build ( schema, anchor, recursive) )
2961+ }
2962+
28352963 pub ( crate ) fn bind_query (
28362964 & mut self ,
28372965 query : & Query ,
28382966 arena : & mut PlanArena ,
28392967 ) -> Result < LogicalPlan , DatabaseError > {
28402968 let origin_step = self . context . step_now ( ) ;
2969+ let cte_checkpoint = self . context . cte_checkpoint ( ) ;
2970+ if let Some ( with) = & query. with {
2971+ if with. recursive && with. cte_tables . len ( ) != 1 {
2972+ return Err ( DatabaseError :: UnsupportedStmt (
2973+ "only one recursive CTE is supported" . to_string ( ) ,
2974+ ) ) ;
2975+ }
2976+
2977+ self . context . cte_depth += 1 ;
2978+ for cte in & with. cte_tables {
2979+ if cte. from . is_some ( ) {
2980+ return Err ( DatabaseError :: UnsupportedStmt (
2981+ "CTE FROM clauses are not supported" . to_string ( ) ,
2982+ ) ) ;
2983+ }
2984+ if matches ! (
2985+ cte. materialized,
2986+ Some ( sqlparser:: ast:: CteAsMaterialized :: Materialized )
2987+ ) {
2988+ return Err ( DatabaseError :: UnsupportedStmt (
2989+ "materialized CTEs are not supported" . to_string ( ) ,
2990+ ) ) ;
2991+ }
28412992
2842- if let Some ( _with) = & query. with {
2843- // TODO support with clause.
2993+ let alias = sql_table_alias ( cte. alias . clone ( ) ) ;
2994+ let plan = if with. recursive {
2995+ self . bind_recursive_cte_plan ( cte, & alias, arena) ?
2996+ } else {
2997+ self . bind_cte_plan ( cte, & alias, arena) ?
2998+ } ;
2999+ self . add_cte_plan ( alias. name , plan, arena) ?;
3000+ }
28443001 }
28453002
28463003 let order_by_exprs = if let Some ( order_by) = & query. order_by {
@@ -2883,6 +3040,7 @@ impl<'a, 'parent, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<
28833040 plan = self . bind_limit ( plan, limit_clause, arena) ?;
28843041 }
28853042
3043+ self . context . restore_ctes ( cte_checkpoint) ;
28863044 self . context . step ( origin_step) ;
28873045 Ok ( plan)
28883046 }
@@ -3160,6 +3318,36 @@ mod tests {
31603318 Ok ( ( ) )
31613319 }
31623320
3321+ #[ test]
3322+ fn test_bind_non_recursive_ctes ( ) -> Result < ( ) , DatabaseError > {
3323+ let tables = build_t1_table ( ) ?;
3324+ let mut arena = PlanArena :: new ( & tables. table_arena ) ;
3325+ let mut plan = tables. plan_with_arena (
3326+ "with first(a) as (select c1 from t1), \
3327+ second as (select a from first) select a from second",
3328+ & mut arena,
3329+ ) ?;
3330+
3331+ let schema = plan. output_schema ( & mut arena) ;
3332+ assert_eq ! ( schema. len( ) , 1 ) ;
3333+ assert_eq ! ( arena. column( schema[ 0 ] ) . name( ) , "a" ) ;
3334+
3335+ assert_unsupported (
3336+ tables
3337+ . plan ( "with recursive cte as (select 1) select * from cte" )
3338+ . unwrap_err ( ) ,
3339+ "recursive CTEs" ,
3340+ ) ;
3341+ assert_unsupported (
3342+ tables
3343+ . plan ( "with cte as (select 1), cte as (select 2) select * from cte" )
3344+ . unwrap_err ( ) ,
3345+ "duplicate CTE name" ,
3346+ ) ;
3347+
3348+ Ok ( ( ) )
3349+ }
3350+
31633351 #[ test]
31643352 fn force_nest_loop_join_marks_join_operator ( ) -> Result < ( ) , DatabaseError > {
31653353 let tables = build_t1_table ( ) ?;
0 commit comments