Skip to content

Commit

Permalink
Modify the code as suggested and fix merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
wugeer committed Oct 27, 2024
1 parent 38f1e57 commit 73c8524
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/ast/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ pub enum UnaryOperator {
PGPrefixFactorial,
/// Absolute value, e.g. `@ -9` (PostgreSQL-specific)
PGAbs,
/// Unary logical not operator: e.g. `! false` (Hive-specific)
BangNot,
}

impl fmt::Display for UnaryOperator {
Expand All @@ -65,6 +67,7 @@ impl fmt::Display for UnaryOperator {
UnaryOperator::PGPostfixFactorial => "!",
UnaryOperator::PGPrefixFactorial => "!!",
UnaryOperator::PGAbs => "@",
UnaryOperator::BangNot => "!",
})
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/hive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ impl Dialect for HiveDialect {
fn require_interval_qualifier(&self) -> bool {
true
}

fn supports_bang_not_operator(&self) -> bool {
true
}
}
10 changes: 10 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,11 @@ pub trait Dialect: Debug + Any {
false
}

/// Returns true if the dialect supports `a!` expressions
fn supports_factorial_operator(&self) -> bool {
false
}

/// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
/// as an alias assignment operator, rather than a boolean expression.
/// For example: the following statements are equivalent for such a dialect:
Expand All @@ -590,6 +595,11 @@ pub trait Dialect: Debug + Any {
fn supports_try_convert(&self) -> bool {
false
}

/// Returns true if the dialect supports `!a` expressions
fn supports_bang_not_operator(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
5 changes: 5 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ impl Dialect for PostgreSqlDialect {
fn supports_explain_with_utility_options(&self) -> bool {
true
}

/// see <https://www.postgresql.org/docs/13/functions-math.html>
fn supports_factorial_operator(&self) -> bool {
true
}
}

pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
Expand Down
55 changes: 49 additions & 6 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,14 @@ impl<'a> Parser<'a> {
),
})
}
Token::ExclamationMark if self.dialect.supports_bang_not_operator() => {
Ok(Expr::UnaryOp {
op: UnaryOperator::BangNot,
expr: Box::new(
self.parse_subexpr(self.dialect.prec_value(Precedence::UnaryNot))?,
),
})
}
tok @ Token::DoubleExclamationMark
| tok @ Token::PGSquareRoot
| tok @ Token::PGCubeRoot
Expand Down Expand Up @@ -1268,7 +1276,6 @@ impl<'a> Parser<'a> {
}
_ => self.expected("an expression", next_token),
}?;

if self.parse_keyword(Keyword::COLLATE) {
Ok(Expr::Collate {
expr: Box::new(expr),
Expand Down Expand Up @@ -2028,6 +2035,13 @@ impl<'a> Parser<'a> {
}
}

pub fn parse_bang_not(&mut self) -> Result<Expr, ParserError> {
Ok(Expr::UnaryOp {
op: UnaryOperator::BangNot,
expr: Box::new(self.parse_subexpr(self.dialect.prec_value(Precedence::UnaryNot))?),
})
}

/// Parses fulltext expressions [`sqlparser::ast::Expr::MatchAgainst`]
///
/// # Errors
Expand Down Expand Up @@ -2800,11 +2814,40 @@ impl<'a> Parser<'a> {
format: None,
})
} else if Token::ExclamationMark == tok {
// PostgreSQL factorial operation
Ok(Expr::UnaryOp {
op: UnaryOperator::PGPostfixFactorial,
expr: Box::new(expr),
})
if self.dialect.supports_factorial_operator() {
match expr {
Expr::Value(_) | Expr::Identifier(_) | Expr::Nested(_) | Expr::BinaryOp{..} => Ok(Expr::UnaryOp {
op: UnaryOperator::PGPostfixFactorial,
expr: Box::new(expr),
}),
_ => {
self.expected(
"Value or Identifier or Nested or BinaryOp struct before factorial operator(!)", self.peek_token())
},
}
} else if self.dialect.supports_bang_not_operator() {
let token = self.next_token();
match token.token {
Token::Word(_) | Token::Number(..) => Ok(Expr::UnaryOp {
op: UnaryOperator::BangNot,
expr: Box::new(expr),
}),
_ => {
parser_err!(
"current dialect support bang not operator, but with wrong synx",
tok.location
)
}
}
} else {
parser_err!(
format!(
"current dialect: {:?} does not support factorial operator or bang not operator",
self.dialect
),
self.peek_token().location
)
}
} else if Token::LBracket == tok {
if dialect_of!(self is PostgreSqlDialect | DuckDbDialect | GenericDialect) {
self.parse_subscript(expr)
Expand Down
46 changes: 46 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11460,3 +11460,49 @@ fn test_try_convert() {
all_dialects_where(|d| d.supports_try_convert() && !d.convert_type_before_value());
dialects.verified_expr("TRY_CONVERT('foo', VARCHAR(MAX))");
}

#[test]
fn parse_bang_not() {
let dialects = all_dialects_where(|d| d.supports_bang_not_operator());
let sql = "SELECT !a, !(b > 3)";
let Select { projection, .. } = dialects.verified_only_select(sql);

for (i, (op, expr)) in [
(
UnaryOperator::BangNot,
Box::new(Expr::Identifier(Ident::new("a"))),
),
(
UnaryOperator::BangNot,
Box::new(Expr::Nested(Box::new(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("b"))),
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(Value::Number("3".parse().unwrap(), false))),
}))),
),
]
.into_iter()
.enumerate()
{
assert_eq!(
SelectItem::UnnamedExpr(Expr::UnaryOp { op: op, expr }),
projection[i]
)
}

let sql = "SELECT a!";
assert_eq!(
dialects.parse_sql_statements(sql).unwrap_err(),
ParserError::ParserError(
"current dialect support bang not operator, but with wrong synx".to_string()
)
);

let sql = "SELECT !a";
assert_eq!(
all_dialects_where(|d| !d.supports_bang_not_operator())
.parse_sql_statements(sql)
.unwrap_err(),
ParserError::ParserError("Expected: an expression, found: !".to_string())
);
}

0 comments on commit 73c8524

Please sign in to comment.