sqlparser/ast/
query.rs1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#[cfg(not(feature = "std"))]
19use alloc::{boxed::Box, vec::Vec};
20
21use helpers::attached_token::AttachedToken;
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25#[cfg(feature = "visitor")]
26use sqlparser_derive::{Visit, VisitMut};
27
28use crate::{
29 ast::*,
30 display_utils::{indented_list, SpaceOrNewline},
31 tokenizer::{Token, TokenWithSpan},
32};
33
34/// The most complete variant of a `SELECT` query expression, optionally
35/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
36#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
39#[cfg_attr(feature = "visitor", visit(with = "visit_query"))]
40pub struct Query {
41 /// WITH (common table expressions, or CTEs)
42 pub with: Option<With>,
43 /// SELECT or UNION / EXCEPT / INTERSECT
44 pub body: Box<SetExpr>,
45 /// ORDER BY
46 pub order_by: Option<OrderBy>,
47 /// `LIMIT ... OFFSET ... | LIMIT <offset>, <limit>`
48 pub limit_clause: Option<LimitClause>,
49 /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
50 pub fetch: Option<Fetch>,
51 /// `FOR { UPDATE | SHARE } [ OF table_name ] [ SKIP LOCKED | NOWAIT ]`
52 pub locks: Vec<LockClause>,
53 /// `FOR XML { RAW | AUTO | EXPLICIT | PATH } [ , ELEMENTS ]`
54 /// `FOR JSON { AUTO | PATH } [ , INCLUDE_NULL_VALUES ]`
55 /// (MSSQL-specific)
56 pub for_clause: Option<ForClause>,
57 /// ClickHouse syntax: `SELECT * FROM t SETTINGS key1 = value1, key2 = value2`
58 ///
59 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select#settings-in-select-query)
60 pub settings: Option<Vec<Setting>>,
61 /// `SELECT * FROM t FORMAT JSONCompact`
62 ///
63 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/format)
64 /// (ClickHouse-specific)
65 pub format_clause: Option<FormatClause>,
66
67 /// Pipe operator
68 pub pipe_operators: Vec<PipeOperator>,
69}
70
71impl fmt::Display for Query {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 if let Some(ref with) = self.with {
74 with.fmt(f)?;
75 SpaceOrNewline.fmt(f)?;
76 }
77 self.body.fmt(f)?;
78 if let Some(ref order_by) = self.order_by {
79 f.write_str(" ")?;
80 order_by.fmt(f)?;
81 }
82
83 if let Some(ref limit_clause) = self.limit_clause {
84 limit_clause.fmt(f)?;
85 }
86 if let Some(ref settings) = self.settings {
87 f.write_str(" SETTINGS ")?;
88 display_comma_separated(settings).fmt(f)?;
89 }
90 if let Some(ref fetch) = self.fetch {
91 f.write_str(" ")?;
92 fetch.fmt(f)?;
93 }
94 if !self.locks.is_empty() {
95 f.write_str(" ")?;
96 display_separated(&self.locks, " ").fmt(f)?;
97 }
98 if let Some(ref for_clause) = self.for_clause {
99 f.write_str(" ")?;
100 for_clause.fmt(f)?;
101 }
102 if let Some(ref format) = self.format_clause {
103 f.write_str(" ")?;
104 format.fmt(f)?;
105 }
106 for pipe_operator in &self.pipe_operators {
107 f.write_str(" |> ")?;
108 pipe_operator.fmt(f)?;
109 }
110 Ok(())
111 }
112}
113
114/// Query syntax for ClickHouse ADD PROJECTION statement.
115/// Its syntax is similar to SELECT statement, but it is used to add a new projection to a table.
116/// Syntax is `SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY]`
117///
118/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
119#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
122pub struct ProjectionSelect {
123 /// The list of projected select items.
124 pub projection: Vec<SelectItem>,
125 /// Optional `ORDER BY` clause for the projection-select.
126 pub order_by: Option<OrderBy>,
127 /// Optional `GROUP BY` clause for the projection-select.
128 pub group_by: Option<GroupByExpr>,
129}
130
131impl fmt::Display for ProjectionSelect {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 write!(f, "SELECT {}", display_comma_separated(&self.projection))?;
134 if let Some(ref group_by) = self.group_by {
135 write!(f, " {group_by}")?;
136 }
137 if let Some(ref order_by) = self.order_by {
138 write!(f, " {order_by}")?;
139 }
140 Ok(())
141 }
142}
143
144/// A node in a tree, representing a "query body" expression, roughly:
145/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
146#[allow(clippy::large_enum_variant)]
147#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
148#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
150pub enum SetExpr {
151 /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
152 Select(Box<Select>),
153 /// Parenthesized SELECT subquery, which may include more set operations
154 /// in its body and an optional ORDER BY / LIMIT.
155 Query(Box<Query>),
156 /// UNION/EXCEPT/INTERSECT of two queries
157 /// A set operation combining two query expressions.
158 SetOperation {
159 /// The set operator used (e.g. `UNION`, `EXCEPT`).
160 op: SetOperator,
161 /// Optional quantifier (`ALL`, `DISTINCT`, etc.).
162 set_quantifier: SetQuantifier,
163 /// Left operand of the set operation.
164 left: Box<SetExpr>,
165 /// Right operand of the set operation.
166 right: Box<SetExpr>,
167 },
168 /// `VALUES (...)`
169 Values(Values),
170 /// `INSERT` statement
171 Insert(Statement),
172 /// `UPDATE` statement
173 Update(Statement),
174 /// `DELETE` statement
175 Delete(Statement),
176 /// `MERGE` statement
177 Merge(Statement),
178 /// `TABLE` command
179 Table(Box<Table>),
180}
181
182impl SetExpr {
183 /// If this `SetExpr` is a `SELECT`, returns the [`Select`].
184 pub fn as_select(&self) -> Option<&Select> {
185 if let Self::Select(select) = self {
186 Some(&**select)
187 } else {
188 None
189 }
190 }
191}
192
193impl fmt::Display for SetExpr {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 match self {
196 SetExpr::Select(s) => s.fmt(f),
197 SetExpr::Query(q) => {
198 f.write_str("(")?;
199 q.fmt(f)?;
200 f.write_str(")")
201 }
202 SetExpr::Values(v) => v.fmt(f),
203 SetExpr::Insert(v) => v.fmt(f),
204 SetExpr::Update(v) => v.fmt(f),
205 SetExpr::Delete(v) => v.fmt(f),
206 SetExpr::Merge(v) => v.fmt(f),
207 SetExpr::Table(t) => t.fmt(f),
208 SetExpr::SetOperation {
209 left,
210 right,
211 op,
212 set_quantifier,
213 } => {
214 left.fmt(f)?;
215 SpaceOrNewline.fmt(f)?;
216 op.fmt(f)?;
217 match set_quantifier {
218 SetQuantifier::All
219 | SetQuantifier::Distinct
220 | SetQuantifier::ByName
221 | SetQuantifier::AllByName
222 | SetQuantifier::DistinctByName => {
223 f.write_str(" ")?;
224 set_quantifier.fmt(f)?;
225 }
226 SetQuantifier::None => {}
227 }
228 SpaceOrNewline.fmt(f)?;
229 right.fmt(f)?;
230 Ok(())
231 }
232 }
233 }
234}
235
236#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
238#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
239/// A set operator for combining two `SetExpr`s.
240pub enum SetOperator {
241 /// `UNION` set operator
242 Union,
243 /// `EXCEPT` set operator
244 Except,
245 /// `INTERSECT` set operator
246 Intersect,
247 /// `MINUS` set operator (non-standard)
248 Minus,
249}
250
251impl fmt::Display for SetOperator {
252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 f.write_str(match self {
254 SetOperator::Union => "UNION",
255 SetOperator::Except => "EXCEPT",
256 SetOperator::Intersect => "INTERSECT",
257 SetOperator::Minus => "MINUS",
258 })
259 }
260}
261
262/// A quantifier for [SetOperator].
263// TODO: Restrict parsing specific SetQuantifier in some specific dialects.
264// For example, BigQuery does not support `DISTINCT` for `EXCEPT` and `INTERSECT`
265#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
267#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
268pub enum SetQuantifier {
269 /// `ALL` quantifier
270 All,
271 /// `DISTINCT` quantifier
272 Distinct,
273 /// `BY NAME` quantifier
274 ByName,
275 /// `ALL BY NAME` quantifier
276 AllByName,
277 /// `DISTINCT BY NAME` quantifier
278 DistinctByName,
279 /// No quantifier specified
280 None,
281}
282
283impl fmt::Display for SetQuantifier {
284 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285 match self {
286 SetQuantifier::All => write!(f, "ALL"),
287 SetQuantifier::Distinct => write!(f, "DISTINCT"),
288 SetQuantifier::ByName => write!(f, "BY NAME"),
289 SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
290 SetQuantifier::DistinctByName => write!(f, "DISTINCT BY NAME"),
291 SetQuantifier::None => Ok(()),
292 }
293 }
294}
295
296#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298/// A [`TABLE` command]( https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE)
299#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
300/// A (possibly schema-qualified) table reference used in `FROM` clauses.
301pub struct Table {
302 /// Optional table name (absent for e.g. `TABLE` command without argument).
303 pub table_name: Option<String>,
304 /// Optional schema/catalog name qualifying the table.
305 pub schema_name: Option<String>,
306}
307
308impl fmt::Display for Table {
309 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310 if let Some(ref schema_name) = self.schema_name {
311 write!(
312 f,
313 "TABLE {}.{}",
314 schema_name,
315 self.table_name.as_ref().unwrap(),
316 )?;
317 } else {
318 write!(f, "TABLE {}", self.table_name.as_ref().unwrap(),)?;
319 }
320 Ok(())
321 }
322}
323
324/// What did this select look like?
325#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
326#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
327#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
328pub enum SelectFlavor {
329 /// `SELECT *`
330 Standard,
331 /// `FROM ... SELECT *`
332 FromFirst,
333 /// `FROM *`
334 FromFirstNoSelect,
335}
336
337/// MySQL-specific SELECT modifiers that appear after the SELECT keyword.
338///
339/// These modifiers affect query execution and optimization. They can appear in any order after
340/// SELECT and before the column list, can be repeated, and can be interleaved with
341/// DISTINCT/DISTINCTROW/ALL:
342///
343/// ```sql
344/// SELECT
345/// [ALL | DISTINCT | DISTINCTROW]
346/// [HIGH_PRIORITY]
347/// [STRAIGHT_JOIN]
348/// [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
349/// [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
350/// select_expr [, select_expr] ...
351/// ```
352///
353/// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
354#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
355#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
356#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
357pub struct SelectModifiers {
358 /// `HIGH_PRIORITY` gives the SELECT higher priority than statements that update a table.
359 ///
360 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
361 pub high_priority: bool,
362 /// `STRAIGHT_JOIN` forces the optimizer to join tables in the order listed in the FROM clause.
363 ///
364 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
365 pub straight_join: bool,
366 /// `SQL_SMALL_RESULT` hints that the result set is small, using in-memory temp tables.
367 ///
368 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
369 pub sql_small_result: bool,
370 /// `SQL_BIG_RESULT` hints that the result set is large, using disk-based temp tables.
371 ///
372 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
373 pub sql_big_result: bool,
374 /// `SQL_BUFFER_RESULT` forces the result to be put into a temporary table to release locks early.
375 ///
376 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
377 pub sql_buffer_result: bool,
378 /// `SQL_NO_CACHE` tells MySQL not to cache the query result. (Deprecated in 8.4+.)
379 ///
380 /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
381 pub sql_no_cache: bool,
382 /// `SQL_CALC_FOUND_ROWS` tells MySQL to calculate the total number of rows. (Deprecated in 8.0.17+.)
383 ///
384 /// - [MySQL SELECT modifiers](https://dev.mysql.com/doc/refman/8.4/en/select.html)
385 /// - [`FOUND_ROWS()`](https://dev.mysql.com/doc/refman/8.4/en/information-functions.html#function_found-rows)
386 pub sql_calc_found_rows: bool,
387}
388
389impl fmt::Display for SelectModifiers {
390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391 if self.high_priority {
392 f.write_str(" HIGH_PRIORITY")?;
393 }
394 if self.straight_join {
395 f.write_str(" STRAIGHT_JOIN")?;
396 }
397 if self.sql_small_result {
398 f.write_str(" SQL_SMALL_RESULT")?;
399 }
400 if self.sql_big_result {
401 f.write_str(" SQL_BIG_RESULT")?;
402 }
403 if self.sql_buffer_result {
404 f.write_str(" SQL_BUFFER_RESULT")?;
405 }
406 if self.sql_no_cache {
407 f.write_str(" SQL_NO_CACHE")?;
408 }
409 if self.sql_calc_found_rows {
410 f.write_str(" SQL_CALC_FOUND_ROWS")?;
411 }
412 Ok(())
413 }
414}
415
416impl SelectModifiers {
417 /// Returns true if any of the modifiers are set.
418 pub fn is_any_set(&self) -> bool {
419 // Using irrefutable destructuring to catch fields added in the future
420 let Self {
421 high_priority,
422 straight_join,
423 sql_small_result,
424 sql_big_result,
425 sql_buffer_result,
426 sql_no_cache,
427 sql_calc_found_rows,
428 } = self;
429 *high_priority
430 || *straight_join
431 || *sql_small_result
432 || *sql_big_result
433 || *sql_buffer_result
434 || *sql_no_cache
435 || *sql_calc_found_rows
436 }
437}
438
439/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
440/// appear either as the only body item of a `Query`, or as an operand
441/// to a set operation like `UNION`.
442#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
444#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
445pub struct Select {
446 /// Token for the `SELECT` keyword
447 pub select_token: AttachedToken,
448 /// A query optimizer hint
449 ///
450 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
451 /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
452 pub optimizer_hint: Option<OptimizerHint>,
453 /// `SELECT [DISTINCT] ...`
454 pub distinct: Option<Distinct>,
455 /// MySQL-specific SELECT modifiers.
456 ///
457 /// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
458 pub select_modifiers: Option<SelectModifiers>,
459 /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
460 pub top: Option<Top>,
461 /// Whether the top was located before `ALL`/`DISTINCT`
462 pub top_before_distinct: bool,
463 /// projection expressions
464 pub projection: Vec<SelectItem>,
465 /// Excluded columns from the projection expression which are not specified
466 /// directly after a wildcard.
467 ///
468 /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
469 pub exclude: Option<ExcludeSelectItem>,
470 /// INTO
471 pub into: Option<SelectInto>,
472 /// FROM
473 pub from: Vec<TableWithJoins>,
474 /// LATERAL VIEWs
475 pub lateral_views: Vec<LateralView>,
476 /// ClickHouse syntax: `PREWHERE a = 1 WHERE b = 2`,
477 /// and it can be used together with WHERE selection.
478 ///
479 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
480 pub prewhere: Option<Expr>,
481 /// WHERE
482 pub selection: Option<Expr>,
483 /// [START WITH ..] CONNECT BY ..
484 pub connect_by: Vec<ConnectByKind>,
485 /// GROUP BY
486 pub group_by: GroupByExpr,
487 /// CLUSTER BY (Hive)
488 pub cluster_by: Vec<Expr>,
489 /// DISTRIBUTE BY (Hive)
490 pub distribute_by: Vec<Expr>,
491 /// SORT BY (Hive)
492 pub sort_by: Vec<OrderByExpr>,
493 /// HAVING
494 pub having: Option<Expr>,
495 /// WINDOW AS
496 pub named_window: Vec<NamedWindowDefinition>,
497 /// QUALIFY (Snowflake)
498 pub qualify: Option<Expr>,
499 /// The positioning of QUALIFY and WINDOW clauses differ between dialects.
500 /// e.g. BigQuery requires that WINDOW comes after QUALIFY, while DUCKDB accepts
501 /// WINDOW before QUALIFY.
502 /// We accept either positioning and flag the accepted variant.
503 pub window_before_qualify: bool,
504 /// BigQuery syntax: `SELECT AS VALUE | SELECT AS STRUCT`
505 pub value_table_mode: Option<ValueTableMode>,
506 /// Was this a FROM-first query?
507 pub flavor: SelectFlavor,
508}
509
510impl fmt::Display for Select {
511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512 match self.flavor {
513 SelectFlavor::Standard => {
514 write!(f, "SELECT")?;
515 }
516 SelectFlavor::FromFirst => {
517 write!(f, "FROM {} SELECT", display_comma_separated(&self.from))?;
518 }
519 SelectFlavor::FromFirstNoSelect => {
520 write!(f, "FROM {}", display_comma_separated(&self.from))?;
521 }
522 }
523
524 if let Some(hint) = self.optimizer_hint.as_ref() {
525 f.write_str(" ")?;
526 hint.fmt(f)?;
527 }
528
529 if let Some(value_table_mode) = self.value_table_mode {
530 f.write_str(" ")?;
531 value_table_mode.fmt(f)?;
532 }
533
534 if let Some(ref top) = self.top {
535 if self.top_before_distinct {
536 f.write_str(" ")?;
537 top.fmt(f)?;
538 }
539 }
540 if let Some(ref distinct) = self.distinct {
541 f.write_str(" ")?;
542 distinct.fmt(f)?;
543 }
544 if let Some(ref top) = self.top {
545 if !self.top_before_distinct {
546 f.write_str(" ")?;
547 top.fmt(f)?;
548 }
549 }
550
551 if let Some(ref select_modifiers) = self.select_modifiers {
552 select_modifiers.fmt(f)?;
553 }
554
555 if !self.projection.is_empty() {
556 indented_list(f, &self.projection)?;
557 }
558
559 if let Some(exclude) = &self.exclude {
560 write!(f, " {exclude}")?;
561 }
562
563 if let Some(ref into) = self.into {
564 f.write_str(" ")?;
565 into.fmt(f)?;
566 }
567
568 if self.flavor == SelectFlavor::Standard && !self.from.is_empty() {
569 SpaceOrNewline.fmt(f)?;
570 f.write_str("FROM")?;
571 indented_list(f, &self.from)?;
572 }
573 if !self.lateral_views.is_empty() {
574 for lv in &self.lateral_views {
575 lv.fmt(f)?;
576 }
577 }
578 if let Some(ref prewhere) = self.prewhere {
579 f.write_str(" PREWHERE ")?;
580 prewhere.fmt(f)?;
581 }
582 if let Some(ref selection) = self.selection {
583 SpaceOrNewline.fmt(f)?;
584 f.write_str("WHERE")?;
585 SpaceOrNewline.fmt(f)?;
586 Indent(selection).fmt(f)?;
587 }
588 for clause in &self.connect_by {
589 SpaceOrNewline.fmt(f)?;
590 clause.fmt(f)?;
591 }
592 match &self.group_by {
593 GroupByExpr::All(_) => {
594 SpaceOrNewline.fmt(f)?;
595 self.group_by.fmt(f)?;
596 }
597 GroupByExpr::Expressions(exprs, _) => {
598 if !exprs.is_empty() {
599 SpaceOrNewline.fmt(f)?;
600 self.group_by.fmt(f)?;
601 }
602 }
603 }
604 if !self.cluster_by.is_empty() {
605 SpaceOrNewline.fmt(f)?;
606 f.write_str("CLUSTER BY")?;
607 SpaceOrNewline.fmt(f)?;
608 Indent(display_comma_separated(&self.cluster_by)).fmt(f)?;
609 }
610 if !self.distribute_by.is_empty() {
611 SpaceOrNewline.fmt(f)?;
612 f.write_str("DISTRIBUTE BY")?;
613 SpaceOrNewline.fmt(f)?;
614 display_comma_separated(&self.distribute_by).fmt(f)?;
615 }
616 if !self.sort_by.is_empty() {
617 SpaceOrNewline.fmt(f)?;
618 f.write_str("SORT BY")?;
619 SpaceOrNewline.fmt(f)?;
620 Indent(display_comma_separated(&self.sort_by)).fmt(f)?;
621 }
622 if let Some(ref having) = self.having {
623 SpaceOrNewline.fmt(f)?;
624 f.write_str("HAVING")?;
625 SpaceOrNewline.fmt(f)?;
626 Indent(having).fmt(f)?;
627 }
628 if self.window_before_qualify {
629 if !self.named_window.is_empty() {
630 SpaceOrNewline.fmt(f)?;
631 f.write_str("WINDOW")?;
632 SpaceOrNewline.fmt(f)?;
633 display_comma_separated(&self.named_window).fmt(f)?;
634 }
635 if let Some(ref qualify) = self.qualify {
636 SpaceOrNewline.fmt(f)?;
637 f.write_str("QUALIFY")?;
638 SpaceOrNewline.fmt(f)?;
639 qualify.fmt(f)?;
640 }
641 } else {
642 if let Some(ref qualify) = self.qualify {
643 SpaceOrNewline.fmt(f)?;
644 f.write_str("QUALIFY")?;
645 SpaceOrNewline.fmt(f)?;
646 qualify.fmt(f)?;
647 }
648 if !self.named_window.is_empty() {
649 SpaceOrNewline.fmt(f)?;
650 f.write_str("WINDOW")?;
651 SpaceOrNewline.fmt(f)?;
652 display_comma_separated(&self.named_window).fmt(f)?;
653 }
654 }
655 Ok(())
656 }
657}
658
659/// A hive LATERAL VIEW with potential column aliases
660#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
662#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
663pub struct LateralView {
664 /// LATERAL VIEW
665 pub lateral_view: Expr,
666 /// LATERAL VIEW table name
667 pub lateral_view_name: ObjectName,
668 /// LATERAL VIEW optional column aliases
669 pub lateral_col_alias: Vec<Ident>,
670 /// LATERAL VIEW OUTER
671 pub outer: bool,
672}
673
674impl fmt::Display for LateralView {
675 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676 write!(
677 f,
678 " LATERAL VIEW{outer} {} {}",
679 self.lateral_view,
680 self.lateral_view_name,
681 outer = if self.outer { " OUTER" } else { "" }
682 )?;
683 if !self.lateral_col_alias.is_empty() {
684 write!(
685 f,
686 " AS {}",
687 display_comma_separated(&self.lateral_col_alias)
688 )?;
689 }
690 Ok(())
691 }
692}
693
694/// An expression used in a named window declaration.
695///
696/// ```sql
697/// WINDOW mywindow AS [named_window_expr]
698/// ```
699#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
701#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
702pub enum NamedWindowExpr {
703 /// A direct reference to another named window definition.
704 /// [BigQuery]
705 ///
706 /// Example:
707 /// ```sql
708 /// WINDOW mywindow AS prev_window
709 /// ```
710 ///
711 /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/window-function-calls#ref_named_window
712 NamedWindow(Ident),
713 /// A window expression.
714 ///
715 /// Example:
716 /// ```sql
717 /// WINDOW mywindow AS (ORDER BY 1)
718 /// ```
719 WindowSpec(WindowSpec),
720}
721
722impl fmt::Display for NamedWindowExpr {
723 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
724 match self {
725 NamedWindowExpr::NamedWindow(named_window) => {
726 write!(f, "{named_window}")?;
727 }
728 NamedWindowExpr::WindowSpec(window_spec) => {
729 write!(f, "({window_spec})")?;
730 }
731 };
732 Ok(())
733 }
734}
735
736#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
738#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
739/// A named window definition: `<name> AS <window specification>`
740pub struct NamedWindowDefinition(pub Ident, pub NamedWindowExpr);
741
742impl fmt::Display for NamedWindowDefinition {
743 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744 write!(f, "{} AS {}", self.0, self.1)
745 }
746}
747
748#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
749#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
750#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
751/// A `WITH` clause, introducing common table expressions (CTEs).
752pub struct With {
753 /// Token for the `WITH` keyword
754 pub with_token: AttachedToken,
755 /// Whether the `WITH` is recursive (`WITH RECURSIVE`).
756 pub recursive: bool,
757 /// The list of CTEs declared by this `WITH` clause.
758 pub cte_tables: Vec<Cte>,
759}
760
761impl fmt::Display for With {
762 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
763 f.write_str("WITH ")?;
764 if self.recursive {
765 f.write_str("RECURSIVE ")?;
766 }
767 display_comma_separated(&self.cte_tables).fmt(f)?;
768 Ok(())
769 }
770}
771
772#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
773#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
774#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
775/// Indicates whether a CTE is materialized or not.
776pub enum CteAsMaterialized {
777 /// The `WITH` statement specifies `AS MATERIALIZED` behavior
778 Materialized,
779 /// The `WITH` statement specifies `AS NOT MATERIALIZED` behavior
780 NotMaterialized,
781}
782
783impl fmt::Display for CteAsMaterialized {
784 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
785 match *self {
786 CteAsMaterialized::Materialized => {
787 write!(f, "MATERIALIZED")?;
788 }
789 CteAsMaterialized::NotMaterialized => {
790 write!(f, "NOT MATERIALIZED")?;
791 }
792 };
793 Ok(())
794 }
795}
796
797/// A single CTE (used after `WITH`): `<alias> [(col1, col2, ...)] AS <materialized> ( <query> )`
798/// The names in the column list before `AS`, when specified, replace the names
799/// of the columns returned by the query. The parser does not validate that the
800/// number of columns in the query matches the number of columns in the query.
801#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
802#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
803#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
804pub struct Cte {
805 /// The CTE alias (name introduced before the `AS` keyword).
806 pub alias: TableAlias,
807 /// The query that defines the CTE body.
808 pub query: Box<Query>,
809 /// Optional `FROM` identifier for materialized CTEs.
810 pub from: Option<Ident>,
811 /// Optional `AS MATERIALIZED` / `AS NOT MATERIALIZED` hint.
812 pub materialized: Option<CteAsMaterialized>,
813 /// Token for the closing parenthesis of the CTE definition.
814 pub closing_paren_token: AttachedToken,
815}
816
817impl fmt::Display for Cte {
818 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
819 match self.materialized.as_ref() {
820 None => {
821 self.alias.fmt(f)?;
822 f.write_str(" AS (")?;
823 NewLine.fmt(f)?;
824 Indent(&self.query).fmt(f)?;
825 NewLine.fmt(f)?;
826 f.write_str(")")?;
827 }
828 Some(materialized) => {
829 self.alias.fmt(f)?;
830 f.write_str(" AS ")?;
831 materialized.fmt(f)?;
832 f.write_str(" (")?;
833 NewLine.fmt(f)?;
834 Indent(&self.query).fmt(f)?;
835 NewLine.fmt(f)?;
836 f.write_str(")")?;
837 }
838 };
839 if let Some(ref fr) = self.from {
840 write!(f, " FROM {fr}")?;
841 }
842 Ok(())
843 }
844}
845
846/// Represents an expression behind a wildcard expansion in a projection.
847/// `SELECT T.* FROM T;
848#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
849#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
850#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
851pub enum SelectItemQualifiedWildcardKind {
852 /// Expression is an object name.
853 /// e.g. `alias.*` or even `schema.table.*`
854 ObjectName(ObjectName),
855 /// Select star on an arbitrary expression.
856 /// e.g. `STRUCT<STRING>('foo').*`
857 Expr(Expr),
858}
859
860/// One item of the comma-separated list following `SELECT`
861#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
862#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
863#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
864pub enum SelectItem {
865 /// Any expression, not followed by `[ AS ] alias`
866 UnnamedExpr(Expr),
867 /// An expression, followed by `[ AS ] alias`
868 ExprWithAlias {
869 /// The expression being projected.
870 expr: Expr,
871 /// The alias for the expression.
872 alias: Ident,
873 },
874 /// An expression, followed by a wildcard expansion.
875 /// e.g. `alias.*`, `STRUCT<STRING>('foo').*`
876 QualifiedWildcard(SelectItemQualifiedWildcardKind, WildcardAdditionalOptions),
877 /// An unqualified `*`
878 Wildcard(WildcardAdditionalOptions),
879}
880
881impl fmt::Display for SelectItemQualifiedWildcardKind {
882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883 match &self {
884 SelectItemQualifiedWildcardKind::ObjectName(object_name) => {
885 write!(f, "{object_name}.*")
886 }
887 SelectItemQualifiedWildcardKind::Expr(expr) => write!(f, "{expr}.*"),
888 }
889 }
890}
891
892/// Single aliased identifier
893///
894/// # Syntax
895/// ```plaintext
896/// <ident> AS <alias>
897/// ```
898#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
899#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
900#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
901pub struct IdentWithAlias {
902 /// The identifier being aliased.
903 pub ident: Ident,
904 /// The alias to apply to `ident`.
905 pub alias: Ident,
906}
907
908impl fmt::Display for IdentWithAlias {
909 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
910 write!(f, "{} AS {}", self.ident, self.alias)
911 }
912}
913
914/// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`.
915#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
916#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
917#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
918pub struct WildcardAdditionalOptions {
919 /// The wildcard token `*`
920 pub wildcard_token: AttachedToken,
921 /// `[ILIKE...]`.
922 /// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
923 pub opt_ilike: Option<IlikeSelectItem>,
924 /// `[EXCLUDE...]`.
925 pub opt_exclude: Option<ExcludeSelectItem>,
926 /// `[EXCEPT...]`.
927 /// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
928 pub opt_except: Option<ExceptSelectItem>,
929 /// `[REPLACE]`
930 /// BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace>
931 /// Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#replace>
932 /// Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
933 pub opt_replace: Option<ReplaceSelectItem>,
934 /// `[RENAME ...]`.
935 pub opt_rename: Option<RenameSelectItem>,
936}
937
938impl Default for WildcardAdditionalOptions {
939 fn default() -> Self {
940 Self {
941 wildcard_token: TokenWithSpan::wrap(Token::Mul).into(),
942 opt_ilike: None,
943 opt_exclude: None,
944 opt_except: None,
945 opt_replace: None,
946 opt_rename: None,
947 }
948 }
949}
950
951impl fmt::Display for WildcardAdditionalOptions {
952 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953 if let Some(ilike) = &self.opt_ilike {
954 write!(f, " {ilike}")?;
955 }
956 if let Some(exclude) = &self.opt_exclude {
957 write!(f, " {exclude}")?;
958 }
959 if let Some(except) = &self.opt_except {
960 write!(f, " {except}")?;
961 }
962 if let Some(replace) = &self.opt_replace {
963 write!(f, " {replace}")?;
964 }
965 if let Some(rename) = &self.opt_rename {
966 write!(f, " {rename}")?;
967 }
968 Ok(())
969 }
970}
971
972/// Snowflake `ILIKE` information.
973///
974/// # Syntax
975/// ```plaintext
976/// ILIKE <value>
977/// ```
978#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
979#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
980#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
981pub struct IlikeSelectItem {
982 /// The pattern expression used with `ILIKE`.
983 pub pattern: String,
984}
985
986impl fmt::Display for IlikeSelectItem {
987 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
988 write!(
989 f,
990 "ILIKE '{}'",
991 value::escape_single_quote_string(&self.pattern)
992 )?;
993 Ok(())
994 }
995}
996/// Snowflake `EXCLUDE` information.
997///
998/// # Syntax
999/// ```plaintext
1000/// <col_name>
1001/// | (<col_name>, <col_name>, ...)
1002/// ```
1003#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1004#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1005#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1006pub enum ExcludeSelectItem {
1007 /// Single column name without parenthesis.
1008 ///
1009 /// # Syntax
1010 /// ```plaintext
1011 /// <col_name>
1012 /// ```
1013 Single(Ident),
1014 /// Multiple column names inside parenthesis.
1015 /// # Syntax
1016 /// ```plaintext
1017 /// (<col_name>, <col_name>, ...)
1018 /// ```
1019 Multiple(Vec<Ident>),
1020}
1021
1022impl fmt::Display for ExcludeSelectItem {
1023 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1024 write!(f, "EXCLUDE")?;
1025 match self {
1026 Self::Single(column) => {
1027 write!(f, " {column}")?;
1028 }
1029 Self::Multiple(columns) => {
1030 write!(f, " ({})", display_comma_separated(columns))?;
1031 }
1032 }
1033 Ok(())
1034 }
1035}
1036
1037/// Snowflake `RENAME` information.
1038///
1039/// # Syntax
1040/// ```plaintext
1041/// <col_name> AS <col_alias>
1042/// | (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
1043/// ```
1044#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1045#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1046#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1047pub enum RenameSelectItem {
1048 /// Single column name with alias without parenthesis.
1049 ///
1050 /// # Syntax
1051 /// ```plaintext
1052 /// <col_name> AS <col_alias>
1053 /// ```
1054 Single(IdentWithAlias),
1055 /// Multiple column names with aliases inside parenthesis.
1056 /// # Syntax
1057 /// ```plaintext
1058 /// (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
1059 /// ```
1060 Multiple(Vec<IdentWithAlias>),
1061}
1062
1063impl fmt::Display for RenameSelectItem {
1064 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1065 write!(f, "RENAME")?;
1066 match self {
1067 Self::Single(column) => {
1068 write!(f, " {column}")?;
1069 }
1070 Self::Multiple(columns) => {
1071 write!(f, " ({})", display_comma_separated(columns))?;
1072 }
1073 }
1074 Ok(())
1075 }
1076}
1077
1078/// Bigquery `EXCEPT` information, with at least one column.
1079///
1080/// # Syntax
1081/// ```plaintext
1082/// EXCEPT (<col_name> [, ...])
1083/// ```
1084#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1085#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1086#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1087pub struct ExceptSelectItem {
1088 /// First guaranteed column.
1089 pub first_element: Ident,
1090 /// Additional columns. This list can be empty.
1091 pub additional_elements: Vec<Ident>,
1092}
1093
1094impl fmt::Display for ExceptSelectItem {
1095 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1096 write!(f, "EXCEPT ")?;
1097 if self.additional_elements.is_empty() {
1098 write!(f, "({})", self.first_element)?;
1099 } else {
1100 write!(
1101 f,
1102 "({}, {})",
1103 self.first_element,
1104 display_comma_separated(&self.additional_elements)
1105 )?;
1106 }
1107 Ok(())
1108 }
1109}
1110
1111/// Bigquery `REPLACE` information.
1112///
1113/// # Syntax
1114/// ```plaintext
1115/// REPLACE (<new_expr> [AS] <col_name>)
1116/// REPLACE (<col_name> [AS] <col_alias>, <col_name> [AS] <col_alias>, ...)
1117/// ```
1118#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1120#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1121pub struct ReplaceSelectItem {
1122 /// List of replacement elements contained in the `REPLACE(...)` clause.
1123 pub items: Vec<Box<ReplaceSelectElement>>,
1124}
1125
1126impl fmt::Display for ReplaceSelectItem {
1127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1128 write!(f, "REPLACE")?;
1129 write!(f, " ({})", display_comma_separated(&self.items))?;
1130 Ok(())
1131 }
1132}
1133
1134/// # Syntax
1135/// ```plaintext
1136/// <expr> [AS] <column_name>
1137/// ```
1138#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1140#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1141pub struct ReplaceSelectElement {
1142 /// Expression producing the replacement value.
1143 pub expr: Expr,
1144 /// The target column name for the replacement.
1145 pub column_name: Ident,
1146 /// Whether the `AS` keyword was present in the original syntax.
1147 pub as_keyword: bool,
1148}
1149
1150impl fmt::Display for ReplaceSelectElement {
1151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1152 if self.as_keyword {
1153 write!(f, "{} AS {}", self.expr, self.column_name)
1154 } else {
1155 write!(f, "{} {}", self.expr, self.column_name)
1156 }
1157 }
1158}
1159
1160impl fmt::Display for SelectItem {
1161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1162 use core::fmt::Write;
1163 match &self {
1164 SelectItem::UnnamedExpr(expr) => expr.fmt(f),
1165 SelectItem::ExprWithAlias { expr, alias } => {
1166 expr.fmt(f)?;
1167 f.write_str(" AS ")?;
1168 alias.fmt(f)
1169 }
1170 SelectItem::QualifiedWildcard(kind, additional_options) => {
1171 kind.fmt(f)?;
1172 additional_options.fmt(f)
1173 }
1174 SelectItem::Wildcard(additional_options) => {
1175 f.write_char('*')?;
1176 additional_options.fmt(f)
1177 }
1178 }
1179 }
1180}
1181
1182#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1183#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1184#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1185/// A left table followed by zero or more joins.
1186pub struct TableWithJoins {
1187 /// The starting table factor (left side) of the join chain.
1188 pub relation: TableFactor,
1189 /// The sequence of joins applied to the relation.
1190 pub joins: Vec<Join>,
1191}
1192
1193impl fmt::Display for TableWithJoins {
1194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1195 self.relation.fmt(f)?;
1196 for join in &self.joins {
1197 SpaceOrNewline.fmt(f)?;
1198 join.fmt(f)?;
1199 }
1200 Ok(())
1201 }
1202}
1203
1204/// Joins a table to itself to process hierarchical data in the table.
1205///
1206/// See <https://docs.snowflake.com/en/sql-reference/constructs/connect-by>.
1207/// See <https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html>
1208#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1209#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1210#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1211pub enum ConnectByKind {
1212 /// CONNECT BY
1213 ConnectBy {
1214 /// the `CONNECT` token
1215 connect_token: AttachedToken,
1216
1217 /// [CONNECT BY] NOCYCLE
1218 ///
1219 /// Optional on [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E__GUID-5377971A-F518-47E4-8781-F06FEB3EF993)
1220 nocycle: bool,
1221
1222 /// join conditions denoting the hierarchical relationship
1223 relationships: Vec<Expr>,
1224 },
1225
1226 /// START WITH
1227 ///
1228 /// Optional on [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E)
1229 /// when comming _after_ the `CONNECT BY`.
1230 StartWith {
1231 /// the `START` token
1232 start_token: AttachedToken,
1233
1234 /// condition selecting the root rows of the hierarchy
1235 condition: Box<Expr>,
1236 },
1237}
1238
1239impl fmt::Display for ConnectByKind {
1240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1241 match self {
1242 ConnectByKind::ConnectBy {
1243 connect_token: _,
1244 nocycle,
1245 relationships,
1246 } => {
1247 write!(
1248 f,
1249 "CONNECT BY {nocycle}{relationships}",
1250 nocycle = if *nocycle { "NOCYCLE " } else { "" },
1251 relationships = display_comma_separated(relationships)
1252 )
1253 }
1254 ConnectByKind::StartWith {
1255 start_token: _,
1256 condition,
1257 } => {
1258 write!(f, "START WITH {condition}")
1259 }
1260 }
1261 }
1262}
1263
1264#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1265#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1266#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1267/// A single setting key-value pair.
1268pub struct Setting {
1269 /// Setting name/key.
1270 pub key: Ident,
1271 /// The value expression assigned to the setting.
1272 pub value: Expr,
1273}
1274
1275impl fmt::Display for Setting {
1276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1277 write!(f, "{} = {}", self.key, self.value)
1278 }
1279}
1280
1281/// An expression optionally followed by an alias.
1282///
1283/// Example:
1284/// ```sql
1285/// 42 AS myint
1286/// ```
1287#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1288#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1289#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1290pub struct ExprWithAlias {
1291 /// The expression.
1292 pub expr: Expr,
1293 /// Optional alias for the expression.
1294 pub alias: Option<Ident>,
1295}
1296
1297impl fmt::Display for ExprWithAlias {
1298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1299 let ExprWithAlias { expr, alias } = self;
1300 write!(f, "{expr}")?;
1301 if let Some(alias) = alias {
1302 write!(f, " AS {alias}")?;
1303 }
1304 Ok(())
1305 }
1306}
1307
1308/// An expression optionally followed by an alias and order by options.
1309///
1310/// Example:
1311/// ```sql
1312/// 42 AS myint ASC
1313/// ```
1314#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1316#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1317pub struct ExprWithAliasAndOrderBy {
1318 /// Expression with optional alias.
1319 pub expr: ExprWithAlias,
1320 /// Ordering options applied to the expression.
1321 pub order_by: OrderByOptions,
1322}
1323
1324impl fmt::Display for ExprWithAliasAndOrderBy {
1325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1326 write!(f, "{}{}", self.expr, self.order_by)
1327 }
1328}
1329
1330/// Arguments to a table-valued function
1331#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1332#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1333#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1334pub struct TableFunctionArgs {
1335 /// The list of arguments passed to the table-valued function.
1336 pub args: Vec<FunctionArg>,
1337 /// ClickHouse-specific `SETTINGS` clause.
1338 /// For example,
1339 /// `SELECT * FROM executable('generate_random.py', TabSeparated, 'id UInt32, random String', SETTINGS send_chunk_header = false, pool_size = 16)`
1340 /// [`executable` table function](https://clickhouse.com/docs/en/engines/table-functions/executable)
1341 pub settings: Option<Vec<Setting>>,
1342}
1343
1344#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1345#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1346#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1347/// Type of index hint (e.g., `USE`, `IGNORE`, `FORCE`).
1348pub enum TableIndexHintType {
1349 /// `USE` hint.
1350 Use,
1351 /// `IGNORE` hint.
1352 Ignore,
1353 /// `FORCE` hint.
1354 Force,
1355}
1356
1357impl fmt::Display for TableIndexHintType {
1358 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1359 f.write_str(match self {
1360 TableIndexHintType::Use => "USE",
1361 TableIndexHintType::Ignore => "IGNORE",
1362 TableIndexHintType::Force => "FORCE",
1363 })
1364 }
1365}
1366
1367#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1368#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1369#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1370/// The kind of index referenced by an index hint (e.g. `USE INDEX`).
1371pub enum TableIndexType {
1372 /// The `INDEX` kind.
1373 Index,
1374 /// The `KEY` kind.
1375 Key,
1376}
1377
1378impl fmt::Display for TableIndexType {
1379 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1380 f.write_str(match self {
1381 TableIndexType::Index => "INDEX",
1382 TableIndexType::Key => "KEY",
1383 })
1384 }
1385}
1386
1387#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1388#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1389#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1390/// Which clause the table index hint applies to.
1391pub enum TableIndexHintForClause {
1392 /// Apply the hint to JOIN clauses.
1393 Join,
1394 /// Apply the hint to `ORDER BY` clauses.
1395 OrderBy,
1396 /// Apply the hint to `GROUP BY` clauses.
1397 GroupBy,
1398}
1399
1400impl fmt::Display for TableIndexHintForClause {
1401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1402 f.write_str(match self {
1403 TableIndexHintForClause::Join => "JOIN",
1404 TableIndexHintForClause::OrderBy => "ORDER BY",
1405 TableIndexHintForClause::GroupBy => "GROUP BY",
1406 })
1407 }
1408}
1409
1410#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1412#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1413/// MySQL-style index hints attached to a table (e.g., `USE INDEX(...)`).
1414pub struct TableIndexHints {
1415 /// Type of hint (e.g., `USE`, `FORCE`, or `IGNORE`).
1416 pub hint_type: TableIndexHintType,
1417 /// The index type (e.g., `INDEX`).
1418 pub index_type: TableIndexType,
1419 /// Optional `FOR` clause specifying the scope (JOIN / ORDER BY / GROUP BY).
1420 pub for_clause: Option<TableIndexHintForClause>,
1421 /// List of index names referred to by the hint.
1422 pub index_names: Vec<Ident>,
1423}
1424
1425impl fmt::Display for TableIndexHints {
1426 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1427 write!(f, "{} {} ", self.hint_type, self.index_type)?;
1428 if let Some(for_clause) = &self.for_clause {
1429 write!(f, "FOR {for_clause} ")?;
1430 }
1431 write!(f, "({})", display_comma_separated(&self.index_names))
1432 }
1433}
1434
1435/// A table name or a parenthesized subquery with an optional alias
1436#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1437#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1438#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1439#[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
1440pub enum TableFactor {
1441 /// A named table or relation, possibly with arguments, hints, or sampling.
1442 Table {
1443 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
1444 /// Table or relation name.
1445 name: ObjectName,
1446 /// Optional alias for the table (e.g. `table AS t`).
1447 alias: Option<TableAlias>,
1448 /// Arguments of a table-valued function, as supported by Postgres
1449 /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
1450 /// will also be parsed as `args`.
1451 ///
1452 /// This field's value is `Some(v)`, where `v` is a (possibly empty)
1453 /// vector of arguments, in the case of a table-valued function call,
1454 /// whereas it's `None` in the case of a regular table name.
1455 args: Option<TableFunctionArgs>,
1456 /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
1457 with_hints: Vec<Expr>,
1458 /// Optional version qualifier to facilitate table time-travel, as
1459 /// supported by BigQuery and MSSQL.
1460 version: Option<TableVersion>,
1461 // Optional table function modifier to generate the ordinality for column.
1462 /// For example, `SELECT * FROM generate_series(1, 10) WITH ORDINALITY AS t(a, b);`
1463 /// [WITH ORDINALITY](https://www.postgresql.org/docs/current/functions-srf.html), supported by Postgres.
1464 with_ordinality: bool,
1465 /// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL.
1466 partitions: Vec<Ident>,
1467 /// Optional PartiQL JsonPath: <https://partiql.org/dql/from.html>
1468 json_path: Option<JsonPath>,
1469 /// Optional table sample modifier
1470 /// See: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#sample-clause>
1471 sample: Option<TableSampleKind>,
1472 /// Optional index hints(mysql)
1473 /// See: <https://dev.mysql.com/doc/refman/8.4/en/index-hints.html>
1474 index_hints: Vec<TableIndexHints>,
1475 },
1476 /// A derived table (a parenthesized subquery), optionally `LATERAL`.
1477 Derived {
1478 /// Whether the derived table is LATERAL.
1479 lateral: bool,
1480 /// The subquery producing the derived table.
1481 subquery: Box<Query>,
1482 /// Optional alias for the derived table.
1483 alias: Option<TableAlias>,
1484 /// Optional table sample modifier
1485 sample: Option<TableSampleKind>,
1486 },
1487 /// `TABLE(<expr>)[ AS <alias> ]`
1488 TableFunction {
1489 /// Expression representing the table function call.
1490 expr: Expr,
1491 /// Optional alias for the table function result.
1492 alias: Option<TableAlias>,
1493 },
1494 /// `e.g. LATERAL FLATTEN(<args>)[ AS <alias> ]`
1495 Function {
1496 /// Whether the function is LATERAL.
1497 lateral: bool,
1498 /// Name of the table function.
1499 name: ObjectName,
1500 /// Arguments passed to the function.
1501 args: Vec<FunctionArg>,
1502 /// Optional alias for the result of the function.
1503 alias: Option<TableAlias>,
1504 },
1505 /// ```sql
1506 /// SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET;
1507 /// +---------+--------+
1508 /// | numbers | offset |
1509 /// +---------+--------+
1510 /// | 10 | 0 |
1511 /// | 20 | 1 |
1512 /// | 30 | 2 |
1513 /// +---------+--------+
1514 /// ```
1515 UNNEST {
1516 /// Optional alias for the UNNEST table (e.g. `UNNEST(...) AS t`).
1517 alias: Option<TableAlias>,
1518 /// Expressions producing the arrays to be unnested.
1519 array_exprs: Vec<Expr>,
1520 /// Whether `WITH OFFSET` was specified to include element offsets.
1521 with_offset: bool,
1522 /// Optional alias for the offset column when `WITH OFFSET` is used.
1523 with_offset_alias: Option<Ident>,
1524 /// Whether `WITH ORDINALITY` was specified to include ordinality.
1525 with_ordinality: bool,
1526 },
1527 /// The `JSON_TABLE` table-valued function.
1528 /// Part of the SQL standard, but implemented only by MySQL, Oracle, and DB2.
1529 ///
1530 /// <https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016#json_table>
1531 /// <https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table>
1532 ///
1533 /// ```sql
1534 /// SELECT * FROM JSON_TABLE(
1535 /// '[{"a": 1, "b": 2}, {"a": 3, "b": 4}]',
1536 /// '$[*]' COLUMNS(
1537 /// a INT PATH '$.a' DEFAULT '0' ON EMPTY,
1538 /// b INT PATH '$.b' NULL ON ERROR
1539 /// )
1540 /// ) AS jt;
1541 /// ````
1542 JsonTable {
1543 /// The JSON expression to be evaluated. It must evaluate to a json string
1544 json_expr: Expr,
1545 /// The path to the array or object to be iterated over.
1546 /// It must evaluate to a json array or object.
1547 json_path: Value,
1548 /// The columns to be extracted from each element of the array or object.
1549 /// Each column must have a name and a type.
1550 columns: Vec<JsonTableColumn>,
1551 /// The alias for the table.
1552 alias: Option<TableAlias>,
1553 },
1554 /// The MSSQL's `OPENJSON` table-valued function.
1555 ///
1556 /// ```sql
1557 /// OPENJSON( jsonExpression [ , path ] ) [ <with_clause> ]
1558 ///
1559 /// <with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
1560 /// ````
1561 ///
1562 /// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
1563 OpenJsonTable {
1564 /// The JSON expression to be evaluated. It must evaluate to a json string
1565 json_expr: Expr,
1566 /// The path to the array or object to be iterated over.
1567 /// It must evaluate to a json array or object.
1568 json_path: Option<Value>,
1569 /// The columns to be extracted from each element of the array or object.
1570 /// Each column must have a name and a type.
1571 columns: Vec<OpenJsonTableColumn>,
1572 /// The alias for the table.
1573 alias: Option<TableAlias>,
1574 },
1575 /// Represents a parenthesized table factor. The SQL spec only allows a
1576 /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
1577 /// possibly several times.
1578 ///
1579 /// The parser may also accept non-standard nesting of bare tables for some
1580 /// dialects, but the information about such nesting is stripped from AST.
1581 NestedJoin {
1582 /// The nested join expression contained in parentheses.
1583 table_with_joins: Box<TableWithJoins>,
1584 /// Optional alias for the nested join.
1585 alias: Option<TableAlias>,
1586 },
1587 /// Represents PIVOT operation on a table.
1588 /// For example `FROM monthly_sales PIVOT(sum(amount) FOR MONTH IN ('JAN', 'FEB'))`
1589 ///
1590 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)
1591 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/pivot)
1592 Pivot {
1593 /// The input table to pivot.
1594 table: Box<TableFactor>,
1595 /// Aggregate expressions used as pivot values (optionally aliased).
1596 aggregate_functions: Vec<ExprWithAlias>, // Function expression
1597 /// Columns producing the values to be pivoted.
1598 value_column: Vec<Expr>,
1599 /// Source of pivot values (e.g. list of literals or columns).
1600 value_source: PivotValueSource,
1601 /// Optional expression providing a default when a pivot produces NULL.
1602 default_on_null: Option<Expr>,
1603 /// Optional alias for the pivoted table.
1604 alias: Option<TableAlias>,
1605 },
1606 /// An UNPIVOT operation on a table.
1607 ///
1608 /// Syntax:
1609 /// ```sql
1610 /// table UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ] (value FOR name IN (column1, [ column2, ... ])) [ alias ]
1611 /// ```
1612 ///
1613 /// See <https://docs.snowflake.com/en/sql-reference/constructs/unpivot>.
1614 /// See <https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot>.
1615 Unpivot {
1616 /// The input table to unpivot.
1617 table: Box<TableFactor>,
1618 /// Expression producing the unpivoted value.
1619 value: Expr,
1620 /// Identifier used for the generated column name.
1621 name: Ident,
1622 /// Columns or expressions to unpivot, optionally aliased.
1623 columns: Vec<ExprWithAlias>,
1624 /// Whether to include or exclude NULLs during unpivot.
1625 null_inclusion: Option<NullInclusion>,
1626 /// Optional alias for the resulting table.
1627 alias: Option<TableAlias>,
1628 },
1629 /// A `MATCH_RECOGNIZE` operation on a table.
1630 ///
1631 /// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize>.
1632 MatchRecognize {
1633 /// The input table to apply `MATCH_RECOGNIZE` on.
1634 table: Box<TableFactor>,
1635 /// `PARTITION BY <expr> [, ... ]`
1636 partition_by: Vec<Expr>,
1637 /// `ORDER BY <expr> [, ... ]`
1638 order_by: Vec<OrderByExpr>,
1639 /// `MEASURES <expr> [AS] <alias> [, ... ]`
1640 measures: Vec<Measure>,
1641 /// `ONE ROW PER MATCH | ALL ROWS PER MATCH [ <option> ]`
1642 rows_per_match: Option<RowsPerMatch>,
1643 /// `AFTER MATCH SKIP <option>`
1644 after_match_skip: Option<AfterMatchSkip>,
1645 /// `PATTERN ( <pattern> )`
1646 pattern: MatchRecognizePattern,
1647 /// `DEFINE <symbol> AS <expr> [, ... ]`
1648 symbols: Vec<SymbolDefinition>,
1649 /// The alias for the table.
1650 alias: Option<TableAlias>,
1651 },
1652 /// The `XMLTABLE` table-valued function.
1653 /// Part of the SQL standard, supported by PostgreSQL, Oracle, and DB2.
1654 ///
1655 /// <https://www.postgresql.org/docs/15/functions-xml.html#FUNCTIONS-XML-PROCESSING>
1656 ///
1657 /// ```sql
1658 /// SELECT xmltable.*
1659 /// FROM xmldata,
1660 /// XMLTABLE('//ROWS/ROW'
1661 /// PASSING data
1662 /// COLUMNS id int PATH '@id',
1663 /// ordinality FOR ORDINALITY,
1664 /// "COUNTRY_NAME" text,
1665 /// country_id text PATH 'COUNTRY_ID',
1666 /// size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
1667 /// size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
1668 /// premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
1669 /// );
1670 /// ````
1671 XmlTable {
1672 /// Optional XMLNAMESPACES clause (empty if not present)
1673 namespaces: Vec<XmlNamespaceDefinition>,
1674 /// The row-generating XPath expression.
1675 row_expression: Expr,
1676 /// The PASSING clause specifying the document expression.
1677 passing: XmlPassingClause,
1678 /// The columns to be extracted from each generated row.
1679 columns: Vec<XmlTableColumn>,
1680 /// The alias for the table.
1681 alias: Option<TableAlias>,
1682 },
1683 /// Snowflake's SEMANTIC_VIEW function for semantic models.
1684 ///
1685 /// <https://docs.snowflake.com/en/sql-reference/constructs/semantic_view>
1686 ///
1687 /// ```sql
1688 /// SELECT * FROM SEMANTIC_VIEW(
1689 /// tpch_analysis
1690 /// DIMENSIONS customer.customer_market_segment
1691 /// METRICS orders.order_average_value
1692 /// );
1693 /// ```
1694 SemanticView {
1695 /// The name of the semantic model
1696 name: ObjectName,
1697 /// List of dimensions or expression referring to dimensions (e.g. DATE_PART('year', col))
1698 dimensions: Vec<Expr>,
1699 /// List of metrics (references to objects like orders.value, value, orders.*)
1700 metrics: Vec<Expr>,
1701 /// List of facts or expressions referring to facts or dimensions.
1702 facts: Vec<Expr>,
1703 /// WHERE clause for filtering
1704 where_clause: Option<Expr>,
1705 /// The alias for the table
1706 alias: Option<TableAlias>,
1707 },
1708}
1709
1710/// The table sample modifier options
1711#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1712#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1713#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1714pub enum TableSampleKind {
1715 /// Table sample located before the table alias option
1716 BeforeTableAlias(Box<TableSample>),
1717 /// Table sample located after the table alias option
1718 AfterTableAlias(Box<TableSample>),
1719}
1720
1721#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1722#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1723#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1724/// Represents a `TABLESAMPLE` clause and its options.
1725pub struct TableSample {
1726 /// Modifier (e.g. `SAMPLE` or `TABLESAMPLE`).
1727 pub modifier: TableSampleModifier,
1728 /// Optional sampling method name (e.g. `BERNOULLI`, `SYSTEM`).
1729 pub name: Option<TableSampleMethod>,
1730 /// Optional sampling quantity (value and optional unit).
1731 pub quantity: Option<TableSampleQuantity>,
1732 /// Optional seed clause.
1733 pub seed: Option<TableSampleSeed>,
1734 /// Optional bucket specification for `BUCKET ... OUT OF ...`-style sampling.
1735 pub bucket: Option<TableSampleBucket>,
1736 /// Optional offset expression for sampling.
1737 pub offset: Option<Expr>,
1738}
1739
1740#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1741#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1742#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1743/// Modifier specifying whether `SAMPLE` or `TABLESAMPLE` keyword was used.
1744pub enum TableSampleModifier {
1745 /// `SAMPLE` modifier.
1746 Sample,
1747 /// `TABLESAMPLE` modifier.
1748 TableSample,
1749}
1750
1751impl fmt::Display for TableSampleModifier {
1752 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1753 match self {
1754 TableSampleModifier::Sample => write!(f, "SAMPLE")?,
1755 TableSampleModifier::TableSample => write!(f, "TABLESAMPLE")?,
1756 }
1757 Ok(())
1758 }
1759}
1760
1761#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1762#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1763#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1764/// Quantity for a `TABLESAMPLE` clause (e.g. `10 PERCENT` or `(10)`).
1765pub struct TableSampleQuantity {
1766 /// Whether the quantity was wrapped in parentheses.
1767 pub parenthesized: bool,
1768 /// The numeric expression specifying the quantity.
1769 pub value: Expr,
1770 /// Optional unit (e.g. `PERCENT`, `ROWS`).
1771 pub unit: Option<TableSampleUnit>,
1772}
1773
1774impl fmt::Display for TableSampleQuantity {
1775 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1776 if self.parenthesized {
1777 write!(f, "(")?;
1778 }
1779 write!(f, "{}", self.value)?;
1780 if let Some(unit) = &self.unit {
1781 write!(f, " {unit}")?;
1782 }
1783 if self.parenthesized {
1784 write!(f, ")")?;
1785 }
1786 Ok(())
1787 }
1788}
1789
1790/// The table sample method names
1791#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1792#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1793#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1794/// Sampling method used by `TABLESAMPLE`.
1795pub enum TableSampleMethod {
1796 /// `ROW` sampling method.
1797 Row,
1798 /// `BERNOULLI` sampling method.
1799 Bernoulli,
1800 /// `SYSTEM` sampling method.
1801 System,
1802 /// `BLOCK` sampling method.
1803 Block,
1804}
1805
1806impl fmt::Display for TableSampleMethod {
1807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1808 match self {
1809 TableSampleMethod::Bernoulli => write!(f, "BERNOULLI"),
1810 TableSampleMethod::Row => write!(f, "ROW"),
1811 TableSampleMethod::System => write!(f, "SYSTEM"),
1812 TableSampleMethod::Block => write!(f, "BLOCK"),
1813 }
1814 }
1815}
1816
1817#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1818#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1819#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1820/// `SEED` or `REPEATABLE` clause used with sampling.
1821pub struct TableSampleSeed {
1822 /// Seed modifier (e.g. `REPEATABLE` or `SEED`).
1823 pub modifier: TableSampleSeedModifier,
1824 /// The seed value expression.
1825 pub value: Value,
1826}
1827
1828impl fmt::Display for TableSampleSeed {
1829 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1830 write!(f, "{} ({})", self.modifier, self.value)?;
1831 Ok(())
1832 }
1833}
1834
1835#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1836#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1837#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1838/// Modifier specifying how the sample seed is applied.
1839pub enum TableSampleSeedModifier {
1840 /// `REPEATABLE` modifier.
1841 Repeatable,
1842 /// `SEED` modifier.
1843 Seed,
1844}
1845
1846impl fmt::Display for TableSampleSeedModifier {
1847 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1848 match self {
1849 TableSampleSeedModifier::Repeatable => write!(f, "REPEATABLE"),
1850 TableSampleSeedModifier::Seed => write!(f, "SEED"),
1851 }
1852 }
1853}
1854
1855#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1856#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1857#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1858/// Unit used with a `TABLESAMPLE` quantity (rows or percent).
1859pub enum TableSampleUnit {
1860 /// `ROWS` unit.
1861 Rows,
1862 /// `PERCENT` unit.
1863 Percent,
1864}
1865
1866impl fmt::Display for TableSampleUnit {
1867 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1868 match self {
1869 TableSampleUnit::Percent => write!(f, "PERCENT"),
1870 TableSampleUnit::Rows => write!(f, "ROWS"),
1871 }
1872 }
1873}
1874
1875#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1876#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1877#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1878/// Bucket-based sampling clause: `BUCKET <bucket> OUT OF <total> [ON <expr>]`.
1879pub struct TableSampleBucket {
1880 /// The bucket index expression.
1881 pub bucket: Value,
1882 /// The total number of buckets expression.
1883 pub total: Value,
1884 /// Optional `ON <expr>` specification.
1885 pub on: Option<Expr>,
1886}
1887
1888impl fmt::Display for TableSampleBucket {
1889 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1890 write!(f, "BUCKET {} OUT OF {}", self.bucket, self.total)?;
1891 if let Some(on) = &self.on {
1892 write!(f, " ON {on}")?;
1893 }
1894 Ok(())
1895 }
1896}
1897impl fmt::Display for TableSample {
1898 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1899 write!(f, "{}", self.modifier)?;
1900 if let Some(name) = &self.name {
1901 write!(f, " {name}")?;
1902 }
1903 if let Some(quantity) = &self.quantity {
1904 write!(f, " {quantity}")?;
1905 }
1906 if let Some(seed) = &self.seed {
1907 write!(f, " {seed}")?;
1908 }
1909 if let Some(bucket) = &self.bucket {
1910 write!(f, " ({bucket})")?;
1911 }
1912 if let Some(offset) = &self.offset {
1913 write!(f, " OFFSET {offset}")?;
1914 }
1915 Ok(())
1916 }
1917}
1918
1919/// The source of values in a `PIVOT` operation.
1920#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1921#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1922#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1923pub enum PivotValueSource {
1924 /// Pivot on a static list of values.
1925 ///
1926 /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-a-specified-list-of-column-values-for-the-pivot-column>.
1927 List(Vec<ExprWithAlias>),
1928 /// Pivot on all distinct values of the pivot column.
1929 ///
1930 /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-all-distinct-column-values-automatically-with-dynamic-pivot>.
1931 Any(Vec<OrderByExpr>),
1932 /// Pivot on all values returned by a subquery.
1933 ///
1934 /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-column-values-using-a-subquery-with-dynamic-pivot>.
1935 Subquery(Box<Query>),
1936}
1937
1938impl fmt::Display for PivotValueSource {
1939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1940 match self {
1941 PivotValueSource::List(values) => write!(f, "{}", display_comma_separated(values)),
1942 PivotValueSource::Any(order_by) => {
1943 write!(f, "ANY")?;
1944 if !order_by.is_empty() {
1945 write!(f, " ORDER BY {}", display_comma_separated(order_by))?;
1946 }
1947 Ok(())
1948 }
1949 PivotValueSource::Subquery(query) => write!(f, "{query}"),
1950 }
1951 }
1952}
1953
1954/// An item in the `MEASURES` subclause of a `MATCH_RECOGNIZE` operation.
1955///
1956/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#measures-specifying-additional-output-columns>.
1957#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1958#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1959#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1960/// An item in the `MEASURES` clause of `MATCH_RECOGNIZE`.
1961pub struct Measure {
1962 /// Expression producing the measure value.
1963 pub expr: Expr,
1964 /// Alias for the measure column.
1965 pub alias: Ident,
1966}
1967
1968impl fmt::Display for Measure {
1969 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1970 write!(f, "{} AS {}", self.expr, self.alias)
1971 }
1972}
1973
1974/// The rows per match option in a `MATCH_RECOGNIZE` operation.
1975///
1976/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#row-s-per-match-specifying-the-rows-to-return>.
1977#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1978#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1979#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1980pub enum RowsPerMatch {
1981 /// `ONE ROW PER MATCH`
1982 OneRow,
1983 /// `ALL ROWS PER MATCH <mode>`
1984 AllRows(Option<EmptyMatchesMode>),
1985}
1986
1987impl fmt::Display for RowsPerMatch {
1988 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1989 match self {
1990 RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
1991 RowsPerMatch::AllRows(mode) => {
1992 write!(f, "ALL ROWS PER MATCH")?;
1993 if let Some(mode) = mode {
1994 write!(f, " {mode}")?;
1995 }
1996 Ok(())
1997 }
1998 }
1999 }
2000}
2001
2002/// The after match skip option in a `MATCH_RECOGNIZE` operation.
2003///
2004/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#after-match-skip-specifying-where-to-continue-after-a-match>.
2005#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2006#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2007#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2008pub enum AfterMatchSkip {
2009 /// `PAST LAST ROW`
2010 PastLastRow,
2011 /// `TO NEXT ROW`
2012 ToNextRow,
2013 /// `TO FIRST <symbol>`
2014 ToFirst(Ident),
2015 /// `TO LAST <symbol>`
2016 ToLast(Ident),
2017}
2018
2019impl fmt::Display for AfterMatchSkip {
2020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021 write!(f, "AFTER MATCH SKIP ")?;
2022 match self {
2023 AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
2024 AfterMatchSkip::ToNextRow => write!(f, " TO NEXT ROW"),
2025 AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {symbol}"),
2026 AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {symbol}"),
2027 }
2028 }
2029}
2030
2031#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2032#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2033#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2034/// The mode for handling empty matches in a `MATCH_RECOGNIZE` operation.
2035pub enum EmptyMatchesMode {
2036 /// `SHOW EMPTY MATCHES`
2037 Show,
2038 /// `OMIT EMPTY MATCHES`
2039 Omit,
2040 /// `WITH UNMATCHED ROWS`
2041 WithUnmatched,
2042}
2043
2044impl fmt::Display for EmptyMatchesMode {
2045 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2046 match self {
2047 EmptyMatchesMode::Show => write!(f, "SHOW EMPTY MATCHES"),
2048 EmptyMatchesMode::Omit => write!(f, "OMIT EMPTY MATCHES"),
2049 EmptyMatchesMode::WithUnmatched => write!(f, "WITH UNMATCHED ROWS"),
2050 }
2051 }
2052}
2053
2054/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2055///
2056/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#define-defining-symbols>.
2057#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2058#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2059#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2060/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2061pub struct SymbolDefinition {
2062 /// The symbol identifier.
2063 pub symbol: Ident,
2064 /// The expression defining the symbol.
2065 pub definition: Expr,
2066}
2067
2068impl fmt::Display for SymbolDefinition {
2069 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2070 write!(f, "{} AS {}", self.symbol, self.definition)
2071 }
2072}
2073
2074/// A symbol in a `MATCH_RECOGNIZE` pattern.
2075#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2076#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2077#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2078pub enum MatchRecognizeSymbol {
2079 /// A named symbol, e.g. `S1`.
2080 Named(Ident),
2081 /// A virtual symbol representing the start of the of partition (`^`).
2082 Start,
2083 /// A virtual symbol representing the end of the partition (`$`).
2084 End,
2085}
2086
2087impl fmt::Display for MatchRecognizeSymbol {
2088 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2089 match self {
2090 MatchRecognizeSymbol::Named(symbol) => write!(f, "{symbol}"),
2091 MatchRecognizeSymbol::Start => write!(f, "^"),
2092 MatchRecognizeSymbol::End => write!(f, "$"),
2093 }
2094 }
2095}
2096
2097/// The pattern in a `MATCH_RECOGNIZE` operation.
2098///
2099/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#pattern-specifying-the-pattern-to-match>.
2100#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2102#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2103pub enum MatchRecognizePattern {
2104 /// A named symbol such as `S1` or a virtual symbol such as `^`.
2105 Symbol(MatchRecognizeSymbol),
2106 /// {- symbol -}
2107 Exclude(MatchRecognizeSymbol),
2108 /// PERMUTE(symbol_1, ..., symbol_n)
2109 Permute(Vec<MatchRecognizeSymbol>),
2110 /// pattern_1 pattern_2 ... pattern_n
2111 Concat(Vec<MatchRecognizePattern>),
2112 /// ( pattern )
2113 Group(Box<MatchRecognizePattern>),
2114 /// pattern_1 | pattern_2 | ... | pattern_n
2115 Alternation(Vec<MatchRecognizePattern>),
2116 /// e.g. pattern*
2117 Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier),
2118}
2119
2120impl fmt::Display for MatchRecognizePattern {
2121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2122 use MatchRecognizePattern::*;
2123 match self {
2124 Symbol(symbol) => write!(f, "{symbol}"),
2125 Exclude(symbol) => write!(f, "{{- {symbol} -}}"),
2126 Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
2127 Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
2128 Group(pattern) => write!(f, "( {pattern} )"),
2129 Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
2130 Repetition(pattern, op) => write!(f, "{pattern}{op}"),
2131 }
2132 }
2133}
2134
2135/// Determines the minimum and maximum allowed occurrences of a pattern in a
2136/// `MATCH_RECOGNIZE` operation.
2137#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2138#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2139#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2140pub enum RepetitionQuantifier {
2141 /// `*`
2142 ZeroOrMore,
2143 /// `+`
2144 OneOrMore,
2145 /// `?`
2146 AtMostOne,
2147 /// `{n}`
2148 Exactly(u32),
2149 /// `{n,}`
2150 AtLeast(u32),
2151 /// `{,n}`
2152 AtMost(u32),
2153 /// `{n,m}
2154 Range(u32, u32),
2155}
2156
2157impl fmt::Display for RepetitionQuantifier {
2158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2159 use RepetitionQuantifier::*;
2160 match self {
2161 ZeroOrMore => write!(f, "*"),
2162 OneOrMore => write!(f, "+"),
2163 AtMostOne => write!(f, "?"),
2164 Exactly(n) => write!(f, "{{{n}}}"),
2165 AtLeast(n) => write!(f, "{{{n},}}"),
2166 AtMost(n) => write!(f, "{{,{n}}}"),
2167 Range(n, m) => write!(f, "{{{n},{m}}}"),
2168 }
2169 }
2170}
2171
2172impl fmt::Display for TableFactor {
2173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2174 match self {
2175 TableFactor::Table {
2176 name,
2177 alias,
2178 args,
2179 with_hints,
2180 version,
2181 partitions,
2182 with_ordinality,
2183 json_path,
2184 sample,
2185 index_hints,
2186 } => {
2187 name.fmt(f)?;
2188 if let Some(json_path) = json_path {
2189 json_path.fmt(f)?;
2190 }
2191 if !partitions.is_empty() {
2192 write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
2193 }
2194 if let Some(args) = args {
2195 write!(f, "(")?;
2196 write!(f, "{}", display_comma_separated(&args.args))?;
2197 if let Some(ref settings) = args.settings {
2198 if !args.args.is_empty() {
2199 write!(f, ", ")?;
2200 }
2201 write!(f, "SETTINGS {}", display_comma_separated(settings))?;
2202 }
2203 write!(f, ")")?;
2204 }
2205 if *with_ordinality {
2206 write!(f, " WITH ORDINALITY")?;
2207 }
2208 if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
2209 write!(f, " {sample}")?;
2210 }
2211 if let Some(alias) = alias {
2212 write!(f, " {alias}")?;
2213 }
2214 if !index_hints.is_empty() {
2215 write!(f, " {}", display_separated(index_hints, " "))?;
2216 }
2217 if !with_hints.is_empty() {
2218 write!(f, " WITH ({})", display_comma_separated(with_hints))?;
2219 }
2220 if let Some(version) = version {
2221 write!(f, " {version}")?;
2222 }
2223 if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2224 write!(f, " {sample}")?;
2225 }
2226 Ok(())
2227 }
2228 TableFactor::Derived {
2229 lateral,
2230 subquery,
2231 alias,
2232 sample,
2233 } => {
2234 if *lateral {
2235 write!(f, "LATERAL ")?;
2236 }
2237 f.write_str("(")?;
2238 NewLine.fmt(f)?;
2239 Indent(subquery).fmt(f)?;
2240 NewLine.fmt(f)?;
2241 f.write_str(")")?;
2242 if let Some(alias) = alias {
2243 write!(f, " {alias}")?;
2244 }
2245 if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2246 write!(f, " {sample}")?;
2247 }
2248 Ok(())
2249 }
2250 TableFactor::Function {
2251 lateral,
2252 name,
2253 args,
2254 alias,
2255 } => {
2256 if *lateral {
2257 write!(f, "LATERAL ")?;
2258 }
2259 write!(f, "{name}")?;
2260 write!(f, "({})", display_comma_separated(args))?;
2261 if let Some(alias) = alias {
2262 write!(f, " {alias}")?;
2263 }
2264 Ok(())
2265 }
2266 TableFactor::TableFunction { expr, alias } => {
2267 write!(f, "TABLE({expr})")?;
2268 if let Some(alias) = alias {
2269 write!(f, " {alias}")?;
2270 }
2271 Ok(())
2272 }
2273 TableFactor::UNNEST {
2274 alias,
2275 array_exprs,
2276 with_offset,
2277 with_offset_alias,
2278 with_ordinality,
2279 } => {
2280 write!(f, "UNNEST({})", display_comma_separated(array_exprs))?;
2281
2282 if *with_ordinality {
2283 write!(f, " WITH ORDINALITY")?;
2284 }
2285
2286 if let Some(alias) = alias {
2287 write!(f, " {alias}")?;
2288 }
2289 if *with_offset {
2290 write!(f, " WITH OFFSET")?;
2291 }
2292 if let Some(alias) = with_offset_alias {
2293 write!(f, " {alias}")?;
2294 }
2295 Ok(())
2296 }
2297 TableFactor::JsonTable {
2298 json_expr,
2299 json_path,
2300 columns,
2301 alias,
2302 } => {
2303 write!(
2304 f,
2305 "JSON_TABLE({json_expr}, {json_path} COLUMNS({columns}))",
2306 columns = display_comma_separated(columns)
2307 )?;
2308 if let Some(alias) = alias {
2309 write!(f, " {alias}")?;
2310 }
2311 Ok(())
2312 }
2313 TableFactor::OpenJsonTable {
2314 json_expr,
2315 json_path,
2316 columns,
2317 alias,
2318 } => {
2319 write!(f, "OPENJSON({json_expr}")?;
2320 if let Some(json_path) = json_path {
2321 write!(f, ", {json_path}")?;
2322 }
2323 write!(f, ")")?;
2324 if !columns.is_empty() {
2325 write!(f, " WITH ({})", display_comma_separated(columns))?;
2326 }
2327 if let Some(alias) = alias {
2328 write!(f, " {alias}")?;
2329 }
2330 Ok(())
2331 }
2332 TableFactor::NestedJoin {
2333 table_with_joins,
2334 alias,
2335 } => {
2336 write!(f, "({table_with_joins})")?;
2337 if let Some(alias) = alias {
2338 write!(f, " {alias}")?;
2339 }
2340 Ok(())
2341 }
2342 TableFactor::Pivot {
2343 table,
2344 aggregate_functions,
2345 value_column,
2346 value_source,
2347 default_on_null,
2348 alias,
2349 } => {
2350 write!(
2351 f,
2352 "{table} PIVOT({} FOR ",
2353 display_comma_separated(aggregate_functions),
2354 )?;
2355 if value_column.len() == 1 {
2356 write!(f, "{}", value_column[0])?;
2357 } else {
2358 write!(f, "({})", display_comma_separated(value_column))?;
2359 }
2360 write!(f, " IN ({value_source})")?;
2361 if let Some(expr) = default_on_null {
2362 write!(f, " DEFAULT ON NULL ({expr})")?;
2363 }
2364 write!(f, ")")?;
2365 if let Some(alias) = alias {
2366 write!(f, " {alias}")?;
2367 }
2368 Ok(())
2369 }
2370 TableFactor::Unpivot {
2371 table,
2372 null_inclusion,
2373 value,
2374 name,
2375 columns,
2376 alias,
2377 } => {
2378 write!(f, "{table} UNPIVOT")?;
2379 if let Some(null_inclusion) = null_inclusion {
2380 write!(f, " {null_inclusion} ")?;
2381 }
2382 write!(
2383 f,
2384 "({} FOR {} IN ({}))",
2385 value,
2386 name,
2387 display_comma_separated(columns)
2388 )?;
2389 if let Some(alias) = alias {
2390 write!(f, " {alias}")?;
2391 }
2392 Ok(())
2393 }
2394 TableFactor::MatchRecognize {
2395 table,
2396 partition_by,
2397 order_by,
2398 measures,
2399 rows_per_match,
2400 after_match_skip,
2401 pattern,
2402 symbols,
2403 alias,
2404 } => {
2405 write!(f, "{table} MATCH_RECOGNIZE(")?;
2406 if !partition_by.is_empty() {
2407 write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
2408 }
2409 if !order_by.is_empty() {
2410 write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
2411 }
2412 if !measures.is_empty() {
2413 write!(f, "MEASURES {} ", display_comma_separated(measures))?;
2414 }
2415 if let Some(rows_per_match) = rows_per_match {
2416 write!(f, "{rows_per_match} ")?;
2417 }
2418 if let Some(after_match_skip) = after_match_skip {
2419 write!(f, "{after_match_skip} ")?;
2420 }
2421 write!(f, "PATTERN ({pattern}) ")?;
2422 write!(f, "DEFINE {})", display_comma_separated(symbols))?;
2423 if let Some(alias) = alias {
2424 write!(f, " {alias}")?;
2425 }
2426 Ok(())
2427 }
2428 TableFactor::XmlTable {
2429 row_expression,
2430 passing,
2431 columns,
2432 alias,
2433 namespaces,
2434 } => {
2435 write!(f, "XMLTABLE(")?;
2436 if !namespaces.is_empty() {
2437 write!(
2438 f,
2439 "XMLNAMESPACES({}), ",
2440 display_comma_separated(namespaces)
2441 )?;
2442 }
2443 write!(
2444 f,
2445 "{row_expression}{passing} COLUMNS {columns})",
2446 columns = display_comma_separated(columns)
2447 )?;
2448 if let Some(alias) = alias {
2449 write!(f, " {alias}")?;
2450 }
2451 Ok(())
2452 }
2453 TableFactor::SemanticView {
2454 name,
2455 dimensions,
2456 metrics,
2457 facts,
2458 where_clause,
2459 alias,
2460 } => {
2461 write!(f, "SEMANTIC_VIEW({name}")?;
2462
2463 if !dimensions.is_empty() {
2464 write!(f, " DIMENSIONS {}", display_comma_separated(dimensions))?;
2465 }
2466
2467 if !metrics.is_empty() {
2468 write!(f, " METRICS {}", display_comma_separated(metrics))?;
2469 }
2470
2471 if !facts.is_empty() {
2472 write!(f, " FACTS {}", display_comma_separated(facts))?;
2473 }
2474
2475 if let Some(where_clause) = where_clause {
2476 write!(f, " WHERE {where_clause}")?;
2477 }
2478
2479 write!(f, ")")?;
2480
2481 if let Some(alias) = alias {
2482 write!(f, " {alias}")?;
2483 }
2484
2485 Ok(())
2486 }
2487 }
2488 }
2489}
2490
2491#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2492#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2493#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2494/// An alias for a table reference, optionally including an explicit `AS` and column names.
2495pub struct TableAlias {
2496 /// Tells whether the alias was introduced with an explicit, preceding "AS"
2497 /// keyword, e.g. `AS name`. Typically, the keyword is preceding the name
2498 /// (e.g. `.. FROM table AS t ..`).
2499 pub explicit: bool,
2500 /// Alias identifier for the table.
2501 pub name: Ident,
2502 /// Optional column aliases declared in parentheses after the table alias.
2503 pub columns: Vec<TableAliasColumnDef>,
2504}
2505
2506impl fmt::Display for TableAlias {
2507 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2508 write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
2509 if !self.columns.is_empty() {
2510 write!(f, " ({})", display_comma_separated(&self.columns))?;
2511 }
2512 Ok(())
2513 }
2514}
2515
2516/// SQL column definition in a table expression alias.
2517/// Most of the time, the data type is not specified.
2518/// But some table-valued functions do require specifying the data type.
2519///
2520/// See <https://www.postgresql.org/docs/17/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS>
2521#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2522#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2523#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2524pub struct TableAliasColumnDef {
2525 /// Column name alias
2526 pub name: Ident,
2527 /// Some table-valued functions require specifying the data type in the alias.
2528 pub data_type: Option<DataType>,
2529}
2530
2531impl TableAliasColumnDef {
2532 /// Create a new table alias column definition with only a name and no type
2533 pub fn from_name<S: Into<String>>(name: S) -> Self {
2534 TableAliasColumnDef {
2535 name: Ident::new(name),
2536 data_type: None,
2537 }
2538 }
2539}
2540
2541impl fmt::Display for TableAliasColumnDef {
2542 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2543 write!(f, "{}", self.name)?;
2544 if let Some(ref data_type) = self.data_type {
2545 write!(f, " {data_type}")?;
2546 }
2547 Ok(())
2548 }
2549}
2550
2551#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2552#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2553#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2554/// Specifies a table version selection, e.g. `FOR SYSTEM_TIME AS OF` or `AT(...)`.
2555pub enum TableVersion {
2556 /// When the table version is defined using `FOR SYSTEM_TIME AS OF`.
2557 /// For example: `SELECT * FROM tbl FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)`
2558 ForSystemTimeAsOf(Expr),
2559 /// When the table version is defined using `TIMESTAMP AS OF`.
2560 /// Databricks supports this syntax.
2561 /// For example: `SELECT * FROM tbl TIMESTAMP AS OF CURRENT_TIMESTAMP() - INTERVAL 1 HOUR`
2562 TimestampAsOf(Expr),
2563 /// When the table version is defined using `VERSION AS OF`.
2564 /// Databricks supports this syntax.
2565 /// For example: `SELECT * FROM tbl VERSION AS OF 2`
2566 VersionAsOf(Expr),
2567 /// When the table version is defined using a function.
2568 /// For example: `SELECT * FROM tbl AT(TIMESTAMP => '2020-08-14 09:30:00')`
2569 Function(Expr),
2570}
2571
2572impl Display for TableVersion {
2573 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2574 match self {
2575 TableVersion::ForSystemTimeAsOf(e) => write!(f, "FOR SYSTEM_TIME AS OF {e}")?,
2576 TableVersion::TimestampAsOf(e) => write!(f, "TIMESTAMP AS OF {e}")?,
2577 TableVersion::VersionAsOf(e) => write!(f, "VERSION AS OF {e}")?,
2578 TableVersion::Function(func) => write!(f, "{func}")?,
2579 }
2580 Ok(())
2581 }
2582}
2583
2584#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2585#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2586#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2587/// A single `JOIN` clause including relation and join operator/options.
2588pub struct Join {
2589 /// The joined table factor (table reference or derived table).
2590 pub relation: TableFactor,
2591 /// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
2592 /// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
2593 pub global: bool,
2594 /// The join operator and its constraint (INNER/LEFT/RIGHT/CROSS/ASOF/etc.).
2595 pub join_operator: JoinOperator,
2596}
2597
2598impl fmt::Display for Join {
2599 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2600 fn prefix(constraint: &JoinConstraint) -> &'static str {
2601 match constraint {
2602 JoinConstraint::Natural => "NATURAL ",
2603 _ => "",
2604 }
2605 }
2606 fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
2607 struct Suffix<'a>(&'a JoinConstraint);
2608 impl fmt::Display for Suffix<'_> {
2609 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2610 match self.0 {
2611 JoinConstraint::On(expr) => write!(f, " ON {expr}"),
2612 JoinConstraint::Using(attrs) => {
2613 write!(f, " USING({})", display_comma_separated(attrs))
2614 }
2615 _ => Ok(()),
2616 }
2617 }
2618 }
2619 Suffix(constraint)
2620 }
2621 if self.global {
2622 write!(f, "GLOBAL ")?;
2623 }
2624
2625 match &self.join_operator {
2626 JoinOperator::Join(constraint) => f.write_fmt(format_args!(
2627 "{}JOIN {}{}",
2628 prefix(constraint),
2629 self.relation,
2630 suffix(constraint)
2631 )),
2632 JoinOperator::Inner(constraint) => f.write_fmt(format_args!(
2633 "{}INNER JOIN {}{}",
2634 prefix(constraint),
2635 self.relation,
2636 suffix(constraint)
2637 )),
2638 JoinOperator::Left(constraint) => f.write_fmt(format_args!(
2639 "{}LEFT JOIN {}{}",
2640 prefix(constraint),
2641 self.relation,
2642 suffix(constraint)
2643 )),
2644 JoinOperator::LeftOuter(constraint) => f.write_fmt(format_args!(
2645 "{}LEFT OUTER JOIN {}{}",
2646 prefix(constraint),
2647 self.relation,
2648 suffix(constraint)
2649 )),
2650 JoinOperator::Right(constraint) => f.write_fmt(format_args!(
2651 "{}RIGHT JOIN {}{}",
2652 prefix(constraint),
2653 self.relation,
2654 suffix(constraint)
2655 )),
2656 JoinOperator::RightOuter(constraint) => f.write_fmt(format_args!(
2657 "{}RIGHT OUTER JOIN {}{}",
2658 prefix(constraint),
2659 self.relation,
2660 suffix(constraint)
2661 )),
2662 JoinOperator::FullOuter(constraint) => f.write_fmt(format_args!(
2663 "{}FULL JOIN {}{}",
2664 prefix(constraint),
2665 self.relation,
2666 suffix(constraint)
2667 )),
2668 JoinOperator::CrossJoin(constraint) => f.write_fmt(format_args!(
2669 "CROSS JOIN {}{}",
2670 self.relation,
2671 suffix(constraint)
2672 )),
2673 JoinOperator::Semi(constraint) => f.write_fmt(format_args!(
2674 "{}SEMI JOIN {}{}",
2675 prefix(constraint),
2676 self.relation,
2677 suffix(constraint)
2678 )),
2679 JoinOperator::LeftSemi(constraint) => f.write_fmt(format_args!(
2680 "{}LEFT SEMI JOIN {}{}",
2681 prefix(constraint),
2682 self.relation,
2683 suffix(constraint)
2684 )),
2685 JoinOperator::RightSemi(constraint) => f.write_fmt(format_args!(
2686 "{}RIGHT SEMI JOIN {}{}",
2687 prefix(constraint),
2688 self.relation,
2689 suffix(constraint)
2690 )),
2691 JoinOperator::Anti(constraint) => f.write_fmt(format_args!(
2692 "{}ANTI JOIN {}{}",
2693 prefix(constraint),
2694 self.relation,
2695 suffix(constraint)
2696 )),
2697 JoinOperator::LeftAnti(constraint) => f.write_fmt(format_args!(
2698 "{}LEFT ANTI JOIN {}{}",
2699 prefix(constraint),
2700 self.relation,
2701 suffix(constraint)
2702 )),
2703 JoinOperator::RightAnti(constraint) => f.write_fmt(format_args!(
2704 "{}RIGHT ANTI JOIN {}{}",
2705 prefix(constraint),
2706 self.relation,
2707 suffix(constraint)
2708 )),
2709 JoinOperator::CrossApply => f.write_fmt(format_args!("CROSS APPLY {}", self.relation)),
2710 JoinOperator::OuterApply => f.write_fmt(format_args!("OUTER APPLY {}", self.relation)),
2711 JoinOperator::AsOf {
2712 match_condition,
2713 constraint,
2714 } => f.write_fmt(format_args!(
2715 "ASOF JOIN {} MATCH_CONDITION ({match_condition}){}",
2716 self.relation,
2717 suffix(constraint)
2718 )),
2719 JoinOperator::StraightJoin(constraint) => f.write_fmt(format_args!(
2720 "STRAIGHT_JOIN {}{}",
2721 self.relation,
2722 suffix(constraint)
2723 )),
2724 }
2725 }
2726}
2727
2728#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2729#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2730#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2731/// The operator used for joining two tables, e.g. `INNER`, `LEFT`, `CROSS`, `ASOF`, etc.
2732pub enum JoinOperator {
2733 /// Generic `JOIN` with an optional constraint.
2734 Join(JoinConstraint),
2735 /// `INNER JOIN` with an optional constraint.
2736 Inner(JoinConstraint),
2737 /// `LEFT JOIN` with an optional constraint.
2738 Left(JoinConstraint),
2739 /// `LEFT OUTER JOIN` with an optional constraint.
2740 LeftOuter(JoinConstraint),
2741 /// `RIGHT JOIN` with an optional constraint.
2742 Right(JoinConstraint),
2743 /// `RIGHT OUTER JOIN` with an optional constraint.
2744 RightOuter(JoinConstraint),
2745 /// `FULL OUTER JOIN` with an optional constraint.
2746 FullOuter(JoinConstraint),
2747 /// `CROSS JOIN` (constraint usage is non-standard).
2748 CrossJoin(JoinConstraint),
2749 /// `SEMI JOIN` (non-standard)
2750 Semi(JoinConstraint),
2751 /// `LEFT SEMI JOIN` (non-standard)
2752 LeftSemi(JoinConstraint),
2753 /// `RIGHT SEMI JOIN` (non-standard)
2754 RightSemi(JoinConstraint),
2755 /// `ANTI JOIN` (non-standard)
2756 Anti(JoinConstraint),
2757 /// `LEFT ANTI JOIN` (non-standard)
2758 LeftAnti(JoinConstraint),
2759 /// `RIGHT ANTI JOIN` (non-standard)
2760 RightAnti(JoinConstraint),
2761 /// `CROSS APPLY` (non-standard)
2762 CrossApply,
2763 /// `OUTER APPLY` (non-standard)
2764 OuterApply,
2765 /// `ASOF` joins are used for joining time-series tables whose timestamp columns do not match exactly.
2766 ///
2767 /// See <https://docs.snowflake.com/en/sql-reference/constructs/asof-join>.
2768 AsOf {
2769 /// Condition used to match records in the `ASOF` join.
2770 match_condition: Expr,
2771 /// Additional constraint applied to the `ASOF` join.
2772 constraint: JoinConstraint,
2773 },
2774 /// `STRAIGHT_JOIN` (MySQL non-standard behavior)
2775 ///
2776 /// See <https://dev.mysql.com/doc/refman/8.4/en/join.html>.
2777 StraightJoin(JoinConstraint),
2778}
2779
2780#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2781#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2782#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2783/// Represents how two tables are constrained in a join: `ON`, `USING`, `NATURAL`, or none.
2784pub enum JoinConstraint {
2785 /// `ON <expr>` join condition.
2786 On(Expr),
2787 /// `USING(...)` list of column names.
2788 Using(Vec<ObjectName>),
2789 /// `NATURAL` join (columns matched automatically).
2790 Natural,
2791 /// No constraint specified (e.g. `CROSS JOIN`).
2792 None,
2793}
2794
2795#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2796#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2797#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2798/// The kind of `ORDER BY` clause: either `ALL` with modifiers or a list of expressions.
2799pub enum OrderByKind {
2800 /// `GROUP BY ALL`/`ORDER BY ALL` syntax with optional modifiers.
2801 ///
2802 /// [DuckDB]: <https://duckdb.org/docs/sql/query_syntax/orderby>
2803 /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
2804 All(OrderByOptions),
2805
2806 /// A standard list of ordering expressions.
2807 Expressions(Vec<OrderByExpr>),
2808}
2809
2810#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2811#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2812#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2813/// Represents an `ORDER BY` clause with its kind and optional `INTERPOLATE`.
2814pub struct OrderBy {
2815 /// The kind of ordering (expressions or `ALL`).
2816 pub kind: OrderByKind,
2817
2818 /// Optional `INTERPOLATE` clause (ClickHouse extension).
2819 pub interpolate: Option<Interpolate>,
2820}
2821
2822impl fmt::Display for OrderBy {
2823 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2824 write!(f, "ORDER BY")?;
2825 match &self.kind {
2826 OrderByKind::Expressions(exprs) => {
2827 write!(f, " {}", display_comma_separated(exprs))?;
2828 }
2829 OrderByKind::All(all) => {
2830 write!(f, " ALL{all}")?;
2831 }
2832 }
2833
2834 if let Some(ref interpolate) = self.interpolate {
2835 match &interpolate.exprs {
2836 Some(exprs) => write!(f, " INTERPOLATE ({})", display_comma_separated(exprs))?,
2837 None => write!(f, " INTERPOLATE")?,
2838 }
2839 }
2840
2841 Ok(())
2842 }
2843}
2844
2845/// An `ORDER BY` expression
2846#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2847#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2848#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2849pub struct OrderByExpr {
2850 /// The expression to order by.
2851 pub expr: Expr,
2852 /// Ordering options such as `ASC`/`DESC` and `NULLS` behavior.
2853 pub options: OrderByOptions,
2854 /// Optional `WITH FILL` clause (ClickHouse extension) which specifies how to fill gaps.
2855 pub with_fill: Option<WithFill>,
2856}
2857
2858impl From<Ident> for OrderByExpr {
2859 fn from(ident: Ident) -> Self {
2860 OrderByExpr {
2861 expr: Expr::Identifier(ident),
2862 options: OrderByOptions::default(),
2863 with_fill: None,
2864 }
2865 }
2866}
2867
2868impl fmt::Display for OrderByExpr {
2869 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2870 write!(f, "{}{}", self.expr, self.options)?;
2871 if let Some(ref with_fill) = self.with_fill {
2872 write!(f, " {with_fill}")?
2873 }
2874 Ok(())
2875 }
2876}
2877
2878/// ClickHouse `WITH FILL` modifier for `ORDER BY` clause.
2879/// Supported by [ClickHouse syntax]
2880///
2881/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
2882#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2883#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2884#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2885/// `WITH FILL` options for ClickHouse `ORDER BY` expressions.
2886pub struct WithFill {
2887 /// Optional lower bound expression for the fill range (`FROM <expr>`).
2888 pub from: Option<Expr>,
2889 /// Optional upper bound expression for the fill range (`TO <expr>`).
2890 pub to: Option<Expr>,
2891 /// Optional step expression specifying interpolation step (`STEP <expr>`).
2892 pub step: Option<Expr>,
2893}
2894
2895impl fmt::Display for WithFill {
2896 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2897 write!(f, "WITH FILL")?;
2898 if let Some(ref from) = self.from {
2899 write!(f, " FROM {from}")?;
2900 }
2901 if let Some(ref to) = self.to {
2902 write!(f, " TO {to}")?;
2903 }
2904 if let Some(ref step) = self.step {
2905 write!(f, " STEP {step}")?;
2906 }
2907 Ok(())
2908 }
2909}
2910
2911/// ClickHouse `INTERPOLATE` clause for use in `ORDER BY` clause when using `WITH FILL` modifier.
2912/// Supported by [ClickHouse syntax]
2913///
2914/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
2915#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2916#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2917#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2918/// An expression used by `WITH FILL`/`INTERPOLATE` to specify interpolation for a column.
2919pub struct InterpolateExpr {
2920 /// The column to interpolate.
2921 pub column: Ident,
2922 /// Optional `AS <expr>` expression specifying how to compute interpolated values.
2923 pub expr: Option<Expr>,
2924}
2925
2926#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2927#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2928#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2929/// `INTERPOLATE` clause used with ClickHouse `WITH FILL` to compute missing values.
2930pub struct Interpolate {
2931 /// Optional list of interpolation expressions.
2932 pub exprs: Option<Vec<InterpolateExpr>>,
2933}
2934
2935impl fmt::Display for InterpolateExpr {
2936 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2937 write!(f, "{}", self.column)?;
2938 if let Some(ref expr) = self.expr {
2939 write!(f, " AS {expr}")?;
2940 }
2941 Ok(())
2942 }
2943}
2944
2945#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2946#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2947#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2948/// Options for an `ORDER BY` expression (ASC/DESC and NULLS FIRST/LAST).
2949pub struct OrderByOptions {
2950 /// Optional `ASC` (`Some(true)`) or `DESC` (`Some(false)`).
2951 pub asc: Option<bool>,
2952 /// Optional `NULLS FIRST` (`Some(true)`) or `NULLS LAST` (`Some(false)`).
2953 pub nulls_first: Option<bool>,
2954}
2955
2956impl fmt::Display for OrderByOptions {
2957 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2958 match self.asc {
2959 Some(true) => write!(f, " ASC")?,
2960 Some(false) => write!(f, " DESC")?,
2961 None => (),
2962 }
2963 match self.nulls_first {
2964 Some(true) => write!(f, " NULLS FIRST")?,
2965 Some(false) => write!(f, " NULLS LAST")?,
2966 None => (),
2967 }
2968 Ok(())
2969 }
2970}
2971
2972#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2973#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2974#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2975/// Represents the different syntactic forms of `LIMIT` clauses.
2976pub enum LimitClause {
2977 /// Standard SQL `LIMIT` syntax (optionally `BY` and `OFFSET`).
2978 ///
2979 /// `LIMIT <limit> [BY <expr>,<expr>,...] [OFFSET <offset>]`
2980 LimitOffset {
2981 /// `LIMIT { <N> | ALL }` expression.
2982 limit: Option<Expr>,
2983 /// Optional `OFFSET` expression with optional `ROW(S)` keyword.
2984 offset: Option<Offset>,
2985 /// Optional `BY { <expr>,... }` list used by some dialects (ClickHouse).
2986 limit_by: Vec<Expr>,
2987 },
2988 /// MySQL-specific syntax: `LIMIT <offset>, <limit>` (order reversed).
2989 OffsetCommaLimit {
2990 /// The offset expression.
2991 offset: Expr,
2992 /// The limit expression.
2993 limit: Expr,
2994 },
2995}
2996
2997impl fmt::Display for LimitClause {
2998 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2999 match self {
3000 LimitClause::LimitOffset {
3001 limit,
3002 limit_by,
3003 offset,
3004 } => {
3005 if let Some(ref limit) = limit {
3006 write!(f, " LIMIT {limit}")?;
3007 }
3008 if let Some(ref offset) = offset {
3009 write!(f, " {offset}")?;
3010 }
3011 if !limit_by.is_empty() {
3012 debug_assert!(limit.is_some());
3013 write!(f, " BY {}", display_separated(limit_by, ", "))?;
3014 }
3015 Ok(())
3016 }
3017 LimitClause::OffsetCommaLimit { offset, limit } => {
3018 write!(f, " LIMIT {offset}, {limit}")
3019 }
3020 }
3021 }
3022}
3023
3024#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3025#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3026#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3027/// `OFFSET` clause consisting of a value and a rows specifier.
3028pub struct Offset {
3029 /// The numeric expression following `OFFSET`.
3030 pub value: Expr,
3031 /// Whether the offset uses `ROW`/`ROWS` or omits it.
3032 pub rows: OffsetRows,
3033}
3034
3035impl fmt::Display for Offset {
3036 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3037 write!(f, "OFFSET {}{}", self.value, self.rows)
3038 }
3039}
3040
3041/// Stores the keyword after `OFFSET <number>`
3042#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3043#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3044#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3045pub enum OffsetRows {
3046 /// Omitting `ROW`/`ROWS` entirely (non-standard MySQL quirk).
3047 None,
3048 /// `ROW` keyword present.
3049 Row,
3050 /// `ROWS` keyword present.
3051 Rows,
3052}
3053
3054impl fmt::Display for OffsetRows {
3055 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3056 match self {
3057 OffsetRows::None => Ok(()),
3058 OffsetRows::Row => write!(f, " ROW"),
3059 OffsetRows::Rows => write!(f, " ROWS"),
3060 }
3061 }
3062}
3063
3064/// Pipe syntax, first introduced in Google BigQuery.
3065/// Example:
3066///
3067/// ```sql
3068/// FROM Produce
3069/// |> WHERE sales > 0
3070/// |> AGGREGATE SUM(sales) AS total_sales, COUNT(*) AS num_sales
3071/// GROUP BY item;
3072/// ```
3073///
3074/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pipe_syntax>
3075#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3076#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3077#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3078pub enum PipeOperator {
3079 /// Limits the number of rows to return in a query, with an optional OFFSET clause to skip over rows.
3080 ///
3081 /// Syntax: `|> LIMIT <n> [OFFSET <m>]`
3082 ///
3083 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#limit_pipe_operator>
3084 Limit {
3085 /// The expression specifying the number of rows to return.
3086 expr: Expr,
3087 /// Optional offset expression provided inline with `LIMIT`.
3088 offset: Option<Expr>,
3089 },
3090 /// Filters the results of the input table.
3091 ///
3092 /// Syntax: `|> WHERE <condition>`
3093 ///
3094 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#where_pipe_operator>
3095 Where {
3096 /// The filter expression.
3097 expr: Expr,
3098 },
3099 /// `ORDER BY <expr> [ASC|DESC], ...`
3100 OrderBy {
3101 /// The ordering expressions.
3102 exprs: Vec<OrderByExpr>,
3103 },
3104 /// Produces a new table with the listed columns, similar to the outermost SELECT clause in a table subquery in standard syntax.
3105 ///
3106 /// Syntax `|> SELECT <expr> [[AS] alias], ...`
3107 ///
3108 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#select_pipe_operator>
3109 Select {
3110 /// The select items to produce.
3111 exprs: Vec<SelectItem>,
3112 },
3113 /// Propagates the existing table and adds computed columns, similar to SELECT *, new_column in standard syntax.
3114 ///
3115 /// Syntax: `|> EXTEND <expr> [[AS] alias], ...`
3116 ///
3117 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#extend_pipe_operator>
3118 Extend {
3119 /// Expressions defining added columns.
3120 exprs: Vec<SelectItem>,
3121 },
3122 /// Replaces the value of a column in the current table, similar to SELECT * REPLACE (expression AS column) in standard syntax.
3123 ///
3124 /// Syntax: `|> SET <column> = <expression>, ...`
3125 ///
3126 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#set_pipe_operator>
3127 Set {
3128 /// Assignments to apply (`column = expr`).
3129 assignments: Vec<Assignment>,
3130 },
3131 /// Removes listed columns from the current table, similar to SELECT * EXCEPT (column) in standard syntax.
3132 ///
3133 /// Syntax: `|> DROP <column>, ...`
3134 ///
3135 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#drop_pipe_operator>
3136 Drop {
3137 /// Columns to drop.
3138 columns: Vec<Ident>,
3139 },
3140 /// Introduces a table alias for the input table, similar to applying the AS alias clause on a table subquery in standard syntax.
3141 ///
3142 /// Syntax: `|> AS <alias>`
3143 ///
3144 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#as_pipe_operator>
3145 As {
3146 /// Alias to assign to the input table.
3147 alias: Ident,
3148 },
3149 /// Performs aggregation on data across grouped rows or an entire table.
3150 ///
3151 /// Syntax: `|> AGGREGATE <agg_expr> [[AS] alias], ...`
3152 ///
3153 /// Syntax:
3154 /// ```norust
3155 /// |> AGGREGATE [<agg_expr> [[AS] alias], ...]
3156 /// GROUP BY <grouping_expr> [AS alias], ...
3157 /// ```
3158 ///
3159 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#aggregate_pipe_operator>
3160 Aggregate {
3161 /// Expressions computed for each row prior to grouping.
3162 full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
3163 /// Grouping expressions for aggregation.
3164 group_by_expr: Vec<ExprWithAliasAndOrderBy>,
3165 },
3166 /// Selects a random sample of rows from the input table.
3167 /// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
3168 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
3169 TableSample {
3170 /// Sampling clause describing the sample.
3171 sample: Box<TableSample>,
3172 },
3173 /// Renames columns in the input table.
3174 ///
3175 /// Syntax: `|> RENAME old_name AS new_name, ...`
3176 ///
3177 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#rename_pipe_operator>
3178 Rename {
3179 /// Mappings of old to new identifiers.
3180 mappings: Vec<IdentWithAlias>,
3181 },
3182 /// Combines the input table with one or more tables using UNION.
3183 ///
3184 /// Syntax: `|> UNION [ALL|DISTINCT] (<query>), (<query>), ...`
3185 ///
3186 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#union_pipe_operator>
3187 Union {
3188 /// Set quantifier (`ALL` or `DISTINCT`).
3189 set_quantifier: SetQuantifier,
3190 /// The queries to combine with `UNION`.
3191 queries: Vec<Query>,
3192 },
3193 /// Returns only the rows that are present in both the input table and the specified tables.
3194 ///
3195 /// Syntax: `|> INTERSECT [DISTINCT] (<query>), (<query>), ...`
3196 ///
3197 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#intersect_pipe_operator>
3198 Intersect {
3199 /// Set quantifier for the `INTERSECT` operator.
3200 set_quantifier: SetQuantifier,
3201 /// The queries to intersect.
3202 queries: Vec<Query>,
3203 },
3204 /// Returns only the rows that are present in the input table but not in the specified tables.
3205 ///
3206 /// Syntax: `|> EXCEPT DISTINCT (<query>), (<query>), ...`
3207 ///
3208 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#except_pipe_operator>
3209 Except {
3210 /// Set quantifier for the `EXCEPT` operator.
3211 set_quantifier: SetQuantifier,
3212 /// The queries to exclude from the input set.
3213 queries: Vec<Query>,
3214 },
3215 /// Calls a table function or procedure that returns a table.
3216 ///
3217 /// Syntax: `|> CALL function_name(args) [AS alias]`
3218 ///
3219 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#call_pipe_operator>
3220 Call {
3221 /// The function or procedure to call which returns a table.
3222 function: Function,
3223 /// Optional alias for the result table.
3224 alias: Option<Ident>,
3225 },
3226 /// Pivots data from rows to columns.
3227 ///
3228 /// Syntax: `|> PIVOT(aggregate_function(column) FOR pivot_column IN (value1, value2, ...)) [AS alias]`
3229 ///
3230 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pivot_pipe_operator>
3231 Pivot {
3232 /// Aggregate functions to compute during pivot.
3233 aggregate_functions: Vec<ExprWithAlias>,
3234 /// Column(s) that provide the pivot values.
3235 value_column: Vec<Ident>,
3236 /// The source of pivot values (literal list or subquery).
3237 value_source: PivotValueSource,
3238 /// Optional alias for the output.
3239 alias: Option<Ident>,
3240 },
3241 /// The `UNPIVOT` pipe operator transforms columns into rows.
3242 ///
3243 /// Syntax:
3244 /// ```sql
3245 /// |> UNPIVOT(value_column FOR name_column IN (column1, column2, ...)) [alias]
3246 /// ```
3247 ///
3248 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#unpivot_pipe_operator>
3249 Unpivot {
3250 /// Output column that will receive the unpivoted value.
3251 value_column: Ident,
3252 /// Column name holding the unpivoted column name.
3253 name_column: Ident,
3254 /// Columns to unpivot.
3255 unpivot_columns: Vec<Ident>,
3256 /// Optional alias for the unpivot result.
3257 alias: Option<Ident>,
3258 },
3259 /// Joins the input table with another table.
3260 ///
3261 /// Syntax: `|> [JOIN_TYPE] JOIN <table> [alias] ON <condition>` or `|> [JOIN_TYPE] JOIN <table> [alias] USING (<columns>)`
3262 ///
3263 /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#join_pipe_operator>
3264 Join(Join),
3265}
3266
3267impl fmt::Display for PipeOperator {
3268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3269 match self {
3270 PipeOperator::Select { exprs } => {
3271 write!(f, "SELECT {}", display_comma_separated(exprs.as_slice()))
3272 }
3273 PipeOperator::Extend { exprs } => {
3274 write!(f, "EXTEND {}", display_comma_separated(exprs.as_slice()))
3275 }
3276 PipeOperator::Set { assignments } => {
3277 write!(f, "SET {}", display_comma_separated(assignments.as_slice()))
3278 }
3279 PipeOperator::Drop { columns } => {
3280 write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
3281 }
3282 PipeOperator::As { alias } => {
3283 write!(f, "AS {alias}")
3284 }
3285 PipeOperator::Limit { expr, offset } => {
3286 write!(f, "LIMIT {expr}")?;
3287 if let Some(offset) = offset {
3288 write!(f, " OFFSET {offset}")?;
3289 }
3290 Ok(())
3291 }
3292 PipeOperator::Aggregate {
3293 full_table_exprs,
3294 group_by_expr,
3295 } => {
3296 write!(f, "AGGREGATE")?;
3297 if !full_table_exprs.is_empty() {
3298 write!(
3299 f,
3300 " {}",
3301 display_comma_separated(full_table_exprs.as_slice())
3302 )?;
3303 }
3304 if !group_by_expr.is_empty() {
3305 write!(f, " GROUP BY {}", display_comma_separated(group_by_expr))?;
3306 }
3307 Ok(())
3308 }
3309
3310 PipeOperator::Where { expr } => {
3311 write!(f, "WHERE {expr}")
3312 }
3313 PipeOperator::OrderBy { exprs } => {
3314 write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
3315 }
3316
3317 PipeOperator::TableSample { sample } => {
3318 write!(f, "{sample}")
3319 }
3320 PipeOperator::Rename { mappings } => {
3321 write!(f, "RENAME {}", display_comma_separated(mappings))
3322 }
3323 PipeOperator::Union {
3324 set_quantifier,
3325 queries,
3326 } => Self::fmt_set_operation(f, "UNION", set_quantifier, queries),
3327 PipeOperator::Intersect {
3328 set_quantifier,
3329 queries,
3330 } => Self::fmt_set_operation(f, "INTERSECT", set_quantifier, queries),
3331 PipeOperator::Except {
3332 set_quantifier,
3333 queries,
3334 } => Self::fmt_set_operation(f, "EXCEPT", set_quantifier, queries),
3335 PipeOperator::Call { function, alias } => {
3336 write!(f, "CALL {function}")?;
3337 Self::fmt_optional_alias(f, alias)
3338 }
3339 PipeOperator::Pivot {
3340 aggregate_functions,
3341 value_column,
3342 value_source,
3343 alias,
3344 } => {
3345 write!(
3346 f,
3347 "PIVOT({} FOR {} IN ({}))",
3348 display_comma_separated(aggregate_functions),
3349 Expr::CompoundIdentifier(value_column.to_vec()),
3350 value_source
3351 )?;
3352 Self::fmt_optional_alias(f, alias)
3353 }
3354 PipeOperator::Unpivot {
3355 value_column,
3356 name_column,
3357 unpivot_columns,
3358 alias,
3359 } => {
3360 write!(
3361 f,
3362 "UNPIVOT({} FOR {} IN ({}))",
3363 value_column,
3364 name_column,
3365 display_comma_separated(unpivot_columns)
3366 )?;
3367 Self::fmt_optional_alias(f, alias)
3368 }
3369 PipeOperator::Join(join) => write!(f, "{join}"),
3370 }
3371 }
3372}
3373
3374impl PipeOperator {
3375 /// Helper function to format optional alias for pipe operators
3376 fn fmt_optional_alias(f: &mut fmt::Formatter<'_>, alias: &Option<Ident>) -> fmt::Result {
3377 if let Some(alias) = alias {
3378 write!(f, " AS {alias}")?;
3379 }
3380 Ok(())
3381 }
3382
3383 /// Helper function to format set operations (UNION, INTERSECT, EXCEPT) with queries
3384 fn fmt_set_operation(
3385 f: &mut fmt::Formatter<'_>,
3386 operation: &str,
3387 set_quantifier: &SetQuantifier,
3388 queries: &[Query],
3389 ) -> fmt::Result {
3390 write!(f, "{operation}")?;
3391 match set_quantifier {
3392 SetQuantifier::None => {}
3393 _ => {
3394 write!(f, " {set_quantifier}")?;
3395 }
3396 }
3397 write!(f, " ")?;
3398 let parenthesized_queries: Vec<String> =
3399 queries.iter().map(|query| format!("({query})")).collect();
3400 write!(f, "{}", display_comma_separated(&parenthesized_queries))
3401 }
3402}
3403
3404#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3405#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3406#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3407/// `FETCH` clause options.
3408pub struct Fetch {
3409 /// `WITH TIES` option is present.
3410 pub with_ties: bool,
3411 /// `PERCENT` modifier is present.
3412 pub percent: bool,
3413 /// Optional quantity expression (e.g. `FETCH FIRST 10 ROWS`).
3414 pub quantity: Option<Expr>,
3415}
3416
3417impl fmt::Display for Fetch {
3418 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3419 let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
3420 if let Some(ref quantity) = self.quantity {
3421 let percent = if self.percent { " PERCENT" } else { "" };
3422 write!(f, "FETCH FIRST {quantity}{percent} ROWS {extension}")
3423 } else {
3424 write!(f, "FETCH FIRST ROWS {extension}")
3425 }
3426 }
3427}
3428
3429#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3430#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3431#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3432/// `FOR ...` locking clause.
3433pub struct LockClause {
3434 /// The kind of lock requested (e.g. `SHARE`, `UPDATE`).
3435 pub lock_type: LockType,
3436 /// Optional object name after `OF` (e.g. `FOR UPDATE OF t1`).
3437 pub of: Option<ObjectName>,
3438 /// Optional non-blocking behavior (`NOWAIT` / `SKIP LOCKED`).
3439 pub nonblock: Option<NonBlock>,
3440}
3441
3442impl fmt::Display for LockClause {
3443 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3444 write!(f, "FOR {}", &self.lock_type)?;
3445 if let Some(ref of) = self.of {
3446 write!(f, " OF {of}")?;
3447 }
3448 if let Some(ref nb) = self.nonblock {
3449 write!(f, " {nb}")?;
3450 }
3451 Ok(())
3452 }
3453}
3454
3455#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3456#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3457#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3458/// The lock type used in `FOR <lock>` clauses (e.g. `FOR SHARE`, `FOR UPDATE`).
3459pub enum LockType {
3460 /// `SHARE` lock (shared lock).
3461 Share,
3462 /// `UPDATE` lock (exclusive/update lock).
3463 Update,
3464}
3465
3466impl fmt::Display for LockType {
3467 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3468 let select_lock = match self {
3469 LockType::Share => "SHARE",
3470 LockType::Update => "UPDATE",
3471 };
3472 write!(f, "{select_lock}")
3473 }
3474}
3475
3476#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3478#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3479/// Non-blocking lock options for `FOR ...` clauses.
3480pub enum NonBlock {
3481 /// `NOWAIT` — do not wait for the lock.
3482 Nowait,
3483 /// `SKIP LOCKED` — skip rows that are locked.
3484 SkipLocked,
3485}
3486
3487impl fmt::Display for NonBlock {
3488 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3489 let nonblock = match self {
3490 NonBlock::Nowait => "NOWAIT",
3491 NonBlock::SkipLocked => "SKIP LOCKED",
3492 };
3493 write!(f, "{nonblock}")
3494 }
3495}
3496
3497#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3498#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3499#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3500/// `ALL`, `DISTINCT`, or `DISTINCT ON (...)` modifiers for `SELECT` lists.
3501pub enum Distinct {
3502 /// `ALL` (keep duplicate rows)
3503 ///
3504 /// Generally this is the default if omitted, but omission should be represented as
3505 /// `None::<Option<Distinct>>`
3506 All,
3507
3508 /// `DISTINCT` (remove duplicate rows)
3509 Distinct,
3510
3511 /// `DISTINCT ON (...)` (Postgres extension)
3512 On(Vec<Expr>),
3513}
3514
3515impl fmt::Display for Distinct {
3516 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3517 match self {
3518 Distinct::All => write!(f, "ALL"),
3519 Distinct::Distinct => write!(f, "DISTINCT"),
3520 Distinct::On(col_names) => {
3521 let col_names = display_comma_separated(col_names);
3522 write!(f, "DISTINCT ON ({col_names})")
3523 }
3524 }
3525 }
3526}
3527
3528#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3529#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3530#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3531/// MSSQL `TOP` clause options.
3532pub struct Top {
3533 /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
3534 /// MSSQL only.
3535 pub with_ties: bool,
3536 /// Apply `PERCENT` extension.
3537 pub percent: bool,
3538 /// The optional quantity (expression or constant) following `TOP`.
3539 pub quantity: Option<TopQuantity>,
3540}
3541
3542#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3543#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3544#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3545/// Quantity used in a `TOP` clause: either an expression or a constant.
3546pub enum TopQuantity {
3547 /// A parenthesized expression (MSSQL syntax: `TOP (expr)`).
3548 Expr(Expr),
3549 /// An unparenthesized integer constant: `TOP 10`.
3550 Constant(u64),
3551}
3552
3553impl fmt::Display for Top {
3554 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3555 let extension = if self.with_ties { " WITH TIES" } else { "" };
3556 if let Some(ref quantity) = self.quantity {
3557 let percent = if self.percent { " PERCENT" } else { "" };
3558 match quantity {
3559 TopQuantity::Expr(quantity) => write!(f, "TOP ({quantity}){percent}{extension}"),
3560 TopQuantity::Constant(quantity) => {
3561 write!(f, "TOP {quantity}{percent}{extension}")
3562 }
3563 }
3564 } else {
3565 write!(f, "TOP{extension}")
3566 }
3567 }
3568}
3569
3570#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3571#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3572#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3573/// An explicit `VALUES` clause and its rows.
3574pub struct Values {
3575 /// Was there an explicit `ROW` keyword (MySQL)?
3576 /// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
3577 pub explicit_row: bool,
3578 /// `true` if `VALUE` (singular) keyword was used instead of `VALUES`.
3579 /// <https://dev.mysql.com/doc/refman/9.2/en/insert.html>
3580 pub value_keyword: bool,
3581 /// The list of rows, each row is a list of expressions.
3582 pub rows: Vec<Vec<Expr>>,
3583}
3584
3585impl fmt::Display for Values {
3586 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3587 match self.value_keyword {
3588 true => f.write_str("VALUE")?,
3589 false => f.write_str("VALUES")?,
3590 };
3591 let prefix = if self.explicit_row { "ROW" } else { "" };
3592 let mut delim = "";
3593 for row in &self.rows {
3594 f.write_str(delim)?;
3595 delim = ",";
3596 SpaceOrNewline.fmt(f)?;
3597 Indent(format_args!("{prefix}({})", display_comma_separated(row))).fmt(f)?;
3598 }
3599 Ok(())
3600 }
3601}
3602
3603#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3604#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3605#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3606/// `SELECT INTO` clause options.
3607pub struct SelectInto {
3608 /// `TEMPORARY` modifier.
3609 pub temporary: bool,
3610 /// `UNLOGGED` modifier.
3611 pub unlogged: bool,
3612 /// `TABLE` keyword present.
3613 pub table: bool,
3614 /// Name of the target table.
3615 pub name: ObjectName,
3616}
3617
3618impl fmt::Display for SelectInto {
3619 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3620 let temporary = if self.temporary { " TEMPORARY" } else { "" };
3621 let unlogged = if self.unlogged { " UNLOGGED" } else { "" };
3622 let table = if self.table { " TABLE" } else { "" };
3623
3624 write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
3625 }
3626}
3627
3628/// ClickHouse supports GROUP BY WITH modifiers(includes ROLLUP|CUBE|TOTALS).
3629/// e.g. GROUP BY year WITH ROLLUP WITH TOTALS
3630///
3631/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3632#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3633#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3634#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3635/// Modifiers used with `GROUP BY` such as `WITH ROLLUP` or `WITH CUBE`.
3636pub enum GroupByWithModifier {
3637 /// `WITH ROLLUP` modifier.
3638 Rollup,
3639 /// `WITH CUBE` modifier.
3640 Cube,
3641 /// `WITH TOTALS` modifier (ClickHouse).
3642 Totals,
3643 /// Hive supports GROUPING SETS syntax, e.g. `GROUP BY GROUPING SETS(...)`.
3644 ///
3645 /// [Hive]: <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=30151323#EnhancedAggregation,Cube,GroupingandRollup-GROUPINGSETSclause>
3646 GroupingSets(Expr),
3647}
3648
3649impl fmt::Display for GroupByWithModifier {
3650 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3651 match self {
3652 GroupByWithModifier::Rollup => write!(f, "WITH ROLLUP"),
3653 GroupByWithModifier::Cube => write!(f, "WITH CUBE"),
3654 GroupByWithModifier::Totals => write!(f, "WITH TOTALS"),
3655 GroupByWithModifier::GroupingSets(expr) => {
3656 write!(f, "{expr}")
3657 }
3658 }
3659 }
3660}
3661
3662#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3663#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3664#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3665/// Represents the two syntactic forms that `GROUP BY` can take, including
3666/// `GROUP BY ALL` with optional modifiers and ordinary `GROUP BY <exprs>`.
3667pub enum GroupByExpr {
3668 /// ALL syntax of [Snowflake], [DuckDB] and [ClickHouse].
3669 ///
3670 /// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
3671 /// [DuckDB]: <https://duckdb.org/docs/sql/query_syntax/groupby.html>
3672 /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#group-by-all>
3673 ///
3674 /// ClickHouse also supports WITH modifiers after GROUP BY ALL and expressions.
3675 ///
3676 /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3677 All(Vec<GroupByWithModifier>),
3678 /// `GROUP BY <expressions>` with optional modifiers.
3679 Expressions(Vec<Expr>, Vec<GroupByWithModifier>),
3680}
3681
3682impl fmt::Display for GroupByExpr {
3683 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3684 match self {
3685 GroupByExpr::All(modifiers) => {
3686 write!(f, "GROUP BY ALL")?;
3687 if !modifiers.is_empty() {
3688 write!(f, " {}", display_separated(modifiers, " "))?;
3689 }
3690 Ok(())
3691 }
3692 GroupByExpr::Expressions(col_names, modifiers) => {
3693 f.write_str("GROUP BY")?;
3694 SpaceOrNewline.fmt(f)?;
3695 Indent(display_comma_separated(col_names)).fmt(f)?;
3696 if !modifiers.is_empty() {
3697 write!(f, " {}", display_separated(modifiers, " "))?;
3698 }
3699 Ok(())
3700 }
3701 }
3702 }
3703}
3704
3705/// `FORMAT` identifier or `FORMAT NULL` clause, specific to ClickHouse.
3706///
3707/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/format>
3708#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3709#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3710#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3711pub enum FormatClause {
3712 /// The format identifier.
3713 Identifier(Ident),
3714 /// `FORMAT NULL` clause.
3715 Null,
3716}
3717
3718impl fmt::Display for FormatClause {
3719 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3720 match self {
3721 FormatClause::Identifier(ident) => write!(f, "FORMAT {ident}"),
3722 FormatClause::Null => write!(f, "FORMAT NULL"),
3723 }
3724 }
3725}
3726
3727/// FORMAT identifier in input context, specific to ClickHouse.
3728///
3729/// [ClickHouse]: <https://clickhouse.com/docs/en/interfaces/formats>
3730#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3731#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3732#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3733pub struct InputFormatClause {
3734 /// The format identifier.
3735 pub ident: Ident,
3736 /// Optional format parameters.
3737 pub values: Vec<Expr>,
3738}
3739
3740impl fmt::Display for InputFormatClause {
3741 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3742 write!(f, "FORMAT {}", self.ident)?;
3743
3744 if !self.values.is_empty() {
3745 write!(f, " {}", display_comma_separated(self.values.as_slice()))?;
3746 }
3747
3748 Ok(())
3749 }
3750}
3751
3752/// `FOR XML` or `FOR JSON` clause (MSSQL): formats the output of a query as XML or JSON.
3753#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3754#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3755#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3756pub enum ForClause {
3757 /// `FOR BROWSE` clause.
3758 Browse,
3759 /// `FOR JSON ...` clause and its options.
3760 Json {
3761 /// JSON mode (`AUTO` or `PATH`).
3762 for_json: ForJson,
3763 /// Optional `ROOT('...')` parameter.
3764 root: Option<String>,
3765 /// `INCLUDE_NULL_VALUES` flag.
3766 include_null_values: bool,
3767 /// `WITHOUT_ARRAY_WRAPPER` flag.
3768 without_array_wrapper: bool,
3769 },
3770 /// `FOR XML ...` clause and its options.
3771 Xml {
3772 /// XML mode (`RAW`, `AUTO`, `EXPLICIT`, `PATH`).
3773 for_xml: ForXml,
3774 /// `ELEMENTS` flag.
3775 elements: bool,
3776 /// `BINARY BASE64` flag.
3777 binary_base64: bool,
3778 /// Optional `ROOT('...')` parameter.
3779 root: Option<String>,
3780 /// `TYPE` flag.
3781 r#type: bool,
3782 },
3783}
3784
3785impl fmt::Display for ForClause {
3786 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3787 match self {
3788 ForClause::Browse => write!(f, "FOR BROWSE"),
3789 ForClause::Json {
3790 for_json,
3791 root,
3792 include_null_values,
3793 without_array_wrapper,
3794 } => {
3795 write!(f, "FOR JSON ")?;
3796 write!(f, "{for_json}")?;
3797 if let Some(root) = root {
3798 write!(f, ", ROOT('{root}')")?;
3799 }
3800 if *include_null_values {
3801 write!(f, ", INCLUDE_NULL_VALUES")?;
3802 }
3803 if *without_array_wrapper {
3804 write!(f, ", WITHOUT_ARRAY_WRAPPER")?;
3805 }
3806 Ok(())
3807 }
3808 ForClause::Xml {
3809 for_xml,
3810 elements,
3811 binary_base64,
3812 root,
3813 r#type,
3814 } => {
3815 write!(f, "FOR XML ")?;
3816 write!(f, "{for_xml}")?;
3817 if *binary_base64 {
3818 write!(f, ", BINARY BASE64")?;
3819 }
3820 if *r#type {
3821 write!(f, ", TYPE")?;
3822 }
3823 if let Some(root) = root {
3824 write!(f, ", ROOT('{root}')")?;
3825 }
3826 if *elements {
3827 write!(f, ", ELEMENTS")?;
3828 }
3829 Ok(())
3830 }
3831 }
3832 }
3833}
3834
3835#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3836#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3837#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3838/// Modes for `FOR XML` clause.
3839pub enum ForXml {
3840 /// `RAW` mode with optional root name: `RAW('root')`.
3841 Raw(Option<String>),
3842 /// `AUTO` mode.
3843 Auto,
3844 /// `EXPLICIT` mode.
3845 Explicit,
3846 /// `PATH` mode with optional root: `PATH('root')`.
3847 Path(Option<String>),
3848}
3849
3850impl fmt::Display for ForXml {
3851 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3852 match self {
3853 ForXml::Raw(root) => {
3854 write!(f, "RAW")?;
3855 if let Some(root) = root {
3856 write!(f, "('{root}')")?;
3857 }
3858 Ok(())
3859 }
3860 ForXml::Auto => write!(f, "AUTO"),
3861 ForXml::Explicit => write!(f, "EXPLICIT"),
3862 ForXml::Path(root) => {
3863 write!(f, "PATH")?;
3864 if let Some(root) = root {
3865 write!(f, "('{root}')")?;
3866 }
3867 Ok(())
3868 }
3869 }
3870 }
3871}
3872
3873#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3874#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3875#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3876/// Modes for `FOR JSON` clause.
3877pub enum ForJson {
3878 /// `AUTO` mode.
3879 Auto,
3880 /// `PATH` mode.
3881 Path,
3882}
3883
3884impl fmt::Display for ForJson {
3885 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3886 match self {
3887 ForJson::Auto => write!(f, "AUTO"),
3888 ForJson::Path => write!(f, "PATH"),
3889 }
3890 }
3891}
3892
3893/// A single column definition in MySQL's `JSON_TABLE` table valued function.
3894///
3895/// See
3896/// - [MySQL's JSON_TABLE documentation](https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table)
3897/// - [Oracle's JSON_TABLE documentation](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/JSON_TABLE.html)
3898/// - [MariaDB's JSON_TABLE documentation](https://mariadb.com/kb/en/json_table/)
3899///
3900/// ```sql
3901/// SELECT *
3902/// FROM JSON_TABLE(
3903/// '["a", "b"]',
3904/// '$[*]' COLUMNS (
3905/// name FOR ORDINALITY,
3906/// value VARCHAR(20) PATH '$',
3907/// NESTED PATH '$[*]' COLUMNS (
3908/// value VARCHAR(20) PATH '$'
3909/// )
3910/// )
3911/// ) AS jt;
3912/// ```
3913#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3914#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3915#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3916pub enum JsonTableColumn {
3917 /// A named column with a JSON path
3918 Named(JsonTableNamedColumn),
3919 /// The FOR ORDINALITY column, which is a special column that returns the index of the current row in a JSON array.
3920 ForOrdinality(Ident),
3921 /// A set of nested columns, which extracts data from a nested JSON array.
3922 Nested(JsonTableNestedColumn),
3923}
3924
3925impl fmt::Display for JsonTableColumn {
3926 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3927 match self {
3928 JsonTableColumn::Named(json_table_named_column) => {
3929 write!(f, "{json_table_named_column}")
3930 }
3931 JsonTableColumn::ForOrdinality(ident) => write!(f, "{ident} FOR ORDINALITY"),
3932 JsonTableColumn::Nested(json_table_nested_column) => {
3933 write!(f, "{json_table_nested_column}")
3934 }
3935 }
3936 }
3937}
3938
3939/// A nested column in a JSON_TABLE column list
3940///
3941/// See <https://mariadb.com/kb/en/json_table/#nested-paths>
3942#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3943#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3944#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3945/// A nested column in a `JSON_TABLE` column list.
3946pub struct JsonTableNestedColumn {
3947 /// JSON path expression (must be a literal `Value`).
3948 pub path: Value,
3949 /// Columns extracted from the matched nested array.
3950 pub columns: Vec<JsonTableColumn>,
3951}
3952
3953impl fmt::Display for JsonTableNestedColumn {
3954 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3955 write!(
3956 f,
3957 "NESTED PATH {} COLUMNS ({})",
3958 self.path,
3959 display_comma_separated(&self.columns)
3960 )
3961 }
3962}
3963
3964/// A single column definition in MySQL's `JSON_TABLE` table valued function.
3965///
3966/// See <https://mariadb.com/kb/en/json_table/#path-columns>
3967///
3968/// ```sql
3969/// value VARCHAR(20) PATH '$'
3970/// ```
3971#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3972#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3973#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3974pub struct JsonTableNamedColumn {
3975 /// The name of the column to be extracted.
3976 pub name: Ident,
3977 /// The type of the column to be extracted.
3978 pub r#type: DataType,
3979 /// The path to the column to be extracted. Must be a literal string.
3980 pub path: Value,
3981 /// true if the column is a boolean set to true if the given path exists
3982 pub exists: bool,
3983 /// The empty handling clause of the column
3984 pub on_empty: Option<JsonTableColumnErrorHandling>,
3985 /// The error handling clause of the column
3986 pub on_error: Option<JsonTableColumnErrorHandling>,
3987}
3988
3989impl fmt::Display for JsonTableNamedColumn {
3990 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3991 write!(
3992 f,
3993 "{} {}{} PATH {}",
3994 self.name,
3995 self.r#type,
3996 if self.exists { " EXISTS" } else { "" },
3997 self.path
3998 )?;
3999 if let Some(on_empty) = &self.on_empty {
4000 write!(f, " {on_empty} ON EMPTY")?;
4001 }
4002 if let Some(on_error) = &self.on_error {
4003 write!(f, " {on_error} ON ERROR")?;
4004 }
4005 Ok(())
4006 }
4007}
4008
4009/// Stores the error handling clause of a `JSON_TABLE` table valued function:
4010/// {NULL | DEFAULT json_string | ERROR} ON {ERROR | EMPTY }
4011#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4012#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4013#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4014/// Error/empty-value handling for `JSON_TABLE` columns.
4015pub enum JsonTableColumnErrorHandling {
4016 /// `NULL` — return NULL when the path does not match.
4017 Null,
4018 /// `DEFAULT <value>` — use the provided `Value` as a default.
4019 Default(Value),
4020 /// `ERROR` — raise an error.
4021 Error,
4022}
4023
4024impl fmt::Display for JsonTableColumnErrorHandling {
4025 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4026 match self {
4027 JsonTableColumnErrorHandling::Null => write!(f, "NULL"),
4028 JsonTableColumnErrorHandling::Default(json_string) => {
4029 write!(f, "DEFAULT {json_string}")
4030 }
4031 JsonTableColumnErrorHandling::Error => write!(f, "ERROR"),
4032 }
4033 }
4034}
4035
4036/// A single column definition in MSSQL's `OPENJSON WITH` clause.
4037///
4038/// ```sql
4039/// colName type [ column_path ] [ AS JSON ]
4040/// ```
4041///
4042/// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
4043#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4044#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4045#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4046pub struct OpenJsonTableColumn {
4047 /// The name of the column to be extracted.
4048 pub name: Ident,
4049 /// The type of the column to be extracted.
4050 pub r#type: DataType,
4051 /// The path to the column to be extracted. Must be a literal string.
4052 pub path: Option<String>,
4053 /// The `AS JSON` option.
4054 pub as_json: bool,
4055}
4056
4057impl fmt::Display for OpenJsonTableColumn {
4058 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4059 write!(f, "{} {}", self.name, self.r#type)?;
4060 if let Some(path) = &self.path {
4061 write!(f, " '{}'", value::escape_single_quote_string(path))?;
4062 }
4063 if self.as_json {
4064 write!(f, " AS JSON")?;
4065 }
4066 Ok(())
4067 }
4068}
4069
4070/// BigQuery supports ValueTables which have 2 modes:
4071/// `SELECT [ALL | DISTINCT] AS STRUCT`
4072/// `SELECT [ALL | DISTINCT] AS VALUE`
4073///
4074/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#value_tables>
4075/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_list>
4076#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4077#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4078#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4079/// Mode of BigQuery value tables, e.g. `AS STRUCT` or `AS VALUE`.
4080pub enum ValueTableMode {
4081 /// `AS STRUCT`
4082 AsStruct,
4083 /// `AS VALUE`
4084 AsValue,
4085 /// `DISTINCT AS STRUCT`
4086 DistinctAsStruct,
4087 /// `DISTINCT AS VALUE`
4088 DistinctAsValue,
4089}
4090
4091impl fmt::Display for ValueTableMode {
4092 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4093 match self {
4094 ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
4095 ValueTableMode::AsValue => write!(f, "AS VALUE"),
4096 ValueTableMode::DistinctAsStruct => write!(f, "DISTINCT AS STRUCT"),
4097 ValueTableMode::DistinctAsValue => write!(f, "DISTINCT AS VALUE"),
4098 }
4099 }
4100}
4101
4102/// The `FROM` clause of an `UPDATE TABLE` statement
4103#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4105#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4106pub enum UpdateTableFromKind {
4107 /// Update Statement where the 'FROM' clause is before the 'SET' keyword (Supported by Snowflake)
4108 /// For Example: `UPDATE FROM t1 SET t1.name='aaa'`
4109 BeforeSet(Vec<TableWithJoins>),
4110 /// Update Statement where the 'FROM' clause is after the 'SET' keyword (Which is the standard way)
4111 /// For Example: `UPDATE SET t1.name='aaa' FROM t1`
4112 AfterSet(Vec<TableWithJoins>),
4113}
4114
4115/// Defines the options for an XmlTable column: Named or ForOrdinality
4116#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4117#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4118#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4119pub enum XmlTableColumnOption {
4120 /// A named column with a type, optional path, and default value.
4121 NamedInfo {
4122 /// The type of the column to be extracted.
4123 r#type: DataType,
4124 /// The path to the column to be extracted. If None, defaults to the column name.
4125 path: Option<Expr>,
4126 /// Default value if path does not match
4127 default: Option<Expr>,
4128 /// Whether the column is nullable (NULL=true, NOT NULL=false)
4129 nullable: bool,
4130 },
4131 /// The FOR ORDINALITY marker
4132 ForOrdinality,
4133}
4134
4135/// A single column definition in XMLTABLE
4136///
4137/// ```sql
4138/// COLUMNS
4139/// id int PATH '@id',
4140/// ordinality FOR ORDINALITY,
4141/// "COUNTRY_NAME" text,
4142/// country_id text PATH 'COUNTRY_ID',
4143/// size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
4144/// size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
4145/// premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
4146/// ```
4147#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4148#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4150pub struct XmlTableColumn {
4151 /// The name of the column.
4152 pub name: Ident,
4153 /// Column options: type/path/default or FOR ORDINALITY
4154 pub option: XmlTableColumnOption,
4155}
4156
4157impl fmt::Display for XmlTableColumn {
4158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4159 write!(f, "{}", self.name)?;
4160 match &self.option {
4161 XmlTableColumnOption::NamedInfo {
4162 r#type,
4163 path,
4164 default,
4165 nullable,
4166 } => {
4167 write!(f, " {type}")?;
4168 if let Some(p) = path {
4169 write!(f, " PATH {p}")?;
4170 }
4171 if let Some(d) = default {
4172 write!(f, " DEFAULT {d}")?;
4173 }
4174 if !*nullable {
4175 write!(f, " NOT NULL")?;
4176 }
4177 Ok(())
4178 }
4179 XmlTableColumnOption::ForOrdinality => {
4180 write!(f, " FOR ORDINALITY")
4181 }
4182 }
4183 }
4184}
4185
4186/// Argument passed in the XMLTABLE PASSING clause
4187#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4188#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4190/// Argument passed in the `XMLTABLE PASSING` clause.
4191pub struct XmlPassingArgument {
4192 /// Expression to pass to the XML table.
4193 pub expr: Expr,
4194 /// Optional alias for the argument.
4195 pub alias: Option<Ident>,
4196 /// `true` if `BY VALUE` is specified for the argument.
4197 pub by_value: bool,
4198}
4199
4200impl fmt::Display for XmlPassingArgument {
4201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4202 if self.by_value {
4203 write!(f, "BY VALUE ")?;
4204 }
4205 write!(f, "{}", self.expr)?;
4206 if let Some(alias) = &self.alias {
4207 write!(f, " AS {alias}")?;
4208 }
4209 Ok(())
4210 }
4211}
4212
4213/// The PASSING clause for XMLTABLE
4214#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4215#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4216#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4217/// The PASSING clause for `XMLTABLE`.
4218pub struct XmlPassingClause {
4219 /// The list of passed arguments.
4220 pub arguments: Vec<XmlPassingArgument>,
4221}
4222
4223impl fmt::Display for XmlPassingClause {
4224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4225 if !self.arguments.is_empty() {
4226 write!(f, " PASSING {}", display_comma_separated(&self.arguments))?;
4227 }
4228 Ok(())
4229 }
4230}
4231
4232/// Represents a single XML namespace definition in the XMLNAMESPACES clause.
4233///
4234/// `namespace_uri AS namespace_name`
4235#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4236#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4238pub struct XmlNamespaceDefinition {
4239 /// The namespace URI (a text expression).
4240 pub uri: Expr,
4241 /// The alias for the namespace (a simple identifier).
4242 pub name: Ident,
4243}
4244
4245impl fmt::Display for XmlNamespaceDefinition {
4246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4247 write!(f, "{} AS {}", self.uri, self.name)
4248 }
4249}