Skip to content

Commit 189708e

Browse files
committed
Added DISTSTYLE and DISTKEY keywords parsing for snowflake
1 parent 40350e3 commit 189708e

10 files changed

Lines changed: 130 additions & 5 deletions

File tree

src/ast/ddl.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3032,6 +3032,12 @@ pub struct CreateTable {
30323032
/// Snowflake "REQUIRE USER" clause for dybamic tables
30333033
/// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
30343034
pub require_user: bool,
3035+
/// Redshift `DISTSTYLE` option
3036+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3037+
pub diststyle: Option<DistStyle>,
3038+
/// Redshift `DISTKEY` option
3039+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3040+
pub distkey: Option<Ident>,
30353041
}
30363042

30373043
impl fmt::Display for CreateTable {
@@ -3330,6 +3336,12 @@ impl fmt::Display for CreateTable {
33303336
if self.strict {
33313337
write!(f, " STRICT")?;
33323338
}
3339+
if let Some(diststyle) = &self.diststyle {
3340+
write!(f, " DISTSTYLE {diststyle}")?;
3341+
}
3342+
if let Some(distkey) = &self.distkey {
3343+
write!(f, " DISTKEY({distkey})")?;
3344+
}
33333345
if let Some(query) = &self.query {
33343346
write!(f, " AS {query}")?;
33353347
}
@@ -3417,6 +3429,34 @@ impl fmt::Display for PartitionBoundValue {
34173429
}
34183430
}
34193431

3432+
/// Redshift distribution style for `CREATE TABLE`.
3433+
///
3434+
/// See [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
3435+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3436+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3437+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3438+
pub enum DistStyle {
3439+
/// `DISTSTYLE AUTO`
3440+
Auto,
3441+
/// `DISTSTYLE EVEN`
3442+
Even,
3443+
/// `DISTSTYLE KEY`
3444+
Key,
3445+
/// `DISTSTYLE ALL`
3446+
All,
3447+
}
3448+
3449+
impl fmt::Display for DistStyle {
3450+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3451+
match self {
3452+
DistStyle::Auto => write!(f, "AUTO"),
3453+
DistStyle::Even => write!(f, "EVEN"),
3454+
DistStyle::Key => write!(f, "KEY"),
3455+
DistStyle::All => write!(f, "ALL"),
3456+
}
3457+
}
3458+
}
3459+
34203460
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
34213461
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34223462
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/ast/helpers/stmt_create_table.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ use serde::{Deserialize, Serialize};
2525
use sqlparser_derive::{Visit, VisitMut};
2626

2727
use crate::ast::{
28-
ClusteredBy, ColumnDef, CommentDef, CreateTable, CreateTableLikeKind, CreateTableOptions, Expr,
29-
FileFormat, ForValues, HiveDistributionStyle, HiveFormat, Ident, InitializeKind, ObjectName,
30-
OnCommit, OneOrManyWithParens, Query, RefreshModeKind, RowAccessPolicy, Statement,
31-
StorageSerializationPolicy, TableConstraint, TableVersion, Tag, WrappedCollection,
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, StorageSerializationPolicy, TableConstraint, TableVersion, Tag,
32+
WrappedCollection,
3233
};
3334

3435
use crate::parser::ParserError;
@@ -170,6 +171,10 @@ pub struct CreateTableBuilder {
170171
pub initialize: Option<InitializeKind>,
171172
/// Whether operations require a user identity.
172173
pub require_user: bool,
174+
/// Redshift `DISTSTYLE` option.
175+
pub diststyle: Option<DistStyle>,
176+
/// Redshift `DISTKEY` option.
177+
pub distkey: Option<Ident>,
173178
}
174179

175180
impl CreateTableBuilder {
@@ -229,6 +234,8 @@ impl CreateTableBuilder {
229234
refresh_mode: None,
230235
initialize: None,
231236
require_user: false,
237+
diststyle: None,
238+
distkey: None,
232239
}
233240
}
234241
/// Set `OR REPLACE` for the CREATE TABLE statement.
@@ -504,6 +511,16 @@ impl CreateTableBuilder {
504511
self.require_user = require_user;
505512
self
506513
}
514+
/// Set Redshift `DISTSTYLE` option.
515+
pub fn diststyle(mut self, diststyle: Option<DistStyle>) -> Self {
516+
self.diststyle = diststyle;
517+
self
518+
}
519+
/// Set Redshift `DISTKEY` option.
520+
pub fn distkey(mut self, distkey: Option<Ident>) -> Self {
521+
self.distkey = distkey;
522+
self
523+
}
507524
/// Consume the builder and produce a `CreateTable`.
508525
pub fn build(self) -> CreateTable {
509526
CreateTable {
@@ -560,6 +577,8 @@ impl CreateTableBuilder {
560577
refresh_mode: self.refresh_mode,
561578
initialize: self.initialize,
562579
require_user: self.require_user,
580+
diststyle: self.diststyle,
581+
distkey: self.distkey,
563582
}
564583
}
565584
}
@@ -635,6 +654,8 @@ impl From<CreateTable> for CreateTableBuilder {
635654
refresh_mode: table.refresh_mode,
636655
initialize: table.initialize,
637656
require_user: table.require_user,
657+
diststyle: table.diststyle,
658+
distkey: table.distkey,
638659
}
639660
}
640661
}

src/ast/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ pub use self::ddl::{
7070
ConstraintCharacteristics, CreateConnector, CreateDomain, CreateExtension, CreateFunction,
7171
CreateIndex, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreatePolicy,
7272
CreatePolicyCommand, CreatePolicyType, CreateTable, CreateTrigger, CreateView, Deduplicate,
73-
DeferrableInitial, DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorClass,
73+
DeferrableInitial, DistStyle, DropBehavior, DropExtension, DropFunction, DropOperator,
74+
DropOperatorClass,
7475
DropOperatorFamily, DropOperatorSignature, DropPolicy, DropTrigger, ForValues, GeneratedAs,
7576
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
7677
IdentityPropertyKind, IdentityPropertyOrder, IndexColumn, IndexOption, IndexType,

src/ast/spans.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@ impl Spanned for CreateTable {
581581
refresh_mode: _,
582582
initialize: _,
583583
require_user: _,
584+
diststyle: _, // enum, no span
585+
distkey: _, // Ident, todo
584586
} = self;
585587

586588
union_spans(

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ define_keywords!(
334334
DISCONNECT,
335335
DISTINCT,
336336
DISTINCTROW,
337+
DISTKEY,
337338
DISTRIBUTE,
339+
DISTSTYLE,
338340
DIV,
339341
DO,
340342
DOMAIN,
@@ -378,6 +380,7 @@ define_keywords!(
378380
ESCAPE,
379381
ESCAPED,
380382
ESTIMATE,
383+
EVEN,
381384
EVENT,
382385
EVERY,
383386
EVOLVE,

src/parser/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8056,6 +8056,23 @@ impl<'a> Parser<'a> {
80568056
}
80578057
}
80588058

8059+
/// Parse Redshift `DISTSTYLE { AUTO | EVEN | KEY | ALL }`.
8060+
///
8061+
/// See <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
8062+
fn parse_dist_style(&mut self) -> Result<DistStyle, ParserError> {
8063+
let token = self.next_token();
8064+
match &token.token {
8065+
Token::Word(w) => match w.keyword {
8066+
Keyword::AUTO => Ok(DistStyle::Auto),
8067+
Keyword::EVEN => Ok(DistStyle::Even),
8068+
Keyword::KEY => Ok(DistStyle::Key),
8069+
Keyword::ALL => Ok(DistStyle::All),
8070+
_ => self.expected("AUTO, EVEN, KEY, or ALL", token),
8071+
},
8072+
_ => self.expected("AUTO, EVEN, KEY, or ALL", token),
8073+
}
8074+
}
8075+
80598076
/// Parse Hive formats.
80608077
pub fn parse_hive_formats(&mut self) -> Result<Option<HiveFormat>, ParserError> {
80618078
let mut hive_format: Option<HiveFormat> = None;
@@ -8326,6 +8343,21 @@ impl<'a> Parser<'a> {
83268343

83278344
let strict = self.parse_keyword(Keyword::STRICT);
83288345

8346+
// Redshift: DISTSTYLE, DISTKEY
8347+
let diststyle = if self.parse_keyword(Keyword::DISTSTYLE) {
8348+
Some(self.parse_dist_style()?)
8349+
} else {
8350+
None
8351+
};
8352+
let distkey = if self.parse_keyword(Keyword::DISTKEY) {
8353+
self.expect_token(&Token::LParen)?;
8354+
let column = self.parse_identifier()?;
8355+
self.expect_token(&Token::RParen)?;
8356+
Some(column)
8357+
} else {
8358+
None
8359+
};
8360+
83298361
// Parse optional `AS ( query )`
83308362
let query = if self.parse_keyword(Keyword::AS) {
83318363
Some(self.parse_query()?)
@@ -8365,6 +8397,8 @@ impl<'a> Parser<'a> {
83658397
.table_options(create_table_config.table_options)
83668398
.primary_key(primary_key)
83678399
.strict(strict)
8400+
.diststyle(diststyle)
8401+
.distkey(distkey)
83688402
.build())
83698403
}
83708404

tests/sqlparser_duckdb.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,8 @@ fn test_duckdb_union_datatype() {
784784
refresh_mode: None,
785785
initialize: None,
786786
require_user: Default::default(),
787+
diststyle: Default::default(),
788+
distkey: Default::default(),
787789
}),
788790
stmt
789791
);

tests/sqlparser_mssql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,8 @@ fn parse_create_table_with_valid_options() {
19691969
refresh_mode: None,
19701970
initialize: None,
19711971
require_user: false,
1972+
diststyle: None,
1973+
distkey: None,
19721974
})
19731975
);
19741976
}
@@ -2137,6 +2139,8 @@ fn parse_create_table_with_identity_column() {
21372139
refresh_mode: None,
21382140
initialize: None,
21392141
require_user: false,
2142+
diststyle: None,
2143+
distkey: None,
21402144
}),
21412145
);
21422146
}

tests/sqlparser_postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6322,6 +6322,8 @@ fn parse_trigger_related_functions() {
63226322
refresh_mode: None,
63236323
initialize: None,
63246324
require_user: false,
6325+
diststyle: None,
6326+
distkey: None,
63256327
}
63266328
);
63276329

tests/sqlparser_redshift.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,19 @@ fn parse_vacuum() {
452452
_ => unreachable!(),
453453
}
454454
}
455+
456+
#[test]
457+
fn test_create_table_diststyle_distkey() {
458+
redshift().verified_stmt(
459+
"CREATE TEMPORARY TABLE tmp_sbk_summary_pp DISTSTYLE KEY DISTKEY(bet_id) AS SELECT 1 AS bet_id",
460+
);
461+
}
462+
463+
#[test]
464+
fn test_create_table_diststyle() {
465+
redshift().verified_stmt("CREATE TABLE t1 (c1 INT) DISTSTYLE AUTO");
466+
redshift().verified_stmt("CREATE TABLE t1 (c1 INT) DISTSTYLE EVEN");
467+
redshift().verified_stmt("CREATE TABLE t1 (c1 INT) DISTSTYLE KEY DISTKEY(c1)");
468+
redshift().verified_stmt("CREATE TABLE t1 (c1 INT) DISTSTYLE ALL");
469+
}
470+

0 commit comments

Comments
 (0)