From 365cfb1bdfb06141cb1070919bc21e5af44058d2 Mon Sep 17 00:00:00 2001 From: James Sadler Date: Wed, 7 May 2025 17:18:49 +1000 Subject: [PATCH] fix: allow arbitrary operators with ANY and ALL on Postgres In sqlparser PR #963 a check was introduced which limits which operators can be used with `ANY` and `ALL` expressions. Postgres can parse more (possibly _all_ binary operators, investigation pending) in this location. Postgres only seems to care that the operator yields a boolean - which is a semantic error, not a syntax (parse) error. Example (semantic error, not a parse error): ``` select 123 % ANY(array[246]); ERROR: op ANY/ALL (array) requires operator to yield boolean LINE 1: select 123 % ANY(array[246]); ^ ``` The following code in `src/parser/mod.rs:2893-2908` is where the allowlist of operators is enforced: ```rust if !matches!( op, BinaryOperator::Gt | BinaryOperator::Lt | BinaryOperator::GtEq | BinaryOperator::LtEq | BinaryOperator::Eq | BinaryOperator::NotEq ) { return parser_err!( format!( "Expected one of [=, >, <, =>, =<, !=] as comparison operator, found: {op}" ), tok.span.start ); }; ``` --- src/parser/mod.rs | 2 +- tests/sqlparser_postgres.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index fc6f44376..64a79aa81 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3471,7 +3471,7 @@ impl<'a> Parser<'a> { right }; - if !matches!( + if !dialect_of!(self is PostgreSqlDialect) && !matches!( op, BinaryOperator::Gt | BinaryOperator::Lt diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 859eca453..0f26bccc8 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -5936,6 +5936,36 @@ fn parse_bitstring_literal() { ); } +#[test] +fn parse_arbitrary_operator_with_any_and_all() { + // The following statement is semantically non-sensical on vanilla postgres but it should *parse* in order to + // support situations where PG operators have been overloaded. + let select = pg().verified_only_select("SELECT 123 % ANY(ARRAY[1, 2, 3])"); + assert!( + matches!( + select.projection[0], + SelectItem::UnnamedExpr(Expr::AnyOp { + left: _, + compare_op: BinaryOperator::Modulo, + right: _, + is_some: false + }) + ) + ); + + let select = pg().verified_only_select("SELECT 123 % ALL(ARRAY[1, 2, 3])"); + assert!( + matches!( + select.projection[0], + SelectItem::UnnamedExpr(Expr::AllOp { + left: _, + compare_op: BinaryOperator::Modulo, + right: _, + }) + ) + ); +} + #[test] fn parse_varbit_datatype() { match pg_and_generic().verified_stmt("CREATE TABLE foo (x VARBIT, y VARBIT(42))") {