sqlparser/ast/
ddl.rs1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to CREATE/ALTER variants of [`Statement`](crate::ast::Statement)
19//! (commonly referred to as Data Definition Language, or DDL)
20
21#[cfg(not(feature = "std"))]
22use alloc::{
23 boxed::Box,
24 format,
25 string::{String, ToString},
26 vec,
27 vec::Vec,
28};
29use core::fmt::{self, Display, Write};
30
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33
34#[cfg(feature = "visitor")]
35use sqlparser_derive::{Visit, VisitMut};
36
37use crate::ast::value::escape_single_quote_string;
38use crate::ast::{
39 display_comma_separated, display_separated,
40 table_constraints::{
41 CheckConstraint, ForeignKeyConstraint, PrimaryKeyConstraint, TableConstraint,
42 UniqueConstraint,
43 },
44 ArgMode, AttachedToken, CommentDef, ConditionalStatements, CreateFunctionBody,
45 CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions, CreateViewParams, DataType, Expr,
46 FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDefinitionSetParam, FunctionDesc,
47 FunctionDeterminismSpecifier, FunctionParallel, FunctionSecurity, HiveDistributionStyle,
48 HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident, InitializeKind,
49 MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg,
50 OrderByExpr, ProjectionSelect, Query, RefreshModeKind, RowAccessPolicy, SequenceOptions,
51 Spanned, SqlOption, StorageSerializationPolicy, TableVersion, Tag, TriggerEvent,
52 TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value, ValueWithSpan,
53 WrappedCollection,
54};
55use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
56use crate::keywords::Keyword;
57use crate::tokenizer::{Span, Token};
58
59/// Index column type.
60#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
63pub struct IndexColumn {
64 /// The indexed column expression.
65 pub column: OrderByExpr,
66 /// Optional operator class (index operator name).
67 pub operator_class: Option<ObjectName>,
68}
69
70impl From<Ident> for IndexColumn {
71 fn from(c: Ident) -> Self {
72 Self {
73 column: OrderByExpr::from(c),
74 operator_class: None,
75 }
76 }
77}
78
79impl<'a> From<&'a str> for IndexColumn {
80 fn from(c: &'a str) -> Self {
81 let ident = Ident::new(c);
82 ident.into()
83 }
84}
85
86impl fmt::Display for IndexColumn {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 write!(f, "{}", self.column)?;
89 if let Some(operator_class) = &self.operator_class {
90 write!(f, " {operator_class}")?;
91 }
92 Ok(())
93 }
94}
95
96/// ALTER TABLE operation REPLICA IDENTITY values
97/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
98#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
101pub enum ReplicaIdentity {
102 /// No replica identity (`REPLICA IDENTITY NOTHING`).
103 Nothing,
104 /// Full replica identity (`REPLICA IDENTITY FULL`).
105 Full,
106 /// Default replica identity (`REPLICA IDENTITY DEFAULT`).
107 Default,
108 /// Use the given index as replica identity (`REPLICA IDENTITY USING INDEX`).
109 Index(Ident),
110}
111
112impl fmt::Display for ReplicaIdentity {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match self {
115 ReplicaIdentity::Nothing => f.write_str("NOTHING"),
116 ReplicaIdentity::Full => f.write_str("FULL"),
117 ReplicaIdentity::Default => f.write_str("DEFAULT"),
118 ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
119 }
120 }
121}
122
123/// An `ALTER TABLE` (`Statement::AlterTable`) operation
124#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
127pub enum AlterTableOperation {
128 /// `ADD <table_constraint> [NOT VALID]`
129 AddConstraint {
130 /// The table constraint to add.
131 constraint: TableConstraint,
132 /// Whether the constraint should be marked `NOT VALID`.
133 not_valid: bool,
134 },
135 /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
136 AddColumn {
137 /// `[COLUMN]`.
138 column_keyword: bool,
139 /// `[IF NOT EXISTS]`
140 if_not_exists: bool,
141 /// <column_def>.
142 column_def: ColumnDef,
143 /// MySQL `ALTER TABLE` only [FIRST | AFTER column_name]
144 column_position: Option<MySQLColumnPosition>,
145 },
146 /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
147 ///
148 /// Note: this is a ClickHouse-specific operation.
149 /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
150 AddProjection {
151 /// Whether `IF NOT EXISTS` was specified.
152 if_not_exists: bool,
153 /// Name of the projection to add.
154 name: Ident,
155 /// The projection's select clause.
156 select: ProjectionSelect,
157 },
158 /// `DROP PROJECTION [IF EXISTS] name`
159 ///
160 /// Note: this is a ClickHouse-specific operation.
161 /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
162 DropProjection {
163 /// Whether `IF EXISTS` was specified.
164 if_exists: bool,
165 /// Name of the projection to drop.
166 name: Ident,
167 },
168 /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
169 ///
170 /// Note: this is a ClickHouse-specific operation.
171 /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
172 MaterializeProjection {
173 /// Whether `IF EXISTS` was specified.
174 if_exists: bool,
175 /// Name of the projection to materialize.
176 name: Ident,
177 /// Optional partition name to operate on.
178 partition: Option<Ident>,
179 },
180 /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
181 ///
182 /// Note: this is a ClickHouse-specific operation.
183 /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
184 ClearProjection {
185 /// Whether `IF EXISTS` was specified.
186 if_exists: bool,
187 /// Name of the projection to clear.
188 name: Ident,
189 /// Optional partition name to operate on.
190 partition: Option<Ident>,
191 },
192 /// `DISABLE ROW LEVEL SECURITY`
193 ///
194 /// Note: this is a PostgreSQL-specific operation.
195 /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
196 DisableRowLevelSecurity,
197 /// `DISABLE RULE rewrite_rule_name`
198 ///
199 /// Note: this is a PostgreSQL-specific operation.
200 DisableRule {
201 /// Name of the rule to disable.
202 name: Ident,
203 },
204 /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
205 ///
206 /// Note: this is a PostgreSQL-specific operation.
207 DisableTrigger {
208 /// Name of the trigger to disable (or ALL/USER).
209 name: Ident,
210 },
211 /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
212 DropConstraint {
213 /// `IF EXISTS` flag for dropping the constraint.
214 if_exists: bool,
215 /// Name of the constraint to drop.
216 name: Ident,
217 /// Optional drop behavior (`CASCADE`/`RESTRICT`).
218 drop_behavior: Option<DropBehavior>,
219 },
220 /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
221 DropColumn {
222 /// Whether the `COLUMN` keyword was present.
223 has_column_keyword: bool,
224 /// Names of columns to drop.
225 column_names: Vec<Ident>,
226 /// Whether `IF EXISTS` was specified for the columns.
227 if_exists: bool,
228 /// Optional drop behavior for the column removal.
229 drop_behavior: Option<DropBehavior>,
230 },
231 /// `ATTACH PART|PARTITION <partition_expr>`
232 /// Note: this is a ClickHouse-specific operation, please refer to
233 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
234 AttachPartition {
235 // PART is not a short form of PARTITION, it's a separate keyword
236 // which represents a physical file on disk and partition is a logical entity.
237 /// Partition expression to attach.
238 partition: Partition,
239 },
240 /// `DETACH PART|PARTITION <partition_expr>`
241 /// Note: this is a ClickHouse-specific operation, please refer to
242 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
243 DetachPartition {
244 // See `AttachPartition` for more details
245 /// Partition expression to detach.
246 partition: Partition,
247 },
248 /// `FREEZE PARTITION <partition_expr>`
249 /// Note: this is a ClickHouse-specific operation, please refer to
250 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
251 FreezePartition {
252 /// Partition to freeze.
253 partition: Partition,
254 /// Optional name for the freeze operation.
255 with_name: Option<Ident>,
256 },
257 /// `UNFREEZE PARTITION <partition_expr>`
258 /// Note: this is a ClickHouse-specific operation, please refer to
259 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
260 UnfreezePartition {
261 /// Partition to unfreeze.
262 partition: Partition,
263 /// Optional name associated with the unfreeze operation.
264 with_name: Option<Ident>,
265 },
266 /// `DROP PRIMARY KEY`
267 ///
268 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
269 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
270 DropPrimaryKey {
271 /// Optional drop behavior for the primary key (`CASCADE`/`RESTRICT`).
272 drop_behavior: Option<DropBehavior>,
273 },
274 /// `DROP FOREIGN KEY <fk_symbol>`
275 ///
276 /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
277 /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
278 DropForeignKey {
279 /// Foreign key symbol/name to drop.
280 name: Ident,
281 /// Optional drop behavior for the foreign key.
282 drop_behavior: Option<DropBehavior>,
283 },
284 /// `DROP INDEX <index_name>`
285 ///
286 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
287 DropIndex {
288 /// Name of the index to drop.
289 name: Ident,
290 },
291 /// `ENABLE ALWAYS RULE rewrite_rule_name`
292 ///
293 /// Note: this is a PostgreSQL-specific operation.
294 EnableAlwaysRule {
295 /// Name of the rule to enable.
296 name: Ident,
297 },
298 /// `ENABLE ALWAYS TRIGGER trigger_name`
299 ///
300 /// Note: this is a PostgreSQL-specific operation.
301 EnableAlwaysTrigger {
302 /// Name of the trigger to enable.
303 name: Ident,
304 },
305 /// `ENABLE REPLICA RULE rewrite_rule_name`
306 ///
307 /// Note: this is a PostgreSQL-specific operation.
308 EnableReplicaRule {
309 /// Name of the replica rule to enable.
310 name: Ident,
311 },
312 /// `ENABLE REPLICA TRIGGER trigger_name`
313 ///
314 /// Note: this is a PostgreSQL-specific operation.
315 EnableReplicaTrigger {
316 /// Name of the replica trigger to enable.
317 name: Ident,
318 },
319 /// `ENABLE ROW LEVEL SECURITY`
320 ///
321 /// Note: this is a PostgreSQL-specific operation.
322 /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
323 EnableRowLevelSecurity,
324 /// `FORCE ROW LEVEL SECURITY`
325 ///
326 /// Note: this is a PostgreSQL-specific operation.
327 /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
328 ForceRowLevelSecurity,
329 /// `NO FORCE ROW LEVEL SECURITY`
330 ///
331 /// Note: this is a PostgreSQL-specific operation.
332 /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
333 NoForceRowLevelSecurity,
334 /// `ENABLE RULE rewrite_rule_name`
335 ///
336 /// Note: this is a PostgreSQL-specific operation.
337 EnableRule {
338 /// Name of the rule to enable.
339 name: Ident,
340 },
341 /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
342 ///
343 /// Note: this is a PostgreSQL-specific operation.
344 EnableTrigger {
345 /// Name of the trigger to enable (or ALL/USER).
346 name: Ident,
347 },
348 /// `RENAME TO PARTITION (partition=val)`
349 RenamePartitions {
350 /// Old partition expressions to be renamed.
351 old_partitions: Vec<Expr>,
352 /// New partition expressions corresponding to the old ones.
353 new_partitions: Vec<Expr>,
354 },
355 /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
356 ///
357 /// Note: this is a PostgreSQL-specific operation.
358 /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
359 ReplicaIdentity {
360 /// Replica identity setting to apply.
361 identity: ReplicaIdentity,
362 },
363 /// Add Partitions
364 AddPartitions {
365 /// Whether `IF NOT EXISTS` was present when adding partitions.
366 if_not_exists: bool,
367 /// New partitions to add.
368 new_partitions: Vec<Partition>,
369 },
370 /// `DROP PARTITIONS ...` / drop partitions from the table.
371 DropPartitions {
372 /// Partitions to drop (expressions).
373 partitions: Vec<Expr>,
374 /// Whether `IF EXISTS` was specified for dropping partitions.
375 if_exists: bool,
376 },
377 /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
378 RenameColumn {
379 /// Existing column name to rename.
380 old_column_name: Ident,
381 /// New column name.
382 new_column_name: Ident,
383 },
384 /// `RENAME TO <table_name>`
385 RenameTable {
386 /// The new table name or renaming kind.
387 table_name: RenameTableNameKind,
388 },
389 // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
390 /// Change an existing column's name, type, and options.
391 ChangeColumn {
392 /// Old column name.
393 old_name: Ident,
394 /// New column name.
395 new_name: Ident,
396 /// New data type for the column.
397 data_type: DataType,
398 /// Column options to apply after the change.
399 options: Vec<ColumnOption>,
400 /// MySQL-specific column position (`FIRST`/`AFTER`).
401 column_position: Option<MySQLColumnPosition>,
402 },
403 // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
404 /// Modify an existing column's type and options.
405 ModifyColumn {
406 /// Column name to modify.
407 col_name: Ident,
408 /// New data type for the column.
409 data_type: DataType,
410 /// Column options to set.
411 options: Vec<ColumnOption>,
412 /// MySQL-specific column position (`FIRST`/`AFTER`).
413 column_position: Option<MySQLColumnPosition>,
414 },
415 /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
416 ///
417 /// Note: this is a PostgreSQL-specific operation.
418 /// Rename a constraint on the table.
419 RenameConstraint {
420 /// Existing constraint name.
421 old_name: Ident,
422 /// New constraint name.
423 new_name: Ident,
424 },
425 /// `ALTER [ COLUMN ]`
426 /// Alter a specific column with the provided operation.
427 AlterColumn {
428 /// The column to alter.
429 column_name: Ident,
430 /// Operation to apply to the column.
431 op: AlterColumnOperation,
432 },
433 /// 'SWAP WITH <table_name>'
434 ///
435 /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
436 SwapWith {
437 /// Table name to swap with.
438 table_name: ObjectName,
439 },
440 /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
441 SetTblProperties {
442 /// Table properties specified as SQL options.
443 table_properties: Vec<SqlOption>,
444 },
445 /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
446 ///
447 /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
448 OwnerTo {
449 /// The new owner to assign to the table.
450 new_owner: Owner,
451 },
452 /// Snowflake table clustering options
453 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
454 ClusterBy {
455 /// Expressions used for clustering the table.
456 exprs: Vec<Expr>,
457 },
458 /// Remove the clustering key from the table.
459 DropClusteringKey,
460 /// Suspend background reclustering operations.
461 SuspendRecluster,
462 /// Resume background reclustering operations.
463 ResumeRecluster,
464 /// `REFRESH [ '<subpath>' ]`
465 ///
466 /// Note: this is Snowflake specific for dynamic/external tables
467 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
468 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
469 Refresh {
470 /// Optional subpath for external table refresh
471 subpath: Option<String>,
472 },
473 /// `SUSPEND`
474 ///
475 /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
476 Suspend,
477 /// `RESUME`
478 ///
479 /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
480 Resume,
481 /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
482 ///
483 /// [MySQL]-specific table alter algorithm.
484 ///
485 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
486 Algorithm {
487 /// Whether the `=` sign was used (`ALGORITHM = ...`).
488 equals: bool,
489 /// The algorithm to use for the alter operation (MySQL-specific).
490 algorithm: AlterTableAlgorithm,
491 },
492
493 /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
494 ///
495 /// [MySQL]-specific table alter lock.
496 ///
497 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
498 Lock {
499 /// Whether the `=` sign was used (`LOCK = ...`).
500 equals: bool,
501 /// The locking behavior to apply (MySQL-specific).
502 lock: AlterTableLock,
503 },
504 /// `AUTO_INCREMENT [=] <value>`
505 ///
506 /// [MySQL]-specific table option for raising current auto increment value.
507 ///
508 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
509 AutoIncrement {
510 /// Whether the `=` sign was used (`AUTO_INCREMENT = ...`).
511 equals: bool,
512 /// Value to set for the auto-increment counter.
513 value: ValueWithSpan,
514 },
515 /// `VALIDATE CONSTRAINT <name>`
516 ValidateConstraint {
517 /// Name of the constraint to validate.
518 name: Ident,
519 },
520 /// Arbitrary parenthesized `SET` options.
521 ///
522 /// Example:
523 /// ```sql
524 /// SET (scale_factor = 0.01, threshold = 500)`
525 /// ```
526 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
527 SetOptionsParens {
528 /// Parenthesized options supplied to `SET (...)`.
529 options: Vec<SqlOption>,
530 },
531}
532
533/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
534///
535/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
536#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
537#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
538#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
539pub enum AlterPolicyOperation {
540 /// Rename the policy to `new_name`.
541 Rename {
542 /// The new identifier for the policy.
543 new_name: Ident,
544 },
545 /// Apply/modify policy properties.
546 Apply {
547 /// Optional list of owners the policy applies to.
548 to: Option<Vec<Owner>>,
549 /// Optional `USING` expression for the policy.
550 using: Option<Expr>,
551 /// Optional `WITH CHECK` expression for the policy.
552 with_check: Option<Expr>,
553 },
554}
555
556impl fmt::Display for AlterPolicyOperation {
557 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558 match self {
559 AlterPolicyOperation::Rename { new_name } => {
560 write!(f, " RENAME TO {new_name}")
561 }
562 AlterPolicyOperation::Apply {
563 to,
564 using,
565 with_check,
566 } => {
567 if let Some(to) = to {
568 write!(f, " TO {}", display_comma_separated(to))?;
569 }
570 if let Some(using) = using {
571 write!(f, " USING ({using})")?;
572 }
573 if let Some(with_check) = with_check {
574 write!(f, " WITH CHECK ({with_check})")?;
575 }
576 Ok(())
577 }
578 }
579 }
580}
581
582/// [MySQL] `ALTER TABLE` algorithm.
583///
584/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
585#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
587#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
588/// Algorithm option for `ALTER TABLE` operations (MySQL-specific).
589pub enum AlterTableAlgorithm {
590 /// Default algorithm selection.
591 Default,
592 /// `INSTANT` algorithm.
593 Instant,
594 /// `INPLACE` algorithm.
595 Inplace,
596 /// `COPY` algorithm.
597 Copy,
598}
599
600impl fmt::Display for AlterTableAlgorithm {
601 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602 f.write_str(match self {
603 Self::Default => "DEFAULT",
604 Self::Instant => "INSTANT",
605 Self::Inplace => "INPLACE",
606 Self::Copy => "COPY",
607 })
608 }
609}
610
611/// [MySQL] `ALTER TABLE` lock.
612///
613/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
614#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
615#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
616#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
617/// Locking behavior for `ALTER TABLE` (MySQL-specific).
618pub enum AlterTableLock {
619 /// `DEFAULT` lock behavior.
620 Default,
621 /// `NONE` lock.
622 None,
623 /// `SHARED` lock.
624 Shared,
625 /// `EXCLUSIVE` lock.
626 Exclusive,
627}
628
629impl fmt::Display for AlterTableLock {
630 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
631 f.write_str(match self {
632 Self::Default => "DEFAULT",
633 Self::None => "NONE",
634 Self::Shared => "SHARED",
635 Self::Exclusive => "EXCLUSIVE",
636 })
637 }
638}
639
640#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
641#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
642#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
643/// New owner specification for `ALTER TABLE ... OWNER TO ...`
644pub enum Owner {
645 /// A specific user/role identifier.
646 Ident(Ident),
647 /// `CURRENT_ROLE` keyword.
648 CurrentRole,
649 /// `CURRENT_USER` keyword.
650 CurrentUser,
651 /// `SESSION_USER` keyword.
652 SessionUser,
653}
654
655impl fmt::Display for Owner {
656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657 match self {
658 Owner::Ident(ident) => write!(f, "{ident}"),
659 Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
660 Owner::CurrentUser => write!(f, "CURRENT_USER"),
661 Owner::SessionUser => write!(f, "SESSION_USER"),
662 }
663 }
664}
665
666#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
667#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
668#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
669/// New connector owner specification for `ALTER CONNECTOR ... OWNER TO ...`
670pub enum AlterConnectorOwner {
671 /// `USER <ident>` connector owner.
672 User(Ident),
673 /// `ROLE <ident>` connector owner.
674 Role(Ident),
675}
676
677impl fmt::Display for AlterConnectorOwner {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 match self {
680 AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
681 AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
682 }
683 }
684}
685
686#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
688#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
689/// Alterations that can be applied to an index.
690pub enum AlterIndexOperation {
691 /// Rename the index to `index_name`.
692 RenameIndex {
693 /// The new name for the index.
694 index_name: ObjectName,
695 },
696}
697
698impl fmt::Display for AlterTableOperation {
699 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
700 match self {
701 AlterTableOperation::AddPartitions {
702 if_not_exists,
703 new_partitions,
704 } => write!(
705 f,
706 "ADD{ine} {}",
707 display_separated(new_partitions, " "),
708 ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
709 ),
710 AlterTableOperation::AddConstraint {
711 not_valid,
712 constraint,
713 } => {
714 write!(f, "ADD {constraint}")?;
715 if *not_valid {
716 write!(f, " NOT VALID")?;
717 }
718 Ok(())
719 }
720 AlterTableOperation::AddColumn {
721 column_keyword,
722 if_not_exists,
723 column_def,
724 column_position,
725 } => {
726 write!(f, "ADD")?;
727 if *column_keyword {
728 write!(f, " COLUMN")?;
729 }
730 if *if_not_exists {
731 write!(f, " IF NOT EXISTS")?;
732 }
733 write!(f, " {column_def}")?;
734
735 if let Some(position) = column_position {
736 write!(f, " {position}")?;
737 }
738
739 Ok(())
740 }
741 AlterTableOperation::AddProjection {
742 if_not_exists,
743 name,
744 select: query,
745 } => {
746 write!(f, "ADD PROJECTION")?;
747 if *if_not_exists {
748 write!(f, " IF NOT EXISTS")?;
749 }
750 write!(f, " {name} ({query})")
751 }
752 AlterTableOperation::Algorithm { equals, algorithm } => {
753 write!(
754 f,
755 "ALGORITHM {}{}",
756 if *equals { "= " } else { "" },
757 algorithm
758 )
759 }
760 AlterTableOperation::DropProjection { if_exists, name } => {
761 write!(f, "DROP PROJECTION")?;
762 if *if_exists {
763 write!(f, " IF EXISTS")?;
764 }
765 write!(f, " {name}")
766 }
767 AlterTableOperation::MaterializeProjection {
768 if_exists,
769 name,
770 partition,
771 } => {
772 write!(f, "MATERIALIZE PROJECTION")?;
773 if *if_exists {
774 write!(f, " IF EXISTS")?;
775 }
776 write!(f, " {name}")?;
777 if let Some(partition) = partition {
778 write!(f, " IN PARTITION {partition}")?;
779 }
780 Ok(())
781 }
782 AlterTableOperation::ClearProjection {
783 if_exists,
784 name,
785 partition,
786 } => {
787 write!(f, "CLEAR PROJECTION")?;
788 if *if_exists {
789 write!(f, " IF EXISTS")?;
790 }
791 write!(f, " {name}")?;
792 if let Some(partition) = partition {
793 write!(f, " IN PARTITION {partition}")?;
794 }
795 Ok(())
796 }
797 AlterTableOperation::AlterColumn { column_name, op } => {
798 write!(f, "ALTER COLUMN {column_name} {op}")
799 }
800 AlterTableOperation::DisableRowLevelSecurity => {
801 write!(f, "DISABLE ROW LEVEL SECURITY")
802 }
803 AlterTableOperation::DisableRule { name } => {
804 write!(f, "DISABLE RULE {name}")
805 }
806 AlterTableOperation::DisableTrigger { name } => {
807 write!(f, "DISABLE TRIGGER {name}")
808 }
809 AlterTableOperation::DropPartitions {
810 partitions,
811 if_exists,
812 } => write!(
813 f,
814 "DROP{ie} PARTITION ({})",
815 display_comma_separated(partitions),
816 ie = if *if_exists { " IF EXISTS" } else { "" }
817 ),
818 AlterTableOperation::DropConstraint {
819 if_exists,
820 name,
821 drop_behavior,
822 } => {
823 write!(
824 f,
825 "DROP CONSTRAINT {}{}",
826 if *if_exists { "IF EXISTS " } else { "" },
827 name
828 )?;
829 if let Some(drop_behavior) = drop_behavior {
830 write!(f, " {drop_behavior}")?;
831 }
832 Ok(())
833 }
834 AlterTableOperation::DropPrimaryKey { drop_behavior } => {
835 write!(f, "DROP PRIMARY KEY")?;
836 if let Some(drop_behavior) = drop_behavior {
837 write!(f, " {drop_behavior}")?;
838 }
839 Ok(())
840 }
841 AlterTableOperation::DropForeignKey {
842 name,
843 drop_behavior,
844 } => {
845 write!(f, "DROP FOREIGN KEY {name}")?;
846 if let Some(drop_behavior) = drop_behavior {
847 write!(f, " {drop_behavior}")?;
848 }
849 Ok(())
850 }
851 AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
852 AlterTableOperation::DropColumn {
853 has_column_keyword,
854 column_names: column_name,
855 if_exists,
856 drop_behavior,
857 } => {
858 write!(
859 f,
860 "DROP {}{}{}",
861 if *has_column_keyword { "COLUMN " } else { "" },
862 if *if_exists { "IF EXISTS " } else { "" },
863 display_comma_separated(column_name),
864 )?;
865 if let Some(drop_behavior) = drop_behavior {
866 write!(f, " {drop_behavior}")?;
867 }
868 Ok(())
869 }
870 AlterTableOperation::AttachPartition { partition } => {
871 write!(f, "ATTACH {partition}")
872 }
873 AlterTableOperation::DetachPartition { partition } => {
874 write!(f, "DETACH {partition}")
875 }
876 AlterTableOperation::EnableAlwaysRule { name } => {
877 write!(f, "ENABLE ALWAYS RULE {name}")
878 }
879 AlterTableOperation::EnableAlwaysTrigger { name } => {
880 write!(f, "ENABLE ALWAYS TRIGGER {name}")
881 }
882 AlterTableOperation::EnableReplicaRule { name } => {
883 write!(f, "ENABLE REPLICA RULE {name}")
884 }
885 AlterTableOperation::EnableReplicaTrigger { name } => {
886 write!(f, "ENABLE REPLICA TRIGGER {name}")
887 }
888 AlterTableOperation::EnableRowLevelSecurity => {
889 write!(f, "ENABLE ROW LEVEL SECURITY")
890 }
891 AlterTableOperation::ForceRowLevelSecurity => {
892 write!(f, "FORCE ROW LEVEL SECURITY")
893 }
894 AlterTableOperation::NoForceRowLevelSecurity => {
895 write!(f, "NO FORCE ROW LEVEL SECURITY")
896 }
897 AlterTableOperation::EnableRule { name } => {
898 write!(f, "ENABLE RULE {name}")
899 }
900 AlterTableOperation::EnableTrigger { name } => {
901 write!(f, "ENABLE TRIGGER {name}")
902 }
903 AlterTableOperation::RenamePartitions {
904 old_partitions,
905 new_partitions,
906 } => write!(
907 f,
908 "PARTITION ({}) RENAME TO PARTITION ({})",
909 display_comma_separated(old_partitions),
910 display_comma_separated(new_partitions)
911 ),
912 AlterTableOperation::RenameColumn {
913 old_column_name,
914 new_column_name,
915 } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
916 AlterTableOperation::RenameTable { table_name } => {
917 write!(f, "RENAME {table_name}")
918 }
919 AlterTableOperation::ChangeColumn {
920 old_name,
921 new_name,
922 data_type,
923 options,
924 column_position,
925 } => {
926 write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
927 if !options.is_empty() {
928 write!(f, " {}", display_separated(options, " "))?;
929 }
930 if let Some(position) = column_position {
931 write!(f, " {position}")?;
932 }
933
934 Ok(())
935 }
936 AlterTableOperation::ModifyColumn {
937 col_name,
938 data_type,
939 options,
940 column_position,
941 } => {
942 write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
943 if !options.is_empty() {
944 write!(f, " {}", display_separated(options, " "))?;
945 }
946 if let Some(position) = column_position {
947 write!(f, " {position}")?;
948 }
949
950 Ok(())
951 }
952 AlterTableOperation::RenameConstraint { old_name, new_name } => {
953 write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
954 }
955 AlterTableOperation::SwapWith { table_name } => {
956 write!(f, "SWAP WITH {table_name}")
957 }
958 AlterTableOperation::OwnerTo { new_owner } => {
959 write!(f, "OWNER TO {new_owner}")
960 }
961 AlterTableOperation::SetTblProperties { table_properties } => {
962 write!(
963 f,
964 "SET TBLPROPERTIES({})",
965 display_comma_separated(table_properties)
966 )
967 }
968 AlterTableOperation::FreezePartition {
969 partition,
970 with_name,
971 } => {
972 write!(f, "FREEZE {partition}")?;
973 if let Some(name) = with_name {
974 write!(f, " WITH NAME {name}")?;
975 }
976 Ok(())
977 }
978 AlterTableOperation::UnfreezePartition {
979 partition,
980 with_name,
981 } => {
982 write!(f, "UNFREEZE {partition}")?;
983 if let Some(name) = with_name {
984 write!(f, " WITH NAME {name}")?;
985 }
986 Ok(())
987 }
988 AlterTableOperation::ClusterBy { exprs } => {
989 write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
990 Ok(())
991 }
992 AlterTableOperation::DropClusteringKey => {
993 write!(f, "DROP CLUSTERING KEY")?;
994 Ok(())
995 }
996 AlterTableOperation::SuspendRecluster => {
997 write!(f, "SUSPEND RECLUSTER")?;
998 Ok(())
999 }
1000 AlterTableOperation::ResumeRecluster => {
1001 write!(f, "RESUME RECLUSTER")?;
1002 Ok(())
1003 }
1004 AlterTableOperation::Refresh { subpath } => {
1005 write!(f, "REFRESH")?;
1006 if let Some(path) = subpath {
1007 write!(f, " '{path}'")?;
1008 }
1009 Ok(())
1010 }
1011 AlterTableOperation::Suspend => {
1012 write!(f, "SUSPEND")
1013 }
1014 AlterTableOperation::Resume => {
1015 write!(f, "RESUME")
1016 }
1017 AlterTableOperation::AutoIncrement { equals, value } => {
1018 write!(
1019 f,
1020 "AUTO_INCREMENT {}{}",
1021 if *equals { "= " } else { "" },
1022 value
1023 )
1024 }
1025 AlterTableOperation::Lock { equals, lock } => {
1026 write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
1027 }
1028 AlterTableOperation::ReplicaIdentity { identity } => {
1029 write!(f, "REPLICA IDENTITY {identity}")
1030 }
1031 AlterTableOperation::ValidateConstraint { name } => {
1032 write!(f, "VALIDATE CONSTRAINT {name}")
1033 }
1034 AlterTableOperation::SetOptionsParens { options } => {
1035 write!(f, "SET ({})", display_comma_separated(options))
1036 }
1037 }
1038 }
1039}
1040
1041impl fmt::Display for AlterIndexOperation {
1042 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1043 match self {
1044 AlterIndexOperation::RenameIndex { index_name } => {
1045 write!(f, "RENAME TO {index_name}")
1046 }
1047 }
1048 }
1049}
1050
1051/// An `ALTER TYPE` statement (`Statement::AlterType`)
1052#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1053#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1054#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1055pub struct AlterType {
1056 /// Name of the type being altered (may be schema-qualified).
1057 pub name: ObjectName,
1058 /// The specific alteration operation to perform.
1059 pub operation: AlterTypeOperation,
1060}
1061
1062/// An [AlterType] operation
1063#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1064#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1065#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1066pub enum AlterTypeOperation {
1067 /// Rename the type.
1068 Rename(AlterTypeRename),
1069 /// Add a new value to the type (for enum-like types).
1070 AddValue(AlterTypeAddValue),
1071 /// Rename an existing value of the type.
1072 RenameValue(AlterTypeRenameValue),
1073}
1074
1075/// See [AlterTypeOperation::Rename]
1076#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1077#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1078#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1079pub struct AlterTypeRename {
1080 /// The new name for the type.
1081 pub new_name: Ident,
1082}
1083
1084/// See [AlterTypeOperation::AddValue]
1085#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1086#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1087#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1088pub struct AlterTypeAddValue {
1089 /// If true, do not error when the value already exists (`IF NOT EXISTS`).
1090 pub if_not_exists: bool,
1091 /// The identifier for the new value to add.
1092 pub value: Ident,
1093 /// Optional relative position for the new value (`BEFORE` / `AFTER`).
1094 pub position: Option<AlterTypeAddValuePosition>,
1095}
1096
1097/// See [AlterTypeAddValue]
1098#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1099#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1100#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1101pub enum AlterTypeAddValuePosition {
1102 /// Place the new value before the given neighbor value.
1103 Before(Ident),
1104 /// Place the new value after the given neighbor value.
1105 After(Ident),
1106}
1107
1108/// See [AlterTypeOperation::RenameValue]
1109#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1110#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1111#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1112pub struct AlterTypeRenameValue {
1113 /// Existing value identifier to rename.
1114 pub from: Ident,
1115 /// New identifier for the value.
1116 pub to: Ident,
1117}
1118
1119impl fmt::Display for AlterTypeOperation {
1120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1121 match self {
1122 Self::Rename(AlterTypeRename { new_name }) => {
1123 write!(f, "RENAME TO {new_name}")
1124 }
1125 Self::AddValue(AlterTypeAddValue {
1126 if_not_exists,
1127 value,
1128 position,
1129 }) => {
1130 write!(f, "ADD VALUE")?;
1131 if *if_not_exists {
1132 write!(f, " IF NOT EXISTS")?;
1133 }
1134 write!(f, " {value}")?;
1135 match position {
1136 Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
1137 write!(f, " BEFORE {neighbor_value}")?;
1138 }
1139 Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
1140 write!(f, " AFTER {neighbor_value}")?;
1141 }
1142 None => {}
1143 };
1144 Ok(())
1145 }
1146 Self::RenameValue(AlterTypeRenameValue { from, to }) => {
1147 write!(f, "RENAME VALUE {from} TO {to}")
1148 }
1149 }
1150 }
1151}
1152
1153/// `ALTER OPERATOR` statement
1154/// See <https://www.postgresql.org/docs/current/sql-alteroperator.html>
1155#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1156#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1157#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1158pub struct AlterOperator {
1159 /// Operator name (can be schema-qualified)
1160 pub name: ObjectName,
1161 /// Left operand type (`None` if no left operand)
1162 pub left_type: Option<DataType>,
1163 /// Right operand type
1164 pub right_type: DataType,
1165 /// The operation to perform
1166 pub operation: AlterOperatorOperation,
1167}
1168
1169/// An [AlterOperator] operation
1170#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1171#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1172#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1173pub enum AlterOperatorOperation {
1174 /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
1175 OwnerTo(Owner),
1176 /// `SET SCHEMA new_schema`
1177 /// Set the operator's schema name.
1178 SetSchema {
1179 /// New schema name for the operator
1180 schema_name: ObjectName,
1181 },
1182 /// `SET ( options )`
1183 Set {
1184 /// List of operator options to set
1185 options: Vec<OperatorOption>,
1186 },
1187}
1188
1189/// Option for `ALTER OPERATOR SET` operation
1190#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1191#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1192#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1193pub enum OperatorOption {
1194 /// `RESTRICT = { res_proc | NONE }`
1195 Restrict(Option<ObjectName>),
1196 /// `JOIN = { join_proc | NONE }`
1197 Join(Option<ObjectName>),
1198 /// `COMMUTATOR = com_op`
1199 Commutator(ObjectName),
1200 /// `NEGATOR = neg_op`
1201 Negator(ObjectName),
1202 /// `HASHES`
1203 Hashes,
1204 /// `MERGES`
1205 Merges,
1206}
1207
1208impl fmt::Display for AlterOperator {
1209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1210 write!(f, "ALTER OPERATOR {} (", self.name)?;
1211 if let Some(left_type) = &self.left_type {
1212 write!(f, "{}", left_type)?;
1213 } else {
1214 write!(f, "NONE")?;
1215 }
1216 write!(f, ", {}) {}", self.right_type, self.operation)
1217 }
1218}
1219
1220impl fmt::Display for AlterOperatorOperation {
1221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1222 match self {
1223 Self::OwnerTo(owner) => write!(f, "OWNER TO {}", owner),
1224 Self::SetSchema { schema_name } => write!(f, "SET SCHEMA {}", schema_name),
1225 Self::Set { options } => {
1226 write!(f, "SET (")?;
1227 for (i, option) in options.iter().enumerate() {
1228 if i > 0 {
1229 write!(f, ", ")?;
1230 }
1231 write!(f, "{}", option)?;
1232 }
1233 write!(f, ")")
1234 }
1235 }
1236 }
1237}
1238
1239impl fmt::Display for OperatorOption {
1240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1241 match self {
1242 Self::Restrict(Some(proc_name)) => write!(f, "RESTRICT = {}", proc_name),
1243 Self::Restrict(None) => write!(f, "RESTRICT = NONE"),
1244 Self::Join(Some(proc_name)) => write!(f, "JOIN = {}", proc_name),
1245 Self::Join(None) => write!(f, "JOIN = NONE"),
1246 Self::Commutator(op_name) => write!(f, "COMMUTATOR = {}", op_name),
1247 Self::Negator(op_name) => write!(f, "NEGATOR = {}", op_name),
1248 Self::Hashes => write!(f, "HASHES"),
1249 Self::Merges => write!(f, "MERGES"),
1250 }
1251 }
1252}
1253
1254/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
1255#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1256#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1257#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1258pub enum AlterColumnOperation {
1259 /// `SET NOT NULL`
1260 SetNotNull,
1261 /// `DROP NOT NULL`
1262 DropNotNull,
1263 /// `SET DEFAULT <expr>`
1264 /// Set the column default value.
1265 SetDefault {
1266 /// Expression representing the new default value.
1267 value: Expr,
1268 },
1269 /// `DROP DEFAULT`
1270 DropDefault,
1271 /// `[SET DATA] TYPE <data_type> [USING <expr>]`
1272 SetDataType {
1273 /// Target data type for the column.
1274 data_type: DataType,
1275 /// PostgreSQL-specific `USING <expr>` expression for conversion.
1276 using: Option<Expr>,
1277 /// Set to true if the statement includes the `SET DATA TYPE` keywords.
1278 had_set: bool,
1279 },
1280
1281 /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
1282 ///
1283 /// Note: this is a PostgreSQL-specific operation.
1284 AddGenerated {
1285 /// Optional `GENERATED AS` specifier (e.g. `ALWAYS` or `BY DEFAULT`).
1286 generated_as: Option<GeneratedAs>,
1287 /// Optional sequence options for identity generation.
1288 sequence_options: Option<Vec<SequenceOptions>>,
1289 },
1290}
1291
1292impl fmt::Display for AlterColumnOperation {
1293 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1294 match self {
1295 AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
1296 AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
1297 AlterColumnOperation::SetDefault { value } => {
1298 write!(f, "SET DEFAULT {value}")
1299 }
1300 AlterColumnOperation::DropDefault => {
1301 write!(f, "DROP DEFAULT")
1302 }
1303 AlterColumnOperation::SetDataType {
1304 data_type,
1305 using,
1306 had_set,
1307 } => {
1308 if *had_set {
1309 write!(f, "SET DATA ")?;
1310 }
1311 write!(f, "TYPE {data_type}")?;
1312 if let Some(expr) = using {
1313 write!(f, " USING {expr}")?;
1314 }
1315 Ok(())
1316 }
1317 AlterColumnOperation::AddGenerated {
1318 generated_as,
1319 sequence_options,
1320 } => {
1321 let generated_as = match generated_as {
1322 Some(GeneratedAs::Always) => " ALWAYS",
1323 Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1324 _ => "",
1325 };
1326
1327 write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1328 if let Some(options) = sequence_options {
1329 write!(f, " (")?;
1330
1331 for sequence_option in options {
1332 write!(f, "{sequence_option}")?;
1333 }
1334
1335 write!(f, " )")?;
1336 }
1337 Ok(())
1338 }
1339 }
1340 }
1341}
1342
1343/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1344/// meaning.
1345///
1346/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1347/// statements of `MySQL` [(1)].
1348///
1349/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1350#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1351#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1352#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1353pub enum KeyOrIndexDisplay {
1354 /// Nothing to display
1355 None,
1356 /// Display the KEY keyword
1357 Key,
1358 /// Display the INDEX keyword
1359 Index,
1360}
1361
1362impl KeyOrIndexDisplay {
1363 /// Check if this is the `None` variant.
1364 pub fn is_none(self) -> bool {
1365 matches!(self, Self::None)
1366 }
1367}
1368
1369impl fmt::Display for KeyOrIndexDisplay {
1370 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1371 let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1372
1373 if left_space && !self.is_none() {
1374 f.write_char(' ')?
1375 }
1376
1377 match self {
1378 KeyOrIndexDisplay::None => {
1379 write!(f, "")
1380 }
1381 KeyOrIndexDisplay::Key => {
1382 write!(f, "KEY")
1383 }
1384 KeyOrIndexDisplay::Index => {
1385 write!(f, "INDEX")
1386 }
1387 }
1388 }
1389}
1390
1391/// Indexing method used by that index.
1392///
1393/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1394/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1395///
1396/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1397/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1398/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1399#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1400#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1401#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1402pub enum IndexType {
1403 /// B-Tree index (commonly default for many databases).
1404 BTree,
1405 /// Hash index.
1406 Hash,
1407 /// Generalized Inverted Index (GIN).
1408 GIN,
1409 /// Generalized Search Tree (GiST) index.
1410 GiST,
1411 /// Space-partitioned GiST (SPGiST) index.
1412 SPGiST,
1413 /// Block Range Index (BRIN).
1414 BRIN,
1415 /// Bloom filter based index.
1416 Bloom,
1417 /// Users may define their own index types, which would
1418 /// not be covered by the above variants.
1419 Custom(Ident),
1420}
1421
1422impl fmt::Display for IndexType {
1423 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1424 match self {
1425 Self::BTree => write!(f, "BTREE"),
1426 Self::Hash => write!(f, "HASH"),
1427 Self::GIN => write!(f, "GIN"),
1428 Self::GiST => write!(f, "GIST"),
1429 Self::SPGiST => write!(f, "SPGIST"),
1430 Self::BRIN => write!(f, "BRIN"),
1431 Self::Bloom => write!(f, "BLOOM"),
1432 Self::Custom(name) => write!(f, "{name}"),
1433 }
1434 }
1435}
1436
1437/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1438///
1439/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1440/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1441/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1442#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1444#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1445pub enum IndexOption {
1446 /// `USING { BTREE | HASH }`: Index type to use for the index.
1447 ///
1448 /// Note that we permissively parse non-MySQL index types, like `GIN`.
1449 Using(IndexType),
1450 /// `COMMENT 'string'`: Specifies a comment for the index.
1451 Comment(String),
1452}
1453
1454impl fmt::Display for IndexOption {
1455 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1456 match self {
1457 Self::Using(index_type) => write!(f, "USING {index_type}"),
1458 Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1459 }
1460 }
1461}
1462
1463/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1464///
1465/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1466#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1467#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1468#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1469pub enum NullsDistinctOption {
1470 /// Not specified
1471 None,
1472 /// NULLS DISTINCT
1473 Distinct,
1474 /// NULLS NOT DISTINCT
1475 NotDistinct,
1476}
1477
1478impl fmt::Display for NullsDistinctOption {
1479 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1480 match self {
1481 Self::None => Ok(()),
1482 Self::Distinct => write!(f, " NULLS DISTINCT"),
1483 Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1484 }
1485 }
1486}
1487
1488#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1489#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1490#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1491/// A parameter of a stored procedure or function declaration.
1492pub struct ProcedureParam {
1493 /// Parameter name.
1494 pub name: Ident,
1495 /// Parameter data type.
1496 pub data_type: DataType,
1497 /// Optional mode (`IN`, `OUT`, `INOUT`, etc.).
1498 pub mode: Option<ArgMode>,
1499 /// Optional default expression for the parameter.
1500 pub default: Option<Expr>,
1501}
1502
1503impl fmt::Display for ProcedureParam {
1504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1505 if let Some(mode) = &self.mode {
1506 if let Some(default) = &self.default {
1507 write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1508 } else {
1509 write!(f, "{mode} {} {}", self.name, self.data_type)
1510 }
1511 } else if let Some(default) = &self.default {
1512 write!(f, "{} {} = {}", self.name, self.data_type, default)
1513 } else {
1514 write!(f, "{} {}", self.name, self.data_type)
1515 }
1516 }
1517}
1518
1519/// SQL column definition
1520#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1521#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1522#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1523pub struct ColumnDef {
1524 /// Column name.
1525 pub name: Ident,
1526 /// Column data type.
1527 pub data_type: DataType,
1528 /// Column options (defaults, constraints, generated, etc.).
1529 pub options: Vec<ColumnOptionDef>,
1530}
1531
1532impl fmt::Display for ColumnDef {
1533 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1534 if self.data_type == DataType::Unspecified {
1535 write!(f, "{}", self.name)?;
1536 } else {
1537 write!(f, "{} {}", self.name, self.data_type)?;
1538 }
1539 for option in &self.options {
1540 write!(f, " {option}")?;
1541 }
1542 Ok(())
1543 }
1544}
1545
1546/// Column definition specified in a `CREATE VIEW` statement.
1547///
1548/// Syntax
1549/// ```markdown
1550/// <name> [data_type][OPTIONS(option, ...)]
1551///
1552/// option: <name> = <value>
1553/// ```
1554///
1555/// Examples:
1556/// ```sql
1557/// name
1558/// age OPTIONS(description = "age column", tag = "prod")
1559/// amount COMMENT 'The total amount for the order line'
1560/// created_at DateTime64
1561/// ```
1562#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1563#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1564#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1565pub struct ViewColumnDef {
1566 /// Column identifier.
1567 pub name: Ident,
1568 /// Optional data type for the column.
1569 pub data_type: Option<DataType>,
1570 /// Optional column options (defaults, comments, etc.).
1571 pub options: Option<ColumnOptions>,
1572}
1573
1574#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1575#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1576#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1577/// Representation of how multiple `ColumnOption`s are grouped for a column.
1578pub enum ColumnOptions {
1579 /// Options separated by comma: `OPTIONS(a, b, c)`.
1580 CommaSeparated(Vec<ColumnOption>),
1581 /// Options separated by spaces: `OPTION_A OPTION_B`.
1582 SpaceSeparated(Vec<ColumnOption>),
1583}
1584
1585impl ColumnOptions {
1586 /// Get the column options as a slice.
1587 pub fn as_slice(&self) -> &[ColumnOption] {
1588 match self {
1589 ColumnOptions::CommaSeparated(options) => options.as_slice(),
1590 ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1591 }
1592 }
1593}
1594
1595impl fmt::Display for ViewColumnDef {
1596 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1597 write!(f, "{}", self.name)?;
1598 if let Some(data_type) = self.data_type.as_ref() {
1599 write!(f, " {data_type}")?;
1600 }
1601 if let Some(options) = self.options.as_ref() {
1602 match options {
1603 ColumnOptions::CommaSeparated(column_options) => {
1604 write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1605 }
1606 ColumnOptions::SpaceSeparated(column_options) => {
1607 write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1608 }
1609 }
1610 }
1611 Ok(())
1612 }
1613}
1614
1615/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1616///
1617/// Note that implementations are substantially more permissive than the ANSI
1618/// specification on what order column options can be presented in, and whether
1619/// they are allowed to be named. The specification distinguishes between
1620/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1621/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1622/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1623/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1624/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1625/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1626/// NOT NULL constraints (the last of which is in violation of the spec).
1627///
1628/// For maximum flexibility, we don't distinguish between constraint and
1629/// non-constraint options, lumping them all together under the umbrella of
1630/// "column options," and we allow any column option to be named.
1631#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1632#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1633#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1634pub struct ColumnOptionDef {
1635 /// Optional name of the constraint.
1636 pub name: Option<Ident>,
1637 /// The actual column option (e.g. `NOT NULL`, `DEFAULT`, `GENERATED`, ...).
1638 pub option: ColumnOption,
1639}
1640
1641impl fmt::Display for ColumnOptionDef {
1642 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1643 write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1644 }
1645}
1646
1647/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1648/// Syntax
1649/// ```sql
1650/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1651/// ```
1652/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1653/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1654#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1655#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1656#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1657pub enum IdentityPropertyKind {
1658 /// An identity property declared via the `AUTOINCREMENT` key word
1659 /// Example:
1660 /// ```sql
1661 /// AUTOINCREMENT(100, 1) NOORDER
1662 /// AUTOINCREMENT START 100 INCREMENT 1 ORDER
1663 /// ```
1664 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1665 Autoincrement(IdentityProperty),
1666 /// An identity property declared via the `IDENTITY` key word
1667 /// Example, [MS SQL Server] or [Snowflake]:
1668 /// ```sql
1669 /// IDENTITY(100, 1)
1670 /// ```
1671 /// [Snowflake]
1672 /// ```sql
1673 /// IDENTITY(100, 1) ORDER
1674 /// IDENTITY START 100 INCREMENT 1 NOORDER
1675 /// ```
1676 /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1677 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1678 Identity(IdentityProperty),
1679}
1680
1681impl fmt::Display for IdentityPropertyKind {
1682 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1683 let (command, property) = match self {
1684 IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1685 IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1686 };
1687 write!(f, "{command}")?;
1688 if let Some(parameters) = &property.parameters {
1689 write!(f, "{parameters}")?;
1690 }
1691 if let Some(order) = &property.order {
1692 write!(f, "{order}")?;
1693 }
1694 Ok(())
1695 }
1696}
1697
1698/// Properties for the `IDENTITY` / `AUTOINCREMENT` column option.
1699#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1701#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1702pub struct IdentityProperty {
1703 /// Optional parameters specifying seed/increment for the identity column.
1704 pub parameters: Option<IdentityPropertyFormatKind>,
1705 /// Optional ordering specifier (`ORDER` / `NOORDER`).
1706 pub order: Option<IdentityPropertyOrder>,
1707}
1708
1709/// A format of parameters of identity column.
1710///
1711/// It is [Snowflake] specific.
1712/// Syntax
1713/// ```sql
1714/// (seed , increment) | START num INCREMENT num
1715/// ```
1716/// [MS SQL Server] uses one way of representing these parameters.
1717/// Syntax
1718/// ```sql
1719/// (seed , increment)
1720/// ```
1721/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1722/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1723#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1725#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1726pub enum IdentityPropertyFormatKind {
1727 /// A parameters of identity column declared like parameters of function call
1728 /// Example:
1729 /// ```sql
1730 /// (100, 1)
1731 /// ```
1732 /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1733 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1734 FunctionCall(IdentityParameters),
1735 /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1736 /// Example:
1737 /// ```sql
1738 /// START 100 INCREMENT 1
1739 /// ```
1740 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1741 StartAndIncrement(IdentityParameters),
1742}
1743
1744impl fmt::Display for IdentityPropertyFormatKind {
1745 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1746 match self {
1747 IdentityPropertyFormatKind::FunctionCall(parameters) => {
1748 write!(f, "({}, {})", parameters.seed, parameters.increment)
1749 }
1750 IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1751 write!(
1752 f,
1753 " START {} INCREMENT {}",
1754 parameters.seed, parameters.increment
1755 )
1756 }
1757 }
1758 }
1759}
1760/// Parameters specifying seed and increment for identity columns.
1761#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1762#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1763#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1764pub struct IdentityParameters {
1765 /// The initial seed expression for the identity column.
1766 pub seed: Expr,
1767 /// The increment expression for the identity column.
1768 pub increment: Expr,
1769}
1770
1771/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1772/// Syntax
1773/// ```sql
1774/// ORDER | NOORDER
1775/// ```
1776/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1777#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1778#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1779#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1780pub enum IdentityPropertyOrder {
1781 /// `ORDER` - preserve ordering for generated values (where supported).
1782 Order,
1783 /// `NOORDER` - do not enforce ordering for generated values.
1784 NoOrder,
1785}
1786
1787impl fmt::Display for IdentityPropertyOrder {
1788 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1789 match self {
1790 IdentityPropertyOrder::Order => write!(f, " ORDER"),
1791 IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1792 }
1793 }
1794}
1795
1796/// Column policy that identify a security policy of access to a column.
1797/// Syntax
1798/// ```sql
1799/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1800/// [ WITH ] PROJECTION POLICY <policy_name>
1801/// ```
1802/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1803#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1804#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1805#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1806pub enum ColumnPolicy {
1807 /// `MASKING POLICY (<property>)`
1808 MaskingPolicy(ColumnPolicyProperty),
1809 /// `PROJECTION POLICY (<property>)`
1810 ProjectionPolicy(ColumnPolicyProperty),
1811}
1812
1813impl fmt::Display for ColumnPolicy {
1814 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1815 let (command, property) = match self {
1816 ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1817 ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1818 };
1819 if property.with {
1820 write!(f, "WITH ")?;
1821 }
1822 write!(f, "{command} {}", property.policy_name)?;
1823 if let Some(using_columns) = &property.using_columns {
1824 write!(f, " USING ({})", display_comma_separated(using_columns))?;
1825 }
1826 Ok(())
1827 }
1828}
1829
1830#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1831#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1832#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1833/// Properties describing a column policy (masking or projection).
1834pub struct ColumnPolicyProperty {
1835 /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1836 /// Example
1837 /// ```sql
1838 /// WITH PROJECTION POLICY sample_policy
1839 /// ```
1840 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1841 pub with: bool,
1842 /// The name of the policy to apply to the column.
1843 pub policy_name: ObjectName,
1844 /// Optional list of column identifiers referenced by the policy.
1845 pub using_columns: Option<Vec<Ident>>,
1846}
1847
1848/// Tags option of column
1849/// Syntax
1850/// ```sql
1851/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1852/// ```
1853/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1854#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1855#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1856#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1857pub struct TagsColumnOption {
1858 /// This flag indicates that the tags option is declared using the `WITH` prefix.
1859 /// Example:
1860 /// ```sql
1861 /// WITH TAG (A = 'Tag A')
1862 /// ```
1863 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1864 pub with: bool,
1865 /// List of tags to attach to the column.
1866 pub tags: Vec<Tag>,
1867}
1868
1869impl fmt::Display for TagsColumnOption {
1870 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1871 if self.with {
1872 write!(f, "WITH ")?;
1873 }
1874 write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1875 Ok(())
1876 }
1877}
1878
1879/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1880/// TABLE` statement.
1881#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1882#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1883#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1884pub enum ColumnOption {
1885 /// `NULL`
1886 Null,
1887 /// `NOT NULL`
1888 NotNull,
1889 /// `DEFAULT <restricted-expr>`
1890 Default(Expr),
1891
1892 /// `MATERIALIZE <expr>`
1893 /// Syntax: `b INT MATERIALIZE (a + 1)`
1894 ///
1895 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1896 Materialized(Expr),
1897 /// `EPHEMERAL [<expr>]`
1898 ///
1899 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1900 Ephemeral(Option<Expr>),
1901 /// `ALIAS <expr>`
1902 ///
1903 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1904 Alias(Expr),
1905
1906 /// `PRIMARY KEY [<constraint_characteristics>]`
1907 PrimaryKey(PrimaryKeyConstraint),
1908 /// `UNIQUE [<constraint_characteristics>]`
1909 Unique(UniqueConstraint),
1910 /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1911 /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1912 /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1913 /// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1914 /// }
1915 /// [<constraint_characteristics>]
1916 /// `).
1917 ForeignKey(ForeignKeyConstraint),
1918 /// `CHECK (<expr>)`
1919 Check(CheckConstraint),
1920 /// Dialect-specific options, such as:
1921 /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1922 /// - ...
1923 DialectSpecific(Vec<Token>),
1924 /// `CHARACTER SET <name>` column option
1925 CharacterSet(ObjectName),
1926 /// `COLLATE <name>` column option
1927 Collation(ObjectName),
1928 /// `COMMENT '<text>'` column option
1929 Comment(String),
1930 /// `ON UPDATE <expr>` column option
1931 OnUpdate(Expr),
1932 /// `Generated`s are modifiers that follow a column definition in a `CREATE
1933 /// TABLE` statement.
1934 Generated {
1935 /// How the column is generated (e.g. `GENERATED ALWAYS`, `BY DEFAULT`, or expression-stored).
1936 generated_as: GeneratedAs,
1937 /// Sequence/identity options when generation is backed by a sequence.
1938 sequence_options: Option<Vec<SequenceOptions>>,
1939 /// Optional expression used to generate the column value.
1940 generation_expr: Option<Expr>,
1941 /// Mode of the generated expression (`VIRTUAL` or `STORED`) when `generation_expr` is present.
1942 generation_expr_mode: Option<GeneratedExpressionMode>,
1943 /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1944 generated_keyword: bool,
1945 },
1946 /// BigQuery specific: Explicit column options in a view [1] or table [2]
1947 /// Syntax
1948 /// ```sql
1949 /// OPTIONS(description="field desc")
1950 /// ```
1951 /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1952 /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1953 Options(Vec<SqlOption>),
1954 /// Creates an identity or an autoincrement column in a table.
1955 /// Syntax
1956 /// ```sql
1957 /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1958 /// ```
1959 /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1960 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1961 Identity(IdentityPropertyKind),
1962 /// SQLite specific: ON CONFLICT option on column definition
1963 /// <https://www.sqlite.org/lang_conflict.html>
1964 OnConflict(Keyword),
1965 /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1966 /// Syntax:
1967 /// ```sql
1968 /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1969 /// [ WITH ] PROJECTION POLICY <policy_name>
1970 /// ```
1971 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1972 Policy(ColumnPolicy),
1973 /// Snowflake specific: Specifies the tag name and the tag string value.
1974 /// Syntax:
1975 /// ```sql
1976 /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1977 /// ```
1978 /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1979 Tags(TagsColumnOption),
1980 /// MySQL specific: Spatial reference identifier
1981 /// Syntax:
1982 /// ```sql
1983 /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
1984 /// ```
1985 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
1986 Srid(Box<Expr>),
1987 /// MySQL specific: Column is invisible via SELECT *
1988 /// Syntax:
1989 /// ```sql
1990 /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
1991 /// ```
1992 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
1993 Invisible,
1994}
1995
1996impl From<UniqueConstraint> for ColumnOption {
1997 fn from(c: UniqueConstraint) -> Self {
1998 ColumnOption::Unique(c)
1999 }
2000}
2001
2002impl From<PrimaryKeyConstraint> for ColumnOption {
2003 fn from(c: PrimaryKeyConstraint) -> Self {
2004 ColumnOption::PrimaryKey(c)
2005 }
2006}
2007
2008impl From<CheckConstraint> for ColumnOption {
2009 fn from(c: CheckConstraint) -> Self {
2010 ColumnOption::Check(c)
2011 }
2012}
2013impl From<ForeignKeyConstraint> for ColumnOption {
2014 fn from(fk: ForeignKeyConstraint) -> Self {
2015 ColumnOption::ForeignKey(fk)
2016 }
2017}
2018
2019impl fmt::Display for ColumnOption {
2020 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2021 use ColumnOption::*;
2022 match self {
2023 Null => write!(f, "NULL"),
2024 NotNull => write!(f, "NOT NULL"),
2025 Default(expr) => write!(f, "DEFAULT {expr}"),
2026 Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
2027 Ephemeral(expr) => {
2028 if let Some(e) = expr {
2029 write!(f, "EPHEMERAL {e}")
2030 } else {
2031 write!(f, "EPHEMERAL")
2032 }
2033 }
2034 Alias(expr) => write!(f, "ALIAS {expr}"),
2035 PrimaryKey(constraint) => {
2036 write!(f, "PRIMARY KEY")?;
2037 if let Some(characteristics) = &constraint.characteristics {
2038 write!(f, " {characteristics}")?;
2039 }
2040 Ok(())
2041 }
2042 Unique(constraint) => {
2043 write!(f, "UNIQUE")?;
2044 if let Some(characteristics) = &constraint.characteristics {
2045 write!(f, " {characteristics}")?;
2046 }
2047 Ok(())
2048 }
2049 ForeignKey(constraint) => {
2050 write!(f, "REFERENCES {}", constraint.foreign_table)?;
2051 if !constraint.referred_columns.is_empty() {
2052 write!(
2053 f,
2054 " ({})",
2055 display_comma_separated(&constraint.referred_columns)
2056 )?;
2057 }
2058 if let Some(match_kind) = &constraint.match_kind {
2059 write!(f, " {match_kind}")?;
2060 }
2061 if let Some(action) = &constraint.on_delete {
2062 write!(f, " ON DELETE {action}")?;
2063 }
2064 if let Some(action) = &constraint.on_update {
2065 write!(f, " ON UPDATE {action}")?;
2066 }
2067 if let Some(characteristics) = &constraint.characteristics {
2068 write!(f, " {characteristics}")?;
2069 }
2070 Ok(())
2071 }
2072 Check(constraint) => write!(f, "{constraint}"),
2073 DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
2074 CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
2075 Collation(n) => write!(f, "COLLATE {n}"),
2076 Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
2077 OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
2078 Generated {
2079 generated_as,
2080 sequence_options,
2081 generation_expr,
2082 generation_expr_mode,
2083 generated_keyword,
2084 } => {
2085 if let Some(expr) = generation_expr {
2086 let modifier = match generation_expr_mode {
2087 None => "",
2088 Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
2089 Some(GeneratedExpressionMode::Stored) => " STORED",
2090 };
2091 if *generated_keyword {
2092 write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
2093 } else {
2094 write!(f, "AS ({expr}){modifier}")?;
2095 }
2096 Ok(())
2097 } else {
2098 // Like Postgres - generated from sequence
2099 let when = match generated_as {
2100 GeneratedAs::Always => "ALWAYS",
2101 GeneratedAs::ByDefault => "BY DEFAULT",
2102 // ExpStored goes with an expression, handled above
2103 GeneratedAs::ExpStored => "",
2104 };
2105 write!(f, "GENERATED {when} AS IDENTITY")?;
2106 if sequence_options.is_some() {
2107 let so = sequence_options.as_ref().unwrap();
2108 if !so.is_empty() {
2109 write!(f, " (")?;
2110 }
2111 for sequence_option in so {
2112 write!(f, "{sequence_option}")?;
2113 }
2114 if !so.is_empty() {
2115 write!(f, " )")?;
2116 }
2117 }
2118 Ok(())
2119 }
2120 }
2121 Options(options) => {
2122 write!(f, "OPTIONS({})", display_comma_separated(options))
2123 }
2124 Identity(parameters) => {
2125 write!(f, "{parameters}")
2126 }
2127 OnConflict(keyword) => {
2128 write!(f, "ON CONFLICT {keyword:?}")?;
2129 Ok(())
2130 }
2131 Policy(parameters) => {
2132 write!(f, "{parameters}")
2133 }
2134 Tags(tags) => {
2135 write!(f, "{tags}")
2136 }
2137 Srid(srid) => {
2138 write!(f, "SRID {srid}")
2139 }
2140 Invisible => {
2141 write!(f, "INVISIBLE")
2142 }
2143 }
2144 }
2145}
2146
2147/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
2148/// 'ExpStored' is used for a column generated from an expression and stored.
2149#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2151#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2152pub enum GeneratedAs {
2153 /// `GENERATED ALWAYS`
2154 Always,
2155 /// `GENERATED BY DEFAULT`
2156 ByDefault,
2157 /// Expression-based generated column that is stored (used internally for expression-stored columns)
2158 ExpStored,
2159}
2160
2161/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
2162/// No modifier is typically the same as Virtual.
2163#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2164#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2165#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2166pub enum GeneratedExpressionMode {
2167 /// `VIRTUAL` generated expression
2168 Virtual,
2169 /// `STORED` generated expression
2170 Stored,
2171}
2172
2173#[must_use]
2174pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
2175 struct ConstraintName<'a>(&'a Option<Ident>);
2176 impl fmt::Display for ConstraintName<'_> {
2177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2178 if let Some(name) = self.0 {
2179 write!(f, "CONSTRAINT {name} ")?;
2180 }
2181 Ok(())
2182 }
2183 }
2184 ConstraintName(name)
2185}
2186
2187/// If `option` is
2188/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
2189/// * `_` => do nothing
2190#[must_use]
2191pub(crate) fn display_option<'a, T: fmt::Display>(
2192 prefix: &'a str,
2193 postfix: &'a str,
2194 option: &'a Option<T>,
2195) -> impl fmt::Display + 'a {
2196 struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
2197 impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
2198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2199 if let Some(inner) = self.2 {
2200 let (prefix, postfix) = (self.0, self.1);
2201 write!(f, "{prefix}{inner}{postfix}")?;
2202 }
2203 Ok(())
2204 }
2205 }
2206 OptionDisplay(prefix, postfix, option)
2207}
2208
2209/// If `option` is
2210/// * `Some(inner)` => create display struct for `" {inner}"`
2211/// * `_` => do nothing
2212#[must_use]
2213pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2214 display_option(" ", "", option)
2215}
2216
2217/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2218///
2219/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2220#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2221#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2222#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2223pub struct ConstraintCharacteristics {
2224 /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2225 pub deferrable: Option<bool>,
2226 /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2227 pub initially: Option<DeferrableInitial>,
2228 /// `[ ENFORCED | NOT ENFORCED ]`
2229 pub enforced: Option<bool>,
2230}
2231
2232/// Initial setting for deferrable constraints (`INITIALLY IMMEDIATE` or `INITIALLY DEFERRED`).
2233#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2235#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2236pub enum DeferrableInitial {
2237 /// `INITIALLY IMMEDIATE`
2238 Immediate,
2239 /// `INITIALLY DEFERRED`
2240 Deferred,
2241}
2242
2243impl ConstraintCharacteristics {
2244 fn deferrable_text(&self) -> Option<&'static str> {
2245 self.deferrable.map(|deferrable| {
2246 if deferrable {
2247 "DEFERRABLE"
2248 } else {
2249 "NOT DEFERRABLE"
2250 }
2251 })
2252 }
2253
2254 fn initially_immediate_text(&self) -> Option<&'static str> {
2255 self.initially
2256 .map(|initially_immediate| match initially_immediate {
2257 DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2258 DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2259 })
2260 }
2261
2262 fn enforced_text(&self) -> Option<&'static str> {
2263 self.enforced.map(
2264 |enforced| {
2265 if enforced {
2266 "ENFORCED"
2267 } else {
2268 "NOT ENFORCED"
2269 }
2270 },
2271 )
2272 }
2273}
2274
2275impl fmt::Display for ConstraintCharacteristics {
2276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2277 let deferrable = self.deferrable_text();
2278 let initially_immediate = self.initially_immediate_text();
2279 let enforced = self.enforced_text();
2280
2281 match (deferrable, initially_immediate, enforced) {
2282 (None, None, None) => Ok(()),
2283 (None, None, Some(enforced)) => write!(f, "{enforced}"),
2284 (None, Some(initial), None) => write!(f, "{initial}"),
2285 (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2286 (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2287 (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2288 (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2289 (Some(deferrable), Some(initial), Some(enforced)) => {
2290 write!(f, "{deferrable} {initial} {enforced}")
2291 }
2292 }
2293 }
2294}
2295
2296/// `<referential_action> =
2297/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2298///
2299/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2300#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2301#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2302#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2303pub enum ReferentialAction {
2304 /// `RESTRICT` - disallow action if it would break referential integrity.
2305 Restrict,
2306 /// `CASCADE` - propagate the action to referencing rows.
2307 Cascade,
2308 /// `SET NULL` - set referencing columns to NULL.
2309 SetNull,
2310 /// `NO ACTION` - no action at the time; may be deferred.
2311 NoAction,
2312 /// `SET DEFAULT` - set referencing columns to their default values.
2313 SetDefault,
2314}
2315
2316impl fmt::Display for ReferentialAction {
2317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2318 f.write_str(match self {
2319 ReferentialAction::Restrict => "RESTRICT",
2320 ReferentialAction::Cascade => "CASCADE",
2321 ReferentialAction::SetNull => "SET NULL",
2322 ReferentialAction::NoAction => "NO ACTION",
2323 ReferentialAction::SetDefault => "SET DEFAULT",
2324 })
2325 }
2326}
2327
2328/// `<drop behavior> ::= CASCADE | RESTRICT`.
2329///
2330/// Used in `DROP` statements.
2331#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2332#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2333#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2334pub enum DropBehavior {
2335 /// `RESTRICT` - refuse to drop if there are any dependent objects.
2336 Restrict,
2337 /// `CASCADE` - automatically drop objects that depend on the object being dropped.
2338 Cascade,
2339}
2340
2341impl fmt::Display for DropBehavior {
2342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2343 f.write_str(match self {
2344 DropBehavior::Restrict => "RESTRICT",
2345 DropBehavior::Cascade => "CASCADE",
2346 })
2347 }
2348}
2349
2350/// SQL user defined type definition
2351#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2352#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2353#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2354pub enum UserDefinedTypeRepresentation {
2355 /// Composite type: `CREATE TYPE name AS (attributes)`
2356 Composite {
2357 /// List of attributes for the composite type.
2358 attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2359 },
2360 /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2361 ///
2362 /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2363 /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2364 Enum {
2365 /// Labels that make up the enum type.
2366 labels: Vec<Ident>,
2367 },
2368 /// Range type: `CREATE TYPE name AS RANGE (options)`
2369 ///
2370 /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2371 Range {
2372 /// Options for the range type definition.
2373 options: Vec<UserDefinedTypeRangeOption>,
2374 },
2375 /// Base type (SQL definition): `CREATE TYPE name (options)`
2376 ///
2377 /// Note the lack of `AS` keyword
2378 ///
2379 /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2380 SqlDefinition {
2381 /// Options for SQL definition of the user-defined type.
2382 options: Vec<UserDefinedTypeSqlDefinitionOption>,
2383 },
2384}
2385
2386impl fmt::Display for UserDefinedTypeRepresentation {
2387 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2388 match self {
2389 Self::Composite { attributes } => {
2390 write!(f, "AS ({})", display_comma_separated(attributes))
2391 }
2392 Self::Enum { labels } => {
2393 write!(f, "AS ENUM ({})", display_comma_separated(labels))
2394 }
2395 Self::Range { options } => {
2396 write!(f, "AS RANGE ({})", display_comma_separated(options))
2397 }
2398 Self::SqlDefinition { options } => {
2399 write!(f, "({})", display_comma_separated(options))
2400 }
2401 }
2402 }
2403}
2404
2405/// SQL user defined type attribute definition
2406#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2407#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2408#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2409pub struct UserDefinedTypeCompositeAttributeDef {
2410 /// Attribute name.
2411 pub name: Ident,
2412 /// Attribute data type.
2413 pub data_type: DataType,
2414 /// Optional collation for the attribute.
2415 pub collation: Option<ObjectName>,
2416}
2417
2418impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2419 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2420 write!(f, "{} {}", self.name, self.data_type)?;
2421 if let Some(collation) = &self.collation {
2422 write!(f, " COLLATE {collation}")?;
2423 }
2424 Ok(())
2425 }
2426}
2427
2428/// Internal length specification for PostgreSQL user-defined base types.
2429///
2430/// Specifies the internal length in bytes of the new type's internal representation.
2431/// The default assumption is that it is variable-length.
2432///
2433/// # PostgreSQL Documentation
2434/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2435///
2436/// # Examples
2437/// ```sql
2438/// CREATE TYPE mytype (
2439/// INPUT = in_func,
2440/// OUTPUT = out_func,
2441/// INTERNALLENGTH = 16 -- Fixed 16-byte length
2442/// );
2443///
2444/// CREATE TYPE mytype2 (
2445/// INPUT = in_func,
2446/// OUTPUT = out_func,
2447/// INTERNALLENGTH = VARIABLE -- Variable length
2448/// );
2449/// ```
2450#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2452#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2453pub enum UserDefinedTypeInternalLength {
2454 /// Fixed internal length: `INTERNALLENGTH = <number>`
2455 Fixed(u64),
2456 /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2457 Variable,
2458}
2459
2460impl fmt::Display for UserDefinedTypeInternalLength {
2461 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2462 match self {
2463 UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2464 UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2465 }
2466 }
2467}
2468
2469/// Alignment specification for PostgreSQL user-defined base types.
2470///
2471/// Specifies the storage alignment requirement for values of the data type.
2472/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2473/// Note that variable-length types must have an alignment of at least 4, since
2474/// they necessarily contain an int4 as their first component.
2475///
2476/// # PostgreSQL Documentation
2477/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2478///
2479/// # Examples
2480/// ```sql
2481/// CREATE TYPE mytype (
2482/// INPUT = in_func,
2483/// OUTPUT = out_func,
2484/// ALIGNMENT = int4 -- 4-byte alignment
2485/// );
2486/// ```
2487#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2488#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2489#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2490pub enum Alignment {
2491 /// Single-byte alignment: `ALIGNMENT = char`
2492 Char,
2493 /// 2-byte alignment: `ALIGNMENT = int2`
2494 Int2,
2495 /// 4-byte alignment: `ALIGNMENT = int4`
2496 Int4,
2497 /// 8-byte alignment: `ALIGNMENT = double`
2498 Double,
2499}
2500
2501impl fmt::Display for Alignment {
2502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2503 match self {
2504 Alignment::Char => write!(f, "char"),
2505 Alignment::Int2 => write!(f, "int2"),
2506 Alignment::Int4 => write!(f, "int4"),
2507 Alignment::Double => write!(f, "double"),
2508 }
2509 }
2510}
2511
2512/// Storage specification for PostgreSQL user-defined base types.
2513///
2514/// Specifies the storage strategy for values of the data type:
2515/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2516/// - `external`: Allows out-of-line storage but not compression
2517/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2518/// - `main`: Allows compression but discourages out-of-line storage
2519///
2520/// # PostgreSQL Documentation
2521/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2522///
2523/// # Examples
2524/// ```sql
2525/// CREATE TYPE mytype (
2526/// INPUT = in_func,
2527/// OUTPUT = out_func,
2528/// STORAGE = plain
2529/// );
2530/// ```
2531#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2532#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2533#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2534pub enum UserDefinedTypeStorage {
2535 /// No compression or out-of-line storage: `STORAGE = plain`
2536 Plain,
2537 /// Out-of-line storage allowed, no compression: `STORAGE = external`
2538 External,
2539 /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2540 Extended,
2541 /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2542 Main,
2543}
2544
2545impl fmt::Display for UserDefinedTypeStorage {
2546 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2547 match self {
2548 UserDefinedTypeStorage::Plain => write!(f, "plain"),
2549 UserDefinedTypeStorage::External => write!(f, "external"),
2550 UserDefinedTypeStorage::Extended => write!(f, "extended"),
2551 UserDefinedTypeStorage::Main => write!(f, "main"),
2552 }
2553 }
2554}
2555
2556/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2557///
2558/// Range types are data types representing a range of values of some element type
2559/// (called the range's subtype). These options configure the behavior of the range type.
2560///
2561/// # PostgreSQL Documentation
2562/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2563///
2564/// # Examples
2565/// ```sql
2566/// CREATE TYPE int4range AS RANGE (
2567/// SUBTYPE = int4,
2568/// SUBTYPE_OPCLASS = int4_ops,
2569/// CANONICAL = int4range_canonical,
2570/// SUBTYPE_DIFF = int4range_subdiff
2571/// );
2572/// ```
2573#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2574#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2575#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2576pub enum UserDefinedTypeRangeOption {
2577 /// The element type that the range type will represent: `SUBTYPE = subtype`
2578 Subtype(DataType),
2579 /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2580 SubtypeOpClass(ObjectName),
2581 /// Collation to use for ordering the subtype: `COLLATION = collation`
2582 Collation(ObjectName),
2583 /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2584 Canonical(ObjectName),
2585 /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2586 SubtypeDiff(ObjectName),
2587 /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2588 MultirangeTypeName(ObjectName),
2589}
2590
2591impl fmt::Display for UserDefinedTypeRangeOption {
2592 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2593 match self {
2594 UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2595 UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2596 write!(f, "SUBTYPE_OPCLASS = {}", name)
2597 }
2598 UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2599 UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2600 UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2601 UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2602 write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2603 }
2604 }
2605 }
2606}
2607
2608/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2609///
2610/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2611/// you must specify functions that convert it to and from text representation, and optionally
2612/// binary representation and other properties.
2613///
2614/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2615///
2616/// # PostgreSQL Documentation
2617/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2618///
2619/// # Examples
2620/// ```sql
2621/// CREATE TYPE complex (
2622/// INPUT = complex_in,
2623/// OUTPUT = complex_out,
2624/// INTERNALLENGTH = 16,
2625/// ALIGNMENT = double
2626/// );
2627/// ```
2628#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2629#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2630#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2631pub enum UserDefinedTypeSqlDefinitionOption {
2632 /// Function to convert from external text representation to internal: `INPUT = input_function`
2633 Input(ObjectName),
2634 /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2635 Output(ObjectName),
2636 /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2637 Receive(ObjectName),
2638 /// Function to convert from internal to external binary representation: `SEND = send_function`
2639 Send(ObjectName),
2640 /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2641 TypmodIn(ObjectName),
2642 /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2643 TypmodOut(ObjectName),
2644 /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2645 Analyze(ObjectName),
2646 /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2647 Subscript(ObjectName),
2648 /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2649 InternalLength(UserDefinedTypeInternalLength),
2650 /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2651 PassedByValue,
2652 /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2653 Alignment(Alignment),
2654 /// Storage strategy for varlena types: `STORAGE = storage`
2655 Storage(UserDefinedTypeStorage),
2656 /// Copy properties from an existing type: `LIKE = like_type`
2657 Like(ObjectName),
2658 /// Type category for implicit casting rules (single char): `CATEGORY = category`
2659 Category(char),
2660 /// Whether this type is preferred within its category: `PREFERRED = preferred`
2661 Preferred(bool),
2662 /// Default value for the type: `DEFAULT = default`
2663 Default(Expr),
2664 /// Element type for array types: `ELEMENT = element`
2665 Element(DataType),
2666 /// Delimiter character for array value display: `DELIMITER = delimiter`
2667 Delimiter(String),
2668 /// Whether the type supports collation: `COLLATABLE = collatable`
2669 Collatable(bool),
2670}
2671
2672impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2673 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2674 match self {
2675 UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2676 UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2677 UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2678 UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2679 UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2680 UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2681 write!(f, "TYPMOD_OUT = {}", name)
2682 }
2683 UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2684 UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2685 write!(f, "SUBSCRIPT = {}", name)
2686 }
2687 UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2688 write!(f, "INTERNALLENGTH = {}", len)
2689 }
2690 UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2691 UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2692 write!(f, "ALIGNMENT = {}", align)
2693 }
2694 UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2695 write!(f, "STORAGE = {}", storage)
2696 }
2697 UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2698 UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2699 UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2700 UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2701 UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2702 UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2703 write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2704 }
2705 UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2706 }
2707 }
2708}
2709
2710/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2711/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2712/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2713#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2714#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2715#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2716pub enum Partition {
2717 /// ClickHouse supports PARTITION ID 'partition_id' syntax.
2718 Identifier(Ident),
2719 /// ClickHouse supports PARTITION expr syntax.
2720 Expr(Expr),
2721 /// ClickHouse supports PART expr which represents physical partition in disk.
2722 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2723 Part(Expr),
2724 /// Hive supports multiple partitions in PARTITION (part1, part2, ...) syntax.
2725 Partitions(Vec<Expr>),
2726}
2727
2728impl fmt::Display for Partition {
2729 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2730 match self {
2731 Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2732 Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2733 Partition::Part(expr) => write!(f, "PART {expr}"),
2734 Partition::Partitions(partitions) => {
2735 write!(f, "PARTITION ({})", display_comma_separated(partitions))
2736 }
2737 }
2738 }
2739}
2740
2741/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2742/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2743#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2744#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2745#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2746pub enum Deduplicate {
2747 /// DEDUPLICATE ALL
2748 All,
2749 /// DEDUPLICATE BY expr
2750 ByExpression(Expr),
2751}
2752
2753impl fmt::Display for Deduplicate {
2754 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2755 match self {
2756 Deduplicate::All => write!(f, "DEDUPLICATE"),
2757 Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2758 }
2759 }
2760}
2761
2762/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2763/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2764///
2765/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2766#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2768#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2769pub struct ClusteredBy {
2770 /// columns used for clustering
2771 pub columns: Vec<Ident>,
2772 /// optional sorted by expressions
2773 pub sorted_by: Option<Vec<OrderByExpr>>,
2774 /// number of buckets
2775 pub num_buckets: Value,
2776}
2777
2778impl fmt::Display for ClusteredBy {
2779 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2780 write!(
2781 f,
2782 "CLUSTERED BY ({})",
2783 display_comma_separated(&self.columns)
2784 )?;
2785 if let Some(ref sorted_by) = self.sorted_by {
2786 write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2787 }
2788 write!(f, " INTO {} BUCKETS", self.num_buckets)
2789 }
2790}
2791
2792/// CREATE INDEX statement.
2793#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2794#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2795#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2796pub struct CreateIndex {
2797 /// index name
2798 pub name: Option<ObjectName>,
2799 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2800 /// table name
2801 pub table_name: ObjectName,
2802 /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2803 /// depending on the position of the option within the statement.
2804 pub using: Option<IndexType>,
2805 /// columns included in the index
2806 pub columns: Vec<IndexColumn>,
2807 /// whether the index is unique
2808 pub unique: bool,
2809 /// whether the index is created concurrently
2810 pub concurrently: bool,
2811 /// IF NOT EXISTS clause
2812 pub if_not_exists: bool,
2813 /// INCLUDE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2814 pub include: Vec<Ident>,
2815 /// NULLS DISTINCT / NOT DISTINCT clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2816 pub nulls_distinct: Option<bool>,
2817 /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2818 pub with: Vec<Expr>,
2819 /// WHERE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2820 pub predicate: Option<Expr>,
2821 /// Index options: <https://www.postgresql.org/docs/current/sql-createindex.html>
2822 pub index_options: Vec<IndexOption>,
2823 /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2824 ///
2825 /// - `ALGORITHM`
2826 /// - `LOCK`
2827 ///
2828 /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2829 pub alter_options: Vec<AlterTableOperation>,
2830}
2831
2832impl fmt::Display for CreateIndex {
2833 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2834 write!(
2835 f,
2836 "CREATE {unique}INDEX {concurrently}{if_not_exists}",
2837 unique = if self.unique { "UNIQUE " } else { "" },
2838 concurrently = if self.concurrently {
2839 "CONCURRENTLY "
2840 } else {
2841 ""
2842 },
2843 if_not_exists = if self.if_not_exists {
2844 "IF NOT EXISTS "
2845 } else {
2846 ""
2847 },
2848 )?;
2849 if let Some(value) = &self.name {
2850 write!(f, "{value} ")?;
2851 }
2852 write!(f, "ON {}", self.table_name)?;
2853 if let Some(value) = &self.using {
2854 write!(f, " USING {value} ")?;
2855 }
2856 write!(f, "({})", display_comma_separated(&self.columns))?;
2857 if !self.include.is_empty() {
2858 write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2859 }
2860 if let Some(value) = self.nulls_distinct {
2861 if value {
2862 write!(f, " NULLS DISTINCT")?;
2863 } else {
2864 write!(f, " NULLS NOT DISTINCT")?;
2865 }
2866 }
2867 if !self.with.is_empty() {
2868 write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2869 }
2870 if let Some(predicate) = &self.predicate {
2871 write!(f, " WHERE {predicate}")?;
2872 }
2873 if !self.index_options.is_empty() {
2874 write!(f, " {}", display_separated(&self.index_options, " "))?;
2875 }
2876 if !self.alter_options.is_empty() {
2877 write!(f, " {}", display_separated(&self.alter_options, " "))?;
2878 }
2879 Ok(())
2880 }
2881}
2882
2883/// CREATE TABLE statement.
2884#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2885#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2886#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2887pub struct CreateTable {
2888 /// `OR REPLACE` clause
2889 pub or_replace: bool,
2890 /// `TEMP` or `TEMPORARY` clause
2891 pub temporary: bool,
2892 /// `EXTERNAL` clause
2893 pub external: bool,
2894 /// `DYNAMIC` clause
2895 pub dynamic: bool,
2896 /// `GLOBAL` clause
2897 pub global: Option<bool>,
2898 /// `IF NOT EXISTS` clause
2899 pub if_not_exists: bool,
2900 /// `TRANSIENT` clause
2901 pub transient: bool,
2902 /// `VOLATILE` clause
2903 pub volatile: bool,
2904 /// `ICEBERG` clause
2905 pub iceberg: bool,
2906 /// Table name
2907 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2908 pub name: ObjectName,
2909 /// Column definitions
2910 pub columns: Vec<ColumnDef>,
2911 /// Table constraints
2912 pub constraints: Vec<TableConstraint>,
2913 /// Hive-specific distribution style
2914 pub hive_distribution: HiveDistributionStyle,
2915 /// Hive-specific formats like `ROW FORMAT DELIMITED` or `ROW FORMAT SERDE 'serde_class' WITH SERDEPROPERTIES (...)`
2916 pub hive_formats: Option<HiveFormat>,
2917 /// Table options
2918 pub table_options: CreateTableOptions,
2919 /// General comment for the table
2920 pub file_format: Option<FileFormat>,
2921 /// Location of the table data
2922 pub location: Option<String>,
2923 /// Query used to populate the table
2924 pub query: Option<Box<Query>>,
2925 /// If the table should be created without a rowid (SQLite)
2926 pub without_rowid: bool,
2927 /// `LIKE` clause
2928 pub like: Option<CreateTableLikeKind>,
2929 /// `CLONE` clause
2930 pub clone: Option<ObjectName>,
2931 /// Table version (for systems that support versioned tables)
2932 pub version: Option<TableVersion>,
2933 /// For Hive dialect, the table comment is after the column definitions without `=`,
2934 /// so the `comment` field is optional and different than the comment field in the general options list.
2935 /// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2936 pub comment: Option<CommentDef>,
2937 /// ClickHouse "ON COMMIT" clause:
2938 /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2939 pub on_commit: Option<OnCommit>,
2940 /// ClickHouse "ON CLUSTER" clause:
2941 /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
2942 pub on_cluster: Option<Ident>,
2943 /// ClickHouse "PRIMARY KEY " clause.
2944 /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2945 pub primary_key: Option<Box<Expr>>,
2946 /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
2947 /// than empty (represented as ()), the latter meaning "no sorting".
2948 /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2949 pub order_by: Option<OneOrManyWithParens<Expr>>,
2950 /// BigQuery: A partition expression for the table.
2951 /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
2952 pub partition_by: Option<Box<Expr>>,
2953 /// BigQuery: Table clustering column list.
2954 /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
2955 /// Snowflake: Table clustering list which contains base column, expressions on base columns.
2956 /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
2957 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
2958 /// Hive: Table clustering column list.
2959 /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
2960 pub clustered_by: Option<ClusteredBy>,
2961 /// Postgres `INHERITs` clause, which contains the list of tables from which
2962 /// the new table inherits.
2963 /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
2964 /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
2965 pub inherits: Option<Vec<ObjectName>>,
2966 /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
2967 /// Contains the parent table name.
2968 /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2969 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2970 pub partition_of: Option<ObjectName>,
2971 /// PostgreSQL partition bound specification for PARTITION OF.
2972 /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2973 pub for_values: Option<ForValues>,
2974 /// SQLite "STRICT" clause.
2975 /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
2976 /// then strict typing rules apply to that table.
2977 pub strict: bool,
2978 /// Snowflake "COPY GRANTS" clause
2979 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2980 pub copy_grants: bool,
2981 /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
2982 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2983 pub enable_schema_evolution: Option<bool>,
2984 /// Snowflake "CHANGE_TRACKING" clause
2985 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2986 pub change_tracking: Option<bool>,
2987 /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
2988 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2989 pub data_retention_time_in_days: Option<u64>,
2990 /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
2991 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2992 pub max_data_extension_time_in_days: Option<u64>,
2993 /// Snowflake "DEFAULT_DDL_COLLATION" clause
2994 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2995 pub default_ddl_collation: Option<String>,
2996 /// Snowflake "WITH AGGREGATION POLICY" clause
2997 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2998 pub with_aggregation_policy: Option<ObjectName>,
2999 /// Snowflake "WITH ROW ACCESS POLICY" clause
3000 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3001 pub with_row_access_policy: Option<RowAccessPolicy>,
3002 /// Snowflake "WITH TAG" clause
3003 /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3004 pub with_tags: Option<Vec<Tag>>,
3005 /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
3006 /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3007 pub external_volume: Option<String>,
3008 /// Snowflake "BASE_LOCATION" clause for Iceberg tables
3009 /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3010 pub base_location: Option<String>,
3011 /// Snowflake "CATALOG" clause for Iceberg tables
3012 /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3013 pub catalog: Option<String>,
3014 /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
3015 /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3016 pub catalog_sync: Option<String>,
3017 /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
3018 /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3019 pub storage_serialization_policy: Option<StorageSerializationPolicy>,
3020 /// Snowflake "TARGET_LAG" clause for dybamic tables
3021 /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3022 pub target_lag: Option<String>,
3023 /// Snowflake "WAREHOUSE" clause for dybamic tables
3024 /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3025 pub warehouse: Option<Ident>,
3026 /// Snowflake "REFRESH_MODE" clause for dybamic tables
3027 /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3028 pub refresh_mode: Option<RefreshModeKind>,
3029 /// Snowflake "INITIALIZE" clause for dybamic tables
3030 /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3031 pub initialize: Option<InitializeKind>,
3032 /// Snowflake "REQUIRE USER" clause for dybamic tables
3033 /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3034 pub require_user: bool,
3035}
3036
3037impl fmt::Display for CreateTable {
3038 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3039 // We want to allow the following options
3040 // Empty column list, allowed by PostgreSQL:
3041 // `CREATE TABLE t ()`
3042 // No columns provided for CREATE TABLE AS:
3043 // `CREATE TABLE t AS SELECT a from t2`
3044 // Columns provided for CREATE TABLE AS:
3045 // `CREATE TABLE t (a INT) AS SELECT a from t2`
3046 write!(
3047 f,
3048 "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}TABLE {if_not_exists}{name}",
3049 or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3050 external = if self.external { "EXTERNAL " } else { "" },
3051 global = self.global
3052 .map(|global| {
3053 if global {
3054 "GLOBAL "
3055 } else {
3056 "LOCAL "
3057 }
3058 })
3059 .unwrap_or(""),
3060 if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
3061 temporary = if self.temporary { "TEMPORARY " } else { "" },
3062 transient = if self.transient { "TRANSIENT " } else { "" },
3063 volatile = if self.volatile { "VOLATILE " } else { "" },
3064 // Only for Snowflake
3065 iceberg = if self.iceberg { "ICEBERG " } else { "" },
3066 dynamic = if self.dynamic { "DYNAMIC " } else { "" },
3067 name = self.name,
3068 )?;
3069 if let Some(partition_of) = &self.partition_of {
3070 write!(f, " PARTITION OF {partition_of}")?;
3071 }
3072 if let Some(on_cluster) = &self.on_cluster {
3073 write!(f, " ON CLUSTER {on_cluster}")?;
3074 }
3075 if !self.columns.is_empty() || !self.constraints.is_empty() {
3076 f.write_str(" (")?;
3077 NewLine.fmt(f)?;
3078 Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
3079 if !self.columns.is_empty() && !self.constraints.is_empty() {
3080 f.write_str(",")?;
3081 SpaceOrNewline.fmt(f)?;
3082 }
3083 Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
3084 NewLine.fmt(f)?;
3085 f.write_str(")")?;
3086 } else if self.query.is_none()
3087 && self.like.is_none()
3088 && self.clone.is_none()
3089 && self.partition_of.is_none()
3090 {
3091 // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
3092 f.write_str(" ()")?;
3093 } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
3094 write!(f, " ({like_in_columns_list})")?;
3095 }
3096 if let Some(for_values) = &self.for_values {
3097 write!(f, " {for_values}")?;
3098 }
3099
3100 // Hive table comment should be after column definitions, please refer to:
3101 // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3102 if let Some(comment) = &self.comment {
3103 write!(f, " COMMENT '{comment}'")?;
3104 }
3105
3106 // Only for SQLite
3107 if self.without_rowid {
3108 write!(f, " WITHOUT ROWID")?;
3109 }
3110
3111 if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
3112 write!(f, " {like}")?;
3113 }
3114
3115 if let Some(c) = &self.clone {
3116 write!(f, " CLONE {c}")?;
3117 }
3118
3119 if let Some(version) = &self.version {
3120 write!(f, " {version}")?;
3121 }
3122
3123 match &self.hive_distribution {
3124 HiveDistributionStyle::PARTITIONED { columns } => {
3125 write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
3126 }
3127 HiveDistributionStyle::SKEWED {
3128 columns,
3129 on,
3130 stored_as_directories,
3131 } => {
3132 write!(
3133 f,
3134 " SKEWED BY ({})) ON ({})",
3135 display_comma_separated(columns),
3136 display_comma_separated(on)
3137 )?;
3138 if *stored_as_directories {
3139 write!(f, " STORED AS DIRECTORIES")?;
3140 }
3141 }
3142 _ => (),
3143 }
3144
3145 if let Some(clustered_by) = &self.clustered_by {
3146 write!(f, " {clustered_by}")?;
3147 }
3148
3149 if let Some(HiveFormat {
3150 row_format,
3151 serde_properties,
3152 storage,
3153 location,
3154 }) = &self.hive_formats
3155 {
3156 match row_format {
3157 Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
3158 Some(HiveRowFormat::DELIMITED { delimiters }) => {
3159 write!(f, " ROW FORMAT DELIMITED")?;
3160 if !delimiters.is_empty() {
3161 write!(f, " {}", display_separated(delimiters, " "))?;
3162 }
3163 }
3164 None => (),
3165 }
3166 match storage {
3167 Some(HiveIOFormat::IOF {
3168 input_format,
3169 output_format,
3170 }) => write!(
3171 f,
3172 " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
3173 )?,
3174 Some(HiveIOFormat::FileFormat { format }) if !self.external => {
3175 write!(f, " STORED AS {format}")?
3176 }
3177 _ => (),
3178 }
3179 if let Some(serde_properties) = serde_properties.as_ref() {
3180 write!(
3181 f,
3182 " WITH SERDEPROPERTIES ({})",
3183 display_comma_separated(serde_properties)
3184 )?;
3185 }
3186 if !self.external {
3187 if let Some(loc) = location {
3188 write!(f, " LOCATION '{loc}'")?;
3189 }
3190 }
3191 }
3192 if self.external {
3193 if let Some(file_format) = self.file_format {
3194 write!(f, " STORED AS {file_format}")?;
3195 }
3196 if let Some(location) = &self.location {
3197 write!(f, " LOCATION '{location}'")?;
3198 }
3199 }
3200
3201 match &self.table_options {
3202 options @ CreateTableOptions::With(_)
3203 | options @ CreateTableOptions::Plain(_)
3204 | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
3205 _ => (),
3206 }
3207
3208 if let Some(primary_key) = &self.primary_key {
3209 write!(f, " PRIMARY KEY {primary_key}")?;
3210 }
3211 if let Some(order_by) = &self.order_by {
3212 write!(f, " ORDER BY {order_by}")?;
3213 }
3214 if let Some(inherits) = &self.inherits {
3215 write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
3216 }
3217 if let Some(partition_by) = self.partition_by.as_ref() {
3218 write!(f, " PARTITION BY {partition_by}")?;
3219 }
3220 if let Some(cluster_by) = self.cluster_by.as_ref() {
3221 write!(f, " CLUSTER BY {cluster_by}")?;
3222 }
3223 if let options @ CreateTableOptions::Options(_) = &self.table_options {
3224 write!(f, " {options}")?;
3225 }
3226 if let Some(external_volume) = self.external_volume.as_ref() {
3227 write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
3228 }
3229
3230 if let Some(catalog) = self.catalog.as_ref() {
3231 write!(f, " CATALOG='{catalog}'")?;
3232 }
3233
3234 if self.iceberg {
3235 if let Some(base_location) = self.base_location.as_ref() {
3236 write!(f, " BASE_LOCATION='{base_location}'")?;
3237 }
3238 }
3239
3240 if let Some(catalog_sync) = self.catalog_sync.as_ref() {
3241 write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
3242 }
3243
3244 if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
3245 write!(
3246 f,
3247 " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
3248 )?;
3249 }
3250
3251 if self.copy_grants {
3252 write!(f, " COPY GRANTS")?;
3253 }
3254
3255 if let Some(is_enabled) = self.enable_schema_evolution {
3256 write!(
3257 f,
3258 " ENABLE_SCHEMA_EVOLUTION={}",
3259 if is_enabled { "TRUE" } else { "FALSE" }
3260 )?;
3261 }
3262
3263 if let Some(is_enabled) = self.change_tracking {
3264 write!(
3265 f,
3266 " CHANGE_TRACKING={}",
3267 if is_enabled { "TRUE" } else { "FALSE" }
3268 )?;
3269 }
3270
3271 if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3272 write!(
3273 f,
3274 " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3275 )?;
3276 }
3277
3278 if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3279 write!(
3280 f,
3281 " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3282 )?;
3283 }
3284
3285 if let Some(default_ddl_collation) = &self.default_ddl_collation {
3286 write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3287 }
3288
3289 if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3290 write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3291 }
3292
3293 if let Some(row_access_policy) = &self.with_row_access_policy {
3294 write!(f, " {row_access_policy}",)?;
3295 }
3296
3297 if let Some(tag) = &self.with_tags {
3298 write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3299 }
3300
3301 if let Some(target_lag) = &self.target_lag {
3302 write!(f, " TARGET_LAG='{target_lag}'")?;
3303 }
3304
3305 if let Some(warehouse) = &self.warehouse {
3306 write!(f, " WAREHOUSE={warehouse}")?;
3307 }
3308
3309 if let Some(refresh_mode) = &self.refresh_mode {
3310 write!(f, " REFRESH_MODE={refresh_mode}")?;
3311 }
3312
3313 if let Some(initialize) = &self.initialize {
3314 write!(f, " INITIALIZE={initialize}")?;
3315 }
3316
3317 if self.require_user {
3318 write!(f, " REQUIRE USER")?;
3319 }
3320
3321 if self.on_commit.is_some() {
3322 let on_commit = match self.on_commit {
3323 Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3324 Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3325 Some(OnCommit::Drop) => "ON COMMIT DROP",
3326 None => "",
3327 };
3328 write!(f, " {on_commit}")?;
3329 }
3330 if self.strict {
3331 write!(f, " STRICT")?;
3332 }
3333 if let Some(query) = &self.query {
3334 write!(f, " AS {query}")?;
3335 }
3336 Ok(())
3337 }
3338}
3339
3340/// PostgreSQL partition bound specification for `PARTITION OF`.
3341///
3342/// Specifies partition bounds for a child partition table.
3343///
3344/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3345#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3346#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3347#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3348pub enum ForValues {
3349 /// `FOR VALUES IN (expr, ...)`
3350 In(Vec<Expr>),
3351 /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3352 From {
3353 /// The lower bound values for the partition.
3354 from: Vec<PartitionBoundValue>,
3355 /// The upper bound values for the partition.
3356 to: Vec<PartitionBoundValue>,
3357 },
3358 /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3359 With {
3360 /// The modulus value for hash partitioning.
3361 modulus: u64,
3362 /// The remainder value for hash partitioning.
3363 remainder: u64,
3364 },
3365 /// `DEFAULT`
3366 Default,
3367}
3368
3369impl fmt::Display for ForValues {
3370 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3371 match self {
3372 ForValues::In(values) => {
3373 write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3374 }
3375 ForValues::From { from, to } => {
3376 write!(
3377 f,
3378 "FOR VALUES FROM ({}) TO ({})",
3379 display_comma_separated(from),
3380 display_comma_separated(to)
3381 )
3382 }
3383 ForValues::With { modulus, remainder } => {
3384 write!(
3385 f,
3386 "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3387 )
3388 }
3389 ForValues::Default => write!(f, "DEFAULT"),
3390 }
3391 }
3392}
3393
3394/// A value in a partition bound specification.
3395///
3396/// Used in RANGE partition bounds where values can be expressions,
3397/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3398#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3399#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3400#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3401pub enum PartitionBoundValue {
3402 /// An expression representing a partition bound value.
3403 Expr(Expr),
3404 /// Represents negative infinity in partition bounds.
3405 MinValue,
3406 /// Represents positive infinity in partition bounds.
3407 MaxValue,
3408}
3409
3410impl fmt::Display for PartitionBoundValue {
3411 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3412 match self {
3413 PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3414 PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3415 PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3416 }
3417 }
3418}
3419
3420#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3421#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3422#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3423/// ```sql
3424/// CREATE DOMAIN name [ AS ] data_type
3425/// [ COLLATE collation ]
3426/// [ DEFAULT expression ]
3427/// [ domain_constraint [ ... ] ]
3428///
3429/// where domain_constraint is:
3430///
3431/// [ CONSTRAINT constraint_name ]
3432/// { NOT NULL | NULL | CHECK (expression) }
3433/// ```
3434/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3435pub struct CreateDomain {
3436 /// The name of the domain to be created.
3437 pub name: ObjectName,
3438 /// The data type of the domain.
3439 pub data_type: DataType,
3440 /// The collation of the domain.
3441 pub collation: Option<Ident>,
3442 /// The default value of the domain.
3443 pub default: Option<Expr>,
3444 /// The constraints of the domain.
3445 pub constraints: Vec<TableConstraint>,
3446}
3447
3448impl fmt::Display for CreateDomain {
3449 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3450 write!(
3451 f,
3452 "CREATE DOMAIN {name} AS {data_type}",
3453 name = self.name,
3454 data_type = self.data_type
3455 )?;
3456 if let Some(collation) = &self.collation {
3457 write!(f, " COLLATE {collation}")?;
3458 }
3459 if let Some(default) = &self.default {
3460 write!(f, " DEFAULT {default}")?;
3461 }
3462 if !self.constraints.is_empty() {
3463 write!(f, " {}", display_separated(&self.constraints, " "))?;
3464 }
3465 Ok(())
3466 }
3467}
3468
3469#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3470#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3471#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3472/// CREATE FUNCTION statement
3473pub struct CreateFunction {
3474 /// True if this is a `CREATE OR ALTER FUNCTION` statement
3475 ///
3476 /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3477 pub or_alter: bool,
3478 /// True if this is a `CREATE OR REPLACE FUNCTION` statement
3479 pub or_replace: bool,
3480 /// True if this is a `CREATE TEMPORARY FUNCTION` statement
3481 pub temporary: bool,
3482 /// True if this is a `CREATE IF NOT EXISTS FUNCTION` statement
3483 pub if_not_exists: bool,
3484 /// Name of the function to be created.
3485 pub name: ObjectName,
3486 /// List of arguments for the function.
3487 pub args: Option<Vec<OperateFunctionArg>>,
3488 /// The return type of the function.
3489 pub return_type: Option<DataType>,
3490 /// The expression that defines the function.
3491 ///
3492 /// Examples:
3493 /// ```sql
3494 /// AS ((SELECT 1))
3495 /// AS "console.log();"
3496 /// ```
3497 pub function_body: Option<CreateFunctionBody>,
3498 /// Behavior attribute for the function
3499 ///
3500 /// IMMUTABLE | STABLE | VOLATILE
3501 ///
3502 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3503 pub behavior: Option<FunctionBehavior>,
3504 /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3505 ///
3506 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3507 pub called_on_null: Option<FunctionCalledOnNull>,
3508 /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3509 ///
3510 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3511 pub parallel: Option<FunctionParallel>,
3512 /// SECURITY { DEFINER | INVOKER }
3513 ///
3514 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3515 pub security: Option<FunctionSecurity>,
3516 /// SET configuration_parameter clauses
3517 ///
3518 /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3519 pub set_params: Vec<FunctionDefinitionSetParam>,
3520 /// USING ... (Hive only)
3521 pub using: Option<CreateFunctionUsing>,
3522 /// Language used in a UDF definition.
3523 ///
3524 /// Example:
3525 /// ```sql
3526 /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3527 /// ```
3528 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3529 pub language: Option<Ident>,
3530 /// Determinism keyword used for non-sql UDF definitions.
3531 ///
3532 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3533 pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3534 /// List of options for creating the function.
3535 ///
3536 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3537 pub options: Option<Vec<SqlOption>>,
3538 /// Connection resource for a remote function.
3539 ///
3540 /// Example:
3541 /// ```sql
3542 /// CREATE FUNCTION foo()
3543 /// RETURNS FLOAT64
3544 /// REMOTE WITH CONNECTION us.myconnection
3545 /// ```
3546 /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3547 pub remote_connection: Option<ObjectName>,
3548}
3549
3550impl fmt::Display for CreateFunction {
3551 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3552 write!(
3553 f,
3554 "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3555 name = self.name,
3556 temp = if self.temporary { "TEMPORARY " } else { "" },
3557 or_alter = if self.or_alter { "OR ALTER " } else { "" },
3558 or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3559 if_not_exists = if self.if_not_exists {
3560 "IF NOT EXISTS "
3561 } else {
3562 ""
3563 },
3564 )?;
3565 if let Some(args) = &self.args {
3566 write!(f, "({})", display_comma_separated(args))?;
3567 }
3568 if let Some(return_type) = &self.return_type {
3569 write!(f, " RETURNS {return_type}")?;
3570 }
3571 if let Some(determinism_specifier) = &self.determinism_specifier {
3572 write!(f, " {determinism_specifier}")?;
3573 }
3574 if let Some(language) = &self.language {
3575 write!(f, " LANGUAGE {language}")?;
3576 }
3577 if let Some(behavior) = &self.behavior {
3578 write!(f, " {behavior}")?;
3579 }
3580 if let Some(called_on_null) = &self.called_on_null {
3581 write!(f, " {called_on_null}")?;
3582 }
3583 if let Some(parallel) = &self.parallel {
3584 write!(f, " {parallel}")?;
3585 }
3586 if let Some(security) = &self.security {
3587 write!(f, " {security}")?;
3588 }
3589 for set_param in &self.set_params {
3590 write!(f, " {set_param}")?;
3591 }
3592 if let Some(remote_connection) = &self.remote_connection {
3593 write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3594 }
3595 if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3596 {
3597 write!(f, " AS {body}")?;
3598 if let Some(link_symbol) = link_symbol {
3599 write!(f, ", {link_symbol}")?;
3600 }
3601 }
3602 if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3603 write!(f, " RETURN {function_body}")?;
3604 }
3605 if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3606 write!(f, " AS RETURN {function_body}")?;
3607 }
3608 if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3609 write!(f, " AS RETURN {function_body}")?;
3610 }
3611 if let Some(using) = &self.using {
3612 write!(f, " {using}")?;
3613 }
3614 if let Some(options) = &self.options {
3615 write!(
3616 f,
3617 " OPTIONS({})",
3618 display_comma_separated(options.as_slice())
3619 )?;
3620 }
3621 if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3622 write!(f, " AS {function_body}")?;
3623 }
3624 if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3625 write!(f, " AS {bes}")?;
3626 }
3627 Ok(())
3628 }
3629}
3630
3631/// ```sql
3632/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3633/// [TYPE datasource_type]
3634/// [URL datasource_url]
3635/// [COMMENT connector_comment]
3636/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3637/// ```
3638///
3639/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3640#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3641#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3642#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3643pub struct CreateConnector {
3644 /// The name of the connector to be created.
3645 pub name: Ident,
3646 /// Whether `IF NOT EXISTS` was specified.
3647 pub if_not_exists: bool,
3648 /// The type of the connector.
3649 pub connector_type: Option<String>,
3650 /// The URL of the connector.
3651 pub url: Option<String>,
3652 /// The comment for the connector.
3653 pub comment: Option<CommentDef>,
3654 /// The DC properties for the connector.
3655 pub with_dcproperties: Option<Vec<SqlOption>>,
3656}
3657
3658impl fmt::Display for CreateConnector {
3659 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3660 write!(
3661 f,
3662 "CREATE CONNECTOR {if_not_exists}{name}",
3663 if_not_exists = if self.if_not_exists {
3664 "IF NOT EXISTS "
3665 } else {
3666 ""
3667 },
3668 name = self.name,
3669 )?;
3670
3671 if let Some(connector_type) = &self.connector_type {
3672 write!(f, " TYPE '{connector_type}'")?;
3673 }
3674
3675 if let Some(url) = &self.url {
3676 write!(f, " URL '{url}'")?;
3677 }
3678
3679 if let Some(comment) = &self.comment {
3680 write!(f, " COMMENT = '{comment}'")?;
3681 }
3682
3683 if let Some(with_dcproperties) = &self.with_dcproperties {
3684 write!(
3685 f,
3686 " WITH DCPROPERTIES({})",
3687 display_comma_separated(with_dcproperties)
3688 )?;
3689 }
3690
3691 Ok(())
3692 }
3693}
3694
3695/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3696///
3697/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3698/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3699#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3701#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3702pub enum AlterSchemaOperation {
3703 /// Set the default collation for the schema.
3704 SetDefaultCollate {
3705 /// The collation to set as default.
3706 collate: Expr,
3707 },
3708 /// Add a replica to the schema.
3709 AddReplica {
3710 /// The replica to add.
3711 replica: Ident,
3712 /// Optional options for the replica.
3713 options: Option<Vec<SqlOption>>,
3714 },
3715 /// Drop a replica from the schema.
3716 DropReplica {
3717 /// The replica to drop.
3718 replica: Ident,
3719 },
3720 /// Set options for the schema.
3721 SetOptionsParens {
3722 /// The options to set.
3723 options: Vec<SqlOption>,
3724 },
3725 /// Rename the schema.
3726 Rename {
3727 /// The new name for the schema.
3728 name: ObjectName,
3729 },
3730 /// Change the owner of the schema.
3731 OwnerTo {
3732 /// The new owner of the schema.
3733 owner: Owner,
3734 },
3735}
3736
3737impl fmt::Display for AlterSchemaOperation {
3738 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3739 match self {
3740 AlterSchemaOperation::SetDefaultCollate { collate } => {
3741 write!(f, "SET DEFAULT COLLATE {collate}")
3742 }
3743 AlterSchemaOperation::AddReplica { replica, options } => {
3744 write!(f, "ADD REPLICA {replica}")?;
3745 if let Some(options) = options {
3746 write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3747 }
3748 Ok(())
3749 }
3750 AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3751 AlterSchemaOperation::SetOptionsParens { options } => {
3752 write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3753 }
3754 AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3755 AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3756 }
3757 }
3758}
3759/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3760///
3761/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3762///
3763/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3764#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3765#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3766#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3767pub enum RenameTableNameKind {
3768 /// `AS new_table_name`
3769 As(ObjectName),
3770 /// `TO new_table_name`
3771 To(ObjectName),
3772}
3773
3774impl fmt::Display for RenameTableNameKind {
3775 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3776 match self {
3777 RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3778 RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3779 }
3780 }
3781}
3782
3783#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3784#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3785#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3786/// An `ALTER SCHEMA` (`Statement::AlterSchema`) statement.
3787pub struct AlterSchema {
3788 /// The schema name to alter.
3789 pub name: ObjectName,
3790 /// Whether `IF EXISTS` was specified.
3791 pub if_exists: bool,
3792 /// The list of operations to perform on the schema.
3793 pub operations: Vec<AlterSchemaOperation>,
3794}
3795
3796impl fmt::Display for AlterSchema {
3797 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3798 write!(f, "ALTER SCHEMA ")?;
3799 if self.if_exists {
3800 write!(f, "IF EXISTS ")?;
3801 }
3802 write!(f, "{}", self.name)?;
3803 for operation in &self.operations {
3804 write!(f, " {operation}")?;
3805 }
3806
3807 Ok(())
3808 }
3809}
3810
3811impl Spanned for RenameTableNameKind {
3812 fn span(&self) -> Span {
3813 match self {
3814 RenameTableNameKind::As(name) => name.span(),
3815 RenameTableNameKind::To(name) => name.span(),
3816 }
3817 }
3818}
3819
3820#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
3821#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3822#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3823/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
3824pub enum TriggerObjectKind {
3825 /// The `FOR` syntax is used.
3826 For(TriggerObject),
3827 /// The `FOR EACH` syntax is used.
3828 ForEach(TriggerObject),
3829}
3830
3831impl Display for TriggerObjectKind {
3832 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3833 match self {
3834 TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
3835 TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
3836 }
3837 }
3838}
3839
3840#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3841#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3842#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3843/// CREATE TRIGGER
3844///
3845/// Examples:
3846///
3847/// ```sql
3848/// CREATE TRIGGER trigger_name
3849/// BEFORE INSERT ON table_name
3850/// FOR EACH ROW
3851/// EXECUTE FUNCTION trigger_function();
3852/// ```
3853///
3854/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
3855/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
3856pub struct CreateTrigger {
3857 /// True if this is a `CREATE OR ALTER TRIGGER` statement
3858 ///
3859 /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
3860 pub or_alter: bool,
3861 /// True if this is a temporary trigger.
3862 ///
3863 /// Examples:
3864 ///
3865 /// ```sql
3866 /// CREATE TEMP TRIGGER trigger_name
3867 /// ```
3868 ///
3869 /// or
3870 ///
3871 /// ```sql
3872 /// CREATE TEMPORARY TRIGGER trigger_name;
3873 /// CREATE TEMP TRIGGER trigger_name;
3874 /// ```
3875 ///
3876 /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
3877 pub temporary: bool,
3878 /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
3879 ///
3880 /// Example:
3881 /// ```sql
3882 /// CREATE OR REPLACE TRIGGER trigger_name
3883 /// AFTER INSERT ON table_name
3884 /// FOR EACH ROW
3885 /// EXECUTE FUNCTION trigger_function();
3886 /// ```
3887 pub or_replace: bool,
3888 /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
3889 pub is_constraint: bool,
3890 /// The name of the trigger to be created.
3891 pub name: ObjectName,
3892 /// Determines whether the function is called before, after, or instead of the event.
3893 ///
3894 /// Example of BEFORE:
3895 ///
3896 /// ```sql
3897 /// CREATE TRIGGER trigger_name
3898 /// BEFORE INSERT ON table_name
3899 /// FOR EACH ROW
3900 /// EXECUTE FUNCTION trigger_function();
3901 /// ```
3902 ///
3903 /// Example of AFTER:
3904 ///
3905 /// ```sql
3906 /// CREATE TRIGGER trigger_name
3907 /// AFTER INSERT ON table_name
3908 /// FOR EACH ROW
3909 /// EXECUTE FUNCTION trigger_function();
3910 /// ```
3911 ///
3912 /// Example of INSTEAD OF:
3913 ///
3914 /// ```sql
3915 /// CREATE TRIGGER trigger_name
3916 /// INSTEAD OF INSERT ON table_name
3917 /// FOR EACH ROW
3918 /// EXECUTE FUNCTION trigger_function();
3919 /// ```
3920 pub period: Option<TriggerPeriod>,
3921 /// Whether the trigger period was specified before the target table name.
3922 /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
3923 /// but rather the position of the period clause in relation to the table name.
3924 ///
3925 /// ```sql
3926 /// -- period_before_table == true: Postgres, MySQL, and standard SQL
3927 /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
3928 /// -- period_before_table == false: MSSQL
3929 /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
3930 /// ```
3931 pub period_before_table: bool,
3932 /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
3933 pub events: Vec<TriggerEvent>,
3934 /// The table on which the trigger is to be created.
3935 pub table_name: ObjectName,
3936 /// The optional referenced table name that can be referenced via
3937 /// the `FROM` keyword.
3938 pub referenced_table_name: Option<ObjectName>,
3939 /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
3940 pub referencing: Vec<TriggerReferencing>,
3941 /// This specifies whether the trigger function should be fired once for
3942 /// every row affected by the trigger event, or just once per SQL statement.
3943 /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
3944 /// those cases, the implied default is `FOR EACH ROW`.
3945 pub trigger_object: Option<TriggerObjectKind>,
3946 /// Triggering conditions
3947 pub condition: Option<Expr>,
3948 /// Execute logic block
3949 pub exec_body: Option<TriggerExecBody>,
3950 /// For MSSQL and dialects where statements are preceded by `AS`
3951 pub statements_as: bool,
3952 /// For SQL dialects with statement(s) for a body
3953 pub statements: Option<ConditionalStatements>,
3954 /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
3955 pub characteristics: Option<ConstraintCharacteristics>,
3956}
3957
3958impl Display for CreateTrigger {
3959 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3960 let CreateTrigger {
3961 or_alter,
3962 temporary,
3963 or_replace,
3964 is_constraint,
3965 name,
3966 period_before_table,
3967 period,
3968 events,
3969 table_name,
3970 referenced_table_name,
3971 referencing,
3972 trigger_object,
3973 condition,
3974 exec_body,
3975 statements_as,
3976 statements,
3977 characteristics,
3978 } = self;
3979 write!(
3980 f,
3981 "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
3982 temporary = if *temporary { "TEMPORARY " } else { "" },
3983 or_alter = if *or_alter { "OR ALTER " } else { "" },
3984 or_replace = if *or_replace { "OR REPLACE " } else { "" },
3985 is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3986 )?;
3987
3988 if *period_before_table {
3989 if let Some(p) = period {
3990 write!(f, "{p} ")?;
3991 }
3992 if !events.is_empty() {
3993 write!(f, "{} ", display_separated(events, " OR "))?;
3994 }
3995 write!(f, "ON {table_name}")?;
3996 } else {
3997 write!(f, "ON {table_name} ")?;
3998 if let Some(p) = period {
3999 write!(f, "{p}")?;
4000 }
4001 if !events.is_empty() {
4002 write!(f, " {}", display_separated(events, ", "))?;
4003 }
4004 }
4005
4006 if let Some(referenced_table_name) = referenced_table_name {
4007 write!(f, " FROM {referenced_table_name}")?;
4008 }
4009
4010 if let Some(characteristics) = characteristics {
4011 write!(f, " {characteristics}")?;
4012 }
4013
4014 if !referencing.is_empty() {
4015 write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
4016 }
4017
4018 if let Some(trigger_object) = trigger_object {
4019 write!(f, " {trigger_object}")?;
4020 }
4021 if let Some(condition) = condition {
4022 write!(f, " WHEN {condition}")?;
4023 }
4024 if let Some(exec_body) = exec_body {
4025 write!(f, " EXECUTE {exec_body}")?;
4026 }
4027 if let Some(statements) = statements {
4028 if *statements_as {
4029 write!(f, " AS")?;
4030 }
4031 write!(f, " {statements}")?;
4032 }
4033 Ok(())
4034 }
4035}
4036
4037#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4038#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4039#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4040/// DROP TRIGGER
4041///
4042/// ```sql
4043/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
4044/// ```
4045///
4046pub struct DropTrigger {
4047 /// Whether to include the `IF EXISTS` clause.
4048 pub if_exists: bool,
4049 /// The name of the trigger to be dropped.
4050 pub trigger_name: ObjectName,
4051 /// The name of the table from which the trigger is to be dropped.
4052 pub table_name: Option<ObjectName>,
4053 /// `CASCADE` or `RESTRICT`
4054 pub option: Option<ReferentialAction>,
4055}
4056
4057impl fmt::Display for DropTrigger {
4058 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4059 let DropTrigger {
4060 if_exists,
4061 trigger_name,
4062 table_name,
4063 option,
4064 } = self;
4065 write!(f, "DROP TRIGGER")?;
4066 if *if_exists {
4067 write!(f, " IF EXISTS")?;
4068 }
4069 match &table_name {
4070 Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
4071 None => write!(f, " {trigger_name}")?,
4072 };
4073 if let Some(option) = option {
4074 write!(f, " {option}")?;
4075 }
4076 Ok(())
4077 }
4078}
4079
4080/// A `TRUNCATE` statement.
4081///
4082/// ```sql
4083/// TRUNCATE TABLE [IF EXISTS] table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
4084/// ```
4085#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4086#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4087#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4088pub struct Truncate {
4089 /// Table names to truncate
4090 pub table_names: Vec<super::TruncateTableTarget>,
4091 /// Optional partition specification
4092 pub partitions: Option<Vec<Expr>>,
4093 /// TABLE - optional keyword
4094 pub table: bool,
4095 /// Snowflake/Redshift-specific option: [ IF EXISTS ]
4096 pub if_exists: bool,
4097 /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
4098 pub identity: Option<super::TruncateIdentityOption>,
4099 /// Postgres-specific option: [ CASCADE | RESTRICT ]
4100 pub cascade: Option<super::CascadeOption>,
4101 /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
4102 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
4103 pub on_cluster: Option<Ident>,
4104}
4105
4106impl fmt::Display for Truncate {
4107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4108 let table = if self.table { "TABLE " } else { "" };
4109 let if_exists = if self.if_exists { "IF EXISTS " } else { "" };
4110
4111 write!(
4112 f,
4113 "TRUNCATE {table}{if_exists}{table_names}",
4114 table_names = display_comma_separated(&self.table_names)
4115 )?;
4116
4117 if let Some(identity) = &self.identity {
4118 match identity {
4119 super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
4120 super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
4121 }
4122 }
4123 if let Some(cascade) = &self.cascade {
4124 match cascade {
4125 super::CascadeOption::Cascade => write!(f, " CASCADE")?,
4126 super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
4127 }
4128 }
4129
4130 if let Some(ref parts) = &self.partitions {
4131 if !parts.is_empty() {
4132 write!(f, " PARTITION ({})", display_comma_separated(parts))?;
4133 }
4134 }
4135 if let Some(on_cluster) = &self.on_cluster {
4136 write!(f, " ON CLUSTER {on_cluster}")?;
4137 }
4138 Ok(())
4139 }
4140}
4141
4142impl Spanned for Truncate {
4143 fn span(&self) -> Span {
4144 Span::union_iter(
4145 self.table_names.iter().map(|i| i.name.span()).chain(
4146 self.partitions
4147 .iter()
4148 .flat_map(|i| i.iter().map(|k| k.span())),
4149 ),
4150 )
4151 }
4152}
4153
4154/// An `MSCK` statement.
4155///
4156/// ```sql
4157/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
4158/// ```
4159/// MSCK (Hive) - MetaStore Check command
4160#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4162#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4163pub struct Msck {
4164 /// Table name to check
4165 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4166 pub table_name: ObjectName,
4167 /// Whether to repair the table
4168 pub repair: bool,
4169 /// Partition action (ADD, DROP, or SYNC)
4170 pub partition_action: Option<super::AddDropSync>,
4171}
4172
4173impl fmt::Display for Msck {
4174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4175 write!(
4176 f,
4177 "MSCK {repair}TABLE {table}",
4178 repair = if self.repair { "REPAIR " } else { "" },
4179 table = self.table_name
4180 )?;
4181 if let Some(pa) = &self.partition_action {
4182 write!(f, " {pa}")?;
4183 }
4184 Ok(())
4185 }
4186}
4187
4188impl Spanned for Msck {
4189 fn span(&self) -> Span {
4190 self.table_name.span()
4191 }
4192}
4193
4194/// CREATE VIEW statement.
4195#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4197#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4198pub struct CreateView {
4199 /// True if this is a `CREATE OR ALTER VIEW` statement
4200 ///
4201 /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
4202 pub or_alter: bool,
4203 /// The `OR REPLACE` clause is used to re-create the view if it already exists.
4204 pub or_replace: bool,
4205 /// if true, has MATERIALIZED view modifier
4206 pub materialized: bool,
4207 /// Snowflake: SECURE view modifier
4208 /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4209 pub secure: bool,
4210 /// View name
4211 pub name: ObjectName,
4212 /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
4213 /// Example:
4214 /// ```sql
4215 /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
4216 /// ```
4217 /// Otherwise, the flag is set to false if the view name comes after the clause
4218 /// Example:
4219 /// ```sql
4220 /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
4221 /// ```
4222 pub name_before_not_exists: bool,
4223 /// Optional column definitions
4224 pub columns: Vec<ViewColumnDef>,
4225 /// The query that defines the view.
4226 pub query: Box<Query>,
4227 /// Table options (e.g., WITH (..), OPTIONS (...))
4228 pub options: CreateTableOptions,
4229 /// BigQuery: CLUSTER BY columns
4230 pub cluster_by: Vec<Ident>,
4231 /// Snowflake: Views can have comments in Snowflake.
4232 /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4233 pub comment: Option<String>,
4234 /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
4235 pub with_no_schema_binding: bool,
4236 /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
4237 pub if_not_exists: bool,
4238 /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
4239 pub temporary: bool,
4240 /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
4241 /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
4242 pub to: Option<ObjectName>,
4243 /// MySQL: Optional parameters for the view algorithm, definer, and security context
4244 pub params: Option<CreateViewParams>,
4245}
4246
4247impl fmt::Display for CreateView {
4248 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4249 write!(
4250 f,
4251 "CREATE {or_alter}{or_replace}",
4252 or_alter = if self.or_alter { "OR ALTER " } else { "" },
4253 or_replace = if self.or_replace { "OR REPLACE " } else { "" },
4254 )?;
4255 if let Some(ref params) = self.params {
4256 params.fmt(f)?;
4257 }
4258 write!(
4259 f,
4260 "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4261 if_not_and_name = if self.if_not_exists {
4262 if self.name_before_not_exists {
4263 format!("{} IF NOT EXISTS", self.name)
4264 } else {
4265 format!("IF NOT EXISTS {}", self.name)
4266 }
4267 } else {
4268 format!("{}", self.name)
4269 },
4270 secure = if self.secure { "SECURE " } else { "" },
4271 materialized = if self.materialized {
4272 "MATERIALIZED "
4273 } else {
4274 ""
4275 },
4276 temporary = if self.temporary { "TEMPORARY " } else { "" },
4277 to = self
4278 .to
4279 .as_ref()
4280 .map(|to| format!(" TO {to}"))
4281 .unwrap_or_default()
4282 )?;
4283 if !self.columns.is_empty() {
4284 write!(f, " ({})", display_comma_separated(&self.columns))?;
4285 }
4286 if matches!(self.options, CreateTableOptions::With(_)) {
4287 write!(f, " {}", self.options)?;
4288 }
4289 if let Some(ref comment) = self.comment {
4290 write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
4291 }
4292 if !self.cluster_by.is_empty() {
4293 write!(
4294 f,
4295 " CLUSTER BY ({})",
4296 display_comma_separated(&self.cluster_by)
4297 )?;
4298 }
4299 if matches!(self.options, CreateTableOptions::Options(_)) {
4300 write!(f, " {}", self.options)?;
4301 }
4302 f.write_str(" AS")?;
4303 SpaceOrNewline.fmt(f)?;
4304 self.query.fmt(f)?;
4305 if self.with_no_schema_binding {
4306 write!(f, " WITH NO SCHEMA BINDING")?;
4307 }
4308 Ok(())
4309 }
4310}
4311
4312/// CREATE EXTENSION statement
4313/// Note: this is a PostgreSQL-specific statement
4314#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4316#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4317pub struct CreateExtension {
4318 /// Extension name
4319 pub name: Ident,
4320 /// Whether `IF NOT EXISTS` was specified for the CREATE EXTENSION.
4321 pub if_not_exists: bool,
4322 /// Whether `CASCADE` was specified for the CREATE EXTENSION.
4323 pub cascade: bool,
4324 /// Optional schema name for the extension.
4325 pub schema: Option<Ident>,
4326 /// Optional version for the extension.
4327 pub version: Option<Ident>,
4328}
4329
4330impl fmt::Display for CreateExtension {
4331 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4332 write!(
4333 f,
4334 "CREATE EXTENSION {if_not_exists}{name}",
4335 if_not_exists = if self.if_not_exists {
4336 "IF NOT EXISTS "
4337 } else {
4338 ""
4339 },
4340 name = self.name
4341 )?;
4342 if self.cascade || self.schema.is_some() || self.version.is_some() {
4343 write!(f, " WITH")?;
4344
4345 if let Some(name) = &self.schema {
4346 write!(f, " SCHEMA {name}")?;
4347 }
4348 if let Some(version) = &self.version {
4349 write!(f, " VERSION {version}")?;
4350 }
4351 if self.cascade {
4352 write!(f, " CASCADE")?;
4353 }
4354 }
4355
4356 Ok(())
4357 }
4358}
4359
4360impl Spanned for CreateExtension {
4361 fn span(&self) -> Span {
4362 Span::empty()
4363 }
4364}
4365
4366/// DROP EXTENSION statement
4367/// Note: this is a PostgreSQL-specific statement
4368///
4369/// # References
4370///
4371/// PostgreSQL Documentation:
4372/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4373#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4374#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4375#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4376pub struct DropExtension {
4377 /// One or more extension names to drop
4378 pub names: Vec<Ident>,
4379 /// Whether `IF EXISTS` was specified for the DROP EXTENSION.
4380 pub if_exists: bool,
4381 /// `CASCADE` or `RESTRICT` behaviour for the drop.
4382 pub cascade_or_restrict: Option<ReferentialAction>,
4383}
4384
4385impl fmt::Display for DropExtension {
4386 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4387 write!(f, "DROP EXTENSION")?;
4388 if self.if_exists {
4389 write!(f, " IF EXISTS")?;
4390 }
4391 write!(f, " {}", display_comma_separated(&self.names))?;
4392 if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4393 write!(f, " {cascade_or_restrict}")?;
4394 }
4395 Ok(())
4396 }
4397}
4398
4399impl Spanned for DropExtension {
4400 fn span(&self) -> Span {
4401 Span::empty()
4402 }
4403}
4404
4405/// Table type for ALTER TABLE statements.
4406/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4407#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4408#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4409#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4410pub enum AlterTableType {
4411 /// Iceberg table type
4412 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4413 Iceberg,
4414 /// Dynamic table type
4415 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
4416 Dynamic,
4417 /// External table type
4418 /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
4419 External,
4420}
4421
4422/// ALTER TABLE statement
4423#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4424#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4425#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4426pub struct AlterTable {
4427 /// Table name
4428 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4429 pub name: ObjectName,
4430 /// Whether `IF EXISTS` was specified for the `ALTER TABLE`.
4431 pub if_exists: bool,
4432 /// Whether the `ONLY` keyword was used (restrict scope to the named table).
4433 pub only: bool,
4434 /// List of `ALTER TABLE` operations to apply.
4435 pub operations: Vec<AlterTableOperation>,
4436 /// Optional Hive `SET LOCATION` clause for the alter operation.
4437 pub location: Option<HiveSetLocation>,
4438 /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4439 /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4440 /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4441 pub on_cluster: Option<Ident>,
4442 /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4443 pub table_type: Option<AlterTableType>,
4444 /// Token that represents the end of the statement (semicolon or EOF)
4445 pub end_token: AttachedToken,
4446}
4447
4448impl fmt::Display for AlterTable {
4449 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4450 match &self.table_type {
4451 Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4452 Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4453 Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
4454 None => write!(f, "ALTER TABLE ")?,
4455 }
4456
4457 if self.if_exists {
4458 write!(f, "IF EXISTS ")?;
4459 }
4460 if self.only {
4461 write!(f, "ONLY ")?;
4462 }
4463 write!(f, "{} ", &self.name)?;
4464 if let Some(cluster) = &self.on_cluster {
4465 write!(f, "ON CLUSTER {cluster} ")?;
4466 }
4467 write!(f, "{}", display_comma_separated(&self.operations))?;
4468 if let Some(loc) = &self.location {
4469 write!(f, " {loc}")?
4470 }
4471 Ok(())
4472 }
4473}
4474
4475/// DROP FUNCTION statement
4476#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4478#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4479pub struct DropFunction {
4480 /// Whether to include the `IF EXISTS` clause.
4481 pub if_exists: bool,
4482 /// One or more functions to drop
4483 pub func_desc: Vec<FunctionDesc>,
4484 /// `CASCADE` or `RESTRICT`
4485 pub drop_behavior: Option<DropBehavior>,
4486}
4487
4488impl fmt::Display for DropFunction {
4489 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4490 write!(
4491 f,
4492 "DROP FUNCTION{} {}",
4493 if self.if_exists { " IF EXISTS" } else { "" },
4494 display_comma_separated(&self.func_desc),
4495 )?;
4496 if let Some(op) = &self.drop_behavior {
4497 write!(f, " {op}")?;
4498 }
4499 Ok(())
4500 }
4501}
4502
4503impl Spanned for DropFunction {
4504 fn span(&self) -> Span {
4505 Span::empty()
4506 }
4507}
4508
4509/// CREATE OPERATOR statement
4510/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4511#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4512#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4513#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4514pub struct CreateOperator {
4515 /// Operator name (can be schema-qualified)
4516 pub name: ObjectName,
4517 /// FUNCTION or PROCEDURE parameter (function name)
4518 pub function: ObjectName,
4519 /// Whether PROCEDURE keyword was used (vs FUNCTION)
4520 pub is_procedure: bool,
4521 /// LEFTARG parameter (left operand type)
4522 pub left_arg: Option<DataType>,
4523 /// RIGHTARG parameter (right operand type)
4524 pub right_arg: Option<DataType>,
4525 /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4526 pub options: Vec<OperatorOption>,
4527}
4528
4529/// CREATE OPERATOR FAMILY statement
4530/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4531#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4532#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4533#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4534pub struct CreateOperatorFamily {
4535 /// Operator family name (can be schema-qualified)
4536 pub name: ObjectName,
4537 /// Index method (btree, hash, gist, gin, etc.)
4538 pub using: Ident,
4539}
4540
4541/// CREATE OPERATOR CLASS statement
4542/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4543#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4544#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4545#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4546pub struct CreateOperatorClass {
4547 /// Operator class name (can be schema-qualified)
4548 pub name: ObjectName,
4549 /// Whether this is the default operator class for the type
4550 pub default: bool,
4551 /// The data type
4552 pub for_type: DataType,
4553 /// Index method (btree, hash, gist, gin, etc.)
4554 pub using: Ident,
4555 /// Optional operator family name
4556 pub family: Option<ObjectName>,
4557 /// List of operator class items (operators, functions, storage)
4558 pub items: Vec<OperatorClassItem>,
4559}
4560
4561impl fmt::Display for CreateOperator {
4562 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4563 write!(f, "CREATE OPERATOR {} (", self.name)?;
4564
4565 let function_keyword = if self.is_procedure {
4566 "PROCEDURE"
4567 } else {
4568 "FUNCTION"
4569 };
4570 let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4571
4572 if let Some(left_arg) = &self.left_arg {
4573 params.push(format!("LEFTARG = {}", left_arg));
4574 }
4575 if let Some(right_arg) = &self.right_arg {
4576 params.push(format!("RIGHTARG = {}", right_arg));
4577 }
4578
4579 for option in &self.options {
4580 params.push(option.to_string());
4581 }
4582
4583 write!(f, "{}", params.join(", "))?;
4584 write!(f, ")")
4585 }
4586}
4587
4588impl fmt::Display for CreateOperatorFamily {
4589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4590 write!(
4591 f,
4592 "CREATE OPERATOR FAMILY {} USING {}",
4593 self.name, self.using
4594 )
4595 }
4596}
4597
4598impl fmt::Display for CreateOperatorClass {
4599 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4600 write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4601 if self.default {
4602 write!(f, " DEFAULT")?;
4603 }
4604 write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4605 if let Some(family) = &self.family {
4606 write!(f, " FAMILY {}", family)?;
4607 }
4608 write!(f, " AS {}", display_comma_separated(&self.items))
4609 }
4610}
4611
4612/// Operator argument types for CREATE OPERATOR CLASS
4613#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4614#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4615#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4616pub struct OperatorArgTypes {
4617 /// Left-hand operand data type for the operator.
4618 pub left: DataType,
4619 /// Right-hand operand data type for the operator.
4620 pub right: DataType,
4621}
4622
4623impl fmt::Display for OperatorArgTypes {
4624 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4625 write!(f, "{}, {}", self.left, self.right)
4626 }
4627}
4628
4629/// An item in a CREATE OPERATOR CLASS statement
4630#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4631#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4632#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4633pub enum OperatorClassItem {
4634 /// `OPERATOR` clause describing a specific operator implementation.
4635 Operator {
4636 /// Strategy number identifying the operator position in the opclass.
4637 strategy_number: u64,
4638 /// The operator name referenced by this clause.
4639 operator_name: ObjectName,
4640 /// Optional operator argument types.
4641 op_types: Option<OperatorArgTypes>,
4642 /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
4643 purpose: Option<OperatorPurpose>,
4644 },
4645 /// `FUNCTION` clause describing a support function for the operator class.
4646 Function {
4647 /// Support function number for this entry.
4648 support_number: u64,
4649 /// Optional function argument types for the operator class.
4650 op_types: Option<Vec<DataType>>,
4651 /// The function name implementing the support function.
4652 function_name: ObjectName,
4653 /// Function argument types for the support function.
4654 argument_types: Vec<DataType>,
4655 },
4656 /// `STORAGE` clause specifying the storage type.
4657 Storage {
4658 /// The storage data type.
4659 storage_type: DataType,
4660 },
4661}
4662
4663/// Purpose of an operator in an operator class
4664#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4666#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4667pub enum OperatorPurpose {
4668 /// Purpose: used for index/search operations.
4669 ForSearch,
4670 /// Purpose: used for ORDER BY; optionally includes a sort family name.
4671 ForOrderBy {
4672 /// Optional sort family object name.
4673 sort_family: ObjectName,
4674 },
4675}
4676
4677impl fmt::Display for OperatorClassItem {
4678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4679 match self {
4680 OperatorClassItem::Operator {
4681 strategy_number,
4682 operator_name,
4683 op_types,
4684 purpose,
4685 } => {
4686 write!(f, "OPERATOR {strategy_number} {operator_name}")?;
4687 if let Some(types) = op_types {
4688 write!(f, " ({types})")?;
4689 }
4690 if let Some(purpose) = purpose {
4691 write!(f, " {purpose}")?;
4692 }
4693 Ok(())
4694 }
4695 OperatorClassItem::Function {
4696 support_number,
4697 op_types,
4698 function_name,
4699 argument_types,
4700 } => {
4701 write!(f, "FUNCTION {support_number}")?;
4702 if let Some(types) = op_types {
4703 write!(f, " ({})", display_comma_separated(types))?;
4704 }
4705 write!(f, " {function_name}")?;
4706 if !argument_types.is_empty() {
4707 write!(f, "({})", display_comma_separated(argument_types))?;
4708 }
4709 Ok(())
4710 }
4711 OperatorClassItem::Storage { storage_type } => {
4712 write!(f, "STORAGE {storage_type}")
4713 }
4714 }
4715 }
4716}
4717
4718impl fmt::Display for OperatorPurpose {
4719 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4720 match self {
4721 OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
4722 OperatorPurpose::ForOrderBy { sort_family } => {
4723 write!(f, "FOR ORDER BY {sort_family}")
4724 }
4725 }
4726 }
4727}
4728
4729/// `DROP OPERATOR` statement
4730/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
4731#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4732#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4733#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4734pub struct DropOperator {
4735 /// `IF EXISTS` clause
4736 pub if_exists: bool,
4737 /// One or more operators to drop with their signatures
4738 pub operators: Vec<DropOperatorSignature>,
4739 /// `CASCADE or RESTRICT`
4740 pub drop_behavior: Option<DropBehavior>,
4741}
4742
4743/// Operator signature for a `DROP OPERATOR` statement
4744#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4745#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4746#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4747pub struct DropOperatorSignature {
4748 /// Operator name
4749 pub name: ObjectName,
4750 /// Left operand type
4751 pub left_type: Option<DataType>,
4752 /// Right operand type
4753 pub right_type: DataType,
4754}
4755
4756impl fmt::Display for DropOperatorSignature {
4757 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4758 write!(f, "{} (", self.name)?;
4759 if let Some(left_type) = &self.left_type {
4760 write!(f, "{}", left_type)?;
4761 } else {
4762 write!(f, "NONE")?;
4763 }
4764 write!(f, ", {})", self.right_type)
4765 }
4766}
4767
4768impl fmt::Display for DropOperator {
4769 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4770 write!(f, "DROP OPERATOR")?;
4771 if self.if_exists {
4772 write!(f, " IF EXISTS")?;
4773 }
4774 write!(f, " {}", display_comma_separated(&self.operators))?;
4775 if let Some(drop_behavior) = &self.drop_behavior {
4776 write!(f, " {}", drop_behavior)?;
4777 }
4778 Ok(())
4779 }
4780}
4781
4782impl Spanned for DropOperator {
4783 fn span(&self) -> Span {
4784 Span::empty()
4785 }
4786}
4787
4788/// `DROP OPERATOR FAMILY` statement
4789/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
4790#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4791#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4792#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4793pub struct DropOperatorFamily {
4794 /// `IF EXISTS` clause
4795 pub if_exists: bool,
4796 /// One or more operator families to drop
4797 pub names: Vec<ObjectName>,
4798 /// Index method (btree, hash, gist, gin, etc.)
4799 pub using: Ident,
4800 /// `CASCADE or RESTRICT`
4801 pub drop_behavior: Option<DropBehavior>,
4802}
4803
4804impl fmt::Display for DropOperatorFamily {
4805 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4806 write!(f, "DROP OPERATOR FAMILY")?;
4807 if self.if_exists {
4808 write!(f, " IF EXISTS")?;
4809 }
4810 write!(f, " {}", display_comma_separated(&self.names))?;
4811 write!(f, " USING {}", self.using)?;
4812 if let Some(drop_behavior) = &self.drop_behavior {
4813 write!(f, " {}", drop_behavior)?;
4814 }
4815 Ok(())
4816 }
4817}
4818
4819impl Spanned for DropOperatorFamily {
4820 fn span(&self) -> Span {
4821 Span::empty()
4822 }
4823}
4824
4825/// `DROP OPERATOR CLASS` statement
4826/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
4827#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4828#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4829#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4830pub struct DropOperatorClass {
4831 /// `IF EXISTS` clause
4832 pub if_exists: bool,
4833 /// One or more operator classes to drop
4834 pub names: Vec<ObjectName>,
4835 /// Index method (btree, hash, gist, gin, etc.)
4836 pub using: Ident,
4837 /// `CASCADE or RESTRICT`
4838 pub drop_behavior: Option<DropBehavior>,
4839}
4840
4841impl fmt::Display for DropOperatorClass {
4842 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4843 write!(f, "DROP OPERATOR CLASS")?;
4844 if self.if_exists {
4845 write!(f, " IF EXISTS")?;
4846 }
4847 write!(f, " {}", display_comma_separated(&self.names))?;
4848 write!(f, " USING {}", self.using)?;
4849 if let Some(drop_behavior) = &self.drop_behavior {
4850 write!(f, " {}", drop_behavior)?;
4851 }
4852 Ok(())
4853 }
4854}
4855
4856impl Spanned for DropOperatorClass {
4857 fn span(&self) -> Span {
4858 Span::empty()
4859 }
4860}
4861
4862/// An item in an ALTER OPERATOR FAMILY ADD statement
4863#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4864#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4865#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4866pub enum OperatorFamilyItem {
4867 /// `OPERATOR` clause in an operator family modification.
4868 Operator {
4869 /// Strategy number for the operator.
4870 strategy_number: u64,
4871 /// Operator name referenced by this entry.
4872 operator_name: ObjectName,
4873 /// Operator argument types.
4874 op_types: Vec<DataType>,
4875 /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
4876 purpose: Option<OperatorPurpose>,
4877 },
4878 /// `FUNCTION` clause in an operator family modification.
4879 Function {
4880 /// Support function number.
4881 support_number: u64,
4882 /// Optional operator argument types for the function.
4883 op_types: Option<Vec<DataType>>,
4884 /// Function name for the support function.
4885 function_name: ObjectName,
4886 /// Function argument types.
4887 argument_types: Vec<DataType>,
4888 },
4889}
4890
4891/// An item in an ALTER OPERATOR FAMILY DROP statement
4892#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4893#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4894#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4895pub enum OperatorFamilyDropItem {
4896 /// `OPERATOR` clause for DROP within an operator family.
4897 Operator {
4898 /// Strategy number for the operator.
4899 strategy_number: u64,
4900 /// Operator argument types.
4901 op_types: Vec<DataType>,
4902 },
4903 /// `FUNCTION` clause for DROP within an operator family.
4904 Function {
4905 /// Support function number.
4906 support_number: u64,
4907 /// Operator argument types for the function.
4908 op_types: Vec<DataType>,
4909 },
4910}
4911
4912impl fmt::Display for OperatorFamilyItem {
4913 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4914 match self {
4915 OperatorFamilyItem::Operator {
4916 strategy_number,
4917 operator_name,
4918 op_types,
4919 purpose,
4920 } => {
4921 write!(
4922 f,
4923 "OPERATOR {strategy_number} {operator_name} ({})",
4924 display_comma_separated(op_types)
4925 )?;
4926 if let Some(purpose) = purpose {
4927 write!(f, " {purpose}")?;
4928 }
4929 Ok(())
4930 }
4931 OperatorFamilyItem::Function {
4932 support_number,
4933 op_types,
4934 function_name,
4935 argument_types,
4936 } => {
4937 write!(f, "FUNCTION {support_number}")?;
4938 if let Some(types) = op_types {
4939 write!(f, " ({})", display_comma_separated(types))?;
4940 }
4941 write!(f, " {function_name}")?;
4942 if !argument_types.is_empty() {
4943 write!(f, "({})", display_comma_separated(argument_types))?;
4944 }
4945 Ok(())
4946 }
4947 }
4948 }
4949}
4950
4951impl fmt::Display for OperatorFamilyDropItem {
4952 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4953 match self {
4954 OperatorFamilyDropItem::Operator {
4955 strategy_number,
4956 op_types,
4957 } => {
4958 write!(
4959 f,
4960 "OPERATOR {strategy_number} ({})",
4961 display_comma_separated(op_types)
4962 )
4963 }
4964 OperatorFamilyDropItem::Function {
4965 support_number,
4966 op_types,
4967 } => {
4968 write!(
4969 f,
4970 "FUNCTION {support_number} ({})",
4971 display_comma_separated(op_types)
4972 )
4973 }
4974 }
4975 }
4976}
4977
4978/// `ALTER OPERATOR FAMILY` statement
4979/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
4980#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4981#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4982#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4983pub struct AlterOperatorFamily {
4984 /// Operator family name (can be schema-qualified)
4985 pub name: ObjectName,
4986 /// Index method (btree, hash, gist, gin, etc.)
4987 pub using: Ident,
4988 /// The operation to perform
4989 pub operation: AlterOperatorFamilyOperation,
4990}
4991
4992/// An [AlterOperatorFamily] operation
4993#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4994#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4995#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4996pub enum AlterOperatorFamilyOperation {
4997 /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
4998 Add {
4999 /// List of operator family items to add
5000 items: Vec<OperatorFamilyItem>,
5001 },
5002 /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
5003 Drop {
5004 /// List of operator family items to drop
5005 items: Vec<OperatorFamilyDropItem>,
5006 },
5007 /// `RENAME TO new_name`
5008 RenameTo {
5009 /// The new name for the operator family.
5010 new_name: ObjectName,
5011 },
5012 /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5013 OwnerTo(Owner),
5014 /// `SET SCHEMA new_schema`
5015 SetSchema {
5016 /// The target schema name.
5017 schema_name: ObjectName,
5018 },
5019}
5020
5021impl fmt::Display for AlterOperatorFamily {
5022 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5023 write!(
5024 f,
5025 "ALTER OPERATOR FAMILY {} USING {}",
5026 self.name, self.using
5027 )?;
5028 write!(f, " {}", self.operation)
5029 }
5030}
5031
5032impl fmt::Display for AlterOperatorFamilyOperation {
5033 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5034 match self {
5035 AlterOperatorFamilyOperation::Add { items } => {
5036 write!(f, "ADD {}", display_comma_separated(items))
5037 }
5038 AlterOperatorFamilyOperation::Drop { items } => {
5039 write!(f, "DROP {}", display_comma_separated(items))
5040 }
5041 AlterOperatorFamilyOperation::RenameTo { new_name } => {
5042 write!(f, "RENAME TO {new_name}")
5043 }
5044 AlterOperatorFamilyOperation::OwnerTo(owner) => {
5045 write!(f, "OWNER TO {owner}")
5046 }
5047 AlterOperatorFamilyOperation::SetSchema { schema_name } => {
5048 write!(f, "SET SCHEMA {schema_name}")
5049 }
5050 }
5051 }
5052}
5053
5054impl Spanned for AlterOperatorFamily {
5055 fn span(&self) -> Span {
5056 Span::empty()
5057 }
5058}
5059
5060/// `ALTER OPERATOR CLASS` statement
5061/// See <https://www.postgresql.org/docs/current/sql-alteropclass.html>
5062#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5063#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5064#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5065pub struct AlterOperatorClass {
5066 /// Operator class name (can be schema-qualified)
5067 pub name: ObjectName,
5068 /// Index method (btree, hash, gist, gin, etc.)
5069 pub using: Ident,
5070 /// The operation to perform
5071 pub operation: AlterOperatorClassOperation,
5072}
5073
5074/// An [AlterOperatorClass] operation
5075#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5076#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5077#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5078pub enum AlterOperatorClassOperation {
5079 /// `RENAME TO new_name`
5080 /// Rename the operator class to a new name.
5081 RenameTo {
5082 /// The new name for the operator class.
5083 new_name: ObjectName,
5084 },
5085 /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5086 OwnerTo(Owner),
5087 /// `SET SCHEMA new_schema`
5088 /// Set the schema for the operator class.
5089 SetSchema {
5090 /// The target schema name.
5091 schema_name: ObjectName,
5092 },
5093}
5094
5095impl fmt::Display for AlterOperatorClass {
5096 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5097 write!(f, "ALTER OPERATOR CLASS {} USING {}", self.name, self.using)?;
5098 write!(f, " {}", self.operation)
5099 }
5100}
5101
5102impl fmt::Display for AlterOperatorClassOperation {
5103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5104 match self {
5105 AlterOperatorClassOperation::RenameTo { new_name } => {
5106 write!(f, "RENAME TO {new_name}")
5107 }
5108 AlterOperatorClassOperation::OwnerTo(owner) => {
5109 write!(f, "OWNER TO {owner}")
5110 }
5111 AlterOperatorClassOperation::SetSchema { schema_name } => {
5112 write!(f, "SET SCHEMA {schema_name}")
5113 }
5114 }
5115 }
5116}
5117
5118impl Spanned for AlterOperatorClass {
5119 fn span(&self) -> Span {
5120 Span::empty()
5121 }
5122}
5123
5124/// CREATE POLICY statement.
5125///
5126/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5127#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5129#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5130pub struct CreatePolicy {
5131 /// Name of the policy.
5132 pub name: Ident,
5133 /// Table the policy is defined on.
5134 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5135 pub table_name: ObjectName,
5136 /// Optional policy type (e.g., `PERMISSIVE` / `RESTRICTIVE`).
5137 pub policy_type: Option<CreatePolicyType>,
5138 /// Optional command the policy applies to (e.g., `SELECT`).
5139 pub command: Option<CreatePolicyCommand>,
5140 /// Optional list of grantee owners.
5141 pub to: Option<Vec<Owner>>,
5142 /// Optional expression for the `USING` clause.
5143 pub using: Option<Expr>,
5144 /// Optional expression for the `WITH CHECK` clause.
5145 pub with_check: Option<Expr>,
5146}
5147
5148impl fmt::Display for CreatePolicy {
5149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5150 write!(
5151 f,
5152 "CREATE POLICY {name} ON {table_name}",
5153 name = self.name,
5154 table_name = self.table_name,
5155 )?;
5156 if let Some(ref policy_type) = self.policy_type {
5157 write!(f, " AS {policy_type}")?;
5158 }
5159 if let Some(ref command) = self.command {
5160 write!(f, " FOR {command}")?;
5161 }
5162 if let Some(ref to) = self.to {
5163 write!(f, " TO {}", display_comma_separated(to))?;
5164 }
5165 if let Some(ref using) = self.using {
5166 write!(f, " USING ({using})")?;
5167 }
5168 if let Some(ref with_check) = self.with_check {
5169 write!(f, " WITH CHECK ({with_check})")?;
5170 }
5171 Ok(())
5172 }
5173}
5174
5175/// Policy type for a `CREATE POLICY` statement.
5176/// ```sql
5177/// AS [ PERMISSIVE | RESTRICTIVE ]
5178/// ```
5179/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5180#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5182#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5183pub enum CreatePolicyType {
5184 /// Policy allows operations unless explicitly denied.
5185 Permissive,
5186 /// Policy denies operations unless explicitly allowed.
5187 Restrictive,
5188}
5189
5190impl fmt::Display for CreatePolicyType {
5191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5192 match self {
5193 CreatePolicyType::Permissive => write!(f, "PERMISSIVE"),
5194 CreatePolicyType::Restrictive => write!(f, "RESTRICTIVE"),
5195 }
5196 }
5197}
5198
5199/// Command that a policy can apply to (FOR clause).
5200/// ```sql
5201/// FOR [ALL | SELECT | INSERT | UPDATE | DELETE]
5202/// ```
5203/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5204#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5206#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5207pub enum CreatePolicyCommand {
5208 /// Applies to all commands.
5209 All,
5210 /// Applies to SELECT.
5211 Select,
5212 /// Applies to INSERT.
5213 Insert,
5214 /// Applies to UPDATE.
5215 Update,
5216 /// Applies to DELETE.
5217 Delete,
5218}
5219
5220impl fmt::Display for CreatePolicyCommand {
5221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5222 match self {
5223 CreatePolicyCommand::All => write!(f, "ALL"),
5224 CreatePolicyCommand::Select => write!(f, "SELECT"),
5225 CreatePolicyCommand::Insert => write!(f, "INSERT"),
5226 CreatePolicyCommand::Update => write!(f, "UPDATE"),
5227 CreatePolicyCommand::Delete => write!(f, "DELETE"),
5228 }
5229 }
5230}
5231
5232/// DROP POLICY statement.
5233///
5234/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
5235#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5237#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5238pub struct DropPolicy {
5239 /// `true` when `IF EXISTS` was present.
5240 pub if_exists: bool,
5241 /// Name of the policy to drop.
5242 pub name: Ident,
5243 /// Name of the table the policy applies to.
5244 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5245 pub table_name: ObjectName,
5246 /// Optional drop behavior (`CASCADE` or `RESTRICT`).
5247 pub drop_behavior: Option<DropBehavior>,
5248}
5249
5250impl fmt::Display for DropPolicy {
5251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5252 write!(
5253 f,
5254 "DROP POLICY {if_exists}{name} ON {table_name}",
5255 if_exists = if self.if_exists { "IF EXISTS " } else { "" },
5256 name = self.name,
5257 table_name = self.table_name
5258 )?;
5259 if let Some(ref behavior) = self.drop_behavior {
5260 write!(f, " {behavior}")?;
5261 }
5262 Ok(())
5263 }
5264}
5265
5266impl From<CreatePolicy> for crate::ast::Statement {
5267 fn from(v: CreatePolicy) -> Self {
5268 crate::ast::Statement::CreatePolicy(v)
5269 }
5270}
5271
5272impl From<DropPolicy> for crate::ast::Statement {
5273 fn from(v: DropPolicy) -> Self {
5274 crate::ast::Statement::DropPolicy(v)
5275 }
5276}
5277
5278/// ALTER POLICY statement.
5279///
5280/// ```sql
5281/// ALTER POLICY <NAME> ON <TABLE NAME> [<OPERATION>]
5282/// ```
5283/// (Postgresql-specific)
5284#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5286#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5287pub struct AlterPolicy {
5288 /// Policy name to alter.
5289 pub name: Ident,
5290 /// Target table name the policy is defined on.
5291 #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5292 pub table_name: ObjectName,
5293 /// Optional operation specific to the policy alteration.
5294 pub operation: AlterPolicyOperation,
5295}
5296
5297impl fmt::Display for AlterPolicy {
5298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5299 write!(
5300 f,
5301 "ALTER POLICY {name} ON {table_name}{operation}",
5302 name = self.name,
5303 table_name = self.table_name,
5304 operation = self.operation
5305 )
5306 }
5307}
5308
5309impl From<AlterPolicy> for crate::ast::Statement {
5310 fn from(v: AlterPolicy) -> Self {
5311 crate::ast::Statement::AlterPolicy(v)
5312 }
5313}