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