1mod analyze;
15mod data_type;
16pub(crate) mod ddl;
17mod legacy_source;
18mod operator;
19mod query;
20mod statement;
21mod value;
22
23use std::collections::HashSet;
24use std::fmt::{self, Display};
25use std::sync::Arc;
26
27use itertools::Itertools;
28use winnow::ModalResult;
29
30pub use self::data_type::{DataType, StructField};
31pub use self::ddl::{
32 AlterColumnOperation, AlterCompactionGroupOperation, AlterConnectionOperation,
33 AlterDatabaseOperation, AlterFragmentOperation, AlterFunctionOperation, AlterRateLimit,
34 AlterRateLimitType, AlterSchemaOperation, AlterSecretOperation, AlterTableOperation, ColumnDef,
35 ColumnOption, ColumnOptionDef, ReferentialAction, SourceWatermark, TableConstraint,
36 WebhookSourceInfo,
37};
38pub use self::legacy_source::{CompatibleFormatEncode, get_delimiter};
39pub use self::operator::{BinaryOperator, QualifiedOperator, UnaryOperator};
40pub use self::query::{
41 AfterMatchSkip, Corresponding, Cte, CteInner, Distinct, Fetch, Join, JoinConstraint,
42 JoinOperator, LateralView, MatchRecognizePattern, MatchRecognizeSymbol, Measure, NamedWindow,
43 OrderByExpr, Query, RepetitionQuantifier, RowsPerMatch, Select, SelectItem, SetExpr,
44 SetOperator, SubsetDefinition, SymbolDefinition, TableAlias, TableFactor, TableWithJoins, Top,
45 Values, With,
46};
47pub use self::statement::*;
48pub use self::value::{
49 ConnectionRefValue, CstyleEscapedString, DateTimeField, DollarQuotedString, JsonPredicateType,
50 SecretRefAsType, SecretRefValue, TrimWhereField, Value,
51};
52pub use crate::ast::analyze::AnalyzeTarget;
53pub use crate::ast::ddl::{
54 AlterIndexOperation, AlterSinkOperation, AlterSourceOperation, AlterSubscriptionOperation,
55 AlterViewOperation,
56};
57use crate::keywords::Keyword;
58use crate::parser::{IncludeOption, IncludeOptionItem, Parser, ParserError, StrError};
59pub use crate::quote_ident::QuoteIdent;
60use crate::tokenizer::Tokenizer;
61
62#[derive(Debug, Default, serde::Serialize)]
64pub struct SqlOptionRedaction {
65 pub keywords: HashSet<String>,
66 pub allowlist: HashSet<String>,
67}
68
69impl SqlOptionRedaction {
70 pub fn new(
71 keywords: impl IntoIterator<Item = String>,
72 allowlist: impl IntoIterator<Item = String>,
73 ) -> Self {
74 Self {
75 keywords: keywords.into_iter().map(|s| s.to_lowercase()).collect(),
76 allowlist: allowlist.into_iter().map(|s| s.to_lowercase()).collect(),
77 }
78 }
79}
80
81pub type SqlOptionRedactionRef = Arc<SqlOptionRedaction>;
82
83task_local::task_local! {
84 pub static SQL_OPTION_REDACTION: SqlOptionRedactionRef;
85}
86
87pub struct DisplaySeparated<'a, T>
88where
89 T: fmt::Display,
90{
91 slice: &'a [T],
92 sep: &'static str,
93}
94
95impl<T> fmt::Display for DisplaySeparated<'_, T>
96where
97 T: fmt::Display,
98{
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 let mut delim = "";
101 for t in self.slice {
102 write!(f, "{}", delim)?;
103 delim = self.sep;
104 write!(f, "{}", t)?;
105 }
106 Ok(())
107 }
108}
109
110pub fn display_separated<'a, T>(slice: &'a [T], sep: &'static str) -> DisplaySeparated<'a, T>
111where
112 T: fmt::Display,
113{
114 DisplaySeparated { slice, sep }
115}
116
117pub fn display_comma_separated<T>(slice: &[T]) -> DisplaySeparated<'_, T>
118where
119 T: fmt::Display,
120{
121 DisplaySeparated { slice, sep: ", " }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
126pub struct Ident {
127 pub(crate) value: String,
129 pub(crate) quote_style: Option<char>,
132}
133
134impl Ident {
135 pub fn new_unchecked<S>(value: S) -> Self
139 where
140 S: Into<String>,
141 {
142 Ident {
143 value: value.into(),
144 quote_style: None,
145 }
146 }
147
148 pub fn with_quote_unchecked<S>(quote: char, value: S) -> Self
152 where
153 S: Into<String>,
154 {
155 Ident {
156 value: value.into(),
157 quote_style: Some(quote),
158 }
159 }
160
161 pub fn with_quote_check<S>(quote: char, value: S) -> Result<Ident, ParserError>
164 where
165 S: Into<String>,
166 {
167 let value_str = value.into();
168 if value_str.is_empty() {
169 return Err(ParserError::ParserError(format!(
170 "zero-length delimited identifier at or near \"{value_str}\""
171 )));
172 }
173
174 if !(quote == '\'' || quote == '"' || quote == '`' || quote == '[') {
175 return Err(ParserError::ParserError(
176 "unexpected quote style".to_owned(),
177 ));
178 }
179
180 Ok(Ident {
181 value: value_str,
182 quote_style: Some(quote),
183 })
184 }
185
186 pub fn real_value(&self) -> String {
192 match self.quote_style {
193 Some('"') => self.value.clone(),
194 _ => self.value.to_lowercase(),
195 }
196 }
197
198 pub fn from_real_value(value: &str) -> Self {
204 let needs_quotes = QuoteIdent::needs_quotes(value);
205
206 if needs_quotes {
207 Self::with_quote_unchecked('"', value)
208 } else {
209 Self::new_unchecked(value)
210 }
211 }
212
213 pub fn quote_style(&self) -> Option<char> {
214 self.quote_style
215 }
216}
217
218impl From<&str> for Ident {
219 fn from(value: &str) -> Self {
220 Self::from_real_value(value)
221 }
222}
223
224impl ParseTo for Ident {
225 fn parse_to(parser: &mut Parser<'_>) -> ModalResult<Self> {
226 parser.parse_identifier()
227 }
228}
229
230impl fmt::Display for Ident {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 match self.quote_style {
233 Some(q) if q == '\'' || q == '`' => write!(f, "{}{}{}", q, self.value, q),
234 Some('"') => write!(f, "\"{}\"", self.value.replace('"', "\"\"")),
235 Some('[') => write!(f, "[{}]", self.value),
236 None => f.write_str(&self.value),
237 _ => panic!("unexpected quote style"),
238 }
239 }
240}
241
242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
246pub struct ObjectName(pub Vec<Ident>);
247
248impl ObjectName {
249 pub fn real_value(&self) -> String {
250 self.0
251 .iter()
252 .map(|ident| ident.real_value())
253 .collect::<Vec<_>>()
254 .join(".")
255 }
256
257 pub fn from_test_str(s: &str) -> Self {
258 ObjectName::from(vec![s.into()])
259 }
260
261 pub fn base_name(&self) -> String {
262 self.0
263 .iter()
264 .last()
265 .expect("should have base name")
266 .real_value()
267 }
268}
269
270impl fmt::Display for ObjectName {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 write!(f, "{}", display_separated(&self.0, "."))
273 }
274}
275
276impl ParseTo for ObjectName {
277 fn parse_to(p: &mut Parser<'_>) -> ModalResult<Self> {
278 p.parse_object_name()
279 }
280}
281
282impl From<Vec<Ident>> for ObjectName {
283 fn from(value: Vec<Ident>) -> Self {
284 Self(value)
285 }
286}
287
288#[derive(Debug, Clone, PartialEq, Eq, Hash)]
290pub struct Array {
291 pub elem: Vec<Expr>,
293
294 pub named: bool,
296}
297
298impl fmt::Display for Array {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 write!(
301 f,
302 "{}[{}]",
303 if self.named { "ARRAY" } else { "" },
304 display_comma_separated(&self.elem)
305 )
306 }
307}
308
309#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
311pub struct EscapeChar(Option<char>);
312
313impl EscapeChar {
314 pub fn escape(ch: char) -> Self {
315 Self(Some(ch))
316 }
317
318 pub fn empty() -> Self {
319 Self(None)
320 }
321}
322
323impl fmt::Display for EscapeChar {
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 match self.0 {
326 Some(ch) => write!(f, "{}", ch),
327 None => f.write_str(""),
328 }
329 }
330}
331
332#[derive(Debug, Clone, PartialEq, Eq, Hash)]
338pub enum Expr {
339 Identifier(Ident),
341 CompoundIdentifier(Vec<Ident>),
343 FieldIdentifier(Box<Expr>, Vec<Ident>),
355 IsNull(Box<Expr>),
357 IsNotNull(Box<Expr>),
359 IsTrue(Box<Expr>),
361 IsNotTrue(Box<Expr>),
363 IsFalse(Box<Expr>),
365 IsNotFalse(Box<Expr>),
367 IsUnknown(Box<Expr>),
369 IsNotUnknown(Box<Expr>),
371 IsDistinctFrom(Box<Expr>, Box<Expr>),
373 IsNotDistinctFrom(Box<Expr>, Box<Expr>),
375 IsJson {
380 expr: Box<Expr>,
381 negated: bool,
382 item_type: JsonPredicateType,
383 unique_keys: bool,
384 },
385 InList {
387 expr: Box<Expr>,
388 list: Vec<Expr>,
389 negated: bool,
390 },
391 InSubquery {
393 expr: Box<Expr>,
394 subquery: Box<Query>,
395 negated: bool,
396 },
397 Between {
399 expr: Box<Expr>,
400 negated: bool,
401 low: Box<Expr>,
402 high: Box<Expr>,
403 },
404 Like {
406 negated: bool,
407 expr: Box<Expr>,
408 pattern: Box<Expr>,
409 escape_char: Option<EscapeChar>,
410 },
411 ILike {
413 negated: bool,
414 expr: Box<Expr>,
415 pattern: Box<Expr>,
416 escape_char: Option<EscapeChar>,
417 },
418 SimilarTo {
420 negated: bool,
421 expr: Box<Expr>,
422 pattern: Box<Expr>,
423 escape_char: Option<EscapeChar>,
424 },
425 BinaryOp {
427 left: Box<Expr>,
428 op: BinaryOperator,
429 right: Box<Expr>,
430 },
431 SomeOp(Box<Expr>),
433 AllOp(Box<Expr>),
435 UnaryOp {
437 op: UnaryOperator,
438 expr: Box<Expr>,
439 },
440 Cast {
442 expr: Box<Expr>,
443 data_type: DataType,
444 },
445 TryCast {
448 expr: Box<Expr>,
449 data_type: DataType,
450 },
451 AtTimeZone {
454 timestamp: Box<Expr>,
455 time_zone: Box<Expr>,
456 },
457 Extract {
459 field: String,
460 expr: Box<Expr>,
461 },
462 Substring {
464 expr: Box<Expr>,
465 substring_from: Option<Box<Expr>>,
466 substring_for: Option<Box<Expr>>,
467 },
468 Position {
470 substring: Box<Expr>,
471 string: Box<Expr>,
472 },
473 Overlay {
475 expr: Box<Expr>,
476 new_substring: Box<Expr>,
477 start: Box<Expr>,
478 count: Option<Box<Expr>>,
479 },
480 Trim {
484 expr: Box<Expr>,
485 trim_where: Option<TrimWhereField>,
487 trim_what: Option<Box<Expr>>,
488 },
489 Collate {
491 expr: Box<Expr>,
492 collation: ObjectName,
493 },
494 Nested(Box<Expr>),
496 Value(Value),
498 Parameter {
500 index: u64,
501 },
502 TypedString {
506 data_type: DataType,
507 value: String,
508 },
509 Function(Function),
511 Case {
517 operand: Option<Box<Expr>>,
518 conditions: Vec<Expr>,
519 results: Vec<Expr>,
520 else_result: Option<Box<Expr>>,
521 },
522 Exists(Box<Query>),
525 Subquery(Box<Query>),
528 GroupingSets(Vec<Vec<Expr>>),
530 Cube(Vec<Vec<Expr>>),
532 Rollup(Vec<Vec<Expr>>),
534 Row(Vec<Expr>),
536 Array(Array),
538 ArraySubquery(Box<Query>),
540 Index {
542 obj: Box<Expr>,
543 index: Box<Expr>,
544 },
545 ArrayRangeIndex {
547 obj: Box<Expr>,
548 start: Option<Box<Expr>>,
549 end: Option<Box<Expr>>,
550 },
551 LambdaFunction {
552 args: Vec<Ident>,
553 body: Box<Expr>,
554 },
555 Map {
556 entries: Vec<(Expr, Expr)>,
557 },
558}
559
560impl fmt::Display for Expr {
561 #[expect(clippy::disallowed_methods, reason = "use zip_eq")]
562 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563 match self {
564 Expr::Identifier(s) => write!(f, "{}", s),
565 Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
566 Expr::FieldIdentifier(ast, s) => write!(f, "({}).{}", ast, display_separated(s, ".")),
567 Expr::IsNull(ast) => write!(f, "{} IS NULL", ast),
568 Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast),
569 Expr::IsTrue(ast) => write!(f, "{} IS TRUE", ast),
570 Expr::IsNotTrue(ast) => write!(f, "{} IS NOT TRUE", ast),
571 Expr::IsFalse(ast) => write!(f, "{} IS FALSE", ast),
572 Expr::IsNotFalse(ast) => write!(f, "{} IS NOT FALSE", ast),
573 Expr::IsUnknown(ast) => write!(f, "{} IS UNKNOWN", ast),
574 Expr::IsNotUnknown(ast) => write!(f, "{} IS NOT UNKNOWN", ast),
575 Expr::IsJson {
576 expr,
577 negated,
578 item_type,
579 unique_keys,
580 } => write!(
581 f,
582 "{} IS {}JSON{}{}",
583 expr,
584 if *negated { "NOT " } else { "" },
585 item_type,
586 if *unique_keys {
587 " WITH UNIQUE KEYS"
588 } else {
589 ""
590 },
591 ),
592 Expr::InList {
593 expr,
594 list,
595 negated,
596 } => write!(
597 f,
598 "{} {}IN ({})",
599 expr,
600 if *negated { "NOT " } else { "" },
601 display_comma_separated(list)
602 ),
603 Expr::InSubquery {
604 expr,
605 subquery,
606 negated,
607 } => write!(
608 f,
609 "{} {}IN ({})",
610 expr,
611 if *negated { "NOT " } else { "" },
612 subquery
613 ),
614 Expr::Between {
615 expr,
616 negated,
617 low,
618 high,
619 } => write!(
620 f,
621 "{} {}BETWEEN {} AND {}",
622 expr,
623 if *negated { "NOT " } else { "" },
624 low,
625 high
626 ),
627 Expr::Like {
628 negated,
629 expr,
630 pattern,
631 escape_char,
632 } => match escape_char {
633 Some(ch) => write!(
634 f,
635 "{} {}LIKE {} ESCAPE '{}'",
636 expr,
637 if *negated { "NOT " } else { "" },
638 pattern,
639 ch
640 ),
641 _ => write!(
642 f,
643 "{} {}LIKE {}",
644 expr,
645 if *negated { "NOT " } else { "" },
646 pattern
647 ),
648 },
649 Expr::ILike {
650 negated,
651 expr,
652 pattern,
653 escape_char,
654 } => match escape_char {
655 Some(ch) => write!(
656 f,
657 "{} {}ILIKE {} ESCAPE '{}'",
658 expr,
659 if *negated { "NOT " } else { "" },
660 pattern,
661 ch
662 ),
663 _ => write!(
664 f,
665 "{} {}ILIKE {}",
666 expr,
667 if *negated { "NOT " } else { "" },
668 pattern
669 ),
670 },
671 Expr::SimilarTo {
672 negated,
673 expr,
674 pattern,
675 escape_char,
676 } => match escape_char {
677 Some(ch) => write!(
678 f,
679 "{} {}SIMILAR TO {} ESCAPE '{}'",
680 expr,
681 if *negated { "NOT " } else { "" },
682 pattern,
683 ch
684 ),
685 _ => write!(
686 f,
687 "{} {}SIMILAR TO {}",
688 expr,
689 if *negated { "NOT " } else { "" },
690 pattern
691 ),
692 },
693 Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right),
694 Expr::SomeOp(expr) => write!(f, "SOME({})", expr),
695 Expr::AllOp(expr) => write!(f, "ALL({})", expr),
696 Expr::UnaryOp { op, expr } => {
697 write!(f, "{} {}", op, expr)
698 }
699 Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
700 Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
701 Expr::AtTimeZone {
702 timestamp,
703 time_zone,
704 } => write!(f, "{} AT TIME ZONE {}", timestamp, time_zone),
705 Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
706 Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
707 Expr::Nested(ast) => write!(f, "({})", ast),
708 Expr::Value(v) => write!(f, "{}", v),
709 Expr::Parameter { index } => write!(f, "${}", index),
710 Expr::TypedString { data_type, value } => {
711 write!(f, "{}", data_type)?;
712 write!(f, " '{}'", value::escape_single_quote_string(value))
713 }
714 Expr::Function(fun) => write!(f, "{}", fun),
715 Expr::Case {
716 operand,
717 conditions,
718 results,
719 else_result,
720 } => {
721 write!(f, "CASE")?;
722 if let Some(operand) = operand {
723 write!(f, " {}", operand)?;
724 }
725 for (c, r) in conditions.iter().zip_eq(results) {
726 write!(f, " WHEN {} THEN {}", c, r)?;
727 }
728
729 if let Some(else_result) = else_result {
730 write!(f, " ELSE {}", else_result)?;
731 }
732 write!(f, " END")
733 }
734 Expr::Exists(s) => write!(f, "EXISTS ({})", s),
735 Expr::Subquery(s) => write!(f, "({})", s),
736 Expr::GroupingSets(sets) => {
737 write!(f, "GROUPING SETS (")?;
738 let mut sep = "";
739 for set in sets {
740 write!(f, "{}", sep)?;
741 sep = ", ";
742 write!(f, "({})", display_comma_separated(set))?;
743 }
744 write!(f, ")")
745 }
746 Expr::Cube(sets) => {
747 write!(f, "CUBE (")?;
748 let mut sep = "";
749 for set in sets {
750 write!(f, "{}", sep)?;
751 sep = ", ";
752 if set.len() == 1 {
753 write!(f, "{}", set[0])?;
754 } else {
755 write!(f, "({})", display_comma_separated(set))?;
756 }
757 }
758 write!(f, ")")
759 }
760 Expr::Rollup(sets) => {
761 write!(f, "ROLLUP (")?;
762 let mut sep = "";
763 for set in sets {
764 write!(f, "{}", sep)?;
765 sep = ", ";
766 if set.len() == 1 {
767 write!(f, "{}", set[0])?;
768 } else {
769 write!(f, "({})", display_comma_separated(set))?;
770 }
771 }
772 write!(f, ")")
773 }
774 Expr::Substring {
775 expr,
776 substring_from,
777 substring_for,
778 } => {
779 write!(f, "SUBSTRING({}", expr)?;
780 if let Some(from_part) = substring_from {
781 write!(f, " FROM {}", from_part)?;
782 }
783 if let Some(from_part) = substring_for {
784 write!(f, " FOR {}", from_part)?;
785 }
786
787 write!(f, ")")
788 }
789 Expr::Position { substring, string } => {
790 write!(f, "POSITION({} IN {})", substring, string)
791 }
792 Expr::Overlay {
793 expr,
794 new_substring,
795 start,
796 count,
797 } => {
798 write!(f, "OVERLAY({}", expr)?;
799 write!(f, " PLACING {}", new_substring)?;
800 write!(f, " FROM {}", start)?;
801
802 if let Some(count_expr) = count {
803 write!(f, " FOR {}", count_expr)?;
804 }
805
806 write!(f, ")")
807 }
808 Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
809 Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
810 Expr::Trim {
811 expr,
812 trim_where,
813 trim_what,
814 } => {
815 write!(f, "TRIM(")?;
816 if let Some(ident) = trim_where {
817 write!(f, "{} ", ident)?;
818 }
819 if let Some(trim_char) = trim_what {
820 write!(f, "{} ", trim_char)?;
821 }
822 write!(f, "FROM {})", expr)
823 }
824 Expr::Row(exprs) => write!(
825 f,
826 "ROW({})",
827 exprs
828 .iter()
829 .map(|v| v.to_string())
830 .collect::<Vec<String>>()
831 .as_slice()
832 .join(", ")
833 ),
834 Expr::Index { obj, index } => {
835 write!(f, "{}[{}]", obj, index)?;
836 Ok(())
837 }
838 Expr::ArrayRangeIndex { obj, start, end } => {
839 let start_str = match start {
840 None => "".to_owned(),
841 Some(start) => format!("{}", start),
842 };
843 let end_str = match end {
844 None => "".to_owned(),
845 Some(end) => format!("{}", end),
846 };
847 write!(f, "{}[{}:{}]", obj, start_str, end_str)?;
848 Ok(())
849 }
850 Expr::Array(exprs) => write!(f, "{}", exprs),
851 Expr::ArraySubquery(s) => write!(f, "ARRAY ({})", s),
852 Expr::LambdaFunction { args, body } => {
853 write!(
854 f,
855 "|{}| {}",
856 args.iter().map(ToString::to_string).join(", "),
857 body
858 )
859 }
860 Expr::Map { entries } => {
861 write!(
862 f,
863 "MAP {{{}}}",
864 entries
865 .iter()
866 .map(|(k, v)| format!("{}: {}", k, v))
867 .join(", ")
868 )
869 }
870 }
871 }
872}
873
874#[derive(Debug, Clone, PartialEq, Eq, Hash)]
877pub struct WindowSpec {
878 pub partition_by: Vec<Expr>,
879 pub order_by: Vec<OrderByExpr>,
880 pub window_frame: Option<WindowFrame>,
881}
882
883#[derive(Debug, Clone, PartialEq, Eq, Hash)]
886pub enum Window {
887 Spec(WindowSpec),
889 Name(Ident),
891}
892
893impl fmt::Display for WindowSpec {
894 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895 let mut delim = "";
896 if !self.partition_by.is_empty() {
897 delim = " ";
898 write!(
899 f,
900 "PARTITION BY {}",
901 display_comma_separated(&self.partition_by)
902 )?;
903 }
904 if !self.order_by.is_empty() {
905 f.write_str(delim)?;
906 delim = " ";
907 write!(f, "ORDER BY {}", display_comma_separated(&self.order_by))?;
908 }
909 if let Some(window_frame) = &self.window_frame {
910 f.write_str(delim)?;
911 window_frame.fmt(f)?;
912 }
913 Ok(())
914 }
915}
916
917impl fmt::Display for Window {
918 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
919 match self {
920 Window::Spec(spec) => write!(f, "({})", spec),
921 Window::Name(name) => write!(f, "{}", name),
922 }
923 }
924}
925
926#[derive(Debug, Clone, PartialEq, Eq, Hash)]
932pub struct WindowFrame {
933 pub units: WindowFrameUnits,
934 pub bounds: WindowFrameBounds,
935 pub exclusion: Option<WindowFrameExclusion>,
936}
937
938#[derive(Debug, Clone, PartialEq, Eq, Hash)]
939pub enum WindowFrameUnits {
940 Rows,
941 Range,
942 Groups,
943 Session,
944}
945
946#[derive(Debug, Clone, PartialEq, Eq, Hash)]
947pub enum WindowFrameBounds {
948 Bounds {
949 start: WindowFrameBound,
950 end: Option<WindowFrameBound>,
954 },
955 Gap(Box<Expr>),
956}
957
958impl fmt::Display for WindowFrame {
959 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
960 write!(f, "{} ", self.units)?;
961 match &self.bounds {
962 WindowFrameBounds::Bounds { start, end } => {
963 if let Some(end) = end {
964 write!(f, "BETWEEN {} AND {}", start, end)
965 } else {
966 write!(f, "{}", start)
967 }
968 }
969 WindowFrameBounds::Gap(gap) => {
970 write!(f, "WITH GAP {}", gap)
971 }
972 }
973 }
974}
975
976impl fmt::Display for WindowFrameUnits {
977 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978 f.write_str(match self {
979 WindowFrameUnits::Rows => "ROWS",
980 WindowFrameUnits::Range => "RANGE",
981 WindowFrameUnits::Groups => "GROUPS",
982 WindowFrameUnits::Session => "SESSION",
983 })
984 }
985}
986
987#[derive(Debug, Clone, PartialEq, Eq, Hash)]
989pub enum WindowFrameBound {
990 CurrentRow,
992 Preceding(Option<Box<Expr>>),
994 Following(Option<Box<Expr>>),
996}
997
998impl fmt::Display for WindowFrameBound {
999 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1000 match self {
1001 WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
1002 WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
1003 WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
1004 WindowFrameBound::Preceding(Some(n)) => write!(f, "{} PRECEDING", n),
1005 WindowFrameBound::Following(Some(n)) => write!(f, "{} FOLLOWING", n),
1006 }
1007 }
1008}
1009
1010#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1012pub enum WindowFrameExclusion {
1013 CurrentRow,
1014 Group,
1015 Ties,
1016 NoOthers,
1017}
1018
1019impl fmt::Display for WindowFrameExclusion {
1020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1021 match self {
1022 WindowFrameExclusion::CurrentRow => f.write_str("EXCLUDE CURRENT ROW"),
1023 WindowFrameExclusion::Group => f.write_str("EXCLUDE GROUP"),
1024 WindowFrameExclusion::Ties => f.write_str("EXCLUDE TIES"),
1025 WindowFrameExclusion::NoOthers => f.write_str("EXCLUDE NO OTHERS"),
1026 }
1027 }
1028}
1029
1030#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1031pub enum AddDropSync {
1032 ADD,
1033 DROP,
1034 SYNC,
1035}
1036
1037impl fmt::Display for AddDropSync {
1038 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1039 match self {
1040 AddDropSync::SYNC => f.write_str("SYNC PARTITIONS"),
1041 AddDropSync::DROP => f.write_str("DROP PARTITIONS"),
1042 AddDropSync::ADD => f.write_str("ADD PARTITIONS"),
1043 }
1044 }
1045}
1046
1047#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1048pub enum ShowObject {
1049 Table { schema: Option<Ident> },
1050 InternalTable { schema: Option<Ident> },
1051 Database,
1052 Schema,
1053 View { schema: Option<Ident> },
1054 MaterializedView { schema: Option<Ident> },
1055 Source { schema: Option<Ident> },
1056 Sink { schema: Option<Ident> },
1057 Subscription { schema: Option<Ident> },
1058 Columns { table: ObjectName },
1059 Connection { schema: Option<Ident> },
1060 Secret { schema: Option<Ident> },
1061 Function { schema: Option<Ident> },
1062 Indexes { table: ObjectName },
1063 Cluster,
1064 Jobs,
1065 ProcessList,
1066 Cursor,
1067 SubscriptionCursor,
1068}
1069
1070#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1071pub struct JobIdents(pub Vec<u32>);
1072
1073impl fmt::Display for ShowObject {
1074 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1075 fn fmt_schema(schema: &Option<Ident>) -> String {
1076 if let Some(schema) = schema {
1077 format!(" FROM {}", schema.value)
1078 } else {
1079 "".to_owned()
1080 }
1081 }
1082
1083 match self {
1084 ShowObject::Database => f.write_str("DATABASES"),
1085 ShowObject::Schema => f.write_str("SCHEMAS"),
1086 ShowObject::Table { schema } => {
1087 write!(f, "TABLES{}", fmt_schema(schema))
1088 }
1089 ShowObject::InternalTable { schema } => {
1090 write!(f, "INTERNAL TABLES{}", fmt_schema(schema))
1091 }
1092 ShowObject::View { schema } => {
1093 write!(f, "VIEWS{}", fmt_schema(schema))
1094 }
1095 ShowObject::MaterializedView { schema } => {
1096 write!(f, "MATERIALIZED VIEWS{}", fmt_schema(schema))
1097 }
1098 ShowObject::Source { schema } => write!(f, "SOURCES{}", fmt_schema(schema)),
1099 ShowObject::Sink { schema } => write!(f, "SINKS{}", fmt_schema(schema)),
1100 ShowObject::Columns { table } => write!(f, "COLUMNS FROM {}", table),
1101 ShowObject::Connection { schema } => write!(f, "CONNECTIONS{}", fmt_schema(schema)),
1102 ShowObject::Function { schema } => write!(f, "FUNCTIONS{}", fmt_schema(schema)),
1103 ShowObject::Indexes { table } => write!(f, "INDEXES FROM {}", table),
1104 ShowObject::Cluster => {
1105 write!(f, "CLUSTER")
1106 }
1107 ShowObject::Jobs => write!(f, "JOBS"),
1108 ShowObject::ProcessList => write!(f, "PROCESSLIST"),
1109 ShowObject::Subscription { schema } => write!(f, "SUBSCRIPTIONS{}", fmt_schema(schema)),
1110 ShowObject::Secret { schema } => write!(f, "SECRETS{}", fmt_schema(schema)),
1111 ShowObject::Cursor => write!(f, "CURSORS"),
1112 ShowObject::SubscriptionCursor => write!(f, "SUBSCRIPTION CURSORS"),
1113 }
1114 }
1115}
1116
1117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1118pub enum ShowCreateType {
1119 Table,
1120 MaterializedView,
1121 View,
1122 Index,
1123 Source,
1124 Sink,
1125 Function,
1126 Subscription,
1127}
1128
1129impl fmt::Display for ShowCreateType {
1130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131 match self {
1132 ShowCreateType::Table => f.write_str("TABLE"),
1133 ShowCreateType::MaterializedView => f.write_str("MATERIALIZED VIEW"),
1134 ShowCreateType::View => f.write_str("VIEW"),
1135 ShowCreateType::Index => f.write_str("INDEX"),
1136 ShowCreateType::Source => f.write_str("SOURCE"),
1137 ShowCreateType::Sink => f.write_str("SINK"),
1138 ShowCreateType::Function => f.write_str("FUNCTION"),
1139 ShowCreateType::Subscription => f.write_str("SUBSCRIPTION"),
1140 }
1141 }
1142}
1143
1144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1145pub enum CommentObject {
1146 Column,
1147 Table,
1148}
1149
1150impl fmt::Display for CommentObject {
1151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1152 match self {
1153 CommentObject::Column => f.write_str("COLUMN"),
1154 CommentObject::Table => f.write_str("TABLE"),
1155 }
1156 }
1157}
1158
1159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1160pub enum ExplainType {
1161 Logical,
1162 Physical,
1163 DistSql,
1164}
1165
1166impl fmt::Display for ExplainType {
1167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1168 match self {
1169 ExplainType::Logical => f.write_str("Logical"),
1170 ExplainType::Physical => f.write_str("Physical"),
1171 ExplainType::DistSql => f.write_str("DistSQL"),
1172 }
1173 }
1174}
1175
1176#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1177pub enum ExplainFormat {
1178 Text,
1179 Json,
1180 Xml,
1181 Yaml,
1182 Dot,
1183}
1184
1185impl fmt::Display for ExplainFormat {
1186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1187 match self {
1188 ExplainFormat::Text => f.write_str("TEXT"),
1189 ExplainFormat::Json => f.write_str("JSON"),
1190 ExplainFormat::Xml => f.write_str("XML"),
1191 ExplainFormat::Yaml => f.write_str("YAML"),
1192 ExplainFormat::Dot => f.write_str("DOT"),
1193 }
1194 }
1195}
1196
1197#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1198pub struct ExplainOptions {
1199 pub verbose: bool,
1201 pub trace: bool,
1203 pub backfill: bool,
1205 pub explain_type: ExplainType,
1207 pub explain_format: ExplainFormat,
1209}
1210
1211impl Default for ExplainOptions {
1212 fn default() -> Self {
1213 Self {
1214 verbose: false,
1215 trace: false,
1216 backfill: false,
1217 explain_type: ExplainType::Physical,
1218 explain_format: ExplainFormat::Text,
1219 }
1220 }
1221}
1222
1223impl fmt::Display for ExplainOptions {
1224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1225 let default = Self::default();
1226 if *self == default {
1227 Ok(())
1228 } else {
1229 let mut option_strs = vec![];
1230 if self.verbose {
1231 option_strs.push("VERBOSE".to_owned());
1232 }
1233 if self.trace {
1234 option_strs.push("TRACE".to_owned());
1235 }
1236 if self.backfill {
1237 option_strs.push("BACKFILL".to_owned());
1238 }
1239 if self.explain_type == default.explain_type {
1240 option_strs.push(self.explain_type.to_string());
1241 }
1242 if self.explain_format == default.explain_format {
1243 option_strs.push(self.explain_format.to_string());
1244 }
1245 write!(f, "{}", option_strs.iter().format(","))
1246 }
1247 }
1248}
1249
1250#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1251pub struct CdcTableInfo {
1252 pub source_name: ObjectName,
1253 pub external_table_name: String,
1254}
1255
1256#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1257pub enum CopyEntity {
1258 Query(Box<Query>),
1259 Table {
1260 table_name: ObjectName,
1262 columns: Vec<Ident>,
1264 },
1265}
1266
1267#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1268pub enum CopyTarget {
1269 Stdin {
1270 values: Vec<Option<String>>,
1272 },
1273 Stdout,
1274}
1275
1276#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1277pub enum WaitTarget {
1278 All,
1279 Table(ObjectName),
1280 MaterializedView(ObjectName),
1281 Sink(ObjectName),
1282 Index(ObjectName),
1283}
1284
1285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1286pub enum FileCacheType {
1287 Meta,
1288 Data,
1289 All,
1290}
1291
1292#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1295pub enum Statement {
1296 Analyze {
1298 table_name: ObjectName,
1299 },
1300 Truncate {
1302 table_name: ObjectName,
1303 },
1304 Refresh {
1306 table_name: ObjectName,
1307 },
1308 Query(Box<Query>),
1310 Insert {
1312 table_name: ObjectName,
1314 columns: Vec<Ident>,
1316 source: Box<Query>,
1318 returning: Vec<SelectItem>,
1320 },
1321 Copy {
1322 entity: CopyEntity,
1323 target: CopyTarget,
1324 },
1325 Update {
1327 table_name: ObjectName,
1329 assignments: Vec<Assignment>,
1331 selection: Option<Expr>,
1333 returning: Vec<SelectItem>,
1335 },
1336 Delete {
1338 table_name: ObjectName,
1340 selection: Option<Expr>,
1342 returning: Vec<SelectItem>,
1344 },
1345 DeleteMetaSnapshots {
1347 snapshot_ids: Vec<u64>,
1348 },
1349 Discard(DiscardType),
1351 CreateView {
1353 or_replace: bool,
1354 materialized: bool,
1355 if_not_exists: bool,
1356 name: ObjectName,
1358 columns: Vec<Ident>,
1359 query: Box<Query>,
1360 emit_mode: Option<EmitMode>,
1361 with_options: Vec<SqlOption>,
1362 },
1363 CreateTable {
1365 or_replace: bool,
1366 temporary: bool,
1367 if_not_exists: bool,
1368 name: ObjectName,
1370 columns: Vec<ColumnDef>,
1372 wildcard_idx: Option<usize>,
1374 constraints: Vec<TableConstraint>,
1375 with_options: Vec<SqlOption>,
1376 format_encode: Option<CompatibleFormatEncode>,
1378 source_watermarks: Vec<SourceWatermark>,
1380 append_only: bool,
1382 on_conflict: Option<OnConflict>,
1384 with_version_columns: Vec<Ident>,
1386 query: Option<Box<Query>>,
1388 cdc_table_info: Option<CdcTableInfo>,
1390 include_column_options: IncludeOption,
1392 webhook_info: Option<WebhookSourceInfo>,
1394 engine: Engine,
1396 },
1397 CreateIndex {
1399 name: ObjectName,
1401 table_name: ObjectName,
1402 columns: Vec<OrderByExpr>,
1403 method: Option<Ident>,
1404 include: Vec<Ident>,
1405 distributed_by: Vec<Expr>,
1406 unique: bool,
1407 if_not_exists: bool,
1408 with_properties: WithProperties,
1409 },
1410 CreateSource {
1412 stmt: CreateSourceStatement,
1413 },
1414 CreateSink {
1416 stmt: CreateSinkStatement,
1417 },
1418 CreateSubscription {
1420 stmt: CreateSubscriptionStatement,
1421 },
1422 CreateConnection {
1424 stmt: CreateConnectionStatement,
1425 },
1426 CreateSecret {
1427 stmt: CreateSecretStatement,
1428 },
1429 CreateFunction {
1433 or_replace: bool,
1434 temporary: bool,
1435 if_not_exists: bool,
1436 name: ObjectName,
1437 args: Option<Vec<OperateFunctionArg>>,
1438 returns: Option<CreateFunctionReturns>,
1439 params: CreateFunctionBody,
1441 with_options: CreateFunctionWithOptions, },
1443 CreateAggregate {
1447 or_replace: bool,
1448 if_not_exists: bool,
1449 name: ObjectName,
1450 args: Vec<OperateFunctionArg>,
1451 returns: DataType,
1452 append_only: bool,
1454 params: CreateFunctionBody,
1455 },
1456
1457 DeclareCursor {
1459 stmt: DeclareCursorStatement,
1460 },
1461
1462 FetchCursor {
1464 stmt: FetchCursorStatement,
1465 },
1466
1467 CloseCursor {
1469 stmt: CloseCursorStatement,
1470 },
1471
1472 AlterDatabase {
1474 name: ObjectName,
1475 operation: AlterDatabaseOperation,
1476 },
1477 AlterSchema {
1479 name: ObjectName,
1480 operation: AlterSchemaOperation,
1481 },
1482 AlterTable {
1484 name: ObjectName,
1486 operation: AlterTableOperation,
1487 },
1488 AlterIndex {
1490 name: ObjectName,
1492 operation: AlterIndexOperation,
1493 },
1494 AlterView {
1496 name: ObjectName,
1498 materialized: bool,
1499 operation: AlterViewOperation,
1500 },
1501 AlterSink {
1503 name: ObjectName,
1505 operation: AlterSinkOperation,
1506 },
1507 AlterSubscription {
1508 name: ObjectName,
1509 operation: AlterSubscriptionOperation,
1510 },
1511 AlterSource {
1513 name: ObjectName,
1515 operation: AlterSourceOperation,
1516 },
1517 AlterFunction {
1519 name: ObjectName,
1521 args: Option<Vec<OperateFunctionArg>>,
1522 operation: AlterFunctionOperation,
1523 },
1524 AlterConnection {
1526 name: ObjectName,
1528 operation: AlterConnectionOperation,
1529 },
1530 AlterSecret {
1532 name: ObjectName,
1534 operation: AlterSecretOperation,
1535 },
1536 AlterFragment {
1538 fragment_ids: Vec<u32>,
1539 operation: AlterFragmentOperation,
1540 },
1541 AlterCompactionGroup {
1543 group_ids: Vec<u64>,
1544 operation: AlterCompactionGroupOperation,
1545 },
1546 AlterDefaultPrivileges {
1549 target_users: Option<Vec<Ident>>,
1550 schema_names: Option<Vec<ObjectName>>,
1551 operation: DefaultPrivilegeOperation,
1552 },
1553 Describe {
1555 name: ObjectName,
1557 kind: DescribeKind,
1558 },
1559 DescribeFragment {
1561 fragment_id: u32,
1562 },
1563 ShowObjects {
1565 object: ShowObject,
1566 filter: Option<ShowStatementFilter>,
1567 },
1568 ShowCreateObject {
1570 create_type: ShowCreateType,
1572 name: ObjectName,
1574 },
1575 ShowTransactionIsolationLevel,
1576 CancelJobs(JobIdents),
1578 Kill(String),
1581 Drop(DropStatement),
1583 DropFunction {
1585 if_exists: bool,
1586 func_desc: Vec<FunctionDesc>,
1588 option: Option<ReferentialAction>,
1590 },
1591 DropAggregate {
1593 if_exists: bool,
1594 func_desc: Vec<FunctionDesc>,
1596 option: Option<ReferentialAction>,
1598 },
1599 SetVariable {
1605 local: bool,
1606 variable: Ident,
1607 value: SetVariableValue,
1608 },
1609 ShowVariable {
1613 variable: Vec<Ident>,
1614 },
1615 StartTransaction {
1617 modes: Vec<TransactionMode>,
1618 },
1619 Begin {
1621 modes: Vec<TransactionMode>,
1622 },
1623 Abort,
1625 SetTransaction {
1627 modes: Vec<TransactionMode>,
1628 snapshot: Option<Value>,
1629 session: bool,
1630 },
1631 SetTimeZone {
1633 local: bool,
1634 value: SetTimeZoneValue,
1635 },
1636 Comment {
1640 object_type: CommentObject,
1641 object_name: ObjectName,
1642 comment: Option<String>,
1643 },
1644 Commit {
1646 chain: bool,
1647 },
1648 Rollback {
1650 chain: bool,
1651 },
1652 CreateSchema {
1654 schema_name: ObjectName,
1655 if_not_exists: bool,
1656 owner: Option<ObjectName>,
1657 },
1658 CreateDatabase {
1660 db_name: ObjectName,
1661 if_not_exists: bool,
1662 owner: Option<ObjectName>,
1663 resource_group: Option<SetVariableValue>,
1664 barrier_interval_ms: Option<u32>,
1665 checkpoint_frequency: Option<u64>,
1666 },
1667 Grant {
1669 privileges: Privileges,
1670 objects: GrantObjects,
1671 grantees: Vec<Ident>,
1672 with_grant_option: bool,
1673 granted_by: Option<Ident>,
1674 },
1675 Revoke {
1677 privileges: Privileges,
1678 objects: GrantObjects,
1679 grantees: Vec<Ident>,
1680 granted_by: Option<Ident>,
1681 revoke_grant_option: bool,
1682 cascade: bool,
1683 },
1684 Deallocate {
1688 name: Option<Ident>,
1689 prepare: bool,
1690 },
1691 Execute {
1695 name: Ident,
1696 parameters: Vec<Expr>,
1697 },
1698 Prepare {
1702 name: Ident,
1703 data_types: Vec<DataType>,
1704 statement: Box<Statement>,
1705 },
1706 Explain {
1708 analyze: bool,
1710 statement: Box<Statement>,
1712 options: ExplainOptions,
1714 },
1715 ExplainAnalyzeStreamJob {
1720 target: AnalyzeTarget,
1721 duration_secs: Option<u64>,
1722 },
1723 CreateUser(CreateUserStatement),
1725 AlterUser(AlterUserStatement),
1727 AlterSystem {
1729 param: Ident,
1730 value: SetVariableValue,
1731 },
1732 AlterSystemClearFileCache {
1734 cache_type: FileCacheType,
1735 },
1736 Flush,
1740 Wait(WaitTarget),
1743 Backup,
1745 Recover,
1747 Use {
1751 db_name: ObjectName,
1752 },
1753 Vacuum {
1757 object_name: ObjectName,
1758 mode: VacuumMode,
1759 },
1760}
1761
1762#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1763pub enum VacuumMode {
1764 Default,
1765 Full,
1766 OrphanFiles,
1767}
1768
1769#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1770pub enum DescribeKind {
1771 Plain,
1773
1774 Fragments,
1776}
1777
1778impl fmt::Display for Statement {
1779 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1784 let sql = self
1786 .try_to_string()
1787 .expect("normalized SQL should be parsable");
1788 f.write_str(&sql)
1789 }
1790}
1791
1792impl Statement {
1793 pub fn try_to_string(&self) -> Result<String, ParserError> {
1797 let sql = self.to_string_unchecked();
1798
1799 if matches!(
1801 self,
1802 Statement::CreateTable { .. } | Statement::CreateSource { .. }
1803 ) {
1804 let _ = Parser::parse_sql(&sql)?;
1805 }
1806 Ok(sql)
1807 }
1808
1809 pub fn to_string_unchecked(&self) -> String {
1815 let mut buf = String::new();
1816 self.fmt_unchecked(&mut buf).unwrap();
1817 buf
1818 }
1819
1820 #[expect(clippy::cognitive_complexity)]
1827 fn fmt_unchecked(&self, mut f: impl std::fmt::Write) -> fmt::Result {
1828 match self {
1829 Statement::Explain {
1830 analyze,
1831 statement,
1832 options,
1833 } => {
1834 write!(f, "EXPLAIN ")?;
1835
1836 if *analyze {
1837 write!(f, "ANALYZE ")?;
1838 }
1839 write!(f, "{}", options)?;
1840
1841 statement.fmt_unchecked(f)
1842 }
1843 Statement::ExplainAnalyzeStreamJob {
1844 target,
1845 duration_secs,
1846 } => {
1847 write!(f, "EXPLAIN ANALYZE {}", target)?;
1848 if let Some(duration_secs) = duration_secs {
1849 write!(f, " (DURATION_SECS {})", duration_secs)?;
1850 }
1851 Ok(())
1852 }
1853 Statement::Query(s) => write!(f, "{}", s),
1854 Statement::Truncate { table_name } => {
1855 write!(f, "TRUNCATE TABLE {}", table_name)?;
1856 Ok(())
1857 }
1858 Statement::Refresh { table_name } => {
1859 write!(f, "REFRESH TABLE {}", table_name)?;
1860 Ok(())
1861 }
1862 Statement::Analyze { table_name } => {
1863 write!(f, "ANALYZE TABLE {}", table_name)?;
1864 Ok(())
1865 }
1866 Statement::Describe { name, kind } => {
1867 write!(f, "DESCRIBE {}", name)?;
1868 match kind {
1869 DescribeKind::Plain => {}
1870
1871 DescribeKind::Fragments => {
1872 write!(f, " FRAGMENTS")?;
1873 }
1874 }
1875 Ok(())
1876 }
1877 Statement::DescribeFragment { fragment_id } => {
1878 write!(f, "DESCRIBE FRAGMENT {}", fragment_id)?;
1879 Ok(())
1880 }
1881 Statement::ShowObjects {
1882 object: show_object,
1883 filter,
1884 } => {
1885 write!(f, "SHOW {}", show_object)?;
1886 if let Some(filter) = filter {
1887 write!(f, " {}", filter)?;
1888 }
1889 Ok(())
1890 }
1891 Statement::ShowCreateObject {
1892 create_type: show_type,
1893 name,
1894 } => {
1895 write!(f, "SHOW CREATE {} {}", show_type, name)?;
1896 Ok(())
1897 }
1898 Statement::ShowTransactionIsolationLevel => {
1899 write!(f, "SHOW TRANSACTION ISOLATION LEVEL")?;
1900 Ok(())
1901 }
1902 Statement::Insert {
1903 table_name,
1904 columns,
1905 source,
1906 returning,
1907 } => {
1908 write!(f, "INSERT INTO {table_name} ", table_name = table_name,)?;
1909 if !columns.is_empty() {
1910 write!(f, "({}) ", display_comma_separated(columns))?;
1911 }
1912 write!(f, "{}", source)?;
1913 if !returning.is_empty() {
1914 write!(f, " RETURNING ({})", display_comma_separated(returning))?;
1915 }
1916 Ok(())
1917 }
1918 Statement::Copy { entity, target } => {
1919 write!(f, "COPY ",)?;
1920 match entity {
1921 CopyEntity::Query(query) => {
1922 write!(f, "({})", query)?;
1923 }
1924 CopyEntity::Table {
1925 table_name,
1926 columns,
1927 } => {
1928 write!(f, "{}", table_name)?;
1929 if !columns.is_empty() {
1930 write!(f, " ({})", display_comma_separated(columns))?;
1931 }
1932 }
1933 }
1934
1935 match target {
1936 CopyTarget::Stdin { values } => {
1937 write!(f, " FROM STDIN; ")?;
1938 if !values.is_empty() {
1939 writeln!(f)?;
1940 let mut delim = "";
1941 for v in values {
1942 write!(f, "{}", delim)?;
1943 delim = "\t";
1944 if let Some(v) = v {
1945 write!(f, "{}", v)?;
1946 } else {
1947 write!(f, "\\N")?;
1948 }
1949 }
1950 }
1951 write!(f, "\n\\.")
1952 }
1953 CopyTarget::Stdout => {
1954 write!(f, " TO STDOUT")
1955 }
1956 }
1957 }
1958 Statement::Update {
1959 table_name,
1960 assignments,
1961 selection,
1962 returning,
1963 } => {
1964 write!(f, "UPDATE {}", table_name)?;
1965 if !assignments.is_empty() {
1966 write!(f, " SET {}", display_comma_separated(assignments))?;
1967 }
1968 if let Some(selection) = selection {
1969 write!(f, " WHERE {}", selection)?;
1970 }
1971 if !returning.is_empty() {
1972 write!(f, " RETURNING ({})", display_comma_separated(returning))?;
1973 }
1974 Ok(())
1975 }
1976 Statement::Delete {
1977 table_name,
1978 selection,
1979 returning,
1980 } => {
1981 write!(f, "DELETE FROM {}", table_name)?;
1982 if let Some(selection) = selection {
1983 write!(f, " WHERE {}", selection)?;
1984 }
1985 if !returning.is_empty() {
1986 write!(f, " RETURNING {}", display_comma_separated(returning))?;
1987 }
1988 Ok(())
1989 }
1990 Statement::DeleteMetaSnapshots { snapshot_ids } => {
1991 write!(
1992 f,
1993 "DELETE META SNAPSHOTS {}",
1994 display_comma_separated(snapshot_ids)
1995 )?;
1996 Ok(())
1997 }
1998 Statement::CreateDatabase {
1999 db_name,
2000 if_not_exists,
2001 owner,
2002 resource_group,
2003 barrier_interval_ms,
2004 checkpoint_frequency,
2005 } => {
2006 write!(f, "CREATE DATABASE")?;
2007 if *if_not_exists {
2008 write!(f, " IF NOT EXISTS")?;
2009 }
2010 write!(f, " {}", db_name)?;
2011 if let Some(owner) = owner {
2012 write!(f, " WITH OWNER = {}", owner)?;
2013 }
2014 if let Some(resource_group) = resource_group {
2015 write!(f, " RESOURCE_GROUP = {}", resource_group)?;
2016 }
2017 if let Some(barrier_interval_ms) = barrier_interval_ms {
2018 write!(f, " BARRIER_INTERVAL_MS = {}", barrier_interval_ms)?;
2019 }
2020 if let Some(checkpoint_frequency) = checkpoint_frequency {
2021 write!(f, " CHECKPOINT_FREQUENCY = {}", checkpoint_frequency)?;
2022 }
2023
2024 Ok(())
2025 }
2026 Statement::CreateFunction {
2027 or_replace,
2028 temporary,
2029 if_not_exists,
2030 name,
2031 args,
2032 returns,
2033 params,
2034 with_options,
2035 } => {
2036 write!(
2037 f,
2038 "CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
2039 temp = if *temporary { "TEMPORARY " } else { "" },
2040 or_replace = if *or_replace { "OR REPLACE " } else { "" },
2041 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2042 )?;
2043 if let Some(args) = args {
2044 write!(f, "({})", display_comma_separated(args))?;
2045 }
2046 if let Some(return_type) = returns {
2047 write!(f, " {}", return_type)?;
2048 }
2049 write!(f, "{params}")?;
2050 write!(f, "{with_options}")?;
2051 Ok(())
2052 }
2053 Statement::CreateAggregate {
2054 or_replace,
2055 if_not_exists,
2056 name,
2057 args,
2058 returns,
2059 append_only,
2060 params,
2061 } => {
2062 write!(
2063 f,
2064 "CREATE {or_replace}AGGREGATE {if_not_exists}{name}",
2065 or_replace = if *or_replace { "OR REPLACE " } else { "" },
2066 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2067 )?;
2068 write!(f, "({})", display_comma_separated(args))?;
2069 write!(f, " RETURNS {}", returns)?;
2070 if *append_only {
2071 write!(f, " APPEND ONLY")?;
2072 }
2073 write!(f, "{params}")?;
2074 Ok(())
2075 }
2076 Statement::CreateView {
2077 name,
2078 or_replace,
2079 if_not_exists,
2080 columns,
2081 query,
2082 materialized,
2083 with_options,
2084 emit_mode,
2085 } => {
2086 write!(
2087 f,
2088 "CREATE {or_replace}{materialized}VIEW {if_not_exists}{name}",
2089 or_replace = if *or_replace { "OR REPLACE " } else { "" },
2090 materialized = if *materialized { "MATERIALIZED " } else { "" },
2091 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2092 name = name
2093 )?;
2094 if !with_options.is_empty() {
2095 write!(f, " WITH ({})", display_comma_separated(with_options))?;
2096 }
2097 if !columns.is_empty() {
2098 write!(f, " ({})", display_comma_separated(columns))?;
2099 }
2100 write!(f, " AS {}", query)?;
2101 if let Some(emit_mode) = emit_mode {
2102 write!(f, " EMIT {}", emit_mode)?;
2103 }
2104 Ok(())
2105 }
2106 Statement::CreateTable {
2107 name,
2108 columns,
2109 wildcard_idx,
2110 constraints,
2111 with_options,
2112 or_replace,
2113 if_not_exists,
2114 temporary,
2115 format_encode,
2116 source_watermarks,
2117 append_only,
2118 on_conflict,
2119 with_version_columns,
2120 query,
2121 cdc_table_info,
2122 include_column_options,
2123 webhook_info,
2124 engine,
2125 } => {
2126 write!(
2134 f,
2135 "CREATE {or_replace}{temporary}TABLE {if_not_exists}{name}",
2136 or_replace = if *or_replace { "OR REPLACE " } else { "" },
2137 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2138 temporary = if *temporary { "TEMPORARY " } else { "" },
2139 name = name,
2140 )?;
2141 if !columns.is_empty() || !constraints.is_empty() {
2142 write!(
2143 f,
2144 " {}",
2145 fmt_create_items(columns, constraints, source_watermarks, *wildcard_idx)?
2146 )?;
2147 } else if query.is_none() {
2148 write!(f, " ()")?;
2150 }
2151 if *append_only {
2152 write!(f, " APPEND ONLY")?;
2153 }
2154
2155 if let Some(on_conflict_behavior) = on_conflict {
2156 write!(f, " ON CONFLICT {}", on_conflict_behavior)?;
2157 }
2158 if !with_version_columns.is_empty() {
2159 write!(
2160 f,
2161 " WITH VERSION COLUMN({})",
2162 display_comma_separated(with_version_columns)
2163 )?;
2164 }
2165 if !include_column_options.is_empty() {
2166 write!(f, " {}", display_separated(include_column_options, " "))?;
2167 }
2168 if !with_options.is_empty() {
2169 write!(f, " WITH ({})", display_comma_separated(with_options))?;
2170 }
2171 if let Some(format_encode) = format_encode {
2172 write!(f, " {}", format_encode)?;
2173 }
2174 if let Some(query) = query {
2175 write!(f, " AS {}", query)?;
2176 }
2177 if let Some(info) = cdc_table_info {
2178 write!(f, " FROM {}", info.source_name)?;
2179 write!(
2180 f,
2181 " TABLE '{}'",
2182 value::escape_single_quote_string(&info.external_table_name)
2183 )?;
2184 }
2185 if let Some(info) = webhook_info
2186 && let Some(signature_expr) = &info.signature_expr
2187 {
2188 if let Some(secret) = &info.secret_ref {
2189 write!(f, " VALIDATE SECRET {}", secret.secret_name)?;
2190 } else {
2191 write!(f, " VALIDATE")?;
2192 }
2193 write!(f, " AS {}", signature_expr)?;
2194 }
2195 match engine {
2196 Engine::Hummock => {}
2197 Engine::Iceberg => {
2198 write!(f, " ENGINE = {}", engine)?;
2199 }
2200 }
2201 Ok(())
2202 }
2203 Statement::CreateIndex {
2204 name,
2205 table_name,
2206 columns,
2207 method,
2208 include,
2209 distributed_by,
2210 unique,
2211 if_not_exists,
2212 with_properties,
2213 } => write!(
2214 f,
2215 "CREATE {unique}INDEX {if_not_exists}{name} ON {table_name}{method}({columns}){include}{distributed_by}{with_properties}",
2216 unique = if *unique { "UNIQUE " } else { "" },
2217 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2218 name = name,
2219 table_name = table_name,
2220 method = if let Some(method) = method {
2221 format!(" USING {} ", method)
2222 } else {
2223 "".to_owned()
2224 },
2225 columns = display_comma_separated(columns),
2226 include = if include.is_empty() {
2227 "".to_owned()
2228 } else {
2229 format!(" INCLUDE({})", display_separated(include, ","))
2230 },
2231 distributed_by = if distributed_by.is_empty() {
2232 "".to_owned()
2233 } else {
2234 format!(
2235 " DISTRIBUTED BY({})",
2236 display_separated(distributed_by, ",")
2237 )
2238 },
2239 with_properties = if !with_properties.0.is_empty() {
2240 format!(" {}", with_properties)
2241 } else {
2242 "".to_owned()
2243 },
2244 ),
2245 Statement::CreateSource { stmt } => write!(f, "CREATE SOURCE {}", stmt,),
2246 Statement::CreateSink { stmt } => {
2247 if stmt.or_replace {
2248 write!(f, "REPLACE SINK {}", stmt)
2249 } else {
2250 write!(f, "CREATE SINK {}", stmt)
2251 }
2252 }
2253 Statement::CreateSubscription { stmt } => write!(f, "CREATE SUBSCRIPTION {}", stmt,),
2254 Statement::CreateConnection { stmt } => write!(f, "CREATE CONNECTION {}", stmt,),
2255 Statement::DeclareCursor { stmt } => write!(f, "DECLARE {}", stmt,),
2256 Statement::FetchCursor { stmt } => write!(f, "FETCH {}", stmt),
2257 Statement::CloseCursor { stmt } => write!(f, "CLOSE {}", stmt),
2258 Statement::CreateSecret { stmt } => write!(f, "CREATE SECRET {}", stmt),
2259 Statement::AlterDatabase { name, operation } => {
2260 write!(f, "ALTER DATABASE {} {}", name, operation)
2261 }
2262 Statement::AlterSchema { name, operation } => {
2263 write!(f, "ALTER SCHEMA {} {}", name, operation)
2264 }
2265 Statement::AlterTable { name, operation } => {
2266 write!(f, "ALTER TABLE {} {}", name, operation)
2267 }
2268 Statement::AlterIndex { name, operation } => {
2269 write!(f, "ALTER INDEX {} {}", name, operation)
2270 }
2271 Statement::AlterView {
2272 materialized,
2273 name,
2274 operation,
2275 } => {
2276 write!(
2277 f,
2278 "ALTER {}VIEW {} {}",
2279 if *materialized { "MATERIALIZED " } else { "" },
2280 name,
2281 operation
2282 )
2283 }
2284 Statement::AlterSink { name, operation } => {
2285 write!(f, "ALTER SINK {} {}", name, operation)
2286 }
2287 Statement::AlterSubscription { name, operation } => {
2288 write!(f, "ALTER SUBSCRIPTION {} {}", name, operation)
2289 }
2290 Statement::AlterSource { name, operation } => {
2291 write!(f, "ALTER SOURCE {} {}", name, operation)
2292 }
2293 Statement::AlterFunction {
2294 name,
2295 args,
2296 operation,
2297 } => {
2298 write!(f, "ALTER FUNCTION {}", name)?;
2299 if let Some(args) = args {
2300 write!(f, "({})", display_comma_separated(args))?;
2301 }
2302 write!(f, " {}", operation)
2303 }
2304 Statement::AlterConnection { name, operation } => {
2305 write!(f, "ALTER CONNECTION {} {}", name, operation)
2306 }
2307 Statement::AlterSecret { name, operation } => {
2308 write!(f, "ALTER SECRET {}", name)?;
2309 write!(f, "{}", operation)
2310 }
2311 Statement::Discard(t) => write!(f, "DISCARD {}", t),
2312 Statement::Drop(stmt) => write!(f, "DROP {}", stmt),
2313 Statement::DropFunction {
2314 if_exists,
2315 func_desc,
2316 option,
2317 } => {
2318 write!(
2319 f,
2320 "DROP FUNCTION{} {}",
2321 if *if_exists { " IF EXISTS" } else { "" },
2322 display_comma_separated(func_desc),
2323 )?;
2324 if let Some(op) = option {
2325 write!(f, " {}", op)?;
2326 }
2327 Ok(())
2328 }
2329 Statement::DropAggregate {
2330 if_exists,
2331 func_desc,
2332 option,
2333 } => {
2334 write!(
2335 f,
2336 "DROP AGGREGATE{} {}",
2337 if *if_exists { " IF EXISTS" } else { "" },
2338 display_comma_separated(func_desc),
2339 )?;
2340 if let Some(op) = option {
2341 write!(f, " {}", op)?;
2342 }
2343 Ok(())
2344 }
2345 Statement::SetVariable {
2346 local,
2347 variable,
2348 value,
2349 } => {
2350 f.write_str("SET ")?;
2351 if *local {
2352 f.write_str("LOCAL ")?;
2353 }
2354 write!(f, "{name} = {value}", name = variable,)
2355 }
2356 Statement::ShowVariable { variable } => {
2357 write!(f, "SHOW")?;
2358 if !variable.is_empty() {
2359 write!(f, " {}", display_separated(variable, " "))?;
2360 }
2361 Ok(())
2362 }
2363 Statement::StartTransaction { modes } => {
2364 write!(f, "START TRANSACTION")?;
2365 if !modes.is_empty() {
2366 write!(f, " {}", display_comma_separated(modes))?;
2367 }
2368 Ok(())
2369 }
2370 Statement::Abort => {
2371 write!(f, "ABORT")?;
2372 Ok(())
2373 }
2374 Statement::SetTransaction {
2375 modes,
2376 snapshot,
2377 session,
2378 } => {
2379 if *session {
2380 write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
2381 } else {
2382 write!(f, "SET TRANSACTION")?;
2383 }
2384 if !modes.is_empty() {
2385 write!(f, " {}", display_comma_separated(modes))?;
2386 }
2387 if let Some(snapshot_id) = snapshot {
2388 write!(f, " SNAPSHOT {}", snapshot_id)?;
2389 }
2390 Ok(())
2391 }
2392 Statement::SetTimeZone { local, value } => {
2393 write!(f, "SET")?;
2394 if *local {
2395 write!(f, " LOCAL")?;
2396 }
2397 write!(f, " TIME ZONE {}", value)?;
2398 Ok(())
2399 }
2400 Statement::Commit { chain } => {
2401 write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
2402 }
2403 Statement::Rollback { chain } => {
2404 write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
2405 }
2406 Statement::CreateSchema {
2407 schema_name,
2408 if_not_exists,
2409 owner,
2410 } => {
2411 write!(
2412 f,
2413 "CREATE SCHEMA {if_not_exists}{name}",
2414 if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2415 name = schema_name
2416 )?;
2417 if let Some(user) = owner {
2418 write!(f, " AUTHORIZATION {}", user)?;
2419 }
2420 Ok(())
2421 }
2422 Statement::Grant {
2423 privileges,
2424 objects,
2425 grantees,
2426 with_grant_option,
2427 granted_by,
2428 } => {
2429 write!(f, "GRANT {} ", privileges)?;
2430 write!(f, "ON {} ", objects)?;
2431 write!(f, "TO {}", display_comma_separated(grantees))?;
2432 if *with_grant_option {
2433 write!(f, " WITH GRANT OPTION")?;
2434 }
2435 if let Some(grantor) = granted_by {
2436 write!(f, " GRANTED BY {}", grantor)?;
2437 }
2438 Ok(())
2439 }
2440 Statement::Revoke {
2441 privileges,
2442 objects,
2443 grantees,
2444 granted_by,
2445 revoke_grant_option,
2446 cascade,
2447 } => {
2448 write!(
2449 f,
2450 "REVOKE {}{} ",
2451 if *revoke_grant_option {
2452 "GRANT OPTION FOR "
2453 } else {
2454 ""
2455 },
2456 privileges
2457 )?;
2458 write!(f, "ON {} ", objects)?;
2459 write!(f, "FROM {}", display_comma_separated(grantees))?;
2460 if let Some(grantor) = granted_by {
2461 write!(f, " GRANTED BY {}", grantor)?;
2462 }
2463 write!(f, " {}", if *cascade { "CASCADE" } else { "RESTRICT" })?;
2464 Ok(())
2465 }
2466 Statement::Deallocate { name, prepare } => {
2467 if let Some(name) = name {
2468 write!(
2469 f,
2470 "DEALLOCATE {prepare}{name}",
2471 prepare = if *prepare { "PREPARE " } else { "" },
2472 name = name,
2473 )
2474 } else {
2475 write!(
2476 f,
2477 "DEALLOCATE {prepare}ALL",
2478 prepare = if *prepare { "PREPARE " } else { "" },
2479 )
2480 }
2481 }
2482 Statement::Execute { name, parameters } => {
2483 write!(f, "EXECUTE {}", name)?;
2484 if !parameters.is_empty() {
2485 write!(f, "({})", display_comma_separated(parameters))?;
2486 }
2487 Ok(())
2488 }
2489 Statement::Prepare {
2490 name,
2491 data_types,
2492 statement,
2493 } => {
2494 write!(f, "PREPARE {} ", name)?;
2495 if !data_types.is_empty() {
2496 write!(f, "({}) ", display_comma_separated(data_types))?;
2497 }
2498 write!(f, "AS ")?;
2499 statement.fmt_unchecked(f)
2500 }
2501 Statement::Comment {
2502 object_type,
2503 object_name,
2504 comment,
2505 } => {
2506 write!(f, "COMMENT ON {} {} IS ", object_type, object_name)?;
2507 if let Some(c) = comment {
2508 write!(f, "'{}'", c)
2509 } else {
2510 write!(f, "NULL")
2511 }
2512 }
2513 Statement::CreateUser(statement) => {
2514 write!(f, "CREATE USER {}", statement)
2515 }
2516 Statement::AlterUser(statement) => {
2517 write!(f, "ALTER USER {}", statement)
2518 }
2519 Statement::AlterSystem { param, value } => {
2520 f.write_str("ALTER SYSTEM SET ")?;
2521 write!(f, "{param} = {value}",)
2522 }
2523 Statement::AlterSystemClearFileCache { cache_type } => {
2524 f.write_str("ALTER SYSTEM CLEAR FILE CACHE ")?;
2525 match cache_type {
2526 FileCacheType::Meta => f.write_str("META"),
2527 FileCacheType::Data => f.write_str("DATA"),
2528 FileCacheType::All => f.write_str("ALL"),
2529 }
2530 }
2531 Statement::Flush => {
2532 write!(f, "FLUSH")
2533 }
2534 Statement::Wait(target) => match target {
2535 WaitTarget::All => write!(f, "WAIT"),
2536 WaitTarget::Table(name) => write!(f, "WAIT TABLE {name}"),
2537 WaitTarget::MaterializedView(name) => {
2538 write!(f, "WAIT MATERIALIZED VIEW {name}")
2539 }
2540 WaitTarget::Sink(name) => write!(f, "WAIT SINK {name}"),
2541 WaitTarget::Index(name) => write!(f, "WAIT INDEX {name}"),
2542 },
2543 Statement::Backup => {
2544 write!(f, "BACKUP")?;
2545 Ok(())
2546 }
2547 Statement::Begin { modes } => {
2548 write!(f, "BEGIN")?;
2549 if !modes.is_empty() {
2550 write!(f, " {}", display_comma_separated(modes))?;
2551 }
2552 Ok(())
2553 }
2554 Statement::CancelJobs(jobs) => {
2555 write!(f, "CANCEL JOBS {}", display_comma_separated(&jobs.0))?;
2556 Ok(())
2557 }
2558 Statement::Kill(worker_process_id) => {
2559 write!(f, "KILL '{}'", worker_process_id)?;
2560 Ok(())
2561 }
2562 Statement::Recover => {
2563 write!(f, "RECOVER")?;
2564 Ok(())
2565 }
2566 Statement::Use { db_name } => {
2567 write!(f, "USE {}", db_name)?;
2568 Ok(())
2569 }
2570 Statement::Vacuum { object_name, mode } => match mode {
2571 VacuumMode::Default => write!(f, "VACUUM {}", object_name),
2572 VacuumMode::Full => write!(f, "VACUUM FULL {}", object_name),
2573 VacuumMode::OrphanFiles => write!(f, "VACUUM ORPHAN {}", object_name),
2574 },
2575 Statement::AlterFragment {
2576 fragment_ids,
2577 operation,
2578 } => {
2579 write!(
2580 f,
2581 "ALTER FRAGMENT {} {}",
2582 display_comma_separated(fragment_ids),
2583 operation
2584 )
2585 }
2586 Statement::AlterCompactionGroup {
2587 group_ids,
2588 operation,
2589 } => {
2590 write!(
2591 f,
2592 "ALTER COMPACTION GROUP {} {}",
2593 display_comma_separated(group_ids),
2594 operation
2595 )
2596 }
2597 Statement::AlterDefaultPrivileges {
2598 target_users,
2599 schema_names,
2600 operation,
2601 } => {
2602 write!(f, "ALTER DEFAULT PRIVILEGES")?;
2603 if let Some(target_users) = target_users {
2604 write!(f, " FOR {}", display_comma_separated(target_users))?;
2605 }
2606 if let Some(schema_names) = schema_names {
2607 write!(f, " IN SCHEMA {}", display_comma_separated(schema_names))?;
2608 }
2609 write!(f, " {}", operation)
2610 }
2611 }
2612 }
2613
2614 pub fn is_create(&self) -> bool {
2615 matches!(
2616 self,
2617 Statement::CreateTable { .. }
2618 | Statement::CreateView { .. }
2619 | Statement::CreateSource { .. }
2620 | Statement::CreateSink { .. }
2621 | Statement::CreateSubscription { .. }
2622 | Statement::CreateConnection { .. }
2623 | Statement::CreateSecret { .. }
2624 | Statement::CreateUser { .. }
2625 | Statement::CreateDatabase { .. }
2626 | Statement::CreateFunction { .. }
2627 | Statement::CreateAggregate { .. }
2628 | Statement::CreateIndex { .. }
2629 | Statement::CreateSchema { .. }
2630 )
2631 }
2632}
2633
2634impl Display for IncludeOptionItem {
2635 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2636 let Self {
2637 column_type,
2638 inner_field,
2639 header_inner_expect_type,
2640 column_alias,
2641 } = self;
2642 write!(f, "INCLUDE {}", column_type)?;
2643 if let Some(inner_field) = inner_field {
2644 write!(f, " '{}'", value::escape_single_quote_string(inner_field))?;
2645 if let Some(expected_type) = header_inner_expect_type {
2646 write!(f, " {}", expected_type)?;
2647 }
2648 }
2649 if let Some(alias) = column_alias {
2650 write!(f, " AS {}", alias)?;
2651 }
2652 Ok(())
2653 }
2654}
2655
2656#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2657#[non_exhaustive]
2658pub enum OnInsert {
2659 DuplicateKeyUpdate(Vec<Assignment>),
2661}
2662
2663impl fmt::Display for OnInsert {
2664 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2665 match self {
2666 Self::DuplicateKeyUpdate(expr) => write!(
2667 f,
2668 " ON DUPLICATE KEY UPDATE {}",
2669 display_comma_separated(expr)
2670 ),
2671 }
2672 }
2673}
2674
2675#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2677pub enum Privileges {
2678 All {
2680 with_privileges_keyword: bool,
2682 },
2683 Actions(Vec<Action>),
2685}
2686
2687impl fmt::Display for Privileges {
2688 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2689 match self {
2690 Privileges::All {
2691 with_privileges_keyword,
2692 } => {
2693 write!(
2694 f,
2695 "ALL{}",
2696 if *with_privileges_keyword {
2697 " PRIVILEGES"
2698 } else {
2699 ""
2700 }
2701 )
2702 }
2703 Privileges::Actions(actions) => {
2704 write!(f, "{}", display_comma_separated(actions))
2705 }
2706 }
2707 }
2708}
2709
2710#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2712pub enum Action {
2713 Connect,
2714 Create,
2715 Delete,
2716 Execute,
2717 Insert { columns: Option<Vec<Ident>> },
2718 References { columns: Option<Vec<Ident>> },
2719 Select { columns: Option<Vec<Ident>> },
2720 Temporary,
2721 Trigger,
2722 Truncate,
2723 Update { columns: Option<Vec<Ident>> },
2724 Usage,
2725}
2726
2727impl fmt::Display for Action {
2728 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2729 match self {
2730 Action::Connect => f.write_str("CONNECT")?,
2731 Action::Create => f.write_str("CREATE")?,
2732 Action::Delete => f.write_str("DELETE")?,
2733 Action::Execute => f.write_str("EXECUTE")?,
2734 Action::Insert { .. } => f.write_str("INSERT")?,
2735 Action::References { .. } => f.write_str("REFERENCES")?,
2736 Action::Select { .. } => f.write_str("SELECT")?,
2737 Action::Temporary => f.write_str("TEMPORARY")?,
2738 Action::Trigger => f.write_str("TRIGGER")?,
2739 Action::Truncate => f.write_str("TRUNCATE")?,
2740 Action::Update { .. } => f.write_str("UPDATE")?,
2741 Action::Usage => f.write_str("USAGE")?,
2742 };
2743 match self {
2744 Action::Insert { columns }
2745 | Action::References { columns }
2746 | Action::Select { columns }
2747 | Action::Update { columns } => {
2748 if let Some(columns) = columns {
2749 write!(f, " ({})", display_comma_separated(columns))?;
2750 }
2751 }
2752 _ => (),
2753 };
2754 Ok(())
2755 }
2756}
2757
2758#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2760pub enum GrantObjects {
2761 AllSequencesInSchema { schemas: Vec<ObjectName> },
2763 AllTablesInSchema { schemas: Vec<ObjectName> },
2765 AllSourcesInSchema { schemas: Vec<ObjectName> },
2767 AllSinksInSchema { schemas: Vec<ObjectName> },
2769 AllMviewsInSchema { schemas: Vec<ObjectName> },
2771 AllViewsInSchema { schemas: Vec<ObjectName> },
2773 AllFunctionsInSchema { schemas: Vec<ObjectName> },
2775 AllSecretsInSchema { schemas: Vec<ObjectName> },
2777 AllSubscriptionsInSchema { schemas: Vec<ObjectName> },
2779 AllConnectionsInSchema { schemas: Vec<ObjectName> },
2781 Databases(Vec<ObjectName>),
2783 Schemas(Vec<ObjectName>),
2785 Sources(Vec<ObjectName>),
2787 Mviews(Vec<ObjectName>),
2789 Sequences(Vec<ObjectName>),
2791 Tables(Vec<ObjectName>),
2793 Sinks(Vec<ObjectName>),
2795 Views(Vec<ObjectName>),
2797 Connections(Vec<ObjectName>),
2799 Subscriptions(Vec<ObjectName>),
2801 Functions(Vec<FunctionDesc>),
2803 Secrets(Vec<ObjectName>),
2805}
2806
2807impl fmt::Display for GrantObjects {
2808 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2809 match self {
2810 GrantObjects::Sequences(sequences) => {
2811 write!(f, "SEQUENCE {}", display_comma_separated(sequences))
2812 }
2813 GrantObjects::Schemas(schemas) => {
2814 write!(f, "SCHEMA {}", display_comma_separated(schemas))
2815 }
2816 GrantObjects::Tables(tables) => {
2817 write!(f, "{}", display_comma_separated(tables))
2818 }
2819 GrantObjects::AllSequencesInSchema { schemas } => {
2820 write!(
2821 f,
2822 "ALL SEQUENCES IN SCHEMA {}",
2823 display_comma_separated(schemas)
2824 )
2825 }
2826 GrantObjects::AllTablesInSchema { schemas } => {
2827 write!(
2828 f,
2829 "ALL TABLES IN SCHEMA {}",
2830 display_comma_separated(schemas)
2831 )
2832 }
2833 GrantObjects::AllSourcesInSchema { schemas } => {
2834 write!(
2835 f,
2836 "ALL SOURCES IN SCHEMA {}",
2837 display_comma_separated(schemas)
2838 )
2839 }
2840 GrantObjects::AllMviewsInSchema { schemas } => {
2841 write!(
2842 f,
2843 "ALL MATERIALIZED VIEWS IN SCHEMA {}",
2844 display_comma_separated(schemas)
2845 )
2846 }
2847 GrantObjects::AllSinksInSchema { schemas } => {
2848 write!(
2849 f,
2850 "ALL SINKS IN SCHEMA {}",
2851 display_comma_separated(schemas)
2852 )
2853 }
2854 GrantObjects::AllViewsInSchema { schemas } => {
2855 write!(
2856 f,
2857 "ALL VIEWS IN SCHEMA {}",
2858 display_comma_separated(schemas)
2859 )
2860 }
2861 GrantObjects::AllFunctionsInSchema { schemas } => {
2862 write!(
2863 f,
2864 "ALL FUNCTIONS IN SCHEMA {}",
2865 display_comma_separated(schemas)
2866 )
2867 }
2868 GrantObjects::AllSecretsInSchema { schemas } => {
2869 write!(
2870 f,
2871 "ALL SECRETS IN SCHEMA {}",
2872 display_comma_separated(schemas)
2873 )
2874 }
2875 GrantObjects::AllSubscriptionsInSchema { schemas } => {
2876 write!(
2877 f,
2878 "ALL SUBSCRIPTIONS IN SCHEMA {}",
2879 display_comma_separated(schemas)
2880 )
2881 }
2882 GrantObjects::AllConnectionsInSchema { schemas } => {
2883 write!(
2884 f,
2885 "ALL CONNECTIONS IN SCHEMA {}",
2886 display_comma_separated(schemas)
2887 )
2888 }
2889 GrantObjects::Databases(databases) => {
2890 write!(f, "DATABASE {}", display_comma_separated(databases))
2891 }
2892 GrantObjects::Sources(sources) => {
2893 write!(f, "SOURCE {}", display_comma_separated(sources))
2894 }
2895 GrantObjects::Mviews(mviews) => {
2896 write!(f, "MATERIALIZED VIEW {}", display_comma_separated(mviews))
2897 }
2898 GrantObjects::Sinks(sinks) => {
2899 write!(f, "SINK {}", display_comma_separated(sinks))
2900 }
2901 GrantObjects::Views(views) => {
2902 write!(f, "VIEW {}", display_comma_separated(views))
2903 }
2904 GrantObjects::Connections(connections) => {
2905 write!(f, "CONNECTION {}", display_comma_separated(connections))
2906 }
2907 GrantObjects::Subscriptions(subscriptions) => {
2908 write!(f, "SUBSCRIPTION {}", display_comma_separated(subscriptions))
2909 }
2910 GrantObjects::Functions(func_descs) => {
2911 write!(f, "FUNCTION {}", display_comma_separated(func_descs))
2912 }
2913 GrantObjects::Secrets(secrets) => {
2914 write!(f, "SECRET {}", display_comma_separated(secrets))
2915 }
2916 }
2917 }
2918}
2919
2920#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2921pub enum PrivilegeObjectType {
2922 Tables,
2923 Sources,
2924 Sinks,
2925 Mviews,
2926 Views,
2927 Functions,
2928 Connections,
2929 Secrets,
2930 Subscriptions,
2931 Schemas,
2932}
2933
2934impl fmt::Display for PrivilegeObjectType {
2935 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2936 match self {
2937 PrivilegeObjectType::Tables => f.write_str("TABLES")?,
2938 PrivilegeObjectType::Sources => f.write_str("SOURCES")?,
2939 PrivilegeObjectType::Sinks => f.write_str("SINKS")?,
2940 PrivilegeObjectType::Mviews => f.write_str("MATERIALIZED VIEWS")?,
2941 PrivilegeObjectType::Views => f.write_str("VIEWS")?,
2942 PrivilegeObjectType::Functions => f.write_str("FUNCTIONS")?,
2943 PrivilegeObjectType::Connections => f.write_str("CONNECTIONS")?,
2944 PrivilegeObjectType::Secrets => f.write_str("SECRETS")?,
2945 PrivilegeObjectType::Subscriptions => f.write_str("SUBSCRIPTIONS")?,
2946 PrivilegeObjectType::Schemas => f.write_str("SCHEMAS")?,
2947 };
2948 Ok(())
2949 }
2950}
2951
2952#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2953pub enum DefaultPrivilegeOperation {
2954 Grant {
2955 privileges: Privileges,
2956 object_type: PrivilegeObjectType,
2957 grantees: Vec<Ident>,
2958 with_grant_option: bool,
2959 },
2960 Revoke {
2961 privileges: Privileges,
2962 object_type: PrivilegeObjectType,
2963 grantees: Vec<Ident>,
2964 revoke_grant_option: bool,
2965 cascade: bool,
2966 },
2967}
2968
2969impl fmt::Display for DefaultPrivilegeOperation {
2970 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2971 match self {
2972 DefaultPrivilegeOperation::Grant {
2973 privileges,
2974 object_type,
2975 grantees,
2976 with_grant_option,
2977 } => {
2978 write!(
2979 f,
2980 "GRANT {} ON {} TO {}",
2981 privileges,
2982 object_type,
2983 display_comma_separated(grantees)
2984 )?;
2985 if *with_grant_option {
2986 write!(f, " WITH GRANT OPTION")?;
2987 }
2988 }
2989 DefaultPrivilegeOperation::Revoke {
2990 privileges,
2991 object_type,
2992 grantees,
2993 revoke_grant_option,
2994 cascade,
2995 } => {
2996 write!(f, "REVOKE")?;
2997 if *revoke_grant_option {
2998 write!(f, " GRANT OPTION FOR")?;
2999 }
3000 write!(
3001 f,
3002 " {} ON {} FROM {}",
3003 privileges,
3004 object_type,
3005 display_comma_separated(grantees)
3006 )?;
3007 write!(f, " {}", if *cascade { "CASCADE" } else { "RESTRICT" })?;
3008 }
3009 }
3010 Ok(())
3011 }
3012}
3013
3014impl DefaultPrivilegeOperation {
3015 pub fn for_schemas(&self) -> bool {
3016 match &self {
3017 DefaultPrivilegeOperation::Grant { object_type, .. } => {
3018 object_type == &PrivilegeObjectType::Schemas
3019 }
3020 DefaultPrivilegeOperation::Revoke { object_type, .. } => {
3021 object_type == &PrivilegeObjectType::Schemas
3022 }
3023 }
3024 }
3025}
3026
3027#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3028pub enum AssignmentValue {
3029 Expr(Expr),
3031 Default,
3033}
3034
3035impl fmt::Display for AssignmentValue {
3036 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3037 match self {
3038 AssignmentValue::Expr(expr) => write!(f, "{}", expr),
3039 AssignmentValue::Default => f.write_str("DEFAULT"),
3040 }
3041 }
3042}
3043
3044#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3046pub struct Assignment {
3047 pub id: Vec<Ident>,
3048 pub value: AssignmentValue,
3049}
3050
3051impl fmt::Display for Assignment {
3052 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3053 write!(f, "{} = {}", display_separated(&self.id, "."), self.value)
3054 }
3055}
3056
3057#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3058pub enum FunctionArgExpr {
3059 Expr(Expr),
3060 ExprQualifiedWildcard(Expr, Vec<Ident>),
3064 QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
3067 Wildcard(Option<Vec<Expr>>),
3069 SecretRef(SecretRefValue),
3071}
3072
3073impl fmt::Display for FunctionArgExpr {
3074 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3075 match self {
3076 FunctionArgExpr::Expr(expr) => write!(f, "{}", expr),
3077 FunctionArgExpr::ExprQualifiedWildcard(expr, prefix) => {
3078 write!(
3079 f,
3080 "({}){}.*",
3081 expr,
3082 prefix
3083 .iter()
3084 .format_with("", |i, f| f(&format_args!(".{i}")))
3085 )
3086 }
3087 FunctionArgExpr::QualifiedWildcard(prefix, except) => match except {
3088 Some(exprs) => write!(
3089 f,
3090 "{}.* EXCEPT ({})",
3091 prefix,
3092 exprs
3093 .iter()
3094 .map(|v| v.to_string())
3095 .collect::<Vec<String>>()
3096 .as_slice()
3097 .join(", ")
3098 ),
3099 None => write!(f, "{}.*", prefix),
3100 },
3101
3102 FunctionArgExpr::SecretRef(secret_ref) => write!(f, "SECRET {}", secret_ref),
3103 FunctionArgExpr::Wildcard(except) => match except {
3104 Some(exprs) => write!(
3105 f,
3106 "* EXCEPT ({})",
3107 exprs
3108 .iter()
3109 .map(|v| v.to_string())
3110 .collect::<Vec<String>>()
3111 .as_slice()
3112 .join(", ")
3113 ),
3114 None => f.write_str("*"),
3115 },
3116 }
3117 }
3118}
3119
3120#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3121pub enum FunctionArg {
3122 Named { name: Ident, arg: FunctionArgExpr },
3123 Unnamed(FunctionArgExpr),
3124}
3125
3126impl FunctionArg {
3127 pub fn get_expr(&self) -> FunctionArgExpr {
3128 match self {
3129 FunctionArg::Named { name: _, arg } => arg.clone(),
3130 FunctionArg::Unnamed(arg) => arg.clone(),
3131 }
3132 }
3133}
3134
3135impl fmt::Display for FunctionArg {
3136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3137 match self {
3138 FunctionArg::Named { name, arg } => write!(f, "{} => {}", name, arg),
3139 FunctionArg::Unnamed(unnamed_arg) => write!(f, "{}", unnamed_arg),
3140 }
3141 }
3142}
3143
3144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3147pub struct FunctionArgList {
3148 pub distinct: bool,
3150 pub args: Vec<FunctionArg>,
3151 pub variadic: bool,
3153 pub order_by: Vec<OrderByExpr>,
3155 pub ignore_nulls: bool,
3157}
3158
3159impl fmt::Display for FunctionArgList {
3160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3161 write!(f, "(")?;
3162 if self.distinct {
3163 write!(f, "DISTINCT ")?;
3164 }
3165 if self.variadic {
3166 for arg in &self.args[0..self.args.len() - 1] {
3167 write!(f, "{}, ", arg)?;
3168 }
3169 write!(f, "VARIADIC {}", self.args.last().unwrap())?;
3170 } else {
3171 write!(f, "{}", display_comma_separated(&self.args))?;
3172 }
3173 if !self.order_by.is_empty() {
3174 write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
3175 }
3176 if self.ignore_nulls {
3177 write!(f, " IGNORE NULLS")?;
3178 }
3179 write!(f, ")")?;
3180 Ok(())
3181 }
3182}
3183
3184impl FunctionArgList {
3185 pub fn empty() -> Self {
3186 Self {
3187 distinct: false,
3188 args: vec![],
3189 variadic: false,
3190 order_by: vec![],
3191 ignore_nulls: false,
3192 }
3193 }
3194
3195 pub fn args_only(args: Vec<FunctionArg>) -> Self {
3196 Self {
3197 distinct: false,
3198 args,
3199 variadic: false,
3200 order_by: vec![],
3201 ignore_nulls: false,
3202 }
3203 }
3204
3205 pub fn is_args_only(&self) -> bool {
3206 !self.distinct && !self.variadic && self.order_by.is_empty() && !self.ignore_nulls
3207 }
3208
3209 pub fn for_agg(distinct: bool, args: Vec<FunctionArg>, order_by: Vec<OrderByExpr>) -> Self {
3210 Self {
3211 distinct,
3212 args,
3213 variadic: false,
3214 order_by,
3215 ignore_nulls: false,
3216 }
3217 }
3218}
3219
3220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3222pub struct Function {
3223 pub scalar_as_agg: bool,
3225 pub name: ObjectName,
3227 pub arg_list: FunctionArgList,
3229 pub within_group: Option<Box<OrderByExpr>>,
3232 pub filter: Option<Box<Expr>>,
3234 pub over: Option<Window>,
3236}
3237
3238impl Function {
3239 pub fn no_arg(name: ObjectName) -> Self {
3240 Self {
3241 scalar_as_agg: false,
3242 name,
3243 arg_list: FunctionArgList::empty(),
3244 within_group: None,
3245 filter: None,
3246 over: None,
3247 }
3248 }
3249}
3250
3251impl fmt::Display for Function {
3252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3253 if self.scalar_as_agg {
3254 write!(f, "AGGREGATE:")?;
3255 }
3256 write!(f, "{}{}", self.name, self.arg_list)?;
3257 if let Some(within_group) = &self.within_group {
3258 write!(f, " WITHIN GROUP (ORDER BY {})", within_group)?;
3259 }
3260 if let Some(filter) = &self.filter {
3261 write!(f, " FILTER (WHERE {})", filter)?;
3262 }
3263 if let Some(o) = &self.over {
3264 write!(f, " OVER {}", o)?;
3265 }
3266 Ok(())
3267 }
3268}
3269
3270#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3271pub enum ObjectType {
3272 Table,
3273 View,
3274 MaterializedView,
3275 Index,
3276 Schema,
3277 Source,
3278 Sink,
3279 Database,
3280 User,
3281 Connection,
3282 Secret,
3283 Subscription,
3284}
3285
3286impl fmt::Display for ObjectType {
3287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3288 f.write_str(match self {
3289 ObjectType::Table => "TABLE",
3290 ObjectType::View => "VIEW",
3291 ObjectType::MaterializedView => "MATERIALIZED VIEW",
3292 ObjectType::Index => "INDEX",
3293 ObjectType::Schema => "SCHEMA",
3294 ObjectType::Source => "SOURCE",
3295 ObjectType::Sink => "SINK",
3296 ObjectType::Database => "DATABASE",
3297 ObjectType::User => "USER",
3298 ObjectType::Secret => "SECRET",
3299 ObjectType::Connection => "CONNECTION",
3300 ObjectType::Subscription => "SUBSCRIPTION",
3301 })
3302 }
3303}
3304
3305impl ParseTo for ObjectType {
3306 fn parse_to(parser: &mut Parser<'_>) -> ModalResult<Self> {
3307 let object_type = if parser.parse_keyword(Keyword::TABLE) {
3308 ObjectType::Table
3309 } else if parser.parse_keyword(Keyword::VIEW) {
3310 ObjectType::View
3311 } else if parser.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEW]) {
3312 ObjectType::MaterializedView
3313 } else if parser.parse_keyword(Keyword::SOURCE) {
3314 ObjectType::Source
3315 } else if parser.parse_keyword(Keyword::SINK) {
3316 ObjectType::Sink
3317 } else if parser.parse_keyword(Keyword::INDEX) {
3318 ObjectType::Index
3319 } else if parser.parse_keyword(Keyword::SCHEMA) {
3320 ObjectType::Schema
3321 } else if parser.parse_keyword(Keyword::DATABASE) {
3322 ObjectType::Database
3323 } else if parser.parse_keyword(Keyword::USER) {
3324 ObjectType::User
3325 } else if parser.parse_keyword(Keyword::CONNECTION) {
3326 ObjectType::Connection
3327 } else if parser.parse_keyword(Keyword::SECRET) {
3328 ObjectType::Secret
3329 } else if parser.parse_keyword(Keyword::SUBSCRIPTION) {
3330 ObjectType::Subscription
3331 } else {
3332 return parser.expected(
3333 "TABLE, VIEW, INDEX, MATERIALIZED VIEW, SOURCE, SINK, SUBSCRIPTION, SCHEMA, DATABASE, USER, SECRET or CONNECTION after DROP",
3334 );
3335 };
3336 Ok(object_type)
3337 }
3338}
3339
3340#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3341pub struct SqlOption {
3342 pub name: ObjectName,
3343 pub value: SqlOptionValue,
3344}
3345
3346impl SqlOption {
3347 pub fn from_secret_ref(name: &str, secret_ref: SecretRefValue) -> Self {
3349 Self {
3350 name: ObjectName(name.split('.').map(Ident::from_real_value).collect()),
3351 value: SqlOptionValue::SecretRef(secret_ref),
3352 }
3353 }
3354}
3355
3356impl fmt::Display for SqlOption {
3357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3358 let should_redact = SQL_OPTION_REDACTION
3359 .try_with(|redaction| {
3360 let sql_option_name = self.name.real_value().to_lowercase();
3361 !redaction.allowlist.contains(&sql_option_name)
3362 && redaction
3363 .keywords
3364 .iter()
3365 .any(|k| sql_option_name.contains(k))
3366 })
3367 .unwrap_or(false);
3368 if should_redact {
3369 write!(f, "{} = [REDACTED]", self.name)
3370 } else {
3371 write!(f, "{} = {}", self.name, self.value)
3372 }
3373 }
3374}
3375
3376impl TryFrom<(&String, &String)> for SqlOption {
3377 type Error = ParserError;
3378
3379 fn try_from((name, value): (&String, &String)) -> Result<Self, Self::Error> {
3380 let name_parts: Vec<&str> = name.split('.').collect();
3384 let object_name = ObjectName(name_parts.into_iter().map(Ident::from_real_value).collect());
3385
3386 let escaped_value = value.replace('\'', "''");
3390 let query = format!("{} = '{}'", object_name, escaped_value);
3391 let mut tokenizer = Tokenizer::new(query.as_str());
3392 let tokens = tokenizer.tokenize_with_location()?;
3393 let mut parser = Parser(&tokens);
3394 parser
3395 .parse_sql_option()
3396 .map_err(|e| ParserError::ParserError(e.to_string()))
3397 }
3398}
3399
3400#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3401pub enum SqlOptionValue {
3402 Value(Value),
3403 SecretRef(SecretRefValue),
3404 ConnectionRef(ConnectionRefValue),
3405 BackfillOrder(BackfillOrderStrategy),
3406}
3407
3408impl SqlOptionValue {
3409 pub const fn null() -> Self {
3411 Self::Value(Value::Null)
3412 }
3413}
3414
3415impl fmt::Display for SqlOptionValue {
3416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3417 match self {
3418 SqlOptionValue::Value(value) => write!(f, "{}", value),
3419 SqlOptionValue::SecretRef(secret_ref) => write!(f, "secret {}", secret_ref),
3420 SqlOptionValue::ConnectionRef(connection_ref) => {
3421 write!(f, "{}", connection_ref)
3422 }
3423 SqlOptionValue::BackfillOrder(order) => {
3424 write!(f, "{}", order)
3425 }
3426 }
3427 }
3428}
3429
3430impl From<Value> for SqlOptionValue {
3431 fn from(value: Value) -> Self {
3432 SqlOptionValue::Value(value)
3433 }
3434}
3435
3436#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3437pub enum EmitMode {
3438 Immediately,
3439 OnWindowClose,
3440}
3441
3442impl fmt::Display for EmitMode {
3443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3444 f.write_str(match self {
3445 EmitMode::Immediately => "IMMEDIATELY",
3446 EmitMode::OnWindowClose => "ON WINDOW CLOSE",
3447 })
3448 }
3449}
3450
3451#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3452pub enum OnConflict {
3453 UpdateFull,
3454 Nothing,
3455 UpdateIfNotNull,
3456}
3457
3458impl fmt::Display for OnConflict {
3459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3460 f.write_str(match self {
3461 OnConflict::UpdateFull => "DO UPDATE FULL",
3462 OnConflict::Nothing => "DO NOTHING",
3463 OnConflict::UpdateIfNotNull => "DO UPDATE IF NOT NULL",
3464 })
3465 }
3466}
3467
3468#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3469pub enum Engine {
3470 Hummock,
3471 Iceberg,
3472}
3473
3474impl fmt::Display for crate::ast::Engine {
3475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3476 f.write_str(match self {
3477 crate::ast::Engine::Hummock => "HUMMOCK",
3478 crate::ast::Engine::Iceberg => "ICEBERG",
3479 })
3480 }
3481}
3482
3483#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3484pub enum SetTimeZoneValue {
3485 Ident(Ident),
3486 Literal(Value),
3487 Local,
3488 Default,
3489}
3490
3491impl fmt::Display for SetTimeZoneValue {
3492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3493 match self {
3494 SetTimeZoneValue::Ident(ident) => write!(f, "{}", ident),
3495 SetTimeZoneValue::Literal(value) => write!(f, "{}", value),
3496 SetTimeZoneValue::Local => f.write_str("LOCAL"),
3497 SetTimeZoneValue::Default => f.write_str("DEFAULT"),
3498 }
3499 }
3500}
3501
3502#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3503pub enum TransactionMode {
3504 AccessMode(TransactionAccessMode),
3505 IsolationLevel(TransactionIsolationLevel),
3506}
3507
3508impl fmt::Display for TransactionMode {
3509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3510 use TransactionMode::*;
3511 match self {
3512 AccessMode(access_mode) => write!(f, "{}", access_mode),
3513 IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
3514 }
3515 }
3516}
3517
3518#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3519pub enum TransactionAccessMode {
3520 ReadOnly,
3521 ReadWrite,
3522}
3523
3524impl fmt::Display for TransactionAccessMode {
3525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3526 use TransactionAccessMode::*;
3527 f.write_str(match self {
3528 ReadOnly => "READ ONLY",
3529 ReadWrite => "READ WRITE",
3530 })
3531 }
3532}
3533
3534#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3535pub enum TransactionIsolationLevel {
3536 ReadUncommitted,
3537 ReadCommitted,
3538 RepeatableRead,
3539 Serializable,
3540}
3541
3542impl fmt::Display for TransactionIsolationLevel {
3543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3544 use TransactionIsolationLevel::*;
3545 f.write_str(match self {
3546 ReadUncommitted => "READ UNCOMMITTED",
3547 ReadCommitted => "READ COMMITTED",
3548 RepeatableRead => "REPEATABLE READ",
3549 Serializable => "SERIALIZABLE",
3550 })
3551 }
3552}
3553
3554#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3555pub enum ShowStatementFilter {
3556 Like(String),
3557 ILike(String),
3558 Where(Expr),
3559}
3560
3561impl fmt::Display for ShowStatementFilter {
3562 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3563 use ShowStatementFilter::*;
3564 match self {
3565 Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
3566 ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)),
3567 Where(expr) => write!(f, "WHERE {}", expr),
3568 }
3569 }
3570}
3571
3572#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3574pub enum DropFunctionOption {
3575 Restrict,
3576 Cascade,
3577}
3578
3579impl fmt::Display for DropFunctionOption {
3580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3581 match self {
3582 DropFunctionOption::Restrict => write!(f, "RESTRICT "),
3583 DropFunctionOption::Cascade => write!(f, "CASCADE "),
3584 }
3585 }
3586}
3587
3588#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3590pub struct FunctionDesc {
3591 pub name: ObjectName,
3592 pub args: Option<Vec<OperateFunctionArg>>,
3593}
3594
3595impl fmt::Display for FunctionDesc {
3596 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3597 write!(f, "{}", self.name)?;
3598 if let Some(args) = &self.args {
3599 write!(f, "({})", display_comma_separated(args))?;
3600 }
3601 Ok(())
3602 }
3603}
3604
3605#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3607pub struct OperateFunctionArg {
3608 pub mode: Option<ArgMode>,
3609 pub name: Option<Ident>,
3610 pub data_type: DataType,
3611 pub default_expr: Option<Expr>,
3612}
3613
3614impl OperateFunctionArg {
3615 pub fn unnamed(data_type: DataType) -> Self {
3617 Self {
3618 mode: None,
3619 name: None,
3620 data_type,
3621 default_expr: None,
3622 }
3623 }
3624
3625 pub fn with_name(name: &str, data_type: DataType) -> Self {
3627 Self {
3628 mode: None,
3629 name: Some(name.into()),
3630 data_type,
3631 default_expr: None,
3632 }
3633 }
3634}
3635
3636impl fmt::Display for OperateFunctionArg {
3637 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3638 if let Some(mode) = &self.mode {
3639 write!(f, "{} ", mode)?;
3640 }
3641 if let Some(name) = &self.name {
3642 write!(f, "{} ", name)?;
3643 }
3644 write!(f, "{}", self.data_type)?;
3645 if let Some(default_expr) = &self.default_expr {
3646 write!(f, " = {}", default_expr)?;
3647 }
3648 Ok(())
3649 }
3650}
3651
3652#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3654pub enum ArgMode {
3655 In,
3656 Out,
3657 InOut,
3658}
3659
3660impl fmt::Display for ArgMode {
3661 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3662 match self {
3663 ArgMode::In => write!(f, "IN"),
3664 ArgMode::Out => write!(f, "OUT"),
3665 ArgMode::InOut => write!(f, "INOUT"),
3666 }
3667 }
3668}
3669
3670#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3672pub enum FunctionBehavior {
3673 Immutable,
3674 Stable,
3675 Volatile,
3676}
3677
3678impl fmt::Display for FunctionBehavior {
3679 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3680 match self {
3681 FunctionBehavior::Immutable => write!(f, "IMMUTABLE"),
3682 FunctionBehavior::Stable => write!(f, "STABLE"),
3683 FunctionBehavior::Volatile => write!(f, "VOLATILE"),
3684 }
3685 }
3686}
3687
3688#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3689pub enum FunctionDefinition {
3690 Identifier(String),
3691 SingleQuotedDef(String),
3692 DoubleDollarDef(String),
3693}
3694
3695impl fmt::Display for FunctionDefinition {
3696 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3697 match self {
3698 FunctionDefinition::Identifier(s) => write!(f, "{s}")?,
3699 FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
3700 FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
3701 }
3702 Ok(())
3703 }
3704}
3705
3706impl FunctionDefinition {
3707 pub fn as_str(&self) -> &str {
3709 match self {
3710 FunctionDefinition::Identifier(s) => s,
3711 FunctionDefinition::SingleQuotedDef(s) => s,
3712 FunctionDefinition::DoubleDollarDef(s) => s,
3713 }
3714 }
3715
3716 pub fn into_string(self) -> String {
3718 match self {
3719 FunctionDefinition::Identifier(s) => s,
3720 FunctionDefinition::SingleQuotedDef(s) => s,
3721 FunctionDefinition::DoubleDollarDef(s) => s,
3722 }
3723 }
3724}
3725
3726#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3728pub enum CreateFunctionReturns {
3729 Value(DataType),
3731 Table(Vec<TableColumnDef>),
3733}
3734
3735impl fmt::Display for CreateFunctionReturns {
3736 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3737 match self {
3738 Self::Value(data_type) => write!(f, "RETURNS {}", data_type),
3739 Self::Table(columns) => {
3740 write!(f, "RETURNS TABLE ({})", display_comma_separated(columns))
3741 }
3742 }
3743 }
3744}
3745
3746#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3748pub struct TableColumnDef {
3749 pub name: Ident,
3750 pub data_type: DataType,
3751}
3752
3753impl fmt::Display for TableColumnDef {
3754 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3755 write!(f, "{} {}", self.name, self.data_type)
3756 }
3757}
3758
3759#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
3764pub struct CreateFunctionBody {
3765 pub language: Option<Ident>,
3767 pub runtime: Option<Ident>,
3769
3770 pub behavior: Option<FunctionBehavior>,
3772 pub as_: Option<FunctionDefinition>,
3776 pub return_: Option<Expr>,
3778 pub using: Option<CreateFunctionUsing>,
3780}
3781
3782impl fmt::Display for CreateFunctionBody {
3783 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3784 if let Some(language) = &self.language {
3785 write!(f, " LANGUAGE {language}")?;
3786 }
3787 if let Some(runtime) = &self.runtime {
3788 write!(f, " RUNTIME {runtime}")?;
3789 }
3790 if let Some(behavior) = &self.behavior {
3791 write!(f, " {behavior}")?;
3792 }
3793 if let Some(definition) = &self.as_ {
3794 write!(f, " AS {definition}")?;
3795 }
3796 if let Some(expr) = &self.return_ {
3797 write!(f, " RETURN {expr}")?;
3798 }
3799 if let Some(using) = &self.using {
3800 write!(f, " {using}")?;
3801 }
3802 Ok(())
3803 }
3804}
3805
3806#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
3807pub struct CreateFunctionWithOptions {
3808 pub always_retry_on_network_error: Option<bool>,
3810 pub r#async: Option<bool>,
3812 pub batch: Option<bool>,
3814}
3815
3816impl TryFrom<Vec<SqlOption>> for CreateFunctionWithOptions {
3818 type Error = StrError;
3819
3820 fn try_from(with_options: Vec<SqlOption>) -> Result<Self, Self::Error> {
3821 let mut options = Self::default();
3822 for option in with_options {
3823 match option.name.to_string().to_lowercase().as_str() {
3824 "always_retry_on_network_error" => {
3825 options.always_retry_on_network_error = Some(matches!(
3826 option.value,
3827 SqlOptionValue::Value(Value::Boolean(true))
3828 ));
3829 }
3830 "async" => {
3831 options.r#async = Some(matches!(
3832 option.value,
3833 SqlOptionValue::Value(Value::Boolean(true))
3834 ))
3835 }
3836 "batch" => {
3837 options.batch = Some(matches!(
3838 option.value,
3839 SqlOptionValue::Value(Value::Boolean(true))
3840 ))
3841 }
3842 _ => {
3843 return Err(StrError(format!("unknown option: {}", option.name)));
3844 }
3845 }
3846 }
3847 Ok(options)
3848 }
3849}
3850
3851impl Display for CreateFunctionWithOptions {
3852 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3853 if self == &Self::default() {
3854 return Ok(());
3855 }
3856 let mut options = vec![];
3857 if let Some(v) = self.always_retry_on_network_error {
3858 options.push(format!("always_retry_on_network_error = {}", v));
3859 }
3860 if let Some(v) = self.r#async {
3861 options.push(format!("async = {}", v));
3862 }
3863 if let Some(v) = self.batch {
3864 options.push(format!("batch = {}", v));
3865 }
3866 write!(f, " WITH ( {} )", display_comma_separated(&options))
3867 }
3868}
3869
3870#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3871pub enum CreateFunctionUsing {
3872 Link(String),
3873 Base64(String),
3874}
3875
3876impl fmt::Display for CreateFunctionUsing {
3877 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3878 write!(f, "USING ")?;
3879 match self {
3880 CreateFunctionUsing::Link(uri) => write!(f, "LINK '{uri}'"),
3881 CreateFunctionUsing::Base64(s) => {
3882 write!(f, "BASE64 '{s}'")
3883 }
3884 }
3885 }
3886}
3887
3888#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3889pub struct ConfigParam {
3890 pub param: Ident,
3891 pub value: SetVariableValue,
3892}
3893
3894impl fmt::Display for ConfigParam {
3895 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3896 write!(f, "SET {} = {}", self.param, self.value)
3897 }
3898}
3899
3900#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3901pub enum SetVariableValue {
3902 Single(SetVariableValueSingle),
3903 List(Vec<SetVariableValueSingle>),
3904 Default,
3905}
3906
3907impl From<SetVariableValueSingle> for SetVariableValue {
3908 fn from(value: SetVariableValueSingle) -> Self {
3909 SetVariableValue::Single(value)
3910 }
3911}
3912
3913impl fmt::Display for SetVariableValue {
3914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3915 use SetVariableValue::*;
3916 match self {
3917 Single(val) => write!(f, "{}", val),
3918 List(list) => write!(f, "{}", display_comma_separated(list),),
3919 Default => write!(f, "DEFAULT"),
3920 }
3921 }
3922}
3923
3924#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3925pub enum SetVariableValueSingle {
3926 Ident(Ident),
3927 Literal(Value),
3928 Raw(String),
3929}
3930
3931impl SetVariableValueSingle {
3932 pub fn to_string_unquoted(&self) -> String {
3933 match self {
3934 Self::Literal(Value::SingleQuotedString(s))
3935 | Self::Literal(Value::DoubleQuotedString(s))
3936 | Self::Raw(s) => s.clone(),
3937 _ => self.to_string(),
3938 }
3939 }
3940}
3941
3942impl fmt::Display for SetVariableValueSingle {
3943 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3944 use SetVariableValueSingle::*;
3945 match self {
3946 Ident(ident) => write!(f, "{}", ident),
3947 Literal(literal) => write!(f, "{}", literal),
3948 Raw(raw) => write!(f, "{}", raw),
3949 }
3950 }
3951}
3952
3953#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3954pub enum AsOf {
3955 ProcessTime,
3956 ProcessTimeBroadcast,
3960 ProcessTimeWithInterval((String, DateTimeField)),
3962 TimestampNum(i64),
3964 TimestampString(String),
3965 VersionNum(i64),
3966 VersionString(String),
3967}
3968
3969impl fmt::Display for AsOf {
3970 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3971 use AsOf::*;
3972 match self {
3973 ProcessTime | ProcessTimeBroadcast => {
3974 write!(f, " FOR SYSTEM_TIME AS OF PROCTIME()")
3975 }
3976 ProcessTimeWithInterval((value, leading_field)) => write!(
3977 f,
3978 " FOR SYSTEM_TIME AS OF NOW() - '{}' {}",
3979 value, leading_field
3980 ),
3981 TimestampNum(ts) => write!(f, " FOR SYSTEM_TIME AS OF {}", ts),
3982 TimestampString(ts) => write!(f, " FOR SYSTEM_TIME AS OF '{}'", ts),
3983 VersionNum(v) => write!(f, " FOR SYSTEM_VERSION AS OF {}", v),
3984 VersionString(v) => write!(f, " FOR SYSTEM_VERSION AS OF '{}'", v),
3985 }
3986 }
3987}
3988
3989#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3990pub enum DiscardType {
3991 All,
3992}
3993
3994impl fmt::Display for DiscardType {
3995 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3996 use DiscardType::*;
3997 match self {
3998 All => write!(f, "ALL"),
3999 }
4000 }
4001}
4002
4003#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
4006pub enum BackfillOrderStrategy {
4007 #[default]
4008 Default,
4009 None,
4010 Auto,
4011 Fixed(Vec<(ObjectName, ObjectName)>),
4012}
4013
4014impl fmt::Display for BackfillOrderStrategy {
4015 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4016 use BackfillOrderStrategy::*;
4017 match self {
4018 Default => write!(f, "DEFAULT"),
4019 None => write!(f, "NONE"),
4020 Auto => write!(f, "AUTO"),
4021 Fixed(map) => {
4022 let mut parts = vec![];
4023 for (start, end) in map {
4024 parts.push(format!("{} -> {}", start, end));
4025 }
4026 write!(f, "FIXED({})", display_comma_separated(&parts))
4027 }
4028 }
4029 }
4030}
4031
4032impl Statement {
4033 pub fn to_redacted_string(&self, redaction: SqlOptionRedactionRef) -> String {
4034 SQL_OPTION_REDACTION.sync_scope(redaction, || self.to_string_unchecked())
4035 }
4036
4037 pub fn default_create_table(name: ObjectName) -> Self {
4039 Self::CreateTable {
4040 name,
4041 or_replace: false,
4042 temporary: false,
4043 if_not_exists: false,
4044 columns: Vec::new(),
4045 wildcard_idx: None,
4046 constraints: Vec::new(),
4047 with_options: Vec::new(),
4048 format_encode: None,
4049 source_watermarks: Vec::new(),
4050 append_only: false,
4051 on_conflict: None,
4052 with_version_columns: Vec::new(),
4053 query: None,
4054 cdc_table_info: None,
4055 include_column_options: Vec::new(),
4056 webhook_info: None,
4057 engine: Engine::Hummock,
4058 }
4059 }
4060}
4061
4062#[cfg(test)]
4063mod tests {
4064 use super::*;
4065
4066 #[test]
4067 fn test_sql_option_redaction_preserves_primary_key() {
4068 let redaction = Arc::new(SqlOptionRedaction::new(
4069 [
4070 "credential".into(),
4071 "key".into(),
4072 "password".into(),
4073 "private".into(),
4074 "secret".into(),
4075 "token".into(),
4076 ],
4077 ["primary_key".into()],
4078 ));
4079 for (name, expected_value) in [
4080 ("primary_key", "'id'"),
4081 ("\"primary_key\"", "'id'"),
4082 ("\"PRIMARY_KEY\"", "'id'"),
4083 ("api_key", "[REDACTED]"),
4084 ("access_key", "[REDACTED]"),
4085 ("password", "[REDACTED]"),
4086 ("token", "[REDACTED]"),
4087 ("primary_key_password", "[REDACTED]"),
4088 ("my_primary_key", "[REDACTED]"),
4089 ("aws.secret_access_key", "[REDACTED]"),
4090 ("connector", "'id'"),
4091 ] {
4092 let sql = format!("CREATE SINK s FROM t WITH ({name} = 'id')");
4093 let statement = Parser::parse_sql(&sql).unwrap().remove(0);
4094 assert_eq!(
4095 statement.to_redacted_string(redaction.clone()),
4096 format!("CREATE SINK s FROM t WITH ({name} = {expected_value})"),
4097 "option: {name}",
4098 );
4099 assert_eq!(statement.to_string_unchecked(), sql);
4100 }
4101 }
4102
4103 #[test]
4104 fn test_sql_option_redaction_custom_allowlist() {
4105 let sql = "CREATE SINK s FROM t WITH (primary_key = 'id', partition_key = 'region', partition_key_password = 'secret')";
4106 let statement = Parser::parse_sql(sql).unwrap().remove(0);
4107 for (allowlist, expected) in [
4108 (
4109 vec![],
4110 "CREATE SINK s FROM t WITH (primary_key = [REDACTED], partition_key = [REDACTED], partition_key_password = [REDACTED])",
4111 ),
4112 (
4113 vec!["PARTITION_KEY".into()],
4114 "CREATE SINK s FROM t WITH (primary_key = [REDACTED], partition_key = 'region', partition_key_password = [REDACTED])",
4115 ),
4116 ] {
4117 let redaction = Arc::new(SqlOptionRedaction::new(["KEY".into()], allowlist));
4118 assert_eq!(statement.to_redacted_string(redaction), expected);
4119 }
4120 }
4121
4122 #[test]
4123 fn test_grouping_sets_display() {
4124 let grouping_sets = Expr::GroupingSets(vec![
4126 vec![Expr::Identifier(Ident::new_unchecked("a"))],
4127 vec![Expr::Identifier(Ident::new_unchecked("b"))],
4128 ]);
4129 assert_eq!("GROUPING SETS ((a), (b))", format!("{}", grouping_sets));
4130
4131 let grouping_sets = Expr::GroupingSets(vec![vec![
4133 Expr::Identifier(Ident::new_unchecked("a")),
4134 Expr::Identifier(Ident::new_unchecked("b")),
4135 ]]);
4136 assert_eq!("GROUPING SETS ((a, b))", format!("{}", grouping_sets));
4137
4138 let grouping_sets = Expr::GroupingSets(vec![
4140 vec![
4141 Expr::Identifier(Ident::new_unchecked("a")),
4142 Expr::Identifier(Ident::new_unchecked("b")),
4143 ],
4144 vec![
4145 Expr::Identifier(Ident::new_unchecked("c")),
4146 Expr::Identifier(Ident::new_unchecked("d")),
4147 ],
4148 ]);
4149 assert_eq!(
4150 "GROUPING SETS ((a, b), (c, d))",
4151 format!("{}", grouping_sets)
4152 );
4153 }
4154
4155 #[test]
4156 fn test_rollup_display() {
4157 let rollup = Expr::Rollup(vec![vec![Expr::Identifier(Ident::new_unchecked("a"))]]);
4158 assert_eq!("ROLLUP (a)", format!("{}", rollup));
4159
4160 let rollup = Expr::Rollup(vec![vec![
4161 Expr::Identifier(Ident::new_unchecked("a")),
4162 Expr::Identifier(Ident::new_unchecked("b")),
4163 ]]);
4164 assert_eq!("ROLLUP ((a, b))", format!("{}", rollup));
4165
4166 let rollup = Expr::Rollup(vec![
4167 vec![Expr::Identifier(Ident::new_unchecked("a"))],
4168 vec![Expr::Identifier(Ident::new_unchecked("b"))],
4169 ]);
4170 assert_eq!("ROLLUP (a, b)", format!("{}", rollup));
4171
4172 let rollup = Expr::Rollup(vec![
4173 vec![Expr::Identifier(Ident::new_unchecked("a"))],
4174 vec![
4175 Expr::Identifier(Ident::new_unchecked("b")),
4176 Expr::Identifier(Ident::new_unchecked("c")),
4177 ],
4178 vec![Expr::Identifier(Ident::new_unchecked("d"))],
4179 ]);
4180 assert_eq!("ROLLUP (a, (b, c), d)", format!("{}", rollup));
4181 }
4182
4183 #[test]
4184 fn test_cube_display() {
4185 let cube = Expr::Cube(vec![vec![Expr::Identifier(Ident::new_unchecked("a"))]]);
4186 assert_eq!("CUBE (a)", format!("{}", cube));
4187
4188 let cube = Expr::Cube(vec![vec![
4189 Expr::Identifier(Ident::new_unchecked("a")),
4190 Expr::Identifier(Ident::new_unchecked("b")),
4191 ]]);
4192 assert_eq!("CUBE ((a, b))", format!("{}", cube));
4193
4194 let cube = Expr::Cube(vec![
4195 vec![Expr::Identifier(Ident::new_unchecked("a"))],
4196 vec![Expr::Identifier(Ident::new_unchecked("b"))],
4197 ]);
4198 assert_eq!("CUBE (a, b)", format!("{}", cube));
4199
4200 let cube = Expr::Cube(vec![
4201 vec![Expr::Identifier(Ident::new_unchecked("a"))],
4202 vec![
4203 Expr::Identifier(Ident::new_unchecked("b")),
4204 Expr::Identifier(Ident::new_unchecked("c")),
4205 ],
4206 vec![Expr::Identifier(Ident::new_unchecked("d"))],
4207 ]);
4208 assert_eq!("CUBE (a, (b, c), d)", format!("{}", cube));
4209 }
4210
4211 #[test]
4212 fn test_array_index_display() {
4213 let array_index = Expr::Index {
4214 obj: Box::new(Expr::Identifier(Ident::new_unchecked("v1"))),
4215 index: Box::new(Expr::Value(Value::Number("1".into()))),
4216 };
4217 assert_eq!("v1[1]", format!("{}", array_index));
4218
4219 let array_index2 = Expr::Index {
4220 obj: Box::new(array_index),
4221 index: Box::new(Expr::Value(Value::Number("1".into()))),
4222 };
4223 assert_eq!("v1[1][1]", format!("{}", array_index2));
4224 }
4225
4226 #[test]
4227 fn test_nested_op_display() {
4229 let binary_op = Expr::BinaryOp {
4230 left: Box::new(Expr::Value(Value::Boolean(true))),
4231 op: BinaryOperator::Or,
4232 right: Box::new(Expr::IsNotFalse(Box::new(Expr::Value(Value::Boolean(
4233 true,
4234 ))))),
4235 };
4236 assert_eq!("true OR true IS NOT FALSE", format!("{}", binary_op));
4237
4238 let unary_op = Expr::UnaryOp {
4239 op: UnaryOperator::Not,
4240 expr: Box::new(Expr::IsNotFalse(Box::new(Expr::Value(Value::Boolean(
4241 true,
4242 ))))),
4243 };
4244 assert_eq!("NOT true IS NOT FALSE", format!("{}", unary_op));
4245 }
4246
4247 #[test]
4248 fn test_create_function_display() {
4249 let create_function = Statement::CreateFunction {
4250 or_replace: false,
4251 temporary: false,
4252 if_not_exists: false,
4253 name: ObjectName(vec![Ident::new_unchecked("foo")]),
4254 args: Some(vec![OperateFunctionArg::unnamed(DataType::Int)]),
4255 returns: Some(CreateFunctionReturns::Value(DataType::Int)),
4256 params: CreateFunctionBody {
4257 language: Some(Ident::new_unchecked("python")),
4258 runtime: None,
4259 behavior: Some(FunctionBehavior::Immutable),
4260 as_: Some(FunctionDefinition::SingleQuotedDef("SELECT 1".to_owned())),
4261 return_: None,
4262 using: None,
4263 },
4264 with_options: CreateFunctionWithOptions {
4265 always_retry_on_network_error: None,
4266 r#async: None,
4267 batch: None,
4268 },
4269 };
4270 assert_eq!(
4271 "CREATE FUNCTION foo(INT) RETURNS INT LANGUAGE python IMMUTABLE AS 'SELECT 1'",
4272 format!("{}", create_function)
4273 );
4274 let create_function = Statement::CreateFunction {
4275 or_replace: false,
4276 temporary: false,
4277 if_not_exists: false,
4278 name: ObjectName(vec![Ident::new_unchecked("foo")]),
4279 args: Some(vec![OperateFunctionArg::unnamed(DataType::Int)]),
4280 returns: Some(CreateFunctionReturns::Value(DataType::Int)),
4281 params: CreateFunctionBody {
4282 language: Some(Ident::new_unchecked("python")),
4283 runtime: None,
4284 behavior: Some(FunctionBehavior::Immutable),
4285 as_: Some(FunctionDefinition::SingleQuotedDef("SELECT 1".to_owned())),
4286 return_: None,
4287 using: None,
4288 },
4289 with_options: CreateFunctionWithOptions {
4290 always_retry_on_network_error: Some(true),
4291 r#async: None,
4292 batch: None,
4293 },
4294 };
4295 assert_eq!(
4296 "CREATE FUNCTION foo(INT) RETURNS INT LANGUAGE python IMMUTABLE AS 'SELECT 1' WITH ( always_retry_on_network_error = true )",
4297 format!("{}", create_function)
4298 );
4299 }
4300
4301 #[test]
4302 fn test_sql_option_from_secret_ref() {
4303 let text_option = SqlOption::from_secret_ref(
4304 "password",
4305 SecretRefValue {
4306 secret_name: ObjectName(vec![
4307 Ident::from_real_value("public"),
4308 Ident::from_real_value("s2"),
4309 ]),
4310 ref_as: SecretRefAsType::Text,
4311 },
4312 );
4313
4314 assert!(matches!(text_option.value, SqlOptionValue::SecretRef(_)));
4315 assert_eq!(text_option.to_string(), "password = secret public.s2");
4316
4317 let file_option = SqlOption::from_secret_ref(
4318 "certificate",
4319 SecretRefValue {
4320 secret_name: ObjectName(vec![Ident::from_real_value("cert")]),
4321 ref_as: SecretRefAsType::File,
4322 },
4323 );
4324
4325 assert_eq!(file_option.to_string(), "certificate = secret cert AS FILE");
4326 }
4327}