feat: Support PostgreSQL exponentiation. (#813)

* Add Postgres exponent operator

* Parse caret as BinaryOperator::PGExp in PostgreSQL

* Update sqlparser_postgres.rs

* update tests to support PGExp

* cargo fmt

* improve extensibility

* cargo fmt

* redundant code and documentation lionks
This commit is contained in:
Mykhailo Bondarenko 2023-03-02 17:39:39 +02:00 committed by GitHub
parent fbbf1a4e84
commit 1cf913e717
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 10 deletions

View file

@ -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("!~"),

View file

@ -1648,7 +1648,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) => {

View file

@ -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::<PostgreSqlDialect>())
.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"))),

View file

@ -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 {