Skip to main content

sqlparser/ast/helpers/
stmt_create_table.rs

1// 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#[cfg(not(feature = "std"))]
19use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
20
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23
24#[cfg(feature = "visitor")]
25use sqlparser_derive::{Visit, VisitMut};
26
27use crate::ast::{
28    ClusteredBy, ColumnDef, CommentDef, CreateTable, CreateTableLikeKind, CreateTableOptions,
29    DistStyle, Expr, FileFormat, ForValues, HiveDistributionStyle, HiveFormat, Ident,
30    InitializeKind, ObjectName, OnCommit, OneOrManyWithParens, Query, RefreshModeKind,
31    RowAccessPolicy, Statement, StorageLifecyclePolicy, StorageSerializationPolicy,
32    TableConstraint, TableVersion, Tag, WithData, WrappedCollection,
33};
34
35use crate::parser::ParserError;
36
37/// Builder for create table statement variant ([1]).
38///
39/// This structure helps building and accessing a create table with more ease, without needing to:
40/// - Match the enum itself a lot of times; or
41/// - Moving a lot of variables around the code.
42///
43/// # Example
44/// ```rust
45/// use sqlparser::ast::helpers::stmt_create_table::CreateTableBuilder;
46/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName};
47/// let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]))
48///    .if_not_exists(true)
49///    .columns(vec![ColumnDef {
50///        name: Ident::new("c1"),
51///        data_type: DataType::Int(None),
52///        options: vec![],
53/// }]);
54/// // You can access internal elements with ease
55/// assert!(builder.if_not_exists);
56/// // Convert to a statement
57/// assert_eq!(
58///    builder.build().to_string(),
59///    "CREATE TABLE IF NOT EXISTS table_name (c1 INT)"
60/// )
61/// ```
62///
63/// [1]: crate::ast::Statement::CreateTable
64#[derive(Debug, Clone, PartialEq, Eq, Hash)]
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
67pub struct CreateTableBuilder {
68    /// Whether the statement uses `OR REPLACE`.
69    pub or_replace: bool,
70    /// Whether the table is `TEMPORARY`.
71    pub temporary: bool,
72    /// Whether the table is `UNLOGGED`.
73    pub unlogged: bool,
74    /// Whether the table is `EXTERNAL`.
75    pub external: bool,
76    /// Optional `GLOBAL` flag for dialects that support it.
77    pub global: Option<bool>,
78    /// Whether `IF NOT EXISTS` was specified.
79    pub if_not_exists: bool,
80    /// Whether `TRANSIENT` was specified.
81    pub transient: bool,
82    /// Whether `VOLATILE` was specified.
83    pub volatile: bool,
84    /// Iceberg-specific table flag.
85    pub iceberg: bool,
86    /// `SNAPSHOT` table flag.
87    pub snapshot: bool,
88    /// Whether `DYNAMIC` table option is set.
89    pub dynamic: bool,
90    /// The table name.
91    pub name: ObjectName,
92    /// Column definitions for the table.
93    pub columns: Vec<ColumnDef>,
94    /// Table-level constraints.
95    pub constraints: Vec<TableConstraint>,
96    /// Hive distribution style.
97    pub hive_distribution: HiveDistributionStyle,
98    /// Optional Hive format settings.
99    pub hive_formats: Option<HiveFormat>,
100    /// Optional file format for storage.
101    pub file_format: Option<FileFormat>,
102    /// Optional storage location.
103    pub location: Option<String>,
104    /// Optional `AS SELECT` query for the table.
105    pub query: Option<Box<Query>>,
106    /// Whether `WITHOUT ROWID` is set.
107    pub without_rowid: bool,
108    /// Optional `LIKE` clause kind.
109    pub like: Option<CreateTableLikeKind>,
110    /// Optional `CLONE` source object name.
111    pub clone: Option<ObjectName>,
112    /// Optional table version.
113    pub version: Option<TableVersion>,
114    /// Optional table comment.
115    pub comment: Option<CommentDef>,
116    /// Optional `ON COMMIT` behavior.
117    pub on_commit: Option<OnCommit>,
118    /// Optional cluster identifier.
119    pub on_cluster: Option<Ident>,
120    /// Optional primary key expression.
121    pub primary_key: Option<Box<Expr>>,
122    /// Optional `ORDER BY` for clustering/sorting.
123    pub order_by: Option<OneOrManyWithParens<Expr>>,
124    /// Optional `PARTITION BY` expression.
125    pub partition_by: Option<Box<Expr>>,
126    /// Optional `CLUSTER BY` expressions.
127    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
128    /// Optional `CLUSTERED BY` clause.
129    pub clustered_by: Option<ClusteredBy>,
130    /// Optional parent tables (`INHERITS`).
131    pub inherits: Option<Vec<ObjectName>>,
132    /// Optional partitioned table (`PARTITION OF`)
133    pub partition_of: Option<ObjectName>,
134    /// Range of values associated with the partition (`FOR VALUES`)
135    pub for_values: Option<ForValues>,
136    /// `STRICT` table flag.
137    pub strict: bool,
138    /// Whether to copy grants from the source.
139    pub copy_grants: bool,
140    /// Optional flag for schema evolution support.
141    pub enable_schema_evolution: Option<bool>,
142    /// Optional change tracking flag.
143    pub change_tracking: Option<bool>,
144    /// Optional data retention time in days.
145    pub data_retention_time_in_days: Option<u64>,
146    /// Optional max data extension time in days.
147    pub max_data_extension_time_in_days: Option<u64>,
148    /// Optional default DDL collation.
149    pub default_ddl_collation: Option<String>,
150    /// Optional aggregation policy object name.
151    pub with_aggregation_policy: Option<ObjectName>,
152    /// Optional row access policy applied to the table.
153    pub with_row_access_policy: Option<RowAccessPolicy>,
154    /// Optional storage lifecycle policy applied to the table.
155    pub with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
156    /// Optional tags/labels attached to the table metadata.
157    pub with_tags: Option<Vec<Tag>>,
158    /// Optional base location for staged data.
159    pub base_location: Option<String>,
160    /// Optional external volume identifier.
161    pub external_volume: Option<String>,
162    /// `WITH CONNECTION` clause.
163    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_external_table_statement)
164    pub with_connection: Option<ObjectName>,
165    /// Optional catalog name.
166    pub catalog: Option<String>,
167    /// Optional catalog synchronization option.
168    pub catalog_sync: Option<String>,
169    /// Optional storage serialization policy.
170    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
171    /// Parsed table options from the statement.
172    pub table_options: CreateTableOptions,
173    /// Optional target lag configuration.
174    pub target_lag: Option<String>,
175    /// Optional warehouse identifier.
176    pub warehouse: Option<Ident>,
177    /// Optional refresh mode for materialized tables.
178    pub refresh_mode: Option<RefreshModeKind>,
179    /// Optional initialization kind for the table.
180    pub initialize: Option<InitializeKind>,
181    /// Whether operations require a user identity.
182    pub require_user: bool,
183    /// Redshift `DISTSTYLE` option.
184    pub diststyle: Option<DistStyle>,
185    /// Redshift `DISTKEY` option.
186    pub distkey: Option<Expr>,
187    /// Redshift `SORTKEY` option.
188    pub sortkey: Option<Vec<Expr>>,
189    /// Redshift `BACKUP` option.
190    pub backup: Option<bool>,
191    /// `MULTISET | SET` table-kind prefix.
192    pub multiset: Option<bool>,
193    /// `FALLBACK` clause.
194    pub fallback: Option<bool>,
195    /// `WITH DATA` clause.
196    pub with_data: Option<WithData>,
197}
198
199impl CreateTableBuilder {
200    /// Create a new `CreateTableBuilder` for the given table name.
201    pub fn new(name: ObjectName) -> Self {
202        Self {
203            or_replace: false,
204            temporary: false,
205            unlogged: false,
206            external: false,
207            global: None,
208            if_not_exists: false,
209            transient: false,
210            volatile: false,
211            iceberg: false,
212            snapshot: false,
213            dynamic: false,
214            name,
215            columns: vec![],
216            constraints: vec![],
217            hive_distribution: HiveDistributionStyle::NONE,
218            hive_formats: None,
219            file_format: None,
220            location: None,
221            query: None,
222            without_rowid: false,
223            like: None,
224            clone: None,
225            version: None,
226            comment: None,
227            on_commit: None,
228            on_cluster: None,
229            primary_key: None,
230            order_by: None,
231            partition_by: None,
232            cluster_by: None,
233            clustered_by: None,
234            inherits: None,
235            partition_of: None,
236            for_values: None,
237            strict: false,
238            copy_grants: false,
239            enable_schema_evolution: None,
240            change_tracking: None,
241            data_retention_time_in_days: None,
242            max_data_extension_time_in_days: None,
243            default_ddl_collation: None,
244            with_aggregation_policy: None,
245            with_row_access_policy: None,
246            with_storage_lifecycle_policy: None,
247            with_tags: None,
248            base_location: None,
249            external_volume: None,
250            with_connection: None,
251            catalog: None,
252            catalog_sync: None,
253            storage_serialization_policy: None,
254            table_options: CreateTableOptions::None,
255            target_lag: None,
256            warehouse: None,
257            refresh_mode: None,
258            initialize: None,
259            require_user: false,
260            diststyle: None,
261            distkey: None,
262            sortkey: None,
263            backup: None,
264            multiset: None,
265            fallback: None,
266            with_data: None,
267        }
268    }
269    /// Set `OR REPLACE` for the CREATE TABLE statement.
270    pub fn or_replace(mut self, or_replace: bool) -> Self {
271        self.or_replace = or_replace;
272        self
273    }
274    /// Mark the table as `TEMPORARY`.
275    pub fn temporary(mut self, temporary: bool) -> Self {
276        self.temporary = temporary;
277        self
278    }
279    /// Mark the table as `UNLOGGED`.
280    pub fn unlogged(mut self, unlogged: bool) -> Self {
281        self.unlogged = unlogged;
282        self
283    }
284    /// Mark the table as `EXTERNAL`.
285    pub fn external(mut self, external: bool) -> Self {
286        self.external = external;
287        self
288    }
289    /// Set optional `GLOBAL` flag (dialect-specific).
290    pub fn global(mut self, global: Option<bool>) -> Self {
291        self.global = global;
292        self
293    }
294    /// Set `IF NOT EXISTS`.
295    pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
296        self.if_not_exists = if_not_exists;
297        self
298    }
299    /// Set `TRANSIENT` flag.
300    pub fn transient(mut self, transient: bool) -> Self {
301        self.transient = transient;
302        self
303    }
304    /// Set `VOLATILE` flag.
305    pub fn volatile(mut self, volatile: bool) -> Self {
306        self.volatile = volatile;
307        self
308    }
309    /// Enable Iceberg table semantics.
310    pub fn iceberg(mut self, iceberg: bool) -> Self {
311        self.iceberg = iceberg;
312        self
313    }
314    /// Set `SNAPSHOT` table flag (BigQuery).
315    pub fn snapshot(mut self, snapshot: bool) -> Self {
316        self.snapshot = snapshot;
317        self
318    }
319    /// Set `DYNAMIC` table option.
320    pub fn dynamic(mut self, dynamic: bool) -> Self {
321        self.dynamic = dynamic;
322        self
323    }
324    /// Set the table column definitions.
325    pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
326        self.columns = columns;
327        self
328    }
329    /// Set table-level constraints.
330    pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
331        self.constraints = constraints;
332        self
333    }
334    /// Set Hive distribution style.
335    pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
336        self.hive_distribution = hive_distribution;
337        self
338    }
339    /// Set Hive-specific formats.
340    pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
341        self.hive_formats = hive_formats;
342        self
343    }
344    /// Set file format for the table (e.g., PARQUET).
345    pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
346        self.file_format = file_format;
347        self
348    }
349    /// Set storage `location` for the table.
350    pub fn location(mut self, location: Option<String>) -> Self {
351        self.location = location;
352        self
353    }
354    /// Set an underlying `AS SELECT` query for the table.
355    pub fn query(mut self, query: Option<Box<Query>>) -> Self {
356        self.query = query;
357        self
358    }
359    /// Set `WITHOUT ROWID` option.
360    pub fn without_rowid(mut self, without_rowid: bool) -> Self {
361        self.without_rowid = without_rowid;
362        self
363    }
364    /// Set `LIKE` clause for the table.
365    pub fn like(mut self, like: Option<CreateTableLikeKind>) -> Self {
366        self.like = like;
367        self
368    }
369    // Different name to allow the object to be cloned
370    /// Set `CLONE` source object name.
371    pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
372        self.clone = clone;
373        self
374    }
375    /// Set table `VERSION`.
376    pub fn version(mut self, version: Option<TableVersion>) -> Self {
377        self.version = version;
378        self
379    }
380    /// Set a comment for the table or following column definitions.
381    pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
382        self.comment = comment;
383        self
384    }
385    /// Set `ON COMMIT` behavior for temporary tables.
386    pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
387        self.on_commit = on_commit;
388        self
389    }
390    /// Set cluster identifier for the table.
391    pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
392        self.on_cluster = on_cluster;
393        self
394    }
395    /// Set a primary key expression for the table.
396    pub fn primary_key(mut self, primary_key: Option<Box<Expr>>) -> Self {
397        self.primary_key = primary_key;
398        self
399    }
400    /// Set `ORDER BY` clause for clustered/sorted tables.
401    pub fn order_by(mut self, order_by: Option<OneOrManyWithParens<Expr>>) -> Self {
402        self.order_by = order_by;
403        self
404    }
405    /// Set `PARTITION BY` expression.
406    pub fn partition_by(mut self, partition_by: Option<Box<Expr>>) -> Self {
407        self.partition_by = partition_by;
408        self
409    }
410    /// Set `CLUSTER BY` expression(s).
411    pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
412        self.cluster_by = cluster_by;
413        self
414    }
415    /// Set `CLUSTERED BY` clause.
416    pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
417        self.clustered_by = clustered_by;
418        self
419    }
420    /// Set parent tables via `INHERITS`.
421    pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
422        self.inherits = inherits;
423        self
424    }
425
426    /// Sets the table which is partitioned to create the current table.
427    pub fn partition_of(mut self, partition_of: Option<ObjectName>) -> Self {
428        self.partition_of = partition_of;
429        self
430    }
431
432    /// Sets the range of values associated with the partition.
433    pub fn for_values(mut self, for_values: Option<ForValues>) -> Self {
434        self.for_values = for_values;
435        self
436    }
437
438    /// Set `STRICT` option.
439    pub fn strict(mut self, strict: bool) -> Self {
440        self.strict = strict;
441        self
442    }
443    /// Enable copying grants from source object.
444    pub fn copy_grants(mut self, copy_grants: bool) -> Self {
445        self.copy_grants = copy_grants;
446        self
447    }
448    /// Enable or disable schema evolution features.
449    pub fn enable_schema_evolution(mut self, enable_schema_evolution: Option<bool>) -> Self {
450        self.enable_schema_evolution = enable_schema_evolution;
451        self
452    }
453    /// Enable or disable change tracking.
454    pub fn change_tracking(mut self, change_tracking: Option<bool>) -> Self {
455        self.change_tracking = change_tracking;
456        self
457    }
458    /// Set data retention time (in days).
459    pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
460        self.data_retention_time_in_days = data_retention_time_in_days;
461        self
462    }
463    /// Set maximum data extension time (in days).
464    pub fn max_data_extension_time_in_days(
465        mut self,
466        max_data_extension_time_in_days: Option<u64>,
467    ) -> Self {
468        self.max_data_extension_time_in_days = max_data_extension_time_in_days;
469        self
470    }
471    /// Set default DDL collation.
472    pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
473        self.default_ddl_collation = default_ddl_collation;
474        self
475    }
476    /// Set aggregation policy object.
477    pub fn with_aggregation_policy(mut self, with_aggregation_policy: Option<ObjectName>) -> Self {
478        self.with_aggregation_policy = with_aggregation_policy;
479        self
480    }
481    /// Attach a row access policy to the table.
482    pub fn with_row_access_policy(
483        mut self,
484        with_row_access_policy: Option<RowAccessPolicy>,
485    ) -> Self {
486        self.with_row_access_policy = with_row_access_policy;
487        self
488    }
489    /// Attach a storage lifecycle policy to the table.
490    pub fn with_storage_lifecycle_policy(
491        mut self,
492        with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
493    ) -> Self {
494        self.with_storage_lifecycle_policy = with_storage_lifecycle_policy;
495        self
496    }
497    /// Attach tags/labels to the table metadata.
498    pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
499        self.with_tags = with_tags;
500        self
501    }
502    /// Set a base storage location for staged data.
503    pub fn base_location(mut self, base_location: Option<String>) -> Self {
504        self.base_location = base_location;
505        self
506    }
507    /// Set an external volume identifier.
508    pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
509        self.external_volume = external_volume;
510        self
511    }
512    /// Set the `WITH CONNECTION` clause.
513    pub fn with_connection(mut self, with_connection: Option<ObjectName>) -> Self {
514        self.with_connection = with_connection;
515        self
516    }
517    /// Set the catalog name for the table.
518    pub fn catalog(mut self, catalog: Option<String>) -> Self {
519        self.catalog = catalog;
520        self
521    }
522    /// Set catalog synchronization option.
523    pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
524        self.catalog_sync = catalog_sync;
525        self
526    }
527    /// Set a storage serialization policy.
528    pub fn storage_serialization_policy(
529        mut self,
530        storage_serialization_policy: Option<StorageSerializationPolicy>,
531    ) -> Self {
532        self.storage_serialization_policy = storage_serialization_policy;
533        self
534    }
535    /// Set arbitrary table options parsed from the statement.
536    pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
537        self.table_options = table_options;
538        self
539    }
540    /// Set a target lag configuration (dialect-specific).
541    pub fn target_lag(mut self, target_lag: Option<String>) -> Self {
542        self.target_lag = target_lag;
543        self
544    }
545    /// Associate the table with a warehouse identifier.
546    pub fn warehouse(mut self, warehouse: Option<Ident>) -> Self {
547        self.warehouse = warehouse;
548        self
549    }
550    /// Set refresh mode for materialized/managed tables.
551    pub fn refresh_mode(mut self, refresh_mode: Option<RefreshModeKind>) -> Self {
552        self.refresh_mode = refresh_mode;
553        self
554    }
555    /// Set initialization mode for the table.
556    pub fn initialize(mut self, initialize: Option<InitializeKind>) -> Self {
557        self.initialize = initialize;
558        self
559    }
560    /// Require a user identity for table operations.
561    pub fn require_user(mut self, require_user: bool) -> Self {
562        self.require_user = require_user;
563        self
564    }
565    /// Set Redshift `DISTSTYLE` option.
566    pub fn diststyle(mut self, diststyle: Option<DistStyle>) -> Self {
567        self.diststyle = diststyle;
568        self
569    }
570    /// Set Redshift `DISTKEY` option.
571    pub fn distkey(mut self, distkey: Option<Expr>) -> Self {
572        self.distkey = distkey;
573        self
574    }
575    /// Set Redshift `SORTKEY` option.
576    pub fn sortkey(mut self, sortkey: Option<Vec<Expr>>) -> Self {
577        self.sortkey = sortkey;
578        self
579    }
580    /// Set the Redshift `BACKUP` option.
581    pub fn backup(mut self, backup: Option<bool>) -> Self {
582        self.backup = backup;
583        self
584    }
585    /// Set `MULTISET | SET` table-kind prefix.
586    /// Some(true) => `MULTISET`, Some(false) => `SET`.
587    pub fn multiset(mut self, multiset: Option<bool>) -> Self {
588        self.multiset = multiset;
589        self
590    }
591    /// Set `FALLBACK` / `NO FALLBACK` flag.
592    pub fn fallback(mut self, fallback: Option<bool>) -> Self {
593        self.fallback = fallback;
594        self
595    }
596    /// Set `WITH DATA` clause.
597    pub fn with_data(mut self, with_data: Option<WithData>) -> Self {
598        self.with_data = with_data;
599        self
600    }
601    /// Consume the builder and produce a `CreateTable`.
602    pub fn build(self) -> CreateTable {
603        CreateTable {
604            or_replace: self.or_replace,
605            temporary: self.temporary,
606            unlogged: self.unlogged,
607            external: self.external,
608            global: self.global,
609            if_not_exists: self.if_not_exists,
610            transient: self.transient,
611            volatile: self.volatile,
612            iceberg: self.iceberg,
613            snapshot: self.snapshot,
614            dynamic: self.dynamic,
615            name: self.name,
616            columns: self.columns,
617            constraints: self.constraints,
618            hive_distribution: self.hive_distribution,
619            hive_formats: self.hive_formats,
620            file_format: self.file_format,
621            location: self.location,
622            query: self.query,
623            without_rowid: self.without_rowid,
624            like: self.like,
625            clone: self.clone,
626            version: self.version,
627            comment: self.comment,
628            on_commit: self.on_commit,
629            on_cluster: self.on_cluster,
630            primary_key: self.primary_key,
631            order_by: self.order_by,
632            partition_by: self.partition_by,
633            cluster_by: self.cluster_by,
634            clustered_by: self.clustered_by,
635            inherits: self.inherits,
636            partition_of: self.partition_of,
637            for_values: self.for_values,
638            strict: self.strict,
639            copy_grants: self.copy_grants,
640            enable_schema_evolution: self.enable_schema_evolution,
641            change_tracking: self.change_tracking,
642            data_retention_time_in_days: self.data_retention_time_in_days,
643            max_data_extension_time_in_days: self.max_data_extension_time_in_days,
644            default_ddl_collation: self.default_ddl_collation,
645            with_aggregation_policy: self.with_aggregation_policy,
646            with_row_access_policy: self.with_row_access_policy,
647            with_storage_lifecycle_policy: self.with_storage_lifecycle_policy,
648            with_tags: self.with_tags,
649            base_location: self.base_location,
650            external_volume: self.external_volume,
651            with_connection: self.with_connection,
652            catalog: self.catalog,
653            catalog_sync: self.catalog_sync,
654            storage_serialization_policy: self.storage_serialization_policy,
655            table_options: self.table_options,
656            target_lag: self.target_lag,
657            warehouse: self.warehouse,
658            refresh_mode: self.refresh_mode,
659            initialize: self.initialize,
660            require_user: self.require_user,
661            diststyle: self.diststyle,
662            distkey: self.distkey,
663            sortkey: self.sortkey,
664            backup: self.backup,
665            multiset: self.multiset,
666            fallback: self.fallback,
667            with_data: self.with_data,
668        }
669    }
670}
671
672impl TryFrom<Statement> for CreateTableBuilder {
673    type Error = ParserError;
674
675    // As the builder can be transformed back to a statement, it shouldn't be a problem to take the
676    // ownership.
677    fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
678        match stmt {
679            Statement::CreateTable(create_table) => Ok(create_table.into()),
680            _ => Err(ParserError::ParserError(format!(
681                "Expected create table statement, but received: {stmt}"
682            ))),
683        }
684    }
685}
686
687impl From<CreateTable> for CreateTableBuilder {
688    fn from(table: CreateTable) -> Self {
689        Self {
690            or_replace: table.or_replace,
691            temporary: table.temporary,
692            unlogged: table.unlogged,
693            external: table.external,
694            global: table.global,
695            if_not_exists: table.if_not_exists,
696            transient: table.transient,
697            volatile: table.volatile,
698            iceberg: table.iceberg,
699            snapshot: table.snapshot,
700            dynamic: table.dynamic,
701            name: table.name,
702            columns: table.columns,
703            constraints: table.constraints,
704            hive_distribution: table.hive_distribution,
705            hive_formats: table.hive_formats,
706            file_format: table.file_format,
707            location: table.location,
708            query: table.query,
709            without_rowid: table.without_rowid,
710            like: table.like,
711            clone: table.clone,
712            version: table.version,
713            comment: table.comment,
714            on_commit: table.on_commit,
715            on_cluster: table.on_cluster,
716            primary_key: table.primary_key,
717            order_by: table.order_by,
718            partition_by: table.partition_by,
719            cluster_by: table.cluster_by,
720            clustered_by: table.clustered_by,
721            inherits: table.inherits,
722            partition_of: table.partition_of,
723            for_values: table.for_values,
724            strict: table.strict,
725            copy_grants: table.copy_grants,
726            enable_schema_evolution: table.enable_schema_evolution,
727            change_tracking: table.change_tracking,
728            data_retention_time_in_days: table.data_retention_time_in_days,
729            max_data_extension_time_in_days: table.max_data_extension_time_in_days,
730            default_ddl_collation: table.default_ddl_collation,
731            with_aggregation_policy: table.with_aggregation_policy,
732            with_row_access_policy: table.with_row_access_policy,
733            with_storage_lifecycle_policy: table.with_storage_lifecycle_policy,
734            with_tags: table.with_tags,
735            base_location: table.base_location,
736            external_volume: table.external_volume,
737            with_connection: table.with_connection,
738            catalog: table.catalog,
739            catalog_sync: table.catalog_sync,
740            storage_serialization_policy: table.storage_serialization_policy,
741            table_options: table.table_options,
742            target_lag: table.target_lag,
743            warehouse: table.warehouse,
744            refresh_mode: table.refresh_mode,
745            initialize: table.initialize,
746            require_user: table.require_user,
747            diststyle: table.diststyle,
748            distkey: table.distkey,
749            sortkey: table.sortkey,
750            backup: table.backup,
751            multiset: table.multiset,
752            fallback: table.fallback,
753            with_data: table.with_data,
754        }
755    }
756}
757
758/// Helper return type when parsing configuration for a `CREATE TABLE` statement.
759#[derive(Default)]
760pub(crate) struct CreateTableConfiguration {
761    pub partition_by: Option<Box<Expr>>,
762    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
763    pub inherits: Option<Vec<ObjectName>>,
764    pub table_options: CreateTableOptions,
765}
766
767#[cfg(test)]
768mod tests {
769    use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
770    use crate::ast::{Ident, ObjectName, Statement};
771    use crate::parser::ParserError;
772
773    #[test]
774    pub fn test_from_valid_statement() {
775        let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
776
777        let create_table = builder.clone().build();
778        let stmt: Statement = create_table.into();
779
780        assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
781    }
782
783    #[test]
784    pub fn test_from_invalid_statement() {
785        let stmt = Statement::Commit {
786            chain: false,
787            end: false,
788            modifier: None,
789        };
790
791        assert_eq!(
792            CreateTableBuilder::try_from(stmt).unwrap_err(),
793            ParserError::ParserError(
794                "Expected create table statement, but received: COMMIT".to_owned()
795            )
796        );
797    }
798}