Fix parsing cast operator after parenthesized DEFAULT expression#2168
Fix parsing cast operator after parenthesized DEFAULT expression#2168iffyio merged 5 commits intoapache:mainfrom
DEFAULT expression#2168Conversation
src/parser/mod.rs
Outdated
| fn parse_column_option_expr(&mut self) -> Result<Expr, ParserError> { | ||
| if self.peek_token_ref().token == Token::LParen { | ||
| let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_prefix())?; | ||
| let mut expr = self.with_state(ParserState::Normal, |p| p.parse_prefix())?; |
There was a problem hiding this comment.
| let mut expr = self.with_state(ParserState::Normal, |p| p.parse_prefix())?; | |
| let mut expr = self.with_state(ParserState::Normal, |p| p.parse_subexpr())?; |
not sure I followed the intent of the added code, but I wonder would the issue be fixed by changing this line instead (thinking since (foo())::INT should be parsed as an expression), or are there other considerations?
There was a problem hiding this comment.
That change would fix the bug here, but break the behavior added in #1927. In Normal state, NOT NULL is treated as an expression (i.e., IS NOT NULL), but in ColumnDefinition state it's not, allowing the trailing NOT NULL to be parsed as a column constraint instead.
My proposed change is basically just duplicating part of the existing logic used in parse_subexpr1. If we run parse_prefix in normal state but the infix loop in ColumnDefinition state, we maintain the NOT NULL parsing behavior added in the previous PR but still properly handle infix operators like ::TEXT.
I'm still familiarizing myself with this repo, so there may be a better way to do this, but this is what I've come up with so far and why it seems like the right approach to me.
Also happy to do a bit of refactoring to cleanly extract a single shared logic for the part of parse_subexpr that we are duplicating if that seems preferable.
Footnotes
There was a problem hiding this comment.
could we do something like this instead?
let expr = self.with_state(ParserState::Normal, |p| p.parse_subexpr(self.dialect.prec_value(Precedence::DoubleColon)))?;
if self.consume_token(&Token::DoubleColon) {
Ok(Expr::Cast {
kind: CastKind::DoubleColon,
expr: Box::new(expr),
data_type: self.parse_data_type()?,
format: None,
})
} else {
Ok(expr)
}There was a problem hiding this comment.
This approach would only handle the :: case. There could be other infix operators or chained casts, which my current approach handles properly by leveraging the full existing infix loop.
I added additional test cases to document this behavior.
There was a problem hiding this comment.
to support the chained cast, we would consume the double colon in a loop? I think the current approach duplicates parts of the expr parsing code most of which aren't exactly related to the problem being solved for, which makes it not ideal
There was a problem hiding this comment.
What about a non :: operator, such as CREATE TABLE t (c INT DEFAULT (foo()) + 1)? (I just added a test case for this)
Admittedly, we are getting into the territory of obscure but technically legal postgres syntax, but it still seems like we should solve this in a more general way than hardcoding one specific operator.
There was a problem hiding this comment.
What about a non :: operator, such as CREATE TABLE t (c INT DEFAULT (foo()) + 1)?
the precedence operator should handle this case?
There was a problem hiding this comment.
Im thinking a generic version would need to use sub_expr somehow, ideally we find a way to reuse the core expr parsing loop
There was a problem hiding this comment.
Thanks for pushing back on this. I thought about this some more, and I think I came up with a more principled approach that also simplifies the solution from #1927: if we just change parse_prefix() for LParen to switch to ParserState::Normal, it allows us to remove the special-cased parse_column_option_expr added in #1927, while also fixing the regression with :: cast.
Let me know what you think of this approach.
There was a problem hiding this comment.
That looks good to me thanks!
iffyio
left a comment
There was a problem hiding this comment.
Thanks @isaacparker0, left some minor comments otherwise I think this looks good overall
iffyio
left a comment
There was a problem hiding this comment.
LGTM! Thanks @isaacparker0!
DEFAULT expression
Fix a regression introduced in v0.59.0 by #1927:
fails to parse with
To fix, continue parsing infix operators after the parenthesized prefix in
parse_column_option_expr.