diff --git a/src/ast/operator.rs b/src/ast/operator.rs index ca609941b..75877c949 100644 --- a/src/ast/operator.rs +++ b/src/ast/operator.rs @@ -88,6 +88,7 @@ pub enum BinaryOperator { PGBitwiseXor, PGBitwiseShiftLeft, PGBitwiseShiftRight, + PGExp, PGRegexMatch, PGRegexIMatch, PGRegexNotMatch, @@ -124,6 +125,7 @@ impl fmt::Display for BinaryOperator { BinaryOperator::PGBitwiseXor => f.write_str("#"), BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"), BinaryOperator::PGBitwiseShiftRight => f.write_str(">>"), + BinaryOperator::PGExp => f.write_str("^"), BinaryOperator::PGRegexMatch => f.write_str("~"), BinaryOperator::PGRegexIMatch => f.write_str("~*"), BinaryOperator::PGRegexNotMatch => f.write_str("!~"), diff --git a/src/parser.rs b/src/parser.rs index a1ecdfe96..c08207f45 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1613,7 +1613,15 @@ impl<'a> Parser<'a> { Token::Mod => Some(BinaryOperator::Modulo), Token::StringConcat => Some(BinaryOperator::StringConcat), Token::Pipe => Some(BinaryOperator::BitwiseOr), - Token::Caret => Some(BinaryOperator::BitwiseXor), + Token::Caret => { + // In PostgreSQL, ^ stands for the exponentiation operation, + // and # stands for XOR. See https://www.postgresql.org/docs/current/functions-math.html + if dialect_of!(self is PostgreSqlDialect) { + Some(BinaryOperator::PGExp) + } else { + Some(BinaryOperator::BitwiseXor) + } + } Token::Ampersand => Some(BinaryOperator::BitwiseAnd), Token::Div => Some(BinaryOperator::Divide), Token::ShiftLeft if dialect_of!(self is PostgreSqlDialect | GenericDialect) => { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index faab5049c..ba3468726 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1228,16 +1228,27 @@ fn parse_string_agg() { ); } +/// selects all dialects but PostgreSQL +pub fn all_dialects_but_pg() -> TestedDialects { + TestedDialects { + dialects: all_dialects() + .dialects + .into_iter() + .filter(|x| !x.is::()) + .collect(), + } +} + #[test] fn parse_bitwise_ops() { let bitwise_ops = &[ - ("^", BinaryOperator::BitwiseXor), - ("|", BinaryOperator::BitwiseOr), - ("&", BinaryOperator::BitwiseAnd), + ("^", BinaryOperator::BitwiseXor, all_dialects_but_pg()), + ("|", BinaryOperator::BitwiseOr, all_dialects()), + ("&", BinaryOperator::BitwiseAnd, all_dialects()), ]; - for (str_op, op) in bitwise_ops { - let select = verified_only_select(&format!("SELECT a {} b", &str_op)); + for (str_op, op, dialects) in bitwise_ops { + let select = dialects.verified_only_select(&format!("SELECT a {} b", &str_op)); assert_eq!( SelectItem::UnnamedExpr(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident::new("a"))), diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 2fbcf977f..72f364650 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1322,15 +1322,16 @@ fn parse_pg_returning() { } #[test] -fn parse_pg_bitwise_binary_ops() { - let bitwise_ops = &[ - // Sharp char cannot be used with Generic Dialect, it conflicts with identifiers +fn parse_pg_binary_ops() { + let binary_ops = &[ + // Sharp char and Caret cannot be used with Generic Dialect, it conflicts with identifiers ("#", BinaryOperator::PGBitwiseXor, pg()), + ("^", BinaryOperator::PGExp, pg()), (">>", BinaryOperator::PGBitwiseShiftRight, pg_and_generic()), ("<<", BinaryOperator::PGBitwiseShiftLeft, pg_and_generic()), ]; - for (str_op, op, dialects) in bitwise_ops { + for (str_op, op, dialects) in binary_ops { let select = dialects.verified_only_select(&format!("SELECT a {} b", &str_op)); assert_eq!( SelectItem::UnnamedExpr(Expr::BinaryOp {