This is an automated email from the ASF dual-hosted git repository. LucaCappelletti94 pushed a commit to branch pg-postfix-factorial-spacing in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 0d001461fa512b64596837ccd196c3110d1c013e Author: LucaCappelletti94 <[email protected]> AuthorDate: Mon Sep 21 23:12:33 2026 +0200 PostgreSQL: Fix spacing between adjacent postfix factorial operators --- src/ast/mod.rs | 28 +++++++++++++++++++++++++++- tests/sqlparser_postgres.rs | 18 ++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index dcfd1a96..0755d7fa 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1956,7 +1956,13 @@ impl fmt::Display for Expr { ) } Expr::UnaryOp { op, expr } => match op { - UnaryOperator::PGPostfixFactorial => write!(f, "{expr}{op}"), + UnaryOperator::PGPostfixFactorial => { + if ends_with_operator_char(expr) { + write!(f, "{expr} {op}") + } else { + write!(f, "{expr}{op}") + } + } UnaryOperator::Not | UnaryOperator::BitwiseNot | UnaryOperator::Hash @@ -8109,6 +8115,26 @@ fn starts_with_operator_char(expr: &Expr) -> bool { first.0.is_some_and(|c| OPERATOR_CHARS.contains(c)) } +/// Whether `expr` renders with an operator character last. A postfix `!` +/// must not abut one, since `!!` is the prefix factorial operator in +/// PostgreSQL. +fn ends_with_operator_char(expr: &Expr) -> bool { + use fmt::Write; + struct LastChar(Option<char>); + impl fmt::Write for LastChar { + fn write_str(&mut self, s: &str) -> fmt::Result { + if let Some(c) = s.chars().last() { + self.0 = Some(c); + } + Ok(()) + } + } + let mut last = LastChar(None); + let _ = write!(last, "{expr}"); + const OPERATOR_CHARS: &str = "+-*/<>=~!@%#^&|"; + last.0.is_some_and(|c| OPERATOR_CHARS.contains(c)) +} + /// `FunctionArgOperator::Space` has no token of its own, so the name and the /// value are separated by a single space instead. fn fmt_named_function_arg( diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index ab2d4b8e..543ff6aa 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -9984,3 +9984,21 @@ fn parse_unary_minus_before_pg_prefix_operators() { pg().verified_stmt("SELECT - @ 2"); pg().one_statement_parses_to("SELECT - #x", "SELECT - # x"); } + +#[test] +fn parse_postfix_factorial_spacing() { + pg().verified_stmt("SELECT a!"); + pg().verified_stmt("SELECT 5!"); + pg().verified_stmt("SELECT (a!)!"); + pg().verified_stmt("SELECT a! !"); + pg().verified_stmt("SELECT a! ! !"); + pg().verified_stmt("SELECT a! ! % 2"); + pg().one_statement_parses_to("SELECT a! !%2", "SELECT a! ! % 2"); + pg().one_statement_parses_to("SELECT -a, +b, a! !%2, a", "SELECT -a, +b, a! ! % 2, a"); + + let err = pg().parse_sql_statements("SELECT a!!").unwrap_err(); + assert_eq!( + ParserError::ParserError("Expected: end of statement, found: !!".to_string()), + err + ); +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
