Skip to content

Commit 1da2ff7

Browse files
authored
Redshift: Added DISTSTYLE and DISTKEY keywords parsing (#2222)
1 parent 31e1942 commit 1da2ff7

File tree

10 files changed

+138
-14
lines changed

10 files changed

+138
-14
lines changed

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: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,17 @@ 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,
74-
DropOperatorFamily, DropOperatorSignature, DropPolicy, DropTrigger, ForValues, GeneratedAs,
75-
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
76-
IdentityPropertyKind, IdentityPropertyOrder, IndexColumn, IndexOption, IndexType,
77-
KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes, OperatorClassItem,
78-
OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorPurpose, Owner, Partition,
79-
PartitionBoundValue, ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity,
80-
TagsColumnOption, TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
81-
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
82-
UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef,
73+
DeferrableInitial, DistStyle, DropBehavior, DropExtension, DropFunction, DropOperator,
74+
DropOperatorClass, DropOperatorFamily, DropOperatorSignature, DropPolicy, DropTrigger,
75+
ForValues, GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
76+
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
77+
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,
78+
OperatorClassItem, OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorPurpose,
79+
Owner, Partition, PartitionBoundValue, ProcedureParam, ReferentialAction, RenameTableNameKind,
80+
ReplicaIdentity, TagsColumnOption, TriggerObjectKind, Truncate,
81+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength,
82+
UserDefinedTypeRangeOption, UserDefinedTypeRepresentation, UserDefinedTypeSqlDefinitionOption,
83+
UserDefinedTypeStorage, ViewColumnDef,
8384
};
8485
pub use self::dml::{
8586
Delete, Insert, Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr,

src/ast/spans.rs

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

587589
union_spans(

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,9 @@ define_keywords!(
335335
DISCONNECT,
336336
DISTINCT,
337337
DISTINCTROW,
338+
DISTKEY,
338339
DISTRIBUTE,
340+
DISTSTYLE,
339341
DIV,
340342
DO,
341343
DOMAIN,
@@ -379,6 +381,7 @@ define_keywords!(
379381
ESCAPE,
380382
ESCAPED,
381383
ESTIMATE,
384+
EVEN,
382385
EVENT,
383386
EVERY,
384387
EVOLVE,

src/parser/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8097,6 +8097,23 @@ impl<'a> Parser<'a> {
80978097
}
80988098
}
80998099

8100+
/// Parse Redshift `DISTSTYLE { AUTO | EVEN | KEY | ALL }`.
8101+
///
8102+
/// See <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
8103+
fn parse_dist_style(&mut self) -> Result<DistStyle, ParserError> {
8104+
let token = self.next_token();
8105+
match &token.token {
8106+
Token::Word(w) => match w.keyword {
8107+
Keyword::AUTO => Ok(DistStyle::Auto),
8108+
Keyword::EVEN => Ok(DistStyle::Even),
8109+
Keyword::KEY => Ok(DistStyle::Key),
8110+
Keyword::ALL => Ok(DistStyle::All),
8111+
_ => self.expected("AUTO, EVEN, KEY, or ALL", token),
8112+
},
8113+
_ => self.expected("AUTO, EVEN, KEY, or ALL", token),
8114+
}
8115+
}
8116+
81008117
/// Parse Hive formats.
81018118
pub fn parse_hive_formats(&mut self) -> Result<Option<HiveFormat>, ParserError> {
81028119
let mut hive_format: Option<HiveFormat> = None;
@@ -8367,6 +8384,21 @@ impl<'a> Parser<'a> {
83678384

83688385
let strict = self.parse_keyword(Keyword::STRICT);
83698386

8387+
// Redshift: DISTSTYLE, DISTKEY
8388+
let diststyle = if self.parse_keyword(Keyword::DISTSTYLE) {
8389+
Some(self.parse_dist_style()?)
8390+
} else {
8391+
None
8392+
};
8393+
let distkey = if self.parse_keyword(Keyword::DISTKEY) {
8394+
self.expect_token(&Token::LParen)?;
8395+
let column = self.parse_identifier()?;
8396+
self.expect_token(&Token::RParen)?;
8397+
Some(column)
8398+
} else {
8399+
None
8400+
};
8401+
83708402
// Parse optional `AS ( query )`
83718403
let query = if self.parse_keyword(Keyword::AS) {
83728404
Some(self.parse_query()?)
@@ -8406,6 +8438,8 @@ impl<'a> Parser<'a> {
84068438
.table_options(create_table_config.table_options)
84078439
.primary_key(primary_key)
84088440
.strict(strict)
8441+
.diststyle(diststyle)
8442+
.distkey(distkey)
84098443
.build())
84108444
}
84118445

tests/sqlparser_duckdb.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,8 @@ fn test_duckdb_union_datatype() {
788788
refresh_mode: None,
789789
initialize: None,
790790
require_user: Default::default(),
791+
diststyle: Default::default(),
792+
distkey: Default::default(),
791793
}),
792794
stmt
793795
);

tests/sqlparser_mssql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,8 @@ fn parse_create_table_with_valid_options() {
20062006
refresh_mode: None,
20072007
initialize: None,
20082008
require_user: false,
2009+
diststyle: None,
2010+
distkey: None,
20092011
})
20102012
);
20112013
}
@@ -2174,6 +2176,8 @@ fn parse_create_table_with_identity_column() {
21742176
refresh_mode: None,
21752177
initialize: None,
21762178
require_user: false,
2179+
diststyle: None,
2180+
distkey: None,
21772181
}),
21782182
);
21792183
}

tests/sqlparser_postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6418,6 +6418,8 @@ fn parse_trigger_related_functions() {
64186418
refresh_mode: None,
64196419
initialize: None,
64206420
require_user: false,
6421+
diststyle: None,
6422+
distkey: None,
64216423
}
64226424
);
64236425

tests/sqlparser_redshift.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,18 @@ 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+
}

0 commit comments

Comments
 (0)