diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs index 6f9ec0d25..a01ced32d 100644 --- a/src/dialect/sqlite.rs +++ b/src/dialect/sqlite.rs @@ -23,6 +23,7 @@ use crate::ast::{Expr, Statement}; use crate::dialect::Dialect; use crate::keywords::Keyword; use crate::parser::{Parser, ParserError}; +use crate::tokenizer::Token; /// A [`Dialect`] for [SQLite](https://www.sqlite.org) /// @@ -97,6 +98,14 @@ impl Dialect for SQLiteDialect { None } + fn get_next_precedence(&self, parser: &Parser) -> Option> { + match &parser.peek_token_ref().token { + // lowest prec to prevent it from turning into a binary op + Token::Colon => Some(Ok(self.prec_unknown())), + _ => None, + } + } + fn supports_in_empty_list(&self) -> bool { true } diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs index b8fad7e9d..9c332c36f 100644 --- a/tests/sqlparser_sqlite.rs +++ b/tests/sqlparser_sqlite.rs @@ -1024,6 +1024,25 @@ fn parse_n_prefix_not_national_string() { all_dialects_where(|d| d.supports_national_string_literal()).verified_stmt("SELECT N'hello'"); } +#[test] +fn parse_colon_does_not_start_json_access() { + // SQLite rejects `SELECT c:se` (`near ":se": syntax error`); no `:` traversal. + assert!(sqlite().parse_sql_statements("SELECT c:se").is_err()); + assert!(sqlite().parse_sql_statements("SELECT a:b FROM t").is_err()); + + let ast = sqlite().verified_only_select("SELECT :xxx"); + assert_eq!( + ast.projection[0], + UnnamedExpr(Expr::Value( + (Value::Placeholder(":xxx".into())).with_empty_span() + )), + ); + + assert!(TestedDialects::new(vec![Box::new(GenericDialect {})]) + .parse_sql_statements("SELECT a:b FROM t") + .is_ok()); +} + fn sqlite() -> TestedDialects { TestedDialects::new(vec![Box::new(SQLiteDialect {})]) }