From b8e9e95051f314d8445e645c209dc8bebbd89dbd Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Tue, 10 Mar 2026 14:35:13 +0100 Subject: [PATCH 1/9] [Oracle] Support for `INSERT INTO () ...` --- src/ast/mod.rs | 15 +++++++++++++-- src/ast/spans.rs | 1 + src/dialect/mod.rs | 7 +++++++ src/dialect/oracle.rs | 4 ++++ src/parser/mod.rs | 14 ++++++++++---- tests/sqlparser_oracle.rs | 40 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c4d1b50cd..3ca3b4019 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -117,8 +117,8 @@ pub use self::trigger::{ }; pub use self::value::{ - escape_double_quote_string, escape_quoted_string, DateTimeField, DollarQuotedString, - NormalizationForm, QuoteDelimitedString, TrimWhereField, Value, ValueWithSpan, + DateTimeField, DollarQuotedString, NormalizationForm, QuoteDelimitedString, TrimWhereField, + Value, ValueWithSpan, escape_double_quote_string, escape_quoted_string, }; use crate::ast::helpers::key_value_options::KeyValueOptions; @@ -10888,6 +10888,16 @@ pub enum TableObject { /// ``` /// [Clickhouse](https://clickhouse.com/docs/en/sql-reference/table-functions) TableFunction(Function), + + /// Table specified through a sub-query + /// Example: + /// ```sql + /// INSERT INTO + /// (SELECT employee_id, last_name, email, hire_date, job_id, salary, commission_pct FROM employees) + /// VALUES (207, 'Gregory', 'pgregory@example.com', sysdate, 'PU_CLERK', 1.2E3, NULL); + /// ``` + /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423__I2126242) + TableQuery(Box), } impl fmt::Display for TableObject { @@ -10895,6 +10905,7 @@ impl fmt::Display for TableObject { match self { Self::TableName(table_name) => write!(f, "{table_name}"), Self::TableFunction(func) => write!(f, "FUNCTION {func}"), + Self::TableQuery(table_query) => write!(f, "({table_query})"), } } } diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 74f731a78..78698bbed 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -2387,6 +2387,7 @@ impl Spanned for TableObject { union_spans(segments.iter().map(|i| i.span())) } TableObject::TableFunction(func) => func.span(), + TableObject::TableQuery(query) => query.span(), } } } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 8703e402c..fed81b60a 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1247,6 +1247,13 @@ pub trait Dialect: Debug + Any { false } + /// Does the dialect support table queries in insertion? + /// + /// e.g. `SELECT INTO () ...` + fn supports_insert_table_query(&self) -> bool { + false + } + /// Does the dialect support insert formats, e.g. `INSERT INTO ... FORMAT ` fn supports_insert_format(&self) -> bool { false diff --git a/src/dialect/oracle.rs b/src/dialect/oracle.rs index dce0493d3..89cb9becb 100644 --- a/src/dialect/oracle.rs +++ b/src/dialect/oracle.rs @@ -114,4 +114,8 @@ impl Dialect for OracleDialect { fn supports_insert_table_alias(&self) -> bool { true } + + fn supports_insert_table_query(&self) -> bool { + true + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6adecb0c6..75ca5746f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12688,6 +12688,8 @@ impl<'a> Parser<'a> { let fn_name = self.parse_object_name(false)?; self.parse_function_call(fn_name) .map(TableObject::TableFunction) + } else if self.dialect.supports_insert_table_query() && self.peek_subquery_start(true) { + self.parse_parenthesized(|p| p.parse_query()).map(TableObject::TableQuery) } else { self.parse_object_name(false).map(TableObject::TableName) } @@ -17434,7 +17436,7 @@ impl<'a> Parser<'a> { { (vec![], None, vec![], None, None, vec![]) } else { - let (columns, partitioned, after_columns) = if !self.peek_subquery_start() { + let (columns, partitioned, after_columns) = if !self.peek_subquery_start(false) { let columns = self.parse_parenthesized_qualified_column_list(Optional, is_mysql)?; @@ -17599,11 +17601,15 @@ impl<'a> Parser<'a> { } /// Returns true if the immediate tokens look like the - /// beginning of a subquery. `(SELECT ...` - fn peek_subquery_start(&mut self) -> bool { + /// beginning of a subquery, e.g. `(SELECT ...`. + /// + /// If `full_query == true` attempt to detect a full query with its + /// optional, leading `WITH` clause, e.g. `(WITH ...)` + fn peek_subquery_start(&mut self, full_query: bool) -> bool { let [maybe_lparen, maybe_select] = self.peek_tokens(); Token::LParen == maybe_lparen - && matches!(maybe_select, Token::Word(w) if w.keyword == Keyword::SELECT) + && matches!(maybe_select, Token::Word(w) + if w.keyword == Keyword::SELECT || (full_query && w.keyword == Keyword::WITH)) } fn parse_conflict_clause(&mut self) -> Option { diff --git a/tests/sqlparser_oracle.rs b/tests/sqlparser_oracle.rs index 35f083111..d50f9fb5a 100644 --- a/tests/sqlparser_oracle.rs +++ b/tests/sqlparser_oracle.rs @@ -22,14 +22,15 @@ use pretty_assertions::assert_eq; use sqlparser::{ ast::{ - BinaryOperator, Expr, Ident, Insert, ObjectName, Query, QuoteDelimitedString, SetExpr, - Statement, TableAliasWithoutColumns, TableObject, Value, ValueWithSpan, + BinaryOperator, Expr, Ident, Insert, ObjectName, ObjectNamePart, Query, + QuoteDelimitedString, Select, SelectItem, SetExpr, Statement, TableAliasWithoutColumns, + TableFactor, TableObject, TableWithJoins, Value, ValueWithSpan, }, dialect::OracleDialect, parser::ParserError, tokenizer::Span, }; -use test_utils::{all_dialects_where, expr_from_projection, number, TestedDialects}; +use test_utils::{TestedDialects, all_dialects_where, expr_from_projection, number}; mod test_utils; @@ -542,3 +543,36 @@ fn test_insert_without_alias() { if matches!(&*source, Query { body, .. } if matches!(&**body, SetExpr::Values(_))) )); } + +#[test] +fn test_insert_with_query_table() { + let oracle_dialect = oracle(); + + // a simple query (block); i.e. SELECT ... + let sql = "INSERT INTO (SELECT employee_id, last_name FROM employees) VALUES (207, 'Gregory')"; + oracle_dialect.verified_stmt(sql); + + // a full blown query; i.e. `WITH ... SELECT .. ORDER BY ...` + let sql = "INSERT INTO \ + (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ + WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id) ORDER BY 1, 2) \ + (id, val) \ + VALUES (1000, 10101)"; + oracle_dialect.verified_stmt(sql); + + // an alias to the insert target query table + let sql = "INSERT INTO \ + (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ + WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id)) abc \ + (id, val) \ + VALUES (1000, 10101)"; + oracle_dialect.verified_stmt(sql); + + // a query table target and a query source + let sql = "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) SELECT 10, 20 FROM dual"; + oracle_dialect.verified_stmt(sql); + + // a query table target and a query source, with explicit columns + let sql = "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) (id, val) SELECT 10, 20 FROM dual"; + oracle_dialect.verified_stmt(sql); +} From a22c74d33c9694138a8311f6665d808a6591d61a Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Tue, 10 Mar 2026 14:35:41 +0100 Subject: [PATCH 2/9] Cargo fmt --- src/ast/mod.rs | 4 ++-- src/parser/mod.rs | 3 ++- tests/sqlparser_oracle.rs | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3ca3b4019..36c41d6ca 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -117,8 +117,8 @@ pub use self::trigger::{ }; pub use self::value::{ - DateTimeField, DollarQuotedString, NormalizationForm, QuoteDelimitedString, TrimWhereField, - Value, ValueWithSpan, escape_double_quote_string, escape_quoted_string, + escape_double_quote_string, escape_quoted_string, DateTimeField, DollarQuotedString, + NormalizationForm, QuoteDelimitedString, TrimWhereField, Value, ValueWithSpan, }; use crate::ast::helpers::key_value_options::KeyValueOptions; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 75ca5746f..55dac9c81 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12689,7 +12689,8 @@ impl<'a> Parser<'a> { self.parse_function_call(fn_name) .map(TableObject::TableFunction) } else if self.dialect.supports_insert_table_query() && self.peek_subquery_start(true) { - self.parse_parenthesized(|p| p.parse_query()).map(TableObject::TableQuery) + self.parse_parenthesized(|p| p.parse_query()) + .map(TableObject::TableQuery) } else { self.parse_object_name(false).map(TableObject::TableName) } diff --git a/tests/sqlparser_oracle.rs b/tests/sqlparser_oracle.rs index d50f9fb5a..49ffee5bc 100644 --- a/tests/sqlparser_oracle.rs +++ b/tests/sqlparser_oracle.rs @@ -30,7 +30,7 @@ use sqlparser::{ parser::ParserError, tokenizer::Span, }; -use test_utils::{TestedDialects, all_dialects_where, expr_from_projection, number}; +use test_utils::{all_dialects_where, expr_from_projection, number, TestedDialects}; mod test_utils; @@ -573,6 +573,7 @@ fn test_insert_with_query_table() { oracle_dialect.verified_stmt(sql); // a query table target and a query source, with explicit columns - let sql = "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) (id, val) SELECT 10, 20 FROM dual"; + let sql = + "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) (id, val) SELECT 10, 20 FROM dual"; oracle_dialect.verified_stmt(sql); } From 48856a8400f7c5640a76da676105bdb201f7825f Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Tue, 10 Mar 2026 14:42:53 +0100 Subject: [PATCH 3/9] Remove unused imports --- tests/sqlparser_oracle.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/sqlparser_oracle.rs b/tests/sqlparser_oracle.rs index 49ffee5bc..e84fb6b84 100644 --- a/tests/sqlparser_oracle.rs +++ b/tests/sqlparser_oracle.rs @@ -22,9 +22,8 @@ use pretty_assertions::assert_eq; use sqlparser::{ ast::{ - BinaryOperator, Expr, Ident, Insert, ObjectName, ObjectNamePart, Query, - QuoteDelimitedString, Select, SelectItem, SetExpr, Statement, TableAliasWithoutColumns, - TableFactor, TableObject, TableWithJoins, Value, ValueWithSpan, + BinaryOperator, Expr, Ident, Insert, ObjectName, Query, QuoteDelimitedString, SetExpr, + Statement, TableAliasWithoutColumns, TableObject, Value, ValueWithSpan, }, dialect::OracleDialect, parser::ParserError, From 1dee2d5e7c0c05fe6522214840dd951be4ac7029 Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 16:21:25 +0100 Subject: [PATCH 4/9] Link relevant documentation --- src/dialect/oracle.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dialect/oracle.rs b/src/dialect/oracle.rs index 89cb9becb..ccbef5b62 100644 --- a/src/dialect/oracle.rs +++ b/src/dialect/oracle.rs @@ -115,6 +115,7 @@ impl Dialect for OracleDialect { true } + /// See fn supports_insert_table_query(&self) -> bool { true } From fcda7d7941dab8f68b87fbb6d362003f271e0040 Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 16:27:47 +0100 Subject: [PATCH 5/9] Generalize test for all dialects --- tests/sqlparser_common.rs | 34 ++++++++++++++++++++++++++++++++++ tests/sqlparser_oracle.rs | 34 ---------------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 08fb6107f..6f9e46959 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -13525,6 +13525,40 @@ fn insert_into_with_parentheses() { dialects.verified_stmt(r#"INSERT INTO t1 ("select", name) (SELECT t2.name FROM t2)"#); } +#[test] +fn test_insert_with_query_table() { + let dialects = all_dialects_where(|d| d.supports_insert_table_query()); + + // a simple query (block); i.e. SELECT ... + let sql = "INSERT INTO (SELECT employee_id, last_name FROM employees) VALUES (207, 'Gregory')"; + dialects.verified_stmt(sql); + + // a full blown query; i.e. `WITH ... SELECT .. ORDER BY ...` + let sql = "INSERT INTO \ + (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ + WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id) ORDER BY 1, 2) \ + (id, val) \ + VALUES (1000, 10101)"; + dialects.verified_stmt(sql); + + // an alias to the insert target query table + let sql = "INSERT INTO \ + (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ + WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id)) abc \ + (id, val) \ + VALUES (1000, 10101)"; + dialects.verified_stmt(sql); + + // a query table target and a query source + let sql = "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) SELECT 10, 20 FROM dual"; + dialects.verified_stmt(sql); + + // a query table target and a query source, with explicit columns + let sql = + "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) (id, val) SELECT 10, 20 FROM dual"; + dialects.verified_stmt(sql); +} + #[test] fn parse_odbc_scalar_function() { let select = verified_only_select("SELECT {fn my_func(1, 2)}"); diff --git a/tests/sqlparser_oracle.rs b/tests/sqlparser_oracle.rs index e84fb6b84..35f083111 100644 --- a/tests/sqlparser_oracle.rs +++ b/tests/sqlparser_oracle.rs @@ -542,37 +542,3 @@ fn test_insert_without_alias() { if matches!(&*source, Query { body, .. } if matches!(&**body, SetExpr::Values(_))) )); } - -#[test] -fn test_insert_with_query_table() { - let oracle_dialect = oracle(); - - // a simple query (block); i.e. SELECT ... - let sql = "INSERT INTO (SELECT employee_id, last_name FROM employees) VALUES (207, 'Gregory')"; - oracle_dialect.verified_stmt(sql); - - // a full blown query; i.e. `WITH ... SELECT .. ORDER BY ...` - let sql = "INSERT INTO \ - (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ - WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id) ORDER BY 1, 2) \ - (id, val) \ - VALUES (1000, 10101)"; - oracle_dialect.verified_stmt(sql); - - // an alias to the insert target query table - let sql = "INSERT INTO \ - (WITH cte AS (SELECT 1 AS id, 2 AS val FROM dual) SELECT foo_t.id, foo_t.val FROM foo_t \ - WHERE EXISTS (SELECT 1 FROM cte WHERE cte.id = foo_t.id)) abc \ - (id, val) \ - VALUES (1000, 10101)"; - oracle_dialect.verified_stmt(sql); - - // a query table target and a query source - let sql = "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) SELECT 10, 20 FROM dual"; - oracle_dialect.verified_stmt(sql); - - // a query table target and a query source, with explicit columns - let sql = - "INSERT INTO (SELECT foo_t.id, foo_t.val FROM foo_t) (id, val) SELECT 10, 20 FROM dual"; - oracle_dialect.verified_stmt(sql); -} From 6300ab90acc0ed034e8f742d944a339ace2c7db3 Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 16:59:12 +0100 Subject: [PATCH 6/9] Simplify method by separation --- src/parser/mod.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 55dac9c81..89888f575 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -4692,6 +4692,17 @@ impl<'a> Parser<'a> { } } + /// Returns `true` if the current token matches `token` and is further + /// followed by one of the specified `keywords`. + /// + /// Does not advance the current token. + #[must_use] + fn peek_token_with_one_of_keywords(&mut self, token: &Token, keywords: &[Keyword]) -> bool { + let [maybe_token, maybe_keyword] = self.peek_tokens_ref(); + &maybe_token.token == token + && matches!(&maybe_keyword.token, Token::Word(w) if keywords.contains(&w.keyword)) + } + /// If the current token is one of the expected keywords, consume the token /// and return the keyword that matches. Otherwise, return an error. pub fn expect_one_of_keywords(&mut self, keywords: &[Keyword]) -> Result { @@ -12688,7 +12699,7 @@ impl<'a> Parser<'a> { let fn_name = self.parse_object_name(false)?; self.parse_function_call(fn_name) .map(TableObject::TableFunction) - } else if self.dialect.supports_insert_table_query() && self.peek_subquery_start(true) { + } else if self.dialect.supports_insert_table_query() && self.peek_subquery_or_cte_start() { self.parse_parenthesized(|p| p.parse_query()) .map(TableObject::TableQuery) } else { @@ -17437,7 +17448,7 @@ impl<'a> Parser<'a> { { (vec![], None, vec![], None, None, vec![]) } else { - let (columns, partitioned, after_columns) = if !self.peek_subquery_start(false) { + let (columns, partitioned, after_columns) = if !self.peek_subquery_start() { let columns = self.parse_parenthesized_qualified_column_list(Optional, is_mysql)?; @@ -17602,15 +17613,16 @@ impl<'a> Parser<'a> { } /// Returns true if the immediate tokens look like the - /// beginning of a subquery, e.g. `(SELECT ...`. - /// - /// If `full_query == true` attempt to detect a full query with its - /// optional, leading `WITH` clause, e.g. `(WITH ...)` - fn peek_subquery_start(&mut self, full_query: bool) -> bool { - let [maybe_lparen, maybe_select] = self.peek_tokens(); - Token::LParen == maybe_lparen - && matches!(maybe_select, Token::Word(w) - if w.keyword == Keyword::SELECT || (full_query && w.keyword == Keyword::WITH)) + /// beginning of a subquery. `(SELECT ...` + fn peek_subquery_start(&mut self) -> bool { + self.peek_token_with_one_of_keywords(&Token::LParen, &[Keyword::SELECT]) + } + + /// Returns true if the immediate tokens look like the + /// beginning of a subquery possibly preceded by CTEs; + /// i.e. `(WITH ...` or `(SELECT ...`. + fn peek_subquery_or_cte_start(&mut self) -> bool { + self.peek_token_with_one_of_keywords(&Token::LParen, &[Keyword::SELECT, Keyword::WITH]) } fn parse_conflict_clause(&mut self) -> Option { From f6cc757bdc9eb3eb3d9256e6b53ac187ccde49d0 Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 17:12:09 +0100 Subject: [PATCH 7/9] Simplify more --- src/parser/mod.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 89888f575..9b4321abb 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -4692,17 +4692,6 @@ impl<'a> Parser<'a> { } } - /// Returns `true` if the current token matches `token` and is further - /// followed by one of the specified `keywords`. - /// - /// Does not advance the current token. - #[must_use] - fn peek_token_with_one_of_keywords(&mut self, token: &Token, keywords: &[Keyword]) -> bool { - let [maybe_token, maybe_keyword] = self.peek_tokens_ref(); - &maybe_token.token == token - && matches!(&maybe_keyword.token, Token::Word(w) if keywords.contains(&w.keyword)) - } - /// If the current token is one of the expected keywords, consume the token /// and return the keyword that matches. Otherwise, return an error. pub fn expect_one_of_keywords(&mut self, keywords: &[Keyword]) -> Result { @@ -17615,14 +17604,19 @@ impl<'a> Parser<'a> { /// Returns true if the immediate tokens look like the /// beginning of a subquery. `(SELECT ...` fn peek_subquery_start(&mut self) -> bool { - self.peek_token_with_one_of_keywords(&Token::LParen, &[Keyword::SELECT]) + let [maybe_lparen, maybe_select] = self.peek_tokens_ref(); + Token::LParen == maybe_lparen.token + && matches!(&maybe_select.token, Token::Word(w) if w.keyword == Keyword::SELECT) } /// Returns true if the immediate tokens look like the /// beginning of a subquery possibly preceded by CTEs; /// i.e. `(WITH ...` or `(SELECT ...`. fn peek_subquery_or_cte_start(&mut self) -> bool { - self.peek_token_with_one_of_keywords(&Token::LParen, &[Keyword::SELECT, Keyword::WITH]) + matches!(self.peek_tokens_ref(), [ + TokenWithSpan { token: Token::LParen, .. }, + TokenWithSpan { token: Token::Word(Word { keyword: Keyword::SELECT | Keyword::WITH, .. }), .. }, + ]) } fn parse_conflict_clause(&mut self) -> Option { From bb6f542bb049bb544ec7ca222a6154326513eb50 Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 17:12:20 +0100 Subject: [PATCH 8/9] Cargo fmt --- src/parser/mod.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9b4321abb..90900e7fa 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17613,10 +17613,22 @@ impl<'a> Parser<'a> { /// beginning of a subquery possibly preceded by CTEs; /// i.e. `(WITH ...` or `(SELECT ...`. fn peek_subquery_or_cte_start(&mut self) -> bool { - matches!(self.peek_tokens_ref(), [ - TokenWithSpan { token: Token::LParen, .. }, - TokenWithSpan { token: Token::Word(Word { keyword: Keyword::SELECT | Keyword::WITH, .. }), .. }, - ]) + matches!( + self.peek_tokens_ref(), + [ + TokenWithSpan { + token: Token::LParen, + .. + }, + TokenWithSpan { + token: Token::Word(Word { + keyword: Keyword::SELECT | Keyword::WITH, + .. + }), + .. + }, + ] + ) } fn parse_conflict_clause(&mut self) -> Option { From da68baa61c0e73c2652672368f3d24805524b0fe Mon Sep 17 00:00:00 2001 From: Petr Novotnik Date: Fri, 13 Mar 2026 17:15:08 +0100 Subject: [PATCH 9/9] Align implementation style --- src/parser/mod.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 90900e7fa..f617caddc 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17604,9 +17604,22 @@ impl<'a> Parser<'a> { /// Returns true if the immediate tokens look like the /// beginning of a subquery. `(SELECT ...` fn peek_subquery_start(&mut self) -> bool { - let [maybe_lparen, maybe_select] = self.peek_tokens_ref(); - Token::LParen == maybe_lparen.token - && matches!(&maybe_select.token, Token::Word(w) if w.keyword == Keyword::SELECT) + matches!( + self.peek_tokens_ref(), + [ + TokenWithSpan { + token: Token::LParen, + .. + }, + TokenWithSpan { + token: Token::Word(Word { + keyword: Keyword::SELECT, + .. + }), + .. + }, + ] + ) } /// Returns true if the immediate tokens look like the