Make BitwiseNot ("~") available for all dialects, not just PostgreSQL (#2081)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled

This commit is contained in:
Alexander Beedie 2025-10-30 15:57:25 +04:00 committed by GitHub
parent bc6e1d6e1a
commit 308a7231bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 29 deletions

View file

@ -33,35 +33,35 @@ use super::display_separated;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum UnaryOperator { pub enum UnaryOperator {
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AtDashAt,
/// Unary logical not operator: e.g. `! false` (Hive-specific)
BangNot,
/// Bitwise Not, e.g. `~9`
BitwiseNot,
/// `@@` Center (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleAt,
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
Hash,
/// Plus, e.g. `+9` /// Plus, e.g. `+9`
Plus, Plus,
/// Minus, e.g. `-9` /// Minus, e.g. `-9`
Minus, Minus,
/// Not, e.g. `NOT(true)` /// Not, e.g. `NOT(true)`
Not, Not,
/// Bitwise Not, e.g. `~9` (PostgreSQL-specific) /// Absolute value, e.g. `@ -9` (PostgreSQL-specific)
PGBitwiseNot, PGAbs,
/// Square root, e.g. `|/9` (PostgreSQL-specific)
PGSquareRoot,
/// Cube root, e.g. `||/27` (PostgreSQL-specific) /// Cube root, e.g. `||/27` (PostgreSQL-specific)
PGCubeRoot, PGCubeRoot,
/// Factorial, e.g. `9!` (PostgreSQL-specific) /// Factorial, e.g. `9!` (PostgreSQL-specific)
PGPostfixFactorial, PGPostfixFactorial,
/// Factorial, e.g. `!!9` (PostgreSQL-specific) /// Factorial, e.g. `!!9` (PostgreSQL-specific)
PGPrefixFactorial, PGPrefixFactorial,
/// Absolute value, e.g. `@ -9` (PostgreSQL-specific) /// Square root, e.g. `|/9` (PostgreSQL-specific)
PGAbs, PGSquareRoot,
/// Unary logical not operator: e.g. `! false` (Hive-specific)
BangNot,
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
Hash,
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AtDashAt,
/// `@@` Center (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleAt,
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator) /// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html> /// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDash, QuestionDash,
@ -73,19 +73,19 @@ pub enum UnaryOperator {
impl fmt::Display for UnaryOperator { impl fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self { f.write_str(match self {
UnaryOperator::Plus => "+", UnaryOperator::AtDashAt => "@-@",
UnaryOperator::BangNot => "!",
UnaryOperator::BitwiseNot => "~",
UnaryOperator::DoubleAt => "@@",
UnaryOperator::Hash => "#",
UnaryOperator::Minus => "-", UnaryOperator::Minus => "-",
UnaryOperator::Not => "NOT", UnaryOperator::Not => "NOT",
UnaryOperator::PGBitwiseNot => "~", UnaryOperator::PGAbs => "@",
UnaryOperator::PGSquareRoot => "|/",
UnaryOperator::PGCubeRoot => "||/", UnaryOperator::PGCubeRoot => "||/",
UnaryOperator::PGPostfixFactorial => "!", UnaryOperator::PGPostfixFactorial => "!",
UnaryOperator::PGPrefixFactorial => "!!", UnaryOperator::PGPrefixFactorial => "!!",
UnaryOperator::PGAbs => "@", UnaryOperator::PGSquareRoot => "|/",
UnaryOperator::BangNot => "!", UnaryOperator::Plus => "+",
UnaryOperator::Hash => "#",
UnaryOperator::AtDashAt => "@-@",
UnaryOperator::DoubleAt => "@@",
UnaryOperator::QuestionDash => "?-", UnaryOperator::QuestionDash => "?-",
UnaryOperator::QuestionPipe => "?|", UnaryOperator::QuestionPipe => "?|",
}) })

View file

@ -1633,7 +1633,6 @@ impl<'a> Parser<'a> {
| tok @ Token::PGSquareRoot | tok @ Token::PGSquareRoot
| tok @ Token::PGCubeRoot | tok @ Token::PGCubeRoot
| tok @ Token::AtSign | tok @ Token::AtSign
| tok @ Token::Tilde
if dialect_is!(dialect is PostgreSqlDialect) => if dialect_is!(dialect is PostgreSqlDialect) =>
{ {
let op = match tok { let op = match tok {
@ -1641,7 +1640,6 @@ impl<'a> Parser<'a> {
Token::PGSquareRoot => UnaryOperator::PGSquareRoot, Token::PGSquareRoot => UnaryOperator::PGSquareRoot,
Token::PGCubeRoot => UnaryOperator::PGCubeRoot, Token::PGCubeRoot => UnaryOperator::PGCubeRoot,
Token::AtSign => UnaryOperator::PGAbs, Token::AtSign => UnaryOperator::PGAbs,
Token::Tilde => UnaryOperator::PGBitwiseNot,
_ => unreachable!(), _ => unreachable!(),
}; };
Ok(Expr::UnaryOp { Ok(Expr::UnaryOp {
@ -1651,6 +1649,10 @@ impl<'a> Parser<'a> {
), ),
}) })
} }
Token::Tilde => Ok(Expr::UnaryOp {
op: UnaryOperator::BitwiseNot,
expr: Box::new(self.parse_subexpr(self.dialect.prec_value(Precedence::PlusMinus))?),
}),
tok @ Token::Sharp tok @ Token::Sharp
| tok @ Token::AtDashAt | tok @ Token::AtDashAt
| tok @ Token::AtAt | tok @ Token::AtAt

View file

@ -17613,3 +17613,22 @@ fn test_parse_alter_user() {
} }
verified_stmt("ALTER USER u1 SET DEFAULT_SECONDARY_ROLES=('ALL'), PASSWORD='secret', WORKLOAD_IDENTITY=(TYPE=AWS, ARN='arn:aws:iam::123456789:r1/')"); verified_stmt("ALTER USER u1 SET DEFAULT_SECONDARY_ROLES=('ALL'), PASSWORD='secret', WORKLOAD_IDENTITY=(TYPE=AWS, ARN='arn:aws:iam::123456789:r1/')");
} }
#[test]
fn parse_generic_unary_ops() {
let unary_ops = &[
("~", UnaryOperator::BitwiseNot),
("-", UnaryOperator::Minus),
("+", UnaryOperator::Plus),
];
for (str_op, op) in unary_ops {
let select = verified_only_select(&format!("SELECT {}expr", &str_op));
assert_eq!(
UnnamedExpr(UnaryOp {
op: *op,
expr: Box::new(Identifier(Ident::new("expr"))),
}),
select.projection[0]
);
}
}

View file

@ -2144,13 +2144,11 @@ fn parse_ampersand_arobase() {
#[test] #[test]
fn parse_pg_unary_ops() { fn parse_pg_unary_ops() {
let pg_unary_ops = &[ let pg_unary_ops = &[
("~", UnaryOperator::PGBitwiseNot),
("|/", UnaryOperator::PGSquareRoot), ("|/", UnaryOperator::PGSquareRoot),
("||/", UnaryOperator::PGCubeRoot), ("||/", UnaryOperator::PGCubeRoot),
("!!", UnaryOperator::PGPrefixFactorial), ("!!", UnaryOperator::PGPrefixFactorial),
("@", UnaryOperator::PGAbs), ("@", UnaryOperator::PGAbs),
]; ];
for (str_op, op) in pg_unary_ops { for (str_op, op) in pg_unary_ops {
let select = pg().verified_only_select(&format!("SELECT {}a", &str_op)); let select = pg().verified_only_select(&format!("SELECT {}a", &str_op));
assert_eq!( assert_eq!(