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 fn build(self) -> Statement {
387 Statement::CreateTable(CreateTable {
388 or_replace: self.or_replace,
389 temporary: self.temporary,
390 external: self.external,
391 global: self.global,
392 if_not_exists: self.if_not_exists,
393 transient: self.transient,
394 volatile: self.volatile,
395 iceberg: self.iceberg,
396 name: self.name,
397 columns: self.columns,
398 constraints: self.constraints,
399 hive_distribution: self.hive_distribution,
400 hive_formats: self.hive_formats,
401 file_format: self.file_format,
402 location: self.location,
403 query: self.query,
404 without_rowid: self.without_rowid,
405 like: self.like,
406 clone: self.clone,
407 comment: self.comment,
408 on_commit: self.on_commit,
409 on_cluster: self.on_cluster,
410 primary_key: self.primary_key,
411 order_by: self.order_by,
412 partition_by: self.partition_by,
413 cluster_by: self.cluster_by,
414 clustered_by: self.clustered_by,
415 inherits: self.inherits,
416 strict: self.strict,
417 copy_grants: self.copy_grants,
418 enable_schema_evolution: self.enable_schema_evolution,
419 change_tracking: self.change_tracking,
420 data_retention_time_in_days: self.data_retention_time_in_days,
421 max_data_extension_time_in_days: self.max_data_extension_time_in_days,
422 default_ddl_collation: self.default_ddl_collation,
423 with_aggregation_policy: self.with_aggregation_policy,
424 with_row_access_policy: self.with_row_access_policy,
425 with_tags: self.with_tags,
426 base_location: self.base_location,
427 external_volume: self.external_volume,
428 catalog: self.catalog,
429 catalog_sync: self.catalog_sync,
430 storage_serialization_policy: self.storage_serialization_policy,
431 table_options: self.table_options,
432 })
433 }
434}
435
436impl TryFrom<Statement> for CreateTableBuilder {
437 type Error = ParserError;
438
439 fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
442 match stmt {
443 Statement::CreateTable(CreateTable {
444 or_replace,
445 temporary,
446 external,
447 global,
448 if_not_exists,
449 transient,
450 volatile,
451 iceberg,
452 name,
453 columns,
454 constraints,
455 hive_distribution,
456 hive_formats,
457 file_format,
458 location,
459 query,
460 without_rowid,
461 like,
462 clone,
463 comment,
464 on_commit,
465 on_cluster,
466 primary_key,
467 order_by,
468 partition_by,
469 cluster_by,
470 clustered_by,
471 inherits,
472 strict,
473 copy_grants,
474 enable_schema_evolution,
475 change_tracking,
476 data_retention_time_in_days,
477 max_data_extension_time_in_days,
478 default_ddl_collation,
479 with_aggregation_policy,
480 with_row_access_policy,
481 with_tags,
482 base_location,
483 external_volume,
484 catalog,
485 catalog_sync,
486 storage_serialization_policy,
487 table_options,
488 }) => Ok(Self {
489 or_replace,
490 temporary,
491 external,
492 global,
493 if_not_exists,
494 transient,
495 name,
496 columns,
497 constraints,
498 hive_distribution,
499 hive_formats,
500 file_format,
501 location,
502 query,
503 without_rowid,
504 like,
505 clone,
506 comment,
507 on_commit,
508 on_cluster,
509 primary_key,
510 order_by,
511 partition_by,
512 cluster_by,
513 clustered_by,
514 inherits,
515 strict,
516 iceberg,
517 copy_grants,
518 enable_schema_evolution,
519 change_tracking,
520 data_retention_time_in_days,
521 max_data_extension_time_in_days,
522 default_ddl_collation,
523 with_aggregation_policy,
524 with_row_access_policy,
525 with_tags,
526 volatile,
527 base_location,
528 external_volume,
529 catalog,
530 catalog_sync,
531 storage_serialization_policy,
532 table_options,
533 }),
534 _ => Err(ParserError::ParserError(format!(
535 "Expected create table statement, but received: {stmt}"
536 ))),
537 }
538 }
539}
540
541#[derive(Default)]
543pub(crate) struct CreateTableConfiguration {
544 pub partition_by: Option<Box<Expr>>,
545 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
546 pub inherits: Option<Vec<ObjectName>>,
547 pub table_options: CreateTableOptions,
548}
549
550#[cfg(test)]
551mod tests {
552 use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
553 use crate::ast::{Ident, ObjectName, Statement};
554 use crate::parser::ParserError;
555
556 #[test]
557 pub fn test_from_valid_statement() {
558 let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
559
560 let stmt = builder.clone().build();
561
562 assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
563 }
564
565 #[test]
566 pub fn test_from_invalid_statement() {
567 let stmt = Statement::Commit {
568 chain: false,
569 end: false,
570 modifier: None,
571 };
572
573 assert_eq!(
574 CreateTableBuilder::try_from(stmt).unwrap_err(),
575 ParserError::ParserError(
576 "Expected create table statement, but received: COMMIT".to_owned()
577 )
578 );
579 }
580}