1use std::collections::BTreeMap;
16use std::fmt::Display;
17use std::fmt::Formatter;
18use std::time::Duration;
19
20use derive_visitor::Drive;
21use derive_visitor::DriveMut;
22
23use crate::ast::CreateOption;
24use crate::ast::Expr;
25use crate::ast::Identifier;
26use crate::ast::Query;
27use crate::ast::TableIndexType;
28use crate::ast::TableReference;
29use crate::ast::TimeTravelPoint;
30use crate::ast::TypeName;
31use crate::ast::UriLocation;
32use crate::ast::quote::QuotedString;
33use crate::ast::statements::constraint::ConstraintType;
34use crate::ast::statements::show::ShowLimit;
35use crate::ast::write_comma_separated_list;
36use crate::ast::write_comma_separated_string_map;
37use crate::ast::write_dot_separated_list;
38use crate::ast::write_space_separated_string_map;
39
40#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
41pub struct ShowTablesStmt {
42 pub catalog: Option<Identifier>,
43 pub database: Option<Identifier>,
44 pub full: bool,
45 pub limit: Option<ShowLimit>,
46 pub with_history: bool,
47}
48
49impl Display for ShowTablesStmt {
50 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
51 write!(f, "SHOW")?;
52 if self.full {
53 write!(f, " FULL")?;
54 }
55 write!(f, " TABLES")?;
56 if self.with_history {
57 write!(f, " HISTORY")?;
58 }
59 if let Some(database) = &self.database {
60 write!(f, " FROM ")?;
61 if let Some(catalog) = &self.catalog {
62 write!(f, "{catalog}.",)?;
63 }
64 write!(f, "{database}")?;
65 }
66 if let Some(limit) = &self.limit {
67 write!(f, " {limit}")?;
68 }
69
70 Ok(())
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
75pub struct ShowCreateTableStmt {
76 pub catalog: Option<Identifier>,
77 pub database: Option<Identifier>,
78 pub table: Identifier,
79 pub with_quoted_ident: bool,
80}
81
82impl Display for ShowCreateTableStmt {
83 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
84 write!(f, "SHOW CREATE TABLE ")?;
85 write_dot_separated_list(
86 f,
87 self.catalog
88 .iter()
89 .chain(&self.database)
90 .chain(Some(&self.table)),
91 )?;
92 if self.with_quoted_ident {
93 write!(f, " WITH QUOTED_IDENTIFIERS")?
94 }
95 Ok(())
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
100pub struct ShowTablesStatusStmt {
101 pub database: Option<Identifier>,
102 pub limit: Option<ShowLimit>,
103}
104
105impl Display for ShowTablesStatusStmt {
106 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
107 write!(f, "SHOW TABLE STATUS")?;
108 if let Some(database) = &self.database {
109 write!(f, " FROM {database}")?;
110 }
111 if let Some(limit) = &self.limit {
112 write!(f, " {limit}")?;
113 }
114
115 Ok(())
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
120pub struct ShowDropTablesStmt {
121 pub database: Option<Identifier>,
122 pub limit: Option<ShowLimit>,
123}
124
125impl Display for ShowDropTablesStmt {
126 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
127 write!(f, "SHOW DROP TABLES")?;
128 if let Some(database) = &self.database {
129 write!(f, " FROM {database}")?;
130 }
131 if let Some(limit) = &self.limit {
132 write!(f, " {limit}")?;
133 }
134
135 Ok(())
136 }
137}
138
139#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
140pub enum ClusterType {
141 Linear,
142 Hilbert,
143}
144
145impl Display for ClusterType {
146 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
147 match self {
148 ClusterType::Linear => write!(f, "LINEAR"),
149 ClusterType::Hilbert => write!(f, "HILBERT"),
150 }
151 }
152}
153
154impl std::str::FromStr for ClusterType {
155 type Err = ();
156 fn from_str(s: &str) -> Result<Self, Self::Err> {
157 match s.to_lowercase().as_str() {
158 "linear" => Ok(ClusterType::Linear),
159 "hilbert" => Ok(ClusterType::Hilbert),
160 _ => Err(()),
161 }
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
166pub struct ClusterOption {
167 pub cluster_type: ClusterType,
168 pub cluster_exprs: Vec<Expr>,
169}
170
171impl Display for ClusterOption {
172 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
173 write!(f, "CLUSTER BY {}(", self.cluster_type)?;
174 write_comma_separated_list(f, &self.cluster_exprs)?;
175 write!(f, ")")
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
180pub struct CreateTableStmt {
181 pub create_option: CreateOption,
182 pub catalog: Option<Identifier>,
183 pub database: Option<Identifier>,
184 pub table: Identifier,
185 pub source: Option<CreateTableSource>,
186 pub engine: Option<Engine>,
187 pub uri_location: Option<UriLocation>,
188 pub cluster_by: Option<ClusterOption>,
189 pub table_options: BTreeMap<String, String>,
190 pub iceberg_table_partition: Option<Vec<Identifier>>,
191 pub table_properties: Option<BTreeMap<String, String>>,
192 pub as_query: Option<Box<Query>>,
193 pub table_type: TableType,
194}
195
196#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
197pub enum TableType {
198 Normal,
199 Transient,
200 Temporary,
201}
202
203impl Display for CreateTableStmt {
204 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
205 write!(f, "CREATE")?;
206 if let CreateOption::CreateOrReplace = self.create_option {
207 write!(f, " OR REPLACE")?;
208 }
209 match self.table_type {
210 TableType::Normal => {}
211 TableType::Transient => write!(f, " TRANSIENT")?,
212 TableType::Temporary => write!(f, " TEMPORARY")?,
213 };
214 write!(f, " TABLE")?;
215 if let CreateOption::CreateIfNotExists = self.create_option {
216 write!(f, " IF NOT EXISTS")?;
217 }
218 write!(f, " ")?;
219 write_dot_separated_list(
220 f,
221 self.catalog
222 .iter()
223 .chain(&self.database)
224 .chain(Some(&self.table)),
225 )?;
226
227 if let Some(source) = &self.source {
228 write!(f, " {source}")?;
229 }
230
231 if let Some(engine) = &self.engine {
232 write!(f, " ENGINE = {engine}")?;
233 }
234
235 if let Some(uri_location) = &self.uri_location {
236 write!(f, " {uri_location}")?;
237 }
238
239 if let Some(cluster_by) = &self.cluster_by {
240 write!(f, " {cluster_by}")?;
241 }
242
243 if !self.table_options.is_empty() {
245 write!(f, " ")?;
246 write_space_separated_string_map(f, &self.table_options)?;
247 }
248
249 if let Some(iceberg_table_partition) = &self.iceberg_table_partition {
250 write!(f, " PARTITION BY(")?;
251 write_comma_separated_list(f, iceberg_table_partition)?;
252 write!(f, ")")?;
253 }
254
255 if let Some(table_properties) = &self.table_properties {
256 write!(f, " PROPERTIES(")?;
257 write_space_separated_string_map(f, table_properties)?;
258 write!(f, ")")?;
259 }
260
261 if let Some(as_query) = &self.as_query {
262 write!(f, " AS {as_query}")?;
263 }
264
265 Ok(())
266 }
267}
268
269#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
270pub struct AttachTableStmt {
271 pub catalog: Option<Identifier>,
272 pub database: Option<Identifier>,
273 pub table: Identifier,
274 pub columns_opt: Option<Vec<Identifier>>,
275 pub uri_location: UriLocation,
276}
277
278impl Display for AttachTableStmt {
279 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
280 write!(f, "ATTACH TABLE ")?;
281 write_dot_separated_list(
282 f,
283 self.catalog
284 .iter()
285 .chain(&self.database)
286 .chain(Some(&self.table)),
287 )?;
288
289 if let Some(cols) = &self.columns_opt {
290 write!(f, " (")?;
291 write_comma_separated_list(f, cols.iter())?;
292 write!(f, ")")?;
293 }
294
295 write!(f, " {}", self.uri_location)?;
296
297 Ok(())
298 }
299}
300
301#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
302pub enum CreateTableSource {
303 Columns {
304 columns: Vec<ColumnDefinition>,
305 opt_table_indexes: Option<Vec<TableIndexDefinition>>,
306 opt_column_constraints: Option<Vec<ConstraintDefinition>>,
307 opt_table_constraints: Option<Vec<ConstraintDefinition>>,
308 },
309 Like {
310 catalog: Option<Identifier>,
311 database: Option<Identifier>,
312 table: Identifier,
313 },
314}
315
316impl Display for CreateTableSource {
317 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
318 match self {
319 CreateTableSource::Columns {
321 columns,
322 opt_table_indexes,
323 opt_column_constraints: _column_constraints,
324 opt_table_constraints: table_constraints,
325 } => {
326 write!(f, "(")?;
327 write_comma_separated_list(f, columns)?;
328 if let Some(table_indexes) = opt_table_indexes {
329 write!(f, ", ")?;
330 write_comma_separated_list(f, table_indexes)?;
331 }
332 if let Some(constraints) = table_constraints {
333 write!(f, ", ")?;
334 write_comma_separated_list(f, constraints)?;
335 }
336 write!(f, ")")
337 }
338 CreateTableSource::Like {
339 catalog,
340 database,
341 table,
342 } => {
343 write!(f, "LIKE ")?;
344 write_dot_separated_list(f, catalog.iter().chain(database).chain(Some(table)))
345 }
346 }
347 }
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
351pub struct DescribeTableStmt {
352 pub catalog: Option<Identifier>,
353 pub database: Option<Identifier>,
354 pub table: Identifier,
355}
356
357impl Display for DescribeTableStmt {
358 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
359 write!(f, "DESCRIBE ")?;
360 write_dot_separated_list(
361 f,
362 self.catalog
363 .iter()
364 .chain(self.database.iter().chain(Some(&self.table))),
365 )
366 }
367}
368
369#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
370pub struct DropTableStmt {
371 pub if_exists: bool,
372 pub catalog: Option<Identifier>,
373 pub database: Option<Identifier>,
374 pub table: Identifier,
375 pub all: bool,
376}
377
378impl Display for DropTableStmt {
379 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
380 write!(f, "DROP TABLE ")?;
381 if self.if_exists {
382 write!(f, "IF EXISTS ")?;
383 }
384 write_dot_separated_list(
385 f,
386 self.catalog
387 .iter()
388 .chain(&self.database)
389 .chain(Some(&self.table)),
390 )?;
391 if self.all {
392 write!(f, " ALL")?;
393 }
394
395 Ok(())
396 }
397}
398
399#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
400pub struct UndropTableStmt {
401 pub catalog: Option<Identifier>,
402 pub database: Option<Identifier>,
403 pub table: Identifier,
404}
405
406impl Display for UndropTableStmt {
407 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
408 write!(f, "UNDROP TABLE ")?;
409 write_dot_separated_list(
410 f,
411 self.catalog
412 .iter()
413 .chain(&self.database)
414 .chain(Some(&self.table)),
415 )
416 }
417}
418
419#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
420pub struct AlterTableStmt {
421 pub if_exists: bool,
422 pub table_reference: TableReference,
423 pub action: AlterTableAction,
424}
425
426impl Display for AlterTableStmt {
427 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
428 write!(f, "ALTER TABLE")?;
429 if self.if_exists {
430 write!(f, " IF EXISTS")?;
431 }
432 write!(f, " {}", self.table_reference)?;
433 write!(f, " {}", self.action)
434 }
435}
436
437#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
438pub enum SnapshotRefType {
439 Branch,
440 Tag,
441}
442
443impl Display for SnapshotRefType {
444 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
445 match self {
446 SnapshotRefType::Branch => write!(f, "BRANCH"),
447 SnapshotRefType::Tag => write!(f, "TAG"),
448 }
449 }
450}
451
452#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
453pub enum AlterTableAction {
454 RenameTable {
455 new_table: Identifier,
456 },
457 SwapWith {
458 target_table: Identifier,
459 },
460 AddColumn {
461 column: ColumnDefinition,
462 option: AddColumnOption,
463 },
464 RenameColumn {
465 old_column: Identifier,
466 new_column: Identifier,
467 },
468 ModifyTableComment {
469 new_comment: String,
470 },
471 ModifyColumn {
472 action: ModifyColumnAction,
473 },
474 AddConstraint {
475 constraint: ConstraintDefinition,
476 },
477 DropConstraint {
478 constraint_name: Identifier,
479 },
480 AddRowAccessPolicy {
482 columns: Vec<Identifier>,
483 policy: Identifier,
484 },
485 DropRowAccessPolicy {
487 policy: Identifier,
488 },
489 DropAllRowAccessPolicies,
490 DropColumn {
491 column: Identifier,
492 },
493 AlterTableClusterKey {
494 cluster_by: ClusterOption,
495 },
496 DropTableClusterKey,
497 ReclusterTable {
498 is_final: bool,
499 selection: Option<Expr>,
500 limit: Option<u64>,
501 },
502 FlashbackTo {
503 point: TimeTravelPoint,
504 },
505 SetOptions {
506 set_options: BTreeMap<String, String>,
507 },
508 UnsetOptions {
509 targets: Vec<Identifier>,
510 },
511 RefreshTableCache,
512 ModifyConnection {
513 new_connection: BTreeMap<String, String>,
514 },
515 CreateTableRef {
516 ref_type: SnapshotRefType,
517 ref_name: Identifier,
518 travel_point: Option<TimeTravelPoint>,
519 #[drive(skip)]
520 retain: Option<Duration>,
521 },
522 DropTableRef {
523 ref_type: SnapshotRefType,
524 ref_name: Identifier,
525 },
526}
527
528impl Display for AlterTableAction {
529 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
530 match self {
531 AlterTableAction::SetOptions { set_options } => {
532 write!(f, "SET OPTIONS (")?;
533 write_comma_separated_string_map(f, set_options)?;
534 write!(f, ")")?;
535 }
536 AlterTableAction::RenameTable { new_table } => {
537 write!(f, "RENAME TO {new_table}")?;
538 }
539 AlterTableAction::SwapWith { target_table } => {
540 write!(f, "SWAP WITH {target_table}")?;
541 }
542 AlterTableAction::ModifyTableComment { new_comment } => {
543 write!(f, "COMMENT={}", QuotedString(new_comment, '\''))?;
544 }
545 AlterTableAction::RenameColumn {
546 old_column,
547 new_column,
548 } => {
549 write!(f, "RENAME COLUMN {old_column} TO {new_column}")?;
550 }
551 AlterTableAction::AddColumn { column, option } => {
552 write!(f, "ADD COLUMN {column}{option}")?;
553 }
554 AlterTableAction::AddConstraint { constraint } => {
555 write!(f, "ADD {}", constraint)?;
556 }
557 AlterTableAction::DropConstraint { constraint_name } => {
558 write!(f, "DROP CONSTRAINT {}", constraint_name)?;
559 }
560 AlterTableAction::ModifyColumn { action } => {
561 write!(f, "MODIFY COLUMN {action}")?;
562 }
563 AlterTableAction::DropColumn { column } => {
564 write!(f, "DROP COLUMN {column}")?;
565 }
566 AlterTableAction::AlterTableClusterKey { cluster_by } => {
567 write!(f, "{cluster_by}")?;
568 }
569 AlterTableAction::DropTableClusterKey => {
570 write!(f, "DROP CLUSTER KEY")?;
571 }
572 AlterTableAction::ReclusterTable {
573 is_final,
574 selection,
575 limit,
576 } => {
577 write!(f, "RECLUSTER")?;
578 if *is_final {
579 write!(f, " FINAL")?;
580 }
581 if let Some(conditions) = selection {
582 write!(f, " WHERE {conditions}")?;
583 }
584 if let Some(limit) = limit {
585 write!(f, " LIMIT {limit}")?;
586 }
587 }
588 AlterTableAction::FlashbackTo { point } => {
589 write!(f, "FLASHBACK TO {}", point)?;
590 }
591 AlterTableAction::UnsetOptions {
592 targets: unset_targets,
593 } => {
594 write!(f, "UNSET OPTIONS ")?;
595 if unset_targets.len() == 1 {
596 write!(f, "{}", unset_targets[0])?;
597 } else {
598 write!(f, "(")?;
599 write_comma_separated_list(f, unset_targets)?;
600 write!(f, ")")?;
601 }
602 }
603 AlterTableAction::RefreshTableCache => {
604 write!(f, "REFRESH CACHE")?;
605 }
606 AlterTableAction::ModifyConnection { new_connection } => {
607 write!(f, "CONNECTION=(")?;
608 write_space_separated_string_map(f, new_connection)?;
609 write!(f, ")")?;
610 }
611 AlterTableAction::AddRowAccessPolicy { columns, policy } => {
612 write!(f, "ADD ROW ACCESS POLICY {} ON (", policy)?;
613 write_comma_separated_list(f, columns)?;
614 write!(f, ")")?
615 }
616 AlterTableAction::DropRowAccessPolicy { policy } => {
617 write!(f, "DROP ROW ACCESS POLICY {}", policy)?
618 }
619 AlterTableAction::DropAllRowAccessPolicies => {
620 write!(f, "DROP ALL ROW ACCESS POLICIES")?
621 }
622 AlterTableAction::CreateTableRef {
623 ref_type,
624 ref_name,
625 travel_point,
626 retain,
627 } => {
628 write!(f, "CREATE {ref_type} {ref_name}")?;
629 if let Some(travel_point) = travel_point {
630 write!(f, " AT {travel_point}")?;
631 }
632 if let Some(retain) = retain {
633 let days = Duration::from_secs(60 * 60 * 24);
634 if retain >= &days {
635 let days = retain.as_secs() / (60 * 60 * 24);
636 write!(f, " RETAIN {days} DAYS ")?;
637 } else {
638 let seconds = retain.as_secs();
639 write!(f, " RETAIN {seconds} SECONDS ")?;
640 }
641 }
642 }
643 AlterTableAction::DropTableRef { ref_type, ref_name } => {
644 write!(f, "DROP {ref_type} {ref_name}")?;
645 }
646 };
647 Ok(())
648 }
649}
650
651#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
652pub enum AddColumnOption {
653 End,
654 First,
655 After(Identifier),
656}
657
658impl Display for AddColumnOption {
659 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
660 match self {
661 AddColumnOption::First => write!(f, " FIRST"),
662 AddColumnOption::After(ident) => write!(f, " AFTER {ident}"),
663 AddColumnOption::End => Ok(()),
664 }
665 }
666}
667
668#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
669pub struct RenameTableStmt {
670 pub if_exists: bool,
671 pub catalog: Option<Identifier>,
672 pub database: Option<Identifier>,
673 pub table: Identifier,
674 pub new_catalog: Option<Identifier>,
675 pub new_database: Option<Identifier>,
676 pub new_table: Identifier,
677}
678
679impl Display for RenameTableStmt {
680 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
681 write!(f, "RENAME TABLE ")?;
682 if self.if_exists {
683 write!(f, "IF EXISTS ")?;
684 }
685 write_dot_separated_list(
686 f,
687 self.catalog
688 .iter()
689 .chain(&self.database)
690 .chain(Some(&self.table)),
691 )?;
692 write!(f, " TO ")?;
693 write_dot_separated_list(
694 f,
695 self.new_catalog
696 .iter()
697 .chain(&self.new_database)
698 .chain(Some(&self.new_table)),
699 )
700 }
701}
702
703#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
704pub struct TruncateTableStmt {
705 pub catalog: Option<Identifier>,
706 pub database: Option<Identifier>,
707 pub table: Identifier,
708}
709
710impl Display for TruncateTableStmt {
711 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
712 write!(f, "TRUNCATE TABLE ")?;
713 write_dot_separated_list(
714 f,
715 self.catalog
716 .iter()
717 .chain(&self.database)
718 .chain(Some(&self.table)),
719 )?;
720 Ok(())
721 }
722}
723
724#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
725pub struct VacuumTableStmt {
726 pub catalog: Option<Identifier>,
727 pub database: Option<Identifier>,
728 pub table: Identifier,
729 pub option: VacuumTableOption,
730}
731
732impl Display for VacuumTableStmt {
733 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
734 write!(f, "VACUUM TABLE ")?;
735 write_dot_separated_list(
736 f,
737 self.catalog
738 .iter()
739 .chain(&self.database)
740 .chain(Some(&self.table)),
741 )?;
742 write!(f, " {}", &self.option)?;
743
744 Ok(())
745 }
746}
747
748#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
749pub struct VacuumDropTableStmt {
750 pub catalog: Option<Identifier>,
751 pub database: Option<Identifier>,
752 pub option: VacuumDropTableOption,
753}
754
755impl Display for VacuumDropTableStmt {
756 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
757 write!(f, "VACUUM DROP TABLE ")?;
758 if self.catalog.is_some() || self.database.is_some() {
759 write!(f, "FROM ")?;
760 write_dot_separated_list(f, self.catalog.iter().chain(&self.database))?;
761 write!(f, " ")?;
762 }
763 write!(f, "{}", &self.option)?;
764
765 Ok(())
766 }
767}
768
769#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
770pub struct VacuumTemporaryFiles {
771 pub limit: Option<u64>,
772 #[drive(skip)]
773 pub retain: Option<Duration>,
774}
775
776impl Display for crate::ast::VacuumTemporaryFiles {
777 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
778 write!(f, "VACUUM TEMPORARY FILES")?;
779 if let Some(retain) = &self.retain {
780 let days = Duration::from_secs(60 * 60 * 24);
781 if retain >= &days {
782 let days = retain.as_secs() / (60 * 60 * 24);
783 write!(f, " RETAIN {days} DAYS")?;
784 } else {
785 let seconds = retain.as_secs();
786 write!(f, " RETAIN {seconds} SECONDS")?;
787 }
788 }
789
790 if let Some(limit) = &self.limit {
791 write!(f, " LIMIT {limit}")?;
792 }
793
794 Ok(())
795 }
796}
797
798#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
799pub struct OptimizeTableStmt {
800 pub catalog: Option<Identifier>,
801 pub database: Option<Identifier>,
802 pub table: Identifier,
803 pub action: OptimizeTableAction,
804 pub limit: Option<u64>,
805}
806
807impl Display for OptimizeTableStmt {
808 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
809 write!(f, "OPTIMIZE TABLE ")?;
810 write_dot_separated_list(
811 f,
812 self.catalog
813 .iter()
814 .chain(&self.database)
815 .chain(Some(&self.table)),
816 )?;
817 write!(f, " {}", &self.action)?;
818 if let Some(limit) = self.limit {
819 write!(f, " LIMIT {limit}")?;
820 }
821
822 Ok(())
823 }
824}
825
826#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
827pub struct AnalyzeTableStmt {
828 pub catalog: Option<Identifier>,
829 pub database: Option<Identifier>,
830 pub table: Identifier,
831 pub no_scan: bool,
832}
833
834impl Display for AnalyzeTableStmt {
835 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
836 write!(f, "ANALYZE TABLE ")?;
837 write_dot_separated_list(
838 f,
839 self.catalog
840 .iter()
841 .chain(&self.database)
842 .chain(Some(&self.table)),
843 )?;
844 if self.no_scan {
845 write!(f, " NOSCAN")?;
846 }
847
848 Ok(())
849 }
850}
851
852#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
853pub struct ExistsTableStmt {
854 pub catalog: Option<Identifier>,
855 pub database: Option<Identifier>,
856 pub table: Identifier,
857}
858
859impl Display for ExistsTableStmt {
860 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
861 write!(f, "EXISTS TABLE ")?;
862 write_dot_separated_list(
863 f,
864 self.catalog
865 .iter()
866 .chain(&self.database)
867 .chain(Some(&self.table)),
868 )
869 }
870}
871
872#[derive(Debug, Clone, Copy, PartialEq, Eq, Drive, DriveMut)]
873pub enum Engine {
874 Null,
875 Memory,
876 Fuse,
877 View,
878 Random,
879 Iceberg,
880 Delta,
881}
882
883impl Display for Engine {
884 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
885 match self {
886 Engine::Null => write!(f, "NULL"),
887 Engine::Memory => write!(f, "MEMORY"),
888 Engine::Fuse => write!(f, "FUSE"),
889 Engine::View => write!(f, "VIEW"),
890 Engine::Random => write!(f, "RANDOM"),
891 Engine::Iceberg => write!(f, "ICEBERG"),
892 Engine::Delta => write!(f, "DELTA"),
893 }
894 }
895}
896
897impl From<&str> for Engine {
898 fn from(s: &str) -> Self {
899 match s.to_lowercase().as_str() {
900 "null" => Engine::Null,
901 "memory" => Engine::Memory,
902 "fuse" => Engine::Fuse,
903 "view" => Engine::View,
904 "random" => Engine::Random,
905 "iceberg" => Engine::Iceberg,
906 "delta" => Engine::Delta,
907 _ => unreachable!("invalid engine: {}", s),
908 }
909 }
910}
911
912#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
913pub enum CompactTarget {
914 Block,
915 Segment,
916}
917
918#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
919pub struct VacuumTableOption {
920 pub dry_run: Option<bool>,
922}
923
924impl Display for VacuumTableOption {
925 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
926 if let Some(summary) = self.dry_run {
927 write!(f, "DRY RUN")?;
928 if summary {
929 write!(f, " SUMMARY")?;
930 }
931 }
932 Ok(())
933 }
934}
935
936#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
937pub struct VacuumDropTableOption {
938 pub dry_run: Option<bool>,
940 pub limit: Option<usize>,
941}
942
943impl Display for VacuumDropTableOption {
944 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
945 if let Some(summary) = self.dry_run {
946 write!(f, "DRY RUN")?;
947 if summary {
948 write!(f, " SUMMARY")?;
949 }
950 }
951 if let Some(limit) = self.limit {
952 write!(f, " LIMIT {}", limit)?;
953 }
954 Ok(())
955 }
956}
957
958#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
959pub enum OptimizeTableAction {
960 All,
961 Purge { before: Option<TimeTravelPoint> },
962 Compact { target: CompactTarget },
963}
964
965impl Display for OptimizeTableAction {
966 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
967 match self {
968 OptimizeTableAction::All => write!(f, "ALL"),
969 OptimizeTableAction::Purge { before } => {
970 write!(f, "PURGE")?;
971 if let Some(point) = before {
972 write!(f, " BEFORE {}", point)?;
973 }
974 Ok(())
975 }
976 OptimizeTableAction::Compact { target } => {
977 match target {
978 CompactTarget::Block => {
979 write!(f, "COMPACT")?;
980 }
981 CompactTarget::Segment => {
982 write!(f, "COMPACT SEGMENT")?;
983 }
984 }
985 Ok(())
986 }
987 }
988 }
989}
990
991#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
992pub enum ColumnExpr {
993 Default(Box<Expr>),
994 Virtual(Box<Expr>),
995 Stored(Box<Expr>),
996 AutoIncrement {
997 start: u64,
998 step: i64,
999 is_ordered: bool,
1000 },
1001}
1002
1003impl Display for ColumnExpr {
1004 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1005 match self {
1006 ColumnExpr::Default(expr) => {
1007 write!(f, " DEFAULT {expr}")?;
1008 }
1009 ColumnExpr::Virtual(expr) => {
1010 write!(f, " AS ({expr}) VIRTUAL")?;
1011 }
1012 ColumnExpr::Stored(expr) => {
1013 write!(f, " AS ({expr}) STORED")?;
1014 }
1015 ColumnExpr::AutoIncrement {
1016 start,
1017 step,
1018 is_ordered,
1019 } => {
1020 write!(f, " AUTOINCREMENT ({}, {}) ", start, step)?;
1021 if *is_ordered {
1022 write!(f, "ORDER")?;
1023 } else {
1024 write!(f, "NOORDER")?;
1025 }
1026 }
1027 }
1028 Ok(())
1029 }
1030}
1031
1032#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1033pub enum NullableConstraint {
1034 Null,
1035 NotNull,
1036}
1037
1038#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1039pub struct ColumnDefinition {
1040 pub name: Identifier,
1041 pub data_type: TypeName,
1042 pub expr: Option<ColumnExpr>,
1043 pub check: Option<Expr>,
1044 pub comment: Option<String>,
1045}
1046
1047impl Display for ColumnDefinition {
1048 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1049 write!(f, "{} {}", self.name, self.data_type)?;
1050 if let Some(expr) = &self.expr {
1051 write!(f, "{expr}")?;
1052 }
1053 if let Some(check_expr) = &self.check {
1054 write!(f, " CHECK ({check_expr})")?;
1055 }
1056 if let Some(comment) = &self.comment {
1057 write!(f, " COMMENT {}", QuotedString(comment, '\''))?;
1058 }
1059 Ok(())
1060 }
1061}
1062
1063#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1064pub struct TableIndexDefinition {
1065 pub index_name: Identifier,
1066 pub index_type: TableIndexType,
1067 pub columns: Vec<Identifier>,
1068 pub sync_creation: bool,
1069 pub index_options: BTreeMap<String, String>,
1070}
1071
1072impl Display for TableIndexDefinition {
1073 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1074 if !self.sync_creation {
1075 write!(f, "ASYNC ")?;
1076 }
1077 write!(f, "{} INDEX", self.index_type)?;
1078 write!(f, " {}", self.index_name)?;
1079 write!(f, " (")?;
1080 write_comma_separated_list(f, &self.columns)?;
1081 write!(f, ")")?;
1082
1083 if !self.index_options.is_empty() {
1084 write!(f, " ")?;
1085 write_space_separated_string_map(f, &self.index_options)?;
1086 }
1087
1088 Ok(())
1089 }
1090}
1091
1092#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1093pub struct ConstraintDefinition {
1094 pub name: Option<Identifier>,
1095 pub constraint_type: ConstraintType,
1096}
1097
1098impl Display for ConstraintDefinition {
1099 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1100 if let Some(constraint_name) = &self.name {
1101 write!(f, "CONSTRAINT {} ", constraint_name)?;
1102 }
1103 write!(f, "{}", self.constraint_type)
1104 }
1105}
1106
1107#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1108pub enum CreateDefinition {
1109 Column(ColumnDefinition),
1110 TableIndex(TableIndexDefinition),
1111 Constraint(ConstraintDefinition),
1112}
1113
1114impl Display for CreateDefinition {
1115 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1116 match self {
1117 CreateDefinition::Column(column_def) => {
1118 write!(f, "{}", column_def)?;
1119 }
1120 CreateDefinition::TableIndex(table_index_def) => {
1121 write!(f, "{}", table_index_def)?;
1122 }
1123 CreateDefinition::Constraint(constraint_def) => {
1124 write!(f, "{}", constraint_def)?;
1125 }
1126 }
1127 Ok(())
1128 }
1129}
1130
1131#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1132pub struct ColumnComment {
1133 pub name: Identifier,
1134 pub comment: String,
1135}
1136
1137impl Display for ColumnComment {
1138 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1139 write!(
1140 f,
1141 "{} COMMENT {}",
1142 self.name,
1143 QuotedString(&self.comment, '\'')
1144 )?;
1145 Ok(())
1146 }
1147}
1148
1149#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1150pub enum ModifyColumnAction {
1151 SetMaskingPolicy(Identifier, String, Option<Vec<Identifier>>),
1164 UnsetMaskingPolicy(Identifier),
1166 SetDataType(Vec<ColumnDefinition>),
1168 ConvertStoredComputedColumn(Identifier),
1170 Comment(Vec<ColumnComment>),
1172}
1173
1174impl Display for ModifyColumnAction {
1175 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1176 match &self {
1177 ModifyColumnAction::SetMaskingPolicy(column, name, using_columns) => {
1178 if let Some(using_columns) = using_columns {
1179 write!(f, "{} SET MASKING POLICY {} USING (", column, name)?;
1180 write_comma_separated_list(f, using_columns)?;
1181 write!(f, ")")?
1182 } else {
1183 write!(f, "{} SET MASKING POLICY {}", column, name)?
1184 }
1185 }
1186 ModifyColumnAction::UnsetMaskingPolicy(column) => {
1187 write!(f, "{} UNSET MASKING POLICY", column)?
1188 }
1189 ModifyColumnAction::SetDataType(column_defs) => {
1190 write_comma_separated_list(f, column_defs)?
1191 }
1192 ModifyColumnAction::ConvertStoredComputedColumn(column) => {
1193 write!(f, "{} DROP STORED", column)?
1194 }
1195 ModifyColumnAction::Comment(columns) => write_comma_separated_list(f, columns)?,
1196 }
1197
1198 Ok(())
1199 }
1200}
1201
1202#[derive(Debug, Clone, PartialEq, Drive, DriveMut, Default)]
1203pub struct ShowStatisticsStmt {
1204 pub catalog: Option<Identifier>,
1205 pub database: Option<Identifier>,
1206 pub target: ShowStatsTarget,
1207}
1208
1209#[derive(Debug, Clone, PartialEq, Drive, DriveMut, Default)]
1210pub enum ShowStatsTarget {
1211 #[default]
1212 Database,
1213 Table(Identifier),
1214}
1215
1216impl Display for ShowStatisticsStmt {
1217 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1218 write!(f, "SHOW STATISTICS")?;
1219 match &self.target {
1220 ShowStatsTarget::Database => {
1221 if let Some(database) = &self.database {
1222 write!(f, " FROM DATABASE ")?;
1223 if let Some(catalog) = &self.catalog {
1224 write!(f, "{catalog}.",)?;
1225 }
1226 write!(f, "{database}")?;
1227 }
1228 }
1229 ShowStatsTarget::Table(table) => {
1230 write!(f, " FROM TABLE ")?;
1231 if let Some(database) = &self.database {
1232 if let Some(catalog) = &self.catalog {
1233 write!(f, "{catalog}.",)?;
1234 }
1235 write!(f, "{database}.")?;
1236 }
1237 write!(f, "{table}")?;
1238 }
1239 }
1240 Ok(())
1241 }
1242}