Plan a SELECT query.
(
query: &Query,
catalog: &dyn SqlCatalog,
functions: &FunctionRegistry,
temporal: TemporalScope,
)
| 57 | |
| 58 | /// Plan a SELECT query. |
| 59 | pub fn plan_query( |
| 60 | query: &Query, |
| 61 | catalog: &dyn SqlCatalog, |
| 62 | functions: &FunctionRegistry, |
| 63 | temporal: TemporalScope, |
| 64 | ) -> Result<SqlPlan> { |
| 65 | // Handle CTEs (WITH clause). |
| 66 | if let Some(with) = &query.with |
| 67 | && with.recursive |
| 68 | { |
| 69 | return crate::planner::cte::plan_recursive_cte(query, catalog, functions, temporal); |
| 70 | } |
| 71 | // Non-recursive CTEs: plan each CTE subquery and the outer query. |
| 72 | if let Some(with) = &query.with |
| 73 | && !with.cte_tables.is_empty() |
| 74 | { |
| 75 | let inner_query = Query { |
| 76 | with: None, |
| 77 | body: query.body.clone(), |
| 78 | order_by: query.order_by.clone(), |
| 79 | limit_clause: query.limit_clause.clone(), |
| 80 | fetch: query.fetch.clone(), |
| 81 | locks: query.locks.clone(), |
| 82 | for_clause: query.for_clause.clone(), |
| 83 | settings: query.settings.clone(), |
| 84 | format_clause: query.format_clause.clone(), |
| 85 | pipe_operators: query.pipe_operators.clone(), |
| 86 | }; |
| 87 | |
| 88 | // Plan each CTE subquery. |
| 89 | let mut definitions = Vec::new(); |
| 90 | let mut cte_names = Vec::new(); |
| 91 | for cte in &with.cte_tables { |
| 92 | let name = normalize_ident(&cte.alias.name); |
| 93 | let cte_plan = plan_query(&cte.query, catalog, functions, temporal)?; |
| 94 | definitions.push((name.clone(), cte_plan)); |
| 95 | cte_names.push(name); |
| 96 | } |
| 97 | |
| 98 | // Build CTE-aware catalog so the outer query can reference CTE names. |
| 99 | let cte_catalog = CteCatalog { |
| 100 | inner: catalog, |
| 101 | cte_names, |
| 102 | }; |
| 103 | let outer = plan_query(&inner_query, &cte_catalog, functions, temporal)?; |
| 104 | |
| 105 | return Ok(SqlPlan::Cte { |
| 106 | definitions, |
| 107 | outer: Box::new(outer), |
| 108 | }); |
| 109 | } |
| 110 | |
| 111 | // Handle UNION. |
| 112 | match &*query.body { |
| 113 | SetExpr::Select(select) => { |
| 114 | let mut plan = plan_select(select, catalog, functions, temporal)?; |
| 115 | // Snapshot the projection before ORDER BY transforms the plan, |
| 116 | // in case `apply_order_by` converts a Scan into VectorSearch. |