Skip to content

Commit bdc7d34

Browse files
committed
Add support for Create Iceberg Table statement for Snowflake parser (apache#1664)
1 parent 548050a commit bdc7d34

File tree

8 files changed

+295
-316
lines changed

8 files changed

+295
-316
lines changed

src/ast/dml.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use super::{
3636
CommentDef, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat,
3737
HiveRowFormat, Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert,
3838
OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, Setting, SqlOption,
39-
SqliteOnConflict, TableEngine, TableObject, TableWithJoins, Tag, WrappedCollection,
39+
SqliteOnConflict, StorageSerializationPolicy, TableEngine, TableObject, TableWithJoins, Tag,
40+
WrappedCollection,
4041
};
4142

4243
/// CREATE INDEX statement.
@@ -117,6 +118,7 @@ pub struct CreateTable {
117118
pub if_not_exists: bool,
118119
pub transient: bool,
119120
pub volatile: bool,
121+
pub iceberg: bool,
120122
/// Table name
121123
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
122124
pub name: ObjectName,
@@ -192,6 +194,21 @@ pub struct CreateTable {
192194
/// Snowflake "WITH TAG" clause
193195
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
194196
pub with_tags: Option<Vec<Tag>>,
197+
/// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
198+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
199+
pub external_volume: Option<String>,
200+
/// Snowflake "BASE_LOCATION" clause for Iceberg tables
201+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
202+
pub base_location: Option<String>,
203+
/// Snowflake "CATALOG" clause for Iceberg tables
204+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
205+
pub catalog: Option<String>,
206+
/// Snowflake "CATALOG_SYNC" clause for Iceberg tables
207+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
208+
pub catalog_sync: Option<String>,
209+
/// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
210+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
211+
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
195212
}
196213

197214
impl Display for CreateTable {
@@ -205,7 +222,7 @@ impl Display for CreateTable {
205222
// `CREATE TABLE t (a INT) AS SELECT a from t2`
206223
write!(
207224
f,
208-
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}TABLE {if_not_exists}{name}",
225+
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{iceberg}TABLE {if_not_exists}{name}",
209226
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
210227
external = if self.external { "EXTERNAL " } else { "" },
211228
global = self.global
@@ -221,6 +238,8 @@ impl Display for CreateTable {
221238
temporary = if self.temporary { "TEMPORARY " } else { "" },
222239
transient = if self.transient { "TRANSIENT " } else { "" },
223240
volatile = if self.volatile { "VOLATILE " } else { "" },
241+
// Only for Snowflake
242+
iceberg = if self.iceberg { "ICEBERG " } else { "" },
224243
name = self.name,
225244
)?;
226245
if let Some(on_cluster) = &self.on_cluster {
@@ -382,6 +401,31 @@ impl Display for CreateTable {
382401
)?;
383402
}
384403

404+
if let Some(external_volume) = self.external_volume.as_ref() {
405+
write!(f, " EXTERNAL_VOLUME = '{external_volume}'")?;
406+
}
407+
408+
if let Some(catalog) = self.catalog.as_ref() {
409+
write!(f, " CATALOG = '{catalog}'")?;
410+
}
411+
412+
if self.iceberg {
413+
if let Some(base_location) = self.base_location.as_ref() {
414+
write!(f, " BASE_LOCATION = '{base_location}'")?;
415+
}
416+
}
417+
418+
if let Some(catalog_sync) = self.catalog_sync.as_ref() {
419+
write!(f, " CATALOG_SYNC = '{catalog_sync}'")?;
420+
}
421+
422+
if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
423+
write!(
424+
f,
425+
" STORAGE_SERIALIZATION_POLICY = {storage_serialization_policy}"
426+
)?;
427+
}
428+
385429
if self.copy_grants {
386430
write!(f, " COPY GRANTS")?;
387431
}

src/ast/helpers/stmt_create_table.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use super::super::dml::CreateTable;
2828
use crate::ast::{
2929
ClusteredBy, ColumnDef, CommentDef, Expr, FileFormat, HiveDistributionStyle, HiveFormat, Ident,
3030
ObjectName, OnCommit, OneOrManyWithParens, Query, RowAccessPolicy, SqlOption, Statement,
31-
TableConstraint, TableEngine, Tag, WrappedCollection,
31+
StorageSerializationPolicy, TableConstraint, TableEngine, Tag, WrappedCollection,
3232
};
3333
use crate::parser::ParserError;
3434

@@ -71,6 +71,7 @@ pub struct CreateTableBuilder {
7171
pub if_not_exists: bool,
7272
pub transient: bool,
7373
pub volatile: bool,
74+
pub iceberg: bool,
7475
pub name: ObjectName,
7576
pub columns: Vec<ColumnDef>,
7677
pub constraints: Vec<TableConstraint>,
@@ -107,6 +108,11 @@ pub struct CreateTableBuilder {
107108
pub with_aggregation_policy: Option<ObjectName>,
108109
pub with_row_access_policy: Option<RowAccessPolicy>,
109110
pub with_tags: Option<Vec<Tag>>,
111+
pub base_location: Option<String>,
112+
pub external_volume: Option<String>,
113+
pub catalog: Option<String>,
114+
pub catalog_sync: Option<String>,
115+
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
110116
}
111117

112118
impl CreateTableBuilder {
@@ -119,6 +125,7 @@ impl CreateTableBuilder {
119125
if_not_exists: false,
120126
transient: false,
121127
volatile: false,
128+
iceberg: false,
122129
name,
123130
columns: vec![],
124131
constraints: vec![],
@@ -155,6 +162,11 @@ impl CreateTableBuilder {
155162
with_aggregation_policy: None,
156163
with_row_access_policy: None,
157164
with_tags: None,
165+
base_location: None,
166+
external_volume: None,
167+
catalog: None,
168+
catalog_sync: None,
169+
storage_serialization_policy: None,
158170
}
159171
}
160172
pub fn or_replace(mut self, or_replace: bool) -> Self {
@@ -192,6 +204,11 @@ impl CreateTableBuilder {
192204
self
193205
}
194206

207+
pub fn iceberg(mut self, iceberg: bool) -> Self {
208+
self.iceberg = iceberg;
209+
self
210+
}
211+
195212
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
196213
self.columns = columns;
197214
self
@@ -371,6 +388,34 @@ impl CreateTableBuilder {
371388
self
372389
}
373390

391+
pub fn base_location(mut self, base_location: Option<String>) -> Self {
392+
self.base_location = base_location;
393+
self
394+
}
395+
396+
pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
397+
self.external_volume = external_volume;
398+
self
399+
}
400+
401+
pub fn catalog(mut self, catalog: Option<String>) -> Self {
402+
self.catalog = catalog;
403+
self
404+
}
405+
406+
pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
407+
self.catalog_sync = catalog_sync;
408+
self
409+
}
410+
411+
pub fn storage_serialization_policy(
412+
mut self,
413+
storage_serialization_policy: Option<StorageSerializationPolicy>,
414+
) -> Self {
415+
self.storage_serialization_policy = storage_serialization_policy;
416+
self
417+
}
418+
374419
pub fn build(self) -> Statement {
375420
Statement::CreateTable(CreateTable {
376421
or_replace: self.or_replace,
@@ -380,6 +425,7 @@ impl CreateTableBuilder {
380425
if_not_exists: self.if_not_exists,
381426
transient: self.transient,
382427
volatile: self.volatile,
428+
iceberg: self.iceberg,
383429
name: self.name,
384430
columns: self.columns,
385431
constraints: self.constraints,
@@ -416,6 +462,11 @@ impl CreateTableBuilder {
416462
with_aggregation_policy: self.with_aggregation_policy,
417463
with_row_access_policy: self.with_row_access_policy,
418464
with_tags: self.with_tags,
465+
base_location: self.base_location,
466+
external_volume: self.external_volume,
467+
catalog: self.catalog,
468+
catalog_sync: self.catalog_sync,
469+
storage_serialization_policy: self.storage_serialization_policy,
419470
})
420471
}
421472
}
@@ -435,6 +486,7 @@ impl TryFrom<Statement> for CreateTableBuilder {
435486
if_not_exists,
436487
transient,
437488
volatile,
489+
iceberg,
438490
name,
439491
columns,
440492
constraints,
@@ -471,6 +523,11 @@ impl TryFrom<Statement> for CreateTableBuilder {
471523
with_aggregation_policy,
472524
with_row_access_policy,
473525
with_tags,
526+
base_location,
527+
external_volume,
528+
catalog,
529+
catalog_sync,
530+
storage_serialization_policy,
474531
}) => Ok(Self {
475532
or_replace,
476533
temporary,
@@ -505,6 +562,7 @@ impl TryFrom<Statement> for CreateTableBuilder {
505562
clustered_by,
506563
options,
507564
strict,
565+
iceberg,
508566
copy_grants,
509567
enable_schema_evolution,
510568
change_tracking,
@@ -515,6 +573,11 @@ impl TryFrom<Statement> for CreateTableBuilder {
515573
with_row_access_policy,
516574
with_tags,
517575
volatile,
576+
base_location,
577+
external_volume,
578+
catalog,
579+
catalog_sync,
580+
storage_serialization_policy,
518581
}),
519582
_ => Err(ParserError::ParserError(format!(
520583
"Expected create table statement, but received: {stmt}"

src/ast/spans.rs

+6
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ impl Spanned for CreateTable {
559559
if_not_exists: _, // bool
560560
transient: _, // bool
561561
volatile: _, // bool
562+
iceberg: _, // bool, Snowflake specific
562563
name,
563564
columns,
564565
constraints,
@@ -595,6 +596,11 @@ impl Spanned for CreateTable {
595596
with_aggregation_policy: _, // todo, Snowflake specific
596597
with_row_access_policy: _, // todo, Snowflake specific
597598
with_tags: _, // todo, Snowflake specific
599+
external_volume: _, // todo, Snowflake specific
600+
base_location: _, // todo, Snowflake specific
601+
catalog: _, // todo, Snowflake specific
602+
catalog_sync: _, // todo, Snowflake specific
603+
storage_serialization_policy: _, // todo, Snowflake specific
598604
} = self;
599605

600606
union_spans(

0 commit comments

Comments
 (0)