Skip to content

Commit e71fa13

Browse files
authored
parse primitives and bugfix on SFW query (#149)
1 parent f57ee41 commit e71fa13

File tree

4 files changed

+61
-26
lines changed

4 files changed

+61
-26
lines changed

partiql-ast/src/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub enum ItemKind {
103103
Ddl(Ddl),
104104
// Data Modification Language statements
105105
Dml(Dml),
106-
// Date retrieval statements
106+
// Data retrieval statements
107107
Query(Query),
108108
}
109109

@@ -245,7 +245,7 @@ pub type LikeAst = AstBytePos<Like>;
245245
pub type ListAst = AstBytePos<List>;
246246
pub type LitAst = AstBytePos<Lit>;
247247
pub type OrderByExprAst = AstBytePos<OrderByExpr>;
248-
pub type ParamAst = AstBytePos<VarRef>;
248+
pub type ParamAst = AstBytePos<Param>;
249249
pub type PathAst = AstBytePos<Path>;
250250
pub type ProjectItemAst = AstBytePos<ProjectItem>;
251251
pub type ProjectionAst = AstBytePos<Projection>;
Submodule partiql-tests updated 32 files

partiql-parser/src/lexer.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ pub enum Token<'input> {
457457
Plus,
458458
#[token("*")]
459459
Star,
460+
#[token("?")]
461+
SqlParameter,
460462
#[token("%")]
461463
Percent,
462464
#[token("/")]
@@ -499,8 +501,8 @@ pub enum Token<'input> {
499501
Real(&'input str),
500502

501503
// strings are single-quoted in SQL/PartiQL
502-
#[regex(r#"'([^'\\]|\\t|\\u|\\n|\\'|(?:''))*'"#,
503-
|lex| lex.slice().trim_matches('\''))]
504+
#[regex(r#"'([^'\\]|\\t|\\u|\\n|\\'|\\|(?:''))*'"#,
505+
|lex| lex.slice().trim_matches('\''))]
504506
String(&'input str),
505507

506508
#[token("`")]
@@ -526,6 +528,8 @@ pub enum Token<'input> {
526528
Case,
527529
#[regex("(?i:Cross)")]
528530
Cross,
531+
#[regex("(?i:Date)")]
532+
Date,
529533
#[regex("(?i:Desc)")]
530534
Desc,
531535
#[regex("(?i:Distinct)")]
@@ -602,6 +606,10 @@ pub enum Token<'input> {
602606
Right,
603607
#[regex("(?i:Select)")]
604608
Select,
609+
#[regex("(?i:Time)")]
610+
Time,
611+
#[regex("(?i:Timestamp)")]
612+
Timestamp,
605613
#[regex("(?i:Then)")]
606614
Then,
607615
#[regex("(?i:True)")]
@@ -636,6 +644,7 @@ impl<'input> Token<'input> {
636644
| Token::Between
637645
| Token::By
638646
| Token::Cross
647+
| Token::Date
639648
| Token::Desc
640649
| Token::Distinct
641650
| Token::Escape
@@ -671,6 +680,8 @@ impl<'input> Token<'input> {
671680
| Token::Preserve
672681
| Token::Right
673682
| Token::Select
683+
| Token::Time
684+
| Token::Timestamp
674685
| Token::Then
675686
| Token::Union
676687
| Token::Unpivot
@@ -713,6 +724,7 @@ impl<'input> fmt::Display for Token<'input> {
713724
Token::Minus => write!(f, "-"),
714725
Token::Plus => write!(f, "+"),
715726
Token::Star => write!(f, "*"),
727+
Token::SqlParameter => write!(f, "?"),
716728
Token::Percent => write!(f, "%"),
717729
Token::Slash => write!(f, "/"),
718730
Token::Caret => write!(f, "^"),
@@ -738,6 +750,7 @@ impl<'input> fmt::Display for Token<'input> {
738750
| Token::By
739751
| Token::Case
740752
| Token::Cross
753+
| Token::Date
741754
| Token::Desc
742755
| Token::Distinct
743756
| Token::Else
@@ -776,6 +789,8 @@ impl<'input> fmt::Display for Token<'input> {
776789
| Token::Preserve
777790
| Token::Right
778791
| Token::Select
792+
| Token::Time
793+
| Token::Timestamp
779794
| Token::Then
780795
| Token::True
781796
| Token::Union
@@ -805,13 +820,13 @@ mod tests {
805820
#[test]
806821
fn display() -> Result<(), ParseError<'static, BytePosition>> {
807822
let symbols =
808-
"( [ { } ] ) << >> ; , < > <= >= != <> = == - + * % / ^ . || : --foo /*block*/";
823+
"( [ { } ] ) << >> ; , < > <= >= != <> = == - + * ? % / ^ . || : --foo /*block*/";
809824
let primitives = r#"unquoted_ident "quoted_ident" @unquoted_atident @"quoted_atident""#;
810825
let keywords =
811826
"WiTH Where Value uSiNg Unpivot UNION True Select right Preserve pivoT Outer Order Or \
812827
On Offset Nulls Null Not Natural Missing Limit Like Left Lateral Last Join \
813828
Intersect Is Inner In Having Group From For Full First False Except Escape Desc \
814-
Cross By Between At As And Asc All Values Case When Then Else End";
829+
Cross Time Timestamp Date By Between At As And Asc All Values Case When Then Else End";
815830
let symbols = symbols.split(' ').chain(primitives.split(' '));
816831
let keywords = keywords.split(' ');
817832

@@ -824,16 +839,16 @@ mod tests {
824839

825840
#[rustfmt::skip]
826841
let expected = vec![
827-
"(", "WITH", "[", "WHERE", "{", "VALUE", "}", "USING", "]", "UNPIVOT",
828-
")", "UNION", "<<", "TRUE", ">>", "SELECT", ";", "RIGHT", ",", "PRESERVE", "<",
829-
"PIVOT", ">", "OUTER", "<=", "ORDER", ">=", "OR", "!=", "ON", "<>", "OFFSET",
830-
"=", "NULLS", "==", "NULL", "-", "NOT", "+", "NATURAL", "*", "MISSING", "%",
831-
"LIMIT", "/", "LIKE", "^", "LEFT", ".", "LATERAL", "||", "LAST", ":", "JOIN",
832-
"--", "INTERSECT", "/**/","IS", "<unquoted_ident:UNQUOTED_IDENT>", "INNER",
833-
"<quoted_ident:QUOTED_IDENT>", "IN", "<unquoted_atident:UNQUOTED_ATIDENT>", "HAVING",
834-
"<quoted_atident:QUOTED_ATIDENT>", "GROUP", "FROM", "FOR", "FULL", "FIRST", "FALSE", "EXCEPT",
835-
"ESCAPE", "DESC", "CROSS", "BY", "BETWEEN", "AT", "AS", "AND", "ASC", "ALL", "VALUES",
836-
"CASE", "WHEN", "THEN", "ELSE", "END",
842+
"(", "WITH", "[", "WHERE", "{", "VALUE", "}", "USING", "]", "UNPIVOT", ")", "UNION",
843+
"<<", "TRUE", ">>", "SELECT", ";", "RIGHT", ",", "PRESERVE", "<", "PIVOT", ">", "OUTER",
844+
"<=", "ORDER", ">=", "OR", "!=", "ON", "<>", "OFFSET", "=", "NULLS", "==", "NULL", "-",
845+
"NOT", "+", "NATURAL", "*", "MISSING", "?", "LIMIT", "%", "LIKE", "/", "LEFT", "^",
846+
"LATERAL", ".", "LAST", "||", "JOIN", ":", "INTERSECT", "--", "IS", "/**/", "INNER",
847+
"<unquoted_ident:UNQUOTED_IDENT>", "IN", "<quoted_ident:QUOTED_IDENT>", "HAVING",
848+
"<unquoted_atident:UNQUOTED_ATIDENT>", "GROUP", "<quoted_atident:QUOTED_ATIDENT>",
849+
"FROM", "FOR", "FULL", "FIRST", "FALSE", "EXCEPT", "ESCAPE", "DESC", "CROSS", "TIME",
850+
"TIMESTAMP", "DATE", "BY", "BETWEEN", "AT", "AS", "AND", "ASC", "ALL", "VALUES", "CASE",
851+
"WHEN", "THEN", "ELSE", "END"
837852
];
838853
let displayed = toks
839854
.into_iter()

partiql-parser/src/parse/partiql.lalrpop

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Values: ast::QuerySetAst = {
100100

101101
#[inline]
102102
ValueRow: Box<ast::Expr> = {
103+
"(" <e:ExprQuery> ")" => Box::new(*e),
103104
<array:ExprTermCollection> => Box::new(array)
104105
}
105106

@@ -283,12 +284,16 @@ TableJoined: ast::FromClauseAst = {
283284

284285
#[inline]
285286
TableCrossJoin: ast::FromClauseAst = {
286-
// Note the `TableReference` on the lhs and the `TableNonJoin` on the rhs of the `JOIN`.
287+
// Note the `TableReference` on the lhs and the `JoinRhs` on the rhs of the `JOIN`.
287288
// This is to prevent ambiguity in the grammar and effectively treats `JOIN` like
288289
// a left-associative operator
289-
<lo:@L> <ltable:TableReference> "CROSS" "JOIN" <rtable:TableNonJoin> <hi:@R> => {
290+
<lo:@L> <ltable:TableReference> <j:JoinType?> "CROSS" "JOIN" <rtable:JoinRhs> <hi:@R> => {
291+
let kind = match j {
292+
Some(j) => j,
293+
None => ast::JoinKind::Cross
294+
};
290295
let join = ast::Join {
291-
kind: ast::JoinKind::Cross,
296+
kind,
292297
left: Box::new(ltable),
293298
right: Box::new(rtable),
294299
predicate: None
@@ -299,10 +304,10 @@ TableCrossJoin: ast::FromClauseAst = {
299304

300305
#[inline]
301306
TableQualifiedJoin: ast::FromClauseAst = {
302-
// Note the `TableReference` on the lhs and the `TableNonJoin` on the rhs of the `JOIN`.
307+
// Note the `TableReference` on the lhs and the `JoinRhs` on the rhs of the `JOIN`.
303308
// This is to prevent ambiguity in the grammar and effectively treats `JOIN` like
304309
// a left-associative operator
305-
<lo:@L> <ltable:TableReference> <j:JoinType> "JOIN" "LATERAL"? <rtable:TableNonJoin> <on:JoinSpec> <hi:@R> => {
310+
<lo:@L> <ltable:TableReference> <j:JoinType> "JOIN" "LATERAL"? <rtable:JoinRhs> <on:JoinSpec> <hi:@R> => {
306311
let join = ast::Join {
307312
kind: j,
308313
left: Box::new(ltable),
@@ -311,18 +316,23 @@ TableQualifiedJoin: ast::FromClauseAst = {
311316
};
312317
ast::FromClause::Join( join.ast(lo..hi) ).ast(lo..hi)
313318
},
314-
// Note the `TableReference` on the lhs and the `TableNonJoin` on the rhs of the `JOIN`.
319+
// Note the `TableReference` on the lhs and the `JoinRhs` on the rhs of the `JOIN`.
315320
// This is to prevent ambiguity in the grammar and effectively treats `JOIN` like
316321
// a left-associative operator
317-
<lo:@L> <ltable:TableReference> <spec:JoinSpecNatural> <j:JoinType> "JOIN" "LATERAL"? <rtable:TableNonJoin> <hi:@R> => {
322+
<lo:@L> <ltable:TableReference> <spec:JoinSpecNatural> <j:JoinType> "JOIN" "LATERAL"? <rtable:JoinRhs> <hi:@R> => {
318323
let join = ast::Join {
319324
kind: j,
320325
left: Box::new(ltable),
321326
right: Box::new(rtable),
322327
predicate: Some(spec)
323328
};
324329
ast::FromClause::Join( join.ast(lo..hi) ).ast(lo..hi)
325-
}
330+
},
331+
}
332+
#[inline]
333+
JoinRhs: ast::FromClauseAst = {
334+
<TableNonJoin>,
335+
"(" <TableJoined> ")"
326336
}
327337
#[inline]
328338
JoinSpecNatural: ast::JoinSpecAst = {
@@ -334,6 +344,7 @@ JoinType: ast::JoinKind = {
334344
"LEFT" "OUTER"? => ast::JoinKind::Left,
335345
"RIGHT" "OUTER"? => ast::JoinKind::Right,
336346
"FULL" "OUTER"? => ast::JoinKind::Full,
347+
"OUTER" => ast::JoinKind::Full,
337348
}
338349
#[inline]
339350
JoinSpec: ast::JoinSpecAst = {
@@ -1037,7 +1048,7 @@ Literal: ast::Lit = {
10371048
<LiteralAbsent>,
10381049
<LiteralScalar>,
10391050
<LiteralIon>,
1040-
// TODO other literals?
1051+
<LiteralDateTime>,
10411052
};
10421053

10431054
#[inline]
@@ -1093,6 +1104,12 @@ LiteralNumber: ast::Lit = {
10931104
LiteralIon: ast::Lit = {
10941105
<ion:"Ion"> => ast::Lit::IonStringLit(ion.to_owned()),
10951106
}
1107+
#[inline]
1108+
LiteralDateTime: ast::Lit = {
1109+
"DATE" <s:"String"> => ast::Lit::DateTimeLit(ast::DateTimeLit::DateLit(s.to_owned())),
1110+
"TIME" <s:"String"> => ast::Lit::DateTimeLit(ast::DateTimeLit::TimeLit(s.to_owned())),
1111+
"TIMESTAMP" <s:"String"> => ast::Lit::DateTimeLit(ast::DateTimeLit::TimestampLit(s.to_owned())),
1112+
}
10961113

10971114
// ------------------------------------------------------------------------------ //
10981115
// //
@@ -1238,6 +1255,7 @@ extern {
12381255
"BY" => lexer::Token::By,
12391256
"CASE" => lexer::Token::Case,
12401257
"CROSS" => lexer::Token::Cross,
1258+
"DATE" => lexer::Token::Date,
12411259
"DESC" => lexer::Token::Desc,
12421260
"DISTINCT" => lexer::Token::Distinct,
12431261
"ELSE" => lexer::Token::Else,
@@ -1276,6 +1294,8 @@ extern {
12761294
"PRESERVE" => lexer::Token::Preserve,
12771295
"RIGHT" => lexer::Token::Right,
12781296
"SELECT" => lexer::Token::Select,
1297+
"TIME" => lexer::Token::Time,
1298+
"TIMESTAMP" => lexer::Token::Timestamp,
12791299
"THEN" => lexer::Token::Then,
12801300
"TRUE" => lexer::Token::True,
12811301
"UNION" => lexer::Token::Union,

0 commit comments

Comments
 (0)