Skip to content

Commit 62fa860

Browse files
authored
PartiQL queries in Redshift (#1534)
1 parent 1051900 commit 62fa860

17 files changed

+254
-10
lines changed

src/ast/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,8 @@ pub enum TableFactor {
974974
with_ordinality: bool,
975975
/// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL.
976976
partitions: Vec<Ident>,
977+
/// Optional PartiQL JsonPath: <https://partiql.org/dql/from.html>
978+
json_path: Option<JsonPath>,
977979
},
978980
Derived {
979981
lateral: bool,
@@ -1375,8 +1377,12 @@ impl fmt::Display for TableFactor {
13751377
version,
13761378
partitions,
13771379
with_ordinality,
1380+
json_path,
13781381
} => {
13791382
write!(f, "{name}")?;
1383+
if let Some(json_path) = json_path {
1384+
write!(f, "{json_path}")?;
1385+
}
13801386
if !partitions.is_empty() {
13811387
write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
13821388
}

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,12 @@ pub trait Dialect: Debug + Any {
675675
fn supports_create_table_select(&self) -> bool {
676676
false
677677
}
678+
679+
/// Returns true if the dialect supports PartiQL for querying semi-structured data
680+
/// <https://partiql.org/index.html>
681+
fn supports_partiql(&self) -> bool {
682+
false
683+
}
678684
}
679685

680686
/// This represents the operators for which precedence must be defined

src/dialect/redshift.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,9 @@ impl Dialect for RedshiftSqlDialect {
7474
fn supports_top_before_distinct(&self) -> bool {
7575
true
7676
}
77+
78+
/// Redshift supports PartiQL: <https://docs.aws.amazon.com/redshift/latest/dg/super-overview.html>
79+
fn supports_partiql(&self) -> bool {
80+
true
81+
}
7782
}

src/parser/mod.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,7 +2936,7 @@ impl<'a> Parser<'a> {
29362936
} else if Token::LBracket == tok {
29372937
if dialect_of!(self is PostgreSqlDialect | DuckDbDialect | GenericDialect) {
29382938
self.parse_subscript(expr)
2939-
} else if dialect_of!(self is SnowflakeDialect) {
2939+
} else if dialect_of!(self is SnowflakeDialect) || self.dialect.supports_partiql() {
29402940
self.prev_token();
29412941
self.parse_json_access(expr)
29422942
} else {
@@ -3072,6 +3072,14 @@ impl<'a> Parser<'a> {
30723072
}
30733073

30743074
fn parse_json_access(&mut self, expr: Expr) -> Result<Expr, ParserError> {
3075+
let path = self.parse_json_path()?;
3076+
Ok(Expr::JsonAccess {
3077+
value: Box::new(expr),
3078+
path,
3079+
})
3080+
}
3081+
3082+
fn parse_json_path(&mut self) -> Result<JsonPath, ParserError> {
30753083
let mut path = Vec::new();
30763084
loop {
30773085
match self.next_token().token {
@@ -3095,10 +3103,7 @@ impl<'a> Parser<'a> {
30953103
}
30963104

30973105
debug_assert!(!path.is_empty());
3098-
Ok(Expr::JsonAccess {
3099-
value: Box::new(expr),
3100-
path: JsonPath { path },
3101-
})
3106+
Ok(JsonPath { path })
31023107
}
31033108

31043109
pub fn parse_map_access(&mut self, expr: Expr) -> Result<Expr, ParserError> {
@@ -10338,6 +10343,11 @@ impl<'a> Parser<'a> {
1033810343
} else {
1033910344
let name = self.parse_object_name(true)?;
1034010345

10346+
let json_path = match self.peek_token().token {
10347+
Token::LBracket if self.dialect.supports_partiql() => Some(self.parse_json_path()?),
10348+
_ => None,
10349+
};
10350+
1034110351
let partitions: Vec<Ident> = if dialect_of!(self is MySqlDialect | GenericDialect)
1034210352
&& self.parse_keyword(Keyword::PARTITION)
1034310353
{
@@ -10380,6 +10390,7 @@ impl<'a> Parser<'a> {
1038010390
version,
1038110391
partitions,
1038210392
with_ordinality,
10393+
json_path,
1038310394
};
1038410395

1038510396
while let Some(kw) = self.parse_one_of_keywords(&[Keyword::PIVOT, Keyword::UNPIVOT]) {

src/test_utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ pub fn table(name: impl Into<String>) -> TableFactor {
345345
version: None,
346346
partitions: vec![],
347347
with_ordinality: false,
348+
json_path: None,
348349
}
349350
}
350351

@@ -360,6 +361,7 @@ pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> Ta
360361
version: None,
361362
partitions: vec![],
362363
with_ordinality: false,
364+
json_path: None,
363365
}
364366
}
365367

tests/sqlparser_bigquery.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ fn parse_delete_statement() {
229229
version: None,
230230
partitions: vec![],
231231
with_ordinality: false,
232+
json_path: None,
232233
},
233234
from[0].relation
234235
);
@@ -1373,6 +1374,7 @@ fn parse_table_identifiers() {
13731374
version: None,
13741375
partitions: vec![],
13751376
with_ordinality: false,
1377+
json_path: None,
13761378
},
13771379
joins: vec![]
13781380
},]
@@ -1546,6 +1548,7 @@ fn parse_table_time_travel() {
15461548
))),
15471549
partitions: vec![],
15481550
with_ordinality: false,
1551+
json_path: None,
15491552
},
15501553
joins: vec![]
15511554
},]
@@ -1644,6 +1647,7 @@ fn parse_merge() {
16441647
version: Default::default(),
16451648
partitions: Default::default(),
16461649
with_ordinality: false,
1650+
json_path: None,
16471651
},
16481652
table
16491653
);
@@ -1659,6 +1663,7 @@ fn parse_merge() {
16591663
version: Default::default(),
16601664
partitions: Default::default(),
16611665
with_ordinality: false,
1666+
json_path: None,
16621667
},
16631668
source
16641669
);

tests/sqlparser_clickhouse.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ fn parse_map_access_expr() {
6767
version: None,
6868
partitions: vec![],
6969
with_ordinality: false,
70+
json_path: None,
7071
},
7172
joins: vec![],
7273
}],
@@ -172,6 +173,7 @@ fn parse_delimited_identifiers() {
172173
version,
173174
with_ordinality: _,
174175
partitions: _,
176+
json_path: _,
175177
} => {
176178
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
177179
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);

0 commit comments

Comments
 (0)