1#[cfg(not(feature = "std"))]
19use alloc::{
20 boxed::Box,
21 format,
22 string::{String, ToString},
23 vec::Vec,
24};
25
26use core::fmt::{self, Display};
27#[cfg(feature = "serde")]
28use serde::{Deserialize, Serialize};
29#[cfg(feature = "visitor")]
30use sqlparser_derive::{Visit, VisitMut};
31
32pub use super::ddl::{ColumnDef, TableConstraint};
33
34use super::{
35 display_comma_separated, display_separated, query::InputFormatClause, Assignment, ClusteredBy,
36 CommentDef, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat,
37 HiveRowFormat, Ident, IndexType, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit,
38 OnInsert, OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, Setting,
39 SqlOption, SqliteOnConflict, StorageSerializationPolicy, TableEngine, TableObject,
40 TableWithJoins, Tag, WrappedCollection,
41};
42
43#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
47pub struct IndexColumn {
48 pub column: OrderByExpr,
49 pub operator_class: Option<Ident>,
50}
51
52impl Display for IndexColumn {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 write!(f, "{}", self.column)?;
55 if let Some(operator_class) = &self.operator_class {
56 write!(f, " {}", operator_class)?;
57 }
58 Ok(())
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
66pub struct CreateIndex {
67 pub name: Option<ObjectName>,
69 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
70 pub table_name: ObjectName,
71 pub using: Option<IndexType>,
72 pub columns: Vec<IndexColumn>,
73 pub unique: bool,
74 pub concurrently: bool,
75 pub if_not_exists: bool,
76 pub include: Vec<Ident>,
77 pub nulls_distinct: Option<bool>,
78 pub with: Vec<Expr>,
80 pub predicate: Option<Expr>,
81}
82
83impl Display for CreateIndex {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 write!(
86 f,
87 "CREATE {unique}INDEX {concurrently}{if_not_exists}",
88 unique = if self.unique { "UNIQUE " } else { "" },
89 concurrently = if self.concurrently {
90 "CONCURRENTLY "
91 } else {
92 ""
93 },
94 if_not_exists = if self.if_not_exists {
95 "IF NOT EXISTS "
96 } else {
97 ""
98 },
99 )?;
100 if let Some(value) = &self.name {
101 write!(f, "{value} ")?;
102 }
103 write!(f, "ON {}", self.table_name)?;
104 if let Some(value) = &self.using {
105 write!(f, " USING {value} ")?;
106 }
107 write!(f, "({})", display_separated(&self.columns, ","))?;
108 if !self.include.is_empty() {
109 write!(f, " INCLUDE ({})", display_separated(&self.include, ","))?;
110 }
111 if let Some(value) = self.nulls_distinct {
112 if value {
113 write!(f, " NULLS DISTINCT")?;
114 } else {
115 write!(f, " NULLS NOT DISTINCT")?;
116 }
117 }
118 if !self.with.is_empty() {
119 write!(f, " WITH ({})", display_comma_separated(&self.with))?;
120 }
121 if let Some(predicate) = &self.predicate {
122 write!(f, " WHERE {predicate}")?;
123 }
124 Ok(())
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
130#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
131#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
132pub struct CreateTable {
133 pub or_replace: bool,
134 pub temporary: bool,
135 pub external: bool,
136 pub global: Option<bool>,
137 pub if_not_exists: bool,
138 pub transient: bool,
139 pub volatile: bool,
140 pub iceberg: bool,
141 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
143 pub name: ObjectName,
144 pub columns: Vec<ColumnDef>,
146 pub constraints: Vec<TableConstraint>,
147 pub hive_distribution: HiveDistributionStyle,
148 pub hive_formats: Option<HiveFormat>,
149 pub table_properties: Vec<SqlOption>,
150 pub with_options: Vec<SqlOption>,
151 pub file_format: Option<FileFormat>,
152 pub location: Option<String>,
153 pub query: Option<Box<Query>>,
154 pub without_rowid: bool,
155 pub like: Option<ObjectName>,
156 pub clone: Option<ObjectName>,
157 pub engine: Option<TableEngine>,
158 pub comment: Option<CommentDef>,
159 pub auto_increment_offset: Option<u32>,
160 pub default_charset: Option<String>,
161 pub collation: Option<String>,
162 pub on_commit: Option<OnCommit>,
163 pub on_cluster: Option<Ident>,
166 pub primary_key: Option<Box<Expr>>,
169 pub order_by: Option<OneOrManyWithParens<Expr>>,
173 pub partition_by: Option<Box<Expr>>,
176 pub cluster_by: Option<WrappedCollection<Vec<Ident>>>,
179 pub clustered_by: Option<ClusteredBy>,
182 pub options: Option<Vec<SqlOption>>,
185 pub inherits: Option<Vec<ObjectName>>,
190 pub strict: bool,
194 pub copy_grants: bool,
197 pub enable_schema_evolution: Option<bool>,
200 pub change_tracking: Option<bool>,
203 pub data_retention_time_in_days: Option<u64>,
206 pub max_data_extension_time_in_days: Option<u64>,
209 pub default_ddl_collation: Option<String>,
212 pub with_aggregation_policy: Option<ObjectName>,
215 pub with_row_access_policy: Option<RowAccessPolicy>,
218 pub with_tags: Option<Vec<Tag>>,
221 pub external_volume: Option<String>,
224 pub base_location: Option<String>,
227 pub catalog: Option<String>,
230 pub catalog_sync: Option<String>,
233 pub storage_serialization_policy: Option<StorageSerializationPolicy>,
236}
237
238impl Display for CreateTable {
239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 write!(
248 f,
249 "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{iceberg}TABLE {if_not_exists}{name}",
250 or_replace = if self.or_replace { "OR REPLACE " } else { "" },
251 external = if self.external { "EXTERNAL " } else { "" },
252 global = self.global
253 .map(|global| {
254 if global {
255 "GLOBAL "
256 } else {
257 "LOCAL "
258 }
259 })
260 .unwrap_or(""),
261 if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
262 temporary = if self.temporary { "TEMPORARY " } else { "" },
263 transient = if self.transient { "TRANSIENT " } else { "" },
264 volatile = if self.volatile { "VOLATILE " } else { "" },
265 iceberg = if self.iceberg { "ICEBERG " } else { "" },
267 name = self.name,
268 )?;
269 if let Some(on_cluster) = &self.on_cluster {
270 write!(f, " ON CLUSTER {}", on_cluster)?;
271 }
272 if !self.columns.is_empty() || !self.constraints.is_empty() {
273 write!(f, " ({}", display_comma_separated(&self.columns))?;
274 if !self.columns.is_empty() && !self.constraints.is_empty() {
275 write!(f, ", ")?;
276 }
277 write!(f, "{})", display_comma_separated(&self.constraints))?;
278 } else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
279 write!(f, " ()")?;
281 }
282
283 if let Some(CommentDef::AfterColumnDefsWithoutEq(comment)) = &self.comment {
286 write!(f, " COMMENT '{comment}'")?;
287 }
288
289 if self.without_rowid {
291 write!(f, " WITHOUT ROWID")?;
292 }
293
294 if let Some(l) = &self.like {
296 write!(f, " LIKE {l}")?;
297 }
298
299 if let Some(c) = &self.clone {
300 write!(f, " CLONE {c}")?;
301 }
302
303 match &self.hive_distribution {
304 HiveDistributionStyle::PARTITIONED { columns } => {
305 write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
306 }
307 HiveDistributionStyle::SKEWED {
308 columns,
309 on,
310 stored_as_directories,
311 } => {
312 write!(
313 f,
314 " SKEWED BY ({})) ON ({})",
315 display_comma_separated(columns),
316 display_comma_separated(on)
317 )?;
318 if *stored_as_directories {
319 write!(f, " STORED AS DIRECTORIES")?;
320 }
321 }
322 _ => (),
323 }
324
325 if let Some(clustered_by) = &self.clustered_by {
326 write!(f, " {clustered_by}")?;
327 }
328
329 if let Some(HiveFormat {
330 row_format,
331 serde_properties,
332 storage,
333 location,
334 }) = &self.hive_formats
335 {
336 match row_format {
337 Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
338 Some(HiveRowFormat::DELIMITED { delimiters }) => {
339 write!(f, " ROW FORMAT DELIMITED")?;
340 if !delimiters.is_empty() {
341 write!(f, " {}", display_separated(delimiters, " "))?;
342 }
343 }
344 None => (),
345 }
346 match storage {
347 Some(HiveIOFormat::IOF {
348 input_format,
349 output_format,
350 }) => write!(
351 f,
352 " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
353 )?,
354 Some(HiveIOFormat::FileFormat { format }) if !self.external => {
355 write!(f, " STORED AS {format}")?
356 }
357 _ => (),
358 }
359 if let Some(serde_properties) = serde_properties.as_ref() {
360 write!(
361 f,
362 " WITH SERDEPROPERTIES ({})",
363 display_comma_separated(serde_properties)
364 )?;
365 }
366 if !self.external {
367 if let Some(loc) = location {
368 write!(f, " LOCATION '{loc}'")?;
369 }
370 }
371 }
372 if self.external {
373 if let Some(file_format) = self.file_format {
374 write!(f, " STORED AS {file_format}")?;
375 }
376 write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
377 }
378 if !self.table_properties.is_empty() {
379 write!(
380 f,
381 " TBLPROPERTIES ({})",
382 display_comma_separated(&self.table_properties)
383 )?;
384 }
385 if !self.with_options.is_empty() {
386 write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
387 }
388 if let Some(engine) = &self.engine {
389 write!(f, " ENGINE={engine}")?;
390 }
391 if let Some(comment_def) = &self.comment {
392 match comment_def {
393 CommentDef::WithEq(comment) => {
394 write!(f, " COMMENT = '{comment}'")?;
395 }
396 CommentDef::WithoutEq(comment) => {
397 write!(f, " COMMENT '{comment}'")?;
398 }
399 CommentDef::AfterColumnDefsWithoutEq(_) => (),
401 }
402 }
403
404 if let Some(auto_increment_offset) = self.auto_increment_offset {
405 write!(f, " AUTO_INCREMENT {auto_increment_offset}")?;
406 }
407 if let Some(primary_key) = &self.primary_key {
408 write!(f, " PRIMARY KEY {}", primary_key)?;
409 }
410 if let Some(order_by) = &self.order_by {
411 write!(f, " ORDER BY {}", order_by)?;
412 }
413 if let Some(inherits) = &self.inherits {
414 write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
415 }
416 if let Some(partition_by) = self.partition_by.as_ref() {
417 write!(f, " PARTITION BY {partition_by}")?;
418 }
419 if let Some(cluster_by) = self.cluster_by.as_ref() {
420 write!(f, " CLUSTER BY {cluster_by}")?;
421 }
422
423 if let Some(options) = self.options.as_ref() {
424 write!(
425 f,
426 " OPTIONS({})",
427 display_comma_separated(options.as_slice())
428 )?;
429 }
430
431 if let Some(external_volume) = self.external_volume.as_ref() {
432 write!(f, " EXTERNAL_VOLUME = '{external_volume}'")?;
433 }
434
435 if let Some(catalog) = self.catalog.as_ref() {
436 write!(f, " CATALOG = '{catalog}'")?;
437 }
438
439 if self.iceberg {
440 if let Some(base_location) = self.base_location.as_ref() {
441 write!(f, " BASE_LOCATION = '{base_location}'")?;
442 }
443 }
444
445 if let Some(catalog_sync) = self.catalog_sync.as_ref() {
446 write!(f, " CATALOG_SYNC = '{catalog_sync}'")?;
447 }
448
449 if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
450 write!(
451 f,
452 " STORAGE_SERIALIZATION_POLICY = {storage_serialization_policy}"
453 )?;
454 }
455
456 if self.copy_grants {
457 write!(f, " COPY GRANTS")?;
458 }
459
460 if let Some(is_enabled) = self.enable_schema_evolution {
461 write!(
462 f,
463 " ENABLE_SCHEMA_EVOLUTION={}",
464 if is_enabled { "TRUE" } else { "FALSE" }
465 )?;
466 }
467
468 if let Some(is_enabled) = self.change_tracking {
469 write!(
470 f,
471 " CHANGE_TRACKING={}",
472 if is_enabled { "TRUE" } else { "FALSE" }
473 )?;
474 }
475
476 if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
477 write!(
478 f,
479 " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
480 )?;
481 }
482
483 if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
484 write!(
485 f,
486 " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
487 )?;
488 }
489
490 if let Some(default_ddl_collation) = &self.default_ddl_collation {
491 write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
492 }
493
494 if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
495 write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
496 }
497
498 if let Some(row_access_policy) = &self.with_row_access_policy {
499 write!(f, " {row_access_policy}",)?;
500 }
501
502 if let Some(tag) = &self.with_tags {
503 write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
504 }
505
506 if let Some(default_charset) = &self.default_charset {
507 write!(f, " DEFAULT CHARSET={default_charset}")?;
508 }
509 if let Some(collation) = &self.collation {
510 write!(f, " COLLATE={collation}")?;
511 }
512
513 if self.on_commit.is_some() {
514 let on_commit = match self.on_commit {
515 Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
516 Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
517 Some(OnCommit::Drop) => "ON COMMIT DROP",
518 None => "",
519 };
520 write!(f, " {on_commit}")?;
521 }
522 if self.strict {
523 write!(f, " STRICT")?;
524 }
525 if let Some(query) = &self.query {
526 write!(f, " AS {query}")?;
527 }
528 Ok(())
529 }
530}
531
532#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
534#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
535#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
536pub struct Insert {
537 pub or: Option<SqliteOnConflict>,
539 pub ignore: bool,
541 pub into: bool,
543 pub table: TableObject,
545 pub table_alias: Option<Ident>,
547 pub columns: Vec<Ident>,
549 pub overwrite: bool,
551 pub source: Option<Box<Query>>,
553 pub assignments: Vec<Assignment>,
556 pub partitioned: Option<Vec<Expr>>,
558 pub after_columns: Vec<Ident>,
560 pub has_table_keyword: bool,
562 pub on: Option<OnInsert>,
563 pub returning: Option<Vec<SelectItem>>,
565 pub replace_into: bool,
567 pub priority: Option<MysqlInsertPriority>,
569 pub insert_alias: Option<InsertAliases>,
571 pub settings: Option<Vec<Setting>>,
577 pub format_clause: Option<InputFormatClause>,
584}
585
586impl Display for Insert {
587 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
588 let table_name = if let Some(alias) = &self.table_alias {
589 format!("{0} AS {alias}", self.table)
590 } else {
591 self.table.to_string()
592 };
593
594 if let Some(on_conflict) = self.or {
595 write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
596 } else {
597 write!(
598 f,
599 "{start}",
600 start = if self.replace_into {
601 "REPLACE"
602 } else {
603 "INSERT"
604 },
605 )?;
606 if let Some(priority) = self.priority {
607 write!(f, " {priority}",)?;
608 }
609
610 write!(
611 f,
612 "{ignore}{over}{int}{tbl} {table_name} ",
613 table_name = table_name,
614 ignore = if self.ignore { " IGNORE" } else { "" },
615 over = if self.overwrite { " OVERWRITE" } else { "" },
616 int = if self.into { " INTO" } else { "" },
617 tbl = if self.has_table_keyword { " TABLE" } else { "" },
618 )?;
619 }
620 if !self.columns.is_empty() {
621 write!(f, "({}) ", display_comma_separated(&self.columns))?;
622 }
623 if let Some(ref parts) = self.partitioned {
624 if !parts.is_empty() {
625 write!(f, "PARTITION ({}) ", display_comma_separated(parts))?;
626 }
627 }
628 if !self.after_columns.is_empty() {
629 write!(f, "({}) ", display_comma_separated(&self.after_columns))?;
630 }
631
632 if let Some(settings) = &self.settings {
633 write!(f, "SETTINGS {} ", display_comma_separated(settings))?;
634 }
635
636 if let Some(source) = &self.source {
637 write!(f, "{source}")?;
638 } else if !self.assignments.is_empty() {
639 write!(f, "SET ")?;
640 write!(f, "{}", display_comma_separated(&self.assignments))?;
641 } else if let Some(format_clause) = &self.format_clause {
642 write!(f, "{format_clause}")?;
643 } else if self.columns.is_empty() {
644 write!(f, "DEFAULT VALUES")?;
645 }
646
647 if let Some(insert_alias) = &self.insert_alias {
648 write!(f, " AS {0}", insert_alias.row_alias)?;
649
650 if let Some(col_aliases) = &insert_alias.col_aliases {
651 if !col_aliases.is_empty() {
652 write!(f, " ({})", display_comma_separated(col_aliases))?;
653 }
654 }
655 }
656
657 if let Some(on) = &self.on {
658 write!(f, "{on}")?;
659 }
660
661 if let Some(returning) = &self.returning {
662 write!(f, " RETURNING {}", display_comma_separated(returning))?;
663 }
664 Ok(())
665 }
666}
667
668#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
670#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
671#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
672pub struct Delete {
673 pub tables: Vec<ObjectName>,
675 pub from: FromTable,
677 pub using: Option<Vec<TableWithJoins>>,
679 pub selection: Option<Expr>,
681 pub returning: Option<Vec<SelectItem>>,
683 pub order_by: Vec<OrderByExpr>,
685 pub limit: Option<Expr>,
687}
688
689impl Display for Delete {
690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
691 write!(f, "DELETE ")?;
692 if !self.tables.is_empty() {
693 write!(f, "{} ", display_comma_separated(&self.tables))?;
694 }
695 match &self.from {
696 FromTable::WithFromKeyword(from) => {
697 write!(f, "FROM {}", display_comma_separated(from))?;
698 }
699 FromTable::WithoutKeyword(from) => {
700 write!(f, "{}", display_comma_separated(from))?;
701 }
702 }
703 if let Some(using) = &self.using {
704 write!(f, " USING {}", display_comma_separated(using))?;
705 }
706 if let Some(selection) = &self.selection {
707 write!(f, " WHERE {selection}")?;
708 }
709 if let Some(returning) = &self.returning {
710 write!(f, " RETURNING {}", display_comma_separated(returning))?;
711 }
712 if !self.order_by.is_empty() {
713 write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
714 }
715 if let Some(limit) = &self.limit {
716 write!(f, " LIMIT {limit}")?;
717 }
718 Ok(())
719 }
720}