1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use std:: collections:: HashMap ;
1516use std:: sync:: Arc ;
1617
18+ use databend_common_ast:: ast:: ColumnDefinition ;
1719use databend_common_ast:: ast:: CreateOption ;
20+ use databend_common_ast:: ast:: CreateTableSource ;
1821use databend_common_ast:: ast:: CreateTableStmt ;
1922use databend_common_ast:: ast:: Engine ;
2023use databend_common_ast:: ast:: Expr ;
21- use databend_common_ast:: ast:: ExprReplacer ;
2224use databend_common_ast:: ast:: Identifier ;
2325use databend_common_ast:: ast:: Query ;
2426use databend_common_ast:: ast:: SetExpr ;
27+ use databend_common_ast:: ast:: TableReference ;
2528use databend_common_ast:: ast:: TableType ;
2629use databend_common_ast:: ast:: With ;
2730use databend_common_ast:: ast:: CTE ;
2831use databend_common_ast:: Span ;
2932use databend_common_catalog:: catalog:: CATALOG_DEFAULT ;
3033use databend_common_exception:: ErrorCode ;
3134use databend_common_exception:: Result ;
35+ use databend_common_expression:: types:: convert_to_type_name;
36+ use derive_visitor:: Drive ;
37+ use derive_visitor:: DriveMut ;
38+ use derive_visitor:: Visitor ;
39+ use derive_visitor:: VisitorMut ;
3240
3341use crate :: binder:: CteInfo ;
3442use crate :: normalize_identifier;
@@ -40,15 +48,42 @@ use crate::plans::BoundColumnRef;
4048use crate :: plans:: ScalarExpr ;
4149use crate :: plans:: Sort ;
4250use crate :: plans:: SortItem ;
51+ use crate :: NameResolutionContext ;
52+
53+ #[ derive( Debug , Default , Visitor ) ]
54+ #[ visitor( TableReference ( enter) ) ]
55+ struct CTERefCounter {
56+ cte_ref_count : HashMap < String , usize > ,
57+ name_resolution_ctx : NameResolutionContext ,
58+ }
59+
60+ impl CTERefCounter {
61+ fn enter_table_reference ( & mut self , table_ref : & TableReference ) {
62+ if let TableReference :: Table { table, .. } = table_ref {
63+ let table_name = normalize_identifier ( table, & self . name_resolution_ctx ) . name ;
64+ if let Some ( count) = self . cte_ref_count . get_mut ( & table_name) {
65+ * count += 1 ;
66+ }
67+ }
68+ }
69+ }
4370
4471impl Binder {
4572 pub ( crate ) fn bind_query (
4673 & mut self ,
4774 bind_context : & mut BindContext ,
4875 query : & Query ,
4976 ) -> Result < ( SExpr , BindContext ) > {
77+ let mut with = query. with . clone ( ) ;
78+ if self . ctx . get_settings ( ) . get_enable_auto_materialize_cte ( ) ? {
79+ if let Some ( with) = & mut with {
80+ if !with. recursive {
81+ self . auto_materialize_cte ( with, query) ?;
82+ }
83+ }
84+ }
5085 // Initialize cte map.
51- self . init_cte ( bind_context, & query . with ) ?;
86+ self . init_cte ( bind_context, & with) ?;
5287
5388 // Extract limit and offset from query.
5489 let ( limit, offset) = self . extract_limit_and_offset ( query) ?;
@@ -66,6 +101,35 @@ impl Binder {
66101 Ok ( ( s_expr, bind_context) )
67102 }
68103
104+ fn auto_materialize_cte ( & mut self , with : & mut With , query : & Query ) -> Result < ( ) > {
105+ // Initialize the count of each CTE to 0
106+ let mut cte_ref_count: HashMap < String , usize > = HashMap :: new ( ) ;
107+ for cte in with. ctes . iter ( ) {
108+ let table_name = self . normalize_identifier ( & cte. alias . name ) . name ;
109+ cte_ref_count. insert ( table_name, 0 ) ;
110+ }
111+
112+ // Count the number of times each CTE is referenced in the query
113+ let mut visitor = CTERefCounter {
114+ cte_ref_count,
115+ name_resolution_ctx : self . name_resolution_ctx . clone ( ) ,
116+ } ;
117+ query. drive ( & mut visitor) ;
118+ cte_ref_count = visitor. cte_ref_count ;
119+
120+ // Update materialization based on reference count
121+ for cte in with. ctes . iter_mut ( ) {
122+ let table_name = self . normalize_identifier ( & cte. alias . name ) . name ;
123+ if let Some ( count) = cte_ref_count. get ( & table_name) {
124+ log:: info!( "[CTE]cte_ref_count: {table_name} {count}" ) ;
125+ // Materialize if referenced more than once
126+ cte. materialized |= * count > 1 ;
127+ }
128+ }
129+
130+ Ok ( ( ) )
131+ }
132+
69133 // Initialize cte map.
70134 pub ( crate ) fn init_cte (
71135 & mut self ,
@@ -205,7 +269,11 @@ impl Binder {
205269 ) ) ) ;
206270 }
207271
208- let expr_replacer = ExprReplacer :: new ( database. clone ( ) , self . m_cte_table_name . clone ( ) ) ;
272+ let mut expr_replacer = TableNameReplacer :: new (
273+ database. clone ( ) ,
274+ self . m_cte_table_name . clone ( ) ,
275+ self . name_resolution_ctx . clone ( ) ,
276+ ) ;
209277 let mut as_query = cte. query . clone ( ) ;
210278 with. ctes . truncate ( cte_index) ;
211279 with. ctes . retain ( |cte| !cte. materialized ) ;
@@ -214,15 +282,42 @@ impl Binder {
214282 } else {
215283 None
216284 } ;
217- expr_replacer. replace_query ( & mut as_query) ;
285+ as_query. drive_mut ( & mut expr_replacer) ;
286+
287+ let source = if cte. alias . columns . is_empty ( ) {
288+ None
289+ } else {
290+ let mut bind_context = BindContext :: new ( ) ;
291+ let ( _, bind_context) = self . bind_query ( & mut bind_context, & as_query) ?;
292+ let columns = & bind_context. columns ;
293+ if columns. len ( ) != cte. alias . columns . len ( ) {
294+ return Err ( ErrorCode :: Internal ( "Number of columns does not match" ) ) ;
295+ }
296+ Some ( CreateTableSource :: Columns (
297+ columns
298+ . iter ( )
299+ . zip ( cte. alias . columns . iter ( ) )
300+ . map ( |( column, ident) | {
301+ let data_type = convert_to_type_name ( & column. data_type ) ;
302+ ColumnDefinition {
303+ name : ident. clone ( ) ,
304+ data_type,
305+ expr : None ,
306+ comment : None ,
307+ }
308+ } )
309+ . collect ( ) ,
310+ None ,
311+ ) )
312+ } ;
218313
219314 let catalog = self . ctx . get_current_catalog ( ) ;
220315 let create_table_stmt = CreateTableStmt {
221316 create_option : CreateOption :: Create ,
222317 catalog : Some ( Identifier :: from_name ( Span :: None , catalog. clone ( ) ) ) ,
223318 database : Some ( Identifier :: from_name ( Span :: None , database. clone ( ) ) ) ,
224319 table : table_identifier,
225- source : None ,
320+ source,
226321 engine : Some ( engine) ,
227322 uri_location : None ,
228323 cluster_by : None ,
@@ -234,6 +329,7 @@ impl Binder {
234329 } ;
235330
236331 let create_table_sql = create_table_stmt. to_string ( ) ;
332+ log:: info!( "[CTE]create_table_sql: {create_table_sql}" ) ;
237333 if let Some ( subquery_executor) = & self . subquery_executor {
238334 let _ = databend_common_base:: runtime:: block_on ( async move {
239335 subquery_executor
@@ -250,3 +346,54 @@ impl Binder {
250346 . evict_table_from_cache ( & catalog, & database, & table_name)
251347 }
252348}
349+
350+ #[ derive( VisitorMut ) ]
351+ #[ visitor( TableReference ( enter) , Expr ( enter) ) ]
352+ pub struct TableNameReplacer {
353+ database : String ,
354+ new_name : HashMap < String , String > ,
355+ name_resolution_ctx : NameResolutionContext ,
356+ }
357+
358+ impl TableNameReplacer {
359+ pub fn new (
360+ database : String ,
361+ new_name : HashMap < String , String > ,
362+ name_resolution_ctx : NameResolutionContext ,
363+ ) -> Self {
364+ Self {
365+ database,
366+ new_name,
367+ name_resolution_ctx,
368+ }
369+ }
370+
371+ fn replace_identifier ( & mut self , identifier : & mut Identifier ) {
372+ let name = normalize_identifier ( identifier, & self . name_resolution_ctx ) . name ;
373+ if let Some ( new_name) = self . new_name . get ( & name) {
374+ identifier. name = new_name. clone ( ) ;
375+ }
376+ }
377+
378+ fn enter_table_reference ( & mut self , table_reference : & mut TableReference ) {
379+ if let TableReference :: Table {
380+ database, table, ..
381+ } = table_reference
382+ {
383+ if database. is_none ( ) || database. as_ref ( ) . unwrap ( ) . name == self . database {
384+ self . replace_identifier ( table) ;
385+ }
386+ }
387+ }
388+
389+ fn enter_expr ( & mut self , expr : & mut Expr ) {
390+ if let Expr :: ColumnRef { column, .. } = expr {
391+ if column. database . is_none ( ) || column. database . as_ref ( ) . unwrap ( ) . name == self . database
392+ {
393+ if let Some ( table_identifier) = & mut column. table {
394+ self . replace_identifier ( table_identifier) ;
395+ }
396+ }
397+ }
398+ }
399+ }
0 commit comments