1use serde::{Deserialize, Serialize};
8use std::sync::atomic::{AtomicU64, Ordering};
9use uqa_core::Value;
10
11use super::{
12 FromClause, FunctionBinding, FunctionBody, MergeWhen, OnConflictAction, SelectStmt, Statement,
13 CTE,
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
20#[doc(hidden)]
21pub struct InternalRelationId(u64);
22
23impl InternalRelationId {
24 #[must_use]
26 pub fn allocate() -> Self {
27 static NEXT_ID: AtomicU64 = AtomicU64::new(1);
28 let id = NEXT_ID
29 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
30 current.checked_add(1)
31 })
32 .expect("internal relation identity space exhausted");
33 Self(id)
34 }
35
36 #[must_use]
38 pub fn column(self, attribute: usize) -> InternalColumnRef {
39 InternalColumnRef {
40 relation: self,
41 attribute: u32::try_from(attribute).expect("internal relation attribute exceeds u32"),
42 }
43 }
44
45 #[must_use]
46 pub const fn raw(self) -> u64 {
47 self.0
48 }
49
50 #[must_use]
51 pub const fn from_raw(raw: u64) -> Self {
52 Self(raw)
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
60#[doc(hidden)]
61pub struct InternalColumnRef {
62 relation: InternalRelationId,
63 attribute: u32,
64}
65
66impl InternalColumnRef {
67 #[must_use]
68 pub const fn relation(self) -> InternalRelationId {
69 self.relation
70 }
71
72 #[must_use]
73 pub const fn attribute(self) -> usize {
74 self.attribute as usize
75 }
76
77 #[must_use]
78 pub const fn from_raw(relation: u64, attribute: u32) -> Self {
79 Self {
80 relation: InternalRelationId::from_raw(relation),
81 attribute,
82 }
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
87pub struct Projection {
88 pub expr: Expr,
89 pub alias: Option<String>,
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct OrderBy {
94 pub expr: Expr,
95 pub descending: bool,
96 pub nulls: Option<NullsOrder>,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
103pub enum NullsOrder {
104 First,
105 Last,
106}
107
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
109pub struct WindowSpec {
110 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub reference: Option<WindowReference>,
113 pub partition_by: Vec<Expr>,
114 pub order_by: Vec<OrderBy>,
115 pub frame: Option<WindowFrame>,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct WindowReference {
122 pub name: String,
123 pub kind: WindowReferenceKind,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
127pub enum WindowReferenceKind {
128 Direct,
130 Copy,
132}
133
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
135pub struct WindowFrame {
136 pub mode: FrameMode,
137 pub start: FrameBound,
138 pub end: FrameBound,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
142pub enum FrameMode {
143 Rows,
144 Range,
145 Groups,
146}
147
148#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub enum FrameBound {
150 UnboundedPreceding,
151 UnboundedFollowing,
152 CurrentRow,
153 Preceding(Box<Expr>),
154 Following(Box<Expr>),
155}
156
157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159pub enum Expr {
160 Star,
161 QualifiedStar(String),
163 Default,
167 Column(String),
169 QualifiedColumn {
171 qualifier: String,
172 column: String,
173 },
174 #[doc(hidden)]
177 InternalColumn(InternalColumnRef),
178 Literal(Value),
179 Param(usize),
181 Func {
184 name: String,
185 #[serde(default, skip_serializing_if = "Option::is_none")]
186 binding: Option<FunctionBinding>,
187 args: Vec<Expr>,
188 distinct: bool,
191 order_by: Vec<OrderBy>,
194 filter: Option<Box<Expr>>,
196 },
197 Array(Vec<Expr>),
200 Row(Vec<Expr>),
202 Binary {
204 op: BinaryOp,
205 lhs: Box<Expr>,
206 rhs: Box<Expr>,
207 },
208 UnaryMinus(Box<Expr>),
211 Not(Box<Expr>),
213 And(Vec<Expr>),
215 Or(Vec<Expr>),
217 IsNull {
219 expr: Box<Expr>,
220 negated: bool,
221 },
222 Between {
224 expr: Box<Expr>,
225 low: Box<Expr>,
226 high: Box<Expr>,
227 },
228 InList {
230 expr: Box<Expr>,
231 list: Vec<Expr>,
232 negated: bool,
233 },
234 WindowCall {
236 name: String,
237 args: Vec<Expr>,
238 spec: WindowSpec,
239 },
240 Case {
245 base: Option<Box<Expr>>,
246 when: Vec<(Expr, Expr)>,
247 else_branch: Option<Box<Expr>>,
248 },
249 Cast {
252 expr: Box<Expr>,
253 ty: String,
254 },
255 ScalarSubquery(Box<SelectStmt>),
258 Exists {
261 body: Box<SelectStmt>,
262 negated: bool,
263 },
264 InSubquery {
268 expr: Box<Expr>,
269 body: Box<SelectStmt>,
270 negated: bool,
271 },
272}
273
274impl Expr {
275 pub fn qualified_column(qualifier: impl Into<String>, column: impl Into<String>) -> Self {
276 Self::QualifiedColumn {
277 qualifier: qualifier.into(),
278 column: column.into(),
279 }
280 }
281
282 #[doc(hidden)]
285 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
286 let mut changed = false;
287 match self {
288 Self::Func {
289 name,
290 binding,
291 args,
292 order_by,
293 filter,
294 ..
295 } => {
296 for argument in args {
297 changed |= argument.upgrade_legacy_serialized_dispatches();
298 }
299 for order in order_by {
300 changed |= order.expr.upgrade_legacy_serialized_dispatches();
301 }
302 if let Some(filter) = filter {
303 changed |= filter.upgrade_legacy_serialized_dispatches();
304 }
305 changed |=
306 super::FunctionBinding::upgrade_legacy_serialized_dispatch(name, binding);
307 }
308 Self::Array(items) | Self::Row(items) | Self::And(items) | Self::Or(items) => {
309 for item in items {
310 changed |= item.upgrade_legacy_serialized_dispatches();
311 }
312 }
313 Self::Binary { lhs, rhs, .. } => {
314 changed |= lhs.upgrade_legacy_serialized_dispatches();
315 changed |= rhs.upgrade_legacy_serialized_dispatches();
316 }
317 Self::UnaryMinus(inner)
318 | Self::Not(inner)
319 | Self::IsNull { expr: inner, .. }
320 | Self::Cast { expr: inner, .. } => {
321 changed |= inner.upgrade_legacy_serialized_dispatches();
322 }
323 Self::Between { expr, low, high } => {
324 changed |= expr.upgrade_legacy_serialized_dispatches();
325 changed |= low.upgrade_legacy_serialized_dispatches();
326 changed |= high.upgrade_legacy_serialized_dispatches();
327 }
328 Self::InList { expr, list, .. } => {
329 changed |= expr.upgrade_legacy_serialized_dispatches();
330 for item in list {
331 changed |= item.upgrade_legacy_serialized_dispatches();
332 }
333 }
334 Self::WindowCall { args, spec, .. } => {
335 for argument in args {
336 changed |= argument.upgrade_legacy_serialized_dispatches();
337 }
338 for partition in &mut spec.partition_by {
339 changed |= partition.upgrade_legacy_serialized_dispatches();
340 }
341 for order in &mut spec.order_by {
342 changed |= order.expr.upgrade_legacy_serialized_dispatches();
343 }
344 if let Some(frame) = &mut spec.frame {
345 for bound in [&mut frame.start, &mut frame.end] {
346 match bound {
347 FrameBound::Preceding(expression)
348 | FrameBound::Following(expression) => {
349 changed |= expression.upgrade_legacy_serialized_dispatches();
350 }
351 FrameBound::UnboundedPreceding
352 | FrameBound::UnboundedFollowing
353 | FrameBound::CurrentRow => {}
354 }
355 }
356 }
357 }
358 Self::Case {
359 base,
360 when,
361 else_branch,
362 } => {
363 if let Some(base) = base {
364 changed |= base.upgrade_legacy_serialized_dispatches();
365 }
366 for (condition, result) in when {
367 changed |= condition.upgrade_legacy_serialized_dispatches();
368 changed |= result.upgrade_legacy_serialized_dispatches();
369 }
370 if let Some(branch) = else_branch {
371 changed |= branch.upgrade_legacy_serialized_dispatches();
372 }
373 }
374 Self::InSubquery { expr, body, .. } => {
375 changed |= expr.upgrade_legacy_serialized_dispatches();
376 changed |= body.upgrade_legacy_serialized_dispatches();
377 }
378 Self::ScalarSubquery(body) | Self::Exists { body, .. } => {
379 changed |= body.upgrade_legacy_serialized_dispatches();
380 }
381 Self::Default
382 | Self::Star
383 | Self::QualifiedStar(_)
384 | Self::Column(_)
385 | Self::QualifiedColumn { .. }
386 | Self::InternalColumn(_)
387 | Self::Literal(_)
388 | Self::Param(_) => {}
389 }
390 changed
391 }
392
393 #[must_use]
395 pub fn contains_window(&self) -> bool {
396 self.any_node(&|node| matches!(node, Self::WindowCall { .. }))
397 }
398
399 #[must_use]
401 pub fn contains_aggregate(&self) -> bool {
402 self.any_node(
403 &|node| matches!(node, Self::Func { name, .. } if is_builtin_aggregate_function(name)),
404 )
405 }
406
407 #[must_use]
409 pub fn contains_unqualified_column(&self) -> bool {
410 self.any_node(&|node| matches!(node, Self::Column(_)))
411 }
412
413 #[must_use]
415 pub fn contains_function_with_unknown_strictness(&self) -> bool {
416 self.any_node(&|node| {
417 matches!(
418 node,
419 Self::Func {
420 name,
421 args,
422 binding,
423 ..
424 } if crate::expr::bound_scalar_function_strictness(
425 name,
426 binding.as_ref(),
427 args.len(),
428 )
429 .is_none()
430 )
431 })
432 }
433
434 #[must_use]
436 pub fn any_node(&self, hit: &dyn Fn(&Self) -> bool) -> bool {
437 if hit(self) {
438 return true;
439 }
440 match self {
441 Self::Func {
442 args,
443 order_by,
444 filter,
445 ..
446 } => {
447 args.iter().any(|arg| arg.any_node(hit))
448 || order_by.iter().any(|order| order.expr.any_node(hit))
449 || filter.as_deref().is_some_and(|filter| filter.any_node(hit))
450 }
451 Self::Array(items) | Self::Row(items) | Self::And(items) | Self::Or(items) => {
452 items.iter().any(|item| item.any_node(hit))
453 }
454 Self::UnaryMinus(expr) | Self::Not(expr) | Self::Cast { expr, .. } => {
455 expr.any_node(hit)
456 }
457 Self::Binary { lhs, rhs, .. } => lhs.any_node(hit) || rhs.any_node(hit),
458 Self::IsNull { expr, .. } | Self::InSubquery { expr, .. } => expr.any_node(hit),
459 Self::Between { expr, low, high } => {
460 expr.any_node(hit) || low.any_node(hit) || high.any_node(hit)
461 }
462 Self::InList { expr, list, .. } => {
463 expr.any_node(hit) || list.iter().any(|item| item.any_node(hit))
464 }
465 Self::Case {
466 base,
467 when,
468 else_branch,
469 } => {
470 base.as_deref().is_some_and(|base| base.any_node(hit))
471 || when
472 .iter()
473 .any(|(condition, result)| condition.any_node(hit) || result.any_node(hit))
474 || else_branch
475 .as_deref()
476 .is_some_and(|branch| branch.any_node(hit))
477 }
478 Self::WindowCall { .. }
479 | Self::Star
480 | Self::QualifiedStar(_)
481 | Self::Default
482 | Self::Column(_)
483 | Self::QualifiedColumn { .. }
484 | Self::InternalColumn(_)
485 | Self::Literal(_)
486 | Self::Param(_)
487 | Self::ScalarSubquery(_)
488 | Self::Exists { .. } => false,
489 }
490 }
491}
492
493fn upgrade_exprs(expressions: &mut [Expr]) -> bool {
494 expressions.iter_mut().fold(false, |changed, expression| {
495 expression.upgrade_legacy_serialized_dispatches() | changed
496 })
497}
498
499fn upgrade_rows(rows: &mut [Vec<Expr>]) -> bool {
500 rows.iter_mut()
501 .fold(false, |changed, row| upgrade_exprs(row) | changed)
502}
503
504fn upgrade_optional(expression: &mut Option<Expr>) -> bool {
505 expression
506 .as_mut()
507 .is_some_and(Expr::upgrade_legacy_serialized_dispatches)
508}
509
510fn upgrade_projections(projections: &mut [Projection]) -> bool {
511 projections.iter_mut().fold(false, |changed, projection| {
512 projection.expr.upgrade_legacy_serialized_dispatches() | changed
513 })
514}
515
516fn upgrade_assignments(assignments: &mut [(String, Expr)]) -> bool {
517 assignments
518 .iter_mut()
519 .fold(false, |changed, (_, expression)| {
520 expression.upgrade_legacy_serialized_dispatches() | changed
521 })
522}
523
524fn upgrade_ctes(ctes: &mut [CTE]) -> bool {
525 ctes.iter_mut().fold(false, |mut changed, cte| {
526 if let Some(cycle) = &mut cte.cycle {
527 changed |= cycle.mark_value.upgrade_legacy_serialized_dispatches();
528 changed |= cycle.mark_default.upgrade_legacy_serialized_dispatches();
529 }
530 changed | cte.query.upgrade_legacy_serialized_dispatches()
531 })
532}
533
534impl FromClause {
535 fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
536 match self {
537 Self::Table { .. } => false,
538 Self::Join {
539 left, right, on, ..
540 } => {
541 left.upgrade_legacy_serialized_dispatches()
542 | right.upgrade_legacy_serialized_dispatches()
543 | upgrade_optional(on)
544 }
545 Self::Values { rows, .. } => upgrade_rows(rows),
546 Self::Function { args, .. } => upgrade_exprs(args),
547 Self::FunctionGroup { functions, .. } => {
548 functions.iter_mut().fold(false, |changed, function| {
549 upgrade_exprs(&mut function.args) | changed
550 })
551 }
552 Self::Subquery { body, .. } => body.upgrade_legacy_serialized_dispatches(),
553 }
554 }
555}
556
557impl SelectStmt {
558 #[doc(hidden)]
560 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
561 let mut changed = upgrade_projections(&mut self.projections);
562 changed |= upgrade_rows(&mut self.values);
563 if let Some(from) = &mut self.from {
564 changed |= from.upgrade_legacy_serialized_dispatches();
565 }
566 changed |= upgrade_optional(&mut self.r#where);
567 changed |= upgrade_exprs(&mut self.group_by);
568 for grouping_set in &mut self.grouping_sets {
569 changed |= upgrade_exprs(grouping_set);
570 }
571 changed |= upgrade_optional(&mut self.having);
572 for order in &mut self.order_by {
573 changed |= order.expr.upgrade_legacy_serialized_dispatches();
574 }
575 changed |= upgrade_optional(&mut self.limit);
576 changed |= upgrade_optional(&mut self.offset);
577 changed |= upgrade_ctes(&mut self.with);
578 if let Some(set_operation) = &mut self.set_op {
579 if let Some(left) = &mut set_operation.left {
580 changed |= left.upgrade_legacy_serialized_dispatches();
581 }
582 changed |= set_operation.right.upgrade_legacy_serialized_dispatches();
583 for order in &mut set_operation.combined_order_by {
584 changed |= order.expr.upgrade_legacy_serialized_dispatches();
585 }
586 changed |= upgrade_optional(&mut set_operation.combined_limit);
587 changed |= upgrade_optional(&mut set_operation.combined_offset);
588 }
589 changed | upgrade_exprs(&mut self.distinct_on)
590 }
591}
592
593impl MergeWhen {
594 fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
595 match self {
596 Self::UpdateMatched {
597 condition,
598 assignments,
599 }
600 | Self::UpdateNotMatchedBySource {
601 condition,
602 assignments,
603 } => upgrade_optional(condition) | upgrade_assignments(assignments),
604 Self::InsertNotMatched {
605 condition, values, ..
606 } => upgrade_optional(condition) | upgrade_exprs(values),
607 Self::DeleteMatched { condition }
608 | Self::DeleteNotMatchedBySource { condition }
609 | Self::NothingMatched { condition }
610 | Self::NothingNotMatched { condition }
611 | Self::NothingNotMatchedBySource { condition } => upgrade_optional(condition),
612 }
613 }
614}
615
616impl Statement {
617 #[doc(hidden)]
619 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
620 match self {
621 Self::Select(select) => select.upgrade_legacy_serialized_dispatches(),
622 Self::Insert(insert) => {
623 let mut changed = upgrade_ctes(&mut insert.with);
624 changed |= upgrade_rows(&mut insert.rows);
625 if let Some(source) = &mut insert.select_source {
626 changed |= source.upgrade_legacy_serialized_dispatches();
627 }
628 if let Some(conflict) = &mut insert.on_conflict {
629 if let OnConflictAction::Update {
630 assignments,
631 r#where,
632 } = &mut conflict.action
633 {
634 changed |= upgrade_assignments(assignments);
635 changed |= upgrade_optional(r#where);
636 }
637 }
638 changed | upgrade_projections(&mut insert.returning)
639 }
640 Self::Update(update) => {
641 let mut changed = upgrade_assignments(&mut update.assignments);
642 changed |= upgrade_optional(&mut update.r#where);
643 changed |= upgrade_ctes(&mut update.with);
644 if let Some(from) = &mut update.from {
645 changed |= from.upgrade_legacy_serialized_dispatches();
646 }
647 changed | upgrade_projections(&mut update.returning)
648 }
649 Self::Delete(delete) => {
650 let mut changed = upgrade_optional(&mut delete.r#where);
651 changed |= upgrade_ctes(&mut delete.with);
652 if let Some(using) = &mut delete.using {
653 changed |= using.upgrade_legacy_serialized_dispatches();
654 }
655 changed | upgrade_projections(&mut delete.returning)
656 }
657 Self::CreateView { body, .. }
658 | Self::CreateMaterializedView { body, .. }
659 | Self::CreateTableAs { body, .. } => body.upgrade_legacy_serialized_dispatches(),
660 Self::Explain { body, .. } | Self::Prepare { body, .. } => {
661 body.upgrade_legacy_serialized_dispatches()
662 }
663 Self::Execute { params, .. } | Self::Call { args: params, .. } => upgrade_exprs(params),
664 Self::Values { rows } => upgrade_rows(rows),
665 Self::Merge(merge) => {
666 let mut changed = merge.source.upgrade_legacy_serialized_dispatches();
667 changed |= merge.join_condition.upgrade_legacy_serialized_dispatches();
668 for clause in &mut merge.when_clauses {
669 changed |= clause.upgrade_legacy_serialized_dispatches();
670 }
671 changed | upgrade_projections(&mut merge.returning)
672 }
673 Self::CreateFunction(definition) => {
674 let mut changed = definition
675 .params
676 .iter_mut()
677 .fold(false, |changed, parameter| {
678 parameter
679 .default
680 .as_mut()
681 .is_some_and(Expr::upgrade_legacy_serialized_dispatches)
682 | changed
683 });
684 if let FunctionBody::Statements(statements) = &mut definition.body {
685 for statement in statements {
686 changed |= statement.upgrade_legacy_serialized_dispatches();
687 }
688 }
689 changed
690 }
691 Self::CreateTrigger(trigger) => upgrade_optional(&mut trigger.when),
692 Self::CreateRule(rule) => {
693 let mut changed = upgrade_optional(&mut rule.condition);
694 for action in &mut rule.actions {
695 changed |= action.upgrade_legacy_serialized_dispatches();
696 }
697 changed
698 }
699 Self::CreateTable(_)
700 | Self::CreateIndex(_)
701 | Self::Drop(_)
702 | Self::AlterTable(_)
703 | Self::AlterViewOptions(_)
704 | Self::RefreshMaterializedView { .. }
705 | Self::CreateSchema { .. }
706 | Self::SetVariable { .. }
707 | Self::SetConstraints { .. }
708 | Self::ShowVariable { .. }
709 | Self::Discard { .. }
710 | Self::Load { .. }
711 | Self::Analyze { .. }
712 | Self::Truncate { .. }
713 | Self::Transaction(_)
714 | Self::CreateSequence(_)
715 | Self::AlterSequence(_)
716 | Self::Deallocate { .. }
717 | Self::CreateForeignServer(_)
718 | Self::CreateForeignTable(_)
719 | Self::DropFunction(_)
720 | Self::AlterRoutine(_)
721 | Self::AlterRoutineOwner(_)
722 | Self::GrantRoutine(_)
723 | Self::CreateRole(_)
724 | Self::AlterRole(_)
725 | Self::DropRole(_)
726 | Self::DropTrigger(_)
727 | Self::DropRule(_)
728 | Self::DoBlock { .. } => false,
729 }
730 }
731}
732
733#[must_use]
735pub fn is_builtin_aggregate_function(name: &str) -> bool {
736 matches!(
737 name.to_ascii_lowercase().as_str(),
738 "count"
739 | "sum"
740 | "avg"
741 | "min"
742 | "max"
743 | "string_agg"
744 | "array_agg"
745 | "bool_and"
746 | "bool_or"
747 | "stddev"
748 | "stddev_samp"
749 | "stddev_pop"
750 | "variance"
751 | "var_samp"
752 | "var_pop"
753 | "percentile_cont"
754 | "percentile_disc"
755 | "mode"
756 | "json_agg"
757 | "jsonb_agg"
758 | "json_object_agg"
759 | "jsonb_object_agg"
760 )
761}
762
763#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
764pub enum BinaryOp {
765 Equal,
766 NotEqual,
767 Less,
768 LessEqual,
769 Greater,
770 GreaterEqual,
771 Add,
772 Subtract,
773 Multiply,
774 Divide,
775}
776
777pub type ValueExpr = Expr;