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