vibesql_executor/select/
cte.rs1use std::collections::HashMap;
4use std::sync::Arc;
5
6use crate::errors::ExecutorError;
7
8pub type CteResult = (vibesql_catalog::TableSchema, Arc<Vec<vibesql_storage::Row>>);
16
17pub(super) fn execute_ctes<F>(
21 ctes: &[vibesql_ast::CommonTableExpr],
22 executor: F,
23) -> Result<HashMap<String, CteResult>, ExecutorError>
24where
25 F: Fn(
26 &vibesql_ast::SelectStmt,
27 &HashMap<String, CteResult>,
28 ) -> Result<Vec<vibesql_storage::Row>, ExecutorError>,
29{
30 execute_ctes_with_memory_check(ctes, executor, |_| Ok(()))
32}
33
34pub(super) fn execute_ctes_with_memory_check<F, M>(
40 ctes: &[vibesql_ast::CommonTableExpr],
41 executor: F,
42 memory_check: M,
43) -> Result<HashMap<String, CteResult>, ExecutorError>
44where
45 F: Fn(
46 &vibesql_ast::SelectStmt,
47 &HashMap<String, CteResult>,
48 ) -> Result<Vec<vibesql_storage::Row>, ExecutorError>,
49 M: Fn(usize) -> Result<(), ExecutorError>,
50{
51 let mut cte_results = HashMap::new();
52
53 for cte in ctes {
56 let rows = executor(&cte.query, &cte_results)?;
59
60 let estimated_size = super::helpers::estimate_result_size(&rows);
62 memory_check(estimated_size)?;
63
64 let schema = derive_cte_schema(cte, &rows)?;
66
67 cte_results.insert(cte.name.clone(), (schema, Arc::new(rows)));
69 }
70
71 Ok(cte_results)
72}
73
74pub(super) fn derive_cte_schema(
76 cte: &vibesql_ast::CommonTableExpr,
77 rows: &[vibesql_storage::Row],
78) -> Result<vibesql_catalog::TableSchema, ExecutorError> {
79 if let Some(column_names) = &cte.columns {
81 if let Some(first_row) = rows.first() {
83 if first_row.values.len() != column_names.len() {
84 return Err(ExecutorError::UnsupportedFeature(format!(
85 "CTE column count mismatch: specified {} columns but query returned {}",
86 column_names.len(),
87 first_row.values.len()
88 )));
89 }
90
91 let columns = column_names
92 .iter()
93 .zip(&first_row.values)
94 .map(|(name, value)| {
95 let data_type = infer_type_from_value(value);
96 vibesql_catalog::ColumnSchema::new(name.clone(), data_type, true) })
99 .collect();
100
101 Ok(vibesql_catalog::TableSchema::new(cte.name.clone(), columns))
102 } else {
103 let columns = column_names
105 .iter()
106 .map(|name| {
107 vibesql_catalog::ColumnSchema::new(
108 name.clone(),
109 vibesql_types::DataType::Varchar { max_length: Some(255) },
110 true,
111 )
112 })
113 .collect();
114
115 Ok(vibesql_catalog::TableSchema::new(cte.name.clone(), columns))
116 }
117 } else {
118 let columns = cte
121 .query
122 .select_list
123 .iter()
124 .enumerate()
125 .map(|(i, item)| {
126 let data_type = if let Some(first_row) = rows.first() {
128 infer_type_from_value(&first_row.values[i])
129 } else {
130 vibesql_types::DataType::Varchar { max_length: Some(255) }
132 };
133
134 let col_name = match item {
136 vibesql_ast::SelectItem::Wildcard { .. }
137 | vibesql_ast::SelectItem::QualifiedWildcard { .. } => format!("col{}", i),
138 vibesql_ast::SelectItem::Expression { expr, alias } => {
139 if let Some(a) = alias {
140 a.clone()
141 } else {
142 match expr {
144 vibesql_ast::Expression::ColumnRef { table: _, column } => {
145 column.clone()
146 }
147 _ => format!("col{}", i),
148 }
149 }
150 }
151 };
152
153 vibesql_catalog::ColumnSchema::new(col_name, data_type, true) })
155 .collect();
156
157 Ok(vibesql_catalog::TableSchema::new(cte.name.clone(), columns))
158 }
159}
160
161pub(super) fn infer_type_from_value(value: &vibesql_types::SqlValue) -> vibesql_types::DataType {
163 match value {
164 vibesql_types::SqlValue::Null => vibesql_types::DataType::Varchar { max_length: Some(255) }, vibesql_types::SqlValue::Integer(_) => vibesql_types::DataType::Integer,
166 vibesql_types::SqlValue::Varchar(_) => vibesql_types::DataType::Varchar { max_length: Some(255) },
167 vibesql_types::SqlValue::Character(_) => vibesql_types::DataType::Character { length: 1 },
168 vibesql_types::SqlValue::Boolean(_) => vibesql_types::DataType::Boolean,
169 vibesql_types::SqlValue::Float(_) => vibesql_types::DataType::Float { precision: 53 },
170 vibesql_types::SqlValue::Double(_) => vibesql_types::DataType::DoublePrecision,
171 vibesql_types::SqlValue::Numeric(_) => vibesql_types::DataType::Numeric { precision: 10, scale: 2 },
172 vibesql_types::SqlValue::Real(_) => vibesql_types::DataType::Real,
173 vibesql_types::SqlValue::Smallint(_) => vibesql_types::DataType::Smallint,
174 vibesql_types::SqlValue::Bigint(_) => vibesql_types::DataType::Bigint,
175 vibesql_types::SqlValue::Unsigned(_) => vibesql_types::DataType::Unsigned,
176 vibesql_types::SqlValue::Date(_) => vibesql_types::DataType::Date,
177 vibesql_types::SqlValue::Time(_) => vibesql_types::DataType::Time { with_timezone: false },
178 vibesql_types::SqlValue::Timestamp(_) => vibesql_types::DataType::Timestamp { with_timezone: false },
179 vibesql_types::SqlValue::Interval(_) => {
180 vibesql_types::DataType::Interval {
182 start_field: vibesql_types::IntervalField::Day,
183 end_field: None,
184 }
185 }
186 vibesql_types::SqlValue::Vector(v) => {
187 vibesql_types::DataType::Vector { dimensions: v.len() as u32 }
188 }
189 }
190}