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 #[doc(hidden)]
181 TypedLiteral {
182 value: Value,
183 ty: String,
184 },
185 Param(usize),
187 Func {
190 name: String,
191 #[serde(default, skip_serializing_if = "Option::is_none")]
192 binding: Option<FunctionBinding>,
193 args: Vec<Expr>,
194 distinct: bool,
197 order_by: Vec<OrderBy>,
200 filter: Option<Box<Expr>>,
202 },
203 Array(Vec<Expr>),
206 Row(Vec<Expr>),
208 Binary {
210 op: BinaryOp,
211 lhs: Box<Expr>,
212 rhs: Box<Expr>,
213 },
214 UnaryMinus(Box<Expr>),
217 Not(Box<Expr>),
219 And(Vec<Expr>),
221 Or(Vec<Expr>),
223 IsNull {
225 expr: Box<Expr>,
226 negated: bool,
227 },
228 Between {
230 expr: Box<Expr>,
231 low: Box<Expr>,
232 high: Box<Expr>,
233 },
234 InList {
236 expr: Box<Expr>,
237 list: Vec<Expr>,
238 negated: bool,
239 },
240 WindowCall {
242 name: String,
243 args: Vec<Expr>,
244 spec: WindowSpec,
245 },
246 Case {
251 base: Option<Box<Expr>>,
252 when: Vec<(Expr, Expr)>,
253 else_branch: Option<Box<Expr>>,
254 },
255 Cast {
258 expr: Box<Expr>,
259 ty: String,
260 },
261 ScalarSubquery(Box<SelectStmt>),
264 Exists {
267 body: Box<SelectStmt>,
268 negated: bool,
269 },
270 InSubquery {
274 expr: Box<Expr>,
275 body: Box<SelectStmt>,
276 negated: bool,
277 },
278}
279
280impl Expr {
281 pub fn qualified_column(qualifier: impl Into<String>, column: impl Into<String>) -> Self {
282 Self::QualifiedColumn {
283 qualifier: qualifier.into(),
284 column: column.into(),
285 }
286 }
287
288 #[doc(hidden)]
291 #[expect(
292 clippy::too_many_lines,
293 reason = "exhaustive AST migration preserves every serialized variant"
294 )]
295 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
296 let mut changed = false;
297 match self {
298 Self::Func {
299 name,
300 binding,
301 args,
302 order_by,
303 filter,
304 ..
305 } => {
306 for argument in args {
307 changed |= argument.upgrade_legacy_serialized_dispatches();
308 }
309 for order in order_by {
310 changed |= order.expr.upgrade_legacy_serialized_dispatches();
311 }
312 if let Some(filter) = filter {
313 changed |= filter.upgrade_legacy_serialized_dispatches();
314 }
315 changed |=
316 super::FunctionBinding::upgrade_legacy_serialized_dispatch(name, binding);
317 }
318 Self::Array(items) | Self::Row(items) | Self::And(items) | Self::Or(items) => {
319 for item in items {
320 changed |= item.upgrade_legacy_serialized_dispatches();
321 }
322 }
323 Self::Binary { lhs, rhs, .. } => {
324 changed |= lhs.upgrade_legacy_serialized_dispatches();
325 changed |= rhs.upgrade_legacy_serialized_dispatches();
326 }
327 Self::UnaryMinus(inner)
328 | Self::Not(inner)
329 | Self::IsNull { expr: inner, .. }
330 | Self::Cast { expr: inner, .. } => {
331 changed |= inner.upgrade_legacy_serialized_dispatches();
332 }
333 Self::Between { expr, low, high } => {
334 changed |= expr.upgrade_legacy_serialized_dispatches();
335 changed |= low.upgrade_legacy_serialized_dispatches();
336 changed |= high.upgrade_legacy_serialized_dispatches();
337 }
338 Self::InList { expr, list, .. } => {
339 changed |= expr.upgrade_legacy_serialized_dispatches();
340 for item in list {
341 changed |= item.upgrade_legacy_serialized_dispatches();
342 }
343 }
344 Self::WindowCall { args, spec, .. } => {
345 for argument in args {
346 changed |= argument.upgrade_legacy_serialized_dispatches();
347 }
348 for partition in &mut spec.partition_by {
349 changed |= partition.upgrade_legacy_serialized_dispatches();
350 }
351 for order in &mut spec.order_by {
352 changed |= order.expr.upgrade_legacy_serialized_dispatches();
353 }
354 if let Some(frame) = &mut spec.frame {
355 for bound in [&mut frame.start, &mut frame.end] {
356 match bound {
357 FrameBound::Preceding(expression)
358 | FrameBound::Following(expression) => {
359 changed |= expression.upgrade_legacy_serialized_dispatches();
360 }
361 FrameBound::UnboundedPreceding
362 | FrameBound::UnboundedFollowing
363 | FrameBound::CurrentRow => {}
364 }
365 }
366 }
367 }
368 Self::Case {
369 base,
370 when,
371 else_branch,
372 } => {
373 if let Some(base) = base {
374 changed |= base.upgrade_legacy_serialized_dispatches();
375 }
376 for (condition, result) in when {
377 changed |= condition.upgrade_legacy_serialized_dispatches();
378 changed |= result.upgrade_legacy_serialized_dispatches();
379 }
380 if let Some(branch) = else_branch {
381 changed |= branch.upgrade_legacy_serialized_dispatches();
382 }
383 }
384 Self::InSubquery { expr, body, .. } => {
385 changed |= expr.upgrade_legacy_serialized_dispatches();
386 changed |= body.upgrade_legacy_serialized_dispatches();
387 }
388 Self::ScalarSubquery(body) | Self::Exists { body, .. } => {
389 changed |= body.upgrade_legacy_serialized_dispatches();
390 }
391 Self::Default
392 | Self::Star
393 | Self::QualifiedStar(_)
394 | Self::Column(_)
395 | Self::QualifiedColumn { .. }
396 | Self::InternalColumn(_)
397 | Self::Literal(_)
398 | Self::TypedLiteral { .. }
399 | Self::Param(_) => {}
400 }
401 changed
402 }
403
404 #[must_use]
406 pub fn contains_window(&self) -> bool {
407 self.any_node(&|node| matches!(node, Self::WindowCall { .. }))
408 }
409
410 #[must_use]
412 pub fn contains_aggregate(&self) -> bool {
413 self.any_node(
414 &|node| matches!(node, Self::Func { name, .. } if is_builtin_aggregate_function(name)),
415 )
416 }
417
418 #[must_use]
420 pub fn contains_unqualified_column(&self) -> bool {
421 self.any_node(&|node| matches!(node, Self::Column(_)))
422 }
423
424 #[must_use]
426 pub fn contains_function_with_unknown_strictness(&self) -> bool {
427 self.any_node(&|node| {
428 matches!(
429 node,
430 Self::Func {
431 name,
432 args,
433 binding,
434 ..
435 } if crate::expr::bound_scalar_function_strictness(
436 name,
437 binding.as_ref(),
438 args.len(),
439 )
440 .is_none()
441 )
442 })
443 }
444
445 #[must_use]
447 pub fn any_node(&self, hit: &dyn Fn(&Self) -> bool) -> bool {
448 if hit(self) {
449 return true;
450 }
451 match self {
452 Self::Func {
453 args,
454 order_by,
455 filter,
456 ..
457 } => {
458 args.iter().any(|arg| arg.any_node(hit))
459 || order_by.iter().any(|order| order.expr.any_node(hit))
460 || filter.as_deref().is_some_and(|filter| filter.any_node(hit))
461 }
462 Self::Array(items) | Self::Row(items) | Self::And(items) | Self::Or(items) => {
463 items.iter().any(|item| item.any_node(hit))
464 }
465 Self::UnaryMinus(expr) | Self::Not(expr) | Self::Cast { expr, .. } => {
466 expr.any_node(hit)
467 }
468 Self::Binary { lhs, rhs, .. } => lhs.any_node(hit) || rhs.any_node(hit),
469 Self::IsNull { expr, .. } | Self::InSubquery { expr, .. } => expr.any_node(hit),
470 Self::Between { expr, low, high } => {
471 expr.any_node(hit) || low.any_node(hit) || high.any_node(hit)
472 }
473 Self::InList { expr, list, .. } => {
474 expr.any_node(hit) || list.iter().any(|item| item.any_node(hit))
475 }
476 Self::Case {
477 base,
478 when,
479 else_branch,
480 } => {
481 base.as_deref().is_some_and(|base| base.any_node(hit))
482 || when
483 .iter()
484 .any(|(condition, result)| condition.any_node(hit) || result.any_node(hit))
485 || else_branch
486 .as_deref()
487 .is_some_and(|branch| branch.any_node(hit))
488 }
489 Self::WindowCall { .. }
490 | Self::Star
491 | Self::QualifiedStar(_)
492 | Self::Default
493 | Self::Column(_)
494 | Self::QualifiedColumn { .. }
495 | Self::InternalColumn(_)
496 | Self::Literal(_)
497 | Self::TypedLiteral { .. }
498 | Self::Param(_)
499 | Self::ScalarSubquery(_)
500 | Self::Exists { .. } => false,
501 }
502 }
503}
504
505fn upgrade_exprs(expressions: &mut [Expr]) -> bool {
506 expressions.iter_mut().fold(false, |changed, expression| {
507 expression.upgrade_legacy_serialized_dispatches() | changed
508 })
509}
510
511fn upgrade_rows(rows: &mut [Vec<Expr>]) -> bool {
512 rows.iter_mut()
513 .fold(false, |changed, row| upgrade_exprs(row) | changed)
514}
515
516fn upgrade_optional(expression: &mut Option<Expr>) -> bool {
517 expression
518 .as_mut()
519 .is_some_and(Expr::upgrade_legacy_serialized_dispatches)
520}
521
522fn upgrade_projections(projections: &mut [Projection]) -> bool {
523 projections.iter_mut().fold(false, |changed, projection| {
524 projection.expr.upgrade_legacy_serialized_dispatches() | changed
525 })
526}
527
528fn upgrade_assignments(assignments: &mut [(String, Expr)]) -> bool {
529 assignments
530 .iter_mut()
531 .fold(false, |changed, (_, expression)| {
532 expression.upgrade_legacy_serialized_dispatches() | changed
533 })
534}
535
536fn upgrade_ctes(ctes: &mut [CTE]) -> bool {
537 ctes.iter_mut().fold(false, |mut changed, cte| {
538 if let Some(cycle) = &mut cte.cycle {
539 changed |= cycle.mark_value.upgrade_legacy_serialized_dispatches();
540 changed |= cycle.mark_default.upgrade_legacy_serialized_dispatches();
541 }
542 let mut statement = cte.body.clone().into_statement();
543 let body_changed = statement.upgrade_legacy_serialized_dispatches();
544 if body_changed {
545 cte.body = super::CteBody::try_from(statement)
546 .expect("dispatch migration preserves the CTE statement kind");
547 }
548 changed | body_changed
549 })
550}
551
552impl FromClause {
553 fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
554 match self {
555 Self::Table { .. } => false,
556 Self::Join {
557 left, right, on, ..
558 } => {
559 left.upgrade_legacy_serialized_dispatches()
560 | right.upgrade_legacy_serialized_dispatches()
561 | upgrade_optional(on)
562 }
563 Self::Values { rows, .. } => upgrade_rows(rows),
564 Self::Function { args, .. } => upgrade_exprs(args),
565 Self::FunctionGroup { functions, .. } => {
566 functions.iter_mut().fold(false, |changed, function| {
567 upgrade_exprs(&mut function.args) | changed
568 })
569 }
570 Self::Subquery { body, .. } => body.upgrade_legacy_serialized_dispatches(),
571 }
572 }
573}
574
575impl SelectStmt {
576 #[doc(hidden)]
578 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
579 let mut changed = upgrade_projections(&mut self.projections);
580 changed |= upgrade_rows(&mut self.values);
581 if let Some(from) = &mut self.from {
582 changed |= from.upgrade_legacy_serialized_dispatches();
583 }
584 changed |= upgrade_optional(&mut self.r#where);
585 changed |= upgrade_exprs(&mut self.group_by);
586 for grouping_set in &mut self.grouping_sets {
587 changed |= upgrade_exprs(grouping_set);
588 }
589 changed |= upgrade_optional(&mut self.having);
590 for order in &mut self.order_by {
591 changed |= order.expr.upgrade_legacy_serialized_dispatches();
592 }
593 changed |= upgrade_optional(&mut self.limit);
594 changed |= upgrade_optional(&mut self.offset);
595 changed |= upgrade_ctes(&mut self.with);
596 if let Some(set_operation) = &mut self.set_op {
597 if let Some(left) = &mut set_operation.left {
598 changed |= left.upgrade_legacy_serialized_dispatches();
599 }
600 changed |= set_operation.right.upgrade_legacy_serialized_dispatches();
601 for order in &mut set_operation.combined_order_by {
602 changed |= order.expr.upgrade_legacy_serialized_dispatches();
603 }
604 changed |= upgrade_optional(&mut set_operation.combined_limit);
605 changed |= upgrade_optional(&mut set_operation.combined_offset);
606 }
607 changed | upgrade_exprs(&mut self.distinct_on)
608 }
609}
610
611impl MergeWhen {
612 fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
613 match self {
614 Self::UpdateMatched {
615 condition,
616 assignments,
617 }
618 | Self::UpdateNotMatchedBySource {
619 condition,
620 assignments,
621 } => upgrade_optional(condition) | upgrade_assignments(assignments),
622 Self::InsertNotMatched {
623 condition, values, ..
624 } => upgrade_optional(condition) | upgrade_exprs(values),
625 Self::DeleteMatched { condition }
626 | Self::DeleteNotMatchedBySource { condition }
627 | Self::NothingMatched { condition }
628 | Self::NothingNotMatched { condition }
629 | Self::NothingNotMatchedBySource { condition } => upgrade_optional(condition),
630 }
631 }
632}
633
634impl Statement {
635 #[doc(hidden)]
637 #[expect(
638 clippy::too_many_lines,
639 reason = "exhaustive AST migration preserves every serialized variant"
640 )]
641 pub fn upgrade_legacy_serialized_dispatches(&mut self) -> bool {
642 match self {
643 Self::Select(select) => select.upgrade_legacy_serialized_dispatches(),
644 Self::CreateDomain(domain) => {
645 let mut changed = upgrade_optional(&mut domain.default);
646 for check in &mut domain.checks {
647 changed |= check.expression.upgrade_legacy_serialized_dispatches();
648 }
649 changed
650 }
651 Self::Insert(insert) => {
652 let mut changed = upgrade_ctes(&mut insert.with);
653 changed |= upgrade_rows(&mut insert.rows);
654 if let Some(source) = &mut insert.select_source {
655 changed |= source.upgrade_legacy_serialized_dispatches();
656 }
657 if let Some(conflict) = &mut insert.on_conflict {
658 for expression in &mut conflict.expressions {
659 changed |= expression.upgrade_legacy_serialized_dispatches();
660 }
661 changed |= conflict
662 .predicate
663 .as_deref_mut()
664 .is_some_and(Expr::upgrade_legacy_serialized_dispatches);
665 if let OnConflictAction::Update {
666 assignments,
667 r#where,
668 } = &mut conflict.action
669 {
670 changed |= upgrade_assignments(assignments);
671 changed |= r#where
672 .as_deref_mut()
673 .is_some_and(Expr::upgrade_legacy_serialized_dispatches);
674 }
675 }
676 changed | upgrade_projections(&mut insert.returning)
677 }
678 Self::Update(update) => {
679 let mut changed = upgrade_assignments(&mut update.assignments);
680 changed |= upgrade_optional(&mut update.r#where);
681 changed |= upgrade_ctes(&mut update.with);
682 if let Some(from) = &mut update.from {
683 changed |= from.upgrade_legacy_serialized_dispatches();
684 }
685 changed | upgrade_projections(&mut update.returning)
686 }
687 Self::Delete(delete) => {
688 let mut changed = upgrade_optional(&mut delete.r#where);
689 changed |= upgrade_ctes(&mut delete.with);
690 if let Some(using) = &mut delete.using {
691 changed |= using.upgrade_legacy_serialized_dispatches();
692 }
693 changed | upgrade_projections(&mut delete.returning)
694 }
695 Self::CreateView { body, .. }
696 | Self::CreateMaterializedView { body, .. }
697 | Self::CreateTableAs { body, .. } => body.upgrade_legacy_serialized_dispatches(),
698 Self::DeclareCursor(cursor) => cursor.query.upgrade_legacy_serialized_dispatches(),
699 Self::Explain { body, .. } | Self::Prepare { body, .. } => {
700 body.upgrade_legacy_serialized_dispatches()
701 }
702 Self::Execute { params, .. } | Self::Call { args: params, .. } => upgrade_exprs(params),
703 Self::Values { rows } => upgrade_rows(rows),
704 Self::Merge(merge) => {
705 let mut changed = upgrade_ctes(&mut merge.with);
706 changed |= merge.source.upgrade_legacy_serialized_dispatches();
707 changed |= merge.join_condition.upgrade_legacy_serialized_dispatches();
708 for clause in &mut merge.when_clauses {
709 changed |= clause.upgrade_legacy_serialized_dispatches();
710 }
711 changed | upgrade_projections(&mut merge.returning)
712 }
713 Self::CreateFunction(definition) => {
714 let mut changed = definition
715 .params
716 .iter_mut()
717 .fold(false, |changed, parameter| {
718 parameter
719 .default
720 .as_mut()
721 .is_some_and(Expr::upgrade_legacy_serialized_dispatches)
722 | changed
723 });
724 if let FunctionBody::Statements(statements) = &mut definition.body {
725 for statement in statements {
726 changed |= statement.upgrade_legacy_serialized_dispatches();
727 }
728 }
729 changed
730 }
731 Self::CreateTrigger(trigger) => upgrade_optional(&mut trigger.when),
732 Self::CreateRule(rule) => {
733 let mut changed = upgrade_optional(&mut rule.condition);
734 for action in &mut rule.actions {
735 changed |= action.upgrade_legacy_serialized_dispatches();
736 }
737 changed
738 }
739 Self::CreateTable(_)
740 | Self::CreateTableIfNotExists(_)
741 | Self::CreateIndex(_)
742 | Self::Drop(_)
743 | Self::AlterTable(_)
744 | Self::AlterForeignTable(_)
745 | Self::AlterView(_)
746 | Self::RefreshMaterializedView { .. }
747 | Self::CreateSchema { .. }
748 | Self::AlterSchemaOwner { .. }
749 | Self::Notify { .. }
750 | Self::Listen { .. }
751 | Self::Unlisten { .. }
752 | Self::SetVariable { .. }
753 | Self::ResetVariable { .. }
754 | Self::ResetAllVariables
755 | Self::SetConstraints { .. }
756 | Self::ShowVariable { .. }
757 | Self::Discard { .. }
758 | Self::Load { .. }
759 | Self::Analyze { .. }
760 | Self::Vacuum(_)
761 | Self::Truncate { .. }
762 | Self::Transaction(_)
763 | Self::FetchCursor(_)
764 | Self::CloseCursor { .. }
765 | Self::CreateSequence(_)
766 | Self::AlterSequence(_)
767 | Self::Deallocate { .. }
768 | Self::CreateForeignServer(_)
769 | Self::CreateForeignTable(_)
770 | Self::CreateForeignTableIfNotExists(_)
771 | Self::DropFunction(_)
772 | Self::AlterRoutine(_)
773 | Self::AlterRoutineOwner(_)
774 | Self::RenameRoutine(_)
775 | Self::GrantRoutine(_)
776 | Self::GrantTable(_)
777 | Self::GrantSequence(_)
778 | Self::GrantDatabase(_)
779 | Self::GrantSchema(_)
780 | Self::GrantRole(_)
781 | Self::CreateRole(_)
782 | Self::AlterRole(_)
783 | Self::DropRole(_)
784 | Self::DropTrigger(_)
785 | Self::DropRule(_)
786 | Self::DoBlock { .. } => false,
787 }
788 }
789}
790
791#[must_use]
793pub fn is_builtin_aggregate_function(name: &str) -> bool {
794 matches!(
795 name.to_ascii_lowercase().as_str(),
796 "count"
797 | "sum"
798 | "avg"
799 | "min"
800 | "max"
801 | "string_agg"
802 | "array_agg"
803 | "bool_and"
804 | "bool_or"
805 | "stddev"
806 | "stddev_samp"
807 | "stddev_pop"
808 | "variance"
809 | "var_samp"
810 | "var_pop"
811 | "percentile_cont"
812 | "percentile_disc"
813 | "mode"
814 | "json_agg"
815 | "jsonb_agg"
816 | "json_object_agg"
817 | "jsonb_object_agg"
818 )
819}
820
821#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
822pub enum BinaryOp {
823 Equal,
824 NotEqual,
825 Less,
826 LessEqual,
827 Greater,
828 GreaterEqual,
829 Add,
830 Subtract,
831 Multiply,
832 Divide,
833}
834
835pub type ValueExpr = Expr;