Skip to content

Commit

Permalink
Add support for PostgreSQL ^@ starts-with operator (#1091)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-beedie authored Jan 15, 2024
1 parent a71b3f5 commit 7cb1654
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/ast/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ pub enum BinaryOperator {
PGRegexNotMatch,
/// String does not match regular expression (case insensitively), e.g. `a !~* b` (PostgreSQL-specific)
PGRegexNotIMatch,
/// String "starts with", eg: `a ^@ b` (PostgreSQL-specific)
PGStartsWith,
/// PostgreSQL-specific custom operator.
///
/// See [CREATE OPERATOR](https://www.postgresql.org/docs/current/sql-createoperator.html)
Expand Down Expand Up @@ -172,6 +174,7 @@ impl fmt::Display for BinaryOperator {
BinaryOperator::PGRegexIMatch => f.write_str("~*"),
BinaryOperator::PGRegexNotMatch => f.write_str("!~"),
BinaryOperator::PGRegexNotIMatch => f.write_str("!~*"),
BinaryOperator::PGStartsWith => f.write_str("^@"),
BinaryOperator::PGCustomBinaryOperator(idents) => {
write!(f, "OPERATOR({})", display_separated(idents, "."))
}
Expand Down
4 changes: 4 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2196,6 +2196,9 @@ impl<'a> Parser<'a> {
Token::Overlap if dialect_of!(self is PostgreSqlDialect | GenericDialect) => {
Some(BinaryOperator::PGOverlap)
}
Token::CaretAt if dialect_of!(self is PostgreSqlDialect | GenericDialect) => {
Some(BinaryOperator::PGStartsWith)
}
Token::Tilde => Some(BinaryOperator::PGRegexMatch),
Token::TildeAsterisk => Some(BinaryOperator::PGRegexIMatch),
Token::ExclamationMarkTilde => Some(BinaryOperator::PGRegexNotMatch),
Expand Down Expand Up @@ -2630,6 +2633,7 @@ impl<'a> Parser<'a> {
| Token::LongArrow
| Token::Arrow
| Token::Overlap
| Token::CaretAt
| Token::HashArrow
| Token::HashLongArrow
| Token::AtArrow
Expand Down
26 changes: 18 additions & 8 deletions src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ pub enum Token {
DoubleQuotedString(String),
/// Dollar quoted string: i.e: $$string$$ or $tag_name$string$tag_name$
DollarQuotedString(DollarQuotedString),
/// Byte string literal: i.e: b'string' or B'string'
/// Byte string literal: i.e: b'string' or B'string' (note that some backends, such as
/// PostgreSQL, may treat this syntax as a bit string literal instead, i.e: b'10010101')
SingleQuotedByteStringLiteral(String),
/// Byte string literal: i.e: b"string" or B"string"
DoubleQuotedByteStringLiteral(String),
Expand Down Expand Up @@ -114,7 +115,7 @@ pub enum Token {
Period,
/// Colon `:`
Colon,
/// DoubleColon `::` (used for casting in postgresql)
/// DoubleColon `::` (used for casting in PostgreSQL)
DoubleColon,
/// Assignment `:=` (used for keyword argument in DuckDB macros)
DuckAssignment,
Expand Down Expand Up @@ -152,27 +153,29 @@ pub enum Token {
ShiftLeft,
/// `>>`, a bitwise shift right operator in PostgreSQL
ShiftRight,
/// '&&', an overlap operator in PostgreSQL
/// `&&`, an overlap operator in PostgreSQL
Overlap,
/// Exclamation Mark `!` used for PostgreSQL factorial operator
ExclamationMark,
/// Double Exclamation Mark `!!` used for PostgreSQL prefix factorial operator
DoubleExclamationMark,
/// AtSign `@` used for PostgreSQL abs operator
AtSign,
/// `^@`, a "starts with" string operator in PostgreSQL
CaretAt,
/// `|/`, a square root math operator in PostgreSQL
PGSquareRoot,
/// `||/`, a cube root math operator in PostgreSQL
PGCubeRoot,
/// `?` or `$` , a prepared statement arg placeholder
Placeholder(String),
/// ->, used as a operator to extract json field in PostgreSQL
/// `->`, used as a operator to extract json field in PostgreSQL
Arrow,
/// ->>, used as a operator to extract json field as text in PostgreSQL
/// `->>`, used as a operator to extract json field as text in PostgreSQL
LongArrow,
/// #> Extracts JSON sub-object at the specified path
/// `#>`, extracts JSON sub-object at the specified path
HashArrow,
/// #>> Extracts JSON sub-object at the specified path as text
/// `#>>`, extracts JSON sub-object at the specified path as text
HashLongArrow,
/// jsonb @> jsonb -> boolean: Test whether left json contains the right json
AtArrow,
Expand Down Expand Up @@ -247,6 +250,7 @@ impl fmt::Display for Token {
Token::ExclamationMarkTilde => f.write_str("!~"),
Token::ExclamationMarkTildeAsterisk => f.write_str("!~*"),
Token::AtSign => f.write_str("@"),
Token::CaretAt => f.write_str("^@"),
Token::ShiftLeft => f.write_str("<<"),
Token::ShiftRight => f.write_str(">>"),
Token::Overlap => f.write_str("&&"),
Expand Down Expand Up @@ -940,7 +944,13 @@ impl<'a> Tokenizer<'a> {
_ => Ok(Some(Token::Ampersand)),
}
}
'^' => self.consume_and_return(chars, Token::Caret),
'^' => {
chars.next(); // consume the '^'
match chars.peek() {
Some('@') => self.consume_and_return(chars, Token::CaretAt),
_ => Ok(Some(Token::Caret)),
}
}
'{' => self.consume_and_return(chars, Token::LBrace),
'}' => self.consume_and_return(chars, Token::RBrace),
'#' if dialect_of!(self is SnowflakeDialect) => {
Expand Down
1 change: 1 addition & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,7 @@ fn parse_pg_binary_ops() {
(">>", BinaryOperator::PGBitwiseShiftRight, pg_and_generic()),
("<<", BinaryOperator::PGBitwiseShiftLeft, pg_and_generic()),
("&&", BinaryOperator::PGOverlap, pg()),
("^@", BinaryOperator::PGStartsWith, pg()),
];

for (str_op, op, dialects) in binary_ops {
Expand Down

0 comments on commit 7cb1654

Please sign in to comment.