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(obj_name) => {
368 write!(f, "{} AS changelog from {}", self.alias, obj_name)?
369 }
370 }
371 Ok(())
372 }
373}
374
375#[derive(Debug, Clone, PartialEq, Eq, Hash)]
376pub enum CteInner {
377 Query(Box<Query>),
378 ChangeLog(ObjectName),
379}
380
381#[derive(Debug, Clone, PartialEq, Eq, Hash)]
383pub enum SelectItem {
384 UnnamedExpr(Expr),
386 ExprQualifiedWildcard(Expr, Vec<Ident>),
390 ExprWithAlias { expr: Expr, alias: Ident },
392 QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
394 Wildcard(Option<Vec<Expr>>),
396}
397
398impl fmt::Display for SelectItem {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 match &self {
401 SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
402 SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
403 SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
404 f,
405 "({}){}.*",
406 expr,
407 prefix
408 .iter()
409 .format_with("", |i, f| f(&format_args!(".{i}")))
410 ),
411 SelectItem::QualifiedWildcard(prefix, except) => match except {
412 Some(cols) => write!(
413 f,
414 "{}.* EXCEPT ({})",
415 prefix,
416 cols.iter()
417 .map(|v| v.to_string())
418 .collect::<Vec<String>>()
419 .as_slice()
420 .join(", ")
421 ),
422 None => write!(f, "{}.*", prefix),
423 },
424 SelectItem::Wildcard(except) => match except {
425 Some(cols) => write!(
426 f,
427 "* EXCEPT ({})",
428 cols.iter()
429 .map(|v| v.to_string())
430 .collect::<Vec<String>>()
431 .as_slice()
432 .join(", ")
433 ),
434 None => write!(f, "*"),
435 },
436 }
437 }
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, Hash)]
441pub struct TableWithJoins {
442 pub relation: TableFactor,
443 pub joins: Vec<Join>,
444}
445
446impl fmt::Display for TableWithJoins {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 write!(f, "{}", self.relation)?;
449 for join in &self.joins {
450 write!(f, "{}", join)?;
451 }
452 Ok(())
453 }
454}
455
456#[derive(Debug, Clone, PartialEq, Eq, Hash)]
458pub enum TableFactor {
459 Table {
460 name: ObjectName,
461 alias: Option<TableAlias>,
462 as_of: Option<AsOf>,
463 },
464 Derived {
465 lateral: bool,
466 subquery: Box<Query>,
467 alias: Option<TableAlias>,
468 },
469 TableFunction {
473 name: ObjectName,
474 alias: Option<TableAlias>,
475 args: Vec<FunctionArg>,
476 with_ordinality: bool,
477 },
478 NestedJoin(Box<TableWithJoins>),
485 MatchRecognize {
488 table: Box<TableFactor>,
490 partition_by: Vec<Expr>,
492 order_by: Vec<OrderByExpr>,
494 measures: Vec<Measure>,
496 rows_per_match: Option<RowsPerMatch>,
498 after_match_skip: Option<AfterMatchSkip>,
500 pattern: MatchRecognizePattern,
502 within: Option<Expr>,
504 subsets: Vec<SubsetDefinition>,
506 symbols: Vec<SymbolDefinition>,
508 alias: Option<TableAlias>,
510 },
511}
512
513#[derive(Debug, Clone, PartialEq, Eq, Hash)]
515pub struct Measure {
516 pub expr: Expr,
517 pub alias: Ident,
518}
519
520impl fmt::Display for Measure {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 write!(f, "{} AS {}", self.expr, self.alias)
523 }
524}
525
526#[derive(Debug, Clone, PartialEq, Eq, Hash)]
528pub enum RowsPerMatch {
529 OneRow,
531 AllRows,
533}
534
535impl fmt::Display for RowsPerMatch {
536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537 match self {
538 RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
539 RowsPerMatch::AllRows => write!(f, "ALL ROWS PER MATCH"),
540 }
541 }
542}
543
544#[derive(Debug, Clone, PartialEq, Eq, Hash)]
546pub enum AfterMatchSkip {
547 PastLastRow,
549 ToNextRow,
551 ToFirst(Ident),
553 ToLast(Ident),
555}
556
557impl fmt::Display for AfterMatchSkip {
558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559 write!(f, "AFTER MATCH SKIP ")?;
560 match self {
561 AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
562 AfterMatchSkip::ToNextRow => write!(f, "TO NEXT ROW"),
563 AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {}", symbol),
564 AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {}", symbol),
565 }
566 }
567}
568
569#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571pub struct SymbolDefinition {
572 pub symbol: Ident,
573 pub definition: Expr,
574}
575
576impl fmt::Display for SymbolDefinition {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578 write!(f, "{} AS {}", self.symbol, self.definition)
579 }
580}
581
582#[derive(Debug, Clone, PartialEq, Eq, Hash)]
584pub struct SubsetDefinition {
585 pub name: Ident,
586 pub members: Vec<Ident>,
587}
588
589impl fmt::Display for SubsetDefinition {
590 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591 write!(
592 f,
593 "{} = ({})",
594 self.name,
595 display_comma_separated(&self.members)
596 )
597 }
598}
599
600#[derive(Debug, Clone, PartialEq, Eq, Hash)]
602pub enum MatchRecognizeSymbol {
603 Named(Ident),
605 Start,
607 End,
609}
610
611impl fmt::Display for MatchRecognizeSymbol {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 match self {
614 MatchRecognizeSymbol::Named(symbol) => write!(f, "{}", symbol),
615 MatchRecognizeSymbol::Start => write!(f, "^"),
616 MatchRecognizeSymbol::End => write!(f, "$"),
617 }
618 }
619}
620
621#[derive(Debug, Clone, PartialEq, Eq, Hash)]
623pub enum MatchRecognizePattern {
624 Symbol(MatchRecognizeSymbol),
626 Exclude(MatchRecognizeSymbol),
628 Permute(Vec<MatchRecognizeSymbol>),
630 Concat(Vec<MatchRecognizePattern>),
632 Group(Box<MatchRecognizePattern>),
634 Alternation(Vec<MatchRecognizePattern>),
636 Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier, bool),
639}
640
641impl fmt::Display for MatchRecognizePattern {
642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 use MatchRecognizePattern::*;
644 match self {
645 Symbol(symbol) => write!(f, "{}", symbol),
646 Exclude(symbol) => write!(f, "{{- {} -}}", symbol),
647 Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
648 Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
649 Group(pattern) => write!(f, "({})", pattern),
650 Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
651 Repetition(pattern, quantifier, reluctant) => {
652 write!(
653 f,
654 "{}{}{}",
655 pattern,
656 quantifier,
657 if *reluctant { "?" } else { "" }
658 )
659 }
660 }
661 }
662}
663
664#[derive(Debug, Clone, PartialEq, Eq, Hash)]
666pub enum RepetitionQuantifier {
667 ZeroOrMore,
669 OneOrMore,
671 AtMostOne,
673 Exactly(u32),
675 AtLeast(u32),
677 AtMost(u32),
679 Range(u32, u32),
681}
682
683impl fmt::Display for RepetitionQuantifier {
684 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685 use RepetitionQuantifier::*;
686 match self {
687 ZeroOrMore => write!(f, "*"),
688 OneOrMore => write!(f, "+"),
689 AtMostOne => write!(f, "?"),
690 Exactly(n) => write!(f, "{{{}}}", n),
691 AtLeast(n) => write!(f, "{{{},}}", n),
692 AtMost(m) => write!(f, "{{,{}}}", m),
693 Range(n, m) => write!(f, "{{{},{}}}", n, m),
694 }
695 }
696}
697
698impl fmt::Display for TableFactor {
699 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
700 match self {
701 TableFactor::Table { name, alias, as_of } => {
702 write!(f, "{}", name)?;
703 if let Some(as_of) = as_of {
704 write!(f, "{}", as_of)?
705 }
706 if let Some(alias) = alias {
707 write!(f, " AS {}", alias)?;
708 }
709 Ok(())
710 }
711 TableFactor::Derived {
712 lateral,
713 subquery,
714 alias,
715 } => {
716 if *lateral {
717 write!(f, "LATERAL ")?;
718 }
719 write!(f, "({})", subquery)?;
720 if let Some(alias) = alias {
721 write!(f, " AS {}", alias)?;
722 }
723 Ok(())
724 }
725 TableFactor::TableFunction {
726 name,
727 alias,
728 args,
729 with_ordinality,
730 } => {
731 write!(f, "{}({})", name, display_comma_separated(args))?;
732 if *with_ordinality {
733 write!(f, " WITH ORDINALITY")?;
734 }
735 if let Some(alias) = alias {
736 write!(f, " AS {}", alias)?;
737 }
738 Ok(())
739 }
740 TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
741 TableFactor::MatchRecognize {
742 table,
743 partition_by,
744 order_by,
745 measures,
746 rows_per_match,
747 after_match_skip,
748 pattern,
749 within,
750 subsets,
751 symbols,
752 alias,
753 } => {
754 write!(f, "{} MATCH_RECOGNIZE (", table)?;
755 if !partition_by.is_empty() {
756 write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
757 }
758 if !order_by.is_empty() {
759 write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
760 }
761 if !measures.is_empty() {
762 write!(f, "MEASURES {} ", display_comma_separated(measures))?;
763 }
764 if let Some(rows_per_match) = rows_per_match {
765 write!(f, "{} ", rows_per_match)?;
766 }
767 if let Some(after_match_skip) = after_match_skip {
768 write!(f, "{} ", after_match_skip)?;
769 }
770 write!(f, "PATTERN ({}) ", pattern)?;
771 if let Some(within) = within {
772 write!(f, "WITHIN {} ", within)?;
773 }
774 if !subsets.is_empty() {
775 write!(f, "SUBSET {} ", display_comma_separated(subsets))?;
776 }
777 write!(f, "DEFINE {})", display_comma_separated(symbols))?;
778 if let Some(alias) = alias {
779 write!(f, " AS {}", alias)?;
780 }
781 Ok(())
782 }
783 }
784 }
785}
786
787#[derive(Debug, Clone, PartialEq, Eq, Hash)]
788pub struct TableAlias {
789 pub name: Ident,
790 pub columns: Vec<Ident>,
791}
792
793impl fmt::Display for TableAlias {
794 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795 write!(f, "{}", self.name)?;
796 if !self.columns.is_empty() {
797 write!(f, " ({})", display_comma_separated(&self.columns))?;
798 }
799 Ok(())
800 }
801}
802
803#[derive(Debug, Clone, PartialEq, Eq, Hash)]
804pub struct Join {
805 pub relation: TableFactor,
806 pub join_operator: JoinOperator,
807}
808
809impl fmt::Display for Join {
810 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811 fn prefix(constraint: &JoinConstraint) -> &'static str {
812 match constraint {
813 JoinConstraint::Natural => "NATURAL ",
814 _ => "",
815 }
816 }
817 fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
818 struct Suffix<'a>(&'a JoinConstraint);
819 impl fmt::Display for Suffix<'_> {
820 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
821 match self.0 {
822 JoinConstraint::On(expr) => write!(f, " ON {}", expr),
823 JoinConstraint::Using(attrs) => {
824 write!(f, " USING({})", display_comma_separated(attrs))
825 }
826 _ => Ok(()),
827 }
828 }
829 }
830 Suffix(constraint)
831 }
832 let broadcast = if matches!(
833 self.relation,
834 TableFactor::Table {
835 as_of: Some(AsOf::ProcessTimeBroadcast),
836 ..
837 }
838 ) {
839 "BROADCAST "
840 } else {
841 ""
842 };
843 match &self.join_operator {
844 JoinOperator::Inner(constraint) => write!(
845 f,
846 " {}{}JOIN {}{}",
847 prefix(constraint),
848 broadcast,
849 self.relation,
850 suffix(constraint)
851 ),
852 JoinOperator::LeftOuter(constraint) => write!(
853 f,
854 " {}{}LEFT JOIN {}{}",
855 prefix(constraint),
856 broadcast,
857 self.relation,
858 suffix(constraint)
859 ),
860 JoinOperator::RightOuter(constraint) => write!(
861 f,
862 " {}RIGHT JOIN {}{}",
863 prefix(constraint),
864 self.relation,
865 suffix(constraint)
866 ),
867 JoinOperator::FullOuter(constraint) => write!(
868 f,
869 " {}FULL JOIN {}{}",
870 prefix(constraint),
871 self.relation,
872 suffix(constraint)
873 ),
874 JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
875 JoinOperator::AsOfInner(constraint) => write!(
876 f,
877 " {}ASOF JOIN {}{}",
878 prefix(constraint),
879 self.relation,
880 suffix(constraint)
881 ),
882 JoinOperator::AsOfLeft(constraint) => write!(
883 f,
884 " {}ASOF LEFT JOIN {}{}",
885 prefix(constraint),
886 self.relation,
887 suffix(constraint)
888 ),
889 }
890 }
891}
892
893#[derive(Debug, Clone, PartialEq, Eq, Hash)]
894pub enum JoinOperator {
895 Inner(JoinConstraint),
896 LeftOuter(JoinConstraint),
897 RightOuter(JoinConstraint),
898 FullOuter(JoinConstraint),
899 CrossJoin,
900 AsOfInner(JoinConstraint),
901 AsOfLeft(JoinConstraint),
902}
903
904#[derive(Debug, Clone, PartialEq, Eq, Hash)]
905pub enum JoinConstraint {
906 On(Expr),
907 Using(Vec<Ident>),
908 Natural,
909 None,
910}
911
912#[derive(Debug, Clone, PartialEq, Eq, Hash)]
914pub struct OrderByExpr {
915 pub expr: Expr,
916 pub asc: Option<bool>,
918 pub nulls_first: Option<bool>,
920}
921
922impl fmt::Display for OrderByExpr {
923 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
924 write!(f, "{}", self.expr)?;
925 match self.asc {
926 Some(true) => write!(f, " ASC")?,
927 Some(false) => write!(f, " DESC")?,
928 None => (),
929 }
930 match self.nulls_first {
931 Some(true) => write!(f, " NULLS FIRST")?,
932 Some(false) => write!(f, " NULLS LAST")?,
933 None => (),
934 }
935 Ok(())
936 }
937}
938
939#[derive(Debug, Clone, PartialEq, Eq, Hash)]
940pub struct Fetch {
941 pub with_ties: bool,
942 pub quantity: Option<String>,
943}
944
945impl fmt::Display for Fetch {
946 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947 let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
948 if let Some(ref quantity) = self.quantity {
949 write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
950 } else {
951 write!(f, "FETCH FIRST ROWS {}", extension)
952 }
953 }
954}
955
956#[derive(Debug, Clone, PartialEq, Eq, Hash)]
957pub struct Top {
958 pub with_ties: bool,
960 pub percent: bool,
961 pub quantity: Option<Expr>,
962}
963
964impl fmt::Display for Top {
965 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966 let extension = if self.with_ties { " WITH TIES" } else { "" };
967 if let Some(ref quantity) = self.quantity {
968 let percent = if self.percent { " PERCENT" } else { "" };
969 write!(f, "TOP ({}){}{}", quantity, percent, extension)
970 } else {
971 write!(f, "TOP{}", extension)
972 }
973 }
974}
975
976#[derive(Debug, Clone, PartialEq, Eq, Hash)]
977pub struct Values(pub Vec<Vec<Expr>>);
978
979impl fmt::Display for Values {
980 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981 write!(f, "VALUES ")?;
982 let mut delim = "";
983 for row in &self.0 {
984 write!(f, "{}", delim)?;
985 delim = ", ";
986 write!(f, "({})", display_comma_separated(row))?;
987 }
988 Ok(())
989 }
990}
991
992#[derive(Debug, Clone, PartialEq, Eq, Hash)]
994pub struct NamedWindow {
995 pub name: Ident,
996 pub window_spec: WindowSpec,
997}
998
999impl fmt::Display for NamedWindow {
1000 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1001 write!(f, "{} AS ({})", self.name, self.window_spec)
1002 }
1003}