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 sqltk_parser_derive::{Visit, VisitMut};
31
32pub use super::ddl::{ColumnDef, TableConstraint};
33
34use super::{
35 display_comma_separated, display_separated, ClusteredBy, CommentDef, Expr, FileFormat,
36 FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
37 InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens,
38 OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine,
39 TableWithJoins, Tag, WrappedCollection,
40};
41
42#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
46pub struct CreateIndex {
47 pub name: Option<ObjectName>,
49 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
50 pub table_name: ObjectName,
51 pub using: Option<Ident>,
52 pub columns: Vec<OrderByExpr>,
53 pub unique: bool,
54 pub concurrently: bool,
55 pub if_not_exists: bool,
56 pub include: Vec<Ident>,
57 pub nulls_distinct: Option<bool>,
58 pub with: Vec<Expr>,
60 pub predicate: Option<Expr>,
61}
62
63impl Display for CreateIndex {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 write!(
66 f,
67 "CREATE {unique}INDEX {concurrently}{if_not_exists}",
68 unique = if self.unique { "UNIQUE " } else { "" },
69 concurrently = if self.concurrently {
70 "CONCURRENTLY "
71 } else {
72 ""
73 },
74 if_not_exists = if self.if_not_exists {
75 "IF NOT EXISTS "
76 } else {
77 ""
78 },
79 )?;
80 if let Some(value) = &self.name {
81 write!(f, "{value} ")?;
82 }
83 write!(f, "ON {}", self.table_name)?;
84 if let Some(value) = &self.using {
85 write!(f, " USING {value} ")?;
86 }
87 write!(f, "({})", display_separated(&self.columns, ","))?;
88 if !self.include.is_empty() {
89 write!(f, " INCLUDE ({})", display_separated(&self.include, ","))?;
90 }
91 if let Some(value) = self.nulls_distinct {
92 if value {
93 write!(f, " NULLS DISTINCT")?;
94 } else {
95 write!(f, " NULLS NOT DISTINCT")?;
96 }
97 }
98 if !self.with.is_empty() {
99 write!(f, " WITH ({})", display_comma_separated(&self.with))?;
100 }
101 if let Some(predicate) = &self.predicate {
102 write!(f, " WHERE {predicate}")?;
103 }
104 Ok(())
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
110#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
111#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
112pub struct CreateTable {
113 pub or_replace: bool,
114 pub temporary: bool,
115 pub external: bool,
116 pub global: Option<bool>,
117 pub if_not_exists: bool,
118 pub transient: bool,
119 pub volatile: bool,
120 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
122 pub name: ObjectName,
123 pub columns: Vec<ColumnDef>,
125 pub constraints: Vec<TableConstraint>,
126 pub hive_distribution: HiveDistributionStyle,
127 pub hive_formats: Option<HiveFormat>,
128 pub table_properties: Vec<SqlOption>,
129 pub with_options: Vec<SqlOption>,
130 pub file_format: Option<FileFormat>,
131 pub location: Option<String>,
132 pub query: Option<Box<Query>>,
133 pub without_rowid: bool,
134 pub like: Option<ObjectName>,
135 pub clone: Option<ObjectName>,
136 pub engine: Option<TableEngine>,
137 pub comment: Option<CommentDef>,
138 pub auto_increment_offset: Option<u32>,
139 pub default_charset: Option<String>,
140 pub collation: Option<String>,
141 pub on_commit: Option<OnCommit>,
142 pub on_cluster: Option<Ident>,
145 pub primary_key: Option<Box<Expr>>,
148 pub order_by: Option<OneOrManyWithParens<Expr>>,
152 pub partition_by: Option<Box<Expr>>,
155 pub cluster_by: Option<WrappedCollection<Vec<Ident>>>,
158 pub clustered_by: Option<ClusteredBy>,
161 pub options: Option<Vec<SqlOption>>,
164 pub strict: bool,
168 pub copy_grants: bool,
171 pub enable_schema_evolution: Option<bool>,
174 pub change_tracking: Option<bool>,
177 pub data_retention_time_in_days: Option<u64>,
180 pub max_data_extension_time_in_days: Option<u64>,
183 pub default_ddl_collation: Option<String>,
186 pub with_aggregation_policy: Option<ObjectName>,
189 pub with_row_access_policy: Option<RowAccessPolicy>,
192 pub with_tags: Option<Vec<Tag>>,
195}
196
197impl Display for CreateTable {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 write!(
207 f,
208 "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}TABLE {if_not_exists}{name}",
209 or_replace = if self.or_replace { "OR REPLACE " } else { "" },
210 external = if self.external { "EXTERNAL " } else { "" },
211 global = self.global
212 .map(|global| {
213 if global {
214 "GLOBAL "
215 } else {
216 "LOCAL "
217 }
218 })
219 .unwrap_or(""),
220 if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
221 temporary = if self.temporary { "TEMPORARY " } else { "" },
222 transient = if self.transient { "TRANSIENT " } else { "" },
223 volatile = if self.volatile { "VOLATILE " } else { "" },
224 name = self.name,
225 )?;
226 if let Some(on_cluster) = &self.on_cluster {
227 write!(f, " ON CLUSTER {}", on_cluster)?;
228 }
229 if !self.columns.is_empty() || !self.constraints.is_empty() {
230 write!(f, " ({}", display_comma_separated(&self.columns))?;
231 if !self.columns.is_empty() && !self.constraints.is_empty() {
232 write!(f, ", ")?;
233 }
234 write!(f, "{})", display_comma_separated(&self.constraints))?;
235 } else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
236 write!(f, " ()")?;
238 }
239
240 if let Some(CommentDef::AfterColumnDefsWithoutEq(comment)) = &self.comment {
243 write!(f, " COMMENT '{comment}'")?;
244 }
245
246 if self.without_rowid {
248 write!(f, " WITHOUT ROWID")?;
249 }
250
251 if let Some(l) = &self.like {
253 write!(f, " LIKE {l}")?;
254 }
255
256 if let Some(c) = &self.clone {
257 write!(f, " CLONE {c}")?;
258 }
259
260 match &self.hive_distribution {
261 HiveDistributionStyle::PARTITIONED { columns } => {
262 write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
263 }
264 HiveDistributionStyle::SKEWED {
265 columns,
266 on,
267 stored_as_directories,
268 } => {
269 write!(
270 f,
271 " SKEWED BY ({})) ON ({})",
272 display_comma_separated(columns),
273 display_comma_separated(on)
274 )?;
275 if *stored_as_directories {
276 write!(f, " STORED AS DIRECTORIES")?;
277 }
278 }
279 _ => (),
280 }
281
282 if let Some(clustered_by) = &self.clustered_by {
283 write!(f, " {clustered_by}")?;
284 }
285
286 if let Some(HiveFormat {
287 row_format,
288 serde_properties,
289 storage,
290 location,
291 }) = &self.hive_formats
292 {
293 match row_format {
294 Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
295 Some(HiveRowFormat::DELIMITED { delimiters }) => {
296 write!(f, " ROW FORMAT DELIMITED")?;
297 if !delimiters.is_empty() {
298 write!(f, " {}", display_separated(delimiters, " "))?;
299 }
300 }
301 None => (),
302 }
303 match storage {
304 Some(HiveIOFormat::IOF {
305 input_format,
306 output_format,
307 }) => write!(
308 f,
309 " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
310 )?,
311 Some(HiveIOFormat::FileFormat { format }) if !self.external => {
312 write!(f, " STORED AS {format}")?
313 }
314 _ => (),
315 }
316 if let Some(serde_properties) = serde_properties.as_ref() {
317 write!(
318 f,
319 " WITH SERDEPROPERTIES ({})",
320 display_comma_separated(serde_properties)
321 )?;
322 }
323 if !self.external {
324 if let Some(loc) = location {
325 write!(f, " LOCATION '{loc}'")?;
326 }
327 }
328 }
329 if self.external {
330 if let Some(file_format) = self.file_format {
331 write!(f, " STORED AS {file_format}")?;
332 }
333 write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
334 }
335 if !self.table_properties.is_empty() {
336 write!(
337 f,
338 " TBLPROPERTIES ({})",
339 display_comma_separated(&self.table_properties)
340 )?;
341 }
342 if !self.with_options.is_empty() {
343 write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
344 }
345 if let Some(engine) = &self.engine {
346 write!(f, " ENGINE={engine}")?;
347 }
348 if let Some(comment_def) = &self.comment {
349 match comment_def {
350 CommentDef::WithEq(comment) => {
351 write!(f, " COMMENT = '{comment}'")?;
352 }
353 CommentDef::WithoutEq(comment) => {
354 write!(f, " COMMENT '{comment}'")?;
355 }
356 CommentDef::AfterColumnDefsWithoutEq(_) => (),
358 }
359 }
360
361 if let Some(auto_increment_offset) = self.auto_increment_offset {
362 write!(f, " AUTO_INCREMENT {auto_increment_offset}")?;
363 }
364 if let Some(primary_key) = &self.primary_key {
365 write!(f, " PRIMARY KEY {}", primary_key)?;
366 }
367 if let Some(order_by) = &self.order_by {
368 write!(f, " ORDER BY {}", order_by)?;
369 }
370 if let Some(partition_by) = self.partition_by.as_ref() {
371 write!(f, " PARTITION BY {partition_by}")?;
372 }
373 if let Some(cluster_by) = self.cluster_by.as_ref() {
374 write!(f, " CLUSTER BY {cluster_by}")?;
375 }
376
377 if let Some(options) = self.options.as_ref() {
378 write!(
379 f,
380 " OPTIONS({})",
381 display_comma_separated(options.as_slice())
382 )?;
383 }
384
385 if self.copy_grants {
386 write!(f, " COPY GRANTS")?;
387 }
388
389 if let Some(is_enabled) = self.enable_schema_evolution {
390 write!(
391 f,
392 " ENABLE_SCHEMA_EVOLUTION={}",
393 if is_enabled { "TRUE" } else { "FALSE" }
394 )?;
395 }
396
397 if let Some(is_enabled) = self.change_tracking {
398 write!(
399 f,
400 " CHANGE_TRACKING={}",
401 if is_enabled { "TRUE" } else { "FALSE" }
402 )?;
403 }
404
405 if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
406 write!(
407 f,
408 " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
409 )?;
410 }
411
412 if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
413 write!(
414 f,
415 " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
416 )?;
417 }
418
419 if let Some(default_ddl_collation) = &self.default_ddl_collation {
420 write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
421 }
422
423 if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
424 write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
425 }
426
427 if let Some(row_access_policy) = &self.with_row_access_policy {
428 write!(f, " {row_access_policy}",)?;
429 }
430
431 if let Some(tag) = &self.with_tags {
432 write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
433 }
434
435 if let Some(default_charset) = &self.default_charset {
436 write!(f, " DEFAULT CHARSET={default_charset}")?;
437 }
438 if let Some(collation) = &self.collation {
439 write!(f, " COLLATE={collation}")?;
440 }
441
442 if self.on_commit.is_some() {
443 let on_commit = match self.on_commit {
444 Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
445 Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
446 Some(OnCommit::Drop) => "ON COMMIT DROP",
447 None => "",
448 };
449 write!(f, " {on_commit}")?;
450 }
451 if self.strict {
452 write!(f, " STRICT")?;
453 }
454 if let Some(query) = &self.query {
455 write!(f, " AS {query}")?;
456 }
457 Ok(())
458 }
459}
460
461#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
463#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
464#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
465pub struct Insert {
466 pub or: Option<SqliteOnConflict>,
468 pub ignore: bool,
470 pub into: bool,
472 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
474 pub table_name: ObjectName,
475 pub table_alias: Option<Ident>,
477 pub columns: Vec<Ident>,
479 pub overwrite: bool,
481 pub source: Option<Box<Query>>,
483 pub partitioned: Option<Vec<Expr>>,
485 pub after_columns: Vec<Ident>,
487 pub table: bool,
489 pub on: Option<OnInsert>,
490 pub returning: Option<Vec<SelectItem>>,
492 pub replace_into: bool,
494 pub priority: Option<MysqlInsertPriority>,
496 pub insert_alias: Option<InsertAliases>,
498}
499
500impl Display for Insert {
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502 let table_name = if let Some(alias) = &self.table_alias {
503 format!("{0} AS {alias}", self.table_name)
504 } else {
505 self.table_name.to_string()
506 };
507
508 if let Some(on_conflict) = self.or {
509 write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
510 } else {
511 write!(
512 f,
513 "{start}",
514 start = if self.replace_into {
515 "REPLACE"
516 } else {
517 "INSERT"
518 },
519 )?;
520 if let Some(priority) = self.priority {
521 write!(f, " {priority}",)?;
522 }
523
524 write!(
525 f,
526 "{ignore}{over}{int}{tbl} {table_name} ",
527 table_name = table_name,
528 ignore = if self.ignore { " IGNORE" } else { "" },
529 over = if self.overwrite { " OVERWRITE" } else { "" },
530 int = if self.into { " INTO" } else { "" },
531 tbl = if self.table { " TABLE" } else { "" },
532 )?;
533 }
534 if !self.columns.is_empty() {
535 write!(f, "({}) ", display_comma_separated(&self.columns))?;
536 }
537 if let Some(ref parts) = self.partitioned {
538 if !parts.is_empty() {
539 write!(f, "PARTITION ({}) ", display_comma_separated(parts))?;
540 }
541 }
542 if !self.after_columns.is_empty() {
543 write!(f, "({}) ", display_comma_separated(&self.after_columns))?;
544 }
545
546 if let Some(source) = &self.source {
547 write!(f, "{source}")?;
548 }
549
550 if self.source.is_none() && self.columns.is_empty() {
551 write!(f, "DEFAULT VALUES")?;
552 }
553
554 if let Some(insert_alias) = &self.insert_alias {
555 write!(f, " AS {0}", insert_alias.row_alias)?;
556
557 if let Some(col_aliases) = &insert_alias.col_aliases {
558 if !col_aliases.is_empty() {
559 write!(f, " ({})", display_comma_separated(col_aliases))?;
560 }
561 }
562 }
563
564 if let Some(on) = &self.on {
565 write!(f, "{on}")?;
566 }
567
568 if let Some(returning) = &self.returning {
569 write!(f, " RETURNING {}", display_comma_separated(returning))?;
570 }
571 Ok(())
572 }
573}
574
575#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
577#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
578#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
579pub struct Delete {
580 pub tables: Vec<ObjectName>,
582 pub from: FromTable,
584 pub using: Option<Vec<TableWithJoins>>,
586 pub selection: Option<Expr>,
588 pub returning: Option<Vec<SelectItem>>,
590 pub order_by: Vec<OrderByExpr>,
592 pub limit: Option<Expr>,
594}
595
596impl Display for Delete {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 write!(f, "DELETE ")?;
599 if !self.tables.is_empty() {
600 write!(f, "{} ", display_comma_separated(&self.tables))?;
601 }
602 match &self.from {
603 FromTable::WithFromKeyword(from) => {
604 write!(f, "FROM {}", display_comma_separated(from))?;
605 }
606 FromTable::WithoutKeyword(from) => {
607 write!(f, "{}", display_comma_separated(from))?;
608 }
609 }
610 if let Some(using) = &self.using {
611 write!(f, " USING {}", display_comma_separated(using))?;
612 }
613 if let Some(selection) = &self.selection {
614 write!(f, " WHERE {selection}")?;
615 }
616 if let Some(returning) = &self.returning {
617 write!(f, " RETURNING {}", display_comma_separated(returning))?;
618 }
619 if !self.order_by.is_empty() {
620 write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
621 }
622 if let Some(limit) = &self.limit {
623 write!(f, " LIMIT {limit}")?;
624 }
625 Ok(())
626 }
627}