1use super::{subquery_table, unsupported, Binder, BoundSource, RecursiveBody, SourceRows};
19use crate::ast::{self, CompoundOp, JoinKind, SelectId};
20use crate::catalog_view::TableInfo;
21use crate::diagnostic::{ParseError, ParseErrorKind};
22use crate::lexer::Span;
23
24#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct CteBinding {
33 pub folded: Vec<u8>,
35 pub name: Vec<u8>,
37 pub columns: Vec<Vec<u8>>,
39 pub select: SelectId,
41 pub recursive: bool,
43}
44
45#[derive(Clone, Debug)]
47pub(super) struct RecursiveTarget {
48 pub(super) folded: Vec<u8>,
50 id: usize,
52 table: TableInfo,
54 referenced: bool,
56}
57
58impl Binder<'_> {
59 pub(crate) fn push_ctes(&mut self, with: &ast::With) -> Result<bool, ParseError> {
61 if with.ctes.is_empty() {
62 return Ok(false);
63 }
64 let mut bindings = Vec::with_capacity(with.ctes.len());
65 for cte in &with.ctes {
66 bindings.push(CteBinding {
67 folded: self.ast.folded(cte.name).to_vec(),
68 name: self.ast.text(cte.name).to_vec(),
69 columns: cte
70 .columns
71 .iter()
72 .map(|name| self.ast.text(*name).to_vec())
73 .collect(),
74 select: cte.select,
75 recursive: with.recursive,
76 });
77 }
78 self.ctes.push(bindings);
79 Ok(true)
80 }
81
82 pub(crate) fn pop_ctes(&mut self) {
84 self.ctes.pop();
85 }
86
87 pub(super) fn find_cte(&self, folded: &[u8]) -> Option<CteBinding> {
89 for level in self.ctes.iter().rev() {
90 if let Some(found) = level.iter().find(|cte| cte.folded == folded) {
91 return Some(found.clone());
92 }
93 }
94 None
95 }
96
97 pub(super) fn select_names_itself(&self, select: ast::SelectId, folded: &[u8]) -> bool {
112 let Some(query) = self.ast.select(select) else {
113 return false;
114 };
115 if query
116 .with
117 .ctes
118 .iter()
119 .any(|inner| self.ast.folded(inner.name) == folded)
120 {
121 return false;
122 }
123 if self.core_names_cte(query.first, folded) {
124 return true;
125 }
126 query
127 .compounds
128 .iter()
129 .any(|(_, arm)| self.core_names_cte(*arm, folded))
130 }
131
132 pub(super) fn core_names_cte(&self, core: ast::SelectCoreId, folded: &[u8]) -> bool {
137 let Some(arm) = self.ast.core(core) else {
138 return false;
139 };
140 let ast::SelectBody::Select { from, .. } = &arm.body else {
141 return false;
142 };
143 self.terms_name_cte(from, folded)
144 }
145
146 pub(super) fn terms_name_cte(&self, terms: &[ast::FromTermId], folded: &[u8]) -> bool {
151 terms.iter().any(|id| match self.ast.from_term(*id) {
152 Some(term) => match &term.source {
153 ast::FromSource::Table { database, name, .. } => {
154 database.is_none() && self.ast.folded(*name) == folded
155 }
156 ast::FromSource::Subquery(select) => self.select_names_itself(*select, folded),
157 ast::FromSource::Join(inner) => self.terms_name_cte(inner, folded),
158 },
159 None => false,
160 })
161 }
162
163 pub(super) fn push_recursive_self(
165 &mut self,
166 position: usize,
167 alias: Option<ast::NameId>,
168 join: JoinKind,
169 ) -> Result<(), ParseError> {
170 let Some(target) = self.recursing.get_mut(position) else {
171 return Err(unsupported("unknown recursive reference", Span::default()));
172 };
173 target.referenced = true;
174 let cte = target.id;
175 let table = target.table.clone();
176 let alias = match alias {
177 Some(alias) => self.ast.text(alias).to_vec(),
178 None => table.name.clone(),
179 };
180 let id = self.sources.len();
181 self.sources.push(BoundSource {
182 index_hint: crate::bind::IndexChoice::Any,
183 id,
184 rows: SourceRows::RecursiveSelf { cte },
185 table: std::rc::Rc::new(table),
186 alias,
187 join,
188 constraint: None,
189 suppressed: Vec::new(),
190 index_exprs: Vec::new(),
191 });
192 if let Some(scope) = self.scopes.last_mut() {
193 scope.push(id);
194 }
195 Ok(())
196 }
197
198 pub(super) fn bind_recursive_cte(
207 &mut self,
208 cte: &CteBinding,
209 alias: Vec<u8>,
210 join: JoinKind,
211 span: Span,
212 ) -> Result<(), ParseError> {
213 let Some(select) = self.ast.select(cte.select) else {
214 return Err(unsupported("missing select", span));
215 };
216 if select.compounds.is_empty() {
217 return self.bind_subquery_term(
218 cte.select,
219 Some(alias),
220 cte.columns.clone(),
221 join,
222 span,
223 );
224 }
225 let arms: Vec<(CompoundOp, ast::SelectCoreId)> = select.compounds.clone();
226 let order_by = select.order_by.clone();
227 let limit = select.limit;
228 let offset = select.offset;
229 let first = select.first;
230 if !order_by.is_empty() || limit.is_some() || offset.is_some() {
231 return Err(ParseError::new(
232 ParseErrorKind::Unsupported(
233 "ORDER BY and LIMIT are not allowed on a recursive CTE",
234 ),
235 span,
236 ));
237 }
238
239 let id = self.sources.len();
240 self.sources.push(BoundSource {
244 index_hint: crate::bind::IndexChoice::Any,
245 id,
246 rows: SourceRows::Table,
247 table: std::rc::Rc::new(TableInfo::subquery(alias.clone(), 0, Vec::new())),
248 alias: alias.clone(),
249 join,
250 constraint: None,
251 suppressed: Vec::new(),
252 index_exprs: Vec::new(),
253 });
254
255 let seed = self.bind_isolated_arm(first)?;
256 let table = subquery_table(&alias, &cte.columns, &seed);
257 if !cte.columns.is_empty() && cte.columns.len() != seed.columns.len() {
258 return Err(ParseError::new(
259 ParseErrorKind::Unsupported("the named column list does not match the query"),
260 span,
261 ));
262 }
263 self.recursing.push(RecursiveTarget {
264 folded: cte.folded.clone(),
265 id,
266 table: table.clone(),
267 referenced: false,
268 });
269 let mut seeds = vec![(CompoundOp::UnionAll, seed)];
270 let mut steps = Vec::new();
271 let mut outcome = Ok(());
272 for (op, arm) in &arms {
273 if !matches!(op, CompoundOp::Union | CompoundOp::UnionAll) {
274 outcome = Err(ParseError::new(
275 ParseErrorKind::Unsupported("recursive query does not use UNION or UNION ALL"),
276 span,
277 ));
278 break;
279 }
280 if let Some(target) = self.recursing.last_mut() {
281 target.referenced = false;
282 }
283 let bound = match self.bind_isolated_arm(*arm) {
284 Ok(bound) => bound,
285 Err(reason) => {
286 outcome = Err(reason);
287 break;
288 }
289 };
290 let referenced = self
291 .recursing
292 .last()
293 .is_some_and(|target| target.referenced);
294 if referenced {
295 steps.push((*op, bound));
296 } else {
297 seeds.push((*op, bound));
298 }
299 }
300 self.recursing.pop();
301 outcome?;
302
303 let mut source = BoundSource {
304 index_hint: crate::bind::IndexChoice::Any,
305 id,
306 rows: SourceRows::Recursive(Box::new(RecursiveBody { seeds, steps })),
307 table: std::rc::Rc::new(table),
308 alias,
309 join,
310 constraint: None,
311 suppressed: Vec::new(),
312 index_exprs: Vec::new(),
313 };
314 if let SourceRows::Recursive(body) = &mut source.rows {
315 if body.steps.is_empty() {
316 let mut arms = core::mem::take(&mut body.seeds);
319 if arms.is_empty() {
320 return Err(unsupported("missing select core", span));
321 }
322 let mut head = arms.remove(0).1;
323 head.compounds = arms;
324 source.rows = SourceRows::Subquery(Box::new(head));
325 }
326 }
327 if let Some(slot) = self.sources.get_mut(id) {
328 *slot = source;
329 }
330 if let Some(scope) = self.scopes.last_mut() {
331 scope.push(id);
332 }
333 Ok(())
334 }
335}