1use std::collections::BTreeMap;
16use std::fmt::Display;
17use std::fmt::Formatter;
18
19use derive_visitor::Drive;
20use derive_visitor::DriveMut;
21use educe::Educe;
22
23use crate::ast::quote::QuotedString;
24use crate::ast::write_comma_separated_list;
25use crate::ast::write_comma_separated_string_map;
26use crate::ast::write_dot_separated_list;
27use crate::ast::Expr;
28use crate::ast::FileLocation;
29use crate::ast::Hint;
30use crate::ast::Identifier;
31use crate::ast::Lambda;
32use crate::ast::SelectStageOptions;
33use crate::ast::WindowDefinition;
34use crate::ParseError;
35use crate::Result;
36use crate::Span;
37
38#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
40pub struct Query {
41 pub span: Span,
42 pub with: Option<With>,
44 pub body: SetExpr,
46
47 pub order_by: Vec<OrderByExpr>,
50 pub limit: Vec<Expr>,
52 pub offset: Option<Expr>,
54
55 pub ignore_result: bool,
57}
58
59impl Display for Query {
60 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
61 if let Some(with) = &self.with {
63 write!(f, "WITH {with} ")?;
64 }
65
66 write!(f, "{}", self.body)?;
68
69 if !self.order_by.is_empty() {
71 write!(f, " ORDER BY ")?;
72 write_comma_separated_list(f, &self.order_by)?;
73 }
74
75 if !self.limit.is_empty() {
77 write!(f, " LIMIT ")?;
78 write_comma_separated_list(f, &self.limit)?;
79 }
80
81 if let Some(offset) = &self.offset {
83 write!(f, " OFFSET {offset}")?;
84 }
85
86 if self.ignore_result {
87 write!(f, " IGNORE_RESULT")?;
88 }
89
90 Ok(())
91 }
92}
93
94#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
95pub struct With {
96 pub span: Span,
97 pub recursive: bool,
98 pub ctes: Vec<CTE>,
99}
100
101impl Display for With {
102 #[recursive::recursive]
103 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
104 if self.recursive {
105 write!(f, "RECURSIVE ")?;
106 }
107
108 write_comma_separated_list(f, &self.ctes)?;
109 Ok(())
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
114pub struct CTE {
115 pub span: Span,
116 pub alias: TableAlias,
117 pub materialized: bool,
118 pub query: Box<Query>,
119}
120
121impl Display for CTE {
122 #[recursive::recursive]
123 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
124 write!(f, "{} AS ", self.alias)?;
125 if self.materialized {
126 write!(f, "MATERIALIZED ")?;
127 }
128 write!(f, "({})", self.query)?;
129 Ok(())
130 }
131}
132
133#[derive(Educe, Drive, DriveMut)]
134#[educe(
135 PartialEq(bound = false, attrs = "#[recursive::recursive]"),
136 Clone(bound = false, attrs = "#[recursive::recursive]"),
137 Debug(bound = false, attrs = "#[recursive::recursive]")
138)]
139pub struct SetOperation {
140 pub span: Span,
141 pub op: SetOperator,
142 pub all: bool,
143 pub left: Box<SetExpr>,
144 pub right: Box<SetExpr>,
145}
146
147#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
149pub struct SelectStmt {
150 pub span: Span,
151 pub hints: Option<Hint>,
152 pub distinct: bool,
153 pub top_n: Option<u64>,
154 pub select_list: Vec<SelectTarget>,
156 pub from: Vec<TableReference>,
160 pub selection: Option<Expr>,
162 pub group_by: Option<GroupBy>,
164 pub having: Option<Expr>,
166 pub window_list: Option<Vec<WindowDefinition>>,
168 pub qualify: Option<Expr>,
170}
171
172impl Display for SelectStmt {
173 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
174 write!(f, "SELECT ")?;
176 if let Some(hints) = &self.hints {
177 write!(f, "{} ", hints)?;
178 }
179 if self.distinct {
180 write!(f, "DISTINCT ")?;
181 }
182 if let Some(topn) = &self.top_n {
183 write!(f, "TOP {} ", topn)?;
184 }
185 write_comma_separated_list(f, &self.select_list)?;
186
187 if !self.from.is_empty() {
189 write!(f, " FROM ")?;
190 write_comma_separated_list(f, &self.from)?;
191 }
192
193 if let Some(expr) = &self.selection {
195 write!(f, " WHERE {expr}")?;
196 }
197
198 if self.group_by.is_some() {
200 write!(f, " GROUP BY ")?;
201 write!(f, "{}", self.group_by.as_ref().unwrap())?;
202 }
203 if let Some(having) = &self.having {
205 write!(f, " HAVING {having}")?;
206 }
207
208 if let Some(windows) = &self.window_list {
210 write!(f, " WINDOW ")?;
211 write_comma_separated_list(f, windows)?;
212 }
213
214 if let Some(qualify) = &self.qualify {
215 write!(f, " QUALIFY {qualify}")?;
216 }
217 Ok(())
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
223pub enum GroupBy {
224 Normal(Vec<Expr>),
226 All,
228 GroupingSets(Vec<Vec<Expr>>),
232 Cube(Vec<Expr>),
234 Rollup(Vec<Expr>),
236 Combined(Vec<GroupBy>),
237}
238
239impl GroupBy {
240 pub fn normal_items(&self) -> Vec<Expr> {
241 match self {
242 GroupBy::Normal(exprs) => exprs.clone(),
243 _ => Vec::new(),
244 }
245 }
246}
247
248impl Display for GroupBy {
249 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
250 match self {
251 GroupBy::Normal(exprs) => {
252 write_comma_separated_list(f, exprs)?;
253 }
254 GroupBy::All => {
255 write!(f, "ALL")?;
256 }
257 GroupBy::GroupingSets(sets) => {
258 write!(f, "GROUPING SETS (")?;
259 for (i, set) in sets.iter().enumerate() {
260 if i > 0 {
261 write!(f, ", ")?;
262 }
263 write!(f, "(")?;
264 write_comma_separated_list(f, set)?;
265 write!(f, ")")?;
266 }
267 write!(f, ")")?;
268 }
269 GroupBy::Cube(exprs) => {
270 write!(f, "CUBE (")?;
271 write_comma_separated_list(f, exprs)?;
272 write!(f, ")")?;
273 }
274 GroupBy::Rollup(exprs) => {
275 write!(f, "ROLLUP (")?;
276 write_comma_separated_list(f, exprs)?;
277 write!(f, ")")?;
278 }
279 GroupBy::Combined(group_bys) => {
280 for (i, group_by) in group_bys.iter().enumerate() {
281 if i > 0 {
282 write!(f, ", ")?;
283 }
284 write!(f, "{}", group_by)?;
285 }
286 }
287 }
288 Ok(())
289 }
290}
291
292#[derive(Educe, Drive, DriveMut)]
294#[educe(
295 PartialEq(bound = false, attrs = "#[recursive::recursive]"),
296 Clone(bound = false, attrs = "#[recursive::recursive]"),
297 Debug(bound = false, attrs = "#[recursive::recursive]")
298)]
299pub enum SetExpr {
300 Select(Box<SelectStmt>),
301 Query(Box<Query>),
302 SetOperation(Box<SetOperation>),
304 Values { span: Span, values: Vec<Vec<Expr>> },
306}
307
308impl Display for SetExpr {
309 #[recursive::recursive]
310 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
311 match self {
312 SetExpr::Select(select_stmt) => {
313 write!(f, "{select_stmt}")?;
314 }
315 SetExpr::Query(query) => {
316 write!(f, "({query})")?;
317 }
318 SetExpr::SetOperation(set_operation) => {
319 let left_needs_parentheses = matches!(set_operation.left.as_ref(), SetExpr::SetOperation(left_op) if left_op.op < set_operation.op);
321 let right_needs_parentheses = matches!(set_operation.right.as_ref(), SetExpr::SetOperation(right_op) if right_op.op < set_operation.op);
322
323 if left_needs_parentheses {
324 write!(f, "(")?;
325 }
326 write!(f, "{}", set_operation.left)?;
327 if left_needs_parentheses {
328 write!(f, ")")?;
329 }
330
331 match set_operation.op {
332 SetOperator::Union => {
333 write!(f, " UNION ")?;
334 }
335 SetOperator::Except => {
336 write!(f, " EXCEPT ")?;
337 }
338 SetOperator::Intersect => {
339 write!(f, " INTERSECT ")?;
340 }
341 }
342 if set_operation.all {
343 write!(f, "ALL ")?;
344 }
345 if right_needs_parentheses {
347 write!(f, "(")?;
348 }
349 write!(f, "{}", set_operation.right)?;
350 if right_needs_parentheses {
351 write!(f, ")")?;
352 }
353 }
354 SetExpr::Values { values, .. } => {
355 write!(f, "VALUES")?;
356 for (i, value) in values.iter().enumerate() {
357 if i > 0 {
358 write!(f, ", ")?;
359 }
360 write!(f, "(")?;
361 write_comma_separated_list(f, value)?;
362 write!(f, ")")?;
363 }
364 }
365 }
366 Ok(())
367 }
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
371pub enum SetOperator {
372 Union,
373 Except,
374 Intersect,
375}
376
377impl PartialOrd for SetOperator {
378 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
379 if self == other {
380 Some(std::cmp::Ordering::Equal)
381 } else if self == &SetOperator::Intersect {
382 Some(std::cmp::Ordering::Greater)
383 } else {
384 Some(std::cmp::Ordering::Less)
385 }
386 }
387}
388
389#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
391pub struct OrderByExpr {
392 pub expr: Expr,
393 pub asc: Option<bool>,
395 pub nulls_first: Option<bool>,
397}
398
399impl Display for OrderByExpr {
400 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
401 write!(f, "{}", self.expr)?;
402 if let Some(asc) = self.asc {
403 if asc {
404 write!(f, " ASC")?;
405 } else {
406 write!(f, " DESC")?;
407 }
408 }
409 if let Some(nulls_first) = self.nulls_first {
410 if nulls_first {
411 write!(f, " NULLS FIRST")?;
412 } else {
413 write!(f, " NULLS LAST")?;
414 }
415 }
416 Ok(())
417 }
418}
419
420#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
422pub enum SelectTarget {
423 AliasedExpr {
425 expr: Box<Expr>,
426 alias: Option<Identifier>,
427 },
428
429 StarColumns {
434 qualified: QualifiedName,
435 column_filter: Option<ColumnFilter>,
436 },
437}
438
439impl SelectTarget {
440 pub fn is_star(&self) -> bool {
441 match self {
442 SelectTarget::AliasedExpr { .. } => false,
443 SelectTarget::StarColumns { qualified, .. } => {
444 matches!(qualified.last(), Some(Indirection::Star(_)))
445 }
446 }
447 }
448
449 pub fn exclude(&mut self, exclude: Vec<Identifier>) {
450 match self {
451 SelectTarget::AliasedExpr { .. } => unreachable!(),
452 SelectTarget::StarColumns { column_filter, .. } => {
453 *column_filter = Some(ColumnFilter::Excludes(exclude));
454 }
455 }
456 }
457
458 pub fn has_window(&self) -> bool {
459 match self {
460 SelectTarget::AliasedExpr { expr, .. } => match &**expr {
461 Expr::FunctionCall { func, .. } => func.window.is_some(),
462 _ => false,
463 },
464 SelectTarget::StarColumns { .. } => false,
465 }
466 }
467
468 pub fn function_call_name(&self) -> Option<String> {
469 match self {
470 SelectTarget::AliasedExpr { expr, .. } => match &**expr {
471 Expr::FunctionCall { func, .. } if func.window.is_none() => {
472 Some(func.name.name.to_lowercase())
473 }
474 _ => None,
475 },
476 SelectTarget::StarColumns { .. } => None,
477 }
478 }
479}
480
481impl Display for SelectTarget {
482 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
483 match self {
484 SelectTarget::AliasedExpr { expr, alias } => {
485 write!(f, "{expr}")?;
486 if let Some(ident) = alias {
487 write!(f, " AS {ident}")?;
488 }
489 }
490 SelectTarget::StarColumns {
491 qualified,
492 column_filter,
493 } => match column_filter {
494 Some(ColumnFilter::Excludes(excludes)) => {
495 write_dot_separated_list(f, qualified)?;
496 write!(f, " EXCLUDE (")?;
497 write_comma_separated_list(f, excludes)?;
498 write!(f, ")")?;
499 }
500 Some(ColumnFilter::Lambda(lambda)) => {
501 write!(f, "COLUMNS({lambda})")?;
502 }
503 None => {
504 write_dot_separated_list(f, qualified)?;
505 }
506 },
507 }
508 Ok(())
509 }
510}
511
512#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
513pub enum ColumnFilter {
514 Excludes(Vec<Identifier>),
515 Lambda(Lambda),
516}
517
518impl ColumnFilter {
519 pub fn get_excludes(&self) -> Option<&[Identifier]> {
520 if let ColumnFilter::Excludes(ex) = self {
521 Some(ex)
522 } else {
523 None
524 }
525 }
526
527 pub fn get_lambda(&self) -> Option<&Lambda> {
528 if let ColumnFilter::Lambda(l) = self {
529 Some(l)
530 } else {
531 None
532 }
533 }
534}
535
536pub type QualifiedName = Vec<Indirection>;
537
538#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
541pub enum Indirection {
542 Identifier(Identifier),
544 Star(Span),
546}
547
548impl Display for Indirection {
549 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
550 match self {
551 Indirection::Identifier(ident) => {
552 write!(f, "{ident}")?;
553 }
554 Indirection::Star(_) => {
555 write!(f, "*")?;
556 }
557 }
558 Ok(())
559 }
560}
561
562#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
564pub enum TimeTravelPoint {
565 Snapshot(String),
566 Timestamp(Box<Expr>),
567 Offset(Box<Expr>),
568 Stream {
569 catalog: Option<Identifier>,
570 database: Option<Identifier>,
571 name: Identifier,
572 },
573}
574
575impl Display for TimeTravelPoint {
576 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
577 match self {
578 TimeTravelPoint::Snapshot(sid) => {
579 write!(f, "(SNAPSHOT => '{sid}')")?;
580 }
581 TimeTravelPoint::Timestamp(ts) => {
582 write!(f, "(TIMESTAMP => {ts})")?;
583 }
584 TimeTravelPoint::Offset(num) => {
585 write!(f, "(OFFSET => {num})")?;
586 }
587 TimeTravelPoint::Stream {
588 catalog,
589 database,
590 name,
591 } => {
592 write!(f, "(STREAM => ")?;
593 write_dot_separated_list(
594 f,
595 catalog.iter().chain(database.iter()).chain(Some(name)),
596 )?;
597 write!(f, ")")?;
598 }
599 }
600
601 Ok(())
602 }
603}
604
605#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
606pub enum PivotValues {
607 ColumnValues(Vec<Expr>),
608 Subquery(Box<Query>),
609}
610
611#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
612pub struct Pivot {
613 pub aggregate: Expr,
614 pub value_column: Identifier,
615 pub values: PivotValues,
616}
617
618impl Display for Pivot {
619 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
620 write!(f, "PIVOT({} FOR {} IN (", self.aggregate, self.value_column)?;
621 match &self.values {
622 PivotValues::ColumnValues(column_values) => {
623 write_comma_separated_list(f, column_values)?;
624 }
625 PivotValues::Subquery(subquery) => {
626 write!(f, "{}", subquery)?;
627 }
628 }
629 write!(f, "))")?;
630 Ok(())
631 }
632}
633
634#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
635pub struct UnpivotName {
636 pub ident: Identifier,
637 pub alias: Option<String>,
638}
639
640impl Display for UnpivotName {
641 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
642 match &self.alias {
643 Some(alias) => {
644 write!(f, "{} AS {}", self.ident, QuotedString(alias, '\''))
645 }
646 None => write!(f, "{}", self.ident),
647 }
648 }
649}
650
651#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
652pub struct Unpivot {
653 pub value_column: Identifier,
654 pub unpivot_column: Identifier,
655 pub column_names: Vec<UnpivotName>,
656}
657
658impl Display for Unpivot {
659 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
660 write!(
661 f,
662 "UNPIVOT({} FOR {} IN (",
663 self.value_column, self.unpivot_column
664 )?;
665 write_comma_separated_list(f, &self.column_names)?;
666 write!(f, "))")
667 }
668}
669
670#[derive(Debug, Clone, PartialEq, Eq, Default, Drive, DriveMut)]
671pub struct WithOptions {
672 pub options: BTreeMap<String, String>,
673}
674
675impl Display for WithOptions {
676 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
677 write!(f, "WITH (")?;
678 write_comma_separated_string_map(f, &self.options)?;
679 write!(f, ")")
680 }
681}
682
683impl WithOptions {
684 pub fn to_change_query_with_clause(&self) -> String {
686 let mut result = String::from(" WITH (");
687 for (i, (k, v)) in self.options.iter().enumerate() {
688 if i > 0 {
689 result.push_str(", ");
690 }
691
692 if k == "consume" {
693 result.push_str("consume = false");
696 } else {
697 result.push_str(&format!("{k} = '{v}'"));
698 }
699 }
700 result.push(')');
701 result
702 }
703}
704
705#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
706pub struct ChangesInterval {
707 pub append_only: bool,
708 pub at_point: TimeTravelPoint,
709 pub end_point: Option<TimeTravelPoint>,
710}
711
712impl Display for ChangesInterval {
713 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
714 write!(f, "CHANGES (INFORMATION => ")?;
715 if self.append_only {
716 write!(f, "APPEND_ONLY")?;
717 } else {
718 write!(f, "DEFAULT")?;
719 }
720 write!(f, ") AT {}", self.at_point)?;
721 if let Some(end_point) = &self.end_point {
722 write!(f, " END {}", end_point)?;
723 }
724 Ok(())
725 }
726}
727
728#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
729pub enum TemporalClause {
730 TimeTravel(TimeTravelPoint),
731 Changes(ChangesInterval),
732}
733
734impl Display for TemporalClause {
735 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
736 match self {
737 TemporalClause::TimeTravel(point) => {
738 write!(f, "AT {}", point)?;
739 }
740 TemporalClause::Changes(changes) => {
741 write!(f, "{}", changes)?;
742 }
743 }
744 Ok(())
745 }
746}
747
748#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Drive, DriveMut)]
749pub enum SampleRowLevel {
750 RowsNum(f64),
751 Probability(f64),
752}
753
754impl SampleRowLevel {
755 pub fn sample_probability(&self, stats_rows: Option<u64>) -> Result<Option<f64>> {
756 let rand = match &self {
757 SampleRowLevel::Probability(probability) => probability / 100.0,
758 SampleRowLevel::RowsNum(rows) => {
759 if let Some(row_num) = stats_rows {
760 if row_num > 0 {
761 rows / row_num as f64
762 } else {
763 return Ok(None);
764 }
765 } else {
766 return Ok(None);
767 }
768 }
769 };
770 if rand > 1.0 {
771 return Err(ParseError(
772 None,
773 format!(
774 "Sample value should be less than or equal to 100, but got {}",
775 rand * 100.0
776 ),
777 ));
778 }
779 Ok(Some(rand))
780 }
781}
782
783impl Eq for SampleRowLevel {}
784
785#[derive(
786 serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Drive, DriveMut, Default,
787)]
788pub struct SampleConfig {
789 pub row_level: Option<SampleRowLevel>,
790 pub block_level: Option<f64>,
791}
792
793impl SampleConfig {
794 pub fn set_row_level_sample(&mut self, value: f64, rows: bool) {
795 if rows {
796 self.row_level = Some(SampleRowLevel::RowsNum(value));
797 } else {
798 self.row_level = Some(SampleRowLevel::Probability(value));
799 }
800 }
801
802 pub fn set_block_level_sample(&mut self, probability: f64) {
803 self.block_level = Some(probability);
804 }
805}
806
807impl Eq for SampleConfig {}
808
809impl Display for SampleConfig {
810 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
811 write!(f, "SAMPLE ")?;
812 if let Some(block_level) = self.block_level {
813 write!(f, "BLOCK ({}) ", block_level)?;
814 }
815 if let Some(row_level) = &self.row_level {
816 match row_level {
817 SampleRowLevel::RowsNum(rows) => {
818 write!(f, "ROW ({} ROWS)", rows)?;
819 }
820 SampleRowLevel::Probability(probability) => {
821 write!(f, "ROW ({})", probability)?;
822 }
823 }
824 }
825 Ok(())
826 }
827}
828
829#[allow(clippy::large_enum_variant)]
831#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
832pub enum TableReference {
833 Table {
835 span: Span,
836 catalog: Option<Identifier>,
837 database: Option<Identifier>,
838 table: Identifier,
839 alias: Option<TableAlias>,
840 temporal: Option<TemporalClause>,
841 with_options: Option<WithOptions>,
842 pivot: Option<Box<Pivot>>,
843 unpivot: Option<Box<Unpivot>>,
844 sample: Option<SampleConfig>,
845 },
846 TableFunction {
848 span: Span,
849 lateral: bool,
851 name: Identifier,
852 params: Vec<Expr>,
853 named_params: Vec<(Identifier, Expr)>,
854 alias: Option<TableAlias>,
855 sample: Option<SampleConfig>,
856 },
857 Subquery {
859 span: Span,
860 lateral: bool,
862 subquery: Box<Query>,
863 alias: Option<TableAlias>,
864 pivot: Option<Box<Pivot>>,
865 unpivot: Option<Box<Unpivot>>,
866 },
867 Join {
868 span: Span,
869 join: Join,
870 },
871 Location {
872 span: Span,
873 location: FileLocation,
874 options: SelectStageOptions,
875 alias: Option<TableAlias>,
876 },
877}
878
879impl TableReference {
880 pub fn pivot(&self) -> Option<&Pivot> {
881 match self {
882 TableReference::Table { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()),
883 TableReference::Subquery { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()),
884 _ => None,
885 }
886 }
887
888 pub fn unpivot(&self) -> Option<&Unpivot> {
889 match self {
890 TableReference::Table { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()),
891 TableReference::Subquery { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()),
892 _ => None,
893 }
894 }
895
896 pub fn is_lateral_table_function(&self) -> bool {
897 match self {
898 TableReference::TableFunction { lateral, .. } => *lateral,
899 _ => false,
900 }
901 }
902
903 pub fn is_lateral_subquery(&self) -> bool {
904 match self {
905 TableReference::Subquery { lateral, .. } => *lateral,
906 _ => false,
907 }
908 }
909}
910
911impl Display for TableReference {
912 #[recursive::recursive]
913 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
914 match self {
915 TableReference::Table {
916 span: _,
917 catalog,
918 database,
919 table,
920 alias,
921 temporal,
922 with_options,
923 pivot,
924 unpivot,
925 sample,
926 } => {
927 write_dot_separated_list(
928 f,
929 catalog.iter().chain(database.iter()).chain(Some(table)),
930 )?;
931
932 if let Some(temporal) = temporal {
933 write!(f, " {temporal}")?;
934 }
935
936 if let Some(with_options) = with_options {
937 write!(f, " {with_options}")?;
938 }
939
940 if let Some(alias) = alias {
941 write!(f, " AS {alias}")?;
942 }
943 if let Some(pivot) = pivot {
944 write!(f, " {pivot}")?;
945 }
946
947 if let Some(unpivot) = unpivot {
948 write!(f, " {unpivot}")?;
949 }
950
951 if let Some(sample) = sample {
952 write!(f, " {sample}")?;
953 }
954 }
955 TableReference::TableFunction {
956 span: _,
957 lateral,
958 name,
959 params,
960 named_params,
961 alias,
962 sample,
963 } => {
964 if *lateral {
965 write!(f, "LATERAL ")?;
966 }
967 write!(f, "{name}(")?;
968 write_comma_separated_list(f, params)?;
969 if !params.is_empty() && !named_params.is_empty() {
970 write!(f, ",")?;
971 }
972 for (i, (k, v)) in named_params.iter().enumerate() {
973 if i > 0 {
974 write!(f, ",")?;
975 }
976 write!(f, "{k}=>{v}")?;
977 }
978 write!(f, ")")?;
979 if let Some(alias) = alias {
980 write!(f, " AS {alias}")?;
981 }
982 if let Some(sample) = sample {
983 write!(f, " {sample}")?;
984 }
985 }
986 TableReference::Subquery {
987 span: _,
988 lateral,
989 subquery,
990 alias,
991 pivot,
992 unpivot,
993 } => {
994 if *lateral {
995 write!(f, "LATERAL ")?;
996 }
997 write!(f, "({subquery})")?;
998 if let Some(alias) = alias {
999 write!(f, " AS {alias}")?;
1000 }
1001
1002 if let Some(pivot) = pivot {
1003 write!(f, " {pivot}")?;
1004 }
1005
1006 if let Some(unpivot) = unpivot {
1007 write!(f, " {unpivot}")?;
1008 }
1009 }
1010 TableReference::Join { span: _, join } => {
1011 write!(f, "{}", join.left)?;
1012 if join.condition == JoinCondition::Natural {
1013 write!(f, " NATURAL")?;
1014 }
1015 match join.op {
1016 JoinOperator::Inner => {
1017 write!(f, " INNER JOIN")?;
1018 }
1019 JoinOperator::LeftOuter => {
1020 write!(f, " LEFT OUTER JOIN")?;
1021 }
1022 JoinOperator::RightOuter => {
1023 write!(f, " RIGHT OUTER JOIN")?;
1024 }
1025 JoinOperator::FullOuter => {
1026 write!(f, " FULL OUTER JOIN")?;
1027 }
1028 JoinOperator::LeftSemi => {
1029 write!(f, " LEFT SEMI JOIN")?;
1030 }
1031 JoinOperator::RightSemi => {
1032 write!(f, " RIGHT SEMI JOIN")?;
1033 }
1034 JoinOperator::LeftAnti => {
1035 write!(f, " LEFT ANTI JOIN")?;
1036 }
1037 JoinOperator::RightAnti => {
1038 write!(f, " RIGHT ANTI JOIN")?;
1039 }
1040 JoinOperator::CrossJoin => {
1041 write!(f, " CROSS JOIN")?;
1042 }
1043 JoinOperator::Asof => {
1044 write!(f, " ASOF JOIN")?;
1045 }
1046 JoinOperator::LeftAsof => {
1047 write!(f, " ASOF LEFT JOIN")?;
1048 }
1049 JoinOperator::RightAsof => {
1050 write!(f, " ASOF RIGHT JOIN")?;
1051 }
1052 }
1053 write!(f, " {}", join.right)?;
1054 match &join.condition {
1055 JoinCondition::On(expr) => {
1056 write!(f, " ON {expr}")?;
1057 }
1058 JoinCondition::Using(idents) => {
1059 write!(f, " USING(")?;
1060 write_comma_separated_list(f, idents)?;
1061 write!(f, ")")?;
1062 }
1063 _ => {}
1064 }
1065 }
1066 TableReference::Location {
1067 span: _,
1068 location,
1069 options,
1070 alias,
1071 } => {
1072 write!(f, "{location}")?;
1073 if !options.is_empty() {
1074 write!(f, "{options}")?;
1075 }
1076 if let Some(alias) = alias {
1077 write!(f, " AS {alias}")?;
1078 }
1079 }
1080 }
1081 Ok(())
1082 }
1083}
1084
1085#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
1086pub struct TableAlias {
1087 pub name: Identifier,
1088 pub columns: Vec<Identifier>,
1089}
1090
1091impl Display for TableAlias {
1092 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1093 write!(f, "{}", &self.name)?;
1094 if !self.columns.is_empty() {
1095 write!(f, "(")?;
1096 write_comma_separated_list(f, &self.columns)?;
1097 write!(f, ")")?;
1098 }
1099 Ok(())
1100 }
1101}
1102
1103#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1104pub struct Join {
1105 pub op: JoinOperator,
1106 pub condition: JoinCondition,
1107 pub left: Box<TableReference>,
1108 pub right: Box<TableReference>,
1109}
1110
1111#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
1112pub enum JoinOperator {
1113 Inner,
1114 LeftOuter,
1116 RightOuter,
1117 FullOuter,
1118 LeftSemi,
1119 LeftAnti,
1120 RightSemi,
1121 RightAnti,
1122 CrossJoin,
1124 Asof,
1126 LeftAsof,
1127 RightAsof,
1128}
1129
1130#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1131pub enum JoinCondition {
1132 On(Box<Expr>),
1133 Using(Vec<Identifier>),
1134 Natural,
1135 None,
1136}
1137
1138impl SetExpr {
1139 pub fn span(&self) -> Span {
1140 match self {
1141 SetExpr::Select(stmt) => stmt.span,
1142 SetExpr::Query(query) => query.span,
1143 SetExpr::SetOperation(op) => op.span,
1144 SetExpr::Values { span, .. } => *span,
1145 }
1146 }
1147
1148 pub fn into_query(self) -> Query {
1149 match self {
1150 SetExpr::Query(query) => *query,
1151 _ => Query {
1152 span: self.span(),
1153 with: None,
1154 body: self,
1155 order_by: vec![],
1156 limit: vec![],
1157 offset: None,
1158 ignore_result: false,
1159 },
1160 }
1161 }
1162}