kumarUjjawal opened a new issue, #2819: URL: https://github.com/apache/datafusion-sqlparser-rs/issues/2819
## Problem In `PostgreSqlDialect`, a unary minus binds more loosely than `^`. The parser reads `-1 ^ 0` as `-(1 ^ 0)`. In PostgreSQL, unary minus binds more tightly than `^` ([operator precedence table](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE)). PostgreSQL reads `-1 ^ 0` as `(-1) ^ 0`. ## Reproduction At `main` (`d1c1790e3`): ```rust use sqlparser::dialect::PostgreSqlDialect; use sqlparser::parser::Parser; let ast = Parser::parse_sql(&PostgreSqlDialect {}, "SELECT -1 ^ 0").unwrap(); println!("{ast:#?}"); ``` The projection expression is (spans removed): ```text UnaryOp { op: Minus, expr: BinaryOp { left: Value(Number("1", false)), op: PGExp, right: Value(Number("0", false)), }, } ``` The expected expression is: ```text BinaryOp { left: UnaryOp { op: Minus, expr: Value(Number("1", false)) }, op: PGExp, right: Value(Number("0", false)), } ``` `SELECT -2 ^ 2` and `SELECT +2 ^ 2` parse the same way. ## Effect on query results The grouping changes the result: | Query | PostgreSQL 17 | DuckDB | DataFusion (PostgreSQL dialect) | |---|---|---|---| | `SELECT -1 ^ 0` | 1 | 1 | -1 | | `SELECT -2 ^ 2` | 4 | 4 | -4 | DataFusion tracks this in apache/datafusion#27094. ## Cause `parse_prefix_inner` parses the operand of a unary `-` or `+` at `Precedence::MulDivModOp` ([src/parser/mod.rs#L1967-L1979](https://github.com/apache/datafusion-sqlparser-rs/blob/d1c1790e3b80dbc325d94072bb5fc0670aef0d08/src/parser/mod.rs#L1967-L1979)): ```rust tok @ Token::Minus | tok @ Token::Plus => { // ... Ok(Expr::UnaryOp { op, expr: Box::new( self.parse_subexpr(self.dialect.prec_value(Precedence::MulDivModOp))?, ), }) } ``` `PostgreSqlDialect` sets `CARET_PREC` (100) above `MUL_DIV_MOD_OP_PREC` (90) ([src/dialect/postgresql.rs#L213-L214](https://github.com/apache/datafusion-sqlparser-rs/blob/d1c1790e3b80dbc325d94072bb5fc0670aef0d08/src/dialect/postgresql.rs#L213-L214)). So the operand of the minus also takes the `^` that follows. For the PostgreSQL dialect, the operand of a unary `-` or `+` must be parsed at a precedence above `CARET_PREC`. In the PostgreSQL table, unary `+` and `-` are also above `COLLATE` and `AT`. The generic dialect is not affected in this way: there, `Caret` is below `MulDivModOp`. Related: #814 (precedence of `~`). -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
