Skip to content

Commit 1cf913e

Browse files
authored
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
1 parent fbbf1a4 commit 1cf913e

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

src/ast/operator.rs

+2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub enum BinaryOperator {
8888
PGBitwiseXor,
8989
PGBitwiseShiftLeft,
9090
PGBitwiseShiftRight,
91+
PGExp,
9192
PGRegexMatch,
9293
PGRegexIMatch,
9394
PGRegexNotMatch,
@@ -124,6 +125,7 @@ impl fmt::Display for BinaryOperator {
124125
BinaryOperator::PGBitwiseXor => f.write_str("#"),
125126
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),
126127
BinaryOperator::PGBitwiseShiftRight => f.write_str(">>"),
128+
BinaryOperator::PGExp => f.write_str("^"),
127129
BinaryOperator::PGRegexMatch => f.write_str("~"),
128130
BinaryOperator::PGRegexIMatch => f.write_str("~*"),
129131
BinaryOperator::PGRegexNotMatch => f.write_str("!~"),

src/parser.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,15 @@ impl<'a> Parser<'a> {
16481648
Token::Mod => Some(BinaryOperator::Modulo),
16491649
Token::StringConcat => Some(BinaryOperator::StringConcat),
16501650
Token::Pipe => Some(BinaryOperator::BitwiseOr),
1651-
Token::Caret => Some(BinaryOperator::BitwiseXor),
1651+
Token::Caret => {
1652+
// In PostgreSQL, ^ stands for the exponentiation operation,
1653+
// and # stands for XOR. See https://www.postgresql.org/docs/current/functions-math.html
1654+
if dialect_of!(self is PostgreSqlDialect) {
1655+
Some(BinaryOperator::PGExp)
1656+
} else {
1657+
Some(BinaryOperator::BitwiseXor)
1658+
}
1659+
}
16521660
Token::Ampersand => Some(BinaryOperator::BitwiseAnd),
16531661
Token::Div => Some(BinaryOperator::Divide),
16541662
Token::ShiftLeft if dialect_of!(self is PostgreSqlDialect | GenericDialect) => {

tests/sqlparser_common.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -1228,16 +1228,27 @@ fn parse_string_agg() {
12281228
);
12291229
}
12301230

1231+
/// selects all dialects but PostgreSQL
1232+
pub fn all_dialects_but_pg() -> TestedDialects {
1233+
TestedDialects {
1234+
dialects: all_dialects()
1235+
.dialects
1236+
.into_iter()
1237+
.filter(|x| !x.is::<PostgreSqlDialect>())
1238+
.collect(),
1239+
}
1240+
}
1241+
12311242
#[test]
12321243
fn parse_bitwise_ops() {
12331244
let bitwise_ops = &[
1234-
("^", BinaryOperator::BitwiseXor),
1235-
("|", BinaryOperator::BitwiseOr),
1236-
("&", BinaryOperator::BitwiseAnd),
1245+
("^", BinaryOperator::BitwiseXor, all_dialects_but_pg()),
1246+
("|", BinaryOperator::BitwiseOr, all_dialects()),
1247+
("&", BinaryOperator::BitwiseAnd, all_dialects()),
12371248
];
12381249

1239-
for (str_op, op) in bitwise_ops {
1240-
let select = verified_only_select(&format!("SELECT a {} b", &str_op));
1250+
for (str_op, op, dialects) in bitwise_ops {
1251+
let select = dialects.verified_only_select(&format!("SELECT a {} b", &str_op));
12411252
assert_eq!(
12421253
SelectItem::UnnamedExpr(Expr::BinaryOp {
12431254
left: Box::new(Expr::Identifier(Ident::new("a"))),

tests/sqlparser_postgres.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1322,15 +1322,16 @@ fn parse_pg_returning() {
13221322
}
13231323

13241324
#[test]
1325-
fn parse_pg_bitwise_binary_ops() {
1326-
let bitwise_ops = &[
1327-
// Sharp char cannot be used with Generic Dialect, it conflicts with identifiers
1325+
fn parse_pg_binary_ops() {
1326+
let binary_ops = &[
1327+
// Sharp char and Caret cannot be used with Generic Dialect, it conflicts with identifiers
13281328
("#", BinaryOperator::PGBitwiseXor, pg()),
1329+
("^", BinaryOperator::PGExp, pg()),
13291330
(">>", BinaryOperator::PGBitwiseShiftRight, pg_and_generic()),
13301331
("<<", BinaryOperator::PGBitwiseShiftLeft, pg_and_generic()),
13311332
];
13321333

1333-
for (str_op, op, dialects) in bitwise_ops {
1334+
for (str_op, op, dialects) in binary_ops {
13341335
let select = dialects.verified_only_select(&format!("SELECT a {} b", &str_op));
13351336
assert_eq!(
13361337
SelectItem::UnnamedExpr(Expr::BinaryOp {

0 commit comments

Comments
 (0)