refactor: Make Parser methods immutable using interior mutability

Changed all parsing methods to take '&self' instead of '\&mut self'.
Mutable parser state (token index and parser state) now uses
for interior mutability.

This refactoring is preparation for the borrowed tokenizer work. When
holding borrowed tokens from the parser (with lifetime tied to '\&self'),
we cannot call methods requiring '\&mut self' due to Rust's borrowing
rules. Using interior mutability resolves this conflict by allowing
state mutations through shared references.
This commit is contained in:
Eyal Leshem 2025-10-21 15:26:23 +03:00 committed by Eyal Leshem
parent b098976cab
commit 650b1ca18f
13 changed files with 658 additions and 716 deletions

View file

@ -2790,7 +2790,7 @@ impl fmt::Display for Declare {
}
/// Sql options of a `CREATE TABLE` statement.
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum CreateTableOptions {

View file

@ -2407,7 +2407,7 @@ pub mod tests {
#[test]
fn test_join() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(
let test = SpanTest::new(
dialect,
"SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id",
);
@ -2432,7 +2432,7 @@ pub mod tests {
#[test]
pub fn test_union() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(
let test = SpanTest::new(
dialect,
"SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source",
);
@ -2449,7 +2449,7 @@ pub mod tests {
#[test]
pub fn test_subquery() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(
let test = SpanTest::new(
dialect,
"SELECT a FROM (SELECT a FROM postgres.public.source) AS b",
);
@ -2474,7 +2474,7 @@ pub mod tests {
#[test]
pub fn test_cte() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(dialect, "WITH cte_outer AS (SELECT a FROM postgres.public.source), cte_ignored AS (SELECT a FROM cte_outer), cte_inner AS (SELECT a FROM cte_outer) SELECT a FROM cte_inner");
let test = SpanTest::new(dialect, "WITH cte_outer AS (SELECT a FROM postgres.public.source), cte_ignored AS (SELECT a FROM cte_outer), cte_inner AS (SELECT a FROM cte_outer) SELECT a FROM cte_inner");
let query = test.0.parse_query().unwrap();
@ -2486,7 +2486,7 @@ pub mod tests {
#[test]
pub fn test_snowflake_lateral_flatten() {
let dialect = &SnowflakeDialect;
let mut test = SpanTest::new(dialect, "SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED");
let test = SpanTest::new(dialect, "SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED");
let query = test.0.parse_select().unwrap();
@ -2498,7 +2498,7 @@ pub mod tests {
#[test]
pub fn test_wildcard_from_cte() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(
let test = SpanTest::new(
dialect,
"WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte",
);
@ -2524,7 +2524,7 @@ pub mod tests {
#[test]
fn test_case_expr_span() {
let dialect = &GenericDialect;
let mut test = SpanTest::new(dialect, "CASE 1 WHEN 2 THEN 3 ELSE 4 END");
let test = SpanTest::new(dialect, "CASE 1 WHEN 2 THEN 3 ELSE 4 END");
let expr = test.0.parse_expr().unwrap();
let expr_span = expr.span();
assert_eq!(

View file

@ -46,7 +46,7 @@ const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
pub struct BigQueryDialect;
impl Dialect for BigQueryDialect {
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::BEGIN) {
if parser.peek_keyword(Keyword::TRANSACTION)
|| parser.peek_token_ref().token == Token::SemiColon
@ -145,7 +145,7 @@ impl Dialect for BigQueryDialect {
true
}
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_column_alias(&self, kw: &Keyword, _parser: &Parser) -> bool {
!RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}

View file

@ -466,7 +466,7 @@ pub trait Dialect: Debug + Any {
}
/// Dialect-specific prefix parser override
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
fn parse_prefix(&self, _parser: &Parser) -> Option<Result<Expr, ParserError>> {
// return None to fall back to the default behavior
None
}
@ -615,7 +615,7 @@ pub trait Dialect: Debug + Any {
/// If `None` is returned, falls back to the default behavior.
fn parse_infix(
&self,
_parser: &mut Parser,
_parser: &Parser,
_expr: &Expr,
_precedence: u8,
) -> Option<Result<Expr, ParserError>> {
@ -778,7 +778,7 @@ pub trait Dialect: Debug + Any {
/// This method is called to parse the next statement.
///
/// If `None` is returned, falls back to the default behavior.
fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, _parser: &Parser) -> Option<Result<Statement, ParserError>> {
// return None to fall back to the default behavior
None
}
@ -790,7 +790,7 @@ pub trait Dialect: Debug + Any {
/// If `None` is returned, falls back to the default behavior.
fn parse_column_option(
&self,
_parser: &mut Parser,
_parser: &Parser,
) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
// return None to fall back to the default behavior
Ok(None)
@ -1021,33 +1021,33 @@ pub trait Dialect: Debug + Any {
/// Returns true if the specified keyword should be parsed as a column identifier.
/// See [keywords::RESERVED_FOR_COLUMN_ALIAS]
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_column_alias(&self, kw: &Keyword, _parser: &Parser) -> bool {
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}
/// Returns true if the specified keyword should be parsed as a select item alias.
/// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
/// to enable looking ahead if needed.
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &Parser) -> bool {
explicit || self.is_column_alias(kw, parser)
}
/// Returns true if the specified keyword should be parsed as a table factor identifier.
/// See [keywords::RESERVED_FOR_TABLE_FACTOR]
fn is_table_factor(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_table_factor(&self, kw: &Keyword, _parser: &Parser) -> bool {
!keywords::RESERVED_FOR_TABLE_FACTOR.contains(kw)
}
/// Returns true if the specified keyword should be parsed as a table factor alias.
/// See [keywords::RESERVED_FOR_TABLE_ALIAS]
fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_table_alias(&self, kw: &Keyword, _parser: &Parser) -> bool {
!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
}
/// Returns true if the specified keyword should be parsed as a table factor alias.
/// When explicit is true, the keyword is preceded by an `AS` word. Parser is provided
/// to enable looking ahead if needed.
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &Parser) -> bool {
explicit || self.is_table_alias(kw, parser)
}
@ -1400,14 +1400,14 @@ mod tests {
fn parse_prefix(
&self,
parser: &mut sqlparser::parser::Parser,
parser: &sqlparser::parser::Parser,
) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
self.0.parse_prefix(parser)
}
fn parse_infix(
&self,
parser: &mut sqlparser::parser::Parser,
parser: &sqlparser::parser::Parser,
expr: &Expr,
precedence: u8,
) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
@ -1423,7 +1423,7 @@ mod tests {
fn parse_statement(
&self,
parser: &mut sqlparser::parser::Parser,
parser: &sqlparser::parser::Parser,
) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
self.0.parse_statement(parser)
}

View file

@ -128,11 +128,11 @@ impl Dialect for MsSqlDialect {
&[GranteesType::Public]
}
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_column_alias(&self, kw: &Keyword, _parser: &Parser) -> bool {
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.peek_keyword(Keyword::IF) {
Some(self.parse_if_stmt(parser))
} else if parser.parse_keywords(&[Keyword::CREATE, Keyword::TRIGGER]) {
@ -157,7 +157,7 @@ impl MsSqlDialect {
/// [ ELSE
/// { sql_statement | statement_block } ]
/// ```
fn parse_if_stmt(&self, parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_if_stmt(&self, parser: &Parser) -> Result<Statement, ParserError> {
let if_token = parser.expect_keyword(Keyword::IF)?;
let condition = parser.parse_expr()?;
@ -240,7 +240,7 @@ impl MsSqlDialect {
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
fn parse_create_trigger(
&self,
parser: &mut Parser,
parser: &Parser,
or_alter: bool,
) -> Result<Statement, ParserError> {
let name = parser.parse_object_name(false)?;
@ -279,7 +279,7 @@ impl MsSqlDialect {
/// Stops parsing when reaching EOF or the given keyword.
fn parse_statement_list(
&self,
parser: &mut Parser,
parser: &Parser,
terminal_keyword: Option<Keyword>,
) -> Result<Vec<Statement>, ParserError> {
let mut stmts = Vec::new();

View file

@ -86,7 +86,7 @@ impl Dialect for MySqlDialect {
fn parse_infix(
&self,
parser: &mut crate::parser::Parser,
parser: &crate::parser::Parser,
expr: &crate::ast::Expr,
_precedence: u8,
) -> Option<Result<crate::ast::Expr, ParserError>> {
@ -102,7 +102,7 @@ impl Dialect for MySqlDialect {
}
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keywords(&[Keyword::LOCK, Keyword::TABLES]) {
Some(parse_lock_tables(parser))
} else if parser.parse_keywords(&[Keyword::UNLOCK, Keyword::TABLES]) {
@ -134,7 +134,7 @@ impl Dialect for MySqlDialect {
true
}
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser: &mut Parser) -> bool {
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser: &Parser) -> bool {
explicit
|| (!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
&& !RESERVED_FOR_TABLE_ALIAS_MYSQL.contains(kw))
@ -171,13 +171,13 @@ impl Dialect for MySqlDialect {
/// `LOCK TABLES`
/// <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
fn parse_lock_tables(parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_lock_tables(parser: &Parser) -> Result<Statement, ParserError> {
let tables = parser.parse_comma_separated(parse_lock_table)?;
Ok(Statement::LockTables { tables })
}
// tbl_name [[AS] alias] lock_type
fn parse_lock_table(parser: &mut Parser) -> Result<LockTable, ParserError> {
fn parse_lock_table(parser: &Parser) -> Result<LockTable, ParserError> {
let table = parser.parse_identifier()?;
let alias =
parser.parse_optional_alias(&[Keyword::READ, Keyword::WRITE, Keyword::LOW_PRIORITY])?;
@ -191,7 +191,7 @@ fn parse_lock_table(parser: &mut Parser) -> Result<LockTable, ParserError> {
}
// READ [LOCAL] | [LOW_PRIORITY] WRITE
fn parse_lock_tables_type(parser: &mut Parser) -> Result<LockTableType, ParserError> {
fn parse_lock_tables_type(parser: &Parser) -> Result<LockTableType, ParserError> {
if parser.parse_keyword(Keyword::READ) {
if parser.parse_keyword(Keyword::LOCAL) {
Ok(LockTableType::Read { local: true })
@ -211,6 +211,6 @@ fn parse_lock_tables_type(parser: &mut Parser) -> Result<LockTableType, ParserEr
/// UNLOCK TABLES
/// <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
fn parse_unlock_tables(_parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_unlock_tables(_parser: &Parser) -> Result<Statement, ParserError> {
Ok(Statement::UnlockTables)
}

View file

@ -211,7 +211,7 @@ impl Dialect for SnowflakeDialect {
true
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::BEGIN) {
return Some(parser.parse_begin_exception_end());
}
@ -318,7 +318,7 @@ impl Dialect for SnowflakeDialect {
fn parse_column_option(
&self,
parser: &mut Parser,
parser: &Parser,
) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
parser.maybe_parse(|parser| {
let with = parser.parse_keyword(Keyword::WITH);
@ -391,7 +391,7 @@ impl Dialect for SnowflakeDialect {
true
}
fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
fn is_column_alias(&self, kw: &Keyword, parser: &Parser) -> bool {
match kw {
// The following keywords can be considered an alias as long as
// they are not followed by other tokens that may change their meaning
@ -437,7 +437,7 @@ impl Dialect for SnowflakeDialect {
}
}
fn is_table_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
fn is_table_alias(&self, kw: &Keyword, parser: &Parser) -> bool {
match kw {
// The following keywords can be considered an alias as long as
// they are not followed by other tokens that may change their meaning
@ -521,7 +521,7 @@ impl Dialect for SnowflakeDialect {
}
}
fn is_table_factor(&self, kw: &Keyword, parser: &mut Parser) -> bool {
fn is_table_factor(&self, kw: &Keyword, parser: &Parser) -> bool {
match kw {
Keyword::LIMIT if peek_for_limit_options(parser) => false,
// Table function
@ -591,7 +591,7 @@ fn peek_for_limit_options(parser: &Parser) -> bool {
}
}
fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_file_staging_command(kw: Keyword, parser: &Parser) -> Result<Statement, ParserError> {
let stage = parse_snowflake_stage_name(parser)?;
let pattern = if parser.parse_keyword(Keyword::PATTERN) {
parser.expect_token(&Token::Eq)?;
@ -613,7 +613,7 @@ fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statem
/// Parse snowflake alter dynamic table.
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_alter_dynamic_table(parser: &Parser) -> Result<Statement, ParserError> {
// Use parse_object_name(true) to support IDENTIFIER() function
let table_name = parser.parse_object_name(true)?;
@ -651,7 +651,7 @@ fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserErr
/// Parse snowflake alter session.
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-session>
fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
fn parse_alter_session(parser: &Parser, set: bool) -> Result<Statement, ParserError> {
let session_options = parse_session_options(parser, set)?;
Ok(Statement::AlterSession {
set,
@ -674,7 +674,7 @@ pub fn parse_create_table(
transient: bool,
iceberg: bool,
dynamic: bool,
parser: &mut Parser,
parser: &Parser,
) -> Result<Statement, ParserError> {
let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
let table_name = parser.parse_object_name(false)?;
@ -912,7 +912,7 @@ pub fn parse_create_table(
pub fn parse_create_database(
or_replace: bool,
transient: bool,
parser: &mut Parser,
parser: &Parser,
) -> Result<Statement, ParserError> {
let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
let name = parser.parse_object_name(false)?;
@ -1017,7 +1017,7 @@ pub fn parse_create_database(
}
pub fn parse_storage_serialization_policy(
parser: &mut Parser,
parser: &Parser,
) -> Result<StorageSerializationPolicy, ParserError> {
let next_token = parser.next_token();
match &next_token.token {
@ -1033,7 +1033,7 @@ pub fn parse_storage_serialization_policy(
pub fn parse_create_stage(
or_replace: bool,
temporary: bool,
parser: &mut Parser,
parser: &Parser,
) -> Result<Statement, ParserError> {
//[ IF NOT EXISTS ]
let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
@ -1092,7 +1092,7 @@ pub fn parse_create_stage(
})
}
pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
pub fn parse_stage_name_identifier(parser: &Parser) -> Result<Ident, ParserError> {
let mut ident = String::new();
while let Some(next_token) = parser.next_token_no_skip() {
match &next_token.token {
@ -1119,7 +1119,7 @@ pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserE
Ok(Ident::new(ident))
}
pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
pub fn parse_snowflake_stage_name(parser: &Parser) -> Result<ObjectName, ParserError> {
match parser.next_token().token {
Token::AtSign => {
parser.prev_token();
@ -1141,7 +1141,7 @@ pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, Par
/// Parses a `COPY INTO` statement. Snowflake has two variants, `COPY INTO <table>`
/// and `COPY INTO <location>` which have different syntax.
pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
pub fn parse_copy_into(parser: &Parser) -> Result<Statement, ParserError> {
let kind = match parser.peek_token().token {
// Indicates an internal stage
Token::AtSign => CopyIntoSnowflakeKind::Location,
@ -1303,7 +1303,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
}
fn parse_select_items_for_data_load(
parser: &mut Parser,
parser: &Parser,
) -> Result<Option<Vec<StageLoadSelectItemKind>>, ParserError> {
let mut select_items: Vec<StageLoadSelectItemKind> = vec![];
loop {
@ -1324,9 +1324,7 @@ fn parse_select_items_for_data_load(
Ok(Some(select_items))
}
fn parse_select_item_for_data_load(
parser: &mut Parser,
) -> Result<StageLoadSelectItem, ParserError> {
fn parse_select_item_for_data_load(parser: &Parser) -> Result<StageLoadSelectItem, ParserError> {
let mut alias: Option<Ident> = None;
let mut file_col_num: i32 = 0;
let mut element: Option<Ident> = None;
@ -1393,7 +1391,7 @@ fn parse_select_item_for_data_load(
})
}
fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
fn parse_stage_params(parser: &Parser) -> Result<StageParamsObject, ParserError> {
let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
let mut encryption: KeyValueOptions = KeyValueOptions {
options: vec![],
@ -1459,10 +1457,7 @@ fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserEr
/// ABORT_DETACHED_QUERY = { TRUE | FALSE }
/// [ ACTIVE_PYTHON_PROFILER = { 'LINE' | 'MEMORY' } ]
/// [ BINARY_INPUT_FORMAT = '\<string\>' ]
fn parse_session_options(
parser: &mut Parser,
set: bool,
) -> Result<Vec<KeyValueOption>, ParserError> {
fn parse_session_options(parser: &Parser, set: bool) -> Result<Vec<KeyValueOption>, ParserError> {
let mut options: Vec<KeyValueOption> = Vec::new();
let empty = String::new;
loop {
@ -1505,7 +1500,7 @@ fn parse_session_options(
/// [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
fn parse_identity_property(parser: &Parser) -> Result<IdentityProperty, ParserError> {
let parameters = if parser.consume_token(&Token::LParen) {
let seed = parser.parse_number()?;
parser.expect_token(&Token::Comma)?;
@ -1541,7 +1536,7 @@ fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, Pars
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
fn parse_column_policy_property(
parser: &mut Parser,
parser: &Parser,
with: bool,
) -> Result<ColumnPolicyProperty, ParserError> {
let policy_name = parser.parse_object_name(false)?;
@ -1567,7 +1562,7 @@ fn parse_column_policy_property(
/// ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
fn parse_column_tags(parser: &Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
parser.expect_token(&Token::LParen)?;
let tags = parser.parse_comma_separated(Parser::parse_tag)?;
parser.expect_token(&Token::RParen)?;
@ -1577,7 +1572,7 @@ fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption
/// Parse snowflake show objects.
/// <https://docs.snowflake.com/en/sql-reference/sql/show-objects>
fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
fn parse_show_objects(terse: bool, parser: &Parser) -> Result<Statement, ParserError> {
let show_options = parser.parse_show_stmt_options()?;
Ok(Statement::ShowObjects(ShowObjects {
terse,

View file

@ -65,7 +65,7 @@ impl Dialect for SQLiteDialect {
self.is_identifier_start(ch) || ch.is_ascii_digit()
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::REPLACE) {
parser.prev_token();
Some(parser.parse_insert(parser.get_current_token().clone()))
@ -76,7 +76,7 @@ impl Dialect for SQLiteDialect {
fn parse_infix(
&self,
parser: &mut crate::parser::Parser,
parser: &crate::parser::Parser,
expr: &crate::ast::Expr,
_precedence: u8,
) -> Option<Result<crate::ast::Expr, ParserError>> {

View file

@ -30,7 +30,7 @@ use crate::{
};
impl Parser<'_> {
pub fn parse_alter_role(&mut self) -> Result<Statement, ParserError> {
pub fn parse_alter_role(&self) -> Result<Statement, ParserError> {
if dialect_of!(self is PostgreSqlDialect) {
return self.parse_pg_alter_role();
} else if dialect_of!(self is MsSqlDialect) {
@ -53,7 +53,7 @@ impl Parser<'_> {
/// ```
///
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterpolicy.html)
pub fn parse_alter_policy(&mut self) -> Result<Statement, ParserError> {
pub fn parse_alter_policy(&self) -> Result<Statement, ParserError> {
let name = self.parse_identifier()?;
self.expect_keyword_is(Keyword::ON)?;
let table_name = self.parse_object_name(false)?;
@ -110,7 +110,7 @@ impl Parser<'_> {
///
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
/// ```
pub fn parse_alter_connector(&mut self) -> Result<Statement, ParserError> {
pub fn parse_alter_connector(&self) -> Result<Statement, ParserError> {
let name = self.parse_identifier()?;
self.expect_keyword_is(Keyword::SET)?;
@ -147,7 +147,7 @@ impl Parser<'_> {
/// ```sql
/// ALTER USER [ IF EXISTS ] [ <name> ] [ OPTIONS ]
/// ```
pub fn parse_alter_user(&mut self) -> Result<Statement, ParserError> {
pub fn parse_alter_user(&self) -> Result<Statement, ParserError> {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let name = self.parse_identifier()?;
let rename_to = if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
@ -314,7 +314,7 @@ impl Parser<'_> {
}))
}
fn parse_mfa_method(&mut self) -> Result<MfaMethodKind, ParserError> {
fn parse_mfa_method(&self) -> Result<MfaMethodKind, ParserError> {
if self.parse_keyword(Keyword::PASSKEY) {
Ok(MfaMethodKind::PassKey)
} else if self.parse_keyword(Keyword::TOTP) {
@ -326,7 +326,7 @@ impl Parser<'_> {
}
}
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
fn parse_mssql_alter_role(&self) -> Result<Statement, ParserError> {
let role_name = self.parse_identifier()?;
let operation = if self.parse_keywords(&[Keyword::ADD, Keyword::MEMBER]) {
@ -352,7 +352,7 @@ impl Parser<'_> {
})
}
fn parse_pg_alter_role(&mut self) -> Result<Statement, ParserError> {
fn parse_pg_alter_role(&self) -> Result<Statement, ParserError> {
let role_name = self.parse_identifier()?;
// [ IN DATABASE _`database_name`_ ]
@ -436,7 +436,7 @@ impl Parser<'_> {
})
}
fn parse_pg_role_option(&mut self) -> Result<RoleOption, ParserError> {
fn parse_pg_role_option(&self) -> Result<RoleOption, ParserError> {
let option = match self.parse_one_of_keywords(&[
Keyword::BYPASSRLS,
Keyword::NOBYPASSRLS,

File diff suppressed because it is too large Load diff

View file

@ -311,8 +311,7 @@ fn parse_insert_default_values() {
fn parse_insert_select_returning() {
// Dialects that support `RETURNING` as a column identifier do
// not support this syntax.
let dialects =
all_dialects_where(|d| !d.is_column_alias(&Keyword::RETURNING, &mut Parser::new(d)));
let dialects = all_dialects_where(|d| !d.is_column_alias(&Keyword::RETURNING, &Parser::new(d)));
dialects.verified_stmt("INSERT INTO t SELECT 1 RETURNING 2");
let stmt = dialects.verified_stmt("INSERT INTO t SELECT x RETURNING x AS y");
@ -5655,7 +5654,7 @@ fn parse_named_window_functions() {
WINDOW w AS (PARTITION BY x), win AS (ORDER BY y)";
supported_dialects.verified_stmt(sql);
let select = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &mut Parser::new(d)))
let select = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &Parser::new(d)))
.verified_only_select(sql);
const EXPECTED_PROJ_QTY: usize = 2;
@ -5686,7 +5685,7 @@ fn parse_named_window_functions() {
#[test]
fn parse_window_clause() {
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &mut Parser::new(d)));
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &Parser::new(d)));
let sql = "SELECT * \
FROM mytable \
WINDOW \
@ -5705,7 +5704,7 @@ fn parse_window_clause() {
let dialects = all_dialects_except(|d| {
d.is::<BigQueryDialect>()
|| d.is::<GenericDialect>()
|| d.is_table_alias(&Keyword::WINDOW, &mut Parser::new(d))
|| d.is_table_alias(&Keyword::WINDOW, &Parser::new(d))
});
let res = dialects.parse_sql_statements(sql);
assert_eq!(
@ -5716,7 +5715,7 @@ fn parse_window_clause() {
#[test]
fn test_parse_named_window() {
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &mut Parser::new(d)));
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::WINDOW, &Parser::new(d)));
let sql = "SELECT \
MIN(c12) OVER window1 AS min1, \
MAX(c12) OVER window2 AS max1 \
@ -5875,8 +5874,8 @@ fn test_parse_named_window() {
#[test]
fn parse_window_and_qualify_clause() {
let dialects = all_dialects_except(|d| {
d.is_table_alias(&Keyword::WINDOW, &mut Parser::new(d))
|| d.is_table_alias(&Keyword::QUALIFY, &mut Parser::new(d))
d.is_table_alias(&Keyword::WINDOW, &Parser::new(d))
|| d.is_table_alias(&Keyword::QUALIFY, &Parser::new(d))
});
let sql = "SELECT \
MIN(c12) OVER window1 AS min1 \
@ -7614,7 +7613,7 @@ fn parse_join_syntax_variants() {
"SELECT c1 FROM t1 FULL JOIN t2 USING(c1)",
);
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::OUTER, &mut Parser::new(d)));
let dialects = all_dialects_except(|d| d.is_table_alias(&Keyword::OUTER, &Parser::new(d)));
let res = dialects.parse_sql_statements("SELECT * FROM a OUTER JOIN b ON 1");
assert_eq!(
ParserError::ParserError("Expected: APPLY, found: JOIN".to_string()),
@ -7829,7 +7828,7 @@ fn parse_union_except_intersect_minus() {
// Dialects that support `MINUS` as column identifier
// do not support `MINUS` as a set operator.
let dialects = all_dialects_where(|d| !d.is_column_alias(&Keyword::MINUS, &mut Parser::new(d)));
let dialects = all_dialects_where(|d| !d.is_column_alias(&Keyword::MINUS, &Parser::new(d)));
dialects.verified_stmt("SELECT 1 MINUS SELECT 2");
dialects.verified_stmt("SELECT 1 MINUS ALL SELECT 2");
dialects.verified_stmt("SELECT 1 MINUS DISTINCT SELECT 1");
@ -8592,8 +8591,7 @@ fn parse_invalid_subquery_without_parens() {
fn parse_offset() {
// Dialects that support `OFFSET` as column identifiers
// don't support this syntax.
let dialects =
all_dialects_where(|d| !d.is_column_alias(&Keyword::OFFSET, &mut Parser::new(d)));
let dialects = all_dialects_where(|d| !d.is_column_alias(&Keyword::OFFSET, &Parser::new(d)));
let expected_limit_clause = &Some(LimitClause::LimitOffset {
limit: None,
@ -12454,7 +12452,7 @@ fn test_buffer_reuse() {
Tokenizer::new(&d, q)
.tokenize_with_location_into_buf(&mut buf)
.unwrap();
let mut p = Parser::new(&d).with_tokens_with_locations(buf);
let p = Parser::new(&d).with_tokens_with_locations(buf);
p.parse_statements().unwrap();
let _ = p.into_tokens();
}
@ -15368,7 +15366,7 @@ fn parse_case_statement() {
#[test]
fn test_case_statement_span() {
let sql = "CASE 1 WHEN 2 THEN SELECT 1; SELECT 2; ELSE SELECT 3; END CASE";
let mut parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
let parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
assert_eq!(
parser.parse_statement().unwrap().span(),
Span::new(Location::new(1, 1), Location::new(1, sql.len() as u64 + 1))
@ -15449,7 +15447,7 @@ fn parse_if_statement() {
#[test]
fn test_if_statement_span() {
let sql = "IF 1=1 THEN SELECT 1; ELSEIF 1=2 THEN SELECT 2; ELSE SELECT 3; END IF";
let mut parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
let parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
assert_eq!(
parser.parse_statement().unwrap().span(),
Span::new(Location::new(1, 1), Location::new(1, sql.len() as u64 + 1))
@ -15463,7 +15461,7 @@ fn test_if_statement_multiline_span() {
let sql_line3 = "ELSE SELECT 3;";
let sql_line4 = "END IF";
let sql = [sql_line1, sql_line2, sql_line3, sql_line4].join("\n");
let mut parser = Parser::new(&GenericDialect {}).try_with_sql(&sql).unwrap();
let parser = Parser::new(&GenericDialect {}).try_with_sql(&sql).unwrap();
assert_eq!(
parser.parse_statement().unwrap().span(),
Span::new(
@ -15476,7 +15474,7 @@ fn test_if_statement_multiline_span() {
#[test]
fn test_conditional_statement_span() {
let sql = "IF 1=1 THEN SELECT 1; ELSEIF 1=2 THEN SELECT 2; ELSE SELECT 3; END IF";
let mut parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
let parser = Parser::new(&GenericDialect {}).try_with_sql(sql).unwrap();
match parser.parse_statement().unwrap() {
Statement::If(IfStatement {
if_block,
@ -16958,7 +16956,7 @@ fn test_select_exclude() {
let dialects = all_dialects_where(|d| {
d.supports_select_wildcard_exclude()
&& !d.supports_select_exclude()
&& d.is_column_alias(&Keyword::EXCLUDE, &mut Parser::new(d))
&& d.is_column_alias(&Keyword::EXCLUDE, &Parser::new(d))
});
assert_eq!(
dialects
@ -16973,7 +16971,7 @@ fn test_select_exclude() {
let dialects = all_dialects_where(|d| {
d.supports_select_wildcard_exclude()
&& !d.supports_select_exclude()
&& !d.is_column_alias(&Keyword::EXCLUDE, &mut Parser::new(d))
&& !d.is_column_alias(&Keyword::EXCLUDE, &Parser::new(d))
});
assert_eq!(
dialects

View file

@ -39,7 +39,7 @@ fn custom_prefix_parser() -> Result<(), ParserError> {
is_identifier_part(ch)
}
fn parse_prefix(&self, parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
fn parse_prefix(&self, parser: &Parser) -> Option<Result<Expr, ParserError>> {
if parser.consume_token(&Token::Number("1".to_string(), false)) {
Some(Ok(Expr::Value(Value::Null.with_empty_span())))
} else {
@ -72,7 +72,7 @@ fn custom_infix_parser() -> Result<(), ParserError> {
fn parse_infix(
&self,
parser: &mut Parser,
parser: &Parser,
expr: &Expr,
_precedence: u8,
) -> Option<Result<Expr, ParserError>> {
@ -110,7 +110,7 @@ fn custom_statement_parser() -> Result<(), ParserError> {
is_identifier_part(ch)
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
fn parse_statement(&self, parser: &Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::SELECT) {
for _ in 0..3 {
let _ = parser.next_token();

View file

@ -2213,7 +2213,7 @@ fn parse_mssql_if_else() {
#[test]
fn test_mssql_if_else_span() {
let sql = "IF 1 = 1 SELECT '1' ELSE SELECT '2'";
let mut parser = Parser::new(&MsSqlDialect {}).try_with_sql(sql).unwrap();
let parser = Parser::new(&MsSqlDialect {}).try_with_sql(sql).unwrap();
assert_eq!(
parser.parse_statement().unwrap().span(),
Span::new(Location::new(1, 1), Location::new(1, sql.len() as u64 + 1))
@ -2226,7 +2226,7 @@ fn test_mssql_if_else_multiline_span() {
let sql_line2 = "SELECT '1'";
let sql_line3 = "ELSE SELECT '2'";
let sql = [sql_line1, sql_line2, sql_line3].join("\n");
let mut parser = Parser::new(&MsSqlDialect {}).try_with_sql(&sql).unwrap();
let parser = Parser::new(&MsSqlDialect {}).try_with_sql(&sql).unwrap();
assert_eq!(
parser.parse_statement().unwrap().span(),
Span::new(