@@ -36,7 +36,8 @@ use sqlparser_derive::{Visit, VisitMut};
3636
3737use crate :: ast:: DollarQuotedString ;
3838use crate :: dialect:: {
39- BigQueryDialect , DuckDbDialect , GenericDialect , HiveDialect , SnowflakeDialect ,
39+ BigQueryDialect , DuckDbDialect , GenericDialect , HiveDialect , PostgreSqlDialect ,
40+ SnowflakeDialect ,
4041} ;
4142use crate :: dialect:: { Dialect , MySqlDialect } ;
4243use crate :: keywords:: { Keyword , ALL_KEYWORDS , ALL_KEYWORDS_INDEX } ;
@@ -199,6 +200,15 @@ pub enum Token {
199200 /// for the specified JSON value. Only the first item of the result is taken into
200201 /// account. If the result is not Boolean, then NULL is returned.
201202 AtAt ,
203+ /// jsonb ? text -> boolean: Checks whether the string exists as a top-level key within the
204+ /// jsonb object
205+ Question ,
206+ /// jsonb ?& text[] -> boolean: Check whether all members of the text array exist as top-level
207+ /// keys within the jsonb object
208+ QuestionAnd ,
209+ /// jsonb ?| text[] -> boolean: Check whether any member of the text array exists as top-level
210+ /// keys within the jsonb object
211+ QuestionPipe ,
202212}
203213
204214impl fmt:: Display for Token {
@@ -278,6 +288,9 @@ impl fmt::Display for Token {
278288 Token :: HashMinus => write ! ( f, "#-" ) ,
279289 Token :: AtQuestion => write ! ( f, "@?" ) ,
280290 Token :: AtAt => write ! ( f, "@@" ) ,
291+ Token :: Question => write ! ( f, "?" ) ,
292+ Token :: QuestionAnd => write ! ( f, "?&" ) ,
293+ Token :: QuestionPipe => write ! ( f, "?|" ) ,
281294 }
282295 }
283296}
@@ -1059,6 +1072,15 @@ impl<'a> Tokenizer<'a> {
10591072 _ => Ok ( Some ( Token :: AtSign ) ) ,
10601073 }
10611074 }
1075+ // Postgres uses ? for jsonb operators, not prepared statements
1076+ '?' if dialect_of ! ( self is PostgreSqlDialect ) => {
1077+ chars. next ( ) ;
1078+ match chars. peek ( ) {
1079+ Some ( '|' ) => self . consume_and_return ( chars, Token :: QuestionPipe ) ,
1080+ Some ( '&' ) => self . consume_and_return ( chars, Token :: QuestionAnd ) ,
1081+ _ => self . consume_and_return ( chars, Token :: Question ) ,
1082+ }
1083+ }
10621084 '?' => {
10631085 chars. next ( ) ;
10641086 let s = peeking_take_while ( chars, |ch| ch. is_numeric ( ) ) ;
0 commit comments