diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs index 6f9ec0d25a..a01ced32d6 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 b19b796cde..8a1dced38d 100644 --- a/tests/sqlparser_sqlite.rs +++ b/tests/sqlparser_sqlite.rs @@ -1117,6 +1117,31 @@ fn parse_create_table_options_list() { } } +#[test] +fn parse_colon_does_not_start_json_access() { + // SQLite rejects `SELECT c:se` (`near ":se": syntax error`); no `:` traversal. + for sql in ["SELECT c:se", "SELECT a:b FROM t"] { + assert_eq!( + sqlite().parse_sql_statements(sql), + Err(ParserError::ParserError( + "Expected: end of statement, found: :".to_string() + )) + ); + } + + let ast = sqlite().verified_only_select("SELECT :xxx"); + assert_eq!( + ast.projection[0], + UnnamedExpr(Expr::Value( + (Value::Placeholder(":xxx".into())).with_empty_span() + )), + ); + + TestedDialects::new(vec![Box::new(GenericDialect {})]) + .parse_sql_statements("SELECT a:b FROM t") + .unwrap(); +} + fn sqlite() -> TestedDialects { TestedDialects::new(vec![Box::new(SQLiteDialect {})]) }