1use fnv::FnvBuildHasher;
2use indexmap::IndexMap;
3use num::Integer;
4use ordered_float::OrderedFloat;
5use partiql_ast::ast;
6use partiql_ast::ast::{
7 Assignment, Bag, BagOpExpr, BagOperator, Between, BinOp, BinOpKind, Call, CallAgg, CallArg,
8 CallArgNamed, CaseSensitivity, CreateIndex, CreateTable, Ddl, DdlOp, Delete, Dml, DmlOp,
9 DropIndex, DropTable, Exclusion, Expr, FromClause, FromLet, FromLetKind, GroupByExpr, GroupKey,
10 GroupingStrategy, Insert, InsertValue, Item, Join, JoinKind, JoinSpec, Like, List, Lit,
11 NullOrderingSpec, OnConflict, OrderByExpr, OrderingSpec, Path, PathStep, ProjectExpr,
12 Projection, ProjectionKind, Query, QuerySet, Remove, SearchedCase, Select, Set, SetQuantifier,
13 SimpleCase, SortSpec, Struct, SymbolPrimitive, UniOp, UniOpKind, VarRef,
14};
15use partiql_ast::visit::{Traverse, Visit, Visitor};
16use partiql_logical as logical;
17use partiql_logical::{
18 AggregateExpression, BagExpr, BagOp, BetweenExpr, BindingsOp, GraphMatchExpr, IsTypeExpr,
19 LikeMatch, LikeNonStringNonLiteralMatch, ListExpr, LogicalPlan, OpId, PathComponent, Pattern,
20 PatternMatchExpr, ProjectAllMode, SortSpecOrder, TupleExpr, ValueExpr, VarRefType,
21};
22use std::borrow::Cow;
23
24use partiql_value::BindingsName;
25
26use crate::builtins::{FnSymTab, FN_SYM_TAB};
27use itertools::Itertools;
28use partiql_ast_passes::name_resolver;
29use partiql_catalog::call_defs::{CallArgument, CallDef};
30
31use partiql_ast_passes::error::{AstTransformError, AstTransformationError};
32
33use crate::functions::Function;
34use partiql_ast_passes::name_resolver::NameRef;
35use partiql_catalog::catalog::SharedCatalog;
36use partiql_common::node::{IdAnnotated, NodeId};
37
38use partiql_logical::AggFunc::{AggAny, AggAvg, AggCount, AggEvery, AggMax, AggMin, AggSum};
39use partiql_logical::ValueExpr::DynamicLookup;
40use rustc_hash::{FxBuildHasher, FxHashMap};
41use std::sync::atomic::{AtomicU32, Ordering};
42
43type FnvIndexMap<K, V> = IndexMap<K, V, FnvBuildHasher>;
44
45#[macro_export]
46macro_rules! eq_or_fault {
47 ($self:ident, $lhs:expr, $rhs:expr, $msg:expr) => {
48 if $lhs != $rhs {
49 $self
50 .errors
51 .push(AstTransformError::IllegalState($msg.to_string()));
52 return partiql_ast::visit::Traverse::Stop;
53 }
54 };
55}
56
57#[macro_export]
58macro_rules! true_or_fault {
59 ($self:ident, $expr:expr, $msg:expr) => {
60 if !$expr {
61 true_or_fault_err!($self, $expr, $msg);
62 return partiql_ast::visit::Traverse::Stop;
63 }
64 };
65}
66
67#[macro_export]
68macro_rules! true_or_fault_err {
69 ($self:ident, $expr:expr, $msg:expr) => {
70 if !$expr {
71 $self
72 .errors
73 .push(AstTransformError::IllegalState($msg.to_string()));
74 }
75 };
76}
77
78#[macro_export]
79macro_rules! not_yet_implemented_fault {
80 ($self:ident, $msg:expr) => {
81 not_yet_implemented_err!($self, $msg);
82 return partiql_ast::visit::Traverse::Stop;
83 };
84}
85
86#[macro_export]
87macro_rules! not_yet_implemented_err {
88 ($self:ident, $msg:expr) => {
89 $self
90 .errors
91 .push(AstTransformError::NotYetImplemented($msg.to_string()));
92 };
93}
94
95pub(crate) fn extract_vexpr_by_id(
96 v: &mut Vec<(NodeId, ValueExpr)>,
97 target: NodeId,
98) -> Option<ValueExpr> {
99 let position: usize = v.iter().position(|(id, _v)| *id == target)?;
100 Some(v.remove(position).1)
101}
102
103#[derive(Copy, Clone, Debug)]
104enum QueryContext {
105 FromLet,
106 Path,
107 Order,
108 Query,
109}
110
111#[derive(Clone, Debug, Default)]
112struct QueryClauses {
113 from_clause: Option<logical::OpId>,
114 let_clause: Option<logical::OpId>,
115 where_clause: Option<logical::OpId>,
116 group_by_clause: Option<logical::OpId>,
117 having_clause: Option<logical::OpId>,
118 order_by_clause: Option<logical::OpId>,
119 limit_offset_clause: Option<logical::OpId>,
120 select_clause: Option<logical::OpId>,
121 distinct: Option<logical::OpId>,
122}
123
124impl QueryClauses {
125 pub fn evaluation_order(&self) -> Vec<OpId> {
126 [
127 self.from_clause,
128 self.let_clause,
129 self.where_clause,
130 self.group_by_clause,
131 self.having_clause,
132 self.order_by_clause,
133 self.limit_offset_clause,
134 self.select_clause,
135 self.distinct,
136 ]
137 .iter()
138 .copied()
139 .flatten()
140 .collect()
141 }
142}
143
144#[derive(Debug)]
145struct IdGenerator {
146 next_id: AtomicU32,
147}
148
149impl Default for IdGenerator {
150 fn default() -> Self {
151 Self {
152 next_id: AtomicU32::new(1),
153 }
154 }
155}
156
157impl IdGenerator {
158 fn id(&self) -> String {
159 format!("_{}", self.next_id())
160 }
161
162 fn next_id(&self) -> u32 {
163 self.next_id.fetch_add(1, Ordering::SeqCst)
164 }
165}
166
167#[derive(Debug)]
168pub struct AstToLogical<'a> {
169 id_stack: Vec<NodeId>,
171
172 q_stack: Vec<QueryClauses>,
173 ctx_stack: Vec<QueryContext>,
174 bexpr_stack: Vec<Vec<logical::OpId>>,
175 vexpr_stack: Vec<Vec<(NodeId, ValueExpr)>>,
176 arg_stack: Vec<Vec<CallArgument>>,
177 path_stack: Vec<Vec<PathComponent>>,
178 sort_stack: Vec<Vec<logical::SortSpec>>,
179 aggregate_exprs: Vec<Vec<AggregateExpression>>,
180 projection_renames: Vec<FnvIndexMap<String, BindingsName<'a>>>,
181
182 aliases: FnvIndexMap<NodeId, SymbolPrimitive>,
183
184 id: IdGenerator,
186 agg_id: IdGenerator,
187
188 plan_stack: Vec<LogicalPlan<BindingsOp>>,
190
191 key_registry: name_resolver::KeyRegistry,
193 fnsym_tab: &'static FnSymTab,
194 catalog: &'a dyn SharedCatalog,
195
196 errors: Vec<AstTransformError>,
198}
199
200fn infer_id(expr: &ValueExpr) -> Option<SymbolPrimitive> {
203 let sensitive = |value: &str| {
204 Some(SymbolPrimitive {
205 value: value.to_string(),
206 case: CaseSensitivity::CaseSensitive,
207 })
208 };
209 let insensitive = |value: &str| {
210 Some(SymbolPrimitive {
211 value: value.to_string(),
212 case: CaseSensitivity::CaseInsensitive,
213 })
214 };
215
216 match expr {
217 ValueExpr::VarRef(BindingsName::CaseInsensitive(s), _) => insensitive(s.as_ref()),
218 ValueExpr::VarRef(BindingsName::CaseSensitive(s), _) => sensitive(s.as_ref()),
219 ValueExpr::Path(_root, steps) => match steps.last() {
220 Some(PathComponent::Key(BindingsName::CaseInsensitive(s))) => insensitive(s.as_ref()),
221 Some(PathComponent::Key(BindingsName::CaseSensitive(s))) => sensitive(s.as_ref()),
222 Some(PathComponent::KeyExpr(ke)) => match &**ke {
223 ValueExpr::VarRef(BindingsName::CaseInsensitive(s), _) => insensitive(s.as_ref()),
224 ValueExpr::VarRef(BindingsName::CaseSensitive(s), _) => sensitive(s.as_ref()),
225 _ => None,
226 },
227 _ => None,
228 },
229 ValueExpr::DynamicLookup(d) => infer_id(d.first().unwrap()),
230 _ => None,
231 }
232}
233
234impl<'a> AstToLogical<'a> {
235 pub fn new(catalog: &'a dyn SharedCatalog, registry: name_resolver::KeyRegistry) -> Self {
236 let fnsym_tab: &FnSymTab = &FN_SYM_TAB;
237 AstToLogical {
238 id_stack: Default::default(),
239
240 q_stack: Default::default(),
241 ctx_stack: Default::default(),
242 bexpr_stack: Default::default(),
243 vexpr_stack: Default::default(),
244 arg_stack: Default::default(),
245 path_stack: Default::default(),
246 sort_stack: Default::default(),
247 aggregate_exprs: Default::default(),
248
249 projection_renames: Default::default(),
250
251 aliases: Default::default(),
252
253 id: Default::default(),
255 agg_id: Default::default(),
256
257 plan_stack: Default::default(),
259
260 key_registry: registry,
261 fnsym_tab,
262 catalog,
263
264 errors: vec![],
265 }
266 }
267
268 pub fn lower_query(
269 mut self,
270 query: &ast::AstNode<ast::TopLevelQuery>,
271 ) -> Result<logical::LogicalPlan<logical::BindingsOp>, AstTransformationError> {
272 self.enter_plan();
273 query.visit(&mut self);
274 true_or_fault_err!(
275 self,
276 self.plan_stack.len() == 1,
277 "self.plan_stack.len() != 1"
278 );
279 if !self.errors.is_empty() {
280 return Err(AstTransformationError {
281 errors: self.errors,
282 });
283 }
284 Ok(self.plan_stack.pop().unwrap())
285 }
286
287 #[inline]
288 fn current_node(&self) -> &NodeId {
289 self.id_stack.last().unwrap()
290 }
291
292 #[inline]
293 fn gen_id(&self) -> SymbolPrimitive {
294 SymbolPrimitive {
296 value: self.id.id(),
297 case: CaseSensitivity::CaseInsensitive,
298 }
299 }
300
301 #[inline]
302 fn infer_id(&self, expr: &ValueExpr, as_alias: &Option<SymbolPrimitive>) -> SymbolPrimitive {
303 as_alias
304 .to_owned()
305 .or_else(|| infer_id(expr))
306 .unwrap_or_else(|| self.gen_id())
307 }
308
309 fn resolve_varref(&self, varref: &ast::VarRef) -> logical::ValueExpr {
310 fn binding_to_static<'a>(binding: &'a BindingsName<'a>) -> BindingsName<'static> {
311 match binding {
312 BindingsName::CaseSensitive(n) => {
313 BindingsName::CaseSensitive(Cow::Owned(n.as_ref().to_string()))
314 }
315 BindingsName::CaseInsensitive(n) => {
316 BindingsName::CaseInsensitive(Cow::Owned(n.as_ref().to_string()))
317 }
318 }
319 }
320
321 fn symprim_to_binding(sym: &SymbolPrimitive) -> BindingsName<'static> {
323 match sym.case {
324 CaseSensitivity::CaseSensitive => {
325 BindingsName::CaseSensitive(Cow::Owned(sym.value.clone()))
326 }
327 CaseSensitivity::CaseInsensitive => {
328 BindingsName::CaseInsensitive(Cow::Owned(sym.value.clone()))
329 }
330 }
331 }
332 fn sym_to_binding(sym: &name_resolver::Symbol) -> Option<BindingsName<'static>> {
334 match sym {
335 name_resolver::Symbol::Known(sym) => Some(symprim_to_binding(sym)),
336 name_resolver::Symbol::Unknown(_) => None,
337 }
338 }
339
340 for id in self.id_stack.iter().rev() {
341 if let Some(key_schema) = self.key_registry.schema.get(id) {
342 let key_schema: &name_resolver::KeySchema = key_schema;
343
344 let name_ref: &NameRef = key_schema
345 .consume
346 .iter()
347 .find(|name_ref| name_ref.sym == varref.name)
348 .expect("NameRef");
349
350 let var_binding = symprim_to_binding(&name_ref.sym);
351 let mut lookups = vec![];
352
353 if matches!(self.current_ctx(), Some(QueryContext::Order)) {
354 if let Some(renames) = self.projection_renames.last() {
355 let binding = renames
356 .iter()
357 .find(|(k, _)| {
358 let SymbolPrimitive { value, case } = &name_ref.sym;
359 match case {
360 CaseSensitivity::CaseSensitive => value == *k,
361 CaseSensitivity::CaseInsensitive => unicase::eq(value, *k),
362 }
363 })
364 .map_or_else(
365 || symprim_to_binding(&name_ref.sym),
366 |(_k, v)| binding_to_static(v),
367 );
368
369 lookups.push(DynamicLookup(Box::new(vec![ValueExpr::VarRef(
370 binding,
371 VarRefType::Local,
372 )])));
373 }
374 }
375
376 for lookup in &name_ref.lookup {
377 match lookup {
378 name_resolver::NameLookup::Global => {
379 let var_ref_expr =
380 ValueExpr::VarRef(var_binding.clone(), VarRefType::Global);
381 if !lookups.contains(&var_ref_expr) {
382 lookups.push(var_ref_expr.clone());
383 }
384 }
385 name_resolver::NameLookup::Local => {
386 if let Some(scope_ids) = self.key_registry.in_scope.get(id) {
387 let scopes: Vec<&name_resolver::KeySchema> = scope_ids
388 .iter()
389 .filter_map(|scope_id| self.key_registry.schema.get(scope_id))
390 .collect();
391
392 let mut exact = scopes.iter().filter(|key_schema| {
393 key_schema.produce.contains(&name_resolver::Symbol::Known(
394 name_ref.sym.clone(),
395 ))
396 });
397
398 if let Some(_matching) = exact.next() {
399 let var_ref_expr =
400 ValueExpr::VarRef(var_binding.clone(), VarRefType::Local);
401 lookups.push(var_ref_expr);
402 continue;
403 }
404
405 for schema in scopes {
406 for produce in &schema.produce {
407 if let name_resolver::Symbol::Known(sym) = produce {
408 if (sym == &varref.name)
409 || (sym.value.to_lowercase()
410 == varref.name.value.to_lowercase()
411 && varref.name.case
412 == ast::CaseSensitivity::CaseInsensitive)
413 {
414 let expr = ValueExpr::VarRef(
415 sym_to_binding(produce).unwrap_or_else(|| {
416 symprim_to_binding(&self.gen_id())
417 }),
418 VarRefType::Local,
419 );
420 if !lookups.contains(&expr) {
421 lookups.push(expr);
422 }
423
424 continue;
425 } else if let Some(_type_entry) = self
426 .catalog
427 .resolve_type(name_ref.sym.value.as_ref())
428 {
429 let expr = ValueExpr::VarRef(
430 var_binding.clone(),
431 VarRefType::Global,
432 );
433 if !lookups.contains(&expr) {
434 lookups.push(expr);
435 }
436 continue;
437 } else {
438 let path = logical::ValueExpr::Path(
439 Box::new(ValueExpr::VarRef(
440 sym_to_binding(produce).unwrap_or_else(
441 || symprim_to_binding(&self.gen_id()),
442 ),
443 VarRefType::Local,
444 )),
445 vec![PathComponent::Key(var_binding.clone())],
446 );
447
448 if !lookups.contains(&path) {
449 lookups.push(path);
450 }
451 }
452 } else if let name_resolver::Symbol::Unknown(num) = produce
453 {
454 let formatted_num = format!("_{num}");
455 if formatted_num == varref.name.value {
456 let expr = ValueExpr::VarRef(
457 BindingsName::CaseInsensitive(Cow::Owned(
458 formatted_num,
459 )),
460 VarRefType::Local,
461 );
462 if !lookups.contains(&expr) {
463 lookups.push(expr);
464 continue;
465 }
466 } else {
467 let path = logical::ValueExpr::Path(
468 Box::new(ValueExpr::VarRef(
469 sym_to_binding(produce).unwrap_or({
470 BindingsName::CaseInsensitive(
471 Cow::Owned(formatted_num),
472 )
473 }),
474 VarRefType::Local,
475 )),
476 vec![PathComponent::Key(var_binding.clone())],
477 );
478
479 if !lookups.contains(&path) {
480 lookups.push(path);
481 }
482 }
483 }
484 }
485 }
486 }
487 }
488 }
489 }
490 return ValueExpr::DynamicLookup(Box::new(lookups));
491 }
492 }
493
494 ValueExpr::VarRef(symprim_to_binding(&varref.name), VarRefType::Global)
498 }
499
500 #[inline]
501 fn enter_q(&mut self) {
502 self.q_stack.push(Default::default());
503 self.aggregate_exprs.push(Default::default());
504 self.ctx_stack.push(QueryContext::Query);
505 self.projection_renames.push(Default::default());
506 }
507
508 #[inline]
509 fn exit_q(&mut self) -> QueryClauses {
510 self.projection_renames.pop().expect("q level");
511 self.ctx_stack.pop().expect("q level");
512 self.aggregate_exprs.pop().expect("q level");
513 self.q_stack.pop().expect("q level")
514 }
515
516 #[inline]
517 fn current_ctx(&self) -> Option<&QueryContext> {
518 self.ctx_stack.last()
519 }
520
521 #[inline]
522 fn current_ctx_mut(&mut self) -> &mut QueryContext {
523 self.ctx_stack.last_mut().unwrap()
524 }
525
526 #[inline]
527 fn current_clauses_mut(&mut self) -> &mut QueryClauses {
528 self.q_stack.last_mut().unwrap()
529 }
530
531 #[inline]
532 fn enter_plan(&mut self) {
533 self.plan_stack.push(LogicalPlan::default());
534 }
535
536 #[inline]
537 fn exit_plan(&mut self) -> LogicalPlan<BindingsOp> {
538 self.plan_stack.pop().expect("environment level")
539 }
540
541 #[inline]
542 fn curr_plan(&mut self) -> &mut LogicalPlan<BindingsOp> {
543 self.plan_stack.last_mut().expect("plan")
544 }
545
546 #[inline]
547 fn enter_benv(&mut self) {
548 self.bexpr_stack.push(vec![]);
549 }
550
551 #[inline]
552 fn exit_benv(&mut self) -> Vec<logical::OpId> {
553 self.bexpr_stack.pop().expect("bexpr level")
554 }
555
556 #[inline]
557 fn push_bexpr(&mut self, bexpr: logical::OpId) {
558 self.bexpr_stack.last_mut().unwrap().push(bexpr);
559 }
560
561 #[inline]
562 fn enter_env(&mut self) {
563 self.vexpr_stack.push(vec![]);
564 }
565
566 #[inline]
567 fn exit_env(&mut self) -> Vec<(NodeId, ValueExpr)> {
568 self.vexpr_stack.pop().expect("environment level")
569 }
570
571 #[inline]
572 fn push_vexpr(&mut self, vexpr: ValueExpr) {
573 let id = self.id_stack.last().unwrap();
574 self.vexpr_stack.last_mut().unwrap().push((*id, vexpr));
575 }
576
577 #[inline]
578 fn push_lit(&mut self, lit: logical::Lit) {
579 self.push_vexpr(ValueExpr::Lit(Box::new(lit)));
580 }
581
582 #[inline]
583 fn enter_call(&mut self) {
584 self.arg_stack.push(vec![]);
585 }
586
587 #[inline]
588 fn exit_call(&mut self) -> Vec<CallArgument> {
589 self.arg_stack.pop().expect("environment level")
590 }
591
592 #[inline]
593 fn push_call_arg(&mut self, arg: CallArgument) {
594 self.arg_stack.last_mut().unwrap().push(arg);
595 }
596
597 #[inline]
598 fn enter_path(&mut self) {
599 self.path_stack.push(vec![]);
600 self.ctx_stack.push(QueryContext::Query);
601 }
602
603 #[inline]
604 fn exit_path(&mut self) -> Vec<PathComponent> {
605 self.ctx_stack.pop();
606 self.path_stack.pop().expect("path level")
607 }
608
609 #[inline]
610 fn push_path_step(&mut self, step: PathComponent) {
611 self.path_stack.last_mut().unwrap().push(step);
612 }
613
614 #[inline]
615 fn enter_sort(&mut self) {
616 self.sort_stack.push(vec![]);
617 self.ctx_stack.push(QueryContext::Order);
618 }
619
620 #[inline]
621 fn exit_sort(&mut self) -> Vec<logical::SortSpec> {
622 self.ctx_stack.pop();
623 self.sort_stack.pop().expect("sort specs")
624 }
625
626 #[inline]
627 fn push_sort_spec(&mut self, spec: logical::SortSpec) {
628 self.sort_stack.last_mut().unwrap().push(spec);
629 }
630}
631
632impl<'ast> Visitor<'ast> for AstToLogical<'_> {
647 fn enter_ast_node(&mut self, id: NodeId) -> Traverse {
648 self.id_stack.push(id);
649 Traverse::Continue
650 }
651 fn exit_ast_node(&mut self, id: NodeId) -> Traverse {
652 let cur_node = self.id_stack.pop();
653 eq_or_fault!(self, cur_node, Some(id), "id_stack node id != id");
654 Traverse::Continue
655 }
656
657 fn enter_item(&mut self, _item: &'ast Item) -> Traverse {
658 not_yet_implemented_fault!(self, "Item");
659 }
660
661 fn enter_ddl(&mut self, _ddl: &'ast Ddl) -> Traverse {
662 not_yet_implemented_fault!(self, "Ddl".to_string());
663 }
664
665 fn enter_ddl_op(&mut self, _ddl_op: &'ast DdlOp) -> Traverse {
666 not_yet_implemented_fault!(self, "DdlOp".to_string());
667 }
668
669 fn enter_create_table(&mut self, _create_table: &'ast CreateTable) -> Traverse {
670 not_yet_implemented_fault!(self, "CreateTable".to_string());
671 }
672
673 fn enter_drop_table(&mut self, _drop_table: &'ast DropTable) -> Traverse {
674 not_yet_implemented_fault!(self, "DropTable".to_string());
675 }
676
677 fn enter_create_index(&mut self, _create_index: &'ast CreateIndex) -> Traverse {
678 not_yet_implemented_fault!(self, "CreateIndex".to_string());
679 }
680
681 fn enter_drop_index(&mut self, _drop_index: &'ast DropIndex) -> Traverse {
682 not_yet_implemented_fault!(self, "DropIndex".to_string());
683 }
684
685 fn enter_dml(&mut self, _dml: &'ast Dml) -> Traverse {
686 not_yet_implemented_fault!(self, "Dml".to_string());
687 }
688
689 fn enter_dml_op(&mut self, _dml_op: &'ast DmlOp) -> Traverse {
690 not_yet_implemented_fault!(self, "DmlOp".to_string());
691 }
692
693 fn enter_insert(&mut self, _insert: &'ast Insert) -> Traverse {
694 not_yet_implemented_fault!(self, "Insert".to_string());
695 }
696
697 fn enter_insert_value(&mut self, _insert_value: &'ast InsertValue) -> Traverse {
698 not_yet_implemented_fault!(self, "InsertValue".to_string());
699 }
700
701 fn enter_set(&mut self, _set: &'ast Set) -> Traverse {
702 not_yet_implemented_fault!(self, "Set".to_string());
703 }
704
705 fn enter_assignment(&mut self, _assignment: &'ast Assignment) -> Traverse {
706 not_yet_implemented_fault!(self, "Assignment".to_string());
707 }
708
709 fn enter_remove(&mut self, _remove: &'ast Remove) -> Traverse {
710 not_yet_implemented_fault!(self, "Remove".to_string());
711 }
712
713 fn enter_delete(&mut self, _delete: &'ast Delete) -> Traverse {
714 not_yet_implemented_fault!(self, "Delete".to_string());
715 }
716
717 fn enter_on_conflict(&mut self, _on_conflict: &'ast OnConflict) -> Traverse {
718 not_yet_implemented_fault!(self, "OnConflict".to_string());
719 }
720
721 fn enter_top_level_query(&mut self, _query: &'ast ast::TopLevelQuery) -> Traverse {
722 self.enter_benv();
723 Traverse::Continue
724 }
725 fn exit_top_level_query(&mut self, _query: &'ast ast::TopLevelQuery) -> Traverse {
726 let mut benv = self.exit_benv();
727 eq_or_fault!(self, benv.len(), 1, "Expect benv.len() == 1");
728 let out = benv.pop().unwrap();
729 let sink_id = self.curr_plan().add_operator(BindingsOp::Sink);
730 self.curr_plan().add_flow(out, sink_id);
731 Traverse::Continue
732 }
733
734 fn enter_query(&mut self, query: &'ast Query) -> Traverse {
735 self.enter_benv();
736 if let QuerySet::Select(_) = query.set.node {
737 self.enter_q();
738 }
739 Traverse::Continue
740 }
741
742 fn exit_query(&mut self, query: &'ast Query) -> Traverse {
743 let benv = self.exit_benv();
744 match query.set.node {
745 QuerySet::Select(_) => {
746 let clauses = self.exit_q();
747 let mut clauses = clauses.evaluation_order().into_iter();
748 if let Some(mut src_id) = clauses.next() {
749 for dst_id in clauses {
750 self.curr_plan().add_flow(src_id, dst_id);
751 src_id = dst_id;
752 }
753 self.push_bexpr(src_id);
754 }
755 }
756 _ => {
757 true_or_fault!(
758 self,
759 (1..=3).contains(&benv.len()),
760 "benv.len() is not between 1 and 3"
761 );
762 let mut out = *benv.first().unwrap();
763 benv.into_iter().skip(1).for_each(|op| {
764 self.curr_plan().add_flow(out, op);
765 out = op;
766 });
767 self.push_bexpr(out);
768 }
769 }
770 Traverse::Continue
771 }
772
773 fn enter_query_set(&mut self, _query_set: &'ast QuerySet) -> Traverse {
774 self.enter_env();
775 self.enter_benv();
776
777 match _query_set {
778 QuerySet::BagOp(_) => {}
779 QuerySet::Select(_) => {}
780 QuerySet::Expr(_) => {}
781 QuerySet::Values(_) => {
782 not_yet_implemented_fault!(self, "QuerySet::Values".to_string());
783 }
784 QuerySet::Table(_) => {
785 not_yet_implemented_fault!(self, "QuerySet::Table".to_string());
786 }
787 }
788 Traverse::Continue
789 }
790
791 fn exit_query_set(&mut self, query_set: &'ast QuerySet) -> Traverse {
792 let env = self.exit_env();
793 let mut benv = self.exit_benv();
794
795 match query_set {
796 QuerySet::BagOp(bag_op) => {
797 eq_or_fault!(self, benv.len(), 2, "qs benv.len() != 2");
798 let rid = benv.pop().unwrap();
799 let lid = benv.pop().unwrap();
800
801 let bag_operator = match bag_op.node.bag_op {
802 BagOperator::Union => logical::BagOperator::Union,
803 BagOperator::Except => logical::BagOperator::Except,
804 BagOperator::Intersect => logical::BagOperator::Intersect,
805 BagOperator::OuterUnion => logical::BagOperator::OuterUnion,
806 BagOperator::OuterExcept => logical::BagOperator::OuterExcept,
807 BagOperator::OuterIntersect => logical::BagOperator::OuterIntersect,
808 };
809 let setq = match bag_op.node.setq {
810 Some(SetQuantifier::All) => logical::SetQuantifier::All,
811 Some(SetQuantifier::Distinct) => logical::SetQuantifier::Distinct,
812 None => logical::SetQuantifier::Distinct,
813 };
814
815 let id = self.curr_plan().add_operator(BindingsOp::BagOp(BagOp {
816 bag_op: bag_operator,
817 setq,
818 }));
819 self.curr_plan().add_flow_with_branch_num(lid, id, 0);
820 self.curr_plan().add_flow_with_branch_num(rid, id, 1);
821 self.push_bexpr(id);
822 }
823 QuerySet::Select(_) => {}
824 QuerySet::Expr(_) => {
825 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
826 let (_, expr) = env.into_iter().next().unwrap();
827 let op = BindingsOp::ExprQuery(logical::ExprQuery { expr });
828 let id = self.curr_plan().add_operator(op);
829 self.push_bexpr(id);
830 }
831 QuerySet::Values(_) => {
832 not_yet_implemented_fault!(self, "QuerySet::Values".to_string());
833 }
834 QuerySet::Table(_) => {
835 not_yet_implemented_fault!(self, "QuerySet::Table".to_string());
836 }
837 }
838 Traverse::Continue
839 }
840
841 fn enter_bag_op_expr(&mut self, _set_expr: &'ast BagOpExpr) -> Traverse {
842 Traverse::Continue
843 }
844
845 fn exit_bag_op_expr(&mut self, _set_expr: &'ast BagOpExpr) -> Traverse {
846 Traverse::Continue
847 }
848
849 fn enter_exclusion(&mut self, _exclusion: &'ast Exclusion) -> Traverse {
850 not_yet_implemented_fault!(self, "EXCLUDE");
851 }
852
853 fn enter_select(&mut self, select: &'ast Select) -> Traverse {
854 if select.having.is_some() && select.group_by.is_none() {
855 self.errors.push(AstTransformError::HavingWithoutGroupBy);
856 Traverse::Stop
857 } else {
858 Traverse::Continue
859 }
860 }
861
862 fn exit_select(&mut self, _select: &'ast Select) -> Traverse {
863 if !self.aggregate_exprs.last().unwrap().is_empty()
866 && self.current_clauses_mut().group_by_clause.is_none()
867 {
868 let exprs = FxHashMap::from_iter([(
869 "$__gk".to_string(),
870 ValueExpr::Lit(Box::new(logical::Lit::Bool(true))),
871 )]);
872 let group_by: BindingsOp = BindingsOp::GroupBy(logical::GroupBy {
873 strategy: logical::GroupingStrategy::GroupFull,
874 exprs,
875 aggregate_exprs: self.aggregate_exprs.last().unwrap().clone(),
876 group_as_alias: None,
877 });
878 let id = self.curr_plan().add_operator(group_by);
879 self.current_clauses_mut().group_by_clause.replace(id);
880 }
881 Traverse::Continue
882 }
883
884 fn enter_projection(&mut self, _projection: &'ast Projection) -> Traverse {
885 self.enter_benv();
886 self.enter_env();
887 Traverse::Continue
888 }
889
890 fn exit_projection(&mut self, projection: &'ast Projection) -> Traverse {
891 let benv = self.exit_benv();
892 eq_or_fault!(self, benv.len(), 0, "benv.len() != 0");
893
894 let env = self.exit_env();
895 eq_or_fault!(self, env.len(), 0, "env.len() != 0");
896
897 if let Some(SetQuantifier::Distinct) = projection.setq {
898 let id = self.curr_plan().add_operator(BindingsOp::Distinct);
899 self.current_clauses_mut().distinct.replace(id);
900 }
901 Traverse::Continue
902 }
903
904 fn enter_projection_kind(&mut self, _projection_kind: &'ast ProjectionKind) -> Traverse {
905 self.enter_benv();
906 self.enter_env();
907 Traverse::Continue
908 }
909
910 fn exit_projection_kind(&mut self, _projection_kind: &'ast ProjectionKind) -> Traverse {
911 let benv = self.exit_benv();
912 if !benv.is_empty() {
913 not_yet_implemented_fault!(self, "Subquery within project".to_string());
914 }
915 let env = self.exit_env();
916
917 let select: BindingsOp = match _projection_kind {
918 ProjectionKind::ProjectStar => logical::BindingsOp::ProjectAll(Default::default()),
919 ProjectionKind::ProjectList(_) => {
920 true_or_fault!(self, env.len().is_even(), "env.len() is not even");
921 let mut exprs = Vec::with_capacity(env.len() / 2);
922 let mut iter = env.into_iter();
923 while let Some((_, value)) = iter.next() {
924 let (_, alias) = iter.next().unwrap();
925 let alias = match alias {
926 ValueExpr::Lit(lit) => match *lit {
927 logical::Lit::String(s) => s.clone(),
928 _ => {
929 self.errors.push(AstTransformError::IllegalState(
931 "Unexpected literal type".to_string(),
932 ));
933 String::new()
934 }
935 },
936 _ => {
937 self.errors.push(AstTransformError::IllegalState(
939 "Invalid alias type".to_string(),
940 ));
941 String::new()
942 }
943 };
944
945 if !alias.is_empty() {
946 if let ValueExpr::VarRef(name, _vrtype) = &value {
947 self.projection_renames
948 .last_mut()
949 .expect("renames")
950 .insert(alias.clone(), name.clone());
951 }
952 }
953 exprs.push((alias, value));
954 }
955
956 logical::BindingsOp::Project(logical::Project { exprs })
957 }
958 ProjectionKind::ProjectPivot(_) => {
959 eq_or_fault!(self, env.len(), 2, "env.len() != 2");
960
961 let mut iter = env.into_iter();
962 let (_, key) = iter.next().unwrap();
963 let (_, value) = iter.next().unwrap();
964 logical::BindingsOp::Pivot(logical::Pivot { key, value })
965 }
966 ProjectionKind::ProjectValue(_) => {
967 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
968
969 let (_, expr) = env.into_iter().next().unwrap();
970 logical::BindingsOp::ProjectValue(logical::ProjectValue { expr })
971 }
972 };
973 let id = self.curr_plan().add_operator(select);
974 self.current_clauses_mut().select_clause.replace(id);
975 Traverse::Continue
976 }
977
978 fn exit_project_expr(&mut self, _project_expr: &'ast ProjectExpr) -> Traverse {
979 let as_key: &name_resolver::Symbol = self
980 .key_registry
981 .aliases
982 .get(self.current_node())
983 .expect("alias");
984 let as_key = match as_key {
986 name_resolver::Symbol::Known(sym) => sym.value.clone(),
987 name_resolver::Symbol::Unknown(id) => format!("_{id}"),
988 };
989 self.push_lit(logical::Lit::String(as_key));
990 Traverse::Continue
991 }
992
993 fn enter_bin_op(&mut self, _bin_op: &'ast BinOp) -> Traverse {
994 self.enter_env();
995 Traverse::Continue
996 }
997
998 fn exit_bin_op(&mut self, _bin_op: &'ast BinOp) -> Traverse {
999 let mut env = self.exit_env();
1000 eq_or_fault!(self, env.len(), 2, "env.len() != 2");
1001
1002 let (_, rhs) = env.pop().unwrap();
1003 let (_, lhs) = env.pop().unwrap();
1004 if _bin_op.kind == BinOpKind::Is {
1005 let is_type = match rhs {
1006 ValueExpr::Lit(lit) => match lit.as_ref() {
1007 logical::Lit::Null => logical::Type::NullType,
1008 logical::Lit::Missing => logical::Type::MissingType,
1009 _ => {
1010 not_yet_implemented_fault!(
1011 self,
1012 "Unsupported rhs literal for `IS`".to_string()
1013 );
1014 }
1015 },
1016 _ => {
1017 not_yet_implemented_fault!(self, "Unsupported rhs for `IS`".to_string());
1018 }
1019 };
1020 self.push_vexpr(ValueExpr::IsTypeExpr(IsTypeExpr {
1021 not: false,
1022 expr: Box::new(lhs),
1023 is_type,
1024 }));
1025 } else {
1026 let op = match _bin_op.kind {
1027 BinOpKind::Add => logical::BinaryOp::Add,
1028 BinOpKind::Div => logical::BinaryOp::Div,
1029 BinOpKind::Exp => logical::BinaryOp::Exp,
1030 BinOpKind::Mod => logical::BinaryOp::Mod,
1031 BinOpKind::Mul => logical::BinaryOp::Mul,
1032 BinOpKind::Sub => logical::BinaryOp::Sub,
1033 BinOpKind::And => logical::BinaryOp::And,
1034 BinOpKind::Or => logical::BinaryOp::Or,
1035 BinOpKind::Concat => logical::BinaryOp::Concat,
1036 BinOpKind::Eq => logical::BinaryOp::Eq,
1037 BinOpKind::Gt => logical::BinaryOp::Gt,
1038 BinOpKind::Gte => logical::BinaryOp::Gteq,
1039 BinOpKind::Lt => logical::BinaryOp::Lt,
1040 BinOpKind::Lte => logical::BinaryOp::Lteq,
1041 BinOpKind::Ne => logical::BinaryOp::Neq,
1042 BinOpKind::Is => unreachable!(),
1043 };
1044 self.push_vexpr(ValueExpr::BinaryExpr(op, Box::new(lhs), Box::new(rhs)));
1045 }
1046 Traverse::Continue
1047 }
1048
1049 fn enter_uni_op(&mut self, _uni_op: &'ast UniOp) -> Traverse {
1050 self.enter_env();
1051 Traverse::Continue
1052 }
1053
1054 fn exit_uni_op(&mut self, _uni_op: &'ast UniOp) -> Traverse {
1055 let mut env = self.exit_env();
1056 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1057
1058 let (_, expr) = env.pop().unwrap();
1059 let op = match _uni_op.kind {
1060 UniOpKind::Pos => logical::UnaryOp::Pos,
1061 UniOpKind::Neg => logical::UnaryOp::Neg,
1062 UniOpKind::Not => logical::UnaryOp::Not,
1063 };
1064 self.push_vexpr(ValueExpr::UnExpr(op, Box::new(expr)));
1065 Traverse::Continue
1066 }
1067
1068 fn enter_between(&mut self, _between: &'ast Between) -> Traverse {
1069 self.enter_env();
1070 Traverse::Continue
1071 }
1072
1073 fn exit_between(&mut self, _between: &'ast Between) -> Traverse {
1074 let mut env = self.exit_env();
1075 eq_or_fault!(self, env.len(), 3, "env.len() != 3");
1076
1077 let to = Box::new(env.pop().unwrap().1);
1078 let from = Box::new(env.pop().unwrap().1);
1079 let value = Box::new(env.pop().unwrap().1);
1080 self.push_vexpr(ValueExpr::BetweenExpr(BetweenExpr { value, from, to }));
1081 Traverse::Continue
1082 }
1083
1084 fn enter_in(&mut self, _in: &'ast ast::In) -> Traverse {
1085 self.enter_env();
1086 Traverse::Continue
1087 }
1088 fn exit_in(&mut self, _in: &'ast ast::In) -> Traverse {
1089 let mut env = self.exit_env();
1090 eq_or_fault!(self, env.len(), 2, "env.len() != 2");
1091
1092 let (_, rhs) = env.pop().unwrap();
1093 let (_, lhs) = env.pop().unwrap();
1094 self.push_vexpr(logical::ValueExpr::BinaryExpr(
1095 logical::BinaryOp::In,
1096 Box::new(lhs),
1097 Box::new(rhs),
1098 ));
1099 Traverse::Continue
1100 }
1101
1102 fn enter_like(&mut self, _like: &'ast Like) -> Traverse {
1103 self.enter_env();
1104 Traverse::Continue
1105 }
1106
1107 fn exit_like(&mut self, _like: &'ast Like) -> Traverse {
1108 let mut env = self.exit_env();
1109 true_or_fault!(
1110 self,
1111 (2..=3).contains(&env.len()),
1112 "env.len() is not between 2 and 3"
1113 );
1114 let escape_ve = if env.len() == 3 {
1115 env.pop().unwrap().1
1116 } else {
1117 ValueExpr::Lit(Box::new(logical::Lit::String(String::default())))
1118 };
1119 let pattern_ve = env.pop().unwrap().1;
1120 let value = Box::new(env.pop().unwrap().1);
1121
1122 let pattern = match (&pattern_ve, &escape_ve) {
1123 (ValueExpr::Lit(pattern_lit), ValueExpr::Lit(escape_lit)) => {
1124 match (pattern_lit.as_ref(), escape_lit.as_ref()) {
1125 (logical::Lit::String(pattern), logical::Lit::String(escape)) => {
1126 Pattern::Like(LikeMatch {
1127 pattern: pattern.to_string(),
1128 escape: escape.to_string(),
1129 })
1130 }
1131 _ => Pattern::LikeNonStringNonLiteral(LikeNonStringNonLiteralMatch {
1132 pattern: Box::new(pattern_ve),
1133 escape: Box::new(escape_ve),
1134 }),
1135 }
1136 }
1137 _ => Pattern::LikeNonStringNonLiteral(LikeNonStringNonLiteralMatch {
1138 pattern: Box::new(pattern_ve),
1139 escape: Box::new(escape_ve),
1140 }),
1141 };
1142
1143 let pattern = ValueExpr::PatternMatchExpr(PatternMatchExpr { value, pattern });
1144 self.push_vexpr(pattern);
1145 Traverse::Continue
1146 }
1147
1148 fn enter_call(&mut self, _call: &'ast Call) -> Traverse {
1149 self.enter_call();
1150 Traverse::Continue
1151 }
1152
1153 fn exit_call(&mut self, call: &'ast Call) -> Traverse {
1154 let args = self.exit_call();
1156 let name = call.func_name.value.to_lowercase();
1157
1158 let call_def_to_vexpr = |call_def: &CallDef| call_def.lookup(&args, &name);
1159
1160 let call_expr = self
1161 .fnsym_tab
1162 .lookup(&name)
1163 .map(call_def_to_vexpr)
1164 .or_else(|| {
1165 self.catalog
1166 .get_function(&name)
1167 .map(|e| e.resolve(&name, &args))
1168 })
1169 .map(|res| res.map_err(Into::into))
1170 .unwrap_or_else(|| Err(AstTransformError::UnsupportedFunction(name.clone())));
1171
1172 let expr = match call_expr {
1173 Ok(expr) => expr,
1174 Err(err) => {
1175 self.errors.push(err);
1176 ValueExpr::Lit(Box::new(logical::Lit::Missing)) }
1178 };
1179 self.push_vexpr(expr);
1180 Traverse::Continue
1181 }
1182
1183 fn enter_call_arg(&mut self, _call_arg: &'ast CallArg) -> Traverse {
1184 self.enter_env();
1185 Traverse::Continue
1186 }
1187
1188 fn exit_call_arg(&mut self, _call_arg: &'ast CallArg) -> Traverse {
1189 let mut env = self.exit_env();
1190 match _call_arg {
1191 CallArg::Star() => {
1192 self.push_call_arg(CallArgument::Star);
1193 }
1194 CallArg::Positional(_) => {
1195 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1196
1197 self.push_call_arg(CallArgument::Positional(env.pop().unwrap().1));
1198 }
1199 CallArg::Named(CallArgNamed { name, .. }) => {
1200 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1201
1202 let name = name.value.to_lowercase();
1203 self.push_call_arg(CallArgument::Named(name, env.pop().unwrap().1));
1204 }
1205 CallArg::PositionalType(_) => {
1206 not_yet_implemented_fault!(self, "PositionalType call argument".to_string());
1207 }
1208 CallArg::NamedType(_) => {
1209 not_yet_implemented_fault!(self, "NamedType call argument".to_string());
1210 }
1211 }
1212 Traverse::Continue
1213 }
1214
1215 fn enter_lit(&mut self, lit: &'ast Lit) -> Traverse {
1218 let val = match lit_to_lit(lit) {
1219 Ok(v) => v,
1220 Err(e) => {
1221 self.errors.push(e);
1223 logical::Lit::Missing
1224 }
1225 };
1226 self.push_lit(val);
1227 Traverse::Continue
1228 }
1229
1230 fn enter_struct(&mut self, _struct: &'ast Struct) -> Traverse {
1231 self.enter_env();
1232 Traverse::Continue
1233 }
1234
1235 fn exit_struct(&mut self, _struct: &'ast Struct) -> Traverse {
1236 let env = self.exit_env();
1237 true_or_fault!(self, env.len().is_even(), "env.len() is not even");
1238
1239 let len = env.len() / 2;
1240 let mut attrs = Vec::with_capacity(len);
1241 let mut values = Vec::with_capacity(len);
1242
1243 let mut iter = env.into_iter();
1244 while let Some((_, attr)) = iter.next() {
1245 let (_, value) = iter.next().unwrap();
1246 attrs.push(attr);
1247 values.push(value);
1248 }
1249
1250 self.push_vexpr(ValueExpr::TupleExpr(TupleExpr { attrs, values }));
1251 Traverse::Continue
1252 }
1253
1254 fn enter_bag(&mut self, _bag: &'ast Bag) -> Traverse {
1255 self.enter_env();
1256 Traverse::Continue
1257 }
1258
1259 fn exit_bag(&mut self, _bag: &'ast Bag) -> Traverse {
1260 let elements = self.exit_env().into_iter().map(|(_, v)| v).collect();
1261 self.push_vexpr(ValueExpr::BagExpr(BagExpr { elements }));
1262 Traverse::Continue
1263 }
1264
1265 fn enter_list(&mut self, _list: &'ast List) -> Traverse {
1266 self.enter_env();
1267 Traverse::Continue
1268 }
1269
1270 fn exit_list(&mut self, _list: &'ast List) -> Traverse {
1271 let elements = self.exit_env().into_iter().map(|(_, v)| v).collect();
1272 self.push_vexpr(ValueExpr::ListExpr(ListExpr { elements }));
1273 Traverse::Continue
1274 }
1275
1276 fn enter_call_agg(&mut self, _call_agg: &'ast CallAgg) -> Traverse {
1277 self.enter_call();
1278 Traverse::Continue
1279 }
1280
1281 fn exit_call_agg(&mut self, call_agg: &'ast CallAgg) -> Traverse {
1282 let mut env = self.exit_call();
1285 let name = call_agg.func_name.value.to_lowercase();
1286
1287 let new_name = "$__agg".to_owned() + &self.agg_id.id();
1292 let new_binding_name = BindingsName::CaseSensitive(Cow::Owned(new_name.clone()));
1293 let new_expr = ValueExpr::VarRef(new_binding_name, VarRefType::Local);
1294 self.push_vexpr(new_expr);
1295
1296 true_or_fault!(self, !env.is_empty(), "env is empty");
1297 let (setq, arg) = match env.pop().unwrap() {
1299 CallArgument::Positional(ve) => (logical::SetQuantifier::All, ve),
1300 CallArgument::Named(name, ve) => match name.as_ref() {
1301 "all" => (logical::SetQuantifier::All, ve),
1302 "distinct" => (logical::SetQuantifier::Distinct, ve),
1303 _ => {
1304 self.errors.push(AstTransformError::IllegalState(
1305 "Invalid set quantifier".to_string(),
1306 ));
1307 return Traverse::Stop;
1308 }
1309 },
1310 CallArgument::Star => (
1311 logical::SetQuantifier::All,
1312 ValueExpr::Lit(Box::new(logical::Lit::Int8(1))),
1313 ),
1314 };
1315
1316 let agg_expr = match name.as_str() {
1317 "avg" => AggregateExpression {
1318 name: new_name,
1319 expr: arg,
1320 func: AggAvg,
1321 setq,
1322 },
1323 "count" => AggregateExpression {
1324 name: new_name,
1325 expr: arg,
1326 func: AggCount,
1327 setq,
1328 },
1329 "max" => AggregateExpression {
1330 name: new_name,
1331 expr: arg,
1332 func: AggMax,
1333 setq,
1334 },
1335 "min" => AggregateExpression {
1336 name: new_name,
1337 expr: arg,
1338 func: AggMin,
1339 setq,
1340 },
1341 "sum" => AggregateExpression {
1342 name: new_name,
1343 expr: arg,
1344 func: AggSum,
1345 setq,
1346 },
1347 "any" | "some" => AggregateExpression {
1348 name: new_name,
1349 expr: arg,
1350 func: AggAny,
1351 setq,
1352 },
1353 "every" => AggregateExpression {
1354 name: new_name,
1355 expr: arg,
1356 func: AggEvery,
1357 setq,
1358 },
1359 _ => {
1360 self.errors
1362 .push(AstTransformError::UnsupportedFunction(name));
1363 AggregateExpression {
1365 name: new_name,
1366 expr: arg,
1367 func: AggAvg,
1368 setq,
1369 }
1370 }
1371 };
1372 self.aggregate_exprs.last_mut().unwrap().push(agg_expr);
1373 Traverse::Continue
1374 }
1375
1376 fn enter_var_ref(&mut self, var_ref: &'ast VarRef) -> Traverse {
1377 let is_path = matches!(self.current_ctx(), Some(QueryContext::Path));
1378 if !is_path {
1379 let options = self.resolve_varref(var_ref);
1380 self.push_vexpr(options);
1381 } else {
1382 let VarRef {
1383 name: SymbolPrimitive { value, case },
1384 qualifier: _,
1385 } = var_ref;
1386 let name = match case {
1387 CaseSensitivity::CaseSensitive => {
1388 BindingsName::CaseSensitive(Cow::Owned(value.clone()))
1389 }
1390 CaseSensitivity::CaseInsensitive => {
1391 BindingsName::CaseInsensitive(Cow::Owned(value.clone()))
1392 }
1393 };
1394 self.push_vexpr(ValueExpr::VarRef(name, VarRefType::Local));
1395 }
1396 Traverse::Continue
1397 }
1398
1399 fn exit_var_ref(&mut self, _var_ref: &'ast VarRef) -> Traverse {
1400 Traverse::Continue
1401 }
1402
1403 fn enter_path(&mut self, _path: &'ast Path) -> Traverse {
1404 self.enter_env();
1405 self.enter_path();
1406 Traverse::Continue
1407 }
1408
1409 fn exit_path(&mut self, _path: &'ast Path) -> Traverse {
1410 let mut env = self.exit_env();
1411 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1412
1413 let steps = self.exit_path();
1414 let (_, root) = env.pop().unwrap();
1415
1416 self.push_vexpr(ValueExpr::Path(Box::new(root), steps));
1417 Traverse::Continue
1418 }
1419
1420 fn enter_path_step(&mut self, path_step: &'ast PathStep) -> Traverse {
1421 if let PathStep::PathIndex(expr) | PathStep::PathProject(expr) = path_step {
1422 self.enter_env();
1423 match *(expr.index) {
1424 Expr::VarRef(_) => {
1425 let qc = self.ctx_stack.last_mut().unwrap();
1427 *qc = QueryContext::Path;
1428 }
1429 _ => {
1430 let qc = self.ctx_stack.last_mut().unwrap();
1432 *qc = QueryContext::Query;
1433 }
1434 }
1435 }
1436 Traverse::Continue
1437 }
1438
1439 fn exit_path_step(&mut self, path_step: &'ast PathStep) -> Traverse {
1440 let step = match path_step {
1441 PathStep::PathProject(_s) | PathStep::PathIndex(_s) => {
1442 let mut env = self.exit_env();
1443 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1444
1445 let (_, path) = env.pop().unwrap();
1446 match path {
1447 ValueExpr::Lit(val) => match *val {
1448 logical::Lit::Int8(idx) => logical::PathComponent::Index(idx.into()),
1449 logical::Lit::Int16(idx) => logical::PathComponent::Index(idx.into()),
1450 logical::Lit::Int32(idx) => logical::PathComponent::Index(idx.into()),
1451 logical::Lit::Int64(idx) => logical::PathComponent::Index(idx),
1452 logical::Lit::String(k) => logical::PathComponent::Key(
1453 BindingsName::CaseInsensitive(Cow::Owned(k)),
1454 ),
1455 expr => logical::PathComponent::IndexExpr(Box::new(ValueExpr::Lit(
1456 Box::new(expr),
1457 ))),
1458 },
1459 ValueExpr::VarRef(name, _) => logical::PathComponent::Key(name),
1460 expr => {
1461 logical::PathComponent::IndexExpr(Box::new(expr))
1463 }
1464 }
1465 }
1466 PathStep::PathForEach => {
1467 not_yet_implemented_fault!(self, "PathStep::PathForEach".to_string());
1468 }
1469 PathStep::PathUnpivot => {
1470 not_yet_implemented_fault!(self, "PathStep::PathUnpivot".to_string());
1471 }
1472 };
1473
1474 self.push_path_step(step);
1475 Traverse::Continue
1476 }
1477
1478 fn enter_from_clause(&mut self, _from_clause: &'ast FromClause) -> Traverse {
1479 self.enter_benv();
1480 self.enter_env();
1481 Traverse::Continue
1482 }
1483
1484 fn exit_from_clause(&mut self, _from_clause: &'ast FromClause) -> Traverse {
1485 let mut benv = self.exit_benv();
1486 eq_or_fault!(self, benv.len(), 1, "benv.len() != 1");
1487
1488 let env = self.exit_env();
1489 eq_or_fault!(self, env.len(), 0, "env.len() != 0");
1490
1491 self.current_clauses_mut()
1492 .from_clause
1493 .replace(benv.pop().unwrap());
1494 Traverse::Continue
1495 }
1496
1497 fn enter_from_let(&mut self, from_let: &'ast FromLet) -> Traverse {
1498 *self.current_ctx_mut() = QueryContext::FromLet;
1499 self.enter_plan();
1500 self.enter_benv();
1501 self.enter_env();
1502
1503 let id = *self.current_node();
1504
1505 for sym in [&from_let.as_alias, &from_let.at_alias, &from_let.by_alias]
1506 .into_iter()
1507 .flatten()
1508 {
1509 self.aliases.insert(id, sym.clone());
1510 }
1511 Traverse::Continue
1512 }
1513
1514 fn exit_from_let(&mut self, from_let: &'ast FromLet) -> Traverse {
1515 *self.current_ctx_mut() = QueryContext::Query;
1516 let subplan = self.exit_plan();
1517 let benv = self.exit_benv();
1518 let mut env = self.exit_env();
1519 eq_or_fault!(self, env.len() + benv.len(), 1, "env.len()+benv.len() != 1");
1520
1521 let expr = if !benv.is_empty() {
1522 let subq = logical::SubQueryExpr { plan: subplan };
1524 ValueExpr::SubQueryExpr(subq)
1525 } else {
1526 self.curr_plan().merge_plan(subplan); env.pop().unwrap().1
1529 };
1530
1531 let FromLet {
1532 kind,
1533 as_alias,
1534 at_alias,
1535 ..
1536 } = from_let;
1537 let as_key = self.infer_id(&expr, as_alias).value;
1538 let at_key = at_alias
1539 .as_ref()
1540 .map(|SymbolPrimitive { value, case: _ }| value.clone());
1541
1542 let (bexpr, project_all_mode) = match kind {
1543 FromLetKind::Scan => (
1544 logical::BindingsOp::Scan(logical::Scan {
1545 expr,
1546 as_key,
1547 at_key,
1548 }),
1549 ProjectAllMode::Unwrap,
1550 ),
1551 FromLetKind::Unpivot => (
1552 logical::BindingsOp::Unpivot(logical::Unpivot {
1553 expr,
1554 as_key,
1555 at_key,
1556 }),
1557 ProjectAllMode::PassThrough,
1558 ),
1559 FromLetKind::GraphTable => (
1560 logical::BindingsOp::Scan(logical::Scan {
1561 expr,
1562 as_key,
1563 at_key,
1564 }),
1565 ProjectAllMode::Unwrap,
1566 ),
1567 };
1568
1569 let id = self.curr_plan().add_operator(bexpr);
1570 self.push_bexpr(id);
1571
1572 if let Some(select_id) = self.current_clauses_mut().select_clause {
1573 if let Some(BindingsOp::ProjectAll(mode)) = self.curr_plan().operator_as_mut(select_id)
1574 {
1575 *mode = project_all_mode
1576 }
1577 }
1578
1579 Traverse::Continue
1580 }
1581
1582 fn enter_join(&mut self, _join: &'ast Join) -> Traverse {
1583 self.enter_benv();
1584 self.enter_env();
1585 Traverse::Continue
1586 }
1587
1588 fn exit_join(&mut self, join: &'ast Join) -> Traverse {
1589 let mut benv = self.exit_benv();
1590 eq_or_fault!(self, benv.len(), 2, "j benv.len() != 2");
1591
1592 let mut env = self.exit_env();
1593 true_or_fault!(
1594 self,
1595 (0..=1).contains(&env.len()),
1596 "env.len() is not between 0 and 1"
1597 );
1598
1599 let Join { kind, .. } = join;
1600
1601 let kind = match kind {
1602 JoinKind::Inner => logical::JoinKind::Inner,
1603 JoinKind::Left => logical::JoinKind::Left,
1604 JoinKind::Right => logical::JoinKind::Right,
1605 JoinKind::Full => logical::JoinKind::Full,
1606 JoinKind::Cross => logical::JoinKind::Cross,
1607 };
1608
1609 let on = env.pop().map(|(_, v)| v);
1610
1611 let rid = benv.pop().unwrap();
1612 let lid = benv.pop().unwrap();
1613 let left = Box::new(self.curr_plan().operator(lid).unwrap().clone());
1614 let right = Box::new(self.curr_plan().operator(rid).unwrap().clone());
1615 let join = logical::BindingsOp::Join(logical::Join {
1616 kind,
1617 left,
1618 right,
1619 on,
1620 });
1621 let join = self.curr_plan().add_operator(join);
1622 self.curr_plan().add_flow_with_branch_num(lid, join, 0);
1623 self.curr_plan().add_flow_with_branch_num(rid, join, 1);
1624 self.push_bexpr(join);
1625 Traverse::Continue
1626 }
1627
1628 fn enter_join_spec(&mut self, join_spec: &'ast JoinSpec) -> Traverse {
1629 match join_spec {
1630 JoinSpec::On(_) => {
1631 }
1633 JoinSpec::Using(_) => {
1634 not_yet_implemented_fault!(self, "JoinSpec::Using".to_string());
1635 }
1636 JoinSpec::Natural => {
1637 not_yet_implemented_fault!(self, "JoinSpec::Natural".to_string());
1638 }
1639 };
1640 Traverse::Continue
1641 }
1642
1643 fn enter_where_clause(&mut self, _where_clause: &'ast ast::WhereClause) -> Traverse {
1644 self.enter_env();
1645 Traverse::Continue
1646 }
1647
1648 fn exit_where_clause(&mut self, _where_clause: &'ast ast::WhereClause) -> Traverse {
1649 let mut env = self.exit_env();
1650 eq_or_fault!(self, env.len(), 1, "env.len() != 1");
1651
1652 let filter = logical::BindingsOp::Filter(logical::Filter {
1653 expr: env.pop().unwrap().1,
1654 });
1655 let id = self.curr_plan().add_operator(filter);
1656
1657 self.current_clauses_mut().where_clause.replace(id);
1658 Traverse::Continue
1659 }
1660
1661 fn enter_having_clause(&mut self, _having_clause: &'ast ast::HavingClause) -> Traverse {
1662 self.enter_env();
1663 Traverse::Continue
1664 }
1665
1666 fn exit_having_clause(&mut self, _having_clause: &'ast ast::HavingClause) -> Traverse {
1667 let mut env = self.exit_env();
1668 eq_or_fault!(self, env.len(), 1, "env.len() is 1");
1669
1670 let having = BindingsOp::Having(logical::Having {
1671 expr: env.pop().unwrap().1,
1672 });
1673 let id = self.curr_plan().add_operator(having);
1674
1675 self.current_clauses_mut().having_clause.replace(id);
1676 Traverse::Continue
1677 }
1678
1679 fn enter_group_by_expr(&mut self, _group_by_expr: &'ast GroupByExpr) -> Traverse {
1680 self.enter_benv();
1681 self.enter_env();
1682 Traverse::Continue
1683 }
1684
1685 fn exit_group_by_expr(&mut self, group_by_expr: &'ast GroupByExpr) -> Traverse {
1686 let aggregate_exprs = self.aggregate_exprs.last().unwrap().clone();
1687 let benv = self.exit_benv();
1688 if !benv.is_empty() {
1689 {
1690 not_yet_implemented_fault!(self, "Subquery in group by".to_string());
1691 }
1692 }
1693 let env = self.exit_env();
1694 true_or_fault!(self, env.len().is_even(), "env.len() is not even");
1695
1696 let group_as_alias = group_by_expr
1697 .group_as_alias
1698 .as_ref()
1699 .map(|SymbolPrimitive { value, case: _ }| value.clone());
1700
1701 let strategy = match group_by_expr.strategy {
1702 None => logical::GroupingStrategy::GroupFull,
1703 Some(GroupingStrategy::GroupFull) => logical::GroupingStrategy::GroupFull,
1704 Some(GroupingStrategy::GroupPartial) => logical::GroupingStrategy::GroupPartial,
1705 };
1706
1707 let select_clause_op_id = self.current_clauses_mut().select_clause;
1717 if select_clause_op_id.is_none() {
1718 self.errors.push(AstTransformError::IllegalState(
1719 "select_clause_op_id is None".to_string(),
1720 ));
1721 return Traverse::Stop;
1722 }
1723 let mut errors = Vec::default();
1724 let select_clause = self
1725 .curr_plan()
1726 .operator_as_mut(select_clause_op_id.expect("select_clause_op_id not None"))
1727 .unwrap();
1728 let mut binding = Vec::new();
1729 let select_clause_exprs = match select_clause {
1730 BindingsOp::Project(ref mut project) => &mut project.exprs,
1731 BindingsOp::ProjectAll(_) => &mut binding,
1732 BindingsOp::ProjectValue(_) => &mut binding, _ => {
1734 self.errors.push(AstTransformError::IllegalState(
1735 "Unexpected project type".to_string(),
1736 ));
1737 return Traverse::Stop;
1738 }
1739 };
1740 let mut exprs = FxHashMap::with_capacity_and_hasher(env.len() / 2, FxBuildHasher);
1741 let mut iter = env.into_iter();
1742
1743 while let Some((_, value)) = iter.next() {
1744 let (_, alias) = iter.next().unwrap();
1745 let alias = match alias {
1746 ValueExpr::Lit(lit) => match *lit {
1747 logical::Lit::String(s) => s.clone(),
1748 _ => {
1749 errors.push(AstTransformError::IllegalState(
1751 "Unexpected literal type".to_string(),
1752 ));
1753 String::new()
1754 }
1755 },
1756 _ => {
1757 errors.push(AstTransformError::IllegalState(
1758 "Unexpected alias type".to_string(),
1759 ));
1760 return Traverse::Stop;
1761 }
1762 };
1763 for (alias, expr) in select_clause_exprs.iter_mut() {
1764 if *expr == value {
1765 let new_binding_name = BindingsName::CaseSensitive(Cow::Owned(alias.clone()));
1766 let new_expr = ValueExpr::VarRef(new_binding_name, VarRefType::Local);
1767 *expr = new_expr;
1768 }
1769 }
1770 exprs.insert(alias, value);
1771 }
1772
1773 self.errors.extend(errors);
1774
1775 let group_by: BindingsOp = BindingsOp::GroupBy(logical::GroupBy {
1776 strategy,
1777 exprs,
1778 aggregate_exprs,
1779 group_as_alias,
1780 });
1781
1782 let id = self.curr_plan().add_operator(group_by);
1783 self.current_clauses_mut().group_by_clause.replace(id);
1784 Traverse::Continue
1785 }
1786
1787 fn exit_group_key(&mut self, _group_key: &'ast GroupKey) -> Traverse {
1788 let as_key: &name_resolver::Symbol = self
1789 .key_registry
1790 .aliases
1791 .get(self.current_node())
1792 .expect("alias");
1793 let as_key = match as_key {
1795 name_resolver::Symbol::Known(sym) => sym.value.clone(),
1796 name_resolver::Symbol::Unknown(id) => format!("_{id}"),
1797 };
1798 self.push_lit(logical::Lit::String(as_key));
1799 Traverse::Continue
1800 }
1801
1802 fn enter_order_by_expr(&mut self, _order_by_expr: &'ast OrderByExpr) -> Traverse {
1803 self.enter_sort();
1804 Traverse::Continue
1805 }
1806
1807 fn exit_order_by_expr(&mut self, _order_by_expr: &'ast OrderByExpr) -> Traverse {
1808 let specs = self.exit_sort();
1809 let order_by = logical::BindingsOp::OrderBy(logical::OrderBy { specs });
1810 let id = self.curr_plan().add_operator(order_by);
1811 if matches!(self.current_ctx(), Some(QueryContext::Query)) {
1812 self.current_clauses_mut().order_by_clause.replace(id);
1813 } else {
1814 self.push_bexpr(id);
1815 }
1816 Traverse::Continue
1817 }
1818
1819 fn enter_sort_spec(&mut self, _sort_spec: &'ast SortSpec) -> Traverse {
1820 self.enter_env();
1821 Traverse::Continue
1822 }
1823
1824 fn exit_sort_spec(&mut self, sort_spec: &'ast SortSpec) -> Traverse {
1825 let mut env = self.exit_env();
1826 eq_or_fault!(self, env.len(), 1, "env.len() is 1");
1827
1828 let (_, expr) = env.pop().unwrap();
1829 let order = match sort_spec
1830 .ordering_spec
1831 .as_ref()
1832 .unwrap_or(&OrderingSpec::Asc)
1833 {
1834 OrderingSpec::Asc => logical::SortSpecOrder::Asc,
1835 OrderingSpec::Desc => logical::SortSpecOrder::Desc,
1836 };
1837
1838 let null_order = match sort_spec.null_ordering_spec {
1839 None => match order {
1840 SortSpecOrder::Asc => logical::SortSpecNullOrder::Last,
1841 SortSpecOrder::Desc => logical::SortSpecNullOrder::First,
1842 },
1843 Some(NullOrderingSpec::First) => logical::SortSpecNullOrder::First,
1844 Some(NullOrderingSpec::Last) => logical::SortSpecNullOrder::Last,
1845 };
1846
1847 self.push_sort_spec(logical::SortSpec {
1848 expr,
1849 order,
1850 null_order,
1851 });
1852 Traverse::Continue
1853 }
1854
1855 fn enter_limit_offset_clause(
1856 &mut self,
1857 _limit_offset: &'ast ast::LimitOffsetClause,
1858 ) -> Traverse {
1859 self.enter_env();
1860 Traverse::Continue
1861 }
1862
1863 fn exit_limit_offset_clause(&mut self, limit_offset: &'ast ast::LimitOffsetClause) -> Traverse {
1864 let mut env = self.exit_env();
1865 true_or_fault!(
1866 self,
1867 (1..=2).contains(&env.len()),
1868 "env.len() is not between 1 and 2"
1869 );
1870
1871 let offset = if limit_offset.offset.is_some() {
1872 env.pop().map(|(_, v)| v)
1873 } else {
1874 None
1875 };
1876 let limit = if limit_offset.limit.is_some() {
1877 env.pop().map(|(_, v)| v)
1878 } else {
1879 None
1880 };
1881
1882 let limit_offset = logical::BindingsOp::LimitOffset(logical::LimitOffset { limit, offset });
1883 let id = self.curr_plan().add_operator(limit_offset);
1884 if matches!(self.current_ctx(), Some(QueryContext::Query)) {
1885 self.current_clauses_mut().limit_offset_clause.replace(id);
1886 } else {
1887 self.push_bexpr(id);
1888 }
1889 Traverse::Continue
1890 }
1891
1892 fn enter_simple_case(&mut self, _simple_case: &'ast SimpleCase) -> Traverse {
1893 self.enter_env();
1894 Traverse::Continue
1895 }
1896
1897 fn exit_simple_case(&mut self, _simple_case: &'ast SimpleCase) -> Traverse {
1898 let mut env = self.exit_env();
1899 true_or_fault!(self, env.len() >= 2, "env.len < 2");
1900
1901 let default = if env.len().is_even() {
1902 Some(Box::new(env.pop().unwrap().1))
1903 } else {
1904 None
1905 };
1906
1907 let mut params = env.into_iter();
1908 let expr = Box::new(params.next().unwrap().1);
1909
1910 let cases = params
1911 .chunks(2)
1912 .into_iter()
1913 .map(|mut c| {
1914 let (_, when) = c.next().unwrap();
1915 let (_, then) = c.next().unwrap();
1916
1917 (Box::new(when), Box::new(then))
1918 })
1919 .collect_vec();
1920
1921 self.push_vexpr(ValueExpr::SimpleCase(logical::SimpleCase {
1922 expr,
1923 cases,
1924 default,
1925 }));
1926 Traverse::Continue
1927 }
1928
1929 fn enter_searched_case(&mut self, _searched_case: &'ast SearchedCase) -> Traverse {
1930 self.enter_env();
1931 Traverse::Continue
1932 }
1933
1934 fn exit_searched_case(&mut self, _searched_case: &'ast SearchedCase) -> Traverse {
1935 let mut env = self.exit_env();
1936 true_or_fault!(self, !env.is_empty(), "env is empty");
1937
1938 let default = if env.len().is_odd() {
1939 Some(Box::new(env.pop().unwrap().1))
1940 } else {
1941 None
1942 };
1943
1944 let cases = env
1945 .into_iter()
1946 .chunks(2)
1947 .into_iter()
1948 .map(|mut c| {
1949 let (_, when) = c.next().unwrap();
1950 let (_, then) = c.next().unwrap();
1951
1952 (Box::new(when), Box::new(then))
1953 })
1954 .collect_vec();
1955 self.push_vexpr(ValueExpr::SearchedCase(logical::SearchedCase {
1956 cases,
1957 default,
1958 }));
1959 Traverse::Continue
1960 }
1961
1962 fn enter_graph_match(&mut self, _graph_pattern: &'ast ast::GraphMatch) -> Traverse {
1963 self.enter_benv();
1964 self.enter_env();
1965 Traverse::Continue
1966 }
1967 fn exit_graph_match(&mut self, graph_match: &'ast ast::GraphMatch) -> Traverse {
1968 let benv = self.exit_benv();
1969 if !benv.is_empty() {
1970 {
1971 not_yet_implemented_fault!(self, "Subexpression in GRAPH MATCH".to_string());
1972 }
1973 }
1974 let mut env = self.exit_env();
1975
1976 let graph_reference = extract_vexpr_by_id(&mut env, graph_match.expr.id());
1977
1978 let graph_planner = crate::graph::GraphToLogical::new(env);
1979 match graph_planner.plan_graph_match(graph_match) {
1980 Ok(pattern) => {
1981 true_or_fault!(
1982 self,
1983 graph_reference.is_some(),
1984 "could not find graph reference"
1985 );
1986 let graph_reference = Box::new(graph_reference.unwrap());
1987
1988 self.push_vexpr(ValueExpr::GraphMatch(Box::new(GraphMatchExpr {
1989 value: graph_reference,
1990 pattern,
1991 })));
1992 Traverse::Continue
1993 }
1994 Err(e) => {
1995 not_yet_implemented_err!(self, e);
1996 Traverse::Stop
1997 }
1998 }
1999 }
2000}
2001
2002fn lit_to_lit(lit: &Lit) -> Result<logical::Lit, AstTransformError> {
2003 fn tuple_pair(
2004 field: &ast::LitField,
2005 ) -> Option<Result<(String, logical::Lit), AstTransformError>> {
2006 let key = field.first.clone();
2007 match &field.second.node {
2008 Lit::Missing => None,
2009 value => match lit_to_lit(value) {
2010 Ok(value) => Some(Ok((key, value))),
2011 Err(e) => Some(Err(e)),
2012 },
2013 }
2014 }
2015
2016 let val = match lit {
2017 Lit::Null => logical::Lit::Null,
2018 Lit::Missing => logical::Lit::Missing,
2019 Lit::Int8Lit(n) => logical::Lit::Int8(*n),
2020 Lit::Int16Lit(n) => logical::Lit::Int16(*n),
2021 Lit::Int32Lit(n) => logical::Lit::Int32(*n),
2022 Lit::Int64Lit(n) => logical::Lit::Int64(*n),
2023 Lit::DecimalLit(d) => logical::Lit::Decimal(*d),
2024 Lit::NumericLit(n) => logical::Lit::Decimal(*n),
2025 Lit::RealLit(f) => logical::Lit::Double(OrderedFloat::from(*f as f64)),
2026 Lit::FloatLit(f) => logical::Lit::Double(OrderedFloat::from(*f as f64)),
2027 Lit::DoubleLit(f) => logical::Lit::Double(OrderedFloat::from(*f)),
2028 Lit::BoolLit(b) => logical::Lit::Bool(*b),
2029 Lit::EmbeddedDocLit(s, _typ) => {
2030 logical::Lit::Variant(s.clone().into_bytes(), "Ion".to_string())
2032 }
2033 Lit::CharStringLit(s) => logical::Lit::String(s.clone()),
2034 Lit::NationalCharStringLit(s) => logical::Lit::String(s.clone()),
2035 Lit::BitStringLit(_) => {
2036 return Err(AstTransformError::NotYetImplemented(
2037 "Lit::BitStringLit".to_string(),
2038 ))
2039 }
2040 Lit::HexStringLit(_) => {
2041 return Err(AstTransformError::NotYetImplemented(
2042 "Lit::HexStringLit".to_string(),
2043 ))
2044 }
2045 Lit::BagLit(b) => {
2046 let bag: Result<_, _> = b.node.values.iter().map(lit_to_lit).collect();
2047 logical::Lit::Bag(bag?)
2048 }
2049 Lit::ListLit(l) => {
2050 let l: Result<_, _> = l.node.values.iter().map(lit_to_lit).collect();
2051 logical::Lit::List(l?)
2052 }
2053 Lit::StructLit(s) => {
2054 let tuple: Result<_, _> = s.node.fields.iter().filter_map(tuple_pair).collect();
2055 logical::Lit::Struct(tuple?)
2056 }
2057 Lit::TypedLit(_, _) => {
2058 return Err(AstTransformError::NotYetImplemented(
2059 "Lit::TypedLit".to_string(),
2060 ))
2061 }
2062 };
2063 Ok(val)
2064}
2065
2066#[cfg(test)]
2067mod tests {
2068 use super::*;
2069 use crate::LogicalPlanner;
2070 use assert_matches::assert_matches;
2071 use partiql_catalog::catalog::{MutableCatalog, PartiqlCatalog, TypeEnvEntry};
2072 use partiql_logical::BindingsOp::Project;
2073 use partiql_logical::ValueExpr;
2074 use partiql_types::PartiqlShape;
2075
2076 #[test]
2077 fn test_plan_non_existent_fns() {
2078 let catalog = PartiqlCatalog::default().to_shared_catalog();
2079 let statement = "foo(1, 2) + bar(3)";
2080 let parsed = partiql_parser::Parser::default()
2081 .parse(statement)
2082 .expect("Expect successful parse");
2083 let planner = LogicalPlanner::new(&catalog);
2084 let logical = planner.lower(&parsed);
2085 assert!(logical.is_err());
2086 let lowering_errs = logical.expect_err("Expect errs").errors;
2087 assert_eq!(lowering_errs.len(), 2);
2088 assert_matches!(
2089 lowering_errs.first(),
2090 Some(AstTransformError::UnsupportedFunction(fnc)) if fnc == "foo"
2091 );
2092 assert_matches!(
2093 lowering_errs.get(1),
2094 Some(AstTransformError::UnsupportedFunction(fnc)) if fnc == "bar"
2095 );
2096 }
2097
2098 #[test]
2099 fn test_plan_bad_num_arguments() {
2100 let catalog = PartiqlCatalog::default().to_shared_catalog();
2101 let statement = "abs(1, 2) + mod(3)";
2102 let parsed = partiql_parser::Parser::default()
2103 .parse(statement)
2104 .expect("Expect successful parse");
2105 let planner = LogicalPlanner::new(&catalog);
2106 let logical = planner.lower(&parsed);
2107 assert!(logical.is_err());
2108 let lowering_errs = logical.expect_err("Expect errs").errors;
2109 assert_eq!(lowering_errs.len(), 2);
2110 assert_matches!(
2111 lowering_errs.first(),
2112 Some(AstTransformError::InvalidNumberOfArguments(fnc)) if fnc == "abs"
2113 );
2114 assert_matches!(
2115 lowering_errs.get(1),
2116 Some(AstTransformError::InvalidNumberOfArguments(fnc)) if fnc == "mod"
2117 );
2118 }
2119
2120 #[test]
2121 fn test_plan_type_entry_in_catalog() {
2122 let mut expected_logical = LogicalPlan::new();
2124 let my_id = ValueExpr::Path(
2125 Box::new(ValueExpr::DynamicLookup(Box::new(vec![
2126 ValueExpr::VarRef(
2127 BindingsName::CaseInsensitive("c".to_string().into()),
2128 VarRefType::Local,
2129 ),
2130 ValueExpr::VarRef(
2131 BindingsName::CaseInsensitive("c".to_string().into()),
2132 VarRefType::Global,
2133 ),
2134 ]))),
2135 vec![PathComponent::Key(BindingsName::CaseInsensitive(
2136 "id".to_string().into(),
2137 ))],
2138 );
2139
2140 let my_name = ValueExpr::Path(
2141 Box::new(ValueExpr::DynamicLookup(Box::new(vec![ValueExpr::VarRef(
2142 BindingsName::CaseInsensitive("customers".to_string().into()),
2143 VarRefType::Global,
2144 )]))),
2145 vec![PathComponent::Key(BindingsName::CaseInsensitive(
2146 "name".to_string().into(),
2147 ))],
2148 );
2149
2150 let project = expected_logical.add_operator(Project(logical::Project {
2151 exprs: Vec::from([
2152 ("my_id".to_string(), my_id),
2153 ("my_name".to_string(), my_name),
2154 ]),
2155 }));
2156
2157 let scan = expected_logical.add_operator(BindingsOp::Scan(logical::Scan {
2158 expr: ValueExpr::DynamicLookup(Box::new(vec![ValueExpr::VarRef(
2159 BindingsName::CaseInsensitive("customers".to_string().into()),
2160 VarRefType::Global,
2161 )])),
2162 as_key: "c".to_string(),
2163 at_key: None,
2164 }));
2165 let sink = expected_logical.add_operator(BindingsOp::Sink);
2166 expected_logical.add_flow_with_branch_num(scan, project, 0);
2167 expected_logical.add_flow_with_branch_num(project, sink, 0);
2168
2169 let mut catalog = PartiqlCatalog::default();
2170 let _oid =
2171 catalog.add_type_entry(TypeEnvEntry::new("customers", &[], PartiqlShape::Dynamic));
2172 let catalog = catalog.to_shared_catalog();
2173 let statement = "SELECT c.id AS my_id, customers.name AS my_name FROM customers AS c";
2174 let parsed = partiql_parser::Parser::default()
2175 .parse(statement)
2176 .expect("Expect successful parse");
2177 let planner = LogicalPlanner::new(&catalog);
2178 let logical = planner.lower(&parsed).expect("Expect successful lowering");
2179 assert_eq!(expected_logical, logical);
2180
2181 println!("logical: {:?}", &logical);
2182 }
2183}