1use crate::ast::*;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct Query {
19 pub with: Option<With>,
21 pub body: SetExpr,
23 pub order_by: Vec<OrderByExpr>,
25 pub limit: Option<Expr>,
27 pub offset: Option<String>,
32 pub fetch: Option<Fetch>,
37}
38
39impl Query {
40 pub fn as_simple_values(&self) -> Option<&Values> {
42 match &self {
43 Query {
44 with: None,
45 body: SetExpr::Values(values),
46 order_by,
47 limit: None,
48 offset: None,
49 fetch: None,
50 } if order_by.is_empty() => Some(values),
51 _ => None,
52 }
53 }
54
55 pub fn as_single_select_item(&self) -> Option<&Expr> {
57 match &self {
58 Query {
59 with: None,
60 body: SetExpr::Select(select),
61 order_by,
62 limit: None,
63 offset: None,
64 fetch: None,
65 } if order_by.is_empty() => match select.as_ref() {
66 Select {
67 distinct: Distinct::All,
68 projection,
69 from,
70 lateral_views,
71 selection: None,
72 group_by,
73 having: None,
74 window,
75 } if projection.len() == 1
76 && from.is_empty()
77 && lateral_views.is_empty()
78 && group_by.is_empty()
79 && window.is_empty() =>
80 {
81 match &projection[0] {
82 SelectItem::UnnamedExpr(expr) => Some(expr),
83 SelectItem::ExprWithAlias { expr, .. } => Some(expr),
84 _ => None,
85 }
86 }
87 _ => None,
88 },
89 _ => None,
90 }
91 }
92}
93
94impl fmt::Display for Query {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 if let Some(ref with) = self.with {
97 write!(f, "{} ", with)?;
98 }
99 write!(f, "{}", self.body)?;
100 if !self.order_by.is_empty() {
101 write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
102 }
103 if let Some(ref limit) = self.limit {
104 write!(f, " LIMIT {}", limit)?;
105 }
106 if let Some(ref offset) = self.offset {
107 write!(f, " OFFSET {}", offset)?;
108 }
109 if let Some(ref fetch) = self.fetch {
110 write!(f, " {}", fetch)?;
111 }
112 Ok(())
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120pub enum SetExpr {
121 Select(Box<Select>),
123 Query(Box<Query>),
126 SetOperation {
128 op: SetOperator,
129 all: bool,
130 corresponding: Corresponding,
131 left: Box<SetExpr>,
132 right: Box<SetExpr>,
133 },
134 Values(Values),
135}
136
137impl fmt::Display for SetExpr {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 SetExpr::Select(s) => write!(f, "{}", s),
141 SetExpr::Query(q) => write!(f, "({})", q),
142 SetExpr::Values(v) => write!(f, "{}", v),
143 SetExpr::SetOperation {
144 left,
145 right,
146 op,
147 all,
148 corresponding,
149 } => {
150 let all_str = if *all { " ALL" } else { "" };
151 write!(f, "{} {}{}{} {}", left, op, all_str, corresponding, right)
152 }
153 }
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158pub enum SetOperator {
159 Union,
160 Except,
161 Intersect,
162}
163
164impl fmt::Display for SetOperator {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 f.write_str(match self {
167 SetOperator::Union => "UNION",
168 SetOperator::Except => "EXCEPT",
169 SetOperator::Intersect => "INTERSECT",
170 })
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Hash)]
176pub struct Corresponding {
177 pub corresponding: bool,
178 pub column_list: Option<Vec<Ident>>,
179}
180
181impl Corresponding {
182 pub fn with_column_list(column_list: Option<Vec<Ident>>) -> Self {
183 Self {
184 corresponding: true,
185 column_list,
186 }
187 }
188
189 pub fn none() -> Self {
190 Self {
191 corresponding: false,
192 column_list: None,
193 }
194 }
195
196 pub fn is_corresponding(&self) -> bool {
197 self.corresponding
198 }
199
200 pub fn column_list(&self) -> Option<&[Ident]> {
201 self.column_list.as_deref()
202 }
203}
204
205impl fmt::Display for Corresponding {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 if self.corresponding {
208 write!(f, " CORRESPONDING")?;
209 if let Some(column_list) = &self.column_list {
210 write!(f, " BY ({})", display_comma_separated(column_list))?;
211 }
212 }
213 Ok(())
214 }
215}
216
217#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
221pub struct Select {
222 pub distinct: Distinct,
223 pub projection: Vec<SelectItem>,
225 pub from: Vec<TableWithJoins>,
227 pub lateral_views: Vec<LateralView>,
229 pub selection: Option<Expr>,
231 pub group_by: Vec<Expr>,
233 pub having: Option<Expr>,
235 pub window: Vec<NamedWindow>,
237}
238
239impl fmt::Display for Select {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 write!(f, "SELECT{}", self.distinct)?;
242 write!(f, " {}", display_comma_separated(&self.projection))?;
243 if !self.from.is_empty() {
244 write!(f, " FROM {}", display_comma_separated(&self.from))?;
245 }
246 if !self.lateral_views.is_empty() {
247 for lv in &self.lateral_views {
248 write!(f, "{}", lv)?;
249 }
250 }
251 if let Some(ref selection) = self.selection {
252 write!(f, " WHERE {}", selection)?;
253 }
254 if !self.group_by.is_empty() {
255 write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
256 }
257 if let Some(ref having) = self.having {
258 write!(f, " HAVING {}", having)?;
259 }
260 if !self.window.is_empty() {
261 write!(f, " WINDOW {}", display_comma_separated(&self.window))?;
262 }
263 Ok(())
264 }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
269#[expect(clippy::enum_variant_names)]
270pub enum Distinct {
271 #[default]
273 All,
274 Distinct,
276 DistinctOn(Vec<Expr>),
278}
279
280impl Distinct {
281 pub const fn is_all(&self) -> bool {
282 matches!(self, Distinct::All)
283 }
284
285 pub const fn is_distinct(&self) -> bool {
286 matches!(self, Distinct::Distinct)
287 }
288}
289
290impl fmt::Display for Distinct {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 match self {
293 Distinct::All => write!(f, ""),
294 Distinct::Distinct => write!(f, " DISTINCT"),
295 Distinct::DistinctOn(exprs) => {
296 write!(f, " DISTINCT ON ({})", display_comma_separated(exprs))
297 }
298 }
299 }
300}
301
302#[derive(Debug, Clone, PartialEq, Eq, Hash)]
304pub struct LateralView {
305 pub lateral_view: Expr,
307 pub lateral_view_name: ObjectName,
309 pub lateral_col_alias: Vec<Ident>,
311 pub outer: bool,
313}
314
315impl fmt::Display for LateralView {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(
318 f,
319 " LATERAL VIEW{outer} {} {}",
320 self.lateral_view,
321 self.lateral_view_name,
322 outer = if self.outer { " OUTER" } else { "" }
323 )?;
324 if !self.lateral_col_alias.is_empty() {
325 write!(
326 f,
327 " AS {}",
328 display_comma_separated(&self.lateral_col_alias)
329 )?;
330 }
331 Ok(())
332 }
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Hash)]
336pub struct With {
337 pub recursive: bool,
338 pub cte_tables: Vec<Cte>,
339}
340
341impl fmt::Display for With {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 write!(
344 f,
345 "WITH {}{}",
346 if self.recursive { "RECURSIVE " } else { "" },
347 display_comma_separated(&self.cte_tables)
348 )
349 }
350}
351
352#[derive(Debug, Clone, PartialEq, Eq, Hash)]
358pub struct Cte {
359 pub alias: TableAlias,
360 pub cte_inner: CteInner,
361}
362
363impl fmt::Display for Cte {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 match &self.cte_inner {
366 CteInner::Query(query) => write!(f, "{} AS ({})", self.alias, query)?,
367 CteInner::ChangeLog { from, key } => {
368 write!(f, "{} AS changelog from {}", self.alias, from)?;
369
370 if let Some(key) = key {
371 write!(f, " KEY ({})", display_comma_separated(key))?;
372 }
373 }
374 }
375 Ok(())
376 }
377}
378
379#[derive(Debug, Clone, PartialEq, Eq, Hash)]
380pub enum CteInner {
381 Query(Box<Query>),
382 ChangeLog {
383 from: ObjectName,
384 key: Option<Vec<Ident>>,
385 },
386}
387
388#[derive(Debug, Clone, PartialEq, Eq, Hash)]
390pub enum SelectItem {
391 UnnamedExpr(Expr),
393 ExprQualifiedWildcard(Expr, Vec<Ident>),
397 ExprWithAlias { expr: Expr, alias: Ident },
399 QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
401 Wildcard(Option<Vec<Expr>>),
403}
404
405impl fmt::Display for SelectItem {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 match &self {
408 SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
409 SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
410 SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
411 f,
412 "({}){}.*",
413 expr,
414 prefix
415 .iter()
416 .format_with("", |i, f| f(&format_args!(".{i}")))
417 ),
418 SelectItem::QualifiedWildcard(prefix, except) => match except {
419 Some(cols) => write!(
420 f,
421 "{}.* EXCEPT ({})",
422 prefix,
423 cols.iter()
424 .map(|v| v.to_string())
425 .collect::<Vec<String>>()
426 .as_slice()
427 .join(", ")
428 ),
429 None => write!(f, "{}.*", prefix),
430 },
431 SelectItem::Wildcard(except) => match except {
432 Some(cols) => write!(
433 f,
434 "* EXCEPT ({})",
435 cols.iter()
436 .map(|v| v.to_string())
437 .collect::<Vec<String>>()
438 .as_slice()
439 .join(", ")
440 ),
441 None => write!(f, "*"),
442 },
443 }
444 }
445}
446
447#[derive(Debug, Clone, PartialEq, Eq, Hash)]
448pub struct TableWithJoins {
449 pub relation: TableFactor,
450 pub joins: Vec<Join>,
451}
452
453impl fmt::Display for TableWithJoins {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 write!(f, "{}", self.relation)?;
456 for join in &self.joins {
457 write!(f, "{}", join)?;
458 }
459 Ok(())
460 }
461}
462
463#[derive(Debug, Clone, PartialEq, Eq, Hash)]
465pub enum TableFactor {
466 Table {
467 name: ObjectName,
468 alias: Option<TableAlias>,
469 as_of: Option<AsOf>,
470 },
471 Derived {
472 lateral: bool,
473 subquery: Box<Query>,
474 alias: Option<TableAlias>,
475 },
476 TableFunction {
480 name: ObjectName,
481 alias: Option<TableAlias>,
482 args: Vec<FunctionArg>,
483 with_ordinality: bool,
484 },
485 NestedJoin(Box<TableWithJoins>),
492 MatchRecognize {
495 table: Box<TableFactor>,
497 partition_by: Vec<Expr>,
499 order_by: Vec<OrderByExpr>,
501 measures: Vec<Measure>,
503 rows_per_match: Option<RowsPerMatch>,
505 after_match_skip: Option<AfterMatchSkip>,
507 pattern: MatchRecognizePattern,
509 within: Option<Expr>,
511 subsets: Vec<SubsetDefinition>,
513 symbols: Vec<SymbolDefinition>,
515 alias: Option<TableAlias>,
517 },
518}
519
520#[derive(Debug, Clone, PartialEq, Eq, Hash)]
522pub struct Measure {
523 pub expr: Expr,
524 pub alias: Ident,
525}
526
527impl fmt::Display for Measure {
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 write!(f, "{} AS {}", self.expr, self.alias)
530 }
531}
532
533#[derive(Debug, Clone, PartialEq, Eq, Hash)]
535pub enum RowsPerMatch {
536 OneRow,
538 AllRows,
540}
541
542impl fmt::Display for RowsPerMatch {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544 match self {
545 RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
546 RowsPerMatch::AllRows => write!(f, "ALL ROWS PER MATCH"),
547 }
548 }
549}
550
551#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub enum AfterMatchSkip {
554 PastLastRow,
556 ToNextRow,
558 ToFirst(Ident),
560 ToLast(Ident),
562}
563
564impl fmt::Display for AfterMatchSkip {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 write!(f, "AFTER MATCH SKIP ")?;
567 match self {
568 AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
569 AfterMatchSkip::ToNextRow => write!(f, "TO NEXT ROW"),
570 AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {}", symbol),
571 AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {}", symbol),
572 }
573 }
574}
575
576#[derive(Debug, Clone, PartialEq, Eq, Hash)]
578pub struct SymbolDefinition {
579 pub symbol: Ident,
580 pub definition: Expr,
581}
582
583impl fmt::Display for SymbolDefinition {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 write!(f, "{} AS {}", self.symbol, self.definition)
586 }
587}
588
589#[derive(Debug, Clone, PartialEq, Eq, Hash)]
591pub struct SubsetDefinition {
592 pub name: Ident,
593 pub members: Vec<Ident>,
594}
595
596impl fmt::Display for SubsetDefinition {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 write!(
599 f,
600 "{} = ({})",
601 self.name,
602 display_comma_separated(&self.members)
603 )
604 }
605}
606
607#[derive(Debug, Clone, PartialEq, Eq, Hash)]
609pub enum MatchRecognizeSymbol {
610 Named(Ident),
612 Start,
614 End,
616}
617
618impl fmt::Display for MatchRecognizeSymbol {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 match self {
621 MatchRecognizeSymbol::Named(symbol) => write!(f, "{}", symbol),
622 MatchRecognizeSymbol::Start => write!(f, "^"),
623 MatchRecognizeSymbol::End => write!(f, "$"),
624 }
625 }
626}
627
628#[derive(Debug, Clone, PartialEq, Eq, Hash)]
630pub enum MatchRecognizePattern {
631 Symbol(MatchRecognizeSymbol),
633 Exclude(MatchRecognizeSymbol),
635 Permute(Vec<MatchRecognizeSymbol>),
637 Concat(Vec<MatchRecognizePattern>),
639 Group(Box<MatchRecognizePattern>),
641 Alternation(Vec<MatchRecognizePattern>),
643 Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier, bool),
646}
647
648impl fmt::Display for MatchRecognizePattern {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 use MatchRecognizePattern::*;
651 match self {
652 Symbol(symbol) => write!(f, "{}", symbol),
653 Exclude(symbol) => write!(f, "{{- {} -}}", symbol),
654 Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
655 Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
656 Group(pattern) => write!(f, "({})", pattern),
657 Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
658 Repetition(pattern, quantifier, reluctant) => {
659 write!(
660 f,
661 "{}{}{}",
662 pattern,
663 quantifier,
664 if *reluctant { "?" } else { "" }
665 )
666 }
667 }
668 }
669}
670
671#[derive(Debug, Clone, PartialEq, Eq, Hash)]
673pub enum RepetitionQuantifier {
674 ZeroOrMore,
676 OneOrMore,
678 AtMostOne,
680 Exactly(u32),
682 AtLeast(u32),
684 AtMost(u32),
686 Range(u32, u32),
688}
689
690impl fmt::Display for RepetitionQuantifier {
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 use RepetitionQuantifier::*;
693 match self {
694 ZeroOrMore => write!(f, "*"),
695 OneOrMore => write!(f, "+"),
696 AtMostOne => write!(f, "?"),
697 Exactly(n) => write!(f, "{{{}}}", n),
698 AtLeast(n) => write!(f, "{{{},}}", n),
699 AtMost(m) => write!(f, "{{,{}}}", m),
700 Range(n, m) => write!(f, "{{{},{}}}", n, m),
701 }
702 }
703}
704
705impl fmt::Display for TableFactor {
706 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707 match self {
708 TableFactor::Table { name, alias, as_of } => {
709 write!(f, "{}", name)?;
710 if let Some(as_of) = as_of {
711 write!(f, "{}", as_of)?
712 }
713 if let Some(alias) = alias {
714 write!(f, " AS {}", alias)?;
715 }
716 Ok(())
717 }
718 TableFactor::Derived {
719 lateral,
720 subquery,
721 alias,
722 } => {
723 if *lateral {
724 write!(f, "LATERAL ")?;
725 }
726 write!(f, "({})", subquery)?;
727 if let Some(alias) = alias {
728 write!(f, " AS {}", alias)?;
729 }
730 Ok(())
731 }
732 TableFactor::TableFunction {
733 name,
734 alias,
735 args,
736 with_ordinality,
737 } => {
738 write!(f, "{}({})", name, display_comma_separated(args))?;
739 if *with_ordinality {
740 write!(f, " WITH ORDINALITY")?;
741 }
742 if let Some(alias) = alias {
743 write!(f, " AS {}", alias)?;
744 }
745 Ok(())
746 }
747 TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
748 TableFactor::MatchRecognize {
749 table,
750 partition_by,
751 order_by,
752 measures,
753 rows_per_match,
754 after_match_skip,
755 pattern,
756 within,
757 subsets,
758 symbols,
759 alias,
760 } => {
761 write!(f, "{} MATCH_RECOGNIZE (", table)?;
762 if !partition_by.is_empty() {
763 write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
764 }
765 if !order_by.is_empty() {
766 write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
767 }
768 if !measures.is_empty() {
769 write!(f, "MEASURES {} ", display_comma_separated(measures))?;
770 }
771 if let Some(rows_per_match) = rows_per_match {
772 write!(f, "{} ", rows_per_match)?;
773 }
774 if let Some(after_match_skip) = after_match_skip {
775 write!(f, "{} ", after_match_skip)?;
776 }
777 write!(f, "PATTERN ({}) ", pattern)?;
778 if let Some(within) = within {
779 write!(f, "WITHIN {} ", within)?;
780 }
781 if !subsets.is_empty() {
782 write!(f, "SUBSET {} ", display_comma_separated(subsets))?;
783 }
784 write!(f, "DEFINE {})", display_comma_separated(symbols))?;
785 if let Some(alias) = alias {
786 write!(f, " AS {}", alias)?;
787 }
788 Ok(())
789 }
790 }
791 }
792}
793
794#[derive(Debug, Clone, PartialEq, Eq, Hash)]
795pub struct TableAlias {
796 pub name: Ident,
797 pub columns: Vec<Ident>,
798}
799
800impl fmt::Display for TableAlias {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 write!(f, "{}", self.name)?;
803 if !self.columns.is_empty() {
804 write!(f, " ({})", display_comma_separated(&self.columns))?;
805 }
806 Ok(())
807 }
808}
809
810#[derive(Debug, Clone, PartialEq, Eq, Hash)]
811pub struct Join {
812 pub relation: TableFactor,
813 pub join_operator: JoinOperator,
814}
815
816impl fmt::Display for Join {
817 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
818 fn prefix(constraint: &JoinConstraint) -> &'static str {
819 match constraint {
820 JoinConstraint::Natural => "NATURAL ",
821 _ => "",
822 }
823 }
824 fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
825 struct Suffix<'a>(&'a JoinConstraint);
826 impl fmt::Display for Suffix<'_> {
827 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
828 match self.0 {
829 JoinConstraint::On(expr) => write!(f, " ON {}", expr),
830 JoinConstraint::Using(attrs) => {
831 write!(f, " USING({})", display_comma_separated(attrs))
832 }
833 _ => Ok(()),
834 }
835 }
836 }
837 Suffix(constraint)
838 }
839 let broadcast = if matches!(
840 self.relation,
841 TableFactor::Table {
842 as_of: Some(AsOf::ProcessTimeBroadcast),
843 ..
844 }
845 ) {
846 "BROADCAST "
847 } else {
848 ""
849 };
850 match &self.join_operator {
851 JoinOperator::Inner(constraint) => write!(
852 f,
853 " {}{}JOIN {}{}",
854 prefix(constraint),
855 broadcast,
856 self.relation,
857 suffix(constraint)
858 ),
859 JoinOperator::LeftOuter(constraint) => write!(
860 f,
861 " {}{}LEFT JOIN {}{}",
862 prefix(constraint),
863 broadcast,
864 self.relation,
865 suffix(constraint)
866 ),
867 JoinOperator::RightOuter(constraint) => write!(
868 f,
869 " {}RIGHT JOIN {}{}",
870 prefix(constraint),
871 self.relation,
872 suffix(constraint)
873 ),
874 JoinOperator::FullOuter(constraint) => write!(
875 f,
876 " {}FULL JOIN {}{}",
877 prefix(constraint),
878 self.relation,
879 suffix(constraint)
880 ),
881 JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
882 JoinOperator::AsOfInner(constraint) => write!(
883 f,
884 " {}ASOF JOIN {}{}",
885 prefix(constraint),
886 self.relation,
887 suffix(constraint)
888 ),
889 JoinOperator::AsOfLeft(constraint) => write!(
890 f,
891 " {}ASOF LEFT JOIN {}{}",
892 prefix(constraint),
893 self.relation,
894 suffix(constraint)
895 ),
896 }
897 }
898}
899
900#[derive(Debug, Clone, PartialEq, Eq, Hash)]
901pub enum JoinOperator {
902 Inner(JoinConstraint),
903 LeftOuter(JoinConstraint),
904 RightOuter(JoinConstraint),
905 FullOuter(JoinConstraint),
906 CrossJoin,
907 AsOfInner(JoinConstraint),
908 AsOfLeft(JoinConstraint),
909}
910
911#[derive(Debug, Clone, PartialEq, Eq, Hash)]
912pub enum JoinConstraint {
913 On(Expr),
914 Using(Vec<Ident>),
915 Natural,
916 None,
917}
918
919#[derive(Debug, Clone, PartialEq, Eq, Hash)]
921pub struct OrderByExpr {
922 pub expr: Expr,
923 pub asc: Option<bool>,
925 pub nulls_first: Option<bool>,
927}
928
929impl fmt::Display for OrderByExpr {
930 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
931 write!(f, "{}", self.expr)?;
932 match self.asc {
933 Some(true) => write!(f, " ASC")?,
934 Some(false) => write!(f, " DESC")?,
935 None => (),
936 }
937 match self.nulls_first {
938 Some(true) => write!(f, " NULLS FIRST")?,
939 Some(false) => write!(f, " NULLS LAST")?,
940 None => (),
941 }
942 Ok(())
943 }
944}
945
946#[derive(Debug, Clone, PartialEq, Eq, Hash)]
947pub struct Fetch {
948 pub with_ties: bool,
949 pub quantity: Option<String>,
950}
951
952impl fmt::Display for Fetch {
953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
955 if let Some(ref quantity) = self.quantity {
956 write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
957 } else {
958 write!(f, "FETCH FIRST ROWS {}", extension)
959 }
960 }
961}
962
963#[derive(Debug, Clone, PartialEq, Eq, Hash)]
964pub struct Top {
965 pub with_ties: bool,
967 pub percent: bool,
968 pub quantity: Option<Expr>,
969}
970
971impl fmt::Display for Top {
972 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
973 let extension = if self.with_ties { " WITH TIES" } else { "" };
974 if let Some(ref quantity) = self.quantity {
975 let percent = if self.percent { " PERCENT" } else { "" };
976 write!(f, "TOP ({}){}{}", quantity, percent, extension)
977 } else {
978 write!(f, "TOP{}", extension)
979 }
980 }
981}
982
983#[derive(Debug, Clone, PartialEq, Eq, Hash)]
984pub struct Values(pub Vec<Vec<Expr>>);
985
986impl fmt::Display for Values {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988 write!(f, "VALUES ")?;
989 let mut delim = "";
990 for row in &self.0 {
991 write!(f, "{}", delim)?;
992 delim = ", ";
993 write!(f, "({})", display_comma_separated(row))?;
994 }
995 Ok(())
996 }
997}
998
999#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1001pub struct NamedWindow {
1002 pub name: Ident,
1003 pub window_spec: WindowSpec,
1004}
1005
1006impl fmt::Display for NamedWindow {
1007 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008 write!(f, "{} AS ({})", self.name, self.window_spec)
1009 }
1010}