-
Notifications
You must be signed in to change notification settings - Fork 543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fallback to identifier parsing if expression parsing fails #1513
base: main
Are you sure you want to change the base?
Conversation
787e396
to
d39af8d
Compare
77243eb
to
6685cce
Compare
src/parser/mod.rs
Outdated
} | ||
} | ||
|
||
fn parse_ident_expr(&mut self, w: &Word) -> Result<Expr, ParserError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm thinking we would need to rename the function, it seems to be doing more than identifiers (and based on the name its unclear what the word w
input argument is for)
6685cce
to
a2d92a4
Compare
src/parser/mod.rs
Outdated
Ok(Some(expr)) => Ok(expr), | ||
// This word indicated an expression prefix but parsing failed. Two options: | ||
// 1. Malformed statement | ||
// 2. The dialect may allow this word as identifier as well as indicating an expression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comments are indeed helpful to follow thanks! Thinking here we could clarify 2. even further with the SELECT MAX(interval) from tbl
example?
a2d92a4
to
1c5c90a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look good to me overall! Left some minor comments then one regarding tests to demonstrate the new behavior
src/parser/mod.rs
Outdated
Ok(None) => Ok(self.parse_expr_prefix_by_unnreserved_word(&w)?), | ||
|
||
// If parsing of the word as a special expression failed, we are facing two options: | ||
// 1. The statement is malformed, e.g. `SELECT INTERVAL '1 DAI` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 1. The statement is malformed, e.g. `SELECT INTERVAL '1 DAI` | |
// 1. The statement is malformed, e.g. `SELECT INTERVAL '1 DAY` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is intentional, DAI is what makes this statement malformed :-)
src/parser/mod.rs
Outdated
/// Parse an expression prefix. | ||
pub fn parse_prefix2(&mut self) -> Result<Expr, ParserError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this version seems unused we can remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shit... Yes, on it.
src/parser/mod.rs
Outdated
} | ||
|
||
// Tries to parse an expression by a word that is not known to have a special meaning in the dialect. | ||
fn parse_expr_prefix_by_unnreserved_word(&mut self, w: &Word) -> Result<Expr, ParserError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn parse_expr_prefix_by_unnreserved_word(&mut self, w: &Word) -> Result<Expr, ParserError> { | |
fn parse_expr_prefix_by_unreserved_word(&mut self, w: &Word) -> Result<Expr, ParserError> { |
src/parser/mod.rs
Outdated
// special expression (to maintain backwards compatibility of parsing errors). | ||
Err(e) => { | ||
if !self.dialect.is_reserved_for_identifier(w.keyword) { | ||
if let Ok(expr) = self.maybe_parse_internal(|parser| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if let Ok(expr) = self.maybe_parse_internal(|parser| { | |
if let Some(expr) = self.maybe_parse(|parser| { |
it looks like we can use the normal maybe_parse here since it doesn't have the special requirement?
src/parser/mod.rs
Outdated
} | ||
|
||
/// Run a parser method `f`, reverting back to the current position if unsuccessful. | ||
pub fn maybe_parse_internal<T, F>(&mut self, mut f: F) -> Result<T, ParserError> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn maybe_parse_internal<T, F>(&mut self, mut f: F) -> Result<T, ParserError> | |
pub fn try_parse<T, F>(&mut self, mut f: F) -> Result<T, ParserError> |
We can probably call try_parse which could hint that it returns an error (vs maybe_parse which hints at an option)
@@ -214,6 +216,16 @@ impl Dialect for SnowflakeDialect { | |||
fn supports_show_like_before_in(&self) -> bool { | |||
true | |||
} | |||
|
|||
fn is_reserved_for_identifier(&self, kw: Keyword) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh are we missing tests for the new behavior (I can't seem to find them in the current PR if so)?
…ifier if the expression parsing fails
1c5c90a
to
e4ebe44
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! cc @alamb
This fixes the following issue: #1496
The parser encounters situations when the next keyword indicates an expression, but in fact it should be parsed as an identifier. Example from Snowflake:
SELECT MAX(interval) from tbl
. When the parser encounters theinterval
word it tries to parse anExpr::Interval
but it fails because in the context of this query,interval
is an identifier that Snowflake (unlike most other dialects) allows in unquoted form.The suggested approach is to try to parse the expression, but if that fails, fallback to parse an identifier under certain conditions. In addition, each dialect can now declare which keywords it reserves for use as an identifier in unquoted form.
Lastly, changed the parsing of the
DEFAULT
word to Expr::Default instead of an identifier.