1#[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 super::super::dml::CreateTable;
28use crate::ast::{
29 ClusteredBy, ColumnDef, CommentDef, CreateTableOptions, Expr, FileFormat,
30 HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, OneOrManyWithParens, Query,
31 RowAccessPolicy, Statement, StorageSerializationPolicy, TableConstraint, Tag,
32 WrappedCollection,
33};
34
35use crate::parser::ParserError;
36
37#[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 pub or_replace: bool,
69 pub temporary: bool,
70 pub external: bool,
71 pub global: Option<bool>,
72 pub if_not_exists: bool,
73 pub transient: bool,
74 pub volatile: bool,
75 pub iceberg: bool,
76 pub name: ObjectName,
77 pub columns: Vec<ColumnDef>,
78 pub constraints: Vec<TableConstraint>,
79 pub hive_distribution: HiveDistributionStyle,
80 pub hive_formats: Option<HiveFormat>,
81 pub file_format: Option<FileFormat>,
82 pub location: Option<String>,
83 pub query: Option<Box<Query>>,
84 pub without_rowid: bool,
85 pub like: Option<ObjectName>,
86 pub clone: Option<ObjectName>,
87 pub comment: Option<CommentDef>,
88 pub on_commit: Option<OnCommit>,
89 pub on_cluster: Option<Ident>,
90 pub primary_key: Option<Box<Expr>>,
91 pub order_by: Option<OneOrManyWithParens<Expr>>,
92 pub partition_by: Option<Box<Expr>>,
93 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
94 pub clustered_by: Option<ClusteredBy>,
95 pub inherits: Option<Vec<ObjectName>>,
96 pub strict: bool,
97 pub copy_grants: bool,
98 pub enable_schema_evolution: Option<bool>,
99 pub change_tracking: Option<bool>,
100 pub data_retention_time_in_days: Option<u64>,
101 pub max_data_extension_time_in_days: Option<u64>,
102 pub default_ddl_collation: Option<String>,
103 pub with_aggregation_policy: Option<ObjectName>,
104 pub with_row_access_policy: Option<RowAccessPolicy>,
105 pub with_tags: Option<Vec<Tag>>,
106 pub base_location: Option<String>,
107 pub external_volume: Option<String>,
108 pub catalog: Option<String>,
109 pub catalog_sync: Option<String>,
110 pub storage_serialization_policy: Option<StorageSerializationPolicy>,
111 pub table_options: CreateTableOptions,
112}
113
114impl CreateTableBuilder {
115 pub fn new(name: ObjectName) -> Self {
116 Self {
117 or_replace: false,
118 temporary: false,
119 external: false,
120 global: None,
121 if_not_exists: false,
122 transient: false,
123 volatile: false,
124 iceberg: false,
125 name,
126 columns: vec![],
127 constraints: vec![],
128 hive_distribution: HiveDistributionStyle::NONE,
129 hive_formats: None,
130 file_format: None,
131 location: None,
132 query: None,
133 without_rowid: false,
134 like: None,
135 clone: None,
136 comment: None,
137 on_commit: None,
138 on_cluster: None,
139 primary_key: None,
140 order_by: None,
141 partition_by: None,
142 cluster_by: None,
143 clustered_by: None,
144 inherits: None,
145 strict: false,
146 copy_grants: false,
147 enable_schema_evolution: None,
148 change_tracking: None,
149 data_retention_time_in_days: None,
150 max_data_extension_time_in_days: None,
151 default_ddl_collation: None,
152 with_aggregation_policy: None,
153 with_row_access_policy: None,
154 with_tags: None,
155 base_location: None,
156 external_volume: None,
157 catalog: None,
158 catalog_sync: None,
159 storage_serialization_policy: None,
160 table_options: CreateTableOptions::None,
161 }
162 }
163 pub fn or_replace(mut self, or_replace: bool) -> Self {
164 self.or_replace = or_replace;
165 self
166 }
167
168 pub fn temporary(mut self, temporary: bool) -> Self {
169 self.temporary = temporary;
170 self
171 }
172
173 pub fn external(mut self, external: bool) -> Self {
174 self.external = external;
175 self
176 }
177
178 pub fn global(mut self, global: Option<bool>) -> Self {
179 self.global = global;
180 self
181 }
182
183 pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
184 self.if_not_exists = if_not_exists;
185 self
186 }
187
188 pub fn transient(mut self, transient: bool) -> Self {
189 self.transient = transient;
190 self
191 }
192
193 pub fn volatile(mut self, volatile: bool) -> Self {
194 self.volatile = volatile;
195 self
196 }
197
198 pub fn iceberg(mut self, iceberg: bool) -> Self {
199 self.iceberg = iceberg;
200 self
201 }
202
203 pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
204 self.columns = columns;
205 self
206 }
207
208 pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
209 self.constraints = constraints;
210 self
211 }
212
213 pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
214 self.hive_distribution = hive_distribution;
215 self
216 }
217
218 pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
219 self.hive_formats = hive_formats;
220 self
221 }
222
223 pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
224 self.file_format = file_format;
225 self
226 }
227 pub fn location(mut self, location: Option<String>) -> Self {
228 self.location = location;
229 self
230 }
231
232 pub fn query(mut self, query: Option<Box<Query>>) -> Self {
233 self.query = query;
234 self
235 }
236 pub fn without_rowid(mut self, without_rowid: bool) -> Self {
237 self.without_rowid = without_rowid;
238 self
239 }
240
241 pub fn like(mut self, like: Option<ObjectName>) -> Self {
242 self.like = like;
243 self
244 }
245
246 pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
248 self.clone = clone;
249 self
250 }
251
252 pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
253 self.comment = comment;
254 self
255 }
256
257 pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
258 self.on_commit = on_commit;
259 self
260 }
261
262 pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
263 self.on_cluster = on_cluster;
264 self
265 }
266
267 pub fn primary_key(mut self, primary_key: Option<Box<Expr>>) -> Self {
268 self.primary_key = primary_key;
269 self
270 }
271
272 pub fn order_by(mut self, order_by: Option<OneOrManyWithParens<Expr>>) -> Self {
273 self.order_by = order_by;
274 self
275 }
276
277 pub fn partition_by(mut self, partition_by: Option<Box<Expr>>) -> Self {
278 self.partition_by = partition_by;
279 self
280 }
281
282 pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
283 self.cluster_by = cluster_by;
284 self
285 }
286
287 pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
288 self.clustered_by = clustered_by;
289 self
290 }
291
292 pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
293 self.inherits = inherits;
294 self
295 }
296
297 pub fn strict(mut self, strict: bool) -> Self {
298 self.strict = strict;
299 self
300 }
301
302 pub fn copy_grants(mut self, copy_grants: bool) -> Self {
303 self.copy_grants = copy_grants;
304 self
305 }
306
307 pub fn enable_schema_evolution(mut self, enable_schema_evolution: Option<bool>) -> Self {
308 self.enable_schema_evolution = enable_schema_evolution;
309 self
310 }
311
312 pub fn change_tracking(mut self, change_tracking: Option<bool>) -> Self {
313 self.change_tracking = change_tracking;
314 self
315 }
316
317 pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
318 self.data_retention_time_in_days = data_retention_time_in_days;
319 self
320 }
321
322 pub fn max_data_extension_time_in_days(
323 mut self,
324 max_data_extension_time_in_days: Option<u64>,
325 ) -> Self {
326 self.max_data_extension_time_in_days = max_data_extension_time_in_days;
327 self
328 }
329
330 pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
331 self.default_ddl_collation = default_ddl_collation;
332 self
333 }
334
335 pub fn with_aggregation_policy(mut self, with_aggregation_policy: Option<ObjectName>) -> Self {
336 self.with_aggregation_policy = with_aggregation_policy;
337 self
338 }
339
340 pub fn with_row_access_policy(
341 mut self,
342 with_row_access_policy: Option<RowAccessPolicy>,
343 ) -> Self {
344 self.with_row_access_policy = with_row_access_policy;
345 self
346 }
347
348 pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
349 self.with_tags = with_tags;
350 self
351 }
352
353 pub fn base_location(mut self, base_location: Option<String>) -> Self {
354 self.base_location = base_location;
355 self
356 }
357
358 pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
359 self.external_volume = external_volume;
360 self
361 }
362
363 pub fn catalog(mut self, catalog: Option<String>) -> Self {
364 self.catalog = catalog;
365 self
366 }
367
368 pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
369 self.catalog_sync = catalog_sync;
370 self
371 }
372
373 pub fn storage_serialization_policy(
374 mut self,
375 storage_serialization_policy: Option<StorageSerializationPolicy>,
376 ) -> Self {
377 self.storage_serialization_policy = storage_serialization_policy;
378 self
379 }
380
381 pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
382 self.table_options = table_options;
383 self
384 }
385
386 pub(crate) fn validate_schema_info(&self) -> bool {
389 let mut sources = 0;
390 if !self.columns.is_empty() {
391 sources += 1;
392 }
393 if self.query.is_some() {
394 sources += 1;
395 }
396 if self.like.is_some() {
397 sources += 1;
398 }
399 if self.clone.is_some() {
400 sources += 1;
401 }
402
403 sources == 1
404 }
405
406 pub fn build(self) -> Statement {
407 Statement::CreateTable(CreateTable {
408 or_replace: self.or_replace,
409 temporary: self.temporary,
410 external: self.external,
411 global: self.global,
412 if_not_exists: self.if_not_exists,
413 transient: self.transient,
414 volatile: self.volatile,
415 iceberg: self.iceberg,
416 name: self.name,
417 columns: self.columns,
418 constraints: self.constraints,
419 hive_distribution: self.hive_distribution,
420 hive_formats: self.hive_formats,
421 file_format: self.file_format,
422 location: self.location,
423 query: self.query,
424 without_rowid: self.without_rowid,
425 like: self.like,
426 clone: self.clone,
427 comment: self.comment,
428 on_commit: self.on_commit,
429 on_cluster: self.on_cluster,
430 primary_key: self.primary_key,
431 order_by: self.order_by,
432 partition_by: self.partition_by,
433 cluster_by: self.cluster_by,
434 clustered_by: self.clustered_by,
435 inherits: self.inherits,
436 strict: self.strict,
437 copy_grants: self.copy_grants,
438 enable_schema_evolution: self.enable_schema_evolution,
439 change_tracking: self.change_tracking,
440 data_retention_time_in_days: self.data_retention_time_in_days,
441 max_data_extension_time_in_days: self.max_data_extension_time_in_days,
442 default_ddl_collation: self.default_ddl_collation,
443 with_aggregation_policy: self.with_aggregation_policy,
444 with_row_access_policy: self.with_row_access_policy,
445 with_tags: self.with_tags,
446 base_location: self.base_location,
447 external_volume: self.external_volume,
448 catalog: self.catalog,
449 catalog_sync: self.catalog_sync,
450 storage_serialization_policy: self.storage_serialization_policy,
451 table_options: self.table_options,
452 })
453 }
454}
455
456impl TryFrom<Statement> for CreateTableBuilder {
457 type Error = ParserError;
458
459 fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
462 match stmt {
463 Statement::CreateTable(CreateTable {
464 or_replace,
465 temporary,
466 external,
467 global,
468 if_not_exists,
469 transient,
470 volatile,
471 iceberg,
472 name,
473 columns,
474 constraints,
475 hive_distribution,
476 hive_formats,
477 file_format,
478 location,
479 query,
480 without_rowid,
481 like,
482 clone,
483 comment,
484 on_commit,
485 on_cluster,
486 primary_key,
487 order_by,
488 partition_by,
489 cluster_by,
490 clustered_by,
491 inherits,
492 strict,
493 copy_grants,
494 enable_schema_evolution,
495 change_tracking,
496 data_retention_time_in_days,
497 max_data_extension_time_in_days,
498 default_ddl_collation,
499 with_aggregation_policy,
500 with_row_access_policy,
501 with_tags,
502 base_location,
503 external_volume,
504 catalog,
505 catalog_sync,
506 storage_serialization_policy,
507 table_options,
508 }) => Ok(Self {
509 or_replace,
510 temporary,
511 external,
512 global,
513 if_not_exists,
514 transient,
515 name,
516 columns,
517 constraints,
518 hive_distribution,
519 hive_formats,
520 file_format,
521 location,
522 query,
523 without_rowid,
524 like,
525 clone,
526 comment,
527 on_commit,
528 on_cluster,
529 primary_key,
530 order_by,
531 partition_by,
532 cluster_by,
533 clustered_by,
534 inherits,
535 strict,
536 iceberg,
537 copy_grants,
538 enable_schema_evolution,
539 change_tracking,
540 data_retention_time_in_days,
541 max_data_extension_time_in_days,
542 default_ddl_collation,
543 with_aggregation_policy,
544 with_row_access_policy,
545 with_tags,
546 volatile,
547 base_location,
548 external_volume,
549 catalog,
550 catalog_sync,
551 storage_serialization_policy,
552 table_options,
553 }),
554 _ => Err(ParserError::ParserError(format!(
555 "Expected create table statement, but received: {stmt}"
556 ))),
557 }
558 }
559}
560
561#[derive(Default)]
563pub(crate) struct CreateTableConfiguration {
564 pub partition_by: Option<Box<Expr>>,
565 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
566 pub inherits: Option<Vec<ObjectName>>,
567 pub table_options: CreateTableOptions,
568}
569
570#[cfg(test)]
571mod tests {
572 use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
573 use crate::ast::{Ident, ObjectName, Statement};
574 use crate::parser::ParserError;
575
576 #[test]
577 pub fn test_from_valid_statement() {
578 let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
579
580 let stmt = builder.clone().build();
581
582 assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
583 }
584
585 #[test]
586 pub fn test_from_invalid_statement() {
587 let stmt = Statement::Commit {
588 chain: false,
589 end: false,
590 modifier: None,
591 };
592
593 assert_eq!(
594 CreateTableBuilder::try_from(stmt).unwrap_err(),
595 ParserError::ParserError(
596 "Expected create table statement, but received: COMMIT".to_owned()
597 )
598 );
599 }
600}