From 1a77bac49db047702fa40ed0dd44bcf6ba1ffd9e Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Mon, 16 Sep 2024 10:36:32 +0200 Subject: [PATCH 01/23] feat(tokenizer): add source location spans to tokens --- src/ast/mod.rs | 1 + src/parser.rs | 20 +++++++-------- src/tokenizer.rs | 66 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index b8d5cf042..a57eee946 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -52,6 +52,7 @@ pub mod helpers; mod operator; mod query; mod value; +mod spans; #[cfg(feature = "visitor")] mod visitor; diff --git a/src/parser.rs b/src/parser.rs index 3883a333d..c16aa5422 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -269,7 +269,7 @@ impl<'a> Parser<'a> { .into_iter() .map(|token| TokenWithLocation { token, - location: Location { line: 0, column: 0 }, + span: Span::empty(), }) .collect(); self.with_tokens_with_locations(tokens_with_locations) @@ -2022,13 +2022,13 @@ impl<'a> Parser<'a> { match self.tokens.get(index - 1) { Some(TokenWithLocation { token: Token::Whitespace(_), - location: _, + span: _, }) => continue, non_whitespace => { if n == 0 { return non_whitespace.cloned().unwrap_or(TokenWithLocation { token: Token::EOF, - location: Location { line: 0, column: 0 }, + span: Span::empty(), }); } n -= 1; @@ -2046,7 +2046,7 @@ impl<'a> Parser<'a> { match self.tokens.get(self.index - 1) { Some(TokenWithLocation { token: Token::Whitespace(_), - location: _, + span: _, }) => continue, token => { return token @@ -2072,7 +2072,7 @@ impl<'a> Parser<'a> { self.index -= 1; if let Some(TokenWithLocation { token: Token::Whitespace(_), - location: _, + span: _, }) = self.tokens.get(self.index) { continue; @@ -3600,7 +3600,7 @@ impl<'a> Parser<'a> { "FULLTEXT or SPATIAL option without constraint name", TokenWithLocation { token: Token::make_keyword(&name.to_string()), - location: next_token.location, + span: next_token.span, }, ); } @@ -4073,7 +4073,7 @@ impl<'a> Parser<'a> { /// Parse a literal value (numbers, strings, date/time, booleans) pub fn parse_value(&mut self) -> Result { let next_token = self.next_token(); - let location = next_token.location; + let span = next_token.span; match next_token.token { Token::Word(w) => match w.keyword { Keyword::TRUE => Ok(Value::Boolean(true)), @@ -4086,7 +4086,7 @@ impl<'a> Parser<'a> { "A value?", TokenWithLocation { token: Token::Word(w), - location, + span, }, )?, }, @@ -4098,7 +4098,7 @@ impl<'a> Parser<'a> { "a concrete value", TokenWithLocation { token: Token::Word(w), - location, + span, }, ), }, @@ -4125,7 +4125,7 @@ impl<'a> Parser<'a> { "a value", TokenWithLocation { token: unexpected, - location, + span, }, ), } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index dcf128542..2cbcf865e 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -338,23 +338,63 @@ pub struct Location { pub column: u64, } +impl Location { + pub fn of(line: u64, column: u64) -> Self { + Self { line, column } + } + + pub fn span_to(self, end: Self) -> Span { + Span { start: self, end } + } +} + +impl From<(u64, u64)> for Location { + fn from((line, column): (u64, u64)) -> Self { + Self { line, column } + } +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct Span { + pub start: Location, + pub end: Location, +} + +impl Span { + pub fn new(start: Location, end: Location) -> Span { + Span { start, end } + } + + pub fn empty() -> Span { + Span { + start: Location { line: 0, column: 0 }, + end: Location { line: 0, column: 0 }, + } + } +} + + /// A [Token] with [Location] attached to it #[derive(Debug, Eq, PartialEq, Clone)] pub struct TokenWithLocation { pub token: Token, - pub location: Location, + pub span: Span, } impl TokenWithLocation { - pub fn new(token: Token, line: u64, column: u64) -> TokenWithLocation { + pub fn new(token: Token, span: Span) -> TokenWithLocation { TokenWithLocation { token, - location: Location { line, column }, + span, } } pub fn wrap(token: Token) -> TokenWithLocation { - TokenWithLocation::new(token, 0, 0) + TokenWithLocation::new(token, Span::empty()) + } + + pub fn at(token: Token, start: Location, end: Location) -> TokenWithLocation { + TokenWithLocation::new(token, Span::new(start, end)) } } @@ -467,9 +507,11 @@ impl<'a> Tokenizer<'a> { let mut location = state.location(); while let Some(token) = self.next_token(&mut state)? { + let span = location.span_to(state.location()); + tokens.push(TokenWithLocation { token, - location: location.clone(), + span, }); location = state.location(); @@ -1815,13 +1857,13 @@ mod tests { let mut tokenizer = Tokenizer::new(&dialect, sql); let tokens = tokenizer.tokenize_with_location().unwrap(); let expected = vec![ - TokenWithLocation::new(Token::make_keyword("SELECT"), 1, 1), - TokenWithLocation::new(Token::Whitespace(Whitespace::Space), 1, 7), - TokenWithLocation::new(Token::make_word("a", None), 1, 8), - TokenWithLocation::new(Token::Comma, 1, 9), - TokenWithLocation::new(Token::Whitespace(Whitespace::Newline), 1, 10), - TokenWithLocation::new(Token::Whitespace(Whitespace::Space), 2, 1), - TokenWithLocation::new(Token::make_word("b", None), 2, 2), + TokenWithLocation::at(Token::make_keyword("SELECT"), (1, 1).into(), (1, 7).into()), + TokenWithLocation::at(Token::Whitespace(Whitespace::Space), (1, 7).into(), (1, 8).into()), + TokenWithLocation::at(Token::make_word("a", None), (1, 8).into(), (1, 9).into()), + TokenWithLocation::at(Token::Comma, (1, 9).into(), (1, 10).into()), + TokenWithLocation::at(Token::Whitespace(Whitespace::Newline), (1, 10).into(), (2, 1).into()), + TokenWithLocation::at(Token::Whitespace(Whitespace::Space), (2, 1).into(), (2, 2).into()), + TokenWithLocation::at(Token::make_word("b", None), (2, 2).into(), (2, 3).into()), ]; compare(expected, tokens); } From d81801227a31dfe6bcfb17e8d820135855a81f26 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Mon, 16 Sep 2024 14:41:02 +0200 Subject: [PATCH 02/23] feat: begin work on trait Spanned --- src/ast/mod.rs | 32 +- src/ast/query.rs | 4 +- src/ast/spans.rs | 286 +++++++++++++ src/dialect/postgresql.rs | 4 +- src/dialect/sqlite.rs | 2 +- src/parser.rs | 670 ++++++++++++++++-------------- src/tokenizer.rs | 85 +++- tests/sqlparser_bigquery.rs | 2 + tests/sqlparser_clickhouse.rs | 3 + tests/sqlparser_common.rs | 44 +- tests/sqlparser_custom_dialect.rs | 2 +- tests/sqlparser_mssql.rs | 4 +- tests/sqlparser_mysql.rs | 15 +- tests/sqlparser_postgres.rs | 42 +- tests/sqlparser_redshift.rs | 19 +- 15 files changed, 845 insertions(+), 369 deletions(-) create mode 100644 src/ast/spans.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a57eee946..7037228c3 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -25,6 +25,8 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; +use crate::tokenizer::Span; + pub use self::data_type::{ CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo, }; @@ -51,8 +53,8 @@ mod ddl; pub mod helpers; mod operator; mod query; -mod value; mod spans; +mod value; #[cfg(feature = "visitor")] mod visitor; @@ -104,6 +106,8 @@ pub struct Ident { /// The starting quote if any. Valid quote characters are the single quote, /// double quote, backtick, and opening square bracket. pub quote_style: Option, + /// The span of the identifier in the original SQL string. + pub span: Span, } impl Ident { @@ -115,6 +119,7 @@ impl Ident { Ident { value: value.into(), quote_style: None, + span: Span::empty(), } } @@ -128,6 +133,30 @@ impl Ident { Ident { value: value.into(), quote_style: Some(quote), + span: Span::empty(), + } + } + + pub fn with_span(span: Span, value: S) -> Self + where + S: Into, + { + Ident { + value: value.into(), + quote_style: None, + span, + } + } + + pub fn with_quote_and_span(quote: char, span: Span, value: S) -> Self + where + S: Into, + { + assert!(quote == '\'' || quote == '"' || quote == '`' || quote == '['); + Ident { + value: value.into(), + quote_style: Some(quote), + span, } } } @@ -137,6 +166,7 @@ impl From<&str> for Ident { Ident { value: value.to_string(), quote_style: None, + span: Span::empty(), } } } diff --git a/src/ast/query.rs b/src/ast/query.rs index f63234b09..53ce5f9fb 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; -use crate::ast::*; +use crate::{ast::*, tokenizer::TokenWithLocation}; /// The most complete variant of a `SELECT` query expression, optionally /// including `WITH`, `UNION` / other set operations, and `ORDER BY`. @@ -193,6 +193,8 @@ impl fmt::Display for Table { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Select { + /// SELECT + pub select_token: TokenWithLocation, pub distinct: bool, /// MSSQL syntax: `TOP () [ PERCENT ] [ WITH TIES ]` pub top: Option, diff --git a/src/ast/spans.rs b/src/ast/spans.rs new file mode 100644 index 000000000..c5169d392 --- /dev/null +++ b/src/ast/spans.rs @@ -0,0 +1,286 @@ +use core::iter; + +use crate::ast; +use crate::tokenizer::Span; + +use super::{Expr, Join, Query, Select, SelectItem, SetExpr, TableFactor, TableWithJoins}; + +pub trait Spanned { + fn span(&self) -> Span; +} + +impl Spanned for Query { + fn span(&self) -> Span { + self.body.span() + } +} + +impl Spanned for SetExpr { + fn span(&self) -> Span { + match self { + SetExpr::Select(select) => select.span(), + SetExpr::Query(query) => todo!(), + SetExpr::SetOperation { + op, + set_quantifier, + left, + right, + } => todo!(), + SetExpr::Values(values) => todo!(), + SetExpr::Insert(statement) => todo!(), + SetExpr::Table(table) => todo!(), + } + } +} + +impl Spanned for Expr { + fn span(&self) -> Span { + match self { + Expr::Identifier(ident) => ident.span, + Expr::CompoundIdentifier(vec) => todo!(), + Expr::JsonAccess { + left, + operator, + right, + } => todo!(), + Expr::CompositeAccess { expr, key } => todo!(), + Expr::IsFalse(expr) => todo!(), + Expr::IsNotFalse(expr) => todo!(), + Expr::IsTrue(expr) => todo!(), + Expr::IsNotTrue(expr) => todo!(), + Expr::IsNull(expr) => todo!(), + Expr::IsNotNull(expr) => todo!(), + Expr::IsUnknown(expr) => todo!(), + Expr::IsNotUnknown(expr) => todo!(), + Expr::IsDistinctFrom(expr, expr1) => todo!(), + Expr::IsNotDistinctFrom(expr, expr1) => todo!(), + Expr::InList { + expr, + list, + negated, + } => todo!(), + Expr::InSubquery { + expr, + subquery, + negated, + } => todo!(), + Expr::InUnnest { + expr, + array_expr, + negated, + } => todo!(), + Expr::Between { + expr, + negated, + low, + high, + } => todo!(), + Expr::BinaryOp { left, op, right } => todo!(), + Expr::Like { + negated, + expr, + pattern, + escape_char, + } => todo!(), + Expr::ILike { + negated, + expr, + pattern, + escape_char, + } => todo!(), + Expr::SimilarTo { + negated, + expr, + pattern, + escape_char, + } => todo!(), + Expr::AnyOp(expr) => todo!(), + Expr::AllOp(expr) => todo!(), + Expr::UnaryOp { op, expr } => todo!(), + Expr::Cast { expr, data_type } => todo!(), + Expr::TryCast { expr, data_type } => todo!(), + Expr::SafeCast { expr, data_type } => todo!(), + Expr::AtTimeZone { + timestamp, + time_zone, + } => todo!(), + Expr::Extract { field, expr } => todo!(), + Expr::Ceil { expr, field } => todo!(), + Expr::Floor { expr, field } => todo!(), + Expr::Position { expr, r#in } => todo!(), + Expr::Substring { + expr, + substring_from, + substring_for, + } => todo!(), + Expr::Trim { + expr, + trim_where, + trim_what, + } => todo!(), + Expr::Overlay { + expr, + overlay_what, + overlay_from, + overlay_for, + } => todo!(), + Expr::Collate { expr, collation } => todo!(), + Expr::Nested(expr) => todo!(), + Expr::Value(value) => todo!(), + Expr::TypedString { data_type, value } => todo!(), + Expr::MapAccess { column, keys } => todo!(), + Expr::Function(function) => todo!(), + Expr::AggregateExpressionWithFilter { expr, filter } => todo!(), + Expr::Case { + operand, + conditions, + results, + else_result, + } => todo!(), + Expr::Exists { subquery, negated } => todo!(), + Expr::Subquery(query) => todo!(), + Expr::ArraySubquery(query) => todo!(), + Expr::ListAgg(list_agg) => todo!(), + Expr::ArrayAgg(array_agg) => todo!(), + Expr::GroupingSets(vec) => todo!(), + Expr::Cube(vec) => todo!(), + Expr::Rollup(vec) => todo!(), + Expr::Tuple(vec) => todo!(), + Expr::ArrayIndex { obj, indexes } => todo!(), + Expr::Array(array) => todo!(), + Expr::Interval { + value, + leading_field, + leading_precision, + last_field, + fractional_seconds_precision, + } => todo!(), + Expr::MatchAgainst { + columns, + match_value, + opt_search_modifier, + } => todo!(), + } + } +} + +impl Spanned for SelectItem { + fn span(&self) -> Span { + match self { + SelectItem::UnnamedExpr(expr) => expr.span(), + SelectItem::ExprWithAlias { expr, alias } => expr.span().union(&alias.span), + SelectItem::QualifiedWildcard(object_name, wildcard_additional_options) => object_name + .0 + .iter() + .map(|i| i.span) + .reduce(|acc, item| acc.union(&item)) + .expect("Empty iterator"), + SelectItem::Wildcard(wildcard_additional_options) => todo!(), + } + } +} + +impl Spanned for TableFactor { + fn span(&self) -> Span { + match self { + TableFactor::Table { + name, + alias, + args, + with_hints, + } => union_spans( + name.0.iter().map(|i| i.span).chain( + alias + .as_ref() + .map(|alias| { + union_spans( + iter::once(alias.name.span) + .chain(alias.columns.iter().map(|i| i.span)), + ) + }) + .into_iter(), + ), + ), + TableFactor::Derived { + lateral, + subquery, + alias, + } => todo!(), + TableFactor::TableFunction { expr, alias } => todo!(), + TableFactor::UNNEST { + alias, + array_expr, + with_offset, + with_offset_alias, + } => todo!(), + TableFactor::NestedJoin { + table_with_joins, + alias, + } => todo!(), + } + } +} + +impl Spanned for Join { + fn span(&self) -> Span { + todo!() + } +} + +impl Spanned for TableWithJoins { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.relation.span()).chain(self.joins.iter().map(|item| item.span())), + ) + } +} + +pub fn union_spans>(iter: I) -> Span { + iter.reduce(|acc, item| acc.union(&item)) + .expect("Empty iterator") +} + +impl Spanned for Select { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.select_token.span.clone()) + .chain(self.projection.iter().map(|item| item.span())) + .chain(self.from.iter().map(|item| item.span())), + ) + } +} + +/** + * TODO: + * + * - CTE + * - With + * - SetExpr + * - Fetch + * - Lock Clause + */ +struct Ignore; + +#[cfg(test)] +pub mod tests { + use crate::dialect::{Dialect, GenericDialect}; + use crate::tokenizer::Span; + + use super::*; + + #[test] + fn test_span() { + let query = crate::parser::Parser::new(&GenericDialect::default()) + .try_with_sql("SELECT id, name FROM users") + .unwrap() + .parse_query() + .unwrap(); + + dbg!(&query); + + assert_eq!( + query.span(), + Span::new((1, 1).into(), (1, 54 - 28 + 1).into()) + ); + } +} diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index fe1953d2a..81d5a9fc4 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -36,7 +36,7 @@ impl Dialect for PostgreSqlDialect { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::COMMENT) { + if parser.parse_keyword(Keyword::COMMENT).is_some() { Some(parse_comment(parser)) } else { None @@ -65,7 +65,7 @@ pub fn parse_comment(parser: &mut Parser) -> Result { }; parser.expect_keyword(Keyword::IS)?; - let comment = if parser.parse_keyword(Keyword::NULL) { + let comment = if parser.parse_keyword(Keyword::NULL).is_some() { None } else { Some(parser.parse_literal_string()?) diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs index 64d7f62fd..5fef13671 100644 --- a/src/dialect/sqlite.rs +++ b/src/dialect/sqlite.rs @@ -40,7 +40,7 @@ impl Dialect for SQLiteDialect { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::REPLACE) { + if parser.parse_keyword(Keyword::REPLACE).is_some() { parser.prev_token(); Some(parser.parse_insert()) } else { diff --git a/src/parser.rs b/src/parser.rs index c16aa5422..2446553d3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -284,8 +284,8 @@ impl<'a> Parser<'a> { pub fn try_with_sql(self, sql: &str) -> Result { debug!("Parsing sql '{}'...", sql); let mut tokenizer = Tokenizer::new(self.dialect, sql); - let tokens = tokenizer.tokenize()?; - Ok(self.with_tokens(tokens)) + let tokens = tokenizer.tokenize_with_location()?; + Ok(self.with_tokens_with_locations(tokens)) } /// Parse potentially multiple statements @@ -412,7 +412,7 @@ impl<'a> Parser<'a> { } pub fn parse_msck(&mut self) -> Result { - let repair = self.parse_keyword(Keyword::REPAIR); + let repair = self.parse_keyword(Keyword::REPAIR).is_some(); self.expect_keyword(Keyword::TABLE)?; let table_name = self.parse_object_name()?; let partition_action = self @@ -442,7 +442,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::TABLE)?; let table_name = self.parse_object_name()?; let mut partitions = None; - if self.parse_keyword(Keyword::PARTITION) { + if self.parse_keyword(Keyword::PARTITION).is_some() { self.expect_token(&Token::LParen)?; partitions = Some(self.parse_comma_separated(Parser::parse_expr)?); self.expect_token(&Token::RParen)?; @@ -516,12 +516,12 @@ impl<'a> Parser<'a> { let next_token = self.next_token(); match next_token.token { Token::Word(w) if self.peek_token().token == Token::Period => { - let mut id_parts: Vec = vec![w.to_ident()]; + let mut id_parts: Vec = vec![w.to_ident(next_token.span)]; while self.consume_token(&Token::Period) { let next_token = self.next_token(); match next_token.token { - Token::Word(w) => id_parts.push(w.to_ident()), + Token::Word(w) => id_parts.push(w.to_ident(next_token.span)), Token::Mul => { return Ok(WildcardExpr::QualifiedWildcard(ObjectName(id_parts))); } @@ -597,7 +597,7 @@ impl<'a> Parser<'a> { pub fn parse_assert(&mut self) -> Result { let condition = self.parse_expr()?; - let message = if self.parse_keyword(Keyword::AS) { + let message = if self.parse_keyword(Keyword::AS).is_some() { Some(self.parse_expr()?) } else { None @@ -666,7 +666,7 @@ impl<'a> Parser<'a> { if dialect_of!(self is PostgreSqlDialect | GenericDialect) => { Ok(Expr::Function(Function { - name: ObjectName(vec![w.to_ident()]), + name: ObjectName(vec![w.to_ident(next_token.span)]), args: vec![], over: None, distinct: false, @@ -678,7 +678,7 @@ impl<'a> Parser<'a> { | Keyword::CURRENT_DATE | Keyword::LOCALTIME | Keyword::LOCALTIMESTAMP => { - self.parse_time_functions(ObjectName(vec![w.to_ident()])) + self.parse_time_functions(ObjectName(vec![w.to_ident(next_token.span)])) } Keyword::CASE => self.parse_case_expr(), Keyword::CAST => self.parse_cast_expr(), @@ -715,11 +715,11 @@ impl<'a> Parser<'a> { // identifier, a function call, or a simple identifier: _ => match self.peek_token().token { Token::LParen | Token::Period => { - let mut id_parts: Vec = vec![w.to_ident()]; + let mut id_parts: Vec = vec![w.to_ident(next_token.span)]; while self.consume_token(&Token::Period) { let next_token = self.next_token(); match next_token.token { - Token::Word(w) => id_parts.push(w.to_ident()), + Token::Word(w) => id_parts.push(w.to_ident(next_token.span)), _ => { return self .expected("an identifier or a '*' after '.'", next_token); @@ -734,7 +734,7 @@ impl<'a> Parser<'a> { Ok(Expr::CompoundIdentifier(id_parts)) } } - _ => Ok(Expr::Identifier(w.to_ident())), + _ => Ok(Expr::Identifier(w.to_ident(next_token.span))), }, }, // End of Token::Word // array `[1, 2, 3]` @@ -786,25 +786,26 @@ impl<'a> Parser<'a> { } Token::LParen => { - let expr = - if self.parse_keyword(Keyword::SELECT) || self.parse_keyword(Keyword::WITH) { - self.prev_token(); - Expr::Subquery(Box::new(self.parse_query()?)) - } else { - let exprs = self.parse_comma_separated(Parser::parse_expr)?; - match exprs.len() { - 0 => unreachable!(), // parse_comma_separated ensures 1 or more - 1 => Expr::Nested(Box::new(exprs.into_iter().next().unwrap())), - _ => Expr::Tuple(exprs), - } - }; + let expr = if self.parse_keyword(Keyword::SELECT).is_some() + || self.parse_keyword(Keyword::WITH).is_some() + { + self.prev_token(); + Expr::Subquery(Box::new(self.parse_query()?)) + } else { + let exprs = self.parse_comma_separated(Parser::parse_expr)?; + match exprs.len() { + 0 => unreachable!(), // parse_comma_separated ensures 1 or more + 1 => Expr::Nested(Box::new(exprs.into_iter().next().unwrap())), + _ => Expr::Tuple(exprs), + } + }; self.expect_token(&Token::RParen)?; if !self.consume_token(&Token::Period) { Ok(expr) } else { let tok = self.next_token(); let key = match tok.token { - Token::Word(word) => word.to_ident(), + Token::Word(word) => word.to_ident(tok.span), _ => return parser_err!(format!("Expected identifier, found: {}", tok)), }; Ok(Expr::CompositeAccess { @@ -820,7 +821,7 @@ impl<'a> Parser<'a> { _ => self.expected("an expression:", next_token), }?; - if self.parse_keyword(Keyword::COLLATE) { + if self.parse_keyword(Keyword::COLLATE).is_some() { Ok(Expr::Collate { expr: Box::new(expr), collation: self.parse_object_name()?, @@ -834,7 +835,7 @@ impl<'a> Parser<'a> { self.expect_token(&Token::LParen)?; let distinct = self.parse_all_or_distinct()?; let args = self.parse_optional_args()?; - let over = if self.parse_keyword(Keyword::OVER) { + let over = if self.parse_keyword(Keyword::OVER).is_some() { // TBD: support window names (`OVER mywin`) in place of inline specification self.expect_token(&Token::LParen)?; let partition_by = if self.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) { @@ -903,7 +904,7 @@ impl<'a> Parser<'a> { pub fn parse_window_frame(&mut self) -> Result { let units = self.parse_window_frame_units()?; - let (start_bound, end_bound) = if self.parse_keyword(Keyword::BETWEEN) { + let (start_bound, end_bound) = if self.parse_keyword(Keyword::BETWEEN).is_some() { let start_bound = self.parse_window_frame_bound()?; self.expect_keyword(Keyword::AND)?; let end_bound = Some(self.parse_window_frame_bound()?); @@ -923,7 +924,7 @@ impl<'a> Parser<'a> { if self.parse_keywords(&[Keyword::CURRENT, Keyword::ROW]) { Ok(WindowFrameBound::CurrentRow) } else { - let rows = if self.parse_keyword(Keyword::UNBOUNDED) { + let rows = if self.parse_keyword(Keyword::UNBOUNDED).is_some() { None } else { Some(Box::new(match self.peek_token().token { @@ -931,9 +932,9 @@ impl<'a> Parser<'a> { _ => self.parse_expr()?, })) }; - if self.parse_keyword(Keyword::PRECEDING) { + if self.parse_keyword(Keyword::PRECEDING).is_some() { Ok(WindowFrameBound::Preceding(rows)) - } else if self.parse_keyword(Keyword::FOLLOWING) { + } else if self.parse_keyword(Keyword::FOLLOWING).is_some() { Ok(WindowFrameBound::Following(rows)) } else { self.expected("PRECEDING or FOLLOWING", self.peek_token()) @@ -950,12 +951,12 @@ impl<'a> Parser<'a> { let result = self.parse_comma_separated(|p| p.parse_tuple(false, true))?; self.expect_token(&Token::RParen)?; Ok(Expr::GroupingSets(result)) - } else if self.parse_keyword(Keyword::CUBE) { + } else if self.parse_keyword(Keyword::CUBE).is_some() { self.expect_token(&Token::LParen)?; let result = self.parse_comma_separated(|p| p.parse_tuple(true, true))?; self.expect_token(&Token::RParen)?; Ok(Expr::Cube(result)) - } else if self.parse_keyword(Keyword::ROLLUP) { + } else if self.parse_keyword(Keyword::ROLLUP).is_some() { self.expect_token(&Token::LParen)?; let result = self.parse_comma_separated(|p| p.parse_tuple(true, true))?; self.expect_token(&Token::RParen)?; @@ -1005,7 +1006,7 @@ impl<'a> Parser<'a> { pub fn parse_case_expr(&mut self) -> Result { let mut operand = None; - if !self.parse_keyword(Keyword::WHEN) { + if !self.parse_keyword(Keyword::WHEN).is_some() { operand = Some(Box::new(self.parse_expr()?)); self.expect_keyword(Keyword::WHEN)?; } @@ -1015,11 +1016,11 @@ impl<'a> Parser<'a> { conditions.push(self.parse_expr()?); self.expect_keyword(Keyword::THEN)?; results.push(self.parse_expr()?); - if !self.parse_keyword(Keyword::WHEN) { + if !self.parse_keyword(Keyword::WHEN).is_some() { break; } } - let else_result = if self.parse_keyword(Keyword::ELSE) { + let else_result = if self.parse_keyword(Keyword::ELSE).is_some() { Some(Box::new(self.parse_expr()?)) } else { None @@ -1100,7 +1101,7 @@ impl<'a> Parser<'a> { let expr = self.parse_expr()?; // Parse `CEIL/FLOOR(expr)` let mut field = DateTimeField::NoDateTime; - let keyword_to = self.parse_keyword(Keyword::TO); + let keyword_to = self.parse_keyword(Keyword::TO).is_some(); if keyword_to { // Parse `CEIL/FLOOR(expr TO DateTimeField)` field = self.parse_date_time_field()?; @@ -1125,7 +1126,7 @@ impl<'a> Parser<'a> { // Parse the subexpr till the IN keyword let expr = self.parse_subexpr(Self::BETWEEN_PREC)?; - if self.parse_keyword(Keyword::IN) { + if self.parse_keyword(Keyword::IN).is_some() { let from = self.parse_expr()?; self.expect_token(&Token::RParen)?; Ok(Expr::Position { @@ -1142,12 +1143,12 @@ impl<'a> Parser<'a> { self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; let mut from_expr = None; - if self.parse_keyword(Keyword::FROM) || self.consume_token(&Token::Comma) { + if self.parse_keyword(Keyword::FROM).is_some() || self.consume_token(&Token::Comma) { from_expr = Some(self.parse_expr()?); } let mut to_expr = None; - if self.parse_keyword(Keyword::FOR) || self.consume_token(&Token::Comma) { + if self.parse_keyword(Keyword::FOR).is_some() || self.consume_token(&Token::Comma) { to_expr = Some(self.parse_expr()?); } self.expect_token(&Token::RParen)?; @@ -1168,7 +1169,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::FROM)?; let from_expr = self.parse_expr()?; let mut for_expr = None; - if self.parse_keyword(Keyword::FOR) { + if self.parse_keyword(Keyword::FOR).is_some() { for_expr = Some(self.parse_expr()?); } self.expect_token(&Token::RParen)?; @@ -1197,7 +1198,7 @@ impl<'a> Parser<'a> { } } let expr = self.parse_expr()?; - if self.parse_keyword(Keyword::FROM) { + if self.parse_keyword(Keyword::FROM).is_some() { let trim_what = Box::new(expr); let expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -1265,7 +1266,7 @@ impl<'a> Parser<'a> { None }; let on_overflow = if self.parse_keywords(&[Keyword::ON, Keyword::OVERFLOW]) { - if self.parse_keyword(Keyword::ERROR) { + if self.parse_keyword(Keyword::ERROR).is_some() { Some(ListAggOnOverflow::Error) } else { self.expect_keyword(Keyword::TRUNCATE)?; @@ -1284,8 +1285,8 @@ impl<'a> Parser<'a> { self.peek_token(), )?, }; - let with_count = self.parse_keyword(Keyword::WITH); - if !with_count && !self.parse_keyword(Keyword::WITHOUT) { + let with_count = self.parse_keyword(Keyword::WITH).is_some(); + if !with_count && !self.parse_keyword(Keyword::WITHOUT).is_some() { self.expected("either WITH or WITHOUT in LISTAGG", self.peek_token())?; } self.expect_keyword(Keyword::COUNT)?; @@ -1317,7 +1318,7 @@ impl<'a> Parser<'a> { pub fn parse_array_agg_expr(&mut self) -> Result { self.expect_token(&Token::LParen)?; - let distinct = self.parse_keyword(Keyword::DISTINCT); + let distinct = self.parse_keyword(Keyword::DISTINCT).is_some(); let expr = Box::new(self.parse_expr()?); // ANSI SQL and BigQuery define ORDER BY inside function. if !self.dialect.supports_within_after_array_aggregation() { @@ -1327,7 +1328,7 @@ impl<'a> Parser<'a> { } else { None }; - let limit = if self.parse_keyword(Keyword::LIMIT) { + let limit = if self.parse_keyword(Keyword::LIMIT).is_some() { self.parse_limit()?.map(Box::new) } else { None @@ -1410,7 +1411,7 @@ impl<'a> Parser<'a> { Token::Word(w) => match w.keyword { Keyword::EXISTS => { let negated = true; - let _ = self.parse_keyword(Keyword::EXISTS); + let _ = self.parse_keyword(Keyword::EXISTS).is_some(); self.parse_exists_expr(negated) } _ => Ok(Expr::UnaryOp { @@ -1555,7 +1556,7 @@ impl<'a> Parser<'a> { (leading_precision, last_field, fsec_precision) } else { let leading_precision = self.parse_optional_precision()?; - if self.parse_keyword(Keyword::TO) { + if self.parse_keyword(Keyword::TO).is_some() { let last_field = Some(self.parse_date_time_field()?); let fsec_precision = if last_field == Some(DateTimeField::Second) { self.parse_optional_precision()? @@ -1669,7 +1670,7 @@ impl<'a> Parser<'a> { } else if let Token::Word(w) = &tok.token { match w.keyword { Keyword::IS => { - if self.parse_keyword(Keyword::NULL) { + if self.parse_keyword(Keyword::NULL).is_some() { Ok(Expr::IsNull(Box::new(expr))) } else if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) { Ok(Expr::IsNotNull(Box::new(expr))) @@ -1700,7 +1701,7 @@ impl<'a> Parser<'a> { } } Keyword::AT => { - // if self.parse_keyword(Keyword::TIME) { + // if self.parse_keyword(Keyword::TIME).is_some() { // self.expect_keyword(Keyword::ZONE)?; if self.parse_keywords(&[Keyword::TIME, Keyword::ZONE]) { let time_zone = self.next_token(); @@ -1728,19 +1729,19 @@ impl<'a> Parser<'a> { | Keyword::ILIKE | Keyword::SIMILAR => { self.prev_token(); - let negated = self.parse_keyword(Keyword::NOT); - if self.parse_keyword(Keyword::IN) { + let negated = self.parse_keyword(Keyword::NOT).is_some(); + if self.parse_keyword(Keyword::IN).is_some() { self.parse_in(expr, negated) - } else if self.parse_keyword(Keyword::BETWEEN) { + } else if self.parse_keyword(Keyword::BETWEEN).is_some() { self.parse_between(expr, negated) - } else if self.parse_keyword(Keyword::LIKE) { + } else if self.parse_keyword(Keyword::LIKE).is_some() { Ok(Expr::Like { negated, expr: Box::new(expr), pattern: Box::new(self.parse_subexpr(Self::LIKE_PREC)?), escape_char: self.parse_escape_char()?, }) - } else if self.parse_keyword(Keyword::ILIKE) { + } else if self.parse_keyword(Keyword::ILIKE).is_some() { Ok(Expr::ILike { negated, expr: Box::new(expr), @@ -1816,7 +1817,7 @@ impl<'a> Parser<'a> { /// parse the ESCAPE CHAR portion of LIKE, ILIKE, and SIMILAR TO pub fn parse_escape_char(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::ESCAPE) { + if self.parse_keyword(Keyword::ESCAPE).is_some() { Ok(Some(self.parse_literal_char()?)) } else { Ok(None) @@ -1862,7 +1863,7 @@ impl<'a> Parser<'a> { pub fn parse_in(&mut self, expr: Expr, negated: bool) -> Result { // BigQuery allows `IN UNNEST(array_expression)` // https://cloud.google.com/bigquery/docs/reference/standard-sql/operators#in_operators - if self.parse_keyword(Keyword::UNNEST) { + if self.parse_keyword(Keyword::UNNEST).is_some() { self.expect_token(&Token::LParen)?; let array_expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -1873,7 +1874,9 @@ impl<'a> Parser<'a> { }); } self.expect_token(&Token::LParen)?; - let in_op = if self.parse_keyword(Keyword::SELECT) || self.parse_keyword(Keyword::WITH) { + let in_op = if self.parse_keyword(Keyword::SELECT).is_some() + || self.parse_keyword(Keyword::WITH).is_some() + { self.prev_token(); Expr::InSubquery { expr: Box::new(expr), @@ -2088,12 +2091,17 @@ impl<'a> Parser<'a> { /// Look for an expected keyword and consume it if it exists #[must_use] - pub fn parse_keyword(&mut self, expected: Keyword) -> bool { + pub fn parse_keyword(&mut self, expected: Keyword) -> Option { match self.peek_token().token { - Token::Word(w) if expected == w.keyword => { - self.next_token(); - true - } + Token::Word(w) if expected == w.keyword => Some(self.next_token()), + _ => None, + } + } + + #[must_use] + pub fn peek_keyword(&mut self, expected: Keyword) -> bool { + match self.peek_token().token { + Token::Word(w) if expected == w.keyword => true, _ => false, } } @@ -2103,7 +2111,7 @@ impl<'a> Parser<'a> { pub fn parse_keywords(&mut self, keywords: &[Keyword]) -> bool { let index = self.index; for &keyword in keywords { - if !self.parse_keyword(keyword) { + if !self.parse_keyword(keyword).is_some() { // println!("parse_keywords aborting .. did not find {:?}", keyword); // reset index and return immediately self.index = index; @@ -2144,9 +2152,9 @@ impl<'a> Parser<'a> { } /// Bail out if the current token is not an expected keyword, or consume it if it is - pub fn expect_keyword(&mut self, expected: Keyword) -> Result<(), ParserError> { - if self.parse_keyword(expected) { - Ok(()) + pub fn expect_keyword(&mut self, expected: Keyword) -> Result { + if let Some(token) = self.parse_keyword(expected) { + Ok(token) } else { self.expected(format!("{:?}", &expected).as_str(), self.peek_token()) } @@ -2242,8 +2250,8 @@ impl<'a> Parser<'a> { /// Parse either `ALL` or `DISTINCT`. Returns `true` if `DISTINCT` is parsed and results in a /// `ParserError` if both `ALL` and `DISTINCT` are fround. pub fn parse_all_or_distinct(&mut self) -> Result { - let all = self.parse_keyword(Keyword::ALL); - let distinct = self.parse_keyword(Keyword::DISTINCT); + let all = self.parse_keyword(Keyword::ALL).is_some(); + let distinct = self.parse_keyword(Keyword::DISTINCT).is_some(); if all && distinct { parser_err!("Cannot specify both ALL and DISTINCT".to_string()) } else { @@ -2266,33 +2274,35 @@ impl<'a> Parser<'a> { let temporary = self .parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY]) .is_some(); - if self.parse_keyword(Keyword::TABLE) { + if self.parse_keyword(Keyword::TABLE).is_some() { self.parse_create_table(or_replace, temporary, global) - } else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) { + } else if self.parse_keyword(Keyword::MATERIALIZED).is_some() + || self.parse_keyword(Keyword::VIEW).is_some() + { self.prev_token(); self.parse_create_view(or_replace) - } else if self.parse_keyword(Keyword::EXTERNAL) { + } else if self.parse_keyword(Keyword::EXTERNAL).is_some() { self.parse_create_external_table(or_replace) - } else if self.parse_keyword(Keyword::FUNCTION) { + } else if self.parse_keyword(Keyword::FUNCTION).is_some() { self.parse_create_function(or_replace, temporary) } else if or_replace { self.expected( "[EXTERNAL] TABLE or [MATERIALIZED] VIEW or FUNCTION after CREATE OR REPLACE", self.peek_token(), ) - } else if self.parse_keyword(Keyword::INDEX) { + } else if self.parse_keyword(Keyword::INDEX).is_some() { self.parse_create_index(false) } else if self.parse_keywords(&[Keyword::UNIQUE, Keyword::INDEX]) { self.parse_create_index(true) - } else if self.parse_keyword(Keyword::VIRTUAL) { + } else if self.parse_keyword(Keyword::VIRTUAL).is_some() { self.parse_create_virtual_table() - } else if self.parse_keyword(Keyword::SCHEMA) { + } else if self.parse_keyword(Keyword::SCHEMA).is_some() { self.parse_create_schema() - } else if self.parse_keyword(Keyword::DATABASE) { + } else if self.parse_keyword(Keyword::DATABASE).is_some() { self.parse_create_database() - } else if self.parse_keyword(Keyword::ROLE) { + } else if self.parse_keyword(Keyword::ROLE).is_some() { self.parse_create_role() - } else if self.parse_keyword(Keyword::SEQUENCE) { + } else if self.parse_keyword(Keyword::SEQUENCE).is_some() { self.parse_create_sequence(temporary) } else { self.expected("an object type after CREATE", self.peek_token()) @@ -2302,7 +2312,7 @@ impl<'a> Parser<'a> { /// Parse a CACHE TABLE statement pub fn parse_cache_table(&mut self) -> Result { let (mut table_flag, mut options, mut has_as, mut query) = (None, vec![], false, None); - if self.parse_keyword(Keyword::TABLE) { + if self.parse_keyword(Keyword::TABLE).is_some() { let table_name = self.parse_object_name()?; if self.peek_token().token != Token::EOF { if let Token::Word(word) = self.peek_token().token { @@ -2335,7 +2345,7 @@ impl<'a> Parser<'a> { } } else { table_flag = Some(self.parse_object_name()?); - if self.parse_keyword(Keyword::TABLE) { + if self.parse_keyword(Keyword::TABLE).is_some() { let table_name = self.parse_object_name()?; if self.peek_token() != Token::EOF { if let Token::Word(word) = self.peek_token().token { @@ -2391,7 +2401,7 @@ impl<'a> Parser<'a> { /// Parse a UNCACHE TABLE statement pub fn parse_uncache_table(&mut self) -> Result { - let has_table = self.parse_keyword(Keyword::TABLE); + let has_table = self.parse_keyword(Keyword::TABLE).is_some(); if has_table { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let table_name = self.parse_object_name()?; @@ -2440,12 +2450,12 @@ impl<'a> Parser<'a> { } fn parse_schema_name(&mut self) -> Result { - if self.parse_keyword(Keyword::AUTHORIZATION) { + if self.parse_keyword(Keyword::AUTHORIZATION).is_some() { Ok(SchemaName::UnnamedAuthorization(self.parse_identifier()?)) } else { let name = self.parse_object_name()?; - if self.parse_keyword(Keyword::AUTHORIZATION) { + if self.parse_keyword(Keyword::AUTHORIZATION).is_some() { Ok(SchemaName::NamedAuthorization( name, self.parse_identifier()?, @@ -2481,7 +2491,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_create_function_using( &mut self, ) -> Result, ParserError> { - if !self.parse_keyword(Keyword::USING) { + if !self.parse_keyword(Keyword::USING).is_some() { return Ok(None); }; let keyword = @@ -2535,7 +2545,7 @@ impl<'a> Parser<'a> { self.expect_token(&Token::RParen)?; - let return_type = if self.parse_keyword(Keyword::RETURNS) { + let return_type = if self.parse_keyword(Keyword::RETURNS).is_some() { Some(self.parse_data_type()?) } else { None @@ -2558,11 +2568,11 @@ impl<'a> Parser<'a> { } fn parse_function_arg(&mut self) -> Result { - let mode = if self.parse_keyword(Keyword::IN) { + let mode = if self.parse_keyword(Keyword::IN).is_some() { Some(ArgMode::In) - } else if self.parse_keyword(Keyword::OUT) { + } else if self.parse_keyword(Keyword::OUT).is_some() { Some(ArgMode::Out) - } else if self.parse_keyword(Keyword::INOUT) { + } else if self.parse_keyword(Keyword::INOUT).is_some() { Some(ArgMode::InOut) } else { None @@ -2577,12 +2587,12 @@ impl<'a> Parser<'a> { data_type = self.parse_data_type()?; } - let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq) - { - Some(self.parse_expr()?) - } else { - None - }; + let default_expr = + if self.parse_keyword(Keyword::DEFAULT).is_some() || self.consume_token(&Token::Eq) { + Some(self.parse_expr()?) + } else { + None + }; Ok(OperateFunctionArg { mode, name, @@ -2602,22 +2612,22 @@ impl<'a> Parser<'a> { } Ok(()) } - if self.parse_keyword(Keyword::AS) { + if self.parse_keyword(Keyword::AS).is_some() { ensure_not_set(&body.as_, "AS")?; body.as_ = Some(self.parse_function_definition()?); - } else if self.parse_keyword(Keyword::LANGUAGE) { + } else if self.parse_keyword(Keyword::LANGUAGE).is_some() { ensure_not_set(&body.language, "LANGUAGE")?; body.language = Some(self.parse_identifier()?); - } else if self.parse_keyword(Keyword::IMMUTABLE) { + } else if self.parse_keyword(Keyword::IMMUTABLE).is_some() { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Immutable); - } else if self.parse_keyword(Keyword::STABLE) { + } else if self.parse_keyword(Keyword::STABLE).is_some() { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Stable); - } else if self.parse_keyword(Keyword::VOLATILE) { + } else if self.parse_keyword(Keyword::VOLATILE).is_some() { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Volatile); - } else if self.parse_keyword(Keyword::RETURN) { + } else if self.parse_keyword(Keyword::RETURN).is_some() { ensure_not_set(&body.return_, "RETURN")?; body.return_ = Some(self.parse_expr()?); } else { @@ -2693,7 +2703,7 @@ impl<'a> Parser<'a> { } pub fn parse_create_view(&mut self, or_replace: bool) -> Result { - let materialized = self.parse_keyword(Keyword::MATERIALIZED); + let materialized = self.parse_keyword(Keyword::MATERIALIZED).is_some(); self.expect_keyword(Keyword::VIEW)?; // Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet). // ANSI SQL and Postgres support RECURSIVE here, but we don't support it either. @@ -2701,7 +2711,7 @@ impl<'a> Parser<'a> { let columns = self.parse_parenthesized_column_list(Optional, false)?; let with_options = self.parse_options(Keyword::WITH)?; - let cluster_by = if self.parse_keyword(Keyword::CLUSTER) { + let cluster_by = if self.parse_keyword(Keyword::CLUSTER).is_some() { self.expect_keyword(Keyword::BY)?; self.parse_parenthesized_column_list(Optional, false)? } else { @@ -2726,7 +2736,7 @@ impl<'a> Parser<'a> { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let names = self.parse_comma_separated(Parser::parse_object_name)?; - let _ = self.parse_keyword(Keyword::WITH); // [ WITH ] + let _ = self.parse_keyword(Keyword::WITH).is_some(); // [ WITH ] let optional_keywords = if dialect_of!(self is MsSqlDialect) { vec![Keyword::AUTHORIZATION] @@ -2847,7 +2857,7 @@ impl<'a> Parser<'a> { if password.is_some() { parser_err!("Found multiple PASSWORD") } else { - password = if self.parse_keyword(Keyword::NULL) { + password = if self.parse_keyword(Keyword::NULL).is_some() { Some(Password::NullPassword) } else { Some(Password::Password(Expr::Value(self.parse_value()?))) @@ -2874,14 +2884,14 @@ impl<'a> Parser<'a> { } } Keyword::IN => { - if self.parse_keyword(Keyword::ROLE) { + if self.parse_keyword(Keyword::ROLE).is_some() { if !in_role.is_empty() { parser_err!("Found multiple IN ROLE") } else { in_role = self.parse_comma_separated(Parser::parse_identifier)?; Ok(()) } - } else if self.parse_keyword(Keyword::GROUP) { + } else if self.parse_keyword(Keyword::GROUP).is_some() { if !in_group.is_empty() { parser_err!("Found multiple IN GROUP") } else { @@ -2943,19 +2953,19 @@ impl<'a> Parser<'a> { } pub fn parse_drop(&mut self) -> Result { - let object_type = if self.parse_keyword(Keyword::TABLE) { + let object_type = if self.parse_keyword(Keyword::TABLE).is_some() { ObjectType::Table - } else if self.parse_keyword(Keyword::VIEW) { + } else if self.parse_keyword(Keyword::VIEW).is_some() { ObjectType::View - } else if self.parse_keyword(Keyword::INDEX) { + } else if self.parse_keyword(Keyword::INDEX).is_some() { ObjectType::Index - } else if self.parse_keyword(Keyword::ROLE) { + } else if self.parse_keyword(Keyword::ROLE).is_some() { ObjectType::Role - } else if self.parse_keyword(Keyword::SCHEMA) { + } else if self.parse_keyword(Keyword::SCHEMA).is_some() { ObjectType::Schema - } else if self.parse_keyword(Keyword::SEQUENCE) { + } else if self.parse_keyword(Keyword::SEQUENCE).is_some() { ObjectType::Sequence - } else if self.parse_keyword(Keyword::FUNCTION) { + } else if self.parse_keyword(Keyword::FUNCTION).is_some() { return self.parse_drop_function(); } else { return self.expected( @@ -2967,9 +2977,9 @@ impl<'a> Parser<'a> { // specifying multiple objects to delete in a single statement let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let names = self.parse_comma_separated(Parser::parse_object_name)?; - let cascade = self.parse_keyword(Keyword::CASCADE); - let restrict = self.parse_keyword(Keyword::RESTRICT); - let purge = self.parse_keyword(Keyword::PURGE); + let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); + let restrict = self.parse_keyword(Keyword::RESTRICT).is_some(); + let purge = self.parse_keyword(Keyword::PURGE).is_some(); if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in DROP"); } @@ -3030,15 +3040,15 @@ impl<'a> Parser<'a> { pub fn parse_declare(&mut self) -> Result { let name = self.parse_identifier()?; - let binary = self.parse_keyword(Keyword::BINARY); - let sensitive = if self.parse_keyword(Keyword::INSENSITIVE) { + let binary = self.parse_keyword(Keyword::BINARY).is_some(); + let sensitive = if self.parse_keyword(Keyword::INSENSITIVE).is_some() { Some(true) - } else if self.parse_keyword(Keyword::ASENSITIVE) { + } else if self.parse_keyword(Keyword::ASENSITIVE).is_some() { Some(false) } else { None }; - let scroll = if self.parse_keyword(Keyword::SCROLL) { + let scroll = if self.parse_keyword(Keyword::SCROLL).is_some() { Some(true) } else if self.parse_keywords(&[Keyword::NO, Keyword::SCROLL]) { Some(false) @@ -3077,24 +3087,24 @@ impl<'a> Parser<'a> { // FETCH [ direction { FROM | IN } ] cursor INTO target; pub fn parse_fetch_statement(&mut self) -> Result { - let direction = if self.parse_keyword(Keyword::NEXT) { + let direction = if self.parse_keyword(Keyword::NEXT).is_some() { FetchDirection::Next - } else if self.parse_keyword(Keyword::PRIOR) { + } else if self.parse_keyword(Keyword::PRIOR).is_some() { FetchDirection::Prior - } else if self.parse_keyword(Keyword::FIRST) { + } else if self.parse_keyword(Keyword::FIRST).is_some() { FetchDirection::First - } else if self.parse_keyword(Keyword::LAST) { + } else if self.parse_keyword(Keyword::LAST).is_some() { FetchDirection::Last - } else if self.parse_keyword(Keyword::ABSOLUTE) { + } else if self.parse_keyword(Keyword::ABSOLUTE).is_some() { FetchDirection::Absolute { limit: self.parse_number_value()?, } - } else if self.parse_keyword(Keyword::RELATIVE) { + } else if self.parse_keyword(Keyword::RELATIVE).is_some() { FetchDirection::Relative { limit: self.parse_number_value()?, } - } else if self.parse_keyword(Keyword::FORWARD) { - if self.parse_keyword(Keyword::ALL) { + } else if self.parse_keyword(Keyword::FORWARD).is_some() { + if self.parse_keyword(Keyword::ALL).is_some() { FetchDirection::ForwardAll } else { FetchDirection::Forward { @@ -3102,8 +3112,8 @@ impl<'a> Parser<'a> { limit: Some(self.parse_number_value()?), } } - } else if self.parse_keyword(Keyword::BACKWARD) { - if self.parse_keyword(Keyword::ALL) { + } else if self.parse_keyword(Keyword::BACKWARD).is_some() { + if self.parse_keyword(Keyword::ALL).is_some() { FetchDirection::BackwardAll } else { FetchDirection::Backward { @@ -3111,7 +3121,7 @@ impl<'a> Parser<'a> { limit: Some(self.parse_number_value()?), } } - } else if self.parse_keyword(Keyword::ALL) { + } else if self.parse_keyword(Keyword::ALL).is_some() { FetchDirection::All } else { FetchDirection::Count { @@ -3123,7 +3133,7 @@ impl<'a> Parser<'a> { let name = self.parse_identifier()?; - let into = if self.parse_keyword(Keyword::INTO) { + let into = if self.parse_keyword(Keyword::INTO).is_some() { Some(self.parse_object_name()?) } else { None @@ -3137,13 +3147,15 @@ impl<'a> Parser<'a> { } pub fn parse_discard(&mut self) -> Result { - let object_type = if self.parse_keyword(Keyword::ALL) { + let object_type = if self.parse_keyword(Keyword::ALL).is_some() { DiscardObject::ALL - } else if self.parse_keyword(Keyword::PLANS) { + } else if self.parse_keyword(Keyword::PLANS).is_some() { DiscardObject::PLANS - } else if self.parse_keyword(Keyword::SEQUENCES) { + } else if self.parse_keyword(Keyword::SEQUENCES).is_some() { DiscardObject::SEQUENCES - } else if self.parse_keyword(Keyword::TEMP) || self.parse_keyword(Keyword::TEMPORARY) { + } else if self.parse_keyword(Keyword::TEMP).is_some() + || self.parse_keyword(Keyword::TEMPORARY).is_some() + { DiscardObject::TEMP } else { return self.expected( @@ -3159,7 +3171,7 @@ impl<'a> Parser<'a> { let index_name = self.parse_object_name()?; self.expect_keyword(Keyword::ON)?; let table_name = self.parse_object_name()?; - let using = if self.parse_keyword(Keyword::USING) { + let using = if self.parse_keyword(Keyword::USING).is_some() { Some(self.parse_identifier()?) } else { None @@ -3198,7 +3210,7 @@ impl<'a> Parser<'a> { } Some(Keyword::STORED) => { self.expect_keyword(Keyword::AS)?; - if self.parse_keyword(Keyword::INPUTFORMAT) { + if self.parse_keyword(Keyword::INPUTFORMAT).is_some() { let input_format = self.parse_expr()?; self.expect_keyword(Keyword::OUTPUTFORMAT)?; let output_format = self.parse_expr()?; @@ -3254,13 +3266,15 @@ impl<'a> Parser<'a> { None }; - let like = if self.parse_keyword(Keyword::LIKE) || self.parse_keyword(Keyword::ILIKE) { + let like = if self.parse_keyword(Keyword::LIKE).is_some() + || self.parse_keyword(Keyword::ILIKE).is_some() + { self.parse_object_name().ok() } else { None }; - let clone = if self.parse_keyword(Keyword::CLONE) { + let clone = if self.parse_keyword(Keyword::CLONE).is_some() { self.parse_object_name().ok() } else { None @@ -3278,13 +3292,13 @@ impl<'a> Parser<'a> { let with_options = self.parse_options(Keyword::WITH)?; let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?; // Parse optional `AS ( query )` - let query = if self.parse_keyword(Keyword::AS) { + let query = if self.parse_keyword(Keyword::AS).is_some() { Some(Box::new(self.parse_query()?)) } else { None }; - let engine = if self.parse_keyword(Keyword::ENGINE) { + let engine = if self.parse_keyword(Keyword::ENGINE).is_some() { self.expect_token(&Token::Eq)?; let next_token = self.next_token(); match next_token.token { @@ -3387,14 +3401,14 @@ impl<'a> Parser<'a> { pub fn parse_column_def(&mut self) -> Result { let name = self.parse_identifier()?; let data_type = self.parse_data_type()?; - let collation = if self.parse_keyword(Keyword::COLLATE) { + let collation = if self.parse_keyword(Keyword::COLLATE).is_some() { Some(self.parse_object_name()?) } else { None }; let mut options = vec![]; loop { - if self.parse_keyword(Keyword::CONSTRAINT) { + if self.parse_keyword(Keyword::CONSTRAINT).is_some() { let name = Some(self.parse_identifier()?); if let Some(option) = self.parse_optional_column_option()? { options.push(ColumnOptionDef { name, option }); @@ -3429,15 +3443,15 @@ impl<'a> Parser<'a> { Token::SingleQuotedString(value, ..) => Ok(Some(ColumnOption::Comment(value))), _ => self.expected("string", next_token), } - } else if self.parse_keyword(Keyword::NULL) { + } else if self.parse_keyword(Keyword::NULL).is_some() { Ok(Some(ColumnOption::Null)) - } else if self.parse_keyword(Keyword::DEFAULT) { + } else if self.parse_keyword(Keyword::DEFAULT).is_some() { Ok(Some(ColumnOption::Default(self.parse_expr()?))) } else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) { Ok(Some(ColumnOption::Unique { is_primary: true })) - } else if self.parse_keyword(Keyword::UNIQUE) { + } else if self.parse_keyword(Keyword::UNIQUE).is_some() { Ok(Some(ColumnOption::Unique { is_primary: false })) - } else if self.parse_keyword(Keyword::REFERENCES) { + } else if self.parse_keyword(Keyword::REFERENCES).is_some() { let foreign_table = self.parse_object_name()?; // PostgreSQL allows omitting the column list and // uses the primary key column of the foreign table by default @@ -3461,19 +3475,19 @@ impl<'a> Parser<'a> { on_delete, on_update, })) - } else if self.parse_keyword(Keyword::CHECK) { + } else if self.parse_keyword(Keyword::CHECK).is_some() { self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; Ok(Some(ColumnOption::Check(expr))) - } else if self.parse_keyword(Keyword::AUTO_INCREMENT) + } else if self.parse_keyword(Keyword::AUTO_INCREMENT).is_some() && dialect_of!(self is MySqlDialect | GenericDialect) { // Support AUTO_INCREMENT for MySQL Ok(Some(ColumnOption::DialectSpecific(vec![ Token::make_keyword("AUTO_INCREMENT"), ]))) - } else if self.parse_keyword(Keyword::AUTOINCREMENT) + } else if self.parse_keyword(Keyword::AUTOINCREMENT).is_some() && dialect_of!(self is SQLiteDialect | GenericDialect) { // Support AUTOINCREMENT for SQLite @@ -3491,9 +3505,9 @@ impl<'a> Parser<'a> { } pub fn parse_referential_action(&mut self) -> Result { - if self.parse_keyword(Keyword::RESTRICT) { + if self.parse_keyword(Keyword::RESTRICT).is_some() { Ok(ReferentialAction::Restrict) - } else if self.parse_keyword(Keyword::CASCADE) { + } else if self.parse_keyword(Keyword::CASCADE).is_some() { Ok(ReferentialAction::Cascade) } else if self.parse_keywords(&[Keyword::SET, Keyword::NULL]) { Ok(ReferentialAction::SetNull) @@ -3512,7 +3526,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_table_constraint( &mut self, ) -> Result, ParserError> { - let name = if self.parse_keyword(Keyword::CONSTRAINT) { + let name = if self.parse_keyword(Keyword::CONSTRAINT).is_some() { Some(self.parse_identifier()?) } else { None @@ -3577,7 +3591,7 @@ impl<'a> Parser<'a> { _ => self.maybe_parse(|parser| parser.parse_identifier()), }; - let index_type = if self.parse_keyword(Keyword::USING) { + let index_type = if self.parse_keyword(Keyword::USING).is_some() { Some(self.parse_index_type()?) } else { None @@ -3607,9 +3621,9 @@ impl<'a> Parser<'a> { let fulltext = w.keyword == Keyword::FULLTEXT; - let index_type_display = if self.parse_keyword(Keyword::KEY) { + let index_type_display = if self.parse_keyword(Keyword::KEY).is_some() { KeyOrIndexDisplay::Key - } else if self.parse_keyword(Keyword::INDEX) { + } else if self.parse_keyword(Keyword::INDEX).is_some() { KeyOrIndexDisplay::Index } else { KeyOrIndexDisplay::None @@ -3638,7 +3652,7 @@ impl<'a> Parser<'a> { } pub fn parse_options(&mut self, keyword: Keyword) -> Result, ParserError> { - if self.parse_keyword(keyword) { + if self.parse_keyword(keyword).is_some() { self.expect_token(&Token::LParen)?; let options = self.parse_comma_separated(Parser::parse_sql_option)?; self.expect_token(&Token::RParen)?; @@ -3649,9 +3663,9 @@ impl<'a> Parser<'a> { } pub fn parse_index_type(&mut self) -> Result { - if self.parse_keyword(Keyword::BTREE) { + if self.parse_keyword(Keyword::BTREE).is_some() { Ok(IndexType::BTree) - } else if self.parse_keyword(Keyword::HASH) { + } else if self.parse_keyword(Keyword::HASH).is_some() { Ok(IndexType::Hash) } else { self.expected("index type {BTREE | HASH}", self.peek_token()) @@ -3669,15 +3683,15 @@ impl<'a> Parser<'a> { let object_type = self.expect_one_of_keywords(&[Keyword::TABLE, Keyword::INDEX])?; match object_type { Keyword::TABLE => { - let _ = self.parse_keyword(Keyword::ONLY); // [ ONLY ] + let _ = self.parse_keyword(Keyword::ONLY).is_some(); // [ ONLY ] let table_name = self.parse_object_name()?; - let operation = if self.parse_keyword(Keyword::ADD) { + let operation = if self.parse_keyword(Keyword::ADD).is_some() { if let Some(constraint) = self.parse_optional_table_constraint()? { AlterTableOperation::AddConstraint(constraint) } else { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); - if self.parse_keyword(Keyword::PARTITION) { + if self.parse_keyword(Keyword::PARTITION).is_some() { self.expect_token(&Token::LParen)?; let partitions = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -3686,7 +3700,7 @@ impl<'a> Parser<'a> { new_partitions: partitions, } } else { - let column_keyword = self.parse_keyword(Keyword::COLUMN); + let column_keyword = self.parse_keyword(Keyword::COLUMN).is_some(); let if_not_exists = if dialect_of!(self is PostgreSqlDialect | BigQueryDialect | GenericDialect) { @@ -3704,19 +3718,19 @@ impl<'a> Parser<'a> { } } } - } else if self.parse_keyword(Keyword::RENAME) { + } else if self.parse_keyword(Keyword::RENAME).is_some() { if dialect_of!(self is PostgreSqlDialect) - && self.parse_keyword(Keyword::CONSTRAINT) + && self.parse_keyword(Keyword::CONSTRAINT).is_some() { let old_name = self.parse_identifier()?; self.expect_keyword(Keyword::TO)?; let new_name = self.parse_identifier()?; AlterTableOperation::RenameConstraint { old_name, new_name } - } else if self.parse_keyword(Keyword::TO) { + } else if self.parse_keyword(Keyword::TO).is_some() { let table_name = self.parse_object_name()?; AlterTableOperation::RenameTable { table_name } } else { - let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] + let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] let old_column_name = self.parse_identifier()?; self.expect_keyword(Keyword::TO)?; let new_column_name = self.parse_identifier()?; @@ -3725,7 +3739,7 @@ impl<'a> Parser<'a> { new_column_name, } } - } else if self.parse_keyword(Keyword::DROP) { + } else if self.parse_keyword(Keyword::DROP).is_some() { if self.parse_keywords(&[Keyword::IF, Keyword::EXISTS, Keyword::PARTITION]) { self.expect_token(&Token::LParen)?; let partitions = self.parse_comma_separated(Parser::parse_expr)?; @@ -3734,7 +3748,7 @@ impl<'a> Parser<'a> { partitions, if_exists: true, } - } else if self.parse_keyword(Keyword::PARTITION) { + } else if self.parse_keyword(Keyword::PARTITION).is_some() { self.expect_token(&Token::LParen)?; let partitions = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -3742,10 +3756,10 @@ impl<'a> Parser<'a> { partitions, if_exists: false, } - } else if self.parse_keyword(Keyword::CONSTRAINT) { + } else if self.parse_keyword(Keyword::CONSTRAINT).is_some() { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let name = self.parse_identifier()?; - let cascade = self.parse_keyword(Keyword::CASCADE); + let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); AlterTableOperation::DropConstraint { if_exists, name, @@ -3756,17 +3770,17 @@ impl<'a> Parser<'a> { { AlterTableOperation::DropPrimaryKey } else { - let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] + let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let column_name = self.parse_identifier()?; - let cascade = self.parse_keyword(Keyword::CASCADE); + let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); AlterTableOperation::DropColumn { column_name, if_exists, cascade, } } - } else if self.parse_keyword(Keyword::PARTITION) { + } else if self.parse_keyword(Keyword::PARTITION).is_some() { self.expect_token(&Token::LParen)?; let before = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -3779,8 +3793,8 @@ impl<'a> Parser<'a> { old_partitions: before, new_partitions: renames, } - } else if self.parse_keyword(Keyword::CHANGE) { - let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] + } else if self.parse_keyword(Keyword::CHANGE).is_some() { + let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] let old_name = self.parse_identifier()?; let new_name = self.parse_identifier()?; let data_type = self.parse_data_type()?; @@ -3795,8 +3809,8 @@ impl<'a> Parser<'a> { data_type, options, } - } else if self.parse_keyword(Keyword::ALTER) { - let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] + } else if self.parse_keyword(Keyword::ALTER).is_some() { + let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] let column_name = self.parse_identifier()?; let is_postgresql = dialect_of!(self is PostgreSqlDialect); @@ -3811,10 +3825,11 @@ impl<'a> Parser<'a> { } else if self.parse_keywords(&[Keyword::DROP, Keyword::DEFAULT]) { AlterColumnOperation::DropDefault {} } else if self.parse_keywords(&[Keyword::SET, Keyword::DATA, Keyword::TYPE]) - || (is_postgresql && self.parse_keyword(Keyword::TYPE)) + || (is_postgresql && self.parse_keyword(Keyword::TYPE).is_some()) { let data_type = self.parse_data_type()?; - let using = if is_postgresql && self.parse_keyword(Keyword::USING) { + let using = if is_postgresql && self.parse_keyword(Keyword::USING).is_some() + { Some(self.parse_expr()?) } else { None @@ -3840,8 +3855,8 @@ impl<'a> Parser<'a> { } Keyword::INDEX => { let index_name = self.parse_object_name()?; - let operation = if self.parse_keyword(Keyword::RENAME) { - if self.parse_keyword(Keyword::TO) { + let operation = if self.parse_keyword(Keyword::RENAME).is_some() { + if self.parse_keyword(Keyword::TO).is_some() { let index_name = self.parse_object_name()?; AlterIndexOperation::RenameIndex { index_name } } else { @@ -3870,11 +3885,11 @@ impl<'a> Parser<'a> { Some(Keyword::TO) => true, _ => self.expected("FROM or TO", self.peek_token())?, }; - let target = if self.parse_keyword(Keyword::STDIN) { + let target = if self.parse_keyword(Keyword::STDIN).is_some() { CopyTarget::Stdin - } else if self.parse_keyword(Keyword::STDOUT) { + } else if self.parse_keyword(Keyword::STDOUT).is_some() { CopyTarget::Stdout - } else if self.parse_keyword(Keyword::PROGRAM) { + } else if self.parse_keyword(Keyword::PROGRAM).is_some() { CopyTarget::Program { command: self.parse_literal_string()?, } @@ -3883,7 +3898,7 @@ impl<'a> Parser<'a> { filename: self.parse_literal_string()?, } }; - let _ = self.parse_keyword(Keyword::WITH); // [ WITH ] + let _ = self.parse_keyword(Keyword::WITH).is_some(); // [ WITH ] let mut options = vec![]; if self.consume_token(&Token::LParen) { options = self.parse_comma_separated(Parser::parse_copy_option)?; @@ -3911,7 +3926,7 @@ impl<'a> Parser<'a> { } pub fn parse_close(&mut self) -> Result { - let cursor = if self.parse_keyword(Keyword::ALL) { + let cursor = if self.parse_keyword(Keyword::ALL).is_some() { CloseCursor::All } else { let name = self.parse_identifier()?; @@ -3973,11 +3988,11 @@ impl<'a> Parser<'a> { ]) { Some(Keyword::BINARY) => CopyLegacyOption::Binary, Some(Keyword::DELIMITER) => { - let _ = self.parse_keyword(Keyword::AS); // [ AS ] + let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] CopyLegacyOption::Delimiter(self.parse_literal_char()?) } Some(Keyword::NULL) => { - let _ = self.parse_keyword(Keyword::AS); // [ AS ] + let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] CopyLegacyOption::Null(self.parse_literal_string()?) } Some(Keyword::CSV) => CopyLegacyOption::Csv({ @@ -4003,11 +4018,11 @@ impl<'a> Parser<'a> { ]) { Some(Keyword::HEADER) => CopyLegacyCsvOption::Header, Some(Keyword::QUOTE) => { - let _ = self.parse_keyword(Keyword::AS); // [ AS ] + let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] CopyLegacyCsvOption::Quote(self.parse_literal_char()?) } Some(Keyword::ESCAPE) => { - let _ = self.parse_keyword(Keyword::AS); // [ AS ] + let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] CopyLegacyCsvOption::Escape(self.parse_literal_char()?) } Some(Keyword::FORCE) if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) => { @@ -4213,7 +4228,7 @@ impl<'a> Parser<'a> { Keyword::FLOAT => Ok(DataType::Float(self.parse_optional_precision()?)), Keyword::REAL => Ok(DataType::Real), Keyword::DOUBLE => { - if self.parse_keyword(Keyword::PRECISION) { + if self.parse_keyword(Keyword::PRECISION).is_some() { Ok(DataType::DoublePrecision) } else { Ok(DataType::Double) @@ -4221,7 +4236,7 @@ impl<'a> Parser<'a> { } Keyword::TINYINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedTinyInt(optional_precision?)) } else { Ok(DataType::TinyInt(optional_precision?)) @@ -4229,7 +4244,7 @@ impl<'a> Parser<'a> { } Keyword::SMALLINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedSmallInt(optional_precision?)) } else { Ok(DataType::SmallInt(optional_precision?)) @@ -4237,7 +4252,7 @@ impl<'a> Parser<'a> { } Keyword::MEDIUMINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedMediumInt(optional_precision?)) } else { Ok(DataType::MediumInt(optional_precision?)) @@ -4245,7 +4260,7 @@ impl<'a> Parser<'a> { } Keyword::INT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedInt(optional_precision?)) } else { Ok(DataType::Int(optional_precision?)) @@ -4253,7 +4268,7 @@ impl<'a> Parser<'a> { } Keyword::INTEGER => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedInteger(optional_precision?)) } else { Ok(DataType::Integer(optional_precision?)) @@ -4261,7 +4276,7 @@ impl<'a> Parser<'a> { } Keyword::BIGINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED) { + if self.parse_keyword(Keyword::UNSIGNED).is_some() { Ok(DataType::UnsignedBigInt(optional_precision?)) } else { Ok(DataType::BigInt(optional_precision?)) @@ -4270,7 +4285,7 @@ impl<'a> Parser<'a> { Keyword::VARCHAR => Ok(DataType::Varchar(self.parse_optional_character_length()?)), Keyword::NVARCHAR => Ok(DataType::Nvarchar(self.parse_optional_precision()?)), Keyword::CHARACTER => { - if self.parse_keyword(Keyword::VARYING) { + if self.parse_keyword(Keyword::VARYING).is_some() { Ok(DataType::CharacterVarying( self.parse_optional_character_length()?, )) @@ -4283,7 +4298,7 @@ impl<'a> Parser<'a> { } } Keyword::CHAR => { - if self.parse_keyword(Keyword::VARYING) { + if self.parse_keyword(Keyword::VARYING).is_some() { Ok(DataType::CharVarying( self.parse_optional_character_length()?, )) @@ -4302,10 +4317,10 @@ impl<'a> Parser<'a> { Keyword::DATETIME => Ok(DataType::Datetime(self.parse_optional_precision()?)), Keyword::TIMESTAMP => { let precision = self.parse_optional_precision()?; - let tz = if self.parse_keyword(Keyword::WITH) { + let tz = if self.parse_keyword(Keyword::WITH).is_some() { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithTimeZone - } else if self.parse_keyword(Keyword::WITHOUT) { + } else if self.parse_keyword(Keyword::WITHOUT).is_some() { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithoutTimeZone } else { @@ -4319,10 +4334,10 @@ impl<'a> Parser<'a> { )), Keyword::TIME => { let precision = self.parse_optional_precision()?; - let tz = if self.parse_keyword(Keyword::WITH) { + let tz = if self.parse_keyword(Keyword::WITH).is_some() { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithTimeZone - } else if self.parse_keyword(Keyword::WITHOUT) { + } else if self.parse_keyword(Keyword::WITHOUT).is_some() { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithoutTimeZone } else { @@ -4422,7 +4437,7 @@ impl<'a> Parser<'a> { &mut self, reserved_kwds: &[Keyword], ) -> Result, ParserError> { - let after_as = self.parse_keyword(Keyword::AS); + let after_as = self.parse_keyword(Keyword::AS).is_some(); let next_token = self.next_token(); match next_token.token { // Accept any identifier after `AS` (though many dialects have restrictions on @@ -4431,7 +4446,7 @@ impl<'a> Parser<'a> { // (For example, in `FROM t1 JOIN` the `JOIN` will always be parsed as a keyword, // not an alias.) Token::Word(w) if after_as || !reserved_kwds.contains(&w.keyword) => { - Ok(Some(w.to_ident())) + Ok(Some(w.to_ident(next_token.span))) } // MSSQL supports single-quoted strings as aliases for columns // We accept them as table aliases too, although MSSQL does not. @@ -4445,9 +4460,13 @@ impl<'a> Parser<'a> { // character. When it sees such a , your DBMS will // ignore the and treat the multiple strings as // a single ." - Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))), + Token::SingleQuotedString(s) => { + Ok(Some(Ident::with_quote_and_span('\'', next_token.span, s))) + } // Support for MySql dialect double quoted string, `AS "HOUR"` for example - Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))), + Token::DoubleQuotedString(s) => { + Ok(Some(Ident::with_quote_and_span('\"', next_token.span, s))) + } _ => { if after_as { return self.expected("an identifier after AS", next_token); @@ -4492,9 +4511,10 @@ impl<'a> Parser<'a> { pub fn parse_identifiers(&mut self) -> Result, ParserError> { let mut idents = vec![]; loop { - match self.peek_token().token { + let token = self.peek_token(); + match token.token { Token::Word(w) => { - idents.push(w.to_ident()); + idents.push(w.to_ident(token.span)); } Token::EOF | Token::Eq => break, _ => {} @@ -4507,12 +4527,15 @@ impl<'a> Parser<'a> { /// Parse a simple one-word identifier (possibly quoted, possibly a keyword) pub fn parse_identifier(&mut self) -> Result { let next_token = self.next_token(); - match next_token.token { - Token::Word(w) => Ok(w.to_ident()), + let mut ident = match next_token.token { + Token::Word(w) => Ok(w.to_ident(next_token.span)), Token::SingleQuotedString(s) => Ok(Ident::with_quote('\'', s)), Token::DoubleQuotedString(s) => Ok(Ident::with_quote('\"', s)), - _ => self.expected("identifier", next_token), - } + _ => self.expected("identifier", next_token.clone()), + }?; + + ident.span = next_token.span; + Ok(ident) } /// Parse a parenthesized comma-separated list of unqualified, possibly quoted identifiers @@ -4568,9 +4591,9 @@ impl<'a> Parser<'a> { pub fn parse_character_length(&mut self) -> Result { let length = self.parse_literal_uint()?; - let unit = if self.parse_keyword(Keyword::CHARACTERS) { + let unit = if self.parse_keyword(Keyword::CHARACTERS).is_some() { Some(CharLengthUnits::Characters) - } else if self.parse_keyword(Keyword::OCTETS) { + } else if self.parse_keyword(Keyword::OCTETS).is_some() { Some(CharLengthUnits::Octets) } else { None @@ -4647,18 +4670,18 @@ impl<'a> Parser<'a> { pub fn parse_delete(&mut self) -> Result { self.expect_keyword(Keyword::FROM)?; let table_name = self.parse_table_factor()?; - let using = if self.parse_keyword(Keyword::USING) { + let using = if self.parse_keyword(Keyword::USING).is_some() { Some(self.parse_table_factor()?) } else { None }; - let selection = if self.parse_keyword(Keyword::WHERE) { + let selection = if self.parse_keyword(Keyword::WHERE).is_some() { Some(self.parse_expr()?) } else { None }; - let returning = if self.parse_keyword(Keyword::RETURNING) { + let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -4699,10 +4722,10 @@ impl<'a> Parser<'a> { } pub fn parse_explain(&mut self, describe_alias: bool) -> Result { - let analyze = self.parse_keyword(Keyword::ANALYZE); - let verbose = self.parse_keyword(Keyword::VERBOSE); + let analyze = self.parse_keyword(Keyword::ANALYZE).is_some(); + let verbose = self.parse_keyword(Keyword::VERBOSE).is_some(); let mut format = None; - if self.parse_keyword(Keyword::FORMAT) { + if self.parse_keyword(Keyword::FORMAT).is_some() { format = Some(self.parse_analyze_format()?); } @@ -4733,16 +4756,16 @@ impl<'a> Parser<'a> { /// expect the initial keyword to be already consumed pub fn parse_query(&mut self) -> Result { let _guard = self.recursion_counter.try_decrease()?; - let with = if self.parse_keyword(Keyword::WITH) { + let with = if self.parse_keyword(Keyword::WITH).is_some() { Some(With { - recursive: self.parse_keyword(Keyword::RECURSIVE), + recursive: self.parse_keyword(Keyword::RECURSIVE).is_some(), cte_tables: self.parse_comma_separated(Parser::parse_cte)?, }) } else { None }; - if !self.parse_keyword(Keyword::INSERT) { + if !self.parse_keyword(Keyword::INSERT).is_some() { let body = Box::new(self.parse_query_body(0)?); let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) { @@ -4755,11 +4778,11 @@ impl<'a> Parser<'a> { let mut offset = None; for _x in 0..2 { - if limit.is_none() && self.parse_keyword(Keyword::LIMIT) { + if limit.is_none() && self.parse_keyword(Keyword::LIMIT).is_some() { limit = self.parse_limit()? } - if offset.is_none() && self.parse_keyword(Keyword::OFFSET) { + if offset.is_none() && self.parse_keyword(Keyword::OFFSET).is_some() { offset = Some(self.parse_offset()?) } @@ -4778,14 +4801,14 @@ impl<'a> Parser<'a> { } } - let fetch = if self.parse_keyword(Keyword::FETCH) { + let fetch = if self.parse_keyword(Keyword::FETCH).is_some() { Some(self.parse_fetch()?) } else { None }; let mut locks = Vec::new(); - while self.parse_keyword(Keyword::FOR) { + while self.parse_keyword(Keyword::FOR).is_some() { locks.push(self.parse_lock()?); } @@ -4817,7 +4840,7 @@ impl<'a> Parser<'a> { pub fn parse_cte(&mut self) -> Result { let name = self.parse_identifier()?; - let mut cte = if self.parse_keyword(Keyword::AS) { + let mut cte = if self.parse_keyword(Keyword::AS).is_some() { self.expect_token(&Token::LParen)?; let query = Box::new(self.parse_query()?); self.expect_token(&Token::RParen)?; @@ -4843,7 +4866,7 @@ impl<'a> Parser<'a> { from: None, } }; - if self.parse_keyword(Keyword::FROM) { + if self.parse_keyword(Keyword::FROM).is_some() { cte.from = Some(self.parse_identifier()?); } Ok(cte) @@ -4860,17 +4883,17 @@ impl<'a> Parser<'a> { pub fn parse_query_body(&mut self, precedence: u8) -> Result { // We parse the expression using a Pratt parser, as in `parse_expr()`. // Start by parsing a restricted SELECT or a `(subquery)`: - let mut expr = if self.parse_keyword(Keyword::SELECT) { + let mut expr = if self.peek_keyword(Keyword::SELECT) { SetExpr::Select(Box::new(self.parse_select()?)) } else if self.consume_token(&Token::LParen) { // CTEs are not allowed here, but the parser currently accepts them let subquery = self.parse_query()?; self.expect_token(&Token::RParen)?; SetExpr::Query(Box::new(subquery)) - } else if self.parse_keyword(Keyword::VALUES) { + } else if self.parse_keyword(Keyword::VALUES).is_some() { let is_mysql = dialect_of!(self is MySqlDialect); SetExpr::Values(self.parse_values(is_mysql)?) - } else if self.parse_keyword(Keyword::TABLE) { + } else if self.parse_keyword(Keyword::TABLE).is_some() { SetExpr::Table(Box::new(self.parse_as_table()?)) } else { return self.expected( @@ -4918,18 +4941,18 @@ impl<'a> Parser<'a> { pub fn parse_set_quantifier(&mut self, op: &Option) -> SetQuantifier { match op { Some(SetOperator::Union) => { - if self.parse_keyword(Keyword::ALL) { + if self.parse_keyword(Keyword::ALL).is_some() { SetQuantifier::All - } else if self.parse_keyword(Keyword::DISTINCT) { + } else if self.parse_keyword(Keyword::DISTINCT).is_some() { SetQuantifier::Distinct } else { SetQuantifier::None } } Some(SetOperator::Except) | Some(SetOperator::Intersect) => { - if self.parse_keyword(Keyword::ALL) { + if self.parse_keyword(Keyword::ALL).is_some() { SetQuantifier::All - } else if self.parse_keyword(Keyword::DISTINCT) { + } else if self.parse_keyword(Keyword::DISTINCT).is_some() { SetQuantifier::Distinct } else { SetQuantifier::None @@ -4940,11 +4963,14 @@ impl<'a> Parser<'a> { } /// Parse a restricted `SELECT` statement (no CTEs / `UNION` / `ORDER BY`), - /// assuming the initial `SELECT` was already consumed + /// assuming the initial `SELECT` was not already consumed pub fn parse_select(&mut self) -> Result { + let select_token = self.expect_keyword(Keyword::SELECT)?; + dbg!(&select_token); + let distinct = self.parse_all_or_distinct()?; - let top = if self.parse_keyword(Keyword::TOP) { + let top = if self.parse_keyword(Keyword::TOP).is_some() { Some(self.parse_top()?) } else { None @@ -4952,12 +4978,12 @@ impl<'a> Parser<'a> { let projection = self.parse_projection()?; - let into = if self.parse_keyword(Keyword::INTO) { + let into = if self.parse_keyword(Keyword::INTO).is_some() { let temporary = self .parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY]) .is_some(); - let unlogged = self.parse_keyword(Keyword::UNLOGGED); - let table = self.parse_keyword(Keyword::TABLE); + let unlogged = self.parse_keyword(Keyword::UNLOGGED).is_some(); + let table = self.parse_keyword(Keyword::TABLE).is_some(); let name = self.parse_object_name()?; Some(SelectInto { temporary, @@ -4974,7 +5000,7 @@ impl<'a> Parser<'a> { // otherwise they may be parsed as an alias as part of the `projection` // or `from`. - let from = if self.parse_keyword(Keyword::FROM) { + let from = if self.parse_keyword(Keyword::FROM).is_some() { self.parse_comma_separated(Parser::parse_table_and_joins)? } else { vec![] @@ -4983,7 +5009,7 @@ impl<'a> Parser<'a> { let mut lateral_views = vec![]; loop { if self.parse_keywords(&[Keyword::LATERAL, Keyword::VIEW]) { - let outer = self.parse_keyword(Keyword::OUTER); + let outer = self.parse_keyword(Keyword::OUTER).is_some(); let lateral_view = self.parse_expr()?; let lateral_view_name = self.parse_object_name()?; let lateral_col_alias = self @@ -5011,7 +5037,7 @@ impl<'a> Parser<'a> { } } - let selection = if self.parse_keyword(Keyword::WHERE) { + let selection = if self.parse_keyword(Keyword::WHERE).is_some() { Some(self.parse_expr()?) } else { None @@ -5041,19 +5067,20 @@ impl<'a> Parser<'a> { vec![] }; - let having = if self.parse_keyword(Keyword::HAVING) { + let having = if self.parse_keyword(Keyword::HAVING).is_some() { Some(self.parse_expr()?) } else { None }; - let qualify = if self.parse_keyword(Keyword::QUALIFY) { + let qualify = if self.parse_keyword(Keyword::QUALIFY).is_some() { Some(self.parse_expr()?) } else { None }; Ok(Select { + select_token, distinct, top, projection, @@ -5120,14 +5147,14 @@ impl<'a> Parser<'a> { self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, Keyword::HIVEVAR]); if let Some(Keyword::HIVEVAR) = modifier { self.expect_token(&Token::Colon)?; - } else if self.parse_keyword(Keyword::ROLE) { + } else if self.parse_keyword(Keyword::ROLE).is_some() { let context_modifier = match modifier { Some(keyword) if keyword == Keyword::LOCAL => ContextModifier::Local, Some(keyword) if keyword == Keyword::SESSION => ContextModifier::Session, _ => ContextModifier::None, }; - let role_name = if self.parse_keyword(Keyword::NONE) { + let role_name = if self.parse_keyword(Keyword::NONE).is_some() { None } else { Some(self.parse_identifier()?) @@ -5147,7 +5174,7 @@ impl<'a> Parser<'a> { if variable.to_string().eq_ignore_ascii_case("NAMES") && dialect_of!(self is MySqlDialect | GenericDialect) { - if self.parse_keyword(Keyword::DEFAULT) { + if self.parse_keyword(Keyword::DEFAULT).is_some() { return Ok(Statement::SetNamesDefault {}); } @@ -5162,7 +5189,7 @@ impl<'a> Parser<'a> { charset_name, collation_name, }) - } else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) { + } else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO).is_some() { let mut values = vec![]; loop { let value = if let Ok(expr) = self.parse_expr() { @@ -5199,7 +5226,7 @@ impl<'a> Parser<'a> { session: true, }) } else if variable.to_string() == "TRANSACTION" && modifier.is_none() { - if self.parse_keyword(Keyword::SNAPSHOT) { + if self.parse_keyword(Keyword::SNAPSHOT).is_some() { let snaphot_id = self.parse_value()?; return Ok(Statement::SetTransaction { modes: vec![], @@ -5218,16 +5245,16 @@ impl<'a> Parser<'a> { } pub fn parse_show(&mut self) -> Result { - let extended = self.parse_keyword(Keyword::EXTENDED); - let full = self.parse_keyword(Keyword::FULL); + let extended = self.parse_keyword(Keyword::EXTENDED).is_some(); + let full = self.parse_keyword(Keyword::FULL).is_some(); if self .parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS]) .is_some() { Ok(self.parse_show_columns(extended, full)?) - } else if self.parse_keyword(Keyword::TABLES) { + } else if self.parse_keyword(Keyword::TABLES).is_some() { Ok(self.parse_show_tables(extended, full)?) - } else if self.parse_keyword(Keyword::FUNCTIONS) { + } else if self.parse_keyword(Keyword::FUNCTIONS).is_some() { Ok(self.parse_show_functions()?) } else if extended || full { Err(ParserError::ParserError( @@ -5235,9 +5262,9 @@ impl<'a> Parser<'a> { )) } else if self.parse_one_of_keywords(&[Keyword::CREATE]).is_some() { Ok(self.parse_show_create()?) - } else if self.parse_keyword(Keyword::COLLATION) { + } else if self.parse_keyword(Keyword::COLLATION).is_some() { Ok(self.parse_show_collation()?) - } else if self.parse_keyword(Keyword::VARIABLES) + } else if self.parse_keyword(Keyword::VARIABLES).is_some() && dialect_of!(self is MySqlDialect | GenericDialect) { // TODO: Support GLOBAL|SESSION @@ -5333,15 +5360,15 @@ impl<'a> Parser<'a> { pub fn parse_show_statement_filter( &mut self, ) -> Result, ParserError> { - if self.parse_keyword(Keyword::LIKE) { + if self.parse_keyword(Keyword::LIKE).is_some() { Ok(Some(ShowStatementFilter::Like( self.parse_literal_string()?, ))) - } else if self.parse_keyword(Keyword::ILIKE) { + } else if self.parse_keyword(Keyword::ILIKE).is_some() { Ok(Some(ShowStatementFilter::ILike( self.parse_literal_string()?, ))) - } else if self.parse_keyword(Keyword::WHERE) { + } else if self.parse_keyword(Keyword::WHERE).is_some() { Ok(Some(ShowStatementFilter::Where(self.parse_expr()?))) } else { Ok(None) @@ -5360,10 +5387,10 @@ impl<'a> Parser<'a> { // a table alias. let mut joins = vec![]; loop { - let join = if self.parse_keyword(Keyword::CROSS) { - let join_operator = if self.parse_keyword(Keyword::JOIN) { + let join = if self.parse_keyword(Keyword::CROSS).is_some() { + let join_operator = if self.parse_keyword(Keyword::JOIN).is_some() { JoinOperator::CrossJoin - } else if self.parse_keyword(Keyword::APPLY) { + } else if self.parse_keyword(Keyword::APPLY).is_some() { // MSSQL extension, similar to CROSS JOIN LATERAL JoinOperator::CrossApply } else { @@ -5373,7 +5400,7 @@ impl<'a> Parser<'a> { relation: self.parse_table_factor()?, join_operator, } - } else if self.parse_keyword(Keyword::OUTER) { + } else if self.parse_keyword(Keyword::OUTER).is_some() { // MSSQL extension, similar to LEFT JOIN LATERAL .. ON 1=1 self.expect_keyword(Keyword::APPLY)?; Join { @@ -5381,7 +5408,7 @@ impl<'a> Parser<'a> { join_operator: JoinOperator::OuterApply, } } else { - let natural = self.parse_keyword(Keyword::NATURAL); + let natural = self.parse_keyword(Keyword::NATURAL).is_some(); let peek_keyword = if let Token::Word(w) = self.peek_token().token { w.keyword } else { @@ -5390,7 +5417,7 @@ impl<'a> Parser<'a> { let join_operator_type = match peek_keyword { Keyword::INNER | Keyword::JOIN => { - let _ = self.parse_keyword(Keyword::INNER); // [ INNER ] + let _ = self.parse_keyword(Keyword::INNER).is_some(); // [ INNER ] self.expect_keyword(Keyword::JOIN)?; JoinOperator::Inner } @@ -5445,7 +5472,7 @@ impl<'a> Parser<'a> { } Keyword::FULL => { let _ = self.next_token(); // consume FULL - let _ = self.parse_keyword(Keyword::OUTER); // [ OUTER ] + let _ = self.parse_keyword(Keyword::OUTER).is_some(); // [ OUTER ] self.expect_keyword(Keyword::JOIN)?; JoinOperator::FullOuter } @@ -5471,13 +5498,13 @@ impl<'a> Parser<'a> { /// A table name or a parenthesized subquery, followed by optional `[AS] alias` pub fn parse_table_factor(&mut self) -> Result { - if self.parse_keyword(Keyword::LATERAL) { + if self.parse_keyword(Keyword::LATERAL).is_some() { // LATERAL must always be followed by a subquery. if !self.consume_token(&Token::LParen) { self.expected("subquery after LATERAL", self.peek_token())?; } self.parse_derived_table_factor(Lateral) - } else if self.parse_keyword(Keyword::TABLE) { + } else if self.parse_keyword(Keyword::TABLE).is_some() { // parse table function (SELECT * FROM TABLE () [ AS ]) self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; @@ -5580,7 +5607,7 @@ impl<'a> Parser<'a> { self.expected("joined table", self.peek_token()) } } else if dialect_of!(self is BigQueryDialect | GenericDialect) - && self.parse_keyword(Keyword::UNNEST) + && self.parse_keyword(Keyword::UNNEST).is_some() { self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; @@ -5624,7 +5651,7 @@ impl<'a> Parser<'a> { let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; // MSSQL-specific table hints: let mut with_hints = vec![]; - if self.parse_keyword(Keyword::WITH) { + if self.parse_keyword(Keyword::WITH).is_some() { if self.consume_token(&Token::LParen) { with_hints = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -5662,10 +5689,10 @@ impl<'a> Parser<'a> { pub fn parse_join_constraint(&mut self, natural: bool) -> Result { if natural { Ok(JoinConstraint::Natural) - } else if self.parse_keyword(Keyword::ON) { + } else if self.parse_keyword(Keyword::ON).is_some() { let constraint = self.parse_expr()?; Ok(JoinConstraint::On(constraint)) - } else if self.parse_keyword(Keyword::USING) { + } else if self.parse_keyword(Keyword::USING).is_some() { let columns = self.parse_parenthesized_column_list(Mandatory, false)?; Ok(JoinConstraint::Using(columns)) } else { @@ -5700,9 +5727,9 @@ impl<'a> Parser<'a> { pub fn parse_grant_revoke_privileges_objects( &mut self, ) -> Result<(Privileges, GrantObjects), ParserError> { - let privileges = if self.parse_keyword(Keyword::ALL) { + let privileges = if self.parse_keyword(Keyword::ALL).is_some() { Privileges::All { - with_privileges_keyword: self.parse_keyword(Keyword::PRIVILEGES), + with_privileges_keyword: self.parse_keyword(Keyword::PRIVILEGES).is_some(), } } else { let (actions, err): (Vec<_>, Vec<_>) = self @@ -5817,8 +5844,8 @@ impl<'a> Parser<'a> { .parse_keywords(&[Keyword::GRANTED, Keyword::BY]) .then(|| self.parse_identifier().unwrap()); - let cascade = self.parse_keyword(Keyword::CASCADE); - let restrict = self.parse_keyword(Keyword::RESTRICT); + let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); + let restrict = self.parse_keyword(Keyword::RESTRICT).is_some(); if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in REVOKE"); } @@ -5846,7 +5873,7 @@ impl<'a> Parser<'a> { Some(SqliteOnConflict::Fail) } else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) { Some(SqliteOnConflict::Ignore) - } else if self.parse_keyword(Keyword::REPLACE) { + } else if self.parse_keyword(Keyword::REPLACE).is_some() { Some(SqliteOnConflict::Replace) } else { None @@ -5856,9 +5883,9 @@ impl<'a> Parser<'a> { let into = action == Some(Keyword::INTO); let overwrite = action == Some(Keyword::OVERWRITE); - let local = self.parse_keyword(Keyword::LOCAL); + let local = self.parse_keyword(Keyword::LOCAL).is_some(); - if self.parse_keyword(Keyword::DIRECTORY) { + if self.parse_keyword(Keyword::DIRECTORY).is_some() { let path = self.parse_literal_string()?; let file_format = if self.parse_keywords(&[Keyword::STORED, Keyword::AS]) { Some(self.parse_file_format()?) @@ -5875,12 +5902,12 @@ impl<'a> Parser<'a> { }) } else { // Hive lets you put table here regardless - let table = self.parse_keyword(Keyword::TABLE); + let table = self.parse_keyword(Keyword::TABLE).is_some(); let table_name = self.parse_object_name()?; let is_mysql = dialect_of!(self is MySqlDialect); let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?; - let partitioned = if self.parse_keyword(Keyword::PARTITION) { + let partitioned = if self.parse_keyword(Keyword::PARTITION).is_some() { self.expect_token(&Token::LParen)?; let r = Some(self.parse_comma_separated(Parser::parse_expr)?); self.expect_token(&Token::RParen)?; @@ -5893,8 +5920,8 @@ impl<'a> Parser<'a> { let after_columns = self.parse_parenthesized_column_list(Optional, false)?; let source = Box::new(self.parse_query()?); - let on = if self.parse_keyword(Keyword::ON) { - if self.parse_keyword(Keyword::CONFLICT) { + let on = if self.parse_keyword(Keyword::ON).is_some() { + if self.parse_keyword(Keyword::CONFLICT).is_some() { let conflict_target = if self.parse_keywords(&[Keyword::ON, Keyword::CONSTRAINT]) { Some(ConflictTarget::OnConstraint(self.parse_object_name()?)) @@ -5907,13 +5934,13 @@ impl<'a> Parser<'a> { }; self.expect_keyword(Keyword::DO)?; - let action = if self.parse_keyword(Keyword::NOTHING) { + let action = if self.parse_keyword(Keyword::NOTHING).is_some() { OnConflictAction::DoNothing } else { self.expect_keyword(Keyword::UPDATE)?; self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; - let selection = if self.parse_keyword(Keyword::WHERE) { + let selection = if self.parse_keyword(Keyword::WHERE).is_some() { Some(self.parse_expr()?) } else { None @@ -5940,7 +5967,7 @@ impl<'a> Parser<'a> { None }; - let returning = if self.parse_keyword(Keyword::RETURNING) { + let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -5966,19 +5993,19 @@ impl<'a> Parser<'a> { let table = self.parse_table_and_joins()?; self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; - let from = if self.parse_keyword(Keyword::FROM) + let from = if self.parse_keyword(Keyword::FROM).is_some() && dialect_of!(self is GenericDialect | PostgreSqlDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect) { Some(self.parse_table_and_joins()?) } else { None }; - let selection = if self.parse_keyword(Keyword::WHERE) { + let selection = if self.parse_keyword(Keyword::WHERE).is_some() { Some(self.parse_expr()?) } else { None }; - let returning = if self.parse_keyword(Keyword::RETURNING) { + let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -6028,10 +6055,12 @@ impl<'a> Parser<'a> { match self.parse_wildcard_expr()? { WildcardExpr::Expr(expr) => { let expr: Expr = if self.dialect.supports_filter_during_aggregation() - && self.parse_keyword(Keyword::FILTER) + && self.parse_keyword(Keyword::FILTER).is_some() { let i = self.index - 1; - if self.consume_token(&Token::LParen) && self.parse_keyword(Keyword::WHERE) { + if self.consume_token(&Token::LParen) + && self.parse_keyword(Keyword::WHERE).is_some() + { let filter = self.parse_expr()?; self.expect_token(&Token::RParen)?; Expr::AggregateExpressionWithFilter { @@ -6096,7 +6125,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_exclude( &mut self, ) -> Result, ParserError> { - let opt_exclude = if self.parse_keyword(Keyword::EXCLUDE) { + let opt_exclude = if self.parse_keyword(Keyword::EXCLUDE).is_some() { if self.consume_token(&Token::LParen) { let columns = self.parse_comma_separated(|parser| parser.parse_identifier())?; self.expect_token(&Token::RParen)?; @@ -6118,7 +6147,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_except( &mut self, ) -> Result, ParserError> { - let opt_except = if self.parse_keyword(Keyword::EXCEPT) { + let opt_except = if self.parse_keyword(Keyword::EXCEPT).is_some() { let idents = self.parse_parenthesized_column_list(Mandatory, false)?; match &idents[..] { [] => { @@ -6143,7 +6172,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_rename( &mut self, ) -> Result, ParserError> { - let opt_rename = if self.parse_keyword(Keyword::RENAME) { + let opt_rename = if self.parse_keyword(Keyword::RENAME).is_some() { if self.consume_token(&Token::LParen) { let idents = self.parse_comma_separated(|parser| parser.parse_identifier_with_alias())?; @@ -6164,9 +6193,9 @@ impl<'a> Parser<'a> { pub fn parse_order_by_expr(&mut self) -> Result { let expr = self.parse_expr()?; - let asc = if self.parse_keyword(Keyword::ASC) { + let asc = if self.parse_keyword(Keyword::ASC).is_some() { Some(true) - } else if self.parse_keyword(Keyword::DESC) { + } else if self.parse_keyword(Keyword::DESC).is_some() { Some(false) } else { None @@ -6198,7 +6227,7 @@ impl<'a> Parser<'a> { Some(Expr::Value(self.parse_number_value()?)) }; - let percent = self.parse_keyword(Keyword::PERCENT); + let percent = self.parse_keyword(Keyword::PERCENT).is_some(); let with_ties = self.parse_keywords(&[Keyword::WITH, Keyword::TIES]); @@ -6211,7 +6240,7 @@ impl<'a> Parser<'a> { /// Parse a LIMIT clause pub fn parse_limit(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::ALL) { + if self.parse_keyword(Keyword::ALL).is_some() { Ok(None) } else { Ok(Some(self.parse_expr()?)) @@ -6221,9 +6250,9 @@ impl<'a> Parser<'a> { /// Parse an OFFSET clause pub fn parse_offset(&mut self) -> Result { let value = self.parse_expr()?; - let rows = if self.parse_keyword(Keyword::ROW) { + let rows = if self.parse_keyword(Keyword::ROW).is_some() { OffsetRows::Row - } else if self.parse_keyword(Keyword::ROWS) { + } else if self.parse_keyword(Keyword::ROWS).is_some() { OffsetRows::Rows } else { OffsetRows::None @@ -6241,11 +6270,11 @@ impl<'a> Parser<'a> { (None, false) } else { let quantity = Expr::Value(self.parse_value()?); - let percent = self.parse_keyword(Keyword::PERCENT); + let percent = self.parse_keyword(Keyword::PERCENT).is_some(); self.expect_one_of_keywords(&[Keyword::ROW, Keyword::ROWS])?; (Some(quantity), percent) }; - let with_ties = if self.parse_keyword(Keyword::ONLY) { + let with_ties = if self.parse_keyword(Keyword::ONLY).is_some() { false } else if self.parse_keywords(&[Keyword::WITH, Keyword::TIES]) { true @@ -6266,12 +6295,12 @@ impl<'a> Parser<'a> { Keyword::SHARE => LockType::Share, _ => unreachable!(), }; - let of = if self.parse_keyword(Keyword::OF) { + let of = if self.parse_keyword(Keyword::OF).is_some() { Some(self.parse_object_name()?) } else { None }; - let nonblock = if self.parse_keyword(Keyword::NOWAIT) { + let nonblock = if self.parse_keyword(Keyword::NOWAIT).is_some() { Some(NonBlock::Nowait) } else if self.parse_keywords(&[Keyword::SKIP, Keyword::LOCKED]) { Some(NonBlock::SkipLocked) @@ -6289,7 +6318,7 @@ impl<'a> Parser<'a> { let mut explicit_row = false; let rows = self.parse_comma_separated(|parser| { - if parser.parse_keyword(Keyword::ROW) { + if parser.parse_keyword(Keyword::ROW).is_some() { explicit_row = true; } @@ -6331,7 +6360,7 @@ impl<'a> Parser<'a> { TransactionIsolationLevel::ReadCommitted } else if self.parse_keywords(&[Keyword::REPEATABLE, Keyword::READ]) { TransactionIsolationLevel::RepeatableRead - } else if self.parse_keyword(Keyword::SERIALIZABLE) { + } else if self.parse_keyword(Keyword::SERIALIZABLE).is_some() { TransactionIsolationLevel::Serializable } else { self.expected("isolation level", self.peek_token())? @@ -6370,8 +6399,8 @@ impl<'a> Parser<'a> { pub fn parse_commit_rollback_chain(&mut self) -> Result { let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]); - if self.parse_keyword(Keyword::AND) { - let chain = !self.parse_keyword(Keyword::NO); + if self.parse_keyword(Keyword::AND).is_some() { + let chain = !self.parse_keyword(Keyword::NO).is_some(); self.expect_keyword(Keyword::CHAIN)?; Ok(chain) } else { @@ -6380,7 +6409,7 @@ impl<'a> Parser<'a> { } pub fn parse_deallocate(&mut self) -> Result { - let prepare = self.parse_keyword(Keyword::PREPARE); + let prepare = self.parse_keyword(Keyword::PREPARE).is_some(); let name = self.parse_identifier()?; Ok(Statement::Deallocate { name, prepare }) } @@ -6423,10 +6452,10 @@ impl<'a> Parser<'a> { } self.expect_keyword(Keyword::WHEN)?; - let is_not_matched = self.parse_keyword(Keyword::NOT); + let is_not_matched = self.parse_keyword(Keyword::NOT).is_some(); self.expect_keyword(Keyword::MATCHED)?; - let predicate = if self.parse_keyword(Keyword::AND) { + let predicate = if self.parse_keyword(Keyword::AND).is_some() { Some(self.parse_expr()?) } else { None @@ -6494,7 +6523,7 @@ impl<'a> Parser<'a> { } pub fn parse_merge(&mut self) -> Result { - let into = self.parse_keyword(Keyword::INTO); + let into = self.parse_keyword(Keyword::INTO).is_some(); let table = self.parse_table_factor()?; @@ -6566,7 +6595,7 @@ impl<'a> Parser<'a> { } } //[ MINVALUE minvalue | NO MINVALUE ] - if self.parse_keyword(Keyword::MINVALUE) { + if self.parse_keyword(Keyword::MINVALUE).is_some() { sequence_options.push(SequenceOptions::MinValue(MinMaxValue::Some(Expr::Value( self.parse_number_value()?, )))); @@ -6623,10 +6652,11 @@ impl<'a> Parser<'a> { } impl Word { - pub fn to_ident(&self) -> Ident { + pub fn to_ident(&self, span: Span) -> Ident { Ident { value: self.value.clone(), quote_style: self.quote_style, + span, } } } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 2cbcf865e..5978161cd 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -24,9 +24,9 @@ use alloc::{ vec, vec::Vec, }; -use core::fmt; use core::iter::Peekable; use core::str::Chars; +use core::{cmp, fmt}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -330,7 +330,7 @@ impl fmt::Display for Whitespace { } /// Location in input string -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Eq, PartialEq, Hash, Clone, Copy, Ord, PartialOrd)] pub struct Location { /// Line number, starting from 1 pub line: u64, @@ -338,6 +338,12 @@ pub struct Location { pub column: u64, } +impl std::fmt::Debug for Location { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Location({}:{})", self.line, self.column) + } +} + impl Location { pub fn of(line: u64, column: u64) -> Self { Self { line, column } @@ -354,12 +360,18 @@ impl From<(u64, u64)> for Location { } } -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord, Copy)] pub struct Span { pub start: Location, pub end: Location, } +impl std::fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Span({:?}..{:?})", self.start, self.end) + } +} + impl Span { pub fn new(start: Location, end: Location) -> Span { Span { start, end } @@ -371,11 +383,24 @@ impl Span { end: Location { line: 0, column: 0 }, } } -} + pub fn union(&self, other: &Span) -> Span { + Span { + start: cmp::min(self.start, other.start), + end: cmp::max(self.end, other.end), + } + } + + pub fn union_opt(&self, other: &Option) -> Span { + match other { + Some(other) => self.union(&other), + None => self.clone(), + } + } +} /// A [Token] with [Location] attached to it -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Debug, Eq, Hash, Clone)] pub struct TokenWithLocation { pub token: Token, pub span: Span, @@ -383,10 +408,7 @@ pub struct TokenWithLocation { impl TokenWithLocation { pub fn new(token: Token, span: Span) -> TokenWithLocation { - TokenWithLocation { - token, - span, - } + TokenWithLocation { token, span } } pub fn wrap(token: Token) -> TokenWithLocation { @@ -398,6 +420,24 @@ impl TokenWithLocation { } } +impl PartialEq for TokenWithLocation { + fn eq(&self, other: &TokenWithLocation) -> bool { + self.token == other.token + } +} + +impl PartialOrd for TokenWithLocation { + fn partial_cmp(&self, other: &TokenWithLocation) -> Option { + self.token.partial_cmp(&other.token) + } +} + +impl Ord for TokenWithLocation { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.token.cmp(&other.token) + } +} + impl PartialEq for TokenWithLocation { fn eq(&self, other: &Token) -> bool { &self.token == other @@ -492,6 +532,7 @@ impl<'a> Tokenizer<'a> { for token_with_location in twl { tokens.push(token_with_location.token); } + Ok(tokens) } @@ -508,14 +549,14 @@ impl<'a> Tokenizer<'a> { let mut location = state.location(); while let Some(token) = self.next_token(&mut state)? { let span = location.span_to(state.location()); + dbg!(span, &token); - tokens.push(TokenWithLocation { - token, - span, - }); + tokens.push(TokenWithLocation { token, span }); location = state.location(); } + + dbg!(&tokens); Ok(tokens) } @@ -1858,11 +1899,23 @@ mod tests { let tokens = tokenizer.tokenize_with_location().unwrap(); let expected = vec![ TokenWithLocation::at(Token::make_keyword("SELECT"), (1, 1).into(), (1, 7).into()), - TokenWithLocation::at(Token::Whitespace(Whitespace::Space), (1, 7).into(), (1, 8).into()), + TokenWithLocation::at( + Token::Whitespace(Whitespace::Space), + (1, 7).into(), + (1, 8).into(), + ), TokenWithLocation::at(Token::make_word("a", None), (1, 8).into(), (1, 9).into()), TokenWithLocation::at(Token::Comma, (1, 9).into(), (1, 10).into()), - TokenWithLocation::at(Token::Whitespace(Whitespace::Newline), (1, 10).into(), (2, 1).into()), - TokenWithLocation::at(Token::Whitespace(Whitespace::Space), (2, 1).into(), (2, 2).into()), + TokenWithLocation::at( + Token::Whitespace(Whitespace::Newline), + (1, 10).into(), + (2, 1).into(), + ), + TokenWithLocation::at( + Token::Whitespace(Whitespace::Space), + (2, 1).into(), + (2, 2).into(), + ), TokenWithLocation::at(Token::make_word("b", None), (2, 2).into(), (2, 3).into()), ]; compare(expected, tokens); diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 3fe5cd92b..afbe96035 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -15,6 +15,7 @@ mod test_utils; use sqlparser::ast::*; use sqlparser::dialect::{BigQueryDialect, GenericDialect}; +use sqlparser::tokenizer::Span; use test_utils::*; #[test] @@ -317,6 +318,7 @@ fn parse_map_access_offset() { column: Box::new(Expr::Identifier(Ident { value: "d".to_string(), quote_style: None, + span: Span::empty(), })), keys: vec![Expr::Function(Function { name: ObjectName(vec!["offset".into()]), diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs index 3e974d56d..7cfca4d80 100644 --- a/tests/sqlparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -16,6 +16,7 @@ #[macro_use] mod test_utils; +use sqlparser::tokenizer::{Span, Token, TokenWithLocation}; use test_utils::*; use sqlparser::ast::Expr::{BinaryOp, Identifier, MapAccess}; @@ -32,12 +33,14 @@ fn parse_map_access_expr() { let select = clickhouse().verified_only_select(sql); assert_eq!( Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![UnnamedExpr(MapAccess { column: Box::new(Identifier(Ident { value: "string_values".to_string(), quote_style: None, + span: Span::empty(), })), keys: vec![Expr::Function(Function { name: ObjectName(vec!["indexOf".into()]), diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index c880eee7c..20fd92a0e 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -26,8 +26,9 @@ use sqlparser::dialect::{ AnsiDialect, BigQueryDialect, ClickHouseDialect, GenericDialect, HiveDialect, MsSqlDialect, MySqlDialect, PostgreSqlDialect, RedshiftSqlDialect, SQLiteDialect, SnowflakeDialect, }; -use sqlparser::keywords::ALL_KEYWORDS; +use sqlparser::keywords::{Keyword, ALL_KEYWORDS}; use sqlparser::parser::{Parser, ParserError}; +use sqlparser::tokenizer::{Span, Token, TokenWithLocation}; use test_utils::{ all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias, TestedDialects, @@ -224,6 +225,7 @@ fn parse_update_set_from() { subquery: Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![ @@ -834,6 +836,7 @@ fn parse_select_with_date_column_name() { &Expr::Identifier(Ident { value: "date".into(), quote_style: None, + span: Span::empty(), }), expr_from_projection(only(&select.projection)), ); @@ -1060,6 +1063,7 @@ fn parse_null_like() { alias: Ident { value: "col_null".to_owned(), quote_style: None, + span: Span::empty(), }, }, select.projection[0] @@ -1075,6 +1079,7 @@ fn parse_null_like() { alias: Ident { value: "null_col".to_owned(), quote_style: None, + span: Span::empty(), }, }, select.projection[1] @@ -1909,6 +1914,7 @@ fn parse_listagg() { expr: Expr::Identifier(Ident { value: "id".to_string(), quote_style: None, + span: Span::empty(), }), asc: None, nulls_first: None, @@ -1917,6 +1923,7 @@ fn parse_listagg() { expr: Expr::Identifier(Ident { value: "username".to_string(), quote_style: None, + span: Span::empty(), }), asc: None, nulls_first: None, @@ -3442,11 +3449,13 @@ fn parse_interval_and_or_xor() { let expected_ast = vec![Statement::Query(Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![UnnamedExpr(Expr::Identifier(Ident { value: "col".to_string(), quote_style: None, + span: Span::empty(), }))], into: None, from: vec![TableWithJoins { @@ -3454,6 +3463,7 @@ fn parse_interval_and_or_xor() { name: ObjectName(vec![Ident { value: "test".to_string(), quote_style: None, + span: Span::empty(), }]), alias: None, args: None, @@ -3467,12 +3477,14 @@ fn parse_interval_and_or_xor() { left: Box::new(Expr::Identifier(Ident { value: "d3_date".to_string(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Gt, right: Box::new(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident { value: "d1_date".to_string(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Plus, right: Box::new(Expr::Interval { @@ -3491,12 +3503,14 @@ fn parse_interval_and_or_xor() { left: Box::new(Expr::Identifier(Ident { value: "d2_date".to_string(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Gt, right: Box::new(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident { value: "d1_date".to_string(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Plus, right: Box::new(Expr::Interval { @@ -3557,6 +3571,7 @@ fn parse_at_timezone() { name: ObjectName(vec![Ident { value: "FROM_UNIXTIME".to_string(), quote_style: None, + span: Span::empty(), }]), args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero.clone()))], over: None, @@ -3576,6 +3591,7 @@ fn parse_at_timezone() { name: ObjectName(vec![Ident { value: "DATE_FORMAT".to_string(), quote_style: None, + span: Span::empty(), },],), args: vec![ FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::AtTimeZone { @@ -3583,6 +3599,7 @@ fn parse_at_timezone() { name: ObjectName(vec![Ident { value: "FROM_UNIXTIME".to_string(), quote_style: None, + span: Span::empty(), },],), args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero))], over: None, @@ -3602,6 +3619,7 @@ fn parse_at_timezone() { alias: Ident { value: "hour".to_string(), quote_style: Some('"'), + span: Span::empty(), }, }, only(&select.projection), @@ -4286,10 +4304,12 @@ fn parse_recursive_cte() { name: Ident { value: "nums".to_string(), quote_style: None, + span: Span::empty(), }, columns: vec![Ident { value: "val".to_string(), quote_style: None, + span: Span::empty(), }], }, query: Box::new(cte_query), @@ -5449,10 +5469,12 @@ fn parse_grant() { Ident { value: "shape".into(), quote_style: None, + span: Span::empty(), }, Ident { value: "size".into(), quote_style: None, + span: Span::empty(), }, ]) }, @@ -5642,6 +5664,7 @@ fn parse_merge() { subquery: Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![SelectItem::Wildcard( @@ -5676,6 +5699,7 @@ fn parse_merge() { name: Ident { value: "stg".to_string(), quote_style: None, + span: Span::empty(), }, columns: vec![], }), @@ -5822,7 +5846,8 @@ fn test_lock_table() { lock.of.unwrap().0, vec![Ident { value: "school".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert!(lock.nonblock.is_none()); @@ -5836,7 +5861,8 @@ fn test_lock_table() { lock.of.unwrap().0, vec![Ident { value: "school".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert!(lock.nonblock.is_none()); @@ -5850,7 +5876,8 @@ fn test_lock_table() { lock.of.unwrap().0, vec![Ident { value: "school".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert!(lock.nonblock.is_none()); @@ -5860,7 +5887,8 @@ fn test_lock_table() { lock.of.unwrap().0, vec![Ident { value: "student".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert!(lock.nonblock.is_none()); @@ -5877,7 +5905,8 @@ fn test_lock_nonblock() { lock.of.unwrap().0, vec![Ident { value: "school".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert_eq!(lock.nonblock.unwrap(), NonBlock::SkipLocked); @@ -5891,7 +5920,8 @@ fn test_lock_nonblock() { lock.of.unwrap().0, vec![Ident { value: "school".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }] ); assert_eq!(lock.nonblock.unwrap(), NonBlock::Nowait); diff --git a/tests/sqlparser_custom_dialect.rs b/tests/sqlparser_custom_dialect.rs index a700dda11..e01c752d7 100644 --- a/tests/sqlparser_custom_dialect.rs +++ b/tests/sqlparser_custom_dialect.rs @@ -106,7 +106,7 @@ fn custom_statement_parser() -> Result<(), ParserError> { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::SELECT) { + if parser.parse_keyword(Keyword::SELECT).is_some() { for _ in 0..3 { let _ = parser.next_token(); } diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 41b0803e4..c7811049f 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -16,6 +16,7 @@ #[macro_use] mod test_utils; +use sqlparser::tokenizer::Span; use test_utils::*; use sqlparser::ast::*; @@ -132,7 +133,8 @@ fn parse_mssql_create_role() { authorization_owner, Some(ObjectName(vec![Ident { value: "helena".into(), - quote_style: None + quote_style: None, + span: Span::empty(), }])) ); } diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 508ae8461..45aecb34c 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -18,7 +18,9 @@ use sqlparser::ast::Expr; use sqlparser::ast::Value; use sqlparser::ast::*; use sqlparser::dialect::{GenericDialect, MySqlDialect}; +use sqlparser::tokenizer::Span; use sqlparser::tokenizer::Token; +use sqlparser::tokenizer::TokenWithLocation; use test_utils::*; #[macro_use] @@ -445,11 +447,13 @@ fn parse_quote_identifiers_2() { Statement::Query(Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "quoted ` identifier".into(), quote_style: Some('`'), + span: Span::empty(), }))], into: None, from: vec![], @@ -479,11 +483,13 @@ fn parse_quote_identifiers_3() { Statement::Query(Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "`quoted identifier`".into(), quote_style: Some('`'), + span: Span::empty(), }))], into: None, from: vec![], @@ -966,6 +972,8 @@ fn parse_alter_table_change_column() { #[test] #[cfg(not(feature = "bigdecimal"))] fn parse_substring_in_select() { + use sqlparser::tokenizer::Span; + let sql = "SELECT DISTINCT SUBSTRING(description, 0, 1) FROM test"; match mysql().one_statement_parses_to( sql, @@ -976,12 +984,14 @@ fn parse_substring_in_select() { Box::new(Query { with: None, body: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: true, top: None, projection: vec![SelectItem::UnnamedExpr(Expr::Substring { expr: Box::new(Expr::Identifier(Ident { value: "description".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), })), substring_from: Some(Box::new(Expr::Value(Value::Number( "0".to_string(), @@ -997,7 +1007,8 @@ fn parse_substring_in_select() { relation: TableFactor::Table { name: ObjectName(vec![Ident { value: "test".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }]), alias: None, args: None, diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 496a61843..1baf37fa9 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -16,6 +16,7 @@ #[macro_use] mod test_utils; +use sqlparser::tokenizer::{Span, Token, TokenWithLocation}; use test_utils::*; use sqlparser::ast::*; @@ -792,7 +793,8 @@ fn parse_set() { variable: ObjectName(vec![Ident::new("a")]), value: vec![Expr::Identifier(Ident { value: "b".into(), - quote_style: None + quote_style: None, + span: Span::empty(), })], } ); @@ -834,7 +836,8 @@ fn parse_set() { variable: ObjectName(vec![Ident::new("a")]), value: vec![Expr::Identifier(Ident { value: "DEFAULT".into(), - quote_style: None + quote_style: None, + span: Span::empty(), })], } ); @@ -859,7 +862,8 @@ fn parse_set() { variable: ObjectName(vec![Ident::new("a"), Ident::new("b"), Ident::new("c")]), value: vec![Expr::Identifier(Ident { value: "b".into(), - quote_style: None + quote_style: None, + span: Span::empty(), })], } ); @@ -931,6 +935,7 @@ fn parse_set_role() { role_name: Some(Ident { value: "rolename".to_string(), quote_style: Some('\"'), + span: Span::empty(), }), } ); @@ -945,6 +950,7 @@ fn parse_set_role() { role_name: Some(Ident { value: "rolename".to_string(), quote_style: Some('\''), + span: Span::empty(), }), } ); @@ -1215,7 +1221,8 @@ fn parse_pg_on_conflict() { selection: Some(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident { value: "dsize".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Gt, right: Box::new(Expr::Value(Value::Placeholder("$2".to_string()))) @@ -1252,7 +1259,8 @@ fn parse_pg_on_conflict() { selection: Some(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident { value: "dsize".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), })), op: BinaryOperator::Gt, right: Box::new(Expr::Value(Value::Placeholder("$2".to_string()))) @@ -1445,11 +1453,13 @@ fn parse_array_index_expr() { num[0].clone(), Expr::Identifier(Ident { value: "baz".to_string(), - quote_style: Some('"') + quote_style: Some('"'), + span: Span::empty(), }), Expr::Identifier(Ident { value: "fooz".to_string(), - quote_style: Some('"') + quote_style: Some('"'), + span: Span::empty(), }) ], }, @@ -1499,6 +1509,7 @@ fn parse_array_subquery_expr() { op: SetOperator::Union, set_quantifier: SetQuantifier::None, left: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![SelectItem::UnnamedExpr(Expr::Value(Value::Number( @@ -1520,6 +1531,7 @@ fn parse_array_subquery_expr() { qualify: None, }))), right: Box::new(SetExpr::Select(Box::new(Select { + select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: false, top: None, projection: vec![SelectItem::UnnamedExpr(Expr::Value(Value::Number( @@ -1999,6 +2011,7 @@ fn parse_custom_operator() { left: Box::new(Expr::Identifier(Ident { value: "relname".into(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::PGCustomBinaryOperator(vec![ "database".into(), @@ -2018,6 +2031,7 @@ fn parse_custom_operator() { left: Box::new(Expr::Identifier(Ident { value: "relname".into(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::PGCustomBinaryOperator(vec!["pg_catalog".into(), "~".into()]), right: Box::new(Expr::Value(Value::SingleQuotedString("^(table)$".into()))) @@ -2033,6 +2047,7 @@ fn parse_custom_operator() { left: Box::new(Expr::Identifier(Ident { value: "relname".into(), quote_style: None, + span: Span::empty(), })), op: BinaryOperator::PGCustomBinaryOperator(vec!["~".into()]), right: Box::new(Expr::Value(Value::SingleQuotedString("^(table)$".into()))) @@ -2428,7 +2443,8 @@ fn parse_drop_function() { func_desc: vec![DropFunctionDesc { name: ObjectName(vec![Ident { value: "test_func".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }]), args: None }], @@ -2444,7 +2460,8 @@ fn parse_drop_function() { func_desc: vec![DropFunctionDesc { name: ObjectName(vec![Ident { value: "test_func".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }]), args: Some(vec![ OperateFunctionArg::with_name("a", DataType::Integer(None)), @@ -2469,7 +2486,8 @@ fn parse_drop_function() { DropFunctionDesc { name: ObjectName(vec![Ident { value: "test_func1".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }]), args: Some(vec![ OperateFunctionArg::with_name("a", DataType::Integer(None)), @@ -2487,7 +2505,8 @@ fn parse_drop_function() { DropFunctionDesc { name: ObjectName(vec![Ident { value: "test_func2".to_string(), - quote_style: None + quote_style: None, + span: Span::empty(), }]), args: Some(vec![ OperateFunctionArg::with_name("a", DataType::Varchar(None)), @@ -2556,6 +2575,7 @@ fn parse_dollar_quoted_string() { alias: Ident { value: "col_name".into(), quote_style: None, + span: Span::empty(), }, } ); diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index 7597ee981..ca1ba03de 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -13,6 +13,7 @@ #[macro_use] mod test_utils; +use sqlparser::tokenizer::Span; use test_utils::*; use sqlparser::ast::*; @@ -25,7 +26,8 @@ fn test_square_brackets_over_db_schema_table_name() { select.projection[0], SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "col1".to_string(), - quote_style: Some('[') + quote_style: Some('['), + span: Span::empty(), })), ); assert_eq!( @@ -35,11 +37,13 @@ fn test_square_brackets_over_db_schema_table_name() { name: ObjectName(vec![ Ident { value: "test_schema".to_string(), - quote_style: Some('[') + quote_style: Some('['), + span: Span::empty(), }, Ident { value: "test_table".to_string(), - quote_style: Some('[') + quote_style: Some('['), + span: Span::empty(), } ]), alias: None, @@ -69,7 +73,8 @@ fn test_double_quotes_over_db_schema_table_name() { select.projection[0], SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "col1".to_string(), - quote_style: Some('"') + quote_style: Some('"'), + span: Span::empty(), })), ); assert_eq!( @@ -79,11 +84,13 @@ fn test_double_quotes_over_db_schema_table_name() { name: ObjectName(vec![ Ident { value: "test_schema".to_string(), - quote_style: Some('"') + quote_style: Some('"'), + span: Span::empty(), }, Ident { value: "test_table".to_string(), - quote_style: Some('"') + quote_style: Some('"'), + span: Span::empty(), } ]), alias: None, From 079a4e273faf3441527238b2c612ff25c391bcc0 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 17 Sep 2024 11:16:03 +0200 Subject: [PATCH 03/23] implement a bunch more stuff --- src/ast/query.rs | 1 + src/ast/spans.rs | 179 +++++++++++++++++++++++++++++++++++++---------- src/parser.rs | 3 +- src/tokenizer.rs | 14 ++-- 4 files changed, 155 insertions(+), 42 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index 53ce5f9fb..1374180fb 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -314,6 +314,7 @@ impl fmt::Display for LateralView { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct With { + pub with_token: TokenWithLocation, pub recursive: bool, pub cte_tables: Vec, } diff --git a/src/ast/spans.rs b/src/ast/spans.rs index c5169d392..9f152f0b4 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -3,7 +3,7 @@ use core::iter; use crate::ast; use crate::tokenizer::Span; -use super::{Expr, Join, Query, Select, SelectItem, SetExpr, TableFactor, TableWithJoins}; +use super::{Cte, Expr, Join, JoinConstraint, JoinOperator, Query, Select, SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins, With}; pub trait Spanned { fn span(&self) -> Span; @@ -11,7 +11,29 @@ pub trait Spanned { impl Spanned for Query { fn span(&self) -> Span { - self.body.span() + union_spans( + self.with.iter().map(|item| item.span()) + .chain(core::iter::once(self.body.span())) + ) + } +} + +impl Spanned for With { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.with_token.span.clone()) + .chain(self.cte_tables.iter().map(|item| item.span())) + ) + } +} + +impl Spanned for Cte { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.alias.span()) + .chain(core::iter::once(self.query.span())) + .chain(self.from.iter().map(|item| item.span)) + ) } } @@ -25,7 +47,7 @@ impl Spanned for SetExpr { set_quantifier, left, right, - } => todo!(), + } => left.span().union(&right.span()), SetExpr::Values(values) => todo!(), SetExpr::Insert(statement) => todo!(), SetExpr::Table(table) => todo!(), @@ -37,23 +59,23 @@ impl Spanned for Expr { fn span(&self) -> Span { match self { Expr::Identifier(ident) => ident.span, - Expr::CompoundIdentifier(vec) => todo!(), + Expr::CompoundIdentifier(vec) => union_spans(vec.iter().map(|i| i.span)), Expr::JsonAccess { left, - operator, + operator: _, right, - } => todo!(), - Expr::CompositeAccess { expr, key } => todo!(), - Expr::IsFalse(expr) => todo!(), - Expr::IsNotFalse(expr) => todo!(), - Expr::IsTrue(expr) => todo!(), - Expr::IsNotTrue(expr) => todo!(), - Expr::IsNull(expr) => todo!(), - Expr::IsNotNull(expr) => todo!(), - Expr::IsUnknown(expr) => todo!(), - Expr::IsNotUnknown(expr) => todo!(), - Expr::IsDistinctFrom(expr, expr1) => todo!(), - Expr::IsNotDistinctFrom(expr, expr1) => todo!(), + } => left.span().union(&right.span()), + Expr::CompositeAccess { expr, key } => expr.span().union(&key.span), + Expr::IsFalse(expr) => expr.span(), + Expr::IsNotFalse(expr) => expr.span(), + Expr::IsTrue(expr) => expr.span(), + Expr::IsNotTrue(expr) => expr.span(), + Expr::IsNull(expr) => expr.span(), + Expr::IsNotNull(expr) => expr.span(), + Expr::IsUnknown(expr) => expr.span(), + Expr::IsNotUnknown(expr) => expr.span(), + Expr::IsDistinctFrom(lhs, rhs) => lhs.span().union(&rhs.span()), + Expr::IsNotDistinctFrom(lhs, rhs) => lhs.span().union(&rhs.span()), Expr::InList { expr, list, @@ -75,7 +97,7 @@ impl Spanned for Expr { low, high, } => todo!(), - Expr::BinaryOp { left, op, right } => todo!(), + Expr::BinaryOp { left, op, right } => left.span().union(&right.span()), Expr::Like { negated, expr, @@ -205,7 +227,7 @@ impl Spanned for TableFactor { lateral, subquery, alias, - } => todo!(), + } => subquery.span().union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::TableFunction { expr, alias } => todo!(), TableFactor::UNNEST { alias, @@ -221,9 +243,47 @@ impl Spanned for TableFactor { } } +impl Spanned for TableAlias { + fn span(&self) -> Span { + union_spans( + iter::once(self.name.span) + .chain(self.columns.iter().map(|i| i.span)) + ) + } +} + impl Spanned for Join { fn span(&self) -> Span { - todo!() + self.relation.span().union(&self.join_operator.span()) + } +} + +impl Spanned for JoinOperator { + fn span(&self) -> Span { + match self { + JoinOperator::Inner(join_constraint) => join_constraint.span(), + JoinOperator::LeftOuter(join_constraint) => join_constraint.span(), + JoinOperator::RightOuter(join_constraint) => join_constraint.span(), + JoinOperator::FullOuter(join_constraint) => join_constraint.span(), + JoinOperator::CrossJoin => Span::empty(), + JoinOperator::LeftSemi(join_constraint) => join_constraint.span(), + JoinOperator::RightSemi(join_constraint) => join_constraint.span(), + JoinOperator::LeftAnti(join_constraint) => join_constraint.span(), + JoinOperator::RightAnti(join_constraint) => join_constraint.span(), + JoinOperator::CrossApply => Span::empty(), + JoinOperator::OuterApply => Span::empty(), + } + } +} + +impl Spanned for JoinConstraint { + fn span(&self) -> Span { + match self { + JoinConstraint::On(expr) => expr.span(), + JoinConstraint::Using(vec) => union_spans(vec.iter().map(|i| i.span)), + JoinConstraint::Natural => Span::empty(), + JoinConstraint::None => Span::empty(), + } } } @@ -250,37 +310,82 @@ impl Spanned for Select { } } -/** - * TODO: - * - * - CTE - * - With - * - SetExpr - * - Fetch - * - Lock Clause - */ -struct Ignore; - #[cfg(test)] pub mod tests { - use crate::dialect::{Dialect, GenericDialect}; + use ast::query; + + use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect}; use crate::tokenizer::Span; use super::*; #[test] - fn test_span() { + fn test_query_span() { let query = crate::parser::Parser::new(&GenericDialect::default()) - .try_with_sql("SELECT id, name FROM users") + .try_with_sql("SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id") .unwrap() .parse_query() .unwrap(); - dbg!(&query); - assert_eq!( query.span(), - Span::new((1, 1).into(), (1, 54 - 28 + 1).into()) + Span::new((1, 1).into(), (1, 109 - 28 + 1).into()) ); } + + + #[test] + pub fn test_union() { + let query = crate::parser::Parser::new(&GenericDialect::default()) + .try_with_sql("SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source") + .unwrap() + .parse_query() + .unwrap(); + + query.span(); + } + + #[test] + pub fn test_subquery() { + let query = crate::parser::Parser::new(&GenericDialect::default()) + .try_with_sql("SELECT a FROM (SELECT a FROM postgres.public.source) AS b") + .unwrap() + .parse_query() + .unwrap(); + + query.span(); + } + + #[test] + pub fn test_cte() { + let query = crate::parser::Parser::new(&GenericDialect::default()) + .try_with_sql("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") + .unwrap() + .parse_query() + .unwrap(); + + query.span(); + } + + #[test] + pub fn test_snowflake_lateral_flatten() { + let query = crate::parser::Parser::new(&SnowflakeDialect::default()) + .try_with_sql("SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED") + .unwrap() + .parse_query() + .unwrap(); + + query.span(); + } + + #[test] + pub fn test_wildcard_from_cte() { + let query = crate::parser::Parser::new(&GenericDialect::default()) + .try_with_sql("WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte") + .unwrap() + .parse_query() + .unwrap(); + + query.span(); + } } diff --git a/src/parser.rs b/src/parser.rs index 2446553d3..f74834789 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4756,8 +4756,9 @@ impl<'a> Parser<'a> { /// expect the initial keyword to be already consumed pub fn parse_query(&mut self) -> Result { let _guard = self.recursion_counter.try_decrease()?; - let with = if self.parse_keyword(Keyword::WITH).is_some() { + let with = if let Some(with_token) = self.parse_keyword(Keyword::WITH) { Some(With { + with_token, recursive: self.parse_keyword(Keyword::RECURSIVE).is_some(), cte_tables: self.parse_comma_separated(Parser::parse_cte)?, }) diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 5978161cd..0a3118831 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -373,11 +373,13 @@ impl std::fmt::Debug for Span { } impl Span { + const EMPTY : Span = Self::empty(); + pub fn new(start: Location, end: Location) -> Span { Span { start, end } } - pub fn empty() -> Span { + pub const fn empty() -> Span { Span { start: Location { line: 0, column: 0 }, end: Location { line: 0, column: 0 }, @@ -385,9 +387,13 @@ impl Span { } pub fn union(&self, other: &Span) -> Span { - Span { - start: cmp::min(self.start, other.start), - end: cmp::max(self.end, other.end), + match (self, other) { + (&Span::EMPTY, _) => other.clone(), + (_, &Span::EMPTY) => self.clone(), + _ => Span { + start: cmp::min(self.start, other.start), + end: cmp::max(self.end, other.end), + }, } } From df9ab1e87ffdf01f938c306740ec9655c93ad3dc Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 17 Sep 2024 13:56:31 +0200 Subject: [PATCH 04/23] fix: restore old behaviour of location display --- src/tokenizer.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a49e5455a..f0f861753 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -424,9 +424,11 @@ pub struct Location { pub column: u64, } - impl std::fmt::Display for Location { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.line == 0 { + return Ok(()); + } write!(f, " at Line: {}, Column: {}", self.line, self.column) } } @@ -466,7 +468,7 @@ impl std::fmt::Debug for Span { } impl Span { - const EMPTY : Span = Self::empty(); + const EMPTY: Span = Self::empty(); pub fn new(start: Location, end: Location) -> Span { Span { start, end } From b718c76359b4f57ef2715c597199994d29e007d4 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 17 Sep 2024 15:44:09 +0200 Subject: [PATCH 05/23] implement spans for eveeeeen more ast nodes --- src/ast/mod.rs | 4 +- src/ast/spans.rs | 344 ++++++++++++++++++++++++++++++++++++++-------- src/parser/mod.rs | 128 +++++++++-------- 3 files changed, 366 insertions(+), 110 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index ae73517f7..a9f1c088d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -81,8 +81,10 @@ mod dml; pub mod helpers; mod operator; mod query; -mod trigger; mod spans; +pub use spans::Spanned; + +mod trigger; mod value; #[cfg(feature = "visitor")] diff --git a/src/ast/spans.rs b/src/ast/spans.rs index ed1c9c9e3..b29a91bb4 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -3,7 +3,13 @@ use core::iter; use crate::ast; use crate::tokenizer::Span; -use super::{Cte, Expr, FunctionArg, FunctionArgExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, Query, Select, SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins, With}; +use super::{ + Cte, ExceptSelectItem, ExcludeSelectItem, Expr, Function, FunctionArg, FunctionArgExpr, + FunctionArgumentClause, FunctionArgumentList, FunctionArguments, HavingBound, IlikeSelectItem, + Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, Query, RenameSelectItem, + ReplaceSelectElement, ReplaceSelectItem, Select, SelectItem, SetExpr, TableAlias, TableFactor, + TableWithJoins, Value, WildcardAdditionalOptions, With, +}; pub trait Spanned { fn span(&self) -> Span; @@ -12,8 +18,10 @@ pub trait Spanned { impl Spanned for Query { fn span(&self) -> Span { union_spans( - self.with.iter().map(|item| item.span()) - .chain(core::iter::once(self.body.span())) + self.with + .iter() + .map(|item| item.span()) + .chain(core::iter::once(self.body.span())), ) } } @@ -22,7 +30,7 @@ impl Spanned for With { fn span(&self) -> Span { union_spans( core::iter::once(self.with_token.span.clone()) - .chain(self.cte_tables.iter().map(|item| item.span())) + .chain(self.cte_tables.iter().map(|item| item.span())), ) } } @@ -32,7 +40,7 @@ impl Spanned for Cte { union_spans( core::iter::once(self.alias.span()) .chain(core::iter::once(self.query.span())) - .chain(self.from.iter().map(|item| item.span)) + .chain(self.from.iter().map(|item| item.span)), ) } } @@ -41,7 +49,7 @@ impl Spanned for SetExpr { fn span(&self) -> Span { match self { SetExpr::Select(select) => select.span(), - SetExpr::Query(query) => todo!(), + SetExpr::Query(query) => query.span(), SetExpr::SetOperation { op, set_quantifier, @@ -76,7 +84,9 @@ impl Spanned for Expr { expr, list, negated, - } => todo!(), + } => union_spans( + core::iter::once(expr.span()).chain(list.iter().map(|item| item.span())), + ), Expr::InSubquery { expr, subquery, @@ -122,11 +132,11 @@ impl Spanned for Expr { overlay_for, } => todo!(), Expr::Collate { expr, collation } => todo!(), - Expr::Nested(expr) => todo!(), - Expr::Value(value) => todo!(), + Expr::Nested(expr) => expr.span(), + Expr::Value(value) => value.span(), Expr::TypedString { data_type, value } => todo!(), Expr::MapAccess { column, keys } => todo!(), - Expr::Function(function) => todo!(), + Expr::Function(function) => function.span(), Expr::GroupingSets(vec) => todo!(), Expr::Cube(vec) => todo!(), Expr::Rollup(vec) => todo!(), @@ -138,20 +148,86 @@ impl Spanned for Expr { opt_search_modifier, } => todo!(), Expr::JsonAccess { value, path } => value.span().union(&path.span()), - Expr::RLike { negated, expr, pattern, regexp } => todo!(), - Expr::AnyOp { left, compare_op, right } => todo!(), - Expr::AllOp { left, compare_op, right } => todo!(), - Expr::UnaryOp { op, expr } => todo!(), - Expr::Convert { expr, data_type, charset, target_before_value, styles } => todo!(), - Expr::Cast { kind, expr, data_type, format } => expr.span(), - Expr::AtTimeZone { timestamp, time_zone } => todo!(), - Expr::Extract { field, syntax, expr } => todo!(), - Expr::Substring { expr, substring_from, substring_for, special } => todo!(), - Expr::Trim { expr, trim_where, trim_what, trim_characters } => todo!(), - Expr::IntroducedString { introducer, value } => todo!(), - Expr::Case { operand, conditions, results, else_result } => todo!(), - Expr::Exists { subquery, negated } => todo!(), - Expr::Subquery(query) => todo!(), + Expr::RLike { + negated, + expr, + pattern, + regexp, + } => todo!(), + Expr::AnyOp { + left, + compare_op, + right, + } => todo!(), + Expr::AllOp { + left, + compare_op, + right, + } => todo!(), + Expr::UnaryOp { op, expr } => expr.span(), + Expr::Convert { + expr, + data_type, + charset, + target_before_value, + styles, + } => todo!(), + Expr::Cast { + kind, + expr, + data_type, + format, + } => expr.span(), + Expr::AtTimeZone { + timestamp, + time_zone, + } => todo!(), + Expr::Extract { + field, + syntax, + expr, + } => todo!(), + Expr::Substring { + expr, + substring_from, + substring_for, + special, + } => union_spans( + core::iter::once(expr.span()) + .chain(substring_from.as_ref().map(|i| i.span())) + .chain(substring_for.as_ref().map(|i| i.span())), + ), + Expr::Trim { + expr, + trim_where, + trim_what, + trim_characters, + } => union_spans( + core::iter::once(expr.span()) + .chain(trim_what.as_ref().map(|i| i.span())) + .chain( + trim_characters + .as_ref() + .map(|items| union_spans(items.iter().map(|i| i.span()))), + ), + ), + Expr::IntroducedString { introducer, value } => value.span(), + Expr::Case { + operand, + conditions, + results, + else_result, + } => union_spans( + operand + .as_ref() + .map(|i| i.span()) + .into_iter() + .chain(conditions.iter().map(|i| i.span())) + .chain(results.iter().map(|i| i.span())) + .chain(else_result.as_ref().map(|i| i.span())), + ), + Expr::Exists { subquery, negated } => subquery.span(), + Expr::Subquery(query) => query.span(), Expr::Struct { values, fields } => todo!(), Expr::Named { expr, name } => todo!(), Expr::Dictionary(vec) => todo!(), @@ -167,13 +243,59 @@ impl Spanned for Expr { } } +impl Spanned for Function { + fn span(&self) -> Span { + union_spans( + self.name + .0 + .iter() + .map(|i| i.span) + .chain(iter::once(self.args.span())), + ) + } +} + +impl Spanned for FunctionArguments { + fn span(&self) -> Span { + match self { + FunctionArguments::None => Span::empty(), + FunctionArguments::Subquery(query) => query.span(), + FunctionArguments::List(list) => list.span(), + } + } +} + +impl Spanned for FunctionArgumentList { + fn span(&self) -> Span { + union_spans( + // # todo: duplicate-treatment span + self.args + .iter() + .map(|i| i.span()) + .chain(self.clauses.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for FunctionArgumentClause { + fn span(&self) -> Span { + match self { + FunctionArgumentClause::IgnoreOrRespectNulls(null_treatment) => Span::empty(), + FunctionArgumentClause::OrderBy(vec) => union_spans(vec.iter().map(|i| i.expr.span())), + FunctionArgumentClause::Limit(expr) => expr.span(), + FunctionArgumentClause::OnOverflow(list_agg_on_overflow) => Span::empty(), + FunctionArgumentClause::Having(HavingBound(kind, expr)) => expr.span(), + FunctionArgumentClause::Separator(value) => value.span(), + } + } +} + impl Spanned for JsonPath { fn span(&self) -> Span { union_spans(self.path.iter().map(|i| i.span())) } } - impl Spanned for JsonPathElem { fn span(&self) -> Span { match self { @@ -188,17 +310,80 @@ impl Spanned for SelectItem { match self { SelectItem::UnnamedExpr(expr) => expr.span(), SelectItem::ExprWithAlias { expr, alias } => expr.span().union(&alias.span), - SelectItem::QualifiedWildcard(object_name, wildcard_additional_options) => object_name - .0 - .iter() - .map(|i| i.span) - .reduce(|acc, item| acc.union(&item)) - .expect("Empty iterator"), - SelectItem::Wildcard(wildcard_additional_options) => todo!(), + SelectItem::QualifiedWildcard(object_name, wildcard_additional_options) => union_spans( + object_name + .0 + .iter() + .map(|i| i.span) + .chain(iter::once(wildcard_additional_options.span())), + ), + SelectItem::Wildcard(wildcard_additional_options) => wildcard_additional_options.span(), + } + } +} + +impl Spanned for WildcardAdditionalOptions { + fn span(&self) -> Span { + union_spans( + self.opt_ilike + .as_ref() + .map(|i| i.span()) + .into_iter() + .chain(self.opt_exclude.as_ref().map(|i| i.span()).into_iter()) + .chain(self.opt_rename.as_ref().map(|i| i.span()).into_iter()) + .chain(self.opt_replace.as_ref().map(|i| i.span()).into_iter()) + .chain(self.opt_except.as_ref().map(|i| i.span()).into_iter()), + ) + } +} + +impl Spanned for IlikeSelectItem { + fn span(&self) -> Span { + Span::empty() // # todo: missing span + } +} + +impl Spanned for ExcludeSelectItem { + fn span(&self) -> Span { + match self { + ExcludeSelectItem::Single(ident) => ident.span, + ExcludeSelectItem::Multiple(vec) => union_spans(vec.iter().map(|i| i.span)), } } } +impl Spanned for RenameSelectItem { + fn span(&self) -> Span { + match self { + RenameSelectItem::Single(ident) => ident.ident.span.union(&ident.alias.span), + RenameSelectItem::Multiple(vec) => { + union_spans(vec.iter().map(|i| i.ident.span.union(&i.alias.span))) + } + } + } +} + +impl Spanned for ExceptSelectItem { + fn span(&self) -> Span { + union_spans( + iter::once(self.first_element.span) + .chain(self.additional_elements.iter().map(|i| i.span)), + ) + } +} + +impl Spanned for ReplaceSelectItem { + fn span(&self) -> Span { + union_spans(self.items.iter().map(|i| i.span())) + } +} + +impl Spanned for ReplaceSelectElement { + fn span(&self) -> Span { + self.expr.span().union(&self.column_name.span) + } +} + impl Spanned for TableFactor { fn span(&self) -> Span { match self { @@ -227,7 +412,9 @@ impl Spanned for TableFactor { lateral, subquery, alias, - } => subquery.span().union_opt(&alias.as_ref().map(|alias| alias.span())), + } => subquery + .span() + .union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::TableFunction { expr, alias } => todo!(), TableFactor::UNNEST { alias, @@ -240,26 +427,62 @@ impl Spanned for TableFactor { table_with_joins, alias, } => todo!(), - TableFactor::Function { lateral, name, args, alias } => union_spans( - name.0.iter().map(|i| i.span) + TableFactor::Function { + lateral, + name, + args, + alias, + } => union_spans( + name.0 + .iter() + .map(|i| i.span) .chain(args.iter().map(|i| i.span())) .chain(alias.as_ref().map(|alias| alias.span())), ), - TableFactor::JsonTable { json_expr, json_path, columns, alias } => todo!(), - TableFactor::Pivot { table, aggregate_functions, value_column, value_source, default_on_null, alias } => todo!(), - TableFactor::Unpivot { table, value, name, columns, alias } => todo!(), - TableFactor::MatchRecognize { table, partition_by, order_by, measures, rows_per_match, after_match_skip, pattern, symbols, alias } => todo!(), + TableFactor::JsonTable { + json_expr, + json_path, + columns, + alias, + } => todo!(), + TableFactor::Pivot { + table, + aggregate_functions, + value_column, + value_source, + default_on_null, + alias, + } => todo!(), + TableFactor::Unpivot { + table, + value, + name, + columns, + alias, + } => todo!(), + TableFactor::MatchRecognize { + table, + partition_by, + order_by, + measures, + rows_per_match, + after_match_skip, + pattern, + symbols, + alias, + } => todo!(), } } } - impl Spanned for FunctionArg { fn span(&self) -> Span { match self { - FunctionArg::Named { name, arg, operator } => { - name.span.union(&arg.span()) - }, + FunctionArg::Named { + name, + arg, + operator, + } => name.span.union(&arg.span()), FunctionArg::Unnamed(arg) => arg.span(), } } @@ -269,7 +492,9 @@ impl Spanned for FunctionArgExpr { fn span(&self) -> Span { match self { FunctionArgExpr::Expr(expr) => expr.span(), - FunctionArgExpr::QualifiedWildcard(object_name) => union_spans(object_name.0.iter().map(|i| i.span)), + FunctionArgExpr::QualifiedWildcard(object_name) => { + union_spans(object_name.0.iter().map(|i| i.span)) + } FunctionArgExpr::Wildcard => Span::empty(), } } @@ -277,10 +502,13 @@ impl Spanned for FunctionArgExpr { impl Spanned for TableAlias { fn span(&self) -> Span { - union_spans( - iter::once(self.name.span) - .chain(self.columns.iter().map(|i| i.span)) - ) + union_spans(iter::once(self.name.span).chain(self.columns.iter().map(|i| i.span))) + } +} + +impl Spanned for Value { + fn span(&self) -> Span { + Span::empty() // # todo: Value needs to store spans before this is possible } } @@ -304,7 +532,10 @@ impl Spanned for JoinOperator { JoinOperator::RightAnti(join_constraint) => join_constraint.span(), JoinOperator::CrossApply => Span::empty(), JoinOperator::OuterApply => Span::empty(), - JoinOperator::AsOf { match_condition, constraint } => todo!(), + JoinOperator::AsOf { + match_condition, + constraint, + } => todo!(), } } } @@ -330,7 +561,7 @@ impl Spanned for TableWithJoins { pub fn union_spans>(iter: I) -> Span { iter.reduce(|acc, item| acc.union(&item)) - .expect("Empty iterator") + .unwrap_or(Span::empty()) } impl Spanned for Select { @@ -355,7 +586,9 @@ pub mod tests { #[test] fn test_query_span() { let query = crate::parser::Parser::new(&GenericDialect::default()) - .try_with_sql("SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id") + .try_with_sql( + "SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id", + ) .unwrap() .parse_query() .unwrap(); @@ -366,11 +599,12 @@ pub mod tests { ); } - #[test] pub fn test_union() { let query = crate::parser::Parser::new(&GenericDialect::default()) - .try_with_sql("SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source") + .try_with_sql( + "SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source", + ) .unwrap() .parse_query() .unwrap(); @@ -414,7 +648,9 @@ pub mod tests { #[test] pub fn test_wildcard_from_cte() { let query = crate::parser::Parser::new(&GenericDialect::default()) - .try_with_sql("WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte") + .try_with_sql( + "WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte", + ) .unwrap() .parse_query() .unwrap(); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 8d8c46cfa..d98528389 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -2189,7 +2189,10 @@ impl<'a> Parser<'a> { let (fields, trailing_bracket) = self.parse_struct_type_def(Self::parse_struct_field_def)?; if trailing_bracket.0 { - return parser_err!("unmatched > in STRUCT literal", self.peek_token().span.start); + return parser_err!( + "unmatched > in STRUCT literal", + self.peek_token().span.start + ); } self.expect_token(&Token::LParen)?; @@ -2992,7 +2995,9 @@ impl<'a> Parser<'a> { }); } self.expect_token(&Token::LParen)?; - let in_op = if self.parse_keyword(Keyword::SELECT).is_some() || self.parse_keyword(Keyword::WITH).is_some() { + let in_op = if self.parse_keyword(Keyword::SELECT).is_some() + || self.parse_keyword(Keyword::WITH).is_some() + { self.prev_token(); Expr::InSubquery { expr: Box::new(expr), @@ -3197,9 +3202,7 @@ impl<'a> Parser<'a> { #[must_use] pub fn parse_keyword(&mut self, expected: Keyword) -> Option { match self.peek_token().token { - Token::Word(w) if expected == w.keyword => { - Some(self.next_token()) - } + Token::Word(w) if expected == w.keyword => Some(self.next_token()), _ => None, } } @@ -3547,7 +3550,9 @@ impl<'a> Parser<'a> { && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some(); if self.parse_keyword(Keyword::TABLE).is_some() { self.parse_create_table(or_replace, temporary, global, transient) - } else if self.parse_keyword(Keyword::MATERIALIZED).is_some() || self.parse_keyword(Keyword::VIEW).is_some() { + } else if self.parse_keyword(Keyword::MATERIALIZED).is_some() + || self.parse_keyword(Keyword::VIEW).is_some() + { self.prev_token(); self.parse_create_view(or_replace, temporary) } else if self.parse_keyword(Keyword::EXTERNAL).is_some() { @@ -4134,12 +4139,12 @@ impl<'a> Parser<'a> { data_type = self.parse_data_type()?; } - let default_expr = if self.parse_keyword(Keyword::DEFAULT).is_some() || self.consume_token(&Token::Eq) - { - Some(self.parse_expr()?) - } else { - None - }; + let default_expr = + if self.parse_keyword(Keyword::DEFAULT).is_some() || self.consume_token(&Token::Eq) { + Some(self.parse_expr()?) + } else { + None + }; Ok(OperateFunctionArg { mode, name, @@ -4219,7 +4224,8 @@ impl<'a> Parser<'a> { }; let condition = self - .parse_keyword(Keyword::WHEN).is_some() + .parse_keyword(Keyword::WHEN) + .is_some() .then(|| self.parse_expr()) .transpose()?; @@ -5300,7 +5306,9 @@ impl<'a> Parser<'a> { DiscardObject::PLANS } else if self.parse_keyword(Keyword::SEQUENCES).is_some() { DiscardObject::SEQUENCES - } else if self.parse_keyword(Keyword::TEMP).is_some() || self.parse_keyword(Keyword::TEMPORARY).is_some() { + } else if self.parse_keyword(Keyword::TEMP).is_some() + || self.parse_keyword(Keyword::TEMPORARY).is_some() + { DiscardObject::TEMP } else { return self.expected( @@ -5591,7 +5599,9 @@ impl<'a> Parser<'a> { // Clickhouse has `ON CLUSTER 'cluster'` syntax for DDLs let on_cluster = self.parse_optional_on_cluster()?; - let like = if self.parse_keyword(Keyword::LIKE).is_some() || self.parse_keyword(Keyword::ILIKE).is_some() { + let like = if self.parse_keyword(Keyword::LIKE).is_some() + || self.parse_keyword(Keyword::ILIKE).is_some() + { self.parse_object_name(allow_unquoted_hyphen).ok() } else { None @@ -6653,7 +6663,9 @@ impl<'a> Parser<'a> { } } } else if self.parse_keyword(Keyword::RENAME).is_some() { - if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::CONSTRAINT).is_some() { + if dialect_of!(self is PostgreSqlDialect) + && self.parse_keyword(Keyword::CONSTRAINT).is_some() + { let old_name = self.parse_identifier(false)?; self.expect_keyword(Keyword::TO)?; let new_name = self.parse_identifier(false)?; @@ -8091,20 +8103,22 @@ impl<'a> Parser<'a> { loop { match self.next_token().token { // ensure that optional period is succeeded by another identifier - Token::Period => { let next_token = self.next_token(); match next_token.token { - Token::Word(w) => idents.push(w.to_ident(next_token.span)), - Token::EOF => { - return Err(ParserError::ParserError( - "Trailing period in identifier".to_string(), - ))? - } - token => { - return Err(ParserError::ParserError(format!( - "Unexpected token following period in identifier: {token}" - )))? + Token::Period => { + let next_token = self.next_token(); + match next_token.token { + Token::Word(w) => idents.push(w.to_ident(next_token.span)), + Token::EOF => { + return Err(ParserError::ParserError( + "Trailing period in identifier".to_string(), + ))? + } + token => { + return Err(ParserError::ParserError(format!( + "Unexpected token following period in identifier: {token}" + )))? + } } } - }, Token::EOF => break, token => { return Err(ParserError::ParserError(format!( @@ -9068,28 +9082,28 @@ impl<'a> Parser<'a> { }; // Accept QUALIFY and WINDOW in any order and flag accordingly. - let (named_windows, qualify, window_before_qualify) = if self.parse_keyword(Keyword::WINDOW).is_some() - { - let named_windows = self.parse_comma_separated(Parser::parse_named_window)?; - if self.parse_keyword(Keyword::QUALIFY).is_some() { - (named_windows, Some(self.parse_expr()?), true) - } else { - (named_windows, None, true) - } - } else if self.parse_keyword(Keyword::QUALIFY).is_some() { - let qualify = Some(self.parse_expr()?); + let (named_windows, qualify, window_before_qualify) = if self.parse_keyword(Keyword::WINDOW).is_some() { - ( - self.parse_comma_separated(Parser::parse_named_window)?, - qualify, - false, - ) + let named_windows = self.parse_comma_separated(Parser::parse_named_window)?; + if self.parse_keyword(Keyword::QUALIFY).is_some() { + (named_windows, Some(self.parse_expr()?), true) + } else { + (named_windows, None, true) + } + } else if self.parse_keyword(Keyword::QUALIFY).is_some() { + let qualify = Some(self.parse_expr()?); + if self.parse_keyword(Keyword::WINDOW).is_some() { + ( + self.parse_comma_separated(Parser::parse_named_window)?, + qualify, + false, + ) + } else { + (Default::default(), qualify, false) + } } else { - (Default::default(), qualify, false) - } - } else { - Default::default() - }; + Default::default() + }; let connect_by = if self.dialect.supports_connect_by() && self @@ -10508,7 +10522,10 @@ impl<'a> Parser<'a> { /// Parse an REPLACE statement pub fn parse_replace(&mut self) -> Result { if !dialect_of!(self is MySqlDialect | GenericDialect) { - return parser_err!("Unsupported statement REPLACE", self.peek_token().span.start); + return parser_err!( + "Unsupported statement REPLACE", + self.peek_token().span.start + ); } let insert = &mut self.parse_insert()?; @@ -10589,12 +10606,13 @@ impl<'a> Parser<'a> { let table = self.parse_keyword(Keyword::TABLE).is_some(); let table_name = self.parse_object_name(false)?; - let table_alias = - if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::AS).is_some() { - Some(self.parse_identifier(false)?) - } else { - None - }; + let table_alias = if dialect_of!(self is PostgreSqlDialect) + && self.parse_keyword(Keyword::AS).is_some() + { + Some(self.parse_identifier(false)?) + } else { + None + }; let is_mysql = dialect_of!(self is MySqlDialect); From 8986a1ecf25e053f1fcd97b938a4cd23287f8b9d Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Thu, 19 Sep 2024 12:05:17 +0200 Subject: [PATCH 06/23] feat: more ast nodes --- src/ast/spans.rs | 43 ++++++++++++++++++++++++++++--------------- src/tokenizer.rs | 4 ++-- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index b29a91bb4..25c8e6dea 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -91,56 +91,69 @@ impl Spanned for Expr { expr, subquery, negated, - } => todo!(), + } => expr.span().union(&subquery.span()), Expr::InUnnest { expr, array_expr, negated, - } => todo!(), + } => expr.span().union(&array_expr.span()), Expr::Between { expr, negated, low, high, - } => todo!(), + } => expr.span().union(&low.span()).union(&high.span()), + Expr::BinaryOp { left, op, right } => left.span().union(&right.span()), Expr::Like { negated, expr, pattern, escape_char, - } => todo!(), + } => expr.span().union(&pattern.span()), Expr::ILike { negated, expr, pattern, escape_char, - } => todo!(), + } => expr.span().union(&pattern.span()), Expr::SimilarTo { negated, expr, pattern, escape_char, - } => todo!(), - Expr::Ceil { expr, field } => todo!(), - Expr::Floor { expr, field } => todo!(), - Expr::Position { expr, r#in } => todo!(), + } => expr.span().union(&pattern.span()), + Expr::Ceil { expr, field } => expr.span(), + Expr::Floor { expr, field } => expr.span(), + Expr::Position { expr, r#in } => expr.span().union(&r#in.span()), Expr::Overlay { expr, overlay_what, overlay_from, overlay_for, - } => todo!(), - Expr::Collate { expr, collation } => todo!(), + } => expr + .span() + .union(&overlay_what.span()) + .union(&overlay_from.span()) + .union_opt(&overlay_for.as_ref().map(|i| i.span())), + Expr::Collate { expr, collation } => expr + .span() + .union(&union_spans(collation.0.iter().map(|i| i.span))), Expr::Nested(expr) => expr.span(), Expr::Value(value) => value.span(), Expr::TypedString { data_type, value } => todo!(), Expr::MapAccess { column, keys } => todo!(), Expr::Function(function) => function.span(), - Expr::GroupingSets(vec) => todo!(), - Expr::Cube(vec) => todo!(), - Expr::Rollup(vec) => todo!(), - Expr::Tuple(vec) => todo!(), + Expr::GroupingSets(vec) => { + union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) + } + Expr::Cube(vec) => { + union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) + } + Expr::Rollup(vec) => { + union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) + } + Expr::Tuple(vec) => union_spans(vec.iter().map(|i| i.span())), Expr::Array(array) => todo!(), Expr::MatchAgainst { columns, diff --git a/src/tokenizer.rs b/src/tokenizer.rs index f0f861753..5c9fcbf10 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -482,6 +482,8 @@ impl Span { } pub fn union(&self, other: &Span) -> Span { + // If either span is empty, return the other + // this prevents propagating (0, 0) through the tree match (self, other) { (&Span::EMPTY, _) => other.clone(), (_, &Span::EMPTY) => self.clone(), @@ -733,8 +735,6 @@ impl<'a> Tokenizer<'a> { while let Some(token) = self.next_token(&mut state)? { let span = location.span_to(state.location()); - location = state.location(); - buf.push(TokenWithLocation { token, span }); location = state.location(); From aeb4f3a76d608297feb2bc3a566b45c5494e98c6 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Fri, 20 Sep 2024 11:24:48 +0200 Subject: [PATCH 07/23] start working on better tests --- src/ast/query.rs | 2 ++ src/ast/spans.rs | 57 +++++++++++++++++++++++++++------------ src/parser/mod.rs | 12 +++++---- tests/sqlparser_common.rs | 1 + 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index 3947d3b8f..2c4d0a7a8 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -544,6 +544,8 @@ pub struct Cte { pub query: Box, pub from: Option, pub materialized: Option, + // needed for accurate span reporting + pub closing_paren_token: TokenWithLocation, } impl fmt::Display for Cte { diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 25c8e6dea..f9ce7845e 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -17,12 +17,9 @@ pub trait Spanned { impl Spanned for Query { fn span(&self) -> Span { - union_spans( - self.with - .iter() - .map(|item| item.span()) - .chain(core::iter::once(self.body.span())), - ) + self.body + .span() + .union_opt(&self.with.as_ref().map(|i| i.span())) } } @@ -40,7 +37,8 @@ impl Spanned for Cte { union_spans( core::iter::once(self.alias.span()) .chain(core::iter::once(self.query.span())) - .chain(self.from.iter().map(|item| item.span)), + .chain(self.from.iter().map(|item| item.span)) + .chain(core::iter::once(self.closing_paren_token.span)), ) } } @@ -589,13 +587,25 @@ impl Spanned for Select { #[cfg(test)] pub mod tests { - use ast::query; - use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect}; + use crate::parser::Parser; use crate::tokenizer::Span; use super::*; + struct SpanTest<'a>(Parser<'a>, &'a str); + + impl<'a> SpanTest<'a> { + fn new(dialect: &'a dyn Dialect, sql: &'a str) -> Self { + Self(Parser::new(dialect).try_with_sql(sql).unwrap(), sql) + } + + fn get_source(&self, span: Span) -> &'a str { + // lines in spans are 1-indexed + &self.1[(span.start.column as usize - 1)..(span.end.column - 1) as usize] + } + } + #[test] fn test_query_span() { let query = crate::parser::Parser::new(&GenericDialect::default()) @@ -660,14 +670,27 @@ pub mod tests { #[test] pub fn test_wildcard_from_cte() { - let query = crate::parser::Parser::new(&GenericDialect::default()) - .try_with_sql( - "WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte", - ) - .unwrap() - .parse_query() - .unwrap(); + let dialect = &GenericDialect::default(); + let mut test = SpanTest::new( + dialect, + "WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte", + ); - query.span(); + let query = test.0.parse_query().unwrap(); + let cte_span = query.clone().with.unwrap().cte_tables[0].span(); + let cte_query_span = query.clone().with.unwrap().cte_tables[0].query.span(); + let body_span = query.body.span(); + + // the WITH keyboard is part of the query + assert_eq!( + test.get_source(cte_span), + "cte AS (SELECT a FROM postgres.public.source)" + ); + assert_eq!( + test.get_source(cte_query_span), + "SELECT a FROM postgres.public.source" + ); + + assert_eq!(test.get_source(body_span), "SELECT cte.* FROM cte"); } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d98528389..14c47000f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3336,9 +3336,9 @@ impl<'a> Parser<'a> { } /// Bail out if the current token is not an expected keyword, or consume it if it is - pub fn expect_token(&mut self, expected: &Token) -> Result<(), ParserError> { - if self.consume_token(expected) { - Ok(()) + pub fn expect_token(&mut self, expected: &Token) -> Result { + if self.peek_token() == *expected { + Ok(self.next_token()) } else { self.expected(&expected.to_string(), self.peek_token()) } @@ -8802,7 +8802,7 @@ impl<'a> Parser<'a> { } self.expect_token(&Token::LParen)?; let query = self.parse_boxed_query()?; - self.expect_token(&Token::RParen)?; + let closing_paren_token = self.expect_token(&Token::RParen)?; let alias = TableAlias { name, columns: vec![], @@ -8812,6 +8812,7 @@ impl<'a> Parser<'a> { query, from: None, materialized: is_materialized, + closing_paren_token, } } else { let columns = self.parse_parenthesized_column_list(Optional, false)?; @@ -8826,13 +8827,14 @@ impl<'a> Parser<'a> { } self.expect_token(&Token::LParen)?; let query = self.parse_boxed_query()?; - self.expect_token(&Token::RParen)?; + let closing_paren_token = self.expect_token(&Token::RParen)?; let alias = TableAlias { name, columns }; Cte { alias, query, from: None, materialized: is_materialized, + closing_paren_token, } }; if self.parse_keyword(Keyword::FROM).is_some() { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 97730c71f..38edc0c78 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -6403,6 +6403,7 @@ fn parse_recursive_cte() { query: Box::new(cte_query), from: None, materialized: None, + closing_paren_token: TokenWithLocation::wrap(Token::RParen), }; assert_eq!(with.cte_tables.first().unwrap(), &expected); } From 4de3209c9570a475c1d2a8256cc34651fa9ef2d5 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Wed, 25 Sep 2024 14:31:11 +0200 Subject: [PATCH 08/23] feat: implement spans for Wildcard projections --- src/ast/mod.rs | 14 +++++++------- src/ast/query.rs | 21 +++++++++++++++++++-- src/ast/spans.rs | 16 ++++++++++------ src/parser/mod.rs | 25 +++++++++++++++---------- tests/sqlparser_common.rs | 8 +------- tests/sqlparser_duckdb.rs | 16 ++-------------- 6 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a9f1c088d..e7ef065d4 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -28,7 +28,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; -use crate::tokenizer::Span; +use crate::tokenizer::{Span, TokenWithLocation}; pub use self::data_type::{ ArrayElemTypeDef, CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, @@ -922,10 +922,10 @@ pub enum Expr { /// `` opt_search_modifier: Option, }, - Wildcard, + Wildcard(TokenWithLocation), /// Qualified wildcard, e.g. `alias.*` or `schema.table.*`. /// (Same caveats apply to `QualifiedWildcard` as to `Wildcard`.) - QualifiedWildcard(ObjectName), + QualifiedWildcard(ObjectName, TokenWithLocation), /// Some dialects support an older syntax for outer joins where columns are /// marked with the `(+)` operator in the WHERE clause, for example: /// @@ -1214,8 +1214,8 @@ impl fmt::Display for Expr { Expr::MapAccess { column, keys } => { write!(f, "{column}{}", display_separated(keys, "")) } - Expr::Wildcard => f.write_str("*"), - Expr::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix), + Expr::Wildcard(_) => f.write_str("*"), + Expr::QualifiedWildcard(prefix, _) => write!(f, "{}.*", prefix), Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")), Expr::IsTrue(ast) => write!(f, "{ast} IS TRUE"), Expr::IsNotTrue(ast) => write!(f, "{ast} IS NOT TRUE"), @@ -5210,8 +5210,8 @@ pub enum FunctionArgExpr { impl From for FunctionArgExpr { fn from(wildcard_expr: Expr) -> Self { match wildcard_expr { - Expr::QualifiedWildcard(prefix) => Self::QualifiedWildcard(prefix), - Expr::Wildcard => Self::Wildcard, + Expr::QualifiedWildcard(prefix, _) => Self::QualifiedWildcard(prefix), + Expr::Wildcard(_) => Self::Wildcard, expr => Self::Expr(expr), } } diff --git a/src/ast/query.rs b/src/ast/query.rs index 2c4d0a7a8..090f8b7b0 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -19,7 +19,10 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; -use crate::{ast::*, tokenizer::TokenWithLocation}; +use crate::{ + ast::*, + tokenizer::{Token, TokenWithLocation}, +}; /// The most complete variant of a `SELECT` query expression, optionally /// including `WITH`, `UNION` / other set operations, and `ORDER BY`. @@ -597,10 +600,11 @@ impl fmt::Display for IdentWithAlias { } /// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct WildcardAdditionalOptions { + pub wildcard_token: TokenWithLocation, /// `[ILIKE...]`. /// Snowflake syntax: pub opt_ilike: Option, @@ -618,6 +622,19 @@ pub struct WildcardAdditionalOptions { pub opt_rename: Option, } +impl Default for WildcardAdditionalOptions { + fn default() -> Self { + Self { + wildcard_token: TokenWithLocation::wrap(Token::Mul), + opt_ilike: None, + opt_exclude: None, + opt_except: None, + opt_replace: None, + opt_rename: None, + } + } +} + impl fmt::Display for WildcardAdditionalOptions { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(ilike) = &self.opt_ilike { diff --git a/src/ast/spans.rs b/src/ast/spans.rs index f9ce7845e..9071e0bcf 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -245,8 +245,14 @@ impl Spanned for Expr { Expr::Map(map) => todo!(), Expr::Subscript { expr, subscript } => todo!(), Expr::Interval(interval) => todo!(), - Expr::Wildcard => todo!(), - Expr::QualifiedWildcard(object_name) => todo!(), + Expr::Wildcard(token) => token.span, + Expr::QualifiedWildcard(object_name, token) => union_spans( + object_name + .0 + .iter() + .map(|i| i.span) + .chain(iter::once(token.span)), + ), Expr::OuterJoin(expr) => todo!(), Expr::Prior(expr) => todo!(), Expr::Lambda(lambda_function) => todo!(), @@ -336,10 +342,8 @@ impl Spanned for SelectItem { impl Spanned for WildcardAdditionalOptions { fn span(&self) -> Span { union_spans( - self.opt_ilike - .as_ref() - .map(|i| i.span()) - .into_iter() + core::iter::once(self.wildcard_token.span) + .chain(self.opt_ilike.as_ref().map(|i| i.span()).into_iter()) .chain(self.opt_exclude.as_ref().map(|i| i.span()).into_iter()) .chain(self.opt_rename.as_ref().map(|i| i.span()).into_iter()) .chain(self.opt_replace.as_ref().map(|i| i.span()).into_iter()) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 14c47000f..d50cf9f35 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -875,7 +875,10 @@ impl<'a> Parser<'a> { id_parts.push(Ident::with_quote('\'', s)) } Token::Mul => { - return Ok(Expr::QualifiedWildcard(ObjectName(id_parts))); + return Ok(Expr::QualifiedWildcard( + ObjectName(id_parts), + next_token, + )); } _ => { return self @@ -886,7 +889,7 @@ impl<'a> Parser<'a> { } } Token::Mul => { - return Ok(Expr::Wildcard); + return Ok(Expr::Wildcard(next_token)); } _ => (), }; @@ -1088,7 +1091,7 @@ impl<'a> Parser<'a> { _ => match self.peek_token().token { Token::LParen | Token::Period => { let mut id_parts: Vec = vec![w.to_ident(next_token.span)]; - let mut ends_with_wildcard = false; + let mut ending_wildcard: Option = None; while self.consume_token(&Token::Period) { let next_token = self.next_token(); match next_token.token { @@ -1097,7 +1100,7 @@ impl<'a> Parser<'a> { // Postgres explicitly allows funcnm(tablenm.*) and the // function array_agg traverses this control flow if dialect_of!(self is PostgreSqlDialect) { - ends_with_wildcard = true; + ending_wildcard = Some(next_token); break; } else { return self @@ -1114,8 +1117,8 @@ impl<'a> Parser<'a> { } } - if ends_with_wildcard { - Ok(Expr::QualifiedWildcard(ObjectName(id_parts))) + if let Some(ending_wildcard_token) = ending_wildcard { + Ok(Expr::QualifiedWildcard(ObjectName(id_parts), ending_wildcard_token)) } else if self.consume_token(&Token::LParen) { if dialect_of!(self is SnowflakeDialect | MsSqlDialect) && self.consume_tokens(&[Token::Plus, Token::RParen]) @@ -10952,12 +10955,12 @@ impl<'a> Parser<'a> { /// Parse a comma-delimited list of projections after SELECT pub fn parse_select_item(&mut self) -> Result { match self.parse_wildcard_expr()? { - Expr::QualifiedWildcard(prefix) => Ok(SelectItem::QualifiedWildcard( + Expr::QualifiedWildcard(prefix, token) => Ok(SelectItem::QualifiedWildcard( prefix, - self.parse_wildcard_additional_options()?, + self.parse_wildcard_additional_options(token)?, )), - Expr::Wildcard => Ok(SelectItem::Wildcard( - self.parse_wildcard_additional_options()?, + Expr::Wildcard(token) => Ok(SelectItem::Wildcard( + self.parse_wildcard_additional_options(token)?, )), Expr::Identifier(v) if v.value.to_lowercase() == "from" && v.quote_style.is_none() => { parser_err!( @@ -10979,6 +10982,7 @@ impl<'a> Parser<'a> { /// If it is not possible to parse it, will return an option. pub fn parse_wildcard_additional_options( &mut self, + wildcard_token: TokenWithLocation, ) -> Result { let opt_ilike = if dialect_of!(self is GenericDialect | SnowflakeDialect) { self.parse_optional_select_item_ilike()? @@ -11010,6 +11014,7 @@ impl<'a> Parser<'a> { }; Ok(WildcardAdditionalOptions { + wildcard_token, opt_ilike, opt_exclude, opt_except, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 38edc0c78..2d373cc11 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -7332,13 +7332,7 @@ fn lateral_function() { select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: None, top: None, - projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { - opt_ilike: None, - opt_exclude: None, - opt_except: None, - opt_rename: None, - opt_replace: None, - })], + projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())], into: None, from: vec![TableWithJoins { relation: TableFactor::Table { diff --git a/tests/sqlparser_duckdb.rs b/tests/sqlparser_duckdb.rs index aded09104..9d8583691 100644 --- a/tests/sqlparser_duckdb.rs +++ b/tests/sqlparser_duckdb.rs @@ -261,13 +261,7 @@ fn test_select_union_by_name() { select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: None, top: None, - projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { - opt_ilike: None, - opt_exclude: None, - opt_except: None, - opt_rename: None, - opt_replace: None, - })], + projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())], into: None, from: vec![TableWithJoins { relation: TableFactor::Table { @@ -303,13 +297,7 @@ fn test_select_union_by_name() { select_token: TokenWithLocation::wrap(Token::make_keyword("SELECT")), distinct: None, top: None, - projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { - opt_ilike: None, - opt_exclude: None, - opt_except: None, - opt_rename: None, - opt_replace: None, - })], + projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions::default())], into: None, from: vec![TableWithJoins { relation: TableFactor::Table { From a04888ac785e6f668bdaef9d634bf3e1560f2f1b Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Thu, 26 Sep 2024 11:40:12 +0200 Subject: [PATCH 09/23] make union_spans public --- src/ast/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e7ef065d4..5b343ee83 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -82,7 +82,7 @@ pub mod helpers; mod operator; mod query; mod spans; -pub use spans::Spanned; +pub use spans::{Spanned, union_spans}; mod trigger; mod value; From 1b2b03d055d922790a3f98dc1d88d0f1174e3b2a Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Mon, 30 Sep 2024 10:42:50 +0200 Subject: [PATCH 10/23] enable serde feat for spans and locations --- src/tokenizer.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 5c9fcbf10..e9ada1fcd 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -417,6 +417,7 @@ impl fmt::Display for Whitespace { /// Location in input string #[derive(Eq, PartialEq, Hash, Clone, Copy, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Location { /// Line number, starting from 1 pub line: u64, @@ -456,6 +457,7 @@ impl From<(u64, u64)> for Location { } #[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Span { pub start: Location, pub end: Location, @@ -504,6 +506,7 @@ impl Span { /// A [Token] with [Location] attached to it #[derive(Debug, Eq, Hash, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TokenWithLocation { pub token: Token, pub span: Span, From 5f60bdc6c20282d37e482ddcb5fcb18d9bd1cfdf Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Mon, 7 Oct 2024 13:27:34 +0200 Subject: [PATCH 11/23] feat: implement remaining ast nodes --- src/ast/mod.rs | 2 +- src/ast/spans.rs | 1224 ++++++++++++++++++++++++++++++++++++++++++--- src/parser/mod.rs | 22 +- src/tokenizer.rs | 8 +- 4 files changed, 1169 insertions(+), 87 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 5b343ee83..123af6522 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -82,7 +82,7 @@ pub mod helpers; mod operator; mod query; mod spans; -pub use spans::{Spanned, union_spans}; +pub use spans::{union_spans, Spanned}; mod trigger; mod value; diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 9071e0bcf..ee8cd2122 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1,17 +1,34 @@ use core::iter; -use crate::ast; use crate::tokenizer::Span; use super::{ - Cte, ExceptSelectItem, ExcludeSelectItem, Expr, Function, FunctionArg, FunctionArgExpr, - FunctionArgumentClause, FunctionArgumentList, FunctionArguments, HavingBound, IlikeSelectItem, - Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, Query, RenameSelectItem, - ReplaceSelectElement, ReplaceSelectItem, Select, SelectItem, SetExpr, TableAlias, TableFactor, - TableWithJoins, Value, WildcardAdditionalOptions, With, + AlterColumnOperation, AlterIndexOperation, AlterTableOperation, Array, Assignment, + AssignmentTarget, CloseCursor, ClusteredIndex, ColumnDef, ColumnOption, ColumnOptionDef, + ConflictTarget, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, + CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr, + ExprWithAlias, FromTable, Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, + FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound, IlikeSelectItem, Insert, + Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, + MatchRecognizePattern, Measure, ObjectName, OnConflict, OnConflictAction, OnInsert, OrderBy, + OrderByExpr, Partition, PivotValueSource, ProjectionSelect, Query, ReferentialAction, + RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectItem, SetExpr, + SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableConstraint, TableFactor, + TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef, + WildcardAdditionalOptions, With, WithFill, }; +/// A trait for AST nodes that have a source span for use in diagnostics. +/// +/// Source spans are not guaranteed to be entirely accurate. They may +/// be missing keywords or other tokens. Some nodes may not have a computable +/// span at all, in which case they return `Span::empty()`. +/// +/// Some impl blocks may contain doc comments with information +/// on which nodes are missing spans. pub trait Spanned { + /// Compute the source span for this AST node, by recursively + /// combining the spans of its children. fn span(&self) -> Span; } @@ -26,7 +43,7 @@ impl Spanned for Query { impl Spanned for With { fn span(&self) -> Span { union_spans( - core::iter::once(self.with_token.span.clone()) + core::iter::once(self.with_token.span) .chain(self.cte_tables.iter().map(|item| item.span())), ) } @@ -43,6 +60,9 @@ impl Spanned for Cte { } } +/// # partial span +/// +/// [SetExpr::Table] is not implemented. impl Spanned for SetExpr { fn span(&self) -> Span { match self { @@ -54,14 +74,921 @@ impl Spanned for SetExpr { left, right, } => left.span().union(&right.span()), - SetExpr::Values(values) => todo!(), - SetExpr::Insert(statement) => todo!(), - SetExpr::Table(table) => todo!(), - SetExpr::Update(statement) => todo!(), + SetExpr::Values(values) => values.span(), + SetExpr::Insert(statement) => statement.span(), + SetExpr::Table(table) => Span::empty(), + SetExpr::Update(statement) => statement.span(), } } } +impl Spanned for Values { + fn span(&self) -> Span { + union_spans( + self.rows + .iter() + .map(|row| union_spans(row.iter().map(|expr| expr.span()))), + ) + } +} + +/// # partial span +/// +/// Missing spans: +/// - [Statement::CopyIntoSnowflake] +/// - [Statement::CreateSecret] +/// - [Statement::CreateRole] +/// - [Statement::AlterRole] +/// - [Statement::AttachDatabase] +/// - [Statement::AttachDuckDBDatabase] +/// - [Statement::DetachDuckDBDatabase] +/// - [Statement::Drop] +/// - [Statement::DropFunction] +/// - [Statement::DropProcedure] +/// - [Statement::DropSecret] +/// - [Statement::Declare] +/// - [Statement::CreateExtension] +/// - [Statement::Fetch] +/// - [Statement::Flush] +/// - [Statement::Discard] +/// - [Statement::SetRole] +/// - [Statement::SetVariable] +/// - [Statement::SetTimeZone] +/// - [Statement::SetNames] +/// - [Statement::SetNamesDefault] +/// - [Statement::ShowFunctions] +/// - [Statement::ShowVariable] +/// - [Statement::ShowStatus] +/// - [Statement::ShowVariables] +/// - [Statement::ShowCreate] +/// - [Statement::ShowColumns] +/// - [Statement::ShowTables] +/// - [Statement::ShowCollation] +/// - [Statement::StartTransaction] +/// - [Statement::SetTransaction] +/// - [Statement::Comment] +/// - [Statement::Commit] +/// - [Statement::Rollback] +/// - [Statement::CreateSchema] +/// - [Statement::CreateDatabase] +/// - [Statement::CreateFunction] +/// - [Statement::CreateTrigger] +/// - [Statement::DropTrigger] +/// - [Statement::CreateProcedure] +/// - [Statement::CreateMacro] +/// - [Statement::CreateStage] +/// - [Statement::Assert] +/// - [Statement::Grant] +/// - [Statement::Revoke] +/// - [Statement::Deallocate] +/// - [Statement::Execute] +/// - [Statement::Prepare] +/// - [Statement::Kill] +/// - [Statement::ExplainTable] +/// - [Statement::Explain] +/// - [Statement::Savepoint] +/// - [Statement::ReleaseSavepoint] +/// - [Statement::Merge] +/// - [Statement::Cache] +/// - [Statement::UNCache] +/// - [Statement::CreateSequence] +/// - [Statement::CreateType] +/// - [Statement::Pragma] +/// - [Statement::LockTables] +/// - [Statement::UnlockTables] +/// - [Statement::Unload] +/// - [Statement::OptimizeTable] +impl Spanned for Statement { + fn span(&self) -> Span { + match self { + Statement::Analyze { + table_name, + partitions, + for_columns: _, + columns, + cache_metadata: _, + noscan: _, + compute_statistics: _, + } => union_spans( + core::iter::once(table_name.span()) + .chain(partitions.iter().flat_map(|i| i.iter().map(|k| k.span()))) + .chain(columns.iter().map(|i| i.span)), + ), + Statement::Truncate { + table_names, + partitions, + table: _, + only: _, + identity: _, + cascade: _, + } => union_spans( + table_names + .iter() + .map(|i| i.name.span()) + .chain(partitions.iter().flat_map(|i| i.iter().map(|k| k.span()))), + ), + Statement::Msck { + table_name, + repair: _, + partition_action: _, + } => table_name.span(), + Statement::Query(query) => query.span(), + Statement::Insert(insert) => insert.span(), + Statement::Install { extension_name } => extension_name.span, + Statement::Load { extension_name } => extension_name.span, + Statement::Directory { + overwrite: _, + local: _, + path: _, + file_format: _, + source, + } => source.span(), + Statement::Call(function) => function.span(), + Statement::Copy { + source, + to: _, + target: _, + options: _, + legacy_options: _, + values: _, + } => source.span(), + Statement::CopyIntoSnowflake { + into: _, + from_stage: _, + from_stage_alias: _, + stage_params: _, + from_transformations: _, + files: _, + pattern: _, + file_format: _, + copy_options: _, + validation_mode: _, + } => Span::empty(), + Statement::Close { cursor } => match cursor { + CloseCursor::All => Span::empty(), + CloseCursor::Specific { name } => name.span, + }, + Statement::Update { + table, + assignments, + from, + selection, + returning, + } => union_spans( + core::iter::once(table.span()) + .chain(assignments.iter().map(|i| i.span())) + .chain(from.iter().map(|i| i.span())) + .chain(selection.iter().map(|i| i.span())) + .chain(returning.iter().flat_map(|i| i.iter().map(|k| k.span()))), + ), + Statement::Delete(delete) => delete.span(), + Statement::CreateView { + or_replace: _, + materialized: _, + name, + columns, + query, + options, + cluster_by, + comment: _, + with_no_schema_binding: _, + if_not_exists: _, + temporary: _, + to, + } => union_spans( + core::iter::once(name.span()) + .chain(columns.iter().map(|i| i.span())) + .chain(core::iter::once(query.span())) + .chain(core::iter::once(options.span())) + .chain(cluster_by.iter().map(|i| i.span)) + .chain(to.iter().map(|i| i.span())), + ), + Statement::CreateTable(create_table) => create_table.span(), + Statement::CreateVirtualTable { + name, + if_not_exists, + module_name, + module_args, + } => union_spans( + core::iter::once(name.span()) + .chain(core::iter::once(module_name.span)) + .chain(module_args.iter().map(|i| i.span)), + ), + Statement::CreateIndex(create_index) => create_index.span(), + Statement::CreateRole { .. } => Span::empty(), + Statement::CreateSecret { .. } => Span::empty(), + Statement::AlterTable { + name, + if_exists, + only, + operations, + location, + on_cluster, + } => union_spans( + core::iter::once(name.span()) + .chain(operations.iter().map(|i| i.span())) + .chain(on_cluster.iter().map(|i| i.span)), + ), + Statement::AlterIndex { name, operation } => name.span().union(&operation.span()), + Statement::AlterView { + name, + columns, + query, + with_options, + } => union_spans( + core::iter::once(name.span()) + .chain(columns.iter().map(|i| i.span)) + .chain(core::iter::once(query.span())) + .chain(with_options.iter().map(|i| i.span())), + ), + Statement::AlterRole { .. } => Span::empty(), + Statement::AttachDatabase { .. } => Span::empty(), + Statement::AttachDuckDBDatabase { .. } => Span::empty(), + Statement::DetachDuckDBDatabase { .. } => Span::empty(), + Statement::Drop { .. } => Span::empty(), + Statement::DropFunction { .. } => Span::empty(), + Statement::DropProcedure { .. } => Span::empty(), + Statement::DropSecret { .. } => Span::empty(), + Statement::Declare { .. } => Span::empty(), + Statement::CreateExtension { .. } => Span::empty(), + Statement::Fetch { .. } => Span::empty(), + Statement::Flush { .. } => Span::empty(), + Statement::Discard { .. } => Span::empty(), + Statement::SetRole { .. } => Span::empty(), + Statement::SetVariable { .. } => Span::empty(), + Statement::SetTimeZone { .. } => Span::empty(), + Statement::SetNames { .. } => Span::empty(), + Statement::SetNamesDefault {} => Span::empty(), + Statement::ShowFunctions { .. } => Span::empty(), + Statement::ShowVariable { .. } => Span::empty(), + Statement::ShowStatus { .. } => Span::empty(), + Statement::ShowVariables { .. } => Span::empty(), + Statement::ShowCreate { .. } => Span::empty(), + Statement::ShowColumns { .. } => Span::empty(), + Statement::ShowTables { .. } => Span::empty(), + Statement::ShowCollation { .. } => Span::empty(), + Statement::Use(u) => u.span(), + Statement::StartTransaction { .. } => Span::empty(), + Statement::SetTransaction { .. } => Span::empty(), + Statement::Comment { .. } => Span::empty(), + Statement::Commit { chain } => Span::empty(), + Statement::Rollback { chain, savepoint } => Span::empty(), + Statement::CreateSchema { .. } => Span::empty(), + Statement::CreateDatabase { .. } => Span::empty(), + Statement::CreateFunction { .. } => Span::empty(), + Statement::CreateTrigger { .. } => Span::empty(), + Statement::DropTrigger { .. } => Span::empty(), + Statement::CreateProcedure { .. } => Span::empty(), + Statement::CreateMacro { .. } => Span::empty(), + Statement::CreateStage { .. } => Span::empty(), + Statement::Assert { condition, message } => Span::empty(), + Statement::Grant { .. } => Span::empty(), + Statement::Revoke { .. } => Span::empty(), + Statement::Deallocate { name, prepare } => Span::empty(), + Statement::Execute { .. } => Span::empty(), + Statement::Prepare { .. } => Span::empty(), + Statement::Kill { modifier, id } => Span::empty(), + Statement::ExplainTable { .. } => Span::empty(), + Statement::Explain { .. } => Span::empty(), + Statement::Savepoint { name } => Span::empty(), + Statement::ReleaseSavepoint { name } => Span::empty(), + Statement::Merge { .. } => Span::empty(), + Statement::Cache { .. } => Span::empty(), + Statement::UNCache { .. } => Span::empty(), + Statement::CreateSequence { .. } => Span::empty(), + Statement::CreateType { .. } => Span::empty(), + Statement::Pragma { name, value, is_eq } => Span::empty(), + Statement::LockTables { tables } => Span::empty(), + Statement::UnlockTables => Span::empty(), + Statement::Unload { query, to, with } => Span::empty(), + Statement::OptimizeTable { .. } => Span::empty(), + } + } +} + +impl Spanned for Use { + fn span(&self) -> Span { + match self { + Use::Catalog(object_name) => object_name.span(), + Use::Schema(object_name) => object_name.span(), + Use::Database(object_name) => object_name.span(), + Use::Warehouse(object_name) => object_name.span(), + Use::Object(object_name) => object_name.span(), + Use::Default => Span::empty(), + } + } +} + +impl Spanned for CreateTable { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.name.span()) + .chain(self.columns.iter().map(|i| i.span())) + .chain(self.constraints.iter().map(|i| i.span())) + .chain(self.table_properties.iter().map(|i| i.span())) + .chain(self.with_options.iter().map(|i| i.span())) + .chain(self.query.iter().map(|i| i.span())) + .chain(self.like.iter().map(|i| i.span())) + .chain(self.clone.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for ColumnDef { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.name.span) + .chain(self.collation.iter().map(|i| i.span())) + .chain(self.options.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for ColumnOptionDef { + fn span(&self) -> Span { + self.option + .span() + .union_opt(&self.name.as_ref().map(|i| i.span)) + } +} + +impl Spanned for TableConstraint { + fn span(&self) -> Span { + match self { + TableConstraint::Unique { + name, + index_name, + index_type_display: _, + index_type: _, + columns, + index_options: _, + characteristics, + } => union_spans( + name.iter() + .map(|i| i.span) + .chain(index_name.iter().map(|i| i.span)) + .chain(columns.iter().map(|i| i.span)) + .chain(characteristics.iter().map(|i| i.span())), + ), + TableConstraint::PrimaryKey { + name, + index_name, + index_type: _, + columns, + index_options: _, + characteristics, + } => union_spans( + name.iter() + .map(|i| i.span) + .chain(index_name.iter().map(|i| i.span)) + .chain(columns.iter().map(|i| i.span)) + .chain(characteristics.iter().map(|i| i.span())), + ), + TableConstraint::ForeignKey { + name, + columns, + foreign_table, + referred_columns, + on_delete, + on_update, + characteristics, + } => union_spans( + name.iter() + .map(|i| i.span) + .chain(columns.iter().map(|i| i.span)) + .chain(core::iter::once(foreign_table.span())) + .chain(referred_columns.iter().map(|i| i.span)) + .chain(on_delete.iter().map(|i| i.span())) + .chain(on_update.iter().map(|i| i.span())) + .chain(characteristics.iter().map(|i| i.span())), + ), + TableConstraint::Check { name, expr } => { + expr.span().union_opt(&name.as_ref().map(|i| i.span)) + } + TableConstraint::Index { + display_as_key, + name, + index_type, + columns, + } => union_spans( + name.iter() + .map(|i| i.span) + .chain(columns.iter().map(|i| i.span)), + ), + TableConstraint::FulltextOrSpatial { + fulltext, + index_type_display, + opt_index_name, + columns, + } => union_spans( + opt_index_name + .iter() + .map(|i| i.span) + .chain(columns.iter().map(|i| i.span)), + ), + } + } +} + +impl Spanned for CreateIndex { + fn span(&self) -> Span { + union_spans( + self.name + .iter() + .map(|i| i.span()) + .chain(core::iter::once(self.table_name.span())) + .chain(self.using.iter().map(|i| i.span)) + .chain(self.columns.iter().map(|i| i.span())) + .chain(self.include.iter().map(|i| i.span)) + .chain(self.with.iter().map(|i| i.span())) + .chain(self.predicate.iter().map(|i| i.span())), + ) + } +} + +/// # partial span +/// +/// Missing spans: +/// - [ColumnOption::Null] +/// - [ColumnOption::NotNull] +/// - [ColumnOption::Comment] +/// - [ColumnOption::Unique]¨ +/// - [ColumnOption::DialectSpecific] +/// - [ColumnOption::Generated] +impl Spanned for ColumnOption { + fn span(&self) -> Span { + match self { + ColumnOption::Null => Span::empty(), + ColumnOption::NotNull => Span::empty(), + ColumnOption::Default(expr) => expr.span(), + ColumnOption::Materialized(expr) => expr.span(), + ColumnOption::Ephemeral(expr) => expr.as_ref().map_or(Span::empty(), |e| e.span()), + ColumnOption::Alias(expr) => expr.span(), + ColumnOption::Unique { .. } => Span::empty(), + ColumnOption::ForeignKey { + foreign_table, + referred_columns, + on_delete, + on_update, + characteristics, + } => union_spans( + core::iter::once(foreign_table.span()) + .chain(referred_columns.iter().map(|i| i.span)) + .chain(on_delete.iter().map(|i| i.span())) + .chain(on_update.iter().map(|i| i.span())) + .chain(characteristics.iter().map(|i| i.span())), + ), + ColumnOption::Check(expr) => expr.span(), + ColumnOption::DialectSpecific(_) => Span::empty(), + ColumnOption::CharacterSet(object_name) => object_name.span(), + ColumnOption::Comment(_) => Span::empty(), + ColumnOption::OnUpdate(expr) => expr.span(), + ColumnOption::Generated { .. } => Span::empty(), + ColumnOption::Options(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +/// # missing span +impl Spanned for ReferentialAction { + fn span(&self) -> Span { + Span::empty() + } +} + +/// # missing span +impl Spanned for ConstraintCharacteristics { + fn span(&self) -> Span { + Span::empty() + } +} + +/// # partial span +/// +/// Missing spans: +/// - [AlterColumnOperation::SetNotNull] +/// - [AlterColumnOperation::DropNotNull] +/// - [AlterColumnOperation::DropDefault] +/// - [AlterColumnOperation::AddGenerated] +impl Spanned for AlterColumnOperation { + fn span(&self) -> Span { + match self { + AlterColumnOperation::SetNotNull => Span::empty(), + AlterColumnOperation::DropNotNull => Span::empty(), + AlterColumnOperation::SetDefault { value } => value.span(), + AlterColumnOperation::DropDefault => Span::empty(), + AlterColumnOperation::SetDataType { + data_type: _, + using, + } => using.as_ref().map_or(Span::empty(), |u| u.span()), + AlterColumnOperation::AddGenerated { .. } => Span::empty(), + } + } +} + +impl Spanned for CopySource { + fn span(&self) -> Span { + match self { + CopySource::Table { + table_name, + columns, + } => union_spans( + core::iter::once(table_name.span()).chain(columns.iter().map(|i| i.span)), + ), + CopySource::Query(query) => query.span(), + } + } +} + +impl Spanned for Delete { + fn span(&self) -> Span { + union_spans( + self.tables + .iter() + .map(|i| i.span()) + .chain(core::iter::once(self.from.span())) + .chain( + self.using + .iter() + .map(|u| union_spans(u.iter().map(|i| i.span()))), + ) + .chain(self.selection.iter().map(|i| i.span())) + .chain( + self.returning + .iter() + .flat_map(|i| i.iter().map(|k| k.span())), + ) + .chain(self.order_by.iter().map(|i| i.span())) + .chain(self.limit.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for FromTable { + fn span(&self) -> Span { + match self { + FromTable::WithFromKeyword(vec) => union_spans(vec.iter().map(|i| i.span())), + FromTable::WithoutKeyword(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +impl Spanned for ViewColumnDef { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.name.span) + .chain(self.options.iter().flat_map(|i| i.iter().map(|k| k.span()))), + ) + } +} + +impl Spanned for SqlOption { + fn span(&self) -> Span { + match self { + SqlOption::Clustered(table_options_clustered) => table_options_clustered.span(), + SqlOption::Ident(ident) => ident.span, + SqlOption::KeyValue { key, value } => key.span.union(&value.span()), + SqlOption::Partition { + column_name, + range_direction: _, + for_values, + } => union_spans( + core::iter::once(column_name.span).chain(for_values.iter().map(|i| i.span())), + ), + } + } +} + +/// # partial span +/// +/// Missing spans: +/// - [TableOptionsClustered::ColumnstoreIndex] +impl Spanned for TableOptionsClustered { + fn span(&self) -> Span { + match self { + TableOptionsClustered::ColumnstoreIndex => Span::empty(), + TableOptionsClustered::ColumnstoreIndexOrder(vec) => { + union_spans(vec.iter().map(|i| i.span)) + } + TableOptionsClustered::Index(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +impl Spanned for ClusteredIndex { + fn span(&self) -> Span { + self.name.span + } +} + +impl Spanned for CreateTableOptions { + fn span(&self) -> Span { + match self { + CreateTableOptions::None => Span::empty(), + CreateTableOptions::With(vec) => union_spans(vec.iter().map(|i| i.span())), + CreateTableOptions::Options(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +/// # partial span +/// +/// Missing spans: +/// - [AlterTableOperation::OwnerTo] +impl Spanned for AlterTableOperation { + fn span(&self) -> Span { + match self { + AlterTableOperation::AddConstraint(table_constraint) => table_constraint.span(), + AlterTableOperation::AddColumn { + column_keyword, + if_not_exists, + column_def, + column_position, + } => column_def.span(), + AlterTableOperation::AddProjection { + if_not_exists, + name, + select, + } => name.span.union(&select.span()), + AlterTableOperation::DropProjection { if_exists, name } => name.span, + AlterTableOperation::MaterializeProjection { + if_exists, + name, + partition, + } => name.span.union_opt(&partition.as_ref().map(|i| i.span)), + AlterTableOperation::ClearProjection { + if_exists, + name, + partition, + } => name.span.union_opt(&partition.as_ref().map(|i| i.span)), + AlterTableOperation::DisableRowLevelSecurity => Span::empty(), + AlterTableOperation::DisableRule { name } => name.span, + AlterTableOperation::DisableTrigger { name } => name.span, + AlterTableOperation::DropConstraint { + if_exists, + name, + cascade, + } => name.span, + AlterTableOperation::DropColumn { + column_name, + if_exists, + cascade, + } => column_name.span, + AlterTableOperation::AttachPartition { partition } => partition.span(), + AlterTableOperation::DetachPartition { partition } => partition.span(), + AlterTableOperation::FreezePartition { + partition, + with_name, + } => partition + .span() + .union_opt(&with_name.as_ref().map(|n| n.span)), + AlterTableOperation::UnfreezePartition { + partition, + with_name, + } => partition + .span() + .union_opt(&with_name.as_ref().map(|n| n.span)), + AlterTableOperation::DropPrimaryKey => Span::empty(), + AlterTableOperation::EnableAlwaysRule { name } => name.span, + AlterTableOperation::EnableAlwaysTrigger { name } => name.span, + AlterTableOperation::EnableReplicaRule { name } => name.span, + AlterTableOperation::EnableReplicaTrigger { name } => name.span, + AlterTableOperation::EnableRowLevelSecurity => Span::empty(), + AlterTableOperation::EnableRule { name } => name.span, + AlterTableOperation::EnableTrigger { name } => name.span, + AlterTableOperation::RenamePartitions { + old_partitions, + new_partitions, + } => union_spans( + old_partitions + .iter() + .map(|i| i.span()) + .chain(new_partitions.iter().map(|i| i.span())), + ), + AlterTableOperation::AddPartitions { + if_not_exists, + new_partitions, + } => union_spans(new_partitions.iter().map(|i| i.span())), + AlterTableOperation::DropPartitions { + partitions, + if_exists, + } => union_spans(partitions.iter().map(|i| i.span())), + AlterTableOperation::RenameColumn { + old_column_name, + new_column_name, + } => old_column_name.span.union(&new_column_name.span), + AlterTableOperation::RenameTable { table_name } => table_name.span(), + AlterTableOperation::ChangeColumn { + old_name, + new_name, + data_type, + options, + column_position, + } => union_spans( + core::iter::once(old_name.span) + .chain(core::iter::once(new_name.span)) + .chain(options.iter().map(|i| i.span())), + ), + AlterTableOperation::ModifyColumn { + col_name, + data_type, + options, + column_position, + } => { + union_spans(core::iter::once(col_name.span).chain(options.iter().map(|i| i.span()))) + } + AlterTableOperation::RenameConstraint { old_name, new_name } => { + old_name.span.union(&new_name.span) + } + AlterTableOperation::AlterColumn { column_name, op } => { + column_name.span.union(&op.span()) + } + AlterTableOperation::SwapWith { table_name } => table_name.span(), + AlterTableOperation::SetTblProperties { table_properties } => { + union_spans(table_properties.iter().map(|i| i.span())) + } + AlterTableOperation::OwnerTo { new_owner } => Span::empty(), + } + } +} + +impl Spanned for Partition { + fn span(&self) -> Span { + match self { + Partition::Identifier(ident) => ident.span, + Partition::Expr(expr) => expr.span(), + Partition::Part(expr) => expr.span(), + Partition::Partitions(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +impl Spanned for ProjectionSelect { + fn span(&self) -> Span { + union_spans( + self.projection + .iter() + .map(|i| i.span()) + .chain(self.order_by.iter().map(|i| i.span())) + .chain(self.group_by.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for OrderBy { + fn span(&self) -> Span { + union_spans( + self.exprs + .iter() + .map(|i| i.span()) + .chain(self.interpolate.iter().map(|i| i.span())), + ) + } +} + +/// # partial span +/// +/// Missing spans: +/// - [GroupByExpr::All] +impl Spanned for GroupByExpr { + fn span(&self) -> Span { + match self { + GroupByExpr::All(vec) => Span::empty(), + GroupByExpr::Expressions(exprs, _modifiers) => { + union_spans(exprs.iter().map(|i| i.span())) + } + } + } +} + +impl Spanned for Interpolate { + fn span(&self) -> Span { + union_spans(self.exprs.iter().flat_map(|i| i.iter().map(|e| e.span()))) + } +} + +impl Spanned for InterpolateExpr { + fn span(&self) -> Span { + self.column + .span + .union_opt(&self.expr.as_ref().map(|e| e.span())) + } +} + +impl Spanned for AlterIndexOperation { + fn span(&self) -> Span { + match self { + AlterIndexOperation::RenameIndex { index_name } => index_name.span(), + } + } +} + +/// # partial span +/// +/// Missing spans:ever +/// - [Insert::insert_alias] +impl Spanned for Insert { + fn span(&self) -> Span { + union_spans( + core::iter::once(self.table_name.span()) + .chain(self.table_alias.as_ref().map(|i| i.span)) + .chain(self.columns.iter().map(|i| i.span)) + .chain(self.source.as_ref().map(|q| q.span())) + .chain( + self.partitioned + .iter() + .flat_map(|i| i.iter().map(|k| k.span())), + ) + .chain(self.after_columns.iter().map(|i| i.span)) + .chain(self.on.as_ref().map(|i| i.span())) + .chain( + self.returning + .iter() + .flat_map(|i| i.iter().map(|k| k.span())), + ), + ) + } +} + +impl Spanned for OnInsert { + fn span(&self) -> Span { + match self { + OnInsert::DuplicateKeyUpdate(vec) => union_spans(vec.iter().map(|i| i.span())), + OnInsert::OnConflict(on_conflict) => on_conflict.span(), + } + } +} + +impl Spanned for OnConflict { + fn span(&self) -> Span { + self.action + .span() + .union_opt(&self.conflict_target.as_ref().map(|i| i.span())) + } +} + +impl Spanned for ConflictTarget { + fn span(&self) -> Span { + match self { + ConflictTarget::Columns(vec) => union_spans(vec.iter().map(|i| i.span)), + ConflictTarget::OnConstraint(object_name) => object_name.span(), + } + } +} + +/// # partial span +/// +/// Missing spans: +/// - [OnConflictAction::DoNothing] +impl Spanned for OnConflictAction { + fn span(&self) -> Span { + match self { + OnConflictAction::DoNothing => Span::empty(), + OnConflictAction::DoUpdate(do_update) => do_update.span(), + } + } +} + +impl Spanned for DoUpdate { + fn span(&self) -> Span { + union_spans( + self.assignments + .iter() + .map(|i| i.span()) + .chain(self.selection.iter().map(|i| i.span())), + ) + } +} + +impl Spanned for Assignment { + fn span(&self) -> Span { + self.target.span().union(&self.value.span()) + } +} + +impl Spanned for AssignmentTarget { + fn span(&self) -> Span { + match self { + AssignmentTarget::ColumnName(object_name) => object_name.span(), + AssignmentTarget::Tuple(vec) => union_spans(vec.iter().map(|i| i.span())), + } + } +} + +/// # partial span +/// +/// Most expressions are missing keywords in their spans. +/// f.e. `IS NULL ` reports as `::span`. +/// +/// Missing spans: +/// - [Expr::TypedString] +/// - [Expr::MatchAgainst] # MySQL specific +/// - [Expr::RLike] # MySQL specific +/// - [Expr::Struct] # BigQuery specific +/// - [Expr::Named] # BigQuery specific +/// - [Expr::Dictionary] # DuckDB specific +/// - [Expr::Map] # DuckDB specific +/// - [Expr::Lambda] impl Spanned for Expr { fn span(&self) -> Span { match self { @@ -139,42 +1066,40 @@ impl Spanned for Expr { .union(&union_spans(collation.0.iter().map(|i| i.span))), Expr::Nested(expr) => expr.span(), Expr::Value(value) => value.span(), - Expr::TypedString { data_type, value } => todo!(), - Expr::MapAccess { column, keys } => todo!(), + Expr::TypedString { data_type, value } => Span::empty(), + Expr::MapAccess { column, keys } => column + .span() + .union(&union_spans(keys.iter().map(|i| i.key.span()))), Expr::Function(function) => function.span(), Expr::GroupingSets(vec) => { - union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) - } - Expr::Cube(vec) => { - union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) - } - Expr::Rollup(vec) => { - union_spans(vec.iter().map(|i| i.iter().map(|k| k.span())).flatten()) + union_spans(vec.iter().flat_map(|i| i.iter().map(|k| k.span()))) } + Expr::Cube(vec) => union_spans(vec.iter().flat_map(|i| i.iter().map(|k| k.span()))), + Expr::Rollup(vec) => union_spans(vec.iter().flat_map(|i| i.iter().map(|k| k.span()))), Expr::Tuple(vec) => union_spans(vec.iter().map(|i| i.span())), - Expr::Array(array) => todo!(), + Expr::Array(array) => array.span(), Expr::MatchAgainst { columns, match_value, opt_search_modifier, - } => todo!(), + } => Span::empty(), Expr::JsonAccess { value, path } => value.span().union(&path.span()), Expr::RLike { negated, expr, pattern, regexp, - } => todo!(), + } => Span::empty(), Expr::AnyOp { left, compare_op, right, - } => todo!(), + } => left.span().union(&right.span()), Expr::AllOp { left, compare_op, right, - } => todo!(), + } => left.span().union(&right.span()), Expr::UnaryOp { op, expr } => expr.span(), Expr::Convert { expr, @@ -182,7 +1107,11 @@ impl Spanned for Expr { charset, target_before_value, styles, - } => todo!(), + } => union_spans( + core::iter::once(expr.span()) + .chain(charset.as_ref().map(|i| i.span())) + .chain(styles.iter().map(|i| i.span())), + ), Expr::Cast { kind, expr, @@ -192,12 +1121,12 @@ impl Spanned for Expr { Expr::AtTimeZone { timestamp, time_zone, - } => todo!(), + } => timestamp.span().union(&time_zone.span()), Expr::Extract { field, syntax, expr, - } => todo!(), + } => expr.span(), Expr::Substring { expr, substring_from, @@ -222,7 +1151,7 @@ impl Spanned for Expr { .map(|items| union_spans(items.iter().map(|i| i.span()))), ), ), - Expr::IntroducedString { introducer, value } => value.span(), + Expr::IntroducedString { value, .. } => value.span(), Expr::Case { operand, conditions, @@ -237,14 +1166,14 @@ impl Spanned for Expr { .chain(results.iter().map(|i| i.span())) .chain(else_result.as_ref().map(|i| i.span())), ), - Expr::Exists { subquery, negated } => subquery.span(), + Expr::Exists { subquery, .. } => subquery.span(), Expr::Subquery(query) => query.span(), - Expr::Struct { values, fields } => todo!(), - Expr::Named { expr, name } => todo!(), - Expr::Dictionary(vec) => todo!(), - Expr::Map(map) => todo!(), - Expr::Subscript { expr, subscript } => todo!(), - Expr::Interval(interval) => todo!(), + Expr::Struct { .. } => Span::empty(), + Expr::Named { .. } => Span::empty(), + Expr::Dictionary(_) => Span::empty(), + Expr::Map(_) => Span::empty(), + Expr::Subscript { expr, subscript } => expr.span().union(&subscript.span()), + Expr::Interval(interval) => interval.value.span(), Expr::Wildcard(token) => token.span, Expr::QualifiedWildcard(object_name, token) => union_spans( object_name @@ -253,13 +1182,47 @@ impl Spanned for Expr { .map(|i| i.span) .chain(iter::once(token.span)), ), - Expr::OuterJoin(expr) => todo!(), - Expr::Prior(expr) => todo!(), - Expr::Lambda(lambda_function) => todo!(), + Expr::OuterJoin(expr) => expr.span(), + Expr::Prior(expr) => expr.span(), + Expr::Lambda(_) => Span::empty(), } } } +impl Spanned for Subscript { + fn span(&self) -> Span { + match self { + Subscript::Index { index } => index.span(), + Subscript::Slice { + lower_bound, + upper_bound, + stride, + } => union_spans( + [ + lower_bound.as_ref().map(|i| i.span()), + upper_bound.as_ref().map(|i| i.span()), + stride.as_ref().map(|i| i.span()), + ] + .iter() + .flatten() + .cloned(), + ), + } + } +} + +impl Spanned for ObjectName { + fn span(&self) -> Span { + union_spans(self.0.iter().map(|i| i.span)) + } +} + +impl Spanned for Array { + fn span(&self) -> Span { + union_spans(self.elem.iter().map(|i| i.span())) + } +} + impl Spanned for Function { fn span(&self) -> Span { union_spans( @@ -272,6 +1235,9 @@ impl Spanned for Function { } } +/// # partial span +/// +/// The span of [FunctionArguments::None] is empty. impl Spanned for FunctionArguments { fn span(&self) -> Span { match self { @@ -307,12 +1273,19 @@ impl Spanned for FunctionArgumentClause { } } +/// # partial span +/// +/// see Spanned impl for JsonPathElem for more information impl Spanned for JsonPath { fn span(&self) -> Span { union_spans(self.path.iter().map(|i| i.span())) } } +/// # partial span +/// +/// Missing spans: +/// - [JsonPathElem::Dot] impl Spanned for JsonPathElem { fn span(&self) -> Span { match self { @@ -343,18 +1316,19 @@ impl Spanned for WildcardAdditionalOptions { fn span(&self) -> Span { union_spans( core::iter::once(self.wildcard_token.span) - .chain(self.opt_ilike.as_ref().map(|i| i.span()).into_iter()) - .chain(self.opt_exclude.as_ref().map(|i| i.span()).into_iter()) - .chain(self.opt_rename.as_ref().map(|i| i.span()).into_iter()) - .chain(self.opt_replace.as_ref().map(|i| i.span()).into_iter()) - .chain(self.opt_except.as_ref().map(|i| i.span()).into_iter()), + .chain(self.opt_ilike.as_ref().map(|i| i.span())) + .chain(self.opt_exclude.as_ref().map(|i| i.span())) + .chain(self.opt_rename.as_ref().map(|i| i.span())) + .chain(self.opt_replace.as_ref().map(|i| i.span())) + .chain(self.opt_except.as_ref().map(|i| i.span())), ) } } +/// # missing span impl Spanned for IlikeSelectItem { fn span(&self) -> Span { - Span::empty() // # todo: missing span + Span::empty() } } @@ -399,6 +1373,10 @@ impl Spanned for ReplaceSelectElement { } } +/// # partial span +/// +/// Missing spans: +/// - [TableFactor::JsonTable] impl Spanned for TableFactor { fn span(&self) -> Span { match self { @@ -411,17 +1389,14 @@ impl Spanned for TableFactor { with_ordinality, partitions, } => union_spans( - name.0.iter().map(|i| i.span).chain( - alias - .as_ref() - .map(|alias| { - union_spans( - iter::once(alias.name.span) - .chain(alias.columns.iter().map(|i| i.span)), - ) - }) - .into_iter(), - ), + name.0 + .iter() + .map(|i| i.span) + .chain(alias.as_ref().map(|alias| { + union_spans( + iter::once(alias.name.span).chain(alias.columns.iter().map(|i| i.span)), + ) + })), ), TableFactor::Derived { lateral, @@ -430,18 +1405,28 @@ impl Spanned for TableFactor { } => subquery .span() .union_opt(&alias.as_ref().map(|alias| alias.span())), - TableFactor::TableFunction { expr, alias } => todo!(), + TableFactor::TableFunction { expr, alias } => expr + .span() + .union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::UNNEST { alias, with_offset, with_offset_alias, array_exprs, with_ordinality, - } => todo!(), + } => union_spans( + alias + .iter() + .map(|i| i.span()) + .chain(array_exprs.iter().map(|i| i.span())) + .chain(with_offset_alias.as_ref().map(|i| i.span)), + ), TableFactor::NestedJoin { table_with_joins, alias, - } => todo!(), + } => table_with_joins + .span() + .union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::Function { lateral, name, @@ -459,7 +1444,7 @@ impl Spanned for TableFactor { json_path, columns, alias, - } => todo!(), + } => Span::empty(), TableFactor::Pivot { table, aggregate_functions, @@ -467,14 +1452,27 @@ impl Spanned for TableFactor { value_source, default_on_null, alias, - } => todo!(), + } => union_spans( + core::iter::once(table.span()) + .chain(aggregate_functions.iter().map(|i| i.span())) + .chain(value_column.iter().map(|i| i.span)) + .chain(core::iter::once(value_source.span())) + .chain(default_on_null.as_ref().map(|i| i.span())) + .chain(alias.as_ref().map(|i| i.span())), + ), TableFactor::Unpivot { table, value, name, columns, alias, - } => todo!(), + } => union_spans( + core::iter::once(table.span()) + .chain(core::iter::once(value.span)) + .chain(core::iter::once(name.span)) + .chain(columns.iter().map(|i| i.span)) + .chain(alias.as_ref().map(|alias| alias.span())), + ), TableFactor::MatchRecognize { table, partition_by, @@ -485,11 +1483,76 @@ impl Spanned for TableFactor { pattern, symbols, alias, - } => todo!(), + } => union_spans( + core::iter::once(table.span()) + .chain(partition_by.iter().map(|i| i.span())) + .chain(order_by.iter().map(|i| i.span())) + .chain(measures.iter().map(|i| i.span())) + .chain(core::iter::once(pattern.span())) + .chain(symbols.iter().map(|i| i.span())) + .chain(alias.as_ref().map(|i| i.span())), + ), } } } +impl Spanned for PivotValueSource { + fn span(&self) -> Span { + match self { + PivotValueSource::List(vec) => union_spans(vec.iter().map(|i| i.span())), + PivotValueSource::Any(vec) => union_spans(vec.iter().map(|i| i.span())), + PivotValueSource::Subquery(query) => query.span(), + } + } +} + +impl Spanned for ExprWithAlias { + fn span(&self) -> Span { + self.expr + .span() + .union_opt(&self.alias.as_ref().map(|i| i.span)) + } +} + +/// # missing span +impl Spanned for MatchRecognizePattern { + fn span(&self) -> Span { + Span::empty() + } +} + +impl Spanned for SymbolDefinition { + fn span(&self) -> Span { + self.symbol.span.union(&self.definition.span()) + } +} + +impl Spanned for Measure { + fn span(&self) -> Span { + self.expr.span().union(&self.alias.span) + } +} + +impl Spanned for OrderByExpr { + fn span(&self) -> Span { + self.expr + .span() + .union_opt(&self.with_fill.as_ref().map(|f| f.span()).clone()) + } +} + +impl Spanned for WithFill { + fn span(&self) -> Span { + union_spans( + self.from + .iter() + .map(|f| f.span()) + .chain(self.to.iter().map(|t| t.span())) + .chain(self.step.iter().map(|s| s.span())), + ) + } +} + impl Spanned for FunctionArg { fn span(&self) -> Span { match self { @@ -503,6 +1566,10 @@ impl Spanned for FunctionArg { } } +/// # partial span +/// +/// Missing spans: +/// - [FunctionArgExpr::Wildcard] impl Spanned for FunctionArgExpr { fn span(&self) -> Span { match self { @@ -521,6 +1588,10 @@ impl Spanned for TableAlias { } } +/// # missing span +/// +/// The span of a `Value` is currently not implemented, as doing so +/// requires a breaking changes, which may be done in a future release. impl Spanned for Value { fn span(&self) -> Span { Span::empty() // # todo: Value needs to store spans before this is possible @@ -533,6 +1604,12 @@ impl Spanned for Join { } } +/// # partial span +/// +/// Missing spans: +/// - [JoinOperator::CrossJoin] +/// - [JoinOperator::CrossApply] +/// - [JoinOperator::OuterApply] impl Spanned for JoinOperator { fn span(&self) -> Span { match self { @@ -550,11 +1627,16 @@ impl Spanned for JoinOperator { JoinOperator::AsOf { match_condition, constraint, - } => todo!(), + } => match_condition.span().union(&constraint.span()), } } } +/// # partial span +/// +/// Missing spans: +/// - [JoinConstraint::Natural] +/// - [JoinConstraint::None] impl Spanned for JoinConstraint { fn span(&self) -> Span { match self { @@ -582,7 +1664,7 @@ pub fn union_spans>(iter: I) -> Span { impl Spanned for Select { fn span(&self) -> Span { union_spans( - core::iter::once(self.select_token.span.clone()) + core::iter::once(self.select_token.span) .chain(self.projection.iter().map(|item| item.span())) .chain(self.from.iter().map(|item| item.span())), ) @@ -612,7 +1694,7 @@ pub mod tests { #[test] fn test_query_span() { - let query = crate::parser::Parser::new(&GenericDialect::default()) + let query = crate::parser::Parser::new(&GenericDialect) .try_with_sql( "SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id", ) @@ -628,7 +1710,7 @@ pub mod tests { #[test] pub fn test_union() { - let query = crate::parser::Parser::new(&GenericDialect::default()) + let query = crate::parser::Parser::new(&GenericDialect) .try_with_sql( "SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source", ) @@ -641,7 +1723,7 @@ pub mod tests { #[test] pub fn test_subquery() { - let query = crate::parser::Parser::new(&GenericDialect::default()) + let query = crate::parser::Parser::new(&GenericDialect) .try_with_sql("SELECT a FROM (SELECT a FROM postgres.public.source) AS b") .unwrap() .parse_query() @@ -652,7 +1734,7 @@ pub mod tests { #[test] pub fn test_cte() { - let query = crate::parser::Parser::new(&GenericDialect::default()) + let query = crate::parser::Parser::new(&GenericDialect) .try_with_sql("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") .unwrap() .parse_query() @@ -663,7 +1745,7 @@ pub mod tests { #[test] pub fn test_snowflake_lateral_flatten() { - let query = crate::parser::Parser::new(&SnowflakeDialect::default()) + let query = crate::parser::Parser::new(&SnowflakeDialect) .try_with_sql("SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED") .unwrap() .parse_query() @@ -674,7 +1756,7 @@ pub mod tests { #[test] pub fn test_wildcard_from_cte() { - let dialect = &GenericDialect::default(); + let dialect = &GenericDialect; let mut test = SpanTest::new( dialect, "WITH cte AS (SELECT a FROM postgres.public.source) SELECT cte.* FROM cte", diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d50cf9f35..da716a326 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> { pub fn parse_case_expr(&mut self) -> Result { let mut operand = None; - if !self.parse_keyword(Keyword::WHEN).is_some() { + if self.parse_keyword(Keyword::WHEN).is_none() { operand = Some(Box::new(self.parse_expr()?)); self.expect_keyword(Keyword::WHEN)?; } @@ -1560,7 +1560,7 @@ impl<'a> Parser<'a> { conditions.push(self.parse_expr()?); self.expect_keyword(Keyword::THEN)?; results.push(self.parse_expr()?); - if !self.parse_keyword(Keyword::WHEN).is_some() { + if self.parse_keyword(Keyword::WHEN).is_none() { break; } } @@ -1906,7 +1906,7 @@ impl<'a> Parser<'a> { )?, }; let with_count = self.parse_keyword(Keyword::WITH).is_some(); - if !with_count && !self.parse_keyword(Keyword::WITHOUT).is_some() { + if !with_count && self.parse_keyword(Keyword::WITHOUT).is_none() { self.expected("either WITH or WITHOUT in LISTAGG", self.peek_token())?; } self.expect_keyword(Keyword::COUNT)?; @@ -3250,7 +3250,7 @@ impl<'a> Parser<'a> { pub fn parse_keywords(&mut self, keywords: &[Keyword]) -> bool { let index = self.index; for &keyword in keywords { - if !self.parse_keyword(keyword).is_some() { + if self.parse_keyword(keyword).is_none() { // println!("parse_keywords aborting .. did not find {:?}", keyword); // reset index and return immediately self.index = index; @@ -3450,7 +3450,7 @@ impl<'a> Parser<'a> { let mut values = vec![]; loop { values.push(f(self)?); - if !self.parse_keyword(keyword).is_some() { + if self.parse_keyword(keyword).is_none() { break; } } @@ -3835,7 +3835,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_create_function_using( &mut self, ) -> Result, ParserError> { - if !self.parse_keyword(Keyword::USING).is_some() { + if self.parse_keyword(Keyword::USING).is_none() { return Ok(None); }; let keyword = @@ -5325,7 +5325,7 @@ impl<'a> Parser<'a> { pub fn parse_create_index(&mut self, unique: bool) -> Result { let concurrently = self.parse_keyword(Keyword::CONCURRENTLY).is_some(); let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); - let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON).is_some() { + let index_name = if if_not_exists || self.parse_keyword(Keyword::ON).is_none() { let index_name = self.parse_object_name(false)?; self.expect_keyword(Keyword::ON)?; Some(index_name) @@ -7940,7 +7940,7 @@ impl<'a> Parser<'a> { let mut modifiers = vec![]; if dialect_of!(self is ClickHouseDialect | GenericDialect) { loop { - if !self.parse_keyword(Keyword::WITH).is_some() { + if self.parse_keyword(Keyword::WITH).is_none() { break; } let keyword = self.expect_one_of_keywords(&[ @@ -8402,7 +8402,7 @@ impl<'a> Parser<'a> { } pub fn parse_delete(&mut self) -> Result { - let (tables, with_from_keyword) = if !self.parse_keyword(Keyword::FROM).is_some() { + let (tables, with_from_keyword) = if self.parse_keyword(Keyword::FROM).is_none() { // `FROM` keyword is optional in BigQuery SQL. // https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#delete_statement if dialect_of!(self is BigQueryDialect | GenericDialect) { @@ -11223,7 +11223,7 @@ impl<'a> Parser<'a> { // Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect) // that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier pub fn parse_interpolations(&mut self) -> Result, ParserError> { - if !self.parse_keyword(Keyword::INTERPOLATE).is_some() { + if self.parse_keyword(Keyword::INTERPOLATE).is_none() { return Ok(None); } @@ -11463,7 +11463,7 @@ impl<'a> Parser<'a> { pub fn parse_commit_rollback_chain(&mut self) -> Result { let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]); if self.parse_keyword(Keyword::AND).is_some() { - let chain = !self.parse_keyword(Keyword::NO).is_some(); + let chain = self.parse_keyword(Keyword::NO).is_none(); self.expect_keyword(Keyword::CHAIN)?; Ok(chain) } else { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e9ada1fcd..a7568176e 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -487,8 +487,8 @@ impl Span { // If either span is empty, return the other // this prevents propagating (0, 0) through the tree match (self, other) { - (&Span::EMPTY, _) => other.clone(), - (_, &Span::EMPTY) => self.clone(), + (&Span::EMPTY, _) => *other, + (_, &Span::EMPTY) => *self, _ => Span { start: cmp::min(self.start, other.start), end: cmp::max(self.end, other.end), @@ -498,8 +498,8 @@ impl Span { pub fn union_opt(&self, other: &Option) -> Span { match other { - Some(other) => self.union(&other), - None => self.clone(), + Some(other) => self.union(other), + None => *self, } } } From ea8a6b1abf2ea5861c21bee413c12c84ccf2b2e8 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 8 Oct 2024 12:38:25 +0200 Subject: [PATCH 12/23] fix unused variable warnings --- src/ast/spans.rs | 184 ++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 99 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index ee8cd2122..b0df0ac15 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -69,14 +69,14 @@ impl Spanned for SetExpr { SetExpr::Select(select) => select.span(), SetExpr::Query(query) => query.span(), SetExpr::SetOperation { - op, - set_quantifier, + op: _, + set_quantifier: _, left, right, } => left.span().union(&right.span()), SetExpr::Values(values) => values.span(), SetExpr::Insert(statement) => statement.span(), - SetExpr::Table(table) => Span::empty(), + SetExpr::Table(_) => Span::empty(), SetExpr::Update(statement) => statement.span(), } } @@ -266,7 +266,7 @@ impl Spanned for Statement { Statement::CreateTable(create_table) => create_table.span(), Statement::CreateVirtualTable { name, - if_not_exists, + if_not_exists: _, module_name, module_args, } => union_spans( @@ -279,10 +279,10 @@ impl Spanned for Statement { Statement::CreateSecret { .. } => Span::empty(), Statement::AlterTable { name, - if_exists, - only, + if_exists: _, + only: _, operations, - location, + location: _, on_cluster, } => union_spans( core::iter::once(name.span()) @@ -331,8 +331,8 @@ impl Spanned for Statement { Statement::StartTransaction { .. } => Span::empty(), Statement::SetTransaction { .. } => Span::empty(), Statement::Comment { .. } => Span::empty(), - Statement::Commit { chain } => Span::empty(), - Statement::Rollback { chain, savepoint } => Span::empty(), + Statement::Commit { .. } => Span::empty(), + Statement::Rollback { .. } => Span::empty(), Statement::CreateSchema { .. } => Span::empty(), Statement::CreateDatabase { .. } => Span::empty(), Statement::CreateFunction { .. } => Span::empty(), @@ -341,26 +341,26 @@ impl Spanned for Statement { Statement::CreateProcedure { .. } => Span::empty(), Statement::CreateMacro { .. } => Span::empty(), Statement::CreateStage { .. } => Span::empty(), - Statement::Assert { condition, message } => Span::empty(), + Statement::Assert { .. } => Span::empty(), Statement::Grant { .. } => Span::empty(), Statement::Revoke { .. } => Span::empty(), - Statement::Deallocate { name, prepare } => Span::empty(), + Statement::Deallocate { .. } => Span::empty(), Statement::Execute { .. } => Span::empty(), Statement::Prepare { .. } => Span::empty(), - Statement::Kill { modifier, id } => Span::empty(), + Statement::Kill { .. } => Span::empty(), Statement::ExplainTable { .. } => Span::empty(), Statement::Explain { .. } => Span::empty(), - Statement::Savepoint { name } => Span::empty(), - Statement::ReleaseSavepoint { name } => Span::empty(), + Statement::Savepoint { .. } => Span::empty(), + Statement::ReleaseSavepoint { .. } => Span::empty(), Statement::Merge { .. } => Span::empty(), Statement::Cache { .. } => Span::empty(), Statement::UNCache { .. } => Span::empty(), Statement::CreateSequence { .. } => Span::empty(), Statement::CreateType { .. } => Span::empty(), - Statement::Pragma { name, value, is_eq } => Span::empty(), - Statement::LockTables { tables } => Span::empty(), + Statement::Pragma { .. } => Span::empty(), + Statement::LockTables { .. } => Span::empty(), Statement::UnlockTables => Span::empty(), - Statement::Unload { query, to, with } => Span::empty(), + Statement::Unload { .. } => Span::empty(), Statement::OptimizeTable { .. } => Span::empty(), } } @@ -466,9 +466,9 @@ impl Spanned for TableConstraint { expr.span().union_opt(&name.as_ref().map(|i| i.span)) } TableConstraint::Index { - display_as_key, + display_as_key: _, name, - index_type, + index_type: _, columns, } => union_spans( name.iter() @@ -476,8 +476,8 @@ impl Spanned for TableConstraint { .chain(columns.iter().map(|i| i.span)), ), TableConstraint::FulltextOrSpatial { - fulltext, - index_type_display, + fulltext: _, + index_type_display: _, opt_index_name, columns, } => union_spans( @@ -700,24 +700,24 @@ impl Spanned for AlterTableOperation { match self { AlterTableOperation::AddConstraint(table_constraint) => table_constraint.span(), AlterTableOperation::AddColumn { - column_keyword, - if_not_exists, + column_keyword: _, + if_not_exists: _, column_def, - column_position, + column_position: _, } => column_def.span(), AlterTableOperation::AddProjection { - if_not_exists, + if_not_exists: _, name, select, } => name.span.union(&select.span()), - AlterTableOperation::DropProjection { if_exists, name } => name.span, + AlterTableOperation::DropProjection { if_exists: _, name } => name.span, AlterTableOperation::MaterializeProjection { - if_exists, + if_exists: _, name, partition, } => name.span.union_opt(&partition.as_ref().map(|i| i.span)), AlterTableOperation::ClearProjection { - if_exists, + if_exists: _, name, partition, } => name.span.union_opt(&partition.as_ref().map(|i| i.span)), @@ -725,14 +725,14 @@ impl Spanned for AlterTableOperation { AlterTableOperation::DisableRule { name } => name.span, AlterTableOperation::DisableTrigger { name } => name.span, AlterTableOperation::DropConstraint { - if_exists, + if_exists: _, name, - cascade, + cascade: _, } => name.span, AlterTableOperation::DropColumn { column_name, - if_exists, - cascade, + if_exists: _, + cascade: _, } => column_name.span, AlterTableOperation::AttachPartition { partition } => partition.span(), AlterTableOperation::DetachPartition { partition } => partition.span(), @@ -766,12 +766,12 @@ impl Spanned for AlterTableOperation { .chain(new_partitions.iter().map(|i| i.span())), ), AlterTableOperation::AddPartitions { - if_not_exists, + if_not_exists: _, new_partitions, } => union_spans(new_partitions.iter().map(|i| i.span())), AlterTableOperation::DropPartitions { partitions, - if_exists, + if_exists: _, } => union_spans(partitions.iter().map(|i| i.span())), AlterTableOperation::RenameColumn { old_column_name, @@ -781,9 +781,9 @@ impl Spanned for AlterTableOperation { AlterTableOperation::ChangeColumn { old_name, new_name, - data_type, + data_type: _, options, - column_position, + column_position: _, } => union_spans( core::iter::once(old_name.span) .chain(core::iter::once(new_name.span)) @@ -791,9 +791,9 @@ impl Spanned for AlterTableOperation { ), AlterTableOperation::ModifyColumn { col_name, - data_type, + data_type: _, options, - column_position, + column_position: _, } => { union_spans(core::iter::once(col_name.span).chain(options.iter().map(|i| i.span()))) } @@ -807,7 +807,7 @@ impl Spanned for AlterTableOperation { AlterTableOperation::SetTblProperties { table_properties } => { union_spans(table_properties.iter().map(|i| i.span())) } - AlterTableOperation::OwnerTo { new_owner } => Span::empty(), + AlterTableOperation::OwnerTo { .. } => Span::empty(), } } } @@ -853,7 +853,7 @@ impl Spanned for OrderBy { impl Spanned for GroupByExpr { fn span(&self) -> Span { match self { - GroupByExpr::All(vec) => Span::empty(), + GroupByExpr::All(_) => Span::empty(), GroupByExpr::Expressions(exprs, _modifiers) => { union_spans(exprs.iter().map(|i| i.span())) } @@ -1008,48 +1008,48 @@ impl Spanned for Expr { Expr::InList { expr, list, - negated, + negated: _, } => union_spans( core::iter::once(expr.span()).chain(list.iter().map(|item| item.span())), ), Expr::InSubquery { expr, subquery, - negated, + negated: _, } => expr.span().union(&subquery.span()), Expr::InUnnest { expr, array_expr, - negated, + negated: _, } => expr.span().union(&array_expr.span()), Expr::Between { expr, - negated, + negated: _, low, high, } => expr.span().union(&low.span()).union(&high.span()), - Expr::BinaryOp { left, op, right } => left.span().union(&right.span()), + Expr::BinaryOp { left, op: _, right } => left.span().union(&right.span()), Expr::Like { - negated, + negated: _, expr, pattern, - escape_char, + escape_char: _, } => expr.span().union(&pattern.span()), Expr::ILike { - negated, + negated: _, expr, pattern, - escape_char, + escape_char: _, } => expr.span().union(&pattern.span()), Expr::SimilarTo { - negated, + negated: _, expr, pattern, - escape_char, + escape_char: _, } => expr.span().union(&pattern.span()), - Expr::Ceil { expr, field } => expr.span(), - Expr::Floor { expr, field } => expr.span(), + Expr::Ceil { expr, field: _ } => expr.span(), + Expr::Floor { expr, field: _ } => expr.span(), Expr::Position { expr, r#in } => expr.span().union(&r#in.span()), Expr::Overlay { expr, @@ -1066,7 +1066,7 @@ impl Spanned for Expr { .union(&union_spans(collation.0.iter().map(|i| i.span))), Expr::Nested(expr) => expr.span(), Expr::Value(value) => value.span(), - Expr::TypedString { data_type, value } => Span::empty(), + Expr::TypedString { .. } => Span::empty(), Expr::MapAccess { column, keys } => column .span() .union(&union_spans(keys.iter().map(|i| i.key.span()))), @@ -1078,34 +1078,25 @@ impl Spanned for Expr { Expr::Rollup(vec) => union_spans(vec.iter().flat_map(|i| i.iter().map(|k| k.span()))), Expr::Tuple(vec) => union_spans(vec.iter().map(|i| i.span())), Expr::Array(array) => array.span(), - Expr::MatchAgainst { - columns, - match_value, - opt_search_modifier, - } => Span::empty(), + Expr::MatchAgainst { .. } => Span::empty(), Expr::JsonAccess { value, path } => value.span().union(&path.span()), - Expr::RLike { - negated, - expr, - pattern, - regexp, - } => Span::empty(), + Expr::RLike { .. } => Span::empty(), Expr::AnyOp { left, - compare_op, + compare_op: _, right, } => left.span().union(&right.span()), Expr::AllOp { left, - compare_op, + compare_op: _, right, } => left.span().union(&right.span()), - Expr::UnaryOp { op, expr } => expr.span(), + Expr::UnaryOp { op: _, expr } => expr.span(), Expr::Convert { expr, - data_type, + data_type: _, charset, - target_before_value, + target_before_value: _, styles, } => union_spans( core::iter::once(expr.span()) @@ -1113,25 +1104,25 @@ impl Spanned for Expr { .chain(styles.iter().map(|i| i.span())), ), Expr::Cast { - kind, + kind: _, expr, - data_type, - format, + data_type: _, + format: _, } => expr.span(), Expr::AtTimeZone { timestamp, time_zone, } => timestamp.span().union(&time_zone.span()), Expr::Extract { - field, - syntax, + field: _, + syntax: _, expr, } => expr.span(), Expr::Substring { expr, substring_from, substring_for, - special, + special: _, } => union_spans( core::iter::once(expr.span()) .chain(substring_from.as_ref().map(|i| i.span())) @@ -1139,7 +1130,7 @@ impl Spanned for Expr { ), Expr::Trim { expr, - trim_where, + trim_where: _, trim_what, trim_characters, } => union_spans( @@ -1263,11 +1254,11 @@ impl Spanned for FunctionArgumentList { impl Spanned for FunctionArgumentClause { fn span(&self) -> Span { match self { - FunctionArgumentClause::IgnoreOrRespectNulls(null_treatment) => Span::empty(), + FunctionArgumentClause::IgnoreOrRespectNulls(_) => Span::empty(), FunctionArgumentClause::OrderBy(vec) => union_spans(vec.iter().map(|i| i.expr.span())), FunctionArgumentClause::Limit(expr) => expr.span(), - FunctionArgumentClause::OnOverflow(list_agg_on_overflow) => Span::empty(), - FunctionArgumentClause::Having(HavingBound(kind, expr)) => expr.span(), + FunctionArgumentClause::OnOverflow(_) => Span::empty(), + FunctionArgumentClause::Having(HavingBound(_kind, expr)) => expr.span(), FunctionArgumentClause::Separator(value) => value.span(), } } @@ -1289,7 +1280,7 @@ impl Spanned for JsonPath { impl Spanned for JsonPathElem { fn span(&self) -> Span { match self { - JsonPathElem::Dot { key, quoted } => Span::empty(), + JsonPathElem::Dot { .. } => Span::empty(), JsonPathElem::Bracket { key } => key.span(), } } @@ -1383,11 +1374,11 @@ impl Spanned for TableFactor { TableFactor::Table { name, alias, - args, - with_hints, - version, - with_ordinality, - partitions, + args: _, + with_hints: _, + version: _, + with_ordinality: _, + partitions: _, } => union_spans( name.0 .iter() @@ -1399,7 +1390,7 @@ impl Spanned for TableFactor { })), ), TableFactor::Derived { - lateral, + lateral: _, subquery, alias, } => subquery @@ -1410,10 +1401,10 @@ impl Spanned for TableFactor { .union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::UNNEST { alias, - with_offset, + with_offset: _, with_offset_alias, array_exprs, - with_ordinality, + with_ordinality: _, } => union_spans( alias .iter() @@ -1428,7 +1419,7 @@ impl Spanned for TableFactor { .span() .union_opt(&alias.as_ref().map(|alias| alias.span())), TableFactor::Function { - lateral, + lateral: _, name, args, alias, @@ -1439,12 +1430,7 @@ impl Spanned for TableFactor { .chain(args.iter().map(|i| i.span())) .chain(alias.as_ref().map(|alias| alias.span())), ), - TableFactor::JsonTable { - json_expr, - json_path, - columns, - alias, - } => Span::empty(), + TableFactor::JsonTable { .. } => Span::empty(), TableFactor::Pivot { table, aggregate_functions, @@ -1478,8 +1464,8 @@ impl Spanned for TableFactor { partition_by, order_by, measures, - rows_per_match, - after_match_skip, + rows_per_match: _, + after_match_skip: _, pattern, symbols, alias, @@ -1559,7 +1545,7 @@ impl Spanned for FunctionArg { FunctionArg::Named { name, arg, - operator, + operator: _, } => name.span.union(&arg.span()), FunctionArg::Unnamed(arg) => arg.span(), } From 6a9250aee884f6bf96a196e58e396c5f0fcc4223 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 8 Oct 2024 12:50:09 +0200 Subject: [PATCH 13/23] undo parse_keyword signature change --- src/dialect/mysql.rs | 8 +- src/dialect/postgresql.rs | 4 +- src/dialect/snowflake.rs | 44 +- src/dialect/sqlite.rs | 2 +- src/parser/alter.rs | 18 +- src/parser/mod.rs | 1017 ++++++++++++++--------------- tests/sqlparser_custom_dialect.rs | 2 +- 7 files changed, 544 insertions(+), 551 deletions(-) diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs index e171733ca..b8c4631fd 100644 --- a/src/dialect/mysql.rs +++ b/src/dialect/mysql.rs @@ -64,7 +64,7 @@ impl Dialect for MySqlDialect { _precedence: u8, ) -> Option> { // Parse DIV as an operator - if parser.parse_keyword(Keyword::DIV).is_some() { + if parser.parse_keyword(Keyword::DIV) { Some(Ok(Expr::BinaryOp { left: Box::new(expr.clone()), op: BinaryOperator::MyIntegerDivide, @@ -113,13 +113,13 @@ fn parse_lock_table(parser: &mut Parser) -> Result { // READ [LOCAL] | [LOW_PRIORITY] WRITE fn parse_lock_tables_type(parser: &mut Parser) -> Result { - if parser.parse_keyword(Keyword::READ).is_some() { - if parser.parse_keyword(Keyword::LOCAL).is_some() { + if parser.parse_keyword(Keyword::READ) { + if parser.parse_keyword(Keyword::LOCAL) { Ok(LockTableType::Read { local: true }) } else { Ok(LockTableType::Read { local: false }) } - } else if parser.parse_keyword(Keyword::WRITE).is_some() { + } else if parser.parse_keyword(Keyword::WRITE) { Ok(LockTableType::Write { low_priority: false, }) diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index 745d823f7..eba3a6989 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -119,7 +119,7 @@ impl Dialect for PostgreSqlDialect { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::COMMENT).is_some() { + if parser.parse_keyword(Keyword::COMMENT) { Some(parse_comment(parser)) } else { None @@ -187,7 +187,7 @@ pub fn parse_comment(parser: &mut Parser) -> Result { }; parser.expect_keyword(Keyword::IS)?; - let comment = if parser.parse_keyword(Keyword::NULL).is_some() { + let comment = if parser.parse_keyword(Keyword::NULL) { None } else { Some(parser.parse_literal_string()?) diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index 9d1c1ae69..4f37004b1 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -90,7 +90,7 @@ impl Dialect for SnowflakeDialect { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::CREATE).is_some() { + if parser.parse_keyword(Keyword::CREATE) { // possibly CREATE STAGE //[ OR REPLACE ] let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]); @@ -117,10 +117,10 @@ impl Dialect for SnowflakeDialect { _ => {} } - if parser.parse_keyword(Keyword::STAGE).is_some() { + if parser.parse_keyword(Keyword::STAGE) { // OK - this is CREATE STAGE statement return Some(parse_create_stage(or_replace, temporary, parser)); - } else if parser.parse_keyword(Keyword::TABLE).is_some() { + } else if parser.parse_keyword(Keyword::TABLE) { return Some(parse_create_table( or_replace, global, temporary, volatile, transient, parser, )); @@ -375,25 +375,25 @@ pub fn parse_create_stage( let stage_params = parse_stage_params(parser)?; // [ directoryTableParams ] - if parser.parse_keyword(Keyword::DIRECTORY).is_some() { + if parser.parse_keyword(Keyword::DIRECTORY) { parser.expect_token(&Token::Eq)?; directory_table_params = parse_parentheses_options(parser)?; } // [ file_format] - if parser.parse_keyword(Keyword::FILE_FORMAT).is_some() { + if parser.parse_keyword(Keyword::FILE_FORMAT) { parser.expect_token(&Token::Eq)?; file_format = parse_parentheses_options(parser)?; } // [ copy_options ] - if parser.parse_keyword(Keyword::COPY_OPTIONS).is_some() { + if parser.parse_keyword(Keyword::COPY_OPTIONS) { parser.expect_token(&Token::Eq)?; copy_options = parse_parentheses_options(parser)?; } // [ comment ] - if parser.parse_keyword(Keyword::COMMENT).is_some() { + if parser.parse_keyword(Keyword::COMMENT) { parser.expect_token(&Token::Eq)?; comment = Some(match parser.next_token().token { Token::SingleQuotedString(word) => Ok(word), @@ -485,7 +485,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result { stage_params = parse_stage_params(parser)?; // as - from_stage_alias = if parser.parse_keyword(Keyword::AS).is_some() { + from_stage_alias = if parser.parse_keyword(Keyword::AS) { Some(match parser.next_token().token { Token::Word(w) => Ok(Ident::new(w.value)), _ => parser.expected("stage alias", parser.peek_token()), @@ -501,7 +501,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result { stage_params = parse_stage_params(parser)?; // as - from_stage_alias = if parser.parse_keyword(Keyword::AS).is_some() { + from_stage_alias = if parser.parse_keyword(Keyword::AS) { Some(match parser.next_token().token { Token::Word(w) => Ok(Ident::new(w.value)), _ => parser.expected("stage alias", parser.peek_token()), @@ -513,7 +513,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result { }; // [ files ] - if parser.parse_keyword(Keyword::FILES).is_some() { + if parser.parse_keyword(Keyword::FILES) { parser.expect_token(&Token::Eq)?; parser.expect_token(&Token::LParen)?; let mut continue_loop = true; @@ -535,7 +535,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result { // [ pattern ] let mut pattern = None; - if parser.parse_keyword(Keyword::PATTERN).is_some() { + if parser.parse_keyword(Keyword::PATTERN) { parser.expect_token(&Token::Eq)?; let next_token = parser.next_token(); pattern = Some(match next_token.token { @@ -546,21 +546,21 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result { // [ file_format] let mut file_format = Vec::new(); - if parser.parse_keyword(Keyword::FILE_FORMAT).is_some() { + if parser.parse_keyword(Keyword::FILE_FORMAT) { parser.expect_token(&Token::Eq)?; file_format = parse_parentheses_options(parser)?; } // [ copy_options ] let mut copy_options = Vec::new(); - if parser.parse_keyword(Keyword::COPY_OPTIONS).is_some() { + if parser.parse_keyword(Keyword::COPY_OPTIONS) { parser.expect_token(&Token::Eq)?; copy_options = parse_parentheses_options(parser)?; } // [ VALIDATION_MODE ] let mut validation_mode = None; - if parser.parse_keyword(Keyword::VALIDATION_MODE).is_some() { + if parser.parse_keyword(Keyword::VALIDATION_MODE) { parser.expect_token(&Token::Eq)?; validation_mode = Some(parser.next_token().token.to_string()); } @@ -640,7 +640,7 @@ fn parse_select_items_for_data_load( } // as - if parser.parse_keyword(Keyword::AS).is_some() { + if parser.parse_keyword(Keyword::AS) { item_as = Some(match parser.next_token().token { Token::Word(w) => Ok(Ident::new(w.value)), _ => parser.expected("column item alias", parser.peek_token()), @@ -673,7 +673,7 @@ fn parse_stage_params(parser: &mut Parser) -> Result Ok(word), @@ -682,13 +682,13 @@ fn parse_stage_params(parser: &mut Parser) -> Result Ok(word), @@ -697,7 +697,7 @@ fn parse_stage_params(parser: &mut Parser) -> Result Result Result break, Token::Word(key) => { parser.expect_token(&Token::Eq)?; - if parser.parse_keyword(Keyword::TRUE).is_some() { + if parser.parse_keyword(Keyword::TRUE) { options.push(DataLoadingOption { option_name: key.value, option_type: DataLoadingOptionType::BOOLEAN, value: "TRUE".to_string(), }); Ok(()) - } else if parser.parse_keyword(Keyword::FALSE).is_some() { + } else if parser.parse_keyword(Keyword::FALSE) { options.push(DataLoadingOption { option_name: key.value, option_type: DataLoadingOptionType::BOOLEAN, diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs index 87f12262a..cc08d7961 100644 --- a/src/dialect/sqlite.rs +++ b/src/dialect/sqlite.rs @@ -57,7 +57,7 @@ impl Dialect for SQLiteDialect { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::REPLACE).is_some() { + if parser.parse_keyword(Keyword::REPLACE) { parser.prev_token(); Some(parser.parse_insert()) } else { diff --git a/src/parser/alter.rs b/src/parser/alter.rs index c6cbf5684..7bf99af66 100644 --- a/src/parser/alter.rs +++ b/src/parser/alter.rs @@ -72,15 +72,15 @@ impl<'a> Parser<'a> { None }; - let operation = if self.parse_keyword(Keyword::RENAME).is_some() { - if self.parse_keyword(Keyword::TO).is_some() { + let operation = if self.parse_keyword(Keyword::RENAME) { + if self.parse_keyword(Keyword::TO) { let role_name = self.parse_identifier(false)?; AlterRoleOperation::RenameRole { role_name } } else { return self.expected("TO after RENAME", self.peek_token()); } // SET - } else if self.parse_keyword(Keyword::SET).is_some() { + } else if self.parse_keyword(Keyword::SET) { let config_name = self.parse_object_name(false)?; // FROM CURRENT if self.parse_keywords(&[Keyword::FROM, Keyword::CURRENT]) { @@ -90,8 +90,8 @@ impl<'a> Parser<'a> { in_database, } // { TO | = } { value | DEFAULT } - } else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO).is_some() { - if self.parse_keyword(Keyword::DEFAULT).is_some() { + } else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) { + if self.parse_keyword(Keyword::DEFAULT) { AlterRoleOperation::Set { config_name, config_value: SetConfigValue::Default, @@ -110,8 +110,8 @@ impl<'a> Parser<'a> { self.expected("'TO' or '=' or 'FROM CURRENT'", self.peek_token())? } // RESET - } else if self.parse_keyword(Keyword::RESET).is_some() { - if self.parse_keyword(Keyword::ALL).is_some() { + } else if self.parse_keyword(Keyword::RESET) { + if self.parse_keyword(Keyword::ALL) { AlterRoleOperation::Reset { config_name: ResetConfig::ALL, in_database, @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { // option } else { // [ WITH ] - let _ = self.parse_keyword(Keyword::WITH).is_some(); + let _ = self.parse_keyword(Keyword::WITH); // option let mut options = vec![]; while let Some(opt) = self.maybe_parse(|parser| parser.parse_pg_role_option()) { @@ -181,7 +181,7 @@ impl<'a> Parser<'a> { Some(Keyword::LOGIN) => RoleOption::Login(true), Some(Keyword::NOLOGIN) => RoleOption::Login(false), Some(Keyword::PASSWORD) => { - let password = if self.parse_keyword(Keyword::NULL).is_some() { + let password = if self.parse_keyword(Keyword::NULL) { Password::NullPassword } else { Password::Password(Expr::Value(self.parse_value()?)) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index da716a326..e9ecfa5c0 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -566,9 +566,9 @@ impl<'a> Parser<'a> { return parser_err!("Unsupported statement FLUSH", self.peek_token().span.start); } - let location = if self.parse_keyword(Keyword::NO_WRITE_TO_BINLOG).is_some() { + let location = if self.parse_keyword(Keyword::NO_WRITE_TO_BINLOG) { Some(FlushLocation::NoWriteToBinlog) - } else if self.parse_keyword(Keyword::LOCAL).is_some() { + } else if self.parse_keyword(Keyword::LOCAL) { Some(FlushLocation::Local) } else { None @@ -584,9 +584,9 @@ impl<'a> Parser<'a> { FlushType::GeneralLogs } else if self.parse_keywords(&[Keyword::HOSTS]) { FlushType::Hosts - } else if self.parse_keyword(Keyword::PRIVILEGES).is_some() { + } else if self.parse_keyword(Keyword::PRIVILEGES) { FlushType::Privileges - } else if self.parse_keyword(Keyword::OPTIMIZER_COSTS).is_some() { + } else if self.parse_keyword(Keyword::OPTIMIZER_COSTS) { FlushType::OptimizerCosts } else if self.parse_keywords(&[Keyword::RELAY, Keyword::LOGS]) { if self.parse_keywords(&[Keyword::FOR, Keyword::CHANNEL]) { @@ -595,9 +595,9 @@ impl<'a> Parser<'a> { FlushType::RelayLogs } else if self.parse_keywords(&[Keyword::SLOW, Keyword::LOGS]) { FlushType::SlowLogs - } else if self.parse_keyword(Keyword::STATUS).is_some() { + } else if self.parse_keyword(Keyword::STATUS) { FlushType::Status - } else if self.parse_keyword(Keyword::USER_RESOURCES).is_some() { + } else if self.parse_keyword(Keyword::USER_RESOURCES) { FlushType::UserResources } else if self.parse_keywords(&[Keyword::LOGS]) { FlushType::Logs @@ -610,7 +610,7 @@ impl<'a> Parser<'a> { read_lock = self.parse_keywords(&[Keyword::READ, Keyword::LOCK]); } Keyword::FOR => { - export = self.parse_keyword(Keyword::EXPORT).is_some(); + export = self.parse_keyword(Keyword::EXPORT); } Keyword::NoKeyword => { self.prev_token(); @@ -644,7 +644,7 @@ impl<'a> Parser<'a> { } pub fn parse_msck(&mut self) -> Result { - let repair = self.parse_keyword(Keyword::REPAIR).is_some(); + let repair = self.parse_keyword(Keyword::REPAIR); self.expect_keyword(Keyword::TABLE)?; let table_name = self.parse_object_name(false)?; let partition_action = self @@ -671,8 +671,8 @@ impl<'a> Parser<'a> { } pub fn parse_truncate(&mut self) -> Result { - let table = self.parse_keyword(Keyword::TABLE).is_some(); - let only = self.parse_keyword(Keyword::ONLY).is_some(); + let table = self.parse_keyword(Keyword::TABLE); + let only = self.parse_keyword(Keyword::ONLY); let table_names = self .parse_comma_separated(|p| p.parse_object_name(false))? @@ -681,7 +681,7 @@ impl<'a> Parser<'a> { .collect(); let mut partitions = None; - if self.parse_keyword(Keyword::PARTITION).is_some() { + if self.parse_keyword(Keyword::PARTITION) { self.expect_token(&Token::LParen)?; partitions = Some(self.parse_comma_separated(Parser::parse_expr)?); self.expect_token(&Token::RParen)?; @@ -699,9 +699,9 @@ impl<'a> Parser<'a> { None }; - cascade = if self.parse_keyword(Keyword::CASCADE).is_some() { + cascade = if self.parse_keyword(Keyword::CASCADE) { Some(TruncateCascadeOption::Cascade) - } else if self.parse_keyword(Keyword::RESTRICT).is_some() { + } else if self.parse_keyword(Keyword::RESTRICT) { Some(TruncateCascadeOption::Restrict) } else { None @@ -727,16 +727,16 @@ impl<'a> Parser<'a> { let mut options = vec![]; loop { - if self.parse_keyword(Keyword::READ_ONLY).is_some() { - let boolean = if self.parse_keyword(Keyword::TRUE).is_some() { + if self.parse_keyword(Keyword::READ_ONLY) { + let boolean = if self.parse_keyword(Keyword::TRUE) { Some(true) - } else if self.parse_keyword(Keyword::FALSE).is_some() { + } else if self.parse_keyword(Keyword::FALSE) { Some(false) } else { None }; options.push(AttachDuckDBDatabaseOption::ReadOnly(boolean)); - } else if self.parse_keyword(Keyword::TYPE).is_some() { + } else if self.parse_keyword(Keyword::TYPE) { let ident = self.parse_identifier(false)?; options.push(AttachDuckDBDatabaseOption::Type(ident)); } else { @@ -754,10 +754,10 @@ impl<'a> Parser<'a> { } pub fn parse_attach_duckdb_database(&mut self) -> Result { - let database = self.parse_keyword(Keyword::DATABASE).is_some(); + let database = self.parse_keyword(Keyword::DATABASE); let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let database_path = self.parse_identifier(false)?; - let database_alias = if self.parse_keyword(Keyword::AS).is_some() { + let database_alias = if self.parse_keyword(Keyword::AS) { Some(self.parse_identifier(false)?) } else { None @@ -774,7 +774,7 @@ impl<'a> Parser<'a> { } pub fn parse_detach_duckdb_database(&mut self) -> Result { - let database = self.parse_keyword(Keyword::DATABASE).is_some(); + let database = self.parse_keyword(Keyword::DATABASE); let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let database_alias = self.parse_identifier(false)?; Ok(Statement::DetachDuckDBDatabase { @@ -785,7 +785,7 @@ impl<'a> Parser<'a> { } pub fn parse_attach_database(&mut self) -> Result { - let database = self.parse_keyword(Keyword::DATABASE).is_some(); + let database = self.parse_keyword(Keyword::DATABASE); let database_file_name = self.parse_expr()?; self.expect_keyword(Keyword::AS)?; let schema_name = self.parse_identifier(false)?; @@ -924,7 +924,7 @@ impl<'a> Parser<'a> { pub fn parse_assert(&mut self) -> Result { let condition = self.parse_expr()?; - let message = if self.parse_keyword(Keyword::AS).is_some() { + let message = if self.parse_keyword(Keyword::AS) { Some(self.parse_expr()?) } else { None @@ -939,7 +939,7 @@ impl<'a> Parser<'a> { } pub fn parse_release(&mut self) -> Result { - let _ = self.parse_keyword(Keyword::SAVEPOINT).is_some(); + let _ = self.parse_keyword(Keyword::SAVEPOINT); let name = self.parse_identifier(false)?; Ok(Statement::ReleaseSavepoint { name }) @@ -1267,7 +1267,7 @@ impl<'a> Parser<'a> { _ => self.expected("an expression:", next_token), }?; - if self.parse_keyword(Keyword::COLLATE).is_some() { + if self.parse_keyword(Keyword::COLLATE) { Ok(Expr::Collate { expr: Box::new(expr), collation: self.parse_object_name(false)?, @@ -1351,9 +1351,9 @@ impl<'a> Parser<'a> { }; let filter = if self.dialect.supports_filter_during_aggregation() - && self.parse_keyword(Keyword::FILTER).is_some() + && self.parse_keyword(Keyword::FILTER) && self.consume_token(&Token::LParen) - && self.parse_keyword(Keyword::WHERE).is_some() + && self.parse_keyword(Keyword::WHERE) { let filter = Some(Box::new(self.parse_expr()?)); self.expect_token(&Token::RParen)?; @@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> { None }; - let over = if self.parse_keyword(Keyword::OVER).is_some() { + let over = if self.parse_keyword(Keyword::OVER) { if self.consume_token(&Token::LParen) { let window_spec = self.parse_window_spec()?; Some(WindowType::WindowSpec(window_spec)) @@ -1444,7 +1444,7 @@ impl<'a> Parser<'a> { pub fn parse_window_frame(&mut self) -> Result { let units = self.parse_window_frame_units()?; - let (start_bound, end_bound) = if self.parse_keyword(Keyword::BETWEEN).is_some() { + let (start_bound, end_bound) = if self.parse_keyword(Keyword::BETWEEN) { let start_bound = self.parse_window_frame_bound()?; self.expect_keyword(Keyword::AND)?; let end_bound = Some(self.parse_window_frame_bound()?); @@ -1464,7 +1464,7 @@ impl<'a> Parser<'a> { if self.parse_keywords(&[Keyword::CURRENT, Keyword::ROW]) { Ok(WindowFrameBound::CurrentRow) } else { - let rows = if self.parse_keyword(Keyword::UNBOUNDED).is_some() { + let rows = if self.parse_keyword(Keyword::UNBOUNDED) { None } else { Some(Box::new(match self.peek_token().token { @@ -1472,9 +1472,9 @@ impl<'a> Parser<'a> { _ => self.parse_expr()?, })) }; - if self.parse_keyword(Keyword::PRECEDING).is_some() { + if self.parse_keyword(Keyword::PRECEDING) { Ok(WindowFrameBound::Preceding(rows)) - } else if self.parse_keyword(Keyword::FOLLOWING).is_some() { + } else if self.parse_keyword(Keyword::FOLLOWING) { Ok(WindowFrameBound::Following(rows)) } else { self.expected("PRECEDING or FOLLOWING", self.peek_token()) @@ -1490,12 +1490,12 @@ impl<'a> Parser<'a> { let result = self.parse_comma_separated(|p| p.parse_tuple(false, true))?; self.expect_token(&Token::RParen)?; Ok(Expr::GroupingSets(result)) - } else if self.parse_keyword(Keyword::CUBE).is_some() { + } else if self.parse_keyword(Keyword::CUBE) { self.expect_token(&Token::LParen)?; let result = self.parse_comma_separated(|p| p.parse_tuple(true, true))?; self.expect_token(&Token::RParen)?; Ok(Expr::Cube(result)) - } else if self.parse_keyword(Keyword::ROLLUP).is_some() { + } else if self.parse_keyword(Keyword::ROLLUP) { self.expect_token(&Token::LParen)?; let result = self.parse_comma_separated(|p| p.parse_tuple(true, true))?; self.expect_token(&Token::RParen)?; @@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> { pub fn parse_case_expr(&mut self) -> Result { let mut operand = None; - if self.parse_keyword(Keyword::WHEN).is_none() { + if !self.parse_keyword(Keyword::WHEN) { operand = Some(Box::new(self.parse_expr()?)); self.expect_keyword(Keyword::WHEN)?; } @@ -1560,11 +1560,11 @@ impl<'a> Parser<'a> { conditions.push(self.parse_expr()?); self.expect_keyword(Keyword::THEN)?; results.push(self.parse_expr()?); - if self.parse_keyword(Keyword::WHEN).is_none() { + if !self.parse_keyword(Keyword::WHEN) { break; } } - let else_result = if self.parse_keyword(Keyword::ELSE).is_some() { + let else_result = if self.parse_keyword(Keyword::ELSE) { Some(Box::new(self.parse_expr()?)) } else { None @@ -1579,7 +1579,7 @@ impl<'a> Parser<'a> { } pub fn parse_optional_cast_format(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::FORMAT).is_some() { + if self.parse_keyword(Keyword::FORMAT) { let value = self.parse_value()?; match self.parse_optional_time_zone()? { Some(tz) => Ok(Some(CastFormat::ValueAtTimeZone(value, tz))), @@ -1629,7 +1629,7 @@ impl<'a> Parser<'a> { } self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; - if self.parse_keyword(Keyword::USING).is_some() { + if self.parse_keyword(Keyword::USING) { let charset = self.parse_object_name(false)?; self.expect_token(&Token::RParen)?; return Ok(Expr::Convert { @@ -1688,7 +1688,7 @@ impl<'a> Parser<'a> { self.expect_token(&Token::LParen)?; let field = self.parse_date_time_field()?; - let syntax = if self.parse_keyword(Keyword::FROM).is_some() { + let syntax = if self.parse_keyword(Keyword::FROM) { ExtractSyntax::From } else if self.consume_token(&Token::Comma) && dialect_of!(self is SnowflakeDialect | GenericDialect) @@ -1713,7 +1713,7 @@ impl<'a> Parser<'a> { self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; // Parse `CEIL/FLOOR(expr)` - let field = if self.parse_keyword(Keyword::TO).is_some() { + let field = if self.parse_keyword(Keyword::TO) { // Parse `CEIL/FLOOR(expr TO DateTimeField)` CeilFloorKind::DateTimeField(self.parse_date_time_field()?) } else if self.consume_token(&Token::Comma) { @@ -1773,12 +1773,12 @@ impl<'a> Parser<'a> { let expr = self.parse_expr()?; let mut from_expr = None; let special = self.consume_token(&Token::Comma); - if special || self.parse_keyword(Keyword::FROM).is_some() { + if special || self.parse_keyword(Keyword::FROM) { from_expr = Some(self.parse_expr()?); } let mut to_expr = None; - if self.parse_keyword(Keyword::FOR).is_some() || self.consume_token(&Token::Comma) { + if self.parse_keyword(Keyword::FOR) || self.consume_token(&Token::Comma) { to_expr = Some(self.parse_expr()?); } self.expect_token(&Token::RParen)?; @@ -1800,7 +1800,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::FROM)?; let from_expr = self.parse_expr()?; let mut for_expr = None; - if self.parse_keyword(Keyword::FOR).is_some() { + if self.parse_keyword(Keyword::FOR) { for_expr = Some(self.parse_expr()?); } self.expect_token(&Token::RParen)?; @@ -1830,7 +1830,7 @@ impl<'a> Parser<'a> { } } let expr = self.parse_expr()?; - if self.parse_keyword(Keyword::FROM).is_some() { + if self.parse_keyword(Keyword::FROM) { let trim_what = Box::new(expr); let expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -1885,7 +1885,7 @@ impl<'a> Parser<'a> { pub fn parse_listagg_on_overflow(&mut self) -> Result, ParserError> { if self.parse_keywords(&[Keyword::ON, Keyword::OVERFLOW]) { - if self.parse_keyword(Keyword::ERROR).is_some() { + if self.parse_keyword(Keyword::ERROR) { Ok(Some(ListAggOnOverflow::Error)) } else { self.expect_keyword(Keyword::TRUNCATE)?; @@ -1905,8 +1905,8 @@ impl<'a> Parser<'a> { self.peek_token(), )?, }; - let with_count = self.parse_keyword(Keyword::WITH).is_some(); - if !with_count && self.parse_keyword(Keyword::WITHOUT).is_none() { + let with_count = self.parse_keyword(Keyword::WITH); + if !with_count && !self.parse_keyword(Keyword::WITHOUT) { self.expected("either WITH or WITHOUT in LISTAGG", self.peek_token())?; } self.expect_keyword(Keyword::COUNT)?; @@ -1992,7 +1992,7 @@ impl<'a> Parser<'a> { Token::Word(w) => match w.keyword { Keyword::EXISTS => { let negated = true; - let _ = self.parse_keyword(Keyword::EXISTS).is_some(); + let _ = self.parse_keyword(Keyword::EXISTS); self.parse_exists_expr(negated) } _ => Ok(Expr::UnaryOp { @@ -2119,7 +2119,7 @@ impl<'a> Parser<'a> { (leading_precision, last_field, fsec_precision) } else { let leading_precision = self.parse_optional_precision()?; - if self.parse_keyword(Keyword::TO).is_some() { + if self.parse_keyword(Keyword::TO) { let last_field = Some(self.parse_date_time_field()?); let fsec_precision = if last_field == Some(DateTimeField::Second) { self.parse_optional_precision()? @@ -2221,7 +2221,7 @@ impl<'a> Parser<'a> { /// [3]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#typeless_struct_syntax fn parse_struct_field_expr(&mut self, typed_syntax: bool) -> Result { let expr = self.parse_expr()?; - if self.parse_keyword(Keyword::AS).is_some() { + if self.parse_keyword(Keyword::AS) { if typed_syntax { return parser_err!("Typed syntax does not allow AS", { self.prev_token(); @@ -2663,7 +2663,7 @@ impl<'a> Parser<'a> { } else if let Token::Word(w) = &tok.token { match w.keyword { Keyword::IS => { - if self.parse_keyword(Keyword::NULL).is_some() { + if self.parse_keyword(Keyword::NULL) { Ok(Expr::IsNull(Box::new(expr))) } else if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) { Ok(Expr::IsNotNull(Box::new(expr))) @@ -2709,9 +2709,9 @@ impl<'a> Parser<'a> { | Keyword::REGEXP | Keyword::RLIKE => { self.prev_token(); - let negated = self.parse_keyword(Keyword::NOT).is_some(); - let regexp = self.parse_keyword(Keyword::REGEXP).is_some(); - let rlike = self.parse_keyword(Keyword::RLIKE).is_some(); + let negated = self.parse_keyword(Keyword::NOT); + let regexp = self.parse_keyword(Keyword::REGEXP); + let rlike = self.parse_keyword(Keyword::RLIKE); if regexp || rlike { Ok(Expr::RLike { negated, @@ -2721,11 +2721,11 @@ impl<'a> Parser<'a> { ), regexp, }) - } else if self.parse_keyword(Keyword::IN).is_some() { + } else if self.parse_keyword(Keyword::IN) { self.parse_in(expr, negated) - } else if self.parse_keyword(Keyword::BETWEEN).is_some() { + } else if self.parse_keyword(Keyword::BETWEEN) { self.parse_between(expr, negated) - } else if self.parse_keyword(Keyword::LIKE).is_some() { + } else if self.parse_keyword(Keyword::LIKE) { Ok(Expr::Like { negated, expr: Box::new(expr), @@ -2734,7 +2734,7 @@ impl<'a> Parser<'a> { ), escape_char: self.parse_escape_char()?, }) - } else if self.parse_keyword(Keyword::ILIKE).is_some() { + } else if self.parse_keyword(Keyword::ILIKE) { Ok(Expr::ILike { negated, expr: Box::new(expr), @@ -2798,7 +2798,7 @@ impl<'a> Parser<'a> { /// Parse the `ESCAPE CHAR` portion of `LIKE`, `ILIKE`, and `SIMILAR TO` pub fn parse_escape_char(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::ESCAPE).is_some() { + if self.parse_keyword(Keyword::ESCAPE) { Ok(Some(self.parse_literal_string()?)) } else { Ok(None) @@ -2987,7 +2987,7 @@ impl<'a> Parser<'a> { pub fn parse_in(&mut self, expr: Expr, negated: bool) -> Result { // BigQuery allows `IN UNNEST(array_expression)` // https://cloud.google.com/bigquery/docs/reference/standard-sql/operators#in_operators - if self.parse_keyword(Keyword::UNNEST).is_some() { + if self.parse_keyword(Keyword::UNNEST) { self.expect_token(&Token::LParen)?; let array_expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -2998,9 +2998,7 @@ impl<'a> Parser<'a> { }); } self.expect_token(&Token::LParen)?; - let in_op = if self.parse_keyword(Keyword::SELECT).is_some() - || self.parse_keyword(Keyword::WITH).is_some() - { + let in_op = if self.parse_keyword(Keyword::SELECT) || self.parse_keyword(Keyword::WITH) { self.prev_token(); Expr::InSubquery { expr: Box::new(expr), @@ -3203,7 +3201,12 @@ impl<'a> Parser<'a> { /// If the current token is the `expected` keyword, consume it and returns /// true. Otherwise, no tokens are consumed and returns false. #[must_use] - pub fn parse_keyword(&mut self, expected: Keyword) -> Option { + pub fn parse_keyword(&mut self, expected: Keyword) -> bool { + self.parse_keyword_token(expected).is_some() + } + + #[must_use] + pub fn parse_keyword_token(&mut self, expected: Keyword) -> Option { match self.peek_token().token { Token::Word(w) if expected == w.keyword => Some(self.next_token()), _ => None, @@ -3250,7 +3253,7 @@ impl<'a> Parser<'a> { pub fn parse_keywords(&mut self, keywords: &[Keyword]) -> bool { let index = self.index; for &keyword in keywords { - if self.parse_keyword(keyword).is_none() { + if !self.parse_keyword(keyword) { // println!("parse_keywords aborting .. did not find {:?}", keyword); // reset index and return immediately self.index = index; @@ -3296,7 +3299,7 @@ impl<'a> Parser<'a> { /// If the current token is the `expected` keyword, consume the token. /// Otherwise, return an error. pub fn expect_keyword(&mut self, expected: Keyword) -> Result { - if let Some(token) = self.parse_keyword(expected) { + if let Some(token) = self.parse_keyword_token(expected) { Ok(token) } else { self.expected(format!("{:?}", &expected).as_str(), self.peek_token()) @@ -3450,7 +3453,7 @@ impl<'a> Parser<'a> { let mut values = vec![]; loop { values.push(f(self)?); - if self.parse_keyword(keyword).is_none() { + if !self.parse_keyword(keyword) { break; } } @@ -3508,15 +3511,15 @@ impl<'a> Parser<'a> { /// and results in a [`ParserError`] if both `ALL` and `DISTINCT` are found. pub fn parse_all_or_distinct(&mut self) -> Result, ParserError> { let loc = self.peek_token().span.start; - let all = self.parse_keyword(Keyword::ALL).is_some(); - let distinct = self.parse_keyword(Keyword::DISTINCT).is_some(); + let all = self.parse_keyword(Keyword::ALL); + let distinct = self.parse_keyword(Keyword::DISTINCT); if !distinct { return Ok(None); } if all { return parser_err!("Cannot specify both ALL and DISTINCT".to_string(), loc); } - let on = self.parse_keyword(Keyword::ON).is_some(); + let on = self.parse_keyword(Keyword::ON); if !on { return Ok(Some(Distinct::Distinct)); } @@ -3551,49 +3554,47 @@ impl<'a> Parser<'a> { .is_some(); let persistent = dialect_of!(self is DuckDbDialect) && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some(); - if self.parse_keyword(Keyword::TABLE).is_some() { + if self.parse_keyword(Keyword::TABLE) { self.parse_create_table(or_replace, temporary, global, transient) - } else if self.parse_keyword(Keyword::MATERIALIZED).is_some() - || self.parse_keyword(Keyword::VIEW).is_some() - { + } else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) { self.prev_token(); self.parse_create_view(or_replace, temporary) - } else if self.parse_keyword(Keyword::EXTERNAL).is_some() { + } else if self.parse_keyword(Keyword::EXTERNAL) { self.parse_create_external_table(or_replace) - } else if self.parse_keyword(Keyword::FUNCTION).is_some() { + } else if self.parse_keyword(Keyword::FUNCTION) { self.parse_create_function(or_replace, temporary) - } else if self.parse_keyword(Keyword::TRIGGER).is_some() { + } else if self.parse_keyword(Keyword::TRIGGER) { self.parse_create_trigger(or_replace, false) } else if self.parse_keywords(&[Keyword::CONSTRAINT, Keyword::TRIGGER]) { self.parse_create_trigger(or_replace, true) - } else if self.parse_keyword(Keyword::MACRO).is_some() { + } else if self.parse_keyword(Keyword::MACRO) { self.parse_create_macro(or_replace, temporary) - } else if self.parse_keyword(Keyword::SECRET).is_some() { + } else if self.parse_keyword(Keyword::SECRET) { self.parse_create_secret(or_replace, temporary, persistent) } else if or_replace { self.expected( "[EXTERNAL] TABLE or [MATERIALIZED] VIEW or FUNCTION after CREATE OR REPLACE", self.peek_token(), ) - } else if self.parse_keyword(Keyword::EXTENSION).is_some() { + } else if self.parse_keyword(Keyword::EXTENSION) { self.parse_create_extension() - } else if self.parse_keyword(Keyword::INDEX).is_some() { + } else if self.parse_keyword(Keyword::INDEX) { self.parse_create_index(false) } else if self.parse_keywords(&[Keyword::UNIQUE, Keyword::INDEX]) { self.parse_create_index(true) - } else if self.parse_keyword(Keyword::VIRTUAL).is_some() { + } else if self.parse_keyword(Keyword::VIRTUAL) { self.parse_create_virtual_table() - } else if self.parse_keyword(Keyword::SCHEMA).is_some() { + } else if self.parse_keyword(Keyword::SCHEMA) { self.parse_create_schema() - } else if self.parse_keyword(Keyword::DATABASE).is_some() { + } else if self.parse_keyword(Keyword::DATABASE) { self.parse_create_database() - } else if self.parse_keyword(Keyword::ROLE).is_some() { + } else if self.parse_keyword(Keyword::ROLE) { self.parse_create_role() - } else if self.parse_keyword(Keyword::SEQUENCE).is_some() { + } else if self.parse_keyword(Keyword::SEQUENCE) { self.parse_create_sequence(temporary) - } else if self.parse_keyword(Keyword::TYPE).is_some() { + } else if self.parse_keyword(Keyword::TYPE) { self.parse_create_type() - } else if self.parse_keyword(Keyword::PROCEDURE).is_some() { + } else if self.parse_keyword(Keyword::PROCEDURE) { self.parse_create_procedure(or_alter) } else { self.expected("an object type after CREATE", self.peek_token()) @@ -3612,7 +3613,7 @@ impl<'a> Parser<'a> { let mut storage_specifier = None; let mut name = None; if self.peek_token() != Token::LParen { - if self.parse_keyword(Keyword::IN).is_some() { + if self.parse_keyword(Keyword::IN) { storage_specifier = self.parse_identifier(false).ok() } else { name = self.parse_identifier(false).ok(); @@ -3621,7 +3622,7 @@ impl<'a> Parser<'a> { // Storage specifier may follow the name if storage_specifier.is_none() && self.peek_token() != Token::LParen - && self.parse_keyword(Keyword::IN).is_some() + && self.parse_keyword(Keyword::IN) { storage_specifier = self.parse_identifier(false).ok(); } @@ -3662,7 +3663,7 @@ impl<'a> Parser<'a> { /// Parse a CACHE TABLE statement pub fn parse_cache_table(&mut self) -> Result { let (mut table_flag, mut options, mut has_as, mut query) = (None, vec![], false, None); - if self.parse_keyword(Keyword::TABLE).is_some() { + if self.parse_keyword(Keyword::TABLE) { let table_name = self.parse_object_name(false)?; if self.peek_token().token != Token::EOF { if let Token::Word(word) = self.peek_token().token { @@ -3695,7 +3696,7 @@ impl<'a> Parser<'a> { } } else { table_flag = Some(self.parse_object_name(false)?); - if self.parse_keyword(Keyword::TABLE).is_some() { + if self.parse_keyword(Keyword::TABLE) { let table_name = self.parse_object_name(false)?; if self.peek_token() != Token::EOF { if let Token::Word(word) = self.peek_token().token { @@ -3792,14 +3793,14 @@ impl<'a> Parser<'a> { } fn parse_schema_name(&mut self) -> Result { - if self.parse_keyword(Keyword::AUTHORIZATION).is_some() { + if self.parse_keyword(Keyword::AUTHORIZATION) { Ok(SchemaName::UnnamedAuthorization( self.parse_identifier(false)?, )) } else { let name = self.parse_object_name(false)?; - if self.parse_keyword(Keyword::AUTHORIZATION).is_some() { + if self.parse_keyword(Keyword::AUTHORIZATION) { Ok(SchemaName::NamedAuthorization( name, self.parse_identifier(false)?, @@ -3835,7 +3836,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_create_function_using( &mut self, ) -> Result, ParserError> { - if self.parse_keyword(Keyword::USING).is_none() { + if !self.parse_keyword(Keyword::USING) { return Ok(None); }; let keyword = @@ -3892,7 +3893,7 @@ impl<'a> Parser<'a> { self.expect_token(&Token::RParen)?; - let return_type = if self.parse_keyword(Keyword::RETURNS).is_some() { + let return_type = if self.parse_keyword(Keyword::RETURNS) { Some(self.parse_data_type()?) } else { None @@ -3916,21 +3917,21 @@ impl<'a> Parser<'a> { } Ok(()) } - if self.parse_keyword(Keyword::AS).is_some() { + if self.parse_keyword(Keyword::AS) { ensure_not_set(&body.function_body, "AS")?; body.function_body = Some(CreateFunctionBody::AsBeforeOptions( self.parse_create_function_body_string()?, )); - } else if self.parse_keyword(Keyword::LANGUAGE).is_some() { + } else if self.parse_keyword(Keyword::LANGUAGE) { ensure_not_set(&body.language, "LANGUAGE")?; body.language = Some(self.parse_identifier(false)?); - } else if self.parse_keyword(Keyword::IMMUTABLE).is_some() { + } else if self.parse_keyword(Keyword::IMMUTABLE) { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Immutable); - } else if self.parse_keyword(Keyword::STABLE).is_some() { + } else if self.parse_keyword(Keyword::STABLE) { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Stable); - } else if self.parse_keyword(Keyword::VOLATILE).is_some() { + } else if self.parse_keyword(Keyword::VOLATILE) { ensure_not_set(&body.behavior, "IMMUTABLE | STABLE | VOLATILE")?; body.behavior = Some(FunctionBehavior::Volatile); } else if self.parse_keywords(&[ @@ -3956,24 +3957,24 @@ impl<'a> Parser<'a> { "CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT", )?; body.called_on_null = Some(FunctionCalledOnNull::ReturnsNullOnNullInput); - } else if self.parse_keyword(Keyword::STRICT).is_some() { + } else if self.parse_keyword(Keyword::STRICT) { ensure_not_set( &body.called_on_null, "CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT", )?; body.called_on_null = Some(FunctionCalledOnNull::Strict); - } else if self.parse_keyword(Keyword::PARALLEL).is_some() { + } else if self.parse_keyword(Keyword::PARALLEL) { ensure_not_set(&body.parallel, "PARALLEL { UNSAFE | RESTRICTED | SAFE }")?; - if self.parse_keyword(Keyword::UNSAFE).is_some() { + if self.parse_keyword(Keyword::UNSAFE) { body.parallel = Some(FunctionParallel::Unsafe); - } else if self.parse_keyword(Keyword::RESTRICTED).is_some() { + } else if self.parse_keyword(Keyword::RESTRICTED) { body.parallel = Some(FunctionParallel::Restricted); - } else if self.parse_keyword(Keyword::SAFE).is_some() { + } else if self.parse_keyword(Keyword::SAFE) { body.parallel = Some(FunctionParallel::Safe); } else { return self.expected("one of UNSAFE | RESTRICTED | SAFE", self.peek_token()); } - } else if self.parse_keyword(Keyword::RETURN).is_some() { + } else if self.parse_keyword(Keyword::RETURN) { ensure_not_set(&body.function_body, "RETURN")?; body.function_body = Some(CreateFunctionBody::Return(self.parse_expr()?)); } else { @@ -4059,13 +4060,13 @@ impl<'a> Parser<'a> { let args = self.parse_comma_separated0(parse_function_param, Token::RParen)?; self.expect_token(&Token::RParen)?; - let return_type = if self.parse_keyword(Keyword::RETURNS).is_some() { + let return_type = if self.parse_keyword(Keyword::RETURNS) { Some(self.parse_data_type()?) } else { None }; - let determinism_specifier = if self.parse_keyword(Keyword::DETERMINISTIC).is_some() { + let determinism_specifier = if self.parse_keyword(Keyword::DETERMINISTIC) { Some(FunctionDeterminismSpecifier::Deterministic) } else if self.parse_keywords(&[Keyword::NOT, Keyword::DETERMINISTIC]) { Some(FunctionDeterminismSpecifier::NotDeterministic) @@ -4073,7 +4074,7 @@ impl<'a> Parser<'a> { None }; - let language = if self.parse_keyword(Keyword::LANGUAGE).is_some() { + let language = if self.parse_keyword(Keyword::LANGUAGE) { Some(self.parse_identifier(false)?) } else { None @@ -4123,11 +4124,11 @@ impl<'a> Parser<'a> { } fn parse_function_arg(&mut self) -> Result { - let mode = if self.parse_keyword(Keyword::IN).is_some() { + let mode = if self.parse_keyword(Keyword::IN) { Some(ArgMode::In) - } else if self.parse_keyword(Keyword::OUT).is_some() { + } else if self.parse_keyword(Keyword::OUT) { Some(ArgMode::Out) - } else if self.parse_keyword(Keyword::INOUT).is_some() { + } else if self.parse_keyword(Keyword::INOUT) { Some(ArgMode::InOut) } else { None @@ -4142,12 +4143,12 @@ impl<'a> Parser<'a> { data_type = self.parse_data_type()?; } - let default_expr = - if self.parse_keyword(Keyword::DEFAULT).is_some() || self.consume_token(&Token::Eq) { - Some(self.parse_expr()?) - } else { - None - }; + let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq) + { + Some(self.parse_expr()?) + } else { + None + }; Ok(OperateFunctionArg { mode, name, @@ -4202,7 +4203,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::ON)?; let table_name = self.parse_object_name(false)?; - let referenced_table_name = if self.parse_keyword(Keyword::FROM).is_some() { + let referenced_table_name = if self.parse_keyword(Keyword::FROM) { self.parse_object_name(true).ok() } else { None @@ -4211,14 +4212,14 @@ impl<'a> Parser<'a> { let characteristics = self.parse_constraint_characteristics()?; let mut referencing = vec![]; - if self.parse_keyword(Keyword::REFERENCING).is_some() { + if self.parse_keyword(Keyword::REFERENCING) { while let Some(refer) = self.parse_trigger_referencing()? { referencing.push(refer); } } self.expect_keyword(Keyword::FOR)?; - let include_each = self.parse_keyword(Keyword::EACH).is_some(); + let include_each = self.parse_keyword(Keyword::EACH); let trigger_object = match self.expect_one_of_keywords(&[Keyword::ROW, Keyword::STATEMENT])? { Keyword::ROW => TriggerObject::Row, @@ -4228,7 +4229,6 @@ impl<'a> Parser<'a> { let condition = self .parse_keyword(Keyword::WHEN) - .is_some() .then(|| self.parse_expr()) .transpose()?; @@ -4280,7 +4280,7 @@ impl<'a> Parser<'a> { ])? { Keyword::INSERT => TriggerEvent::Insert, Keyword::UPDATE => { - if self.parse_keyword(Keyword::OF).is_some() { + if self.parse_keyword(Keyword::OF) { let cols = self.parse_comma_separated(|ident| { Parser::parse_identifier(ident, false) })?; @@ -4298,10 +4298,10 @@ impl<'a> Parser<'a> { pub fn parse_trigger_referencing(&mut self) -> Result, ParserError> { let refer_type = match self.parse_one_of_keywords(&[Keyword::OLD, Keyword::NEW]) { - Some(Keyword::OLD) if self.parse_keyword(Keyword::TABLE).is_some() => { + Some(Keyword::OLD) if self.parse_keyword(Keyword::TABLE) => { TriggerReferencingType::OldTable } - Some(Keyword::NEW) if self.parse_keyword(Keyword::TABLE).is_some() => { + Some(Keyword::NEW) if self.parse_keyword(Keyword::TABLE) => { TriggerReferencingType::NewTable } _ => { @@ -4309,7 +4309,7 @@ impl<'a> Parser<'a> { } }; - let is_as = self.parse_keyword(Keyword::AS).is_some(); + let is_as = self.parse_keyword(Keyword::AS); let transition_relation_name = self.parse_object_name(false)?; Ok(Some(TriggerReferencing { refer_type, @@ -4354,7 +4354,7 @@ impl<'a> Parser<'a> { temporary, name, args, - definition: if self.parse_keyword(Keyword::TABLE).is_some() { + definition: if self.parse_keyword(Keyword::TABLE) { MacroDefinition::Table(self.parse_query()?) } else { MacroDefinition::Expr(self.parse_expr()?) @@ -4449,7 +4449,7 @@ impl<'a> Parser<'a> { or_replace: bool, temporary: bool, ) -> Result { - let materialized = self.parse_keyword(Keyword::MATERIALIZED).is_some(); + let materialized = self.parse_keyword(Keyword::MATERIALIZED); self.expect_keyword(Keyword::VIEW)?; let if_not_exists = dialect_of!(self is BigQueryDialect|SQLiteDialect|GenericDialect) && self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); @@ -4464,7 +4464,7 @@ impl<'a> Parser<'a> { options = CreateTableOptions::With(with_options); } - let cluster_by = if self.parse_keyword(Keyword::CLUSTER).is_some() { + let cluster_by = if self.parse_keyword(Keyword::CLUSTER) { self.expect_keyword(Keyword::BY)?; self.parse_parenthesized_column_list(Optional, false)? } else { @@ -4480,7 +4480,7 @@ impl<'a> Parser<'a> { } let to = if dialect_of!(self is ClickHouseDialect | GenericDialect) - && self.parse_keyword(Keyword::TO).is_some() + && self.parse_keyword(Keyword::TO) { Some(self.parse_object_name(false)?) } else { @@ -4488,7 +4488,7 @@ impl<'a> Parser<'a> { }; let comment = if dialect_of!(self is SnowflakeDialect | GenericDialect) - && self.parse_keyword(Keyword::COMMENT).is_some() + && self.parse_keyword(Keyword::COMMENT) { self.expect_token(&Token::Eq)?; let next_token = self.next_token(); @@ -4532,7 +4532,7 @@ impl<'a> Parser<'a> { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let names = self.parse_comma_separated(|p| p.parse_object_name(false))?; - let _ = self.parse_keyword(Keyword::WITH).is_some(); // [ WITH ] + let _ = self.parse_keyword(Keyword::WITH); // [ WITH ] let optional_keywords = if dialect_of!(self is MsSqlDialect) { vec![Keyword::AUTHORIZATION] @@ -4657,7 +4657,7 @@ impl<'a> Parser<'a> { if password.is_some() { parser_err!("Found multiple PASSWORD", loc) } else { - password = if self.parse_keyword(Keyword::NULL).is_some() { + password = if self.parse_keyword(Keyword::NULL) { Some(Password::NullPassword) } else { Some(Password::Password(Expr::Value(self.parse_value()?))) @@ -4684,14 +4684,14 @@ impl<'a> Parser<'a> { } } Keyword::IN => { - if self.parse_keyword(Keyword::ROLE).is_some() { + if self.parse_keyword(Keyword::ROLE) { if !in_role.is_empty() { parser_err!("Found multiple IN ROLE", loc) } else { in_role = self.parse_comma_separated(|p| p.parse_identifier(false))?; Ok(()) } - } else if self.parse_keyword(Keyword::GROUP).is_some() { + } else if self.parse_keyword(Keyword::GROUP) { if !in_group.is_empty() { parser_err!("Found multiple IN GROUP", loc) } else { @@ -4755,31 +4755,31 @@ impl<'a> Parser<'a> { pub fn parse_drop(&mut self) -> Result { // MySQL dialect supports `TEMPORARY` let temporary = dialect_of!(self is MySqlDialect | GenericDialect | DuckDbDialect) - && self.parse_keyword(Keyword::TEMPORARY).is_some(); + && self.parse_keyword(Keyword::TEMPORARY); let persistent = dialect_of!(self is DuckDbDialect) && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some(); - let object_type = if self.parse_keyword(Keyword::TABLE).is_some() { + let object_type = if self.parse_keyword(Keyword::TABLE) { ObjectType::Table - } else if self.parse_keyword(Keyword::VIEW).is_some() { + } else if self.parse_keyword(Keyword::VIEW) { ObjectType::View - } else if self.parse_keyword(Keyword::INDEX).is_some() { + } else if self.parse_keyword(Keyword::INDEX) { ObjectType::Index - } else if self.parse_keyword(Keyword::ROLE).is_some() { + } else if self.parse_keyword(Keyword::ROLE) { ObjectType::Role - } else if self.parse_keyword(Keyword::SCHEMA).is_some() { + } else if self.parse_keyword(Keyword::SCHEMA) { ObjectType::Schema - } else if self.parse_keyword(Keyword::SEQUENCE).is_some() { + } else if self.parse_keyword(Keyword::SEQUENCE) { ObjectType::Sequence - } else if self.parse_keyword(Keyword::STAGE).is_some() { + } else if self.parse_keyword(Keyword::STAGE) { ObjectType::Stage - } else if self.parse_keyword(Keyword::FUNCTION).is_some() { + } else if self.parse_keyword(Keyword::FUNCTION) { return self.parse_drop_function(); - } else if self.parse_keyword(Keyword::PROCEDURE).is_some() { + } else if self.parse_keyword(Keyword::PROCEDURE) { return self.parse_drop_procedure(); - } else if self.parse_keyword(Keyword::SECRET).is_some() { + } else if self.parse_keyword(Keyword::SECRET) { return self.parse_drop_secret(temporary, persistent); - } else if self.parse_keyword(Keyword::TRIGGER).is_some() { + } else if self.parse_keyword(Keyword::TRIGGER) { return self.parse_drop_trigger(); } else { return self.expected( @@ -4793,9 +4793,9 @@ impl<'a> Parser<'a> { let names = self.parse_comma_separated(|p| p.parse_object_name(false))?; let loc = self.peek_token().span.start; - let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); - let restrict = self.parse_keyword(Keyword::RESTRICT).is_some(); - let purge = self.parse_keyword(Keyword::PURGE).is_some(); + let cascade = self.parse_keyword(Keyword::CASCADE); + let restrict = self.parse_keyword(Keyword::RESTRICT); + let purge = self.parse_keyword(Keyword::PURGE); if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in DROP", loc); } @@ -4881,7 +4881,7 @@ impl<'a> Parser<'a> { ) -> Result { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let name = self.parse_identifier(false)?; - let storage_specifier = if self.parse_keyword(Keyword::FROM).is_some() { + let storage_specifier = if self.parse_keyword(Keyword::FROM) { self.parse_identifier(false).ok() } else { None @@ -4923,15 +4923,15 @@ impl<'a> Parser<'a> { let name = self.parse_identifier(false)?; - let binary = Some(self.parse_keyword(Keyword::BINARY).is_some()); - let sensitive = if self.parse_keyword(Keyword::INSENSITIVE).is_some() { + let binary = Some(self.parse_keyword(Keyword::BINARY)); + let sensitive = if self.parse_keyword(Keyword::INSENSITIVE) { Some(true) - } else if self.parse_keyword(Keyword::ASENSITIVE).is_some() { + } else if self.parse_keyword(Keyword::ASENSITIVE) { Some(false) } else { None }; - let scroll = if self.parse_keyword(Keyword::SCROLL).is_some() { + let scroll = if self.parse_keyword(Keyword::SCROLL) { Some(true) } else if self.parse_keywords(&[Keyword::NO, Keyword::SCROLL]) { Some(false) @@ -4990,7 +4990,7 @@ impl<'a> Parser<'a> { }; let expr = if data_type.is_some() { - if self.parse_keyword(Keyword::DEFAULT).is_some() { + if self.parse_keyword(Keyword::DEFAULT) { Some(self.parse_expr()?) } else { None @@ -5046,7 +5046,7 @@ impl<'a> Parser<'a> { loop { let name = self.parse_identifier(false)?; let (declare_type, for_query, assigned_expr, data_type) = - if self.parse_keyword(Keyword::CURSOR).is_some() { + if self.parse_keyword(Keyword::CURSOR) { self.expect_keyword(Keyword::FOR)?; match self.peek_token().token { Token::Word(w) if w.keyword == Keyword::SELECT => ( @@ -5062,7 +5062,7 @@ impl<'a> Parser<'a> { None, ), } - } else if self.parse_keyword(Keyword::RESULTSET).is_some() { + } else if self.parse_keyword(Keyword::RESULTSET) { let assigned_expr = if self.peek_token().token != Token::SemiColon { self.parse_snowflake_variable_declaration_expression()? } else { @@ -5071,7 +5071,7 @@ impl<'a> Parser<'a> { }; (Some(DeclareType::ResultSet), None, assigned_expr, None) - } else if self.parse_keyword(Keyword::EXCEPTION).is_some() { + } else if self.parse_keyword(Keyword::EXCEPTION) { let assigned_expr = if self.peek_token().token == Token::LParen { Some(DeclareAssignment::Expr(Box::new(self.parse_expr()?))) } else { @@ -5243,24 +5243,24 @@ impl<'a> Parser<'a> { // FETCH [ direction { FROM | IN } ] cursor INTO target; pub fn parse_fetch_statement(&mut self) -> Result { - let direction = if self.parse_keyword(Keyword::NEXT).is_some() { + let direction = if self.parse_keyword(Keyword::NEXT) { FetchDirection::Next - } else if self.parse_keyword(Keyword::PRIOR).is_some() { + } else if self.parse_keyword(Keyword::PRIOR) { FetchDirection::Prior - } else if self.parse_keyword(Keyword::FIRST).is_some() { + } else if self.parse_keyword(Keyword::FIRST) { FetchDirection::First - } else if self.parse_keyword(Keyword::LAST).is_some() { + } else if self.parse_keyword(Keyword::LAST) { FetchDirection::Last - } else if self.parse_keyword(Keyword::ABSOLUTE).is_some() { + } else if self.parse_keyword(Keyword::ABSOLUTE) { FetchDirection::Absolute { limit: self.parse_number_value()?, } - } else if self.parse_keyword(Keyword::RELATIVE).is_some() { + } else if self.parse_keyword(Keyword::RELATIVE) { FetchDirection::Relative { limit: self.parse_number_value()?, } - } else if self.parse_keyword(Keyword::FORWARD).is_some() { - if self.parse_keyword(Keyword::ALL).is_some() { + } else if self.parse_keyword(Keyword::FORWARD) { + if self.parse_keyword(Keyword::ALL) { FetchDirection::ForwardAll } else { FetchDirection::Forward { @@ -5268,8 +5268,8 @@ impl<'a> Parser<'a> { limit: Some(self.parse_number_value()?), } } - } else if self.parse_keyword(Keyword::BACKWARD).is_some() { - if self.parse_keyword(Keyword::ALL).is_some() { + } else if self.parse_keyword(Keyword::BACKWARD) { + if self.parse_keyword(Keyword::ALL) { FetchDirection::BackwardAll } else { FetchDirection::Backward { @@ -5277,7 +5277,7 @@ impl<'a> Parser<'a> { limit: Some(self.parse_number_value()?), } } - } else if self.parse_keyword(Keyword::ALL).is_some() { + } else if self.parse_keyword(Keyword::ALL) { FetchDirection::All } else { FetchDirection::Count { @@ -5289,7 +5289,7 @@ impl<'a> Parser<'a> { let name = self.parse_identifier(false)?; - let into = if self.parse_keyword(Keyword::INTO).is_some() { + let into = if self.parse_keyword(Keyword::INTO) { Some(self.parse_object_name(false)?) } else { None @@ -5303,15 +5303,13 @@ impl<'a> Parser<'a> { } pub fn parse_discard(&mut self) -> Result { - let object_type = if self.parse_keyword(Keyword::ALL).is_some() { + let object_type = if self.parse_keyword(Keyword::ALL) { DiscardObject::ALL - } else if self.parse_keyword(Keyword::PLANS).is_some() { + } else if self.parse_keyword(Keyword::PLANS) { DiscardObject::PLANS - } else if self.parse_keyword(Keyword::SEQUENCES).is_some() { + } else if self.parse_keyword(Keyword::SEQUENCES) { DiscardObject::SEQUENCES - } else if self.parse_keyword(Keyword::TEMP).is_some() - || self.parse_keyword(Keyword::TEMPORARY).is_some() - { + } else if self.parse_keyword(Keyword::TEMP) || self.parse_keyword(Keyword::TEMPORARY) { DiscardObject::TEMP } else { return self.expected( @@ -5323,9 +5321,9 @@ impl<'a> Parser<'a> { } pub fn parse_create_index(&mut self, unique: bool) -> Result { - let concurrently = self.parse_keyword(Keyword::CONCURRENTLY).is_some(); + let concurrently = self.parse_keyword(Keyword::CONCURRENTLY); let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); - let index_name = if if_not_exists || self.parse_keyword(Keyword::ON).is_none() { + let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) { let index_name = self.parse_object_name(false)?; self.expect_keyword(Keyword::ON)?; Some(index_name) @@ -5333,7 +5331,7 @@ impl<'a> Parser<'a> { None }; let table_name = self.parse_object_name(false)?; - let using = if self.parse_keyword(Keyword::USING).is_some() { + let using = if self.parse_keyword(Keyword::USING) { Some(self.parse_identifier(false)?) } else { None @@ -5342,7 +5340,7 @@ impl<'a> Parser<'a> { let columns = self.parse_comma_separated(Parser::parse_order_by_expr)?; self.expect_token(&Token::RParen)?; - let include = if self.parse_keyword(Keyword::INCLUDE).is_some() { + let include = if self.parse_keyword(Keyword::INCLUDE) { self.expect_token(&Token::LParen)?; let columns = self.parse_comma_separated(|p| p.parse_identifier(false))?; self.expect_token(&Token::RParen)?; @@ -5351,8 +5349,8 @@ impl<'a> Parser<'a> { vec![] }; - let nulls_distinct = if self.parse_keyword(Keyword::NULLS).is_some() { - let not = self.parse_keyword(Keyword::NOT).is_some(); + let nulls_distinct = if self.parse_keyword(Keyword::NULLS) { + let not = self.parse_keyword(Keyword::NOT); self.expect_keyword(Keyword::DISTINCT)?; Some(!not) } else { @@ -5360,7 +5358,7 @@ impl<'a> Parser<'a> { }; let with = if self.dialect.supports_create_index_with_clause() - && self.parse_keyword(Keyword::WITH).is_some() + && self.parse_keyword(Keyword::WITH) { self.expect_token(&Token::LParen)?; let with_params = self.parse_comma_separated(Parser::parse_expr)?; @@ -5370,7 +5368,7 @@ impl<'a> Parser<'a> { Vec::new() }; - let predicate = if self.parse_keyword(Keyword::WHERE).is_some() { + let predicate = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { None @@ -5395,20 +5393,20 @@ impl<'a> Parser<'a> { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let name = self.parse_identifier(false)?; - let (schema, version, cascade) = if self.parse_keyword(Keyword::WITH).is_some() { - let schema = if self.parse_keyword(Keyword::SCHEMA).is_some() { + let (schema, version, cascade) = if self.parse_keyword(Keyword::WITH) { + let schema = if self.parse_keyword(Keyword::SCHEMA) { Some(self.parse_identifier(false)?) } else { None }; - let version = if self.parse_keyword(Keyword::VERSION).is_some() { + let version = if self.parse_keyword(Keyword::VERSION) { Some(self.parse_identifier(false)?) } else { None }; - let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); + let cascade = self.parse_keyword(Keyword::CASCADE); (schema, version, cascade) } else { @@ -5450,7 +5448,7 @@ impl<'a> Parser<'a> { } Some(Keyword::STORED) => { self.expect_keyword(Keyword::AS)?; - if self.parse_keyword(Keyword::INPUTFORMAT).is_some() { + if self.parse_keyword(Keyword::INPUTFORMAT) { let input_format = self.parse_expr()?; self.expect_keyword(Keyword::OUTPUTFORMAT)?; let output_format = self.parse_expr()?; @@ -5602,15 +5600,13 @@ impl<'a> Parser<'a> { // Clickhouse has `ON CLUSTER 'cluster'` syntax for DDLs let on_cluster = self.parse_optional_on_cluster()?; - let like = if self.parse_keyword(Keyword::LIKE).is_some() - || self.parse_keyword(Keyword::ILIKE).is_some() - { + let like = if self.parse_keyword(Keyword::LIKE) || self.parse_keyword(Keyword::ILIKE) { self.parse_object_name(allow_unquoted_hyphen).ok() } else { None }; - let clone = if self.parse_keyword(Keyword::CLONE).is_some() { + let clone = if self.parse_keyword(Keyword::CLONE) { self.parse_object_name(allow_unquoted_hyphen).ok() } else { None @@ -5619,7 +5615,7 @@ impl<'a> Parser<'a> { // parse optional column list (schema) let (columns, constraints) = self.parse_columns()?; let mut comment = if dialect_of!(self is HiveDialect) - && self.parse_keyword(Keyword::COMMENT).is_some() + && self.parse_keyword(Keyword::COMMENT) { let next_token = self.next_token(); match next_token.token { @@ -5640,7 +5636,7 @@ impl<'a> Parser<'a> { let with_options = self.parse_options(Keyword::WITH)?; let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?; - let engine = if self.parse_keyword(Keyword::ENGINE).is_some() { + let engine = if self.parse_keyword(Keyword::ENGINE) { self.expect_token(&Token::Eq)?; let next_token = self.next_token(); match next_token.token { @@ -5659,7 +5655,7 @@ impl<'a> Parser<'a> { None }; - let auto_increment_offset = if self.parse_keyword(Keyword::AUTO_INCREMENT).is_some() { + let auto_increment_offset = if self.parse_keyword(Keyword::AUTO_INCREMENT) { let _ = self.consume_token(&Token::Eq); let next_token = self.next_token(); match next_token.token { @@ -5737,10 +5733,10 @@ impl<'a> Parser<'a> { None }; - let strict = self.parse_keyword(Keyword::STRICT).is_some(); + let strict = self.parse_keyword(Keyword::STRICT); // Excludes Hive dialect here since it has been handled after table column definitions. - if !dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::COMMENT).is_some() { + if !dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::COMMENT) { let _ = self.consume_token(&Token::Eq); let next_token = self.next_token(); comment = match next_token.token { @@ -5750,7 +5746,7 @@ impl<'a> Parser<'a> { }; // Parse optional `AS ( query )` - let query = if self.parse_keyword(Keyword::AS).is_some() { + let query = if self.parse_keyword(Keyword::AS) { Some(self.parse_boxed_query()?) } else { None @@ -5894,14 +5890,14 @@ impl<'a> Parser<'a> { } else { self.parse_data_type()? }; - let mut collation = if self.parse_keyword(Keyword::COLLATE).is_some() { + let mut collation = if self.parse_keyword(Keyword::COLLATE) { Some(self.parse_object_name(false)?) } else { None }; let mut options = vec![]; loop { - if self.parse_keyword(Keyword::CONSTRAINT).is_some() { + if self.parse_keyword(Keyword::CONSTRAINT) { let name = Some(self.parse_identifier(false)?); if let Some(option) = self.parse_optional_column_option()? { options.push(ColumnOptionDef { name, option }); @@ -5914,7 +5910,7 @@ impl<'a> Parser<'a> { } else if let Some(option) = self.parse_optional_column_option()? { options.push(ColumnOptionDef { name: None, option }); } else if dialect_of!(self is MySqlDialect | GenericDialect) - && self.parse_keyword(Keyword::COLLATE).is_some() + && self.parse_keyword(Keyword::COLLATE) { collation = Some(self.parse_object_name(false)?); } else { @@ -5965,20 +5961,20 @@ impl<'a> Parser<'a> { Token::SingleQuotedString(value, ..) => Ok(Some(ColumnOption::Comment(value))), _ => self.expected("string", next_token), } - } else if self.parse_keyword(Keyword::NULL).is_some() { + } else if self.parse_keyword(Keyword::NULL) { Ok(Some(ColumnOption::Null)) - } else if self.parse_keyword(Keyword::DEFAULT).is_some() { + } else if self.parse_keyword(Keyword::DEFAULT) { Ok(Some(ColumnOption::Default(self.parse_expr()?))) } else if dialect_of!(self is ClickHouseDialect| GenericDialect) - && self.parse_keyword(Keyword::MATERIALIZED).is_some() + && self.parse_keyword(Keyword::MATERIALIZED) { Ok(Some(ColumnOption::Materialized(self.parse_expr()?))) } else if dialect_of!(self is ClickHouseDialect| GenericDialect) - && self.parse_keyword(Keyword::ALIAS).is_some() + && self.parse_keyword(Keyword::ALIAS) { Ok(Some(ColumnOption::Alias(self.parse_expr()?))) } else if dialect_of!(self is ClickHouseDialect| GenericDialect) - && self.parse_keyword(Keyword::EPHEMERAL).is_some() + && self.parse_keyword(Keyword::EPHEMERAL) { // The expression is optional for the EPHEMERAL syntax, so we need to check // if the column definition has remaining tokens before parsing the expression. @@ -5993,13 +5989,13 @@ impl<'a> Parser<'a> { is_primary: true, characteristics, })) - } else if self.parse_keyword(Keyword::UNIQUE).is_some() { + } else if self.parse_keyword(Keyword::UNIQUE) { let characteristics = self.parse_constraint_characteristics()?; Ok(Some(ColumnOption::Unique { is_primary: false, characteristics, })) - } else if self.parse_keyword(Keyword::REFERENCES).is_some() { + } else if self.parse_keyword(Keyword::REFERENCES) { let foreign_table = self.parse_object_name(false)?; // PostgreSQL allows omitting the column list and // uses the primary key column of the foreign table by default @@ -6026,19 +6022,19 @@ impl<'a> Parser<'a> { on_update, characteristics, })) - } else if self.parse_keyword(Keyword::CHECK).is_some() { + } else if self.parse_keyword(Keyword::CHECK) { self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; self.expect_token(&Token::RParen)?; Ok(Some(ColumnOption::Check(expr))) - } else if self.parse_keyword(Keyword::AUTO_INCREMENT).is_some() + } else if self.parse_keyword(Keyword::AUTO_INCREMENT) && dialect_of!(self is MySqlDialect | GenericDialect) { // Support AUTO_INCREMENT for MySQL Ok(Some(ColumnOption::DialectSpecific(vec![ Token::make_keyword("AUTO_INCREMENT"), ]))) - } else if self.parse_keyword(Keyword::AUTOINCREMENT).is_some() + } else if self.parse_keyword(Keyword::AUTOINCREMENT) && dialect_of!(self is SQLiteDialect | GenericDialect) { // Support AUTOINCREMENT for SQLite @@ -6050,16 +6046,16 @@ impl<'a> Parser<'a> { { let expr = self.parse_expr()?; Ok(Some(ColumnOption::OnUpdate(expr))) - } else if self.parse_keyword(Keyword::GENERATED).is_some() { + } else if self.parse_keyword(Keyword::GENERATED) { self.parse_optional_column_option_generated() } else if dialect_of!(self is BigQueryDialect | GenericDialect) - && self.parse_keyword(Keyword::OPTIONS).is_some() + && self.parse_keyword(Keyword::OPTIONS) { self.prev_token(); Ok(Some(ColumnOption::Options( self.parse_options(Keyword::OPTIONS)?, ))) - } else if self.parse_keyword(Keyword::AS).is_some() + } else if self.parse_keyword(Keyword::AS) && dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect) { self.parse_optional_column_option_as() @@ -6190,9 +6186,9 @@ impl<'a> Parser<'a> { } pub fn parse_referential_action(&mut self) -> Result { - if self.parse_keyword(Keyword::RESTRICT).is_some() { + if self.parse_keyword(Keyword::RESTRICT) { Ok(ReferentialAction::Restrict) - } else if self.parse_keyword(Keyword::CASCADE).is_some() { + } else if self.parse_keyword(Keyword::CASCADE) { Ok(ReferentialAction::Cascade) } else if self.parse_keywords(&[Keyword::SET, Keyword::NULL]) { Ok(ReferentialAction::SetNull) @@ -6217,17 +6213,17 @@ impl<'a> Parser<'a> { if cc.deferrable.is_none() && self.parse_keywords(&[Keyword::NOT, Keyword::DEFERRABLE]) { cc.deferrable = Some(false); - } else if cc.deferrable.is_none() && self.parse_keyword(Keyword::DEFERRABLE).is_some() { + } else if cc.deferrable.is_none() && self.parse_keyword(Keyword::DEFERRABLE) { cc.deferrable = Some(true); - } else if cc.initially.is_none() && self.parse_keyword(Keyword::INITIALLY).is_some() { - if self.parse_keyword(Keyword::DEFERRED).is_some() { + } else if cc.initially.is_none() && self.parse_keyword(Keyword::INITIALLY) { + if self.parse_keyword(Keyword::DEFERRED) { cc.initially = Some(DeferrableInitial::Deferred); - } else if self.parse_keyword(Keyword::IMMEDIATE).is_some() { + } else if self.parse_keyword(Keyword::IMMEDIATE) { cc.initially = Some(DeferrableInitial::Immediate); } else { self.expected("one of DEFERRED or IMMEDIATE", self.peek_token())?; } - } else if cc.enforced.is_none() && self.parse_keyword(Keyword::ENFORCED).is_some() { + } else if cc.enforced.is_none() && self.parse_keyword(Keyword::ENFORCED) { cc.enforced = Some(true); } else if cc.enforced.is_none() && self.parse_keywords(&[Keyword::NOT, Keyword::ENFORCED]) @@ -6248,7 +6244,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_table_constraint( &mut self, ) -> Result, ParserError> { - let name = if self.parse_keyword(Keyword::CONSTRAINT).is_some() { + let name = if self.parse_keyword(Keyword::CONSTRAINT) { Some(self.parse_identifier(false)?) } else { None @@ -6415,7 +6411,7 @@ impl<'a> Parser<'a> { } pub fn parse_options(&mut self, keyword: Keyword) -> Result, ParserError> { - if self.parse_keyword(keyword).is_some() { + if self.parse_keyword(keyword) { self.expect_token(&Token::LParen)?; let options = self.parse_comma_separated(Parser::parse_sql_option)?; self.expect_token(&Token::RParen)?; @@ -6440,9 +6436,9 @@ impl<'a> Parser<'a> { } pub fn parse_index_type(&mut self) -> Result { - if self.parse_keyword(Keyword::BTREE).is_some() { + if self.parse_keyword(Keyword::BTREE) { Ok(IndexType::BTree) - } else if self.parse_keyword(Keyword::HASH).is_some() { + } else if self.parse_keyword(Keyword::HASH) { Ok(IndexType::Hash) } else { self.expected("index type {BTREE | HASH}", self.peek_token()) @@ -6453,7 +6449,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_using_then_index_type( &mut self, ) -> Result, ParserError> { - if self.parse_keyword(Keyword::USING).is_some() { + if self.parse_keyword(Keyword::USING) { Ok(Some(self.parse_index_type()?)) } else { Ok(None) @@ -6468,9 +6464,9 @@ impl<'a> Parser<'a> { #[must_use] pub fn parse_index_type_display(&mut self) -> KeyOrIndexDisplay { - if self.parse_keyword(Keyword::KEY).is_some() { + if self.parse_keyword(Keyword::KEY) { KeyOrIndexDisplay::Key - } else if self.parse_keyword(Keyword::INDEX).is_some() { + } else if self.parse_keyword(Keyword::INDEX) { KeyOrIndexDisplay::Index } else { KeyOrIndexDisplay::None @@ -6480,7 +6476,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_index_option(&mut self) -> Result, ParserError> { if let Some(index_type) = self.parse_optional_using_then_index_type()? { Ok(Some(IndexOption::Using(index_type))) - } else if self.parse_keyword(Keyword::COMMENT).is_some() { + } else if self.parse_keyword(Keyword::COMMENT) { let s = self.parse_literal_string()?; Ok(Some(IndexOption::Comment(s))) } else { @@ -6564,9 +6560,9 @@ impl<'a> Parser<'a> { let column_name = self.parse_identifier(false)?; self.expect_keyword(Keyword::RANGE)?; - let range_direction = if self.parse_keyword(Keyword::LEFT).is_some() { + let range_direction = if self.parse_keyword(Keyword::LEFT) { Some(PartitionRangeDirection::Left) - } else if self.parse_keyword(Keyword::RIGHT).is_some() { + } else if self.parse_keyword(Keyword::RIGHT) { Some(PartitionRangeDirection::Right) } else { None @@ -6619,11 +6615,11 @@ impl<'a> Parser<'a> { } pub fn parse_alter_table_operation(&mut self) -> Result { - let operation = if self.parse_keyword(Keyword::ADD).is_some() { + let operation = if self.parse_keyword(Keyword::ADD) { if let Some(constraint) = self.parse_optional_table_constraint()? { AlterTableOperation::AddConstraint(constraint) } else if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::PROJECTION).is_some() + && self.parse_keyword(Keyword::PROJECTION) { return self.parse_alter_table_add_projection(); } else { @@ -6631,7 +6627,7 @@ impl<'a> Parser<'a> { self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let mut new_partitions = vec![]; loop { - if self.parse_keyword(Keyword::PARTITION).is_some() { + if self.parse_keyword(Keyword::PARTITION) { new_partitions.push(self.parse_partition()?); } else { break; @@ -6643,7 +6639,7 @@ impl<'a> Parser<'a> { new_partitions, } } else { - let column_keyword = self.parse_keyword(Keyword::COLUMN).is_some(); + let column_keyword = self.parse_keyword(Keyword::COLUMN); let if_not_exists = if dialect_of!(self is PostgreSqlDialect | BigQueryDialect | DuckDbDialect | GenericDialect) { @@ -6665,19 +6661,17 @@ impl<'a> Parser<'a> { } } } - } else if self.parse_keyword(Keyword::RENAME).is_some() { - if dialect_of!(self is PostgreSqlDialect) - && self.parse_keyword(Keyword::CONSTRAINT).is_some() - { + } else if self.parse_keyword(Keyword::RENAME) { + if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::CONSTRAINT) { let old_name = self.parse_identifier(false)?; self.expect_keyword(Keyword::TO)?; let new_name = self.parse_identifier(false)?; AlterTableOperation::RenameConstraint { old_name, new_name } - } else if self.parse_keyword(Keyword::TO).is_some() { + } else if self.parse_keyword(Keyword::TO) { let table_name = self.parse_object_name(false)?; AlterTableOperation::RenameTable { table_name } } else { - let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] + let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let old_column_name = self.parse_identifier(false)?; self.expect_keyword(Keyword::TO)?; let new_column_name = self.parse_identifier(false)?; @@ -6686,13 +6680,13 @@ impl<'a> Parser<'a> { new_column_name, } } - } else if self.parse_keyword(Keyword::DISABLE).is_some() { + } else if self.parse_keyword(Keyword::DISABLE) { if self.parse_keywords(&[Keyword::ROW, Keyword::LEVEL, Keyword::SECURITY]) { AlterTableOperation::DisableRowLevelSecurity {} - } else if self.parse_keyword(Keyword::RULE).is_some() { + } else if self.parse_keyword(Keyword::RULE) { let name = self.parse_identifier(false)?; AlterTableOperation::DisableRule { name } - } else if self.parse_keyword(Keyword::TRIGGER).is_some() { + } else if self.parse_keyword(Keyword::TRIGGER) { let name = self.parse_identifier(false)?; AlterTableOperation::DisableTrigger { name } } else { @@ -6701,7 +6695,7 @@ impl<'a> Parser<'a> { self.peek_token(), ); } - } else if self.parse_keyword(Keyword::ENABLE).is_some() { + } else if self.parse_keyword(Keyword::ENABLE) { if self.parse_keywords(&[Keyword::ALWAYS, Keyword::RULE]) { let name = self.parse_identifier(false)?; AlterTableOperation::EnableAlwaysRule { name } @@ -6716,10 +6710,10 @@ impl<'a> Parser<'a> { } else if self.parse_keywords(&[Keyword::REPLICA, Keyword::TRIGGER]) { let name = self.parse_identifier(false)?; AlterTableOperation::EnableReplicaTrigger { name } - } else if self.parse_keyword(Keyword::RULE).is_some() { + } else if self.parse_keyword(Keyword::RULE) { let name = self.parse_identifier(false)?; AlterTableOperation::EnableRule { name } - } else if self.parse_keyword(Keyword::TRIGGER).is_some() { + } else if self.parse_keyword(Keyword::TRIGGER) { let name = self.parse_identifier(false)?; AlterTableOperation::EnableTrigger { name } } else { @@ -6758,7 +6752,7 @@ impl<'a> Parser<'a> { name, partition, } - } else if self.parse_keyword(Keyword::DROP).is_some() { + } else if self.parse_keyword(Keyword::DROP) { if self.parse_keywords(&[Keyword::IF, Keyword::EXISTS, Keyword::PARTITION]) { self.expect_token(&Token::LParen)?; let partitions = self.parse_comma_separated(Parser::parse_expr)?; @@ -6767,7 +6761,7 @@ impl<'a> Parser<'a> { partitions, if_exists: true, } - } else if self.parse_keyword(Keyword::PARTITION).is_some() { + } else if self.parse_keyword(Keyword::PARTITION) { self.expect_token(&Token::LParen)?; let partitions = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -6775,10 +6769,10 @@ impl<'a> Parser<'a> { partitions, if_exists: false, } - } else if self.parse_keyword(Keyword::CONSTRAINT).is_some() { + } else if self.parse_keyword(Keyword::CONSTRAINT) { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let name = self.parse_identifier(false)?; - let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); + let cascade = self.parse_keyword(Keyword::CASCADE); AlterTableOperation::DropConstraint { if_exists, name, @@ -6788,24 +6782,24 @@ impl<'a> Parser<'a> { && dialect_of!(self is MySqlDialect | GenericDialect) { AlterTableOperation::DropPrimaryKey - } else if self.parse_keyword(Keyword::PROJECTION).is_some() + } else if self.parse_keyword(Keyword::PROJECTION) && dialect_of!(self is ClickHouseDialect|GenericDialect) { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let name = self.parse_identifier(false)?; AlterTableOperation::DropProjection { if_exists, name } } else { - let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] + let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let column_name = self.parse_identifier(false)?; - let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); + let cascade = self.parse_keyword(Keyword::CASCADE); AlterTableOperation::DropColumn { column_name, if_exists, cascade, } } - } else if self.parse_keyword(Keyword::PARTITION).is_some() { + } else if self.parse_keyword(Keyword::PARTITION) { self.expect_token(&Token::LParen)?; let before = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -6818,8 +6812,8 @@ impl<'a> Parser<'a> { old_partitions: before, new_partitions: renames, } - } else if self.parse_keyword(Keyword::CHANGE).is_some() { - let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] + } else if self.parse_keyword(Keyword::CHANGE) { + let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let old_name = self.parse_identifier(false)?; let new_name = self.parse_identifier(false)?; let data_type = self.parse_data_type()?; @@ -6837,8 +6831,8 @@ impl<'a> Parser<'a> { options, column_position, } - } else if self.parse_keyword(Keyword::MODIFY).is_some() { - let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] + } else if self.parse_keyword(Keyword::MODIFY) { + let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let col_name = self.parse_identifier(false)?; let data_type = self.parse_data_type()?; let mut options = vec![]; @@ -6854,8 +6848,8 @@ impl<'a> Parser<'a> { options, column_position, } - } else if self.parse_keyword(Keyword::ALTER).is_some() { - let _ = self.parse_keyword(Keyword::COLUMN).is_some(); // [ COLUMN ] + } else if self.parse_keyword(Keyword::ALTER) { + let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let column_name = self.parse_identifier(false)?; let is_postgresql = dialect_of!(self is PostgreSqlDialect); @@ -6874,17 +6868,17 @@ impl<'a> Parser<'a> { } else if self.parse_keywords(&[Keyword::DROP, Keyword::DEFAULT]) { AlterColumnOperation::DropDefault {} } else if self.parse_keywords(&[Keyword::SET, Keyword::DATA, Keyword::TYPE]) - || (is_postgresql && self.parse_keyword(Keyword::TYPE).is_some()) + || (is_postgresql && self.parse_keyword(Keyword::TYPE)) { let data_type = self.parse_data_type()?; - let using = if is_postgresql && self.parse_keyword(Keyword::USING).is_some() { + let using = if is_postgresql && self.parse_keyword(Keyword::USING) { Some(self.parse_expr()?) } else { None }; AlterColumnOperation::SetDataType { data_type, using } } else if self.parse_keywords(&[Keyword::ADD, Keyword::GENERATED]) { - let generated_as = if self.parse_keyword(Keyword::ALWAYS).is_some() { + let generated_as = if self.parse_keyword(Keyword::ALWAYS) { Some(GeneratedAs::Always) } else if self.parse_keywords(&[Keyword::BY, Keyword::DEFAULT]) { Some(GeneratedAs::ByDefault) @@ -6916,7 +6910,7 @@ impl<'a> Parser<'a> { return self.expected(message, self.peek_token()); }; AlterTableOperation::AlterColumn { column_name, op } - } else if self.parse_keyword(Keyword::SWAP).is_some() { + } else if self.parse_keyword(Keyword::SWAP) { self.expect_keyword(Keyword::WITH)?; let table_name = self.parse_object_name(false)?; AlterTableOperation::SwapWith { table_name } @@ -6940,22 +6934,22 @@ impl<'a> Parser<'a> { AlterTableOperation::OwnerTo { new_owner } } else if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::ATTACH).is_some() + && self.parse_keyword(Keyword::ATTACH) { AlterTableOperation::AttachPartition { partition: self.parse_part_or_partition()?, } } else if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::DETACH).is_some() + && self.parse_keyword(Keyword::DETACH) { AlterTableOperation::DetachPartition { partition: self.parse_part_or_partition()?, } } else if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::FREEZE).is_some() + && self.parse_keyword(Keyword::FREEZE) { let partition = self.parse_part_or_partition()?; - let with_name = if self.parse_keyword(Keyword::WITH).is_some() { + let with_name = if self.parse_keyword(Keyword::WITH) { self.expect_keyword(Keyword::NAME)?; Some(self.parse_identifier(false)?) } else { @@ -6966,10 +6960,10 @@ impl<'a> Parser<'a> { with_name, } } else if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::UNFREEZE).is_some() + && self.parse_keyword(Keyword::UNFREEZE) { let partition = self.parse_part_or_partition()?; - let with_name = if self.parse_keyword(Keyword::WITH).is_some() { + let with_name = if self.parse_keyword(Keyword::WITH) { self.expect_keyword(Keyword::NAME)?; Some(self.parse_identifier(false)?) } else { @@ -7017,13 +7011,13 @@ impl<'a> Parser<'a> { Keyword::VIEW => self.parse_alter_view(), Keyword::TABLE => { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); - let only = self.parse_keyword(Keyword::ONLY).is_some(); // [ ONLY ] + let only = self.parse_keyword(Keyword::ONLY); // [ ONLY ] let table_name = self.parse_object_name(false)?; let on_cluster = self.parse_optional_on_cluster()?; let operations = self.parse_comma_separated(Parser::parse_alter_table_operation)?; let mut location = None; - if self.parse_keyword(Keyword::LOCATION).is_some() { + if self.parse_keyword(Keyword::LOCATION) { location = Some(HiveSetLocation { has_set: false, location: self.parse_identifier(false)?, @@ -7046,8 +7040,8 @@ impl<'a> Parser<'a> { } Keyword::INDEX => { let index_name = self.parse_object_name(false)?; - let operation = if self.parse_keyword(Keyword::RENAME).is_some() { - if self.parse_keyword(Keyword::TO).is_some() { + let operation = if self.parse_keyword(Keyword::RENAME) { + if self.parse_keyword(Keyword::TO) { let index_name = self.parse_object_name(false)?; AlterIndexOperation::RenameIndex { index_name } } else { @@ -7138,11 +7132,11 @@ impl<'a> Parser<'a> { )); } } - let target = if self.parse_keyword(Keyword::STDIN).is_some() { + let target = if self.parse_keyword(Keyword::STDIN) { CopyTarget::Stdin - } else if self.parse_keyword(Keyword::STDOUT).is_some() { + } else if self.parse_keyword(Keyword::STDOUT) { CopyTarget::Stdout - } else if self.parse_keyword(Keyword::PROGRAM).is_some() { + } else if self.parse_keyword(Keyword::PROGRAM) { CopyTarget::Program { command: self.parse_literal_string()?, } @@ -7151,7 +7145,7 @@ impl<'a> Parser<'a> { filename: self.parse_literal_string()?, } }; - let _ = self.parse_keyword(Keyword::WITH).is_some(); // [ WITH ] + let _ = self.parse_keyword(Keyword::WITH); // [ WITH ] let mut options = vec![]; if self.consume_token(&Token::LParen) { options = self.parse_comma_separated(Parser::parse_copy_option)?; @@ -7178,7 +7172,7 @@ impl<'a> Parser<'a> { } pub fn parse_close(&mut self) -> Result { - let cursor = if self.parse_keyword(Keyword::ALL).is_some() { + let cursor = if self.parse_keyword(Keyword::ALL) { CloseCursor::All } else { let name = self.parse_identifier(false)?; @@ -7240,11 +7234,11 @@ impl<'a> Parser<'a> { ]) { Some(Keyword::BINARY) => CopyLegacyOption::Binary, Some(Keyword::DELIMITER) => { - let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] + let _ = self.parse_keyword(Keyword::AS); // [ AS ] CopyLegacyOption::Delimiter(self.parse_literal_char()?) } Some(Keyword::NULL) => { - let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] + let _ = self.parse_keyword(Keyword::AS); // [ AS ] CopyLegacyOption::Null(self.parse_literal_string()?) } Some(Keyword::CSV) => CopyLegacyOption::Csv({ @@ -7270,11 +7264,11 @@ impl<'a> Parser<'a> { ]) { Some(Keyword::HEADER) => CopyLegacyCsvOption::Header, Some(Keyword::QUOTE) => { - let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] + let _ = self.parse_keyword(Keyword::AS); // [ AS ] CopyLegacyCsvOption::Quote(self.parse_literal_char()?) } Some(Keyword::ESCAPE) => { - let _ = self.parse_keyword(Keyword::AS).is_some(); // [ AS ] + let _ = self.parse_keyword(Keyword::AS); // [ AS ] CopyLegacyCsvOption::Escape(self.parse_literal_char()?) } Some(Keyword::FORCE) if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) => { @@ -7555,7 +7549,7 @@ impl<'a> Parser<'a> { Keyword::FLOAT64 => Ok(DataType::Float64), Keyword::FLOAT8 => Ok(DataType::Float8), Keyword::DOUBLE => { - if self.parse_keyword(Keyword::PRECISION).is_some() { + if self.parse_keyword(Keyword::PRECISION) { Ok(DataType::DoublePrecision) } else { Ok(DataType::Double) @@ -7563,7 +7557,7 @@ impl<'a> Parser<'a> { } Keyword::TINYINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedTinyInt(optional_precision?)) } else { Ok(DataType::TinyInt(optional_precision?)) @@ -7571,7 +7565,7 @@ impl<'a> Parser<'a> { } Keyword::INT2 => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedInt2(optional_precision?)) } else { Ok(DataType::Int2(optional_precision?)) @@ -7579,7 +7573,7 @@ impl<'a> Parser<'a> { } Keyword::SMALLINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedSmallInt(optional_precision?)) } else { Ok(DataType::SmallInt(optional_precision?)) @@ -7587,7 +7581,7 @@ impl<'a> Parser<'a> { } Keyword::MEDIUMINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedMediumInt(optional_precision?)) } else { Ok(DataType::MediumInt(optional_precision?)) @@ -7595,7 +7589,7 @@ impl<'a> Parser<'a> { } Keyword::INT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedInt(optional_precision?)) } else { Ok(DataType::Int(optional_precision?)) @@ -7603,7 +7597,7 @@ impl<'a> Parser<'a> { } Keyword::INT4 => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedInt4(optional_precision?)) } else { Ok(DataType::Int4(optional_precision?)) @@ -7611,7 +7605,7 @@ impl<'a> Parser<'a> { } Keyword::INT8 => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedInt8(optional_precision?)) } else { Ok(DataType::Int8(optional_precision?)) @@ -7624,7 +7618,7 @@ impl<'a> Parser<'a> { Keyword::INT256 => Ok(DataType::Int256), Keyword::INTEGER => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedInteger(optional_precision?)) } else { Ok(DataType::Integer(optional_precision?)) @@ -7632,7 +7626,7 @@ impl<'a> Parser<'a> { } Keyword::BIGINT => { let optional_precision = self.parse_optional_precision(); - if self.parse_keyword(Keyword::UNSIGNED).is_some() { + if self.parse_keyword(Keyword::UNSIGNED) { Ok(DataType::UnsignedBigInt(optional_precision?)) } else { Ok(DataType::BigInt(optional_precision?)) @@ -7649,7 +7643,7 @@ impl<'a> Parser<'a> { Ok(DataType::Nvarchar(self.parse_optional_character_length()?)) } Keyword::CHARACTER => { - if self.parse_keyword(Keyword::VARYING).is_some() { + if self.parse_keyword(Keyword::VARYING) { Ok(DataType::CharacterVarying( self.parse_optional_character_length()?, )) @@ -7662,7 +7656,7 @@ impl<'a> Parser<'a> { } } Keyword::CHAR => { - if self.parse_keyword(Keyword::VARYING).is_some() { + if self.parse_keyword(Keyword::VARYING) { Ok(DataType::CharVarying( self.parse_optional_character_length()?, )) @@ -7688,10 +7682,10 @@ impl<'a> Parser<'a> { } Keyword::TIMESTAMP => { let precision = self.parse_optional_precision()?; - let tz = if self.parse_keyword(Keyword::WITH).is_some() { + let tz = if self.parse_keyword(Keyword::WITH) { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithTimeZone - } else if self.parse_keyword(Keyword::WITHOUT).is_some() { + } else if self.parse_keyword(Keyword::WITHOUT) { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithoutTimeZone } else { @@ -7705,10 +7699,10 @@ impl<'a> Parser<'a> { )), Keyword::TIME => { let precision = self.parse_optional_precision()?; - let tz = if self.parse_keyword(Keyword::WITH).is_some() { + let tz = if self.parse_keyword(Keyword::WITH) { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithTimeZone - } else if self.parse_keyword(Keyword::WITHOUT).is_some() { + } else if self.parse_keyword(Keyword::WITHOUT) { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; TimezoneInfo::WithoutTimeZone } else { @@ -7876,7 +7870,7 @@ impl<'a> Parser<'a> { &mut self, reserved_kwds: &[Keyword], ) -> Result, ParserError> { - let after_as = self.parse_keyword(Keyword::AS).is_some(); + let after_as = self.parse_keyword(Keyword::AS); let next_token = self.next_token(); match next_token.token { // Accept any identifier after `AS` (though many dialects have restrictions on @@ -7931,7 +7925,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_group_by(&mut self) -> Result, ParserError> { if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) { - let expressions = if self.parse_keyword(Keyword::ALL).is_some() { + let expressions = if self.parse_keyword(Keyword::ALL) { None } else { Some(self.parse_comma_separated(Parser::parse_group_by_expr)?) @@ -7940,7 +7934,7 @@ impl<'a> Parser<'a> { let mut modifiers = vec![]; if dialect_of!(self is ClickHouseDialect | GenericDialect) { loop { - if self.parse_keyword(Keyword::WITH).is_none() { + if !self.parse_keyword(Keyword::WITH) { break; } let keyword = self.expect_one_of_keywords(&[ @@ -8220,7 +8214,7 @@ impl<'a> Parser<'a> { fn parse_view_column(&mut self) -> Result { let name = self.parse_identifier(false)?; let options = if dialect_of!(self is BigQueryDialect | GenericDialect) - && self.parse_keyword(Keyword::OPTIONS).is_some() + && self.parse_keyword(Keyword::OPTIONS) { self.prev_token(); Some(self.parse_options(Keyword::OPTIONS)?) @@ -8311,13 +8305,13 @@ impl<'a> Parser<'a> { } pub fn parse_character_length(&mut self) -> Result { - if self.parse_keyword(Keyword::MAX).is_some() { + if self.parse_keyword(Keyword::MAX) { return Ok(CharacterLength::Max); } let length = self.parse_literal_uint()?; - let unit = if self.parse_keyword(Keyword::CHARACTERS).is_some() { + let unit = if self.parse_keyword(Keyword::CHARACTERS) { Some(CharLengthUnits::Characters) - } else if self.parse_keyword(Keyword::OCTETS).is_some() { + } else if self.parse_keyword(Keyword::OCTETS) { Some(CharLengthUnits::Octets) } else { None @@ -8402,7 +8396,7 @@ impl<'a> Parser<'a> { } pub fn parse_delete(&mut self) -> Result { - let (tables, with_from_keyword) = if self.parse_keyword(Keyword::FROM).is_none() { + let (tables, with_from_keyword) = if !self.parse_keyword(Keyword::FROM) { // `FROM` keyword is optional in BigQuery SQL. // https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#delete_statement if dialect_of!(self is BigQueryDialect | GenericDialect) { @@ -8417,17 +8411,17 @@ impl<'a> Parser<'a> { }; let from = self.parse_comma_separated(Parser::parse_table_and_joins)?; - let using = if self.parse_keyword(Keyword::USING).is_some() { + let using = if self.parse_keyword(Keyword::USING) { Some(self.parse_comma_separated(Parser::parse_table_and_joins)?) } else { None }; - let selection = if self.parse_keyword(Keyword::WHERE).is_some() { + let selection = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { None }; - let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { + let returning = if self.parse_keyword(Keyword::RETURNING) { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -8437,7 +8431,7 @@ impl<'a> Parser<'a> { } else { vec![] }; - let limit = if self.parse_keyword(Keyword::LIMIT).is_some() { + let limit = if self.parse_keyword(Keyword::LIMIT) { self.parse_limit()? } else { None @@ -8488,10 +8482,10 @@ impl<'a> Parser<'a> { &mut self, describe_alias: DescribeAlias, ) -> Result { - let analyze = self.parse_keyword(Keyword::ANALYZE).is_some(); - let verbose = self.parse_keyword(Keyword::VERBOSE).is_some(); + let analyze = self.parse_keyword(Keyword::ANALYZE); + let verbose = self.parse_keyword(Keyword::VERBOSE); let mut format = None; - if self.parse_keyword(Keyword::FORMAT).is_some() { + if self.parse_keyword(Keyword::FORMAT) { format = Some(self.parse_analyze_format()?); } @@ -8516,7 +8510,7 @@ impl<'a> Parser<'a> { let has_table_keyword = if self.dialect.describe_requires_table_keyword() { // only allow to use TABLE keyword for DESC|DESCRIBE statement - self.parse_keyword(Keyword::TABLE).is_some() + self.parse_keyword(Keyword::TABLE) } else { false }; @@ -8547,16 +8541,16 @@ impl<'a> Parser<'a> { /// expect the initial keyword to be already consumed pub fn parse_query(&mut self) -> Result { let _guard = self.recursion_counter.try_decrease()?; - let with = if let Some(with_token) = self.parse_keyword(Keyword::WITH) { + let with = if let Some(with_token) = self.parse_keyword_token(Keyword::WITH) { Some(With { with_token, - recursive: self.parse_keyword(Keyword::RECURSIVE).is_some(), + recursive: self.parse_keyword(Keyword::RECURSIVE), cte_tables: self.parse_comma_separated(Parser::parse_cte)?, }) } else { None }; - if self.parse_keyword(Keyword::INSERT).is_some() { + if self.parse_keyword(Keyword::INSERT) { Ok(Query { with, body: self.parse_insert_setexpr_boxed()?, @@ -8570,7 +8564,7 @@ impl<'a> Parser<'a> { settings: None, format_clause: None, }) - } else if self.parse_keyword(Keyword::UPDATE).is_some() { + } else if self.parse_keyword(Keyword::UPDATE) { Ok(Query { with, body: self.parse_update_setexpr_boxed()?, @@ -8593,11 +8587,11 @@ impl<'a> Parser<'a> { let mut offset = None; for _x in 0..2 { - if limit.is_none() && self.parse_keyword(Keyword::LIMIT).is_some() { + if limit.is_none() && self.parse_keyword(Keyword::LIMIT) { limit = self.parse_limit()? } - if offset.is_none() && self.parse_keyword(Keyword::OFFSET).is_some() { + if offset.is_none() && self.parse_keyword(Keyword::OFFSET) { offset = Some(self.parse_offset()?) } @@ -8617,7 +8611,7 @@ impl<'a> Parser<'a> { } let limit_by = if dialect_of!(self is ClickHouseDialect | GenericDialect) - && self.parse_keyword(Keyword::BY).is_some() + && self.parse_keyword(Keyword::BY) { self.parse_comma_separated(Parser::parse_expr)? } else { @@ -8626,7 +8620,7 @@ impl<'a> Parser<'a> { let settings = self.parse_settings()?; - let fetch = if self.parse_keyword(Keyword::FETCH).is_some() { + let fetch = if self.parse_keyword(Keyword::FETCH) { Some(self.parse_fetch()?) } else { None @@ -8634,7 +8628,7 @@ impl<'a> Parser<'a> { let mut for_clause = None; let mut locks = Vec::new(); - while self.parse_keyword(Keyword::FOR).is_some() { + while self.parse_keyword(Keyword::FOR) { if let Some(parsed_for_clause) = self.parse_for_clause()? { for_clause = Some(parsed_for_clause); break; @@ -8643,9 +8637,9 @@ impl<'a> Parser<'a> { } } let format_clause = if dialect_of!(self is ClickHouseDialect | GenericDialect) - && self.parse_keyword(Keyword::FORMAT).is_some() + && self.parse_keyword(Keyword::FORMAT) { - if self.parse_keyword(Keyword::NULL).is_some() { + if self.parse_keyword(Keyword::NULL) { Some(FormatClause::Null) } else { let ident = self.parse_identifier(false)?; @@ -8673,7 +8667,7 @@ impl<'a> Parser<'a> { fn parse_settings(&mut self) -> Result>, ParserError> { let settings = if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::SETTINGS).is_some() + && self.parse_keyword(Keyword::SETTINGS) { let key_values = self.parse_comma_separated(|p| { let key = p.parse_identifier(false)?; @@ -8690,11 +8684,11 @@ impl<'a> Parser<'a> { /// Parse a mssql `FOR [XML | JSON | BROWSE]` clause pub fn parse_for_clause(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::XML).is_some() { + if self.parse_keyword(Keyword::XML) { Ok(Some(self.parse_for_xml()?)) - } else if self.parse_keyword(Keyword::JSON).is_some() { + } else if self.parse_keyword(Keyword::JSON) { Ok(Some(self.parse_for_json()?)) - } else if self.parse_keyword(Keyword::BROWSE).is_some() { + } else if self.parse_keyword(Keyword::BROWSE) { Ok(Some(ForClause::Browse)) } else { Ok(None) @@ -8703,7 +8697,7 @@ impl<'a> Parser<'a> { /// Parse a mssql `FOR XML` clause pub fn parse_for_xml(&mut self) -> Result { - let for_xml = if self.parse_keyword(Keyword::RAW).is_some() { + let for_xml = if self.parse_keyword(Keyword::RAW) { let mut element_name = None; if self.peek_token().token == Token::LParen { self.expect_token(&Token::LParen)?; @@ -8711,11 +8705,11 @@ impl<'a> Parser<'a> { self.expect_token(&Token::RParen)?; } ForXml::Raw(element_name) - } else if self.parse_keyword(Keyword::AUTO).is_some() { + } else if self.parse_keyword(Keyword::AUTO) { ForXml::Auto - } else if self.parse_keyword(Keyword::EXPLICIT).is_some() { + } else if self.parse_keyword(Keyword::EXPLICIT) { ForXml::Explicit - } else if self.parse_keyword(Keyword::PATH).is_some() { + } else if self.parse_keyword(Keyword::PATH) { let mut element_name = None; if self.peek_token().token == Token::LParen { self.expect_token(&Token::LParen)?; @@ -8734,16 +8728,16 @@ impl<'a> Parser<'a> { let mut r#type = false; while self.peek_token().token == Token::Comma { self.next_token(); - if self.parse_keyword(Keyword::ELEMENTS).is_some() { + if self.parse_keyword(Keyword::ELEMENTS) { elements = true; - } else if self.parse_keyword(Keyword::BINARY).is_some() { + } else if self.parse_keyword(Keyword::BINARY) { self.expect_keyword(Keyword::BASE64)?; binary_base64 = true; - } else if self.parse_keyword(Keyword::ROOT).is_some() { + } else if self.parse_keyword(Keyword::ROOT) { self.expect_token(&Token::LParen)?; root = Some(self.parse_literal_string()?); self.expect_token(&Token::RParen)?; - } else if self.parse_keyword(Keyword::TYPE).is_some() { + } else if self.parse_keyword(Keyword::TYPE) { r#type = true; } } @@ -8758,9 +8752,9 @@ impl<'a> Parser<'a> { /// Parse a mssql `FOR JSON` clause pub fn parse_for_json(&mut self) -> Result { - let for_json = if self.parse_keyword(Keyword::AUTO).is_some() { + let for_json = if self.parse_keyword(Keyword::AUTO) { ForJson::Auto - } else if self.parse_keyword(Keyword::PATH).is_some() { + } else if self.parse_keyword(Keyword::PATH) { ForJson::Path } else { return Err(ParserError::ParserError( @@ -8772,13 +8766,13 @@ impl<'a> Parser<'a> { let mut without_array_wrapper = false; while self.peek_token().token == Token::Comma { self.next_token(); - if self.parse_keyword(Keyword::ROOT).is_some() { + if self.parse_keyword(Keyword::ROOT) { self.expect_token(&Token::LParen)?; root = Some(self.parse_literal_string()?); self.expect_token(&Token::RParen)?; - } else if self.parse_keyword(Keyword::INCLUDE_NULL_VALUES).is_some() { + } else if self.parse_keyword(Keyword::INCLUDE_NULL_VALUES) { include_null_values = true; - } else if self.parse_keyword(Keyword::WITHOUT_ARRAY_WRAPPER).is_some() { + } else if self.parse_keyword(Keyword::WITHOUT_ARRAY_WRAPPER) { without_array_wrapper = true; } } @@ -8794,10 +8788,10 @@ impl<'a> Parser<'a> { pub fn parse_cte(&mut self) -> Result { let name = self.parse_identifier(false)?; - let mut cte = if self.parse_keyword(Keyword::AS).is_some() { + let mut cte = if self.parse_keyword(Keyword::AS) { let mut is_materialized = None; if dialect_of!(self is PostgreSqlDialect) { - if self.parse_keyword(Keyword::MATERIALIZED).is_some() { + if self.parse_keyword(Keyword::MATERIALIZED) { is_materialized = Some(CteAsMaterialized::Materialized); } else if self.parse_keywords(&[Keyword::NOT, Keyword::MATERIALIZED]) { is_materialized = Some(CteAsMaterialized::NotMaterialized); @@ -8822,7 +8816,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::AS)?; let mut is_materialized = None; if dialect_of!(self is PostgreSqlDialect) { - if self.parse_keyword(Keyword::MATERIALIZED).is_some() { + if self.parse_keyword(Keyword::MATERIALIZED) { is_materialized = Some(CteAsMaterialized::Materialized); } else if self.parse_keywords(&[Keyword::NOT, Keyword::MATERIALIZED]) { is_materialized = Some(CteAsMaterialized::NotMaterialized); @@ -8840,7 +8834,7 @@ impl<'a> Parser<'a> { closing_paren_token, } }; - if self.parse_keyword(Keyword::FROM).is_some() { + if self.parse_keyword(Keyword::FROM) { cte.from = Some(self.parse_identifier(false)?); } Ok(cte) @@ -8876,10 +8870,10 @@ impl<'a> Parser<'a> { let subquery = self.parse_boxed_query()?; self.expect_token(&Token::RParen)?; SetExpr::Query(subquery) - } else if self.parse_keyword(Keyword::VALUES).is_some() { + } else if self.parse_keyword(Keyword::VALUES) { let is_mysql = dialect_of!(self is MySqlDialect); SetExpr::Values(self.parse_values(is_mysql)?) - } else if self.parse_keyword(Keyword::TABLE).is_some() { + } else if self.parse_keyword(Keyword::TABLE) { SetExpr::Table(Box::new(self.parse_as_table()?)) } else { return self.expected( @@ -8942,13 +8936,13 @@ impl<'a> Parser<'a> { SetQuantifier::DistinctByName } else if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) { SetQuantifier::ByName - } else if self.parse_keyword(Keyword::ALL).is_some() { + } else if self.parse_keyword(Keyword::ALL) { if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) { SetQuantifier::AllByName } else { SetQuantifier::All } - } else if self.parse_keyword(Keyword::DISTINCT).is_some() { + } else if self.parse_keyword(Keyword::DISTINCT) { SetQuantifier::Distinct } else { SetQuantifier::None @@ -8963,10 +8957,10 @@ impl<'a> Parser<'a> { pub fn parse_select(&mut self) -> Result { let select_token = self.expect_keyword(Keyword::SELECT)?; let value_table_mode = - if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::AS).is_some() { - if self.parse_keyword(Keyword::VALUE).is_some() { + if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::AS) { + if self.parse_keyword(Keyword::VALUE) { Some(ValueTableMode::AsValue) - } else if self.parse_keyword(Keyword::STRUCT).is_some() { + } else if self.parse_keyword(Keyword::STRUCT) { Some(ValueTableMode::AsStruct) } else { self.expected("VALUE or STRUCT", self.peek_token())? @@ -8977,7 +8971,7 @@ impl<'a> Parser<'a> { let distinct = self.parse_all_or_distinct()?; - let top = if self.parse_keyword(Keyword::TOP).is_some() { + let top = if self.parse_keyword(Keyword::TOP) { Some(self.parse_top()?) } else { None @@ -8985,12 +8979,12 @@ impl<'a> Parser<'a> { let projection = self.parse_projection()?; - let into = if self.parse_keyword(Keyword::INTO).is_some() { + let into = if self.parse_keyword(Keyword::INTO) { let temporary = self .parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY]) .is_some(); - let unlogged = self.parse_keyword(Keyword::UNLOGGED).is_some(); - let table = self.parse_keyword(Keyword::TABLE).is_some(); + let unlogged = self.parse_keyword(Keyword::UNLOGGED); + let table = self.parse_keyword(Keyword::TABLE); let name = self.parse_object_name(false)?; Some(SelectInto { temporary, @@ -9007,7 +9001,7 @@ impl<'a> Parser<'a> { // otherwise they may be parsed as an alias as part of the `projection` // or `from`. - let from = if self.parse_keyword(Keyword::FROM).is_some() { + let from = if self.parse_keyword(Keyword::FROM) { self.parse_comma_separated(Parser::parse_table_and_joins)? } else { vec![] @@ -9016,7 +9010,7 @@ impl<'a> Parser<'a> { let mut lateral_views = vec![]; loop { if self.parse_keywords(&[Keyword::LATERAL, Keyword::VIEW]) { - let outer = self.parse_keyword(Keyword::OUTER).is_some(); + let outer = self.parse_keyword(Keyword::OUTER); let lateral_view = self.parse_expr()?; let lateral_view_name = self.parse_object_name(false)?; let lateral_col_alias = self @@ -9045,14 +9039,14 @@ impl<'a> Parser<'a> { } let prewhere = if dialect_of!(self is ClickHouseDialect|GenericDialect) - && self.parse_keyword(Keyword::PREWHERE).is_some() + && self.parse_keyword(Keyword::PREWHERE) { Some(self.parse_expr()?) } else { None }; - let selection = if self.parse_keyword(Keyword::WHERE).is_some() { + let selection = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { None @@ -9080,35 +9074,35 @@ impl<'a> Parser<'a> { vec![] }; - let having = if self.parse_keyword(Keyword::HAVING).is_some() { + let having = if self.parse_keyword(Keyword::HAVING) { Some(self.parse_expr()?) } else { None }; // Accept QUALIFY and WINDOW in any order and flag accordingly. - let (named_windows, qualify, window_before_qualify) = - if self.parse_keyword(Keyword::WINDOW).is_some() { - let named_windows = self.parse_comma_separated(Parser::parse_named_window)?; - if self.parse_keyword(Keyword::QUALIFY).is_some() { - (named_windows, Some(self.parse_expr()?), true) - } else { - (named_windows, None, true) - } - } else if self.parse_keyword(Keyword::QUALIFY).is_some() { - let qualify = Some(self.parse_expr()?); - if self.parse_keyword(Keyword::WINDOW).is_some() { - ( - self.parse_comma_separated(Parser::parse_named_window)?, - qualify, - false, - ) - } else { - (Default::default(), qualify, false) - } + let (named_windows, qualify, window_before_qualify) = if self.parse_keyword(Keyword::WINDOW) + { + let named_windows = self.parse_comma_separated(Parser::parse_named_window)?; + if self.parse_keyword(Keyword::QUALIFY) { + (named_windows, Some(self.parse_expr()?), true) } else { - Default::default() - }; + (named_windows, None, true) + } + } else if self.parse_keyword(Keyword::QUALIFY) { + let qualify = Some(self.parse_expr()?); + if self.parse_keyword(Keyword::WINDOW) { + ( + self.parse_comma_separated(Parser::parse_named_window)?, + qualify, + false, + ) + } else { + (Default::default(), qualify, false) + } + } else { + Default::default() + }; let connect_by = if self.dialect.supports_connect_by() && self @@ -9231,14 +9225,14 @@ impl<'a> Parser<'a> { self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, Keyword::HIVEVAR]); if let Some(Keyword::HIVEVAR) = modifier { self.expect_token(&Token::Colon)?; - } else if self.parse_keyword(Keyword::ROLE).is_some() { + } else if self.parse_keyword(Keyword::ROLE) { let context_modifier = match modifier { Some(Keyword::LOCAL) => ContextModifier::Local, Some(Keyword::SESSION) => ContextModifier::Session, _ => ContextModifier::None, }; - let role_name = if self.parse_keyword(Keyword::NONE).is_some() { + let role_name = if self.parse_keyword(Keyword::NONE) { None } else { Some(self.parse_identifier(false)?) @@ -9271,7 +9265,7 @@ impl<'a> Parser<'a> { if matches!(&variables, OneOrManyWithParens::One(variable) if variable.to_string().eq_ignore_ascii_case("NAMES") && dialect_of!(self is MySqlDialect | GenericDialect)) { - if self.parse_keyword(Keyword::DEFAULT).is_some() { + if self.parse_keyword(Keyword::DEFAULT) { return Ok(Statement::SetNamesDefault {}); } @@ -9290,7 +9284,7 @@ impl<'a> Parser<'a> { let parenthesized_assignment = matches!(&variables, OneOrManyWithParens::Many(_)); - if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO).is_some() { + if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) { if parenthesized_assignment { self.expect_token(&Token::LParen)?; } @@ -9343,7 +9337,7 @@ impl<'a> Parser<'a> { session: true, }) } else if variable.to_string() == "TRANSACTION" && modifier.is_none() { - if self.parse_keyword(Keyword::SNAPSHOT).is_some() { + if self.parse_keyword(Keyword::SNAPSHOT) { let snapshot_id = self.parse_value()?; return Ok(Statement::SetTransaction { modes: vec![], @@ -9362,18 +9356,18 @@ impl<'a> Parser<'a> { } pub fn parse_show(&mut self) -> Result { - let extended = self.parse_keyword(Keyword::EXTENDED).is_some(); - let full = self.parse_keyword(Keyword::FULL).is_some(); - let session = self.parse_keyword(Keyword::SESSION).is_some(); - let global = self.parse_keyword(Keyword::GLOBAL).is_some(); + let extended = self.parse_keyword(Keyword::EXTENDED); + let full = self.parse_keyword(Keyword::FULL); + let session = self.parse_keyword(Keyword::SESSION); + let global = self.parse_keyword(Keyword::GLOBAL); if self .parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS]) .is_some() { Ok(self.parse_show_columns(extended, full)?) - } else if self.parse_keyword(Keyword::TABLES).is_some() { + } else if self.parse_keyword(Keyword::TABLES) { Ok(self.parse_show_tables(extended, full)?) - } else if self.parse_keyword(Keyword::FUNCTIONS).is_some() { + } else if self.parse_keyword(Keyword::FUNCTIONS) { Ok(self.parse_show_functions()?) } else if extended || full { Err(ParserError::ParserError( @@ -9381,9 +9375,9 @@ impl<'a> Parser<'a> { )) } else if self.parse_one_of_keywords(&[Keyword::CREATE]).is_some() { Ok(self.parse_show_create()?) - } else if self.parse_keyword(Keyword::COLLATION).is_some() { + } else if self.parse_keyword(Keyword::COLLATION) { Ok(self.parse_show_collation()?) - } else if self.parse_keyword(Keyword::VARIABLES).is_some() + } else if self.parse_keyword(Keyword::VARIABLES) && dialect_of!(self is MySqlDialect | GenericDialect) { Ok(Statement::ShowVariables { @@ -9391,7 +9385,7 @@ impl<'a> Parser<'a> { session, global, }) - } else if self.parse_keyword(Keyword::STATUS).is_some() + } else if self.parse_keyword(Keyword::STATUS) && dialect_of!(self is MySqlDialect | GenericDialect) { Ok(Statement::ShowStatus { @@ -9487,15 +9481,15 @@ impl<'a> Parser<'a> { pub fn parse_show_statement_filter( &mut self, ) -> Result, ParserError> { - if self.parse_keyword(Keyword::LIKE).is_some() { + if self.parse_keyword(Keyword::LIKE) { Ok(Some(ShowStatementFilter::Like( self.parse_literal_string()?, ))) - } else if self.parse_keyword(Keyword::ILIKE).is_some() { + } else if self.parse_keyword(Keyword::ILIKE) { Ok(Some(ShowStatementFilter::ILike( self.parse_literal_string()?, ))) - } else if self.parse_keyword(Keyword::WHERE).is_some() { + } else if self.parse_keyword(Keyword::WHERE) { Ok(Some(ShowStatementFilter::Where(self.parse_expr()?))) } else { Ok(None) @@ -9506,7 +9500,7 @@ impl<'a> Parser<'a> { // Determine which keywords are recognized by the current dialect let parsed_keyword = if dialect_of!(self is HiveDialect) { // HiveDialect accepts USE DEFAULT; statement without any db specified - if self.parse_keyword(Keyword::DEFAULT).is_some() { + if self.parse_keyword(Keyword::DEFAULT) { return Ok(Statement::Use(Use::Default)); } None // HiveDialect doesn't expect any other specific keyword after `USE` @@ -9537,11 +9531,11 @@ impl<'a> Parser<'a> { // a table alias. let mut joins = vec![]; loop { - let global = self.parse_keyword(Keyword::GLOBAL).is_some(); - let join = if self.parse_keyword(Keyword::CROSS).is_some() { - let join_operator = if self.parse_keyword(Keyword::JOIN).is_some() { + let global = self.parse_keyword(Keyword::GLOBAL); + let join = if self.parse_keyword(Keyword::CROSS) { + let join_operator = if self.parse_keyword(Keyword::JOIN) { JoinOperator::CrossJoin - } else if self.parse_keyword(Keyword::APPLY).is_some() { + } else if self.parse_keyword(Keyword::APPLY) { // MSSQL extension, similar to CROSS JOIN LATERAL JoinOperator::CrossApply } else { @@ -9552,7 +9546,7 @@ impl<'a> Parser<'a> { global, join_operator, } - } else if self.parse_keyword(Keyword::OUTER).is_some() { + } else if self.parse_keyword(Keyword::OUTER) { // MSSQL extension, similar to LEFT JOIN LATERAL .. ON 1=1 self.expect_keyword(Keyword::APPLY)?; Join { @@ -9560,7 +9554,7 @@ impl<'a> Parser<'a> { global, join_operator: JoinOperator::OuterApply, } - } else if self.parse_keyword(Keyword::ASOF).is_some() { + } else if self.parse_keyword(Keyword::ASOF) { self.expect_keyword(Keyword::JOIN)?; let relation = self.parse_table_factor()?; self.expect_keyword(Keyword::MATCH_CONDITION)?; @@ -9574,7 +9568,7 @@ impl<'a> Parser<'a> { }, } } else { - let natural = self.parse_keyword(Keyword::NATURAL).is_some(); + let natural = self.parse_keyword(Keyword::NATURAL); let peek_keyword = if let Token::Word(w) = self.peek_token().token { w.keyword } else { @@ -9583,7 +9577,7 @@ impl<'a> Parser<'a> { let join_operator_type = match peek_keyword { Keyword::INNER | Keyword::JOIN => { - let _ = self.parse_keyword(Keyword::INNER).is_some(); // [ INNER ] + let _ = self.parse_keyword(Keyword::INNER); // [ INNER ] self.expect_keyword(Keyword::JOIN)?; JoinOperator::Inner } @@ -9637,7 +9631,7 @@ impl<'a> Parser<'a> { } Keyword::FULL => { let _ = self.next_token(); // consume FULL - let _ = self.parse_keyword(Keyword::OUTER).is_some(); // [ OUTER ] + let _ = self.parse_keyword(Keyword::OUTER); // [ OUTER ] self.expect_keyword(Keyword::JOIN)?; JoinOperator::FullOuter } @@ -9664,7 +9658,7 @@ impl<'a> Parser<'a> { /// A table name or a parenthesized subquery, followed by optional `[AS] alias` pub fn parse_table_factor(&mut self) -> Result { - if self.parse_keyword(Keyword::LATERAL).is_some() { + if self.parse_keyword(Keyword::LATERAL) { // LATERAL must always be followed by a subquery or table function. if self.consume_token(&Token::LParen) { self.parse_derived_table_factor(Lateral) @@ -9680,7 +9674,7 @@ impl<'a> Parser<'a> { alias, }) } - } else if self.parse_keyword(Keyword::TABLE).is_some() { + } else if self.parse_keyword(Keyword::TABLE) { // parse table function (SELECT * FROM TABLE () [ AS ]) self.expect_token(&Token::LParen)?; let expr = self.parse_expr()?; @@ -9834,7 +9828,7 @@ impl<'a> Parser<'a> { alias, }) } else if dialect_of!(self is BigQueryDialect | PostgreSqlDialect | GenericDialect) - && self.parse_keyword(Keyword::UNNEST).is_some() + && self.parse_keyword(Keyword::UNNEST) { self.expect_token(&Token::LParen)?; let array_exprs = self.parse_comma_separated(Parser::parse_expr)?; @@ -9889,7 +9883,7 @@ impl<'a> Parser<'a> { let name = self.parse_object_name(true)?; let partitions: Vec = if dialect_of!(self is MySqlDialect | GenericDialect) - && self.parse_keyword(Keyword::PARTITION).is_some() + && self.parse_keyword(Keyword::PARTITION) { self.parse_parenthesized_identifiers()? } else { @@ -9912,7 +9906,7 @@ impl<'a> Parser<'a> { // MSSQL-specific table hints: let mut with_hints = vec![]; - if self.parse_keyword(Keyword::WITH).is_some() { + if self.parse_keyword(Keyword::WITH) { if self.consume_token(&Token::LParen) { with_hints = self.parse_comma_separated(Parser::parse_expr)?; self.expect_token(&Token::RParen)?; @@ -9941,7 +9935,7 @@ impl<'a> Parser<'a> { } if self.dialect.supports_match_recognize() - && self.parse_keyword(Keyword::MATCH_RECOGNIZE).is_some() + && self.parse_keyword(Keyword::MATCH_RECOGNIZE) { table = self.parse_match_recognize(table)?; } @@ -9965,10 +9959,10 @@ impl<'a> Parser<'a> { vec![] }; - let measures = if self.parse_keyword(Keyword::MEASURES).is_some() { + let measures = if self.parse_keyword(Keyword::MEASURES) { self.parse_comma_separated(|p| { let expr = p.parse_expr()?; - let _ = p.parse_keyword(Keyword::AS).is_some(); + let _ = p.parse_keyword(Keyword::AS); let alias = p.parse_identifier(false)?; Ok(Measure { expr, alias }) })? @@ -10197,13 +10191,13 @@ impl<'a> Parser<'a> { pub fn parse_json_table_column_def(&mut self) -> Result { let name = self.parse_identifier(false)?; let r#type = self.parse_data_type()?; - let exists = self.parse_keyword(Keyword::EXISTS).is_some(); + let exists = self.parse_keyword(Keyword::EXISTS); self.expect_keyword(Keyword::PATH)?; let path = self.parse_value()?; let mut on_empty = None; let mut on_error = None; while let Some(error_handling) = self.parse_json_table_column_error_handling()? { - if self.parse_keyword(Keyword::EMPTY).is_some() { + if self.parse_keyword(Keyword::EMPTY) { on_empty = Some(error_handling); } else { self.expect_keyword(Keyword::ERROR)?; @@ -10223,11 +10217,11 @@ impl<'a> Parser<'a> { fn parse_json_table_column_error_handling( &mut self, ) -> Result, ParserError> { - let res = if self.parse_keyword(Keyword::NULL).is_some() { + let res = if self.parse_keyword(Keyword::NULL) { JsonTableColumnErrorHandling::Null - } else if self.parse_keyword(Keyword::ERROR).is_some() { + } else if self.parse_keyword(Keyword::ERROR) { JsonTableColumnErrorHandling::Error - } else if self.parse_keyword(Keyword::DEFAULT).is_some() { + } else if self.parse_keyword(Keyword::DEFAULT) { JsonTableColumnErrorHandling::Default(self.parse_value()?) } else { return Ok(None); @@ -10259,7 +10253,7 @@ impl<'a> Parser<'a> { _ => self.expected("a function identifier", self.peek_token()), }?; let expr = self.parse_function(ObjectName(vec![Ident::new(function_name)]))?; - let alias = if self.parse_keyword(Keyword::AS).is_some() { + let alias = if self.parse_keyword(Keyword::AS) { Some(self.parse_identifier(false)?) } else { None @@ -10270,7 +10264,7 @@ impl<'a> Parser<'a> { fn parse_expr_with_alias(&mut self) -> Result { let expr = self.parse_expr()?; - let alias = if self.parse_keyword(Keyword::AS).is_some() { + let alias = if self.parse_keyword(Keyword::AS) { Some(self.parse_identifier(false)?) } else { None @@ -10290,7 +10284,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::IN)?; self.expect_token(&Token::LParen)?; - let value_source = if self.parse_keyword(Keyword::ANY).is_some() { + let value_source = if self.parse_keyword(Keyword::ANY) { let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) { self.parse_comma_separated(Parser::parse_order_by_expr)? } else { @@ -10354,10 +10348,10 @@ impl<'a> Parser<'a> { pub fn parse_join_constraint(&mut self, natural: bool) -> Result { if natural { Ok(JoinConstraint::Natural) - } else if self.parse_keyword(Keyword::ON).is_some() { + } else if self.parse_keyword(Keyword::ON) { let constraint = self.parse_expr()?; Ok(JoinConstraint::On(constraint)) - } else if self.parse_keyword(Keyword::USING).is_some() { + } else if self.parse_keyword(Keyword::USING) { let columns = self.parse_parenthesized_column_list(Mandatory, false)?; Ok(JoinConstraint::Using(columns)) } else { @@ -10392,9 +10386,9 @@ impl<'a> Parser<'a> { pub fn parse_grant_revoke_privileges_objects( &mut self, ) -> Result<(Privileges, GrantObjects), ParserError> { - let privileges = if self.parse_keyword(Keyword::ALL).is_some() { + let privileges = if self.parse_keyword(Keyword::ALL) { Privileges::All { - with_privileges_keyword: self.parse_keyword(Keyword::PRIVILEGES).is_some(), + with_privileges_keyword: self.parse_keyword(Keyword::PRIVILEGES), } } else { let (actions, err): (Vec<_>, Vec<_>) = self @@ -10509,8 +10503,8 @@ impl<'a> Parser<'a> { .then(|| self.parse_identifier(false).unwrap()); let loc = self.peek_token().span.start; - let cascade = self.parse_keyword(Keyword::CASCADE).is_some(); - let restrict = self.parse_keyword(Keyword::RESTRICT).is_some(); + let cascade = self.parse_keyword(Keyword::CASCADE); + let restrict = self.parse_keyword(Keyword::RESTRICT); if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in REVOKE", loc); } @@ -10562,7 +10556,7 @@ impl<'a> Parser<'a> { Some(SqliteOnConflict::Fail) } else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) { Some(SqliteOnConflict::Ignore) - } else if self.parse_keyword(Keyword::REPLACE).is_some() { + } else if self.parse_keyword(Keyword::REPLACE) { Some(SqliteOnConflict::Replace) } else { None @@ -10570,18 +10564,18 @@ impl<'a> Parser<'a> { let priority = if !dialect_of!(self is MySqlDialect | GenericDialect) { None - } else if self.parse_keyword(Keyword::LOW_PRIORITY).is_some() { + } else if self.parse_keyword(Keyword::LOW_PRIORITY) { Some(MysqlInsertPriority::LowPriority) - } else if self.parse_keyword(Keyword::DELAYED).is_some() { + } else if self.parse_keyword(Keyword::DELAYED) { Some(MysqlInsertPriority::Delayed) - } else if self.parse_keyword(Keyword::HIGH_PRIORITY).is_some() { + } else if self.parse_keyword(Keyword::HIGH_PRIORITY) { Some(MysqlInsertPriority::HighPriority) } else { None }; let ignore = dialect_of!(self is MySqlDialect | GenericDialect) - && self.parse_keyword(Keyword::IGNORE).is_some(); + && self.parse_keyword(Keyword::IGNORE); let replace_into = false; @@ -10589,9 +10583,9 @@ impl<'a> Parser<'a> { let into = action == Some(Keyword::INTO); let overwrite = action == Some(Keyword::OVERWRITE); - let local = self.parse_keyword(Keyword::LOCAL).is_some(); + let local = self.parse_keyword(Keyword::LOCAL); - if self.parse_keyword(Keyword::DIRECTORY).is_some() { + if self.parse_keyword(Keyword::DIRECTORY) { let path = self.parse_literal_string()?; let file_format = if self.parse_keywords(&[Keyword::STORED, Keyword::AS]) { Some(self.parse_file_format()?) @@ -10608,16 +10602,15 @@ impl<'a> Parser<'a> { }) } else { // Hive lets you put table here regardless - let table = self.parse_keyword(Keyword::TABLE).is_some(); + let table = self.parse_keyword(Keyword::TABLE); let table_name = self.parse_object_name(false)?; - let table_alias = if dialect_of!(self is PostgreSqlDialect) - && self.parse_keyword(Keyword::AS).is_some() - { - Some(self.parse_identifier(false)?) - } else { - None - }; + let table_alias = + if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::AS) { + Some(self.parse_identifier(false)?) + } else { + None + }; let is_mysql = dialect_of!(self is MySqlDialect); @@ -10641,7 +10634,7 @@ impl<'a> Parser<'a> { }; let insert_alias = if dialect_of!(self is MySqlDialect | GenericDialect) - && self.parse_keyword(Keyword::AS).is_some() + && self.parse_keyword(Keyword::AS) { let row_alias = self.parse_object_name(false)?; let col_aliases = Some(self.parse_parenthesized_column_list(Optional, false)?); @@ -10653,8 +10646,8 @@ impl<'a> Parser<'a> { None }; - let on = if self.parse_keyword(Keyword::ON).is_some() { - if self.parse_keyword(Keyword::CONFLICT).is_some() { + let on = if self.parse_keyword(Keyword::ON) { + if self.parse_keyword(Keyword::CONFLICT) { let conflict_target = if self.parse_keywords(&[Keyword::ON, Keyword::CONSTRAINT]) { Some(ConflictTarget::OnConstraint(self.parse_object_name(false)?)) @@ -10667,13 +10660,13 @@ impl<'a> Parser<'a> { }; self.expect_keyword(Keyword::DO)?; - let action = if self.parse_keyword(Keyword::NOTHING).is_some() { + let action = if self.parse_keyword(Keyword::NOTHING) { OnConflictAction::DoNothing } else { self.expect_keyword(Keyword::UPDATE)?; self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; - let selection = if self.parse_keyword(Keyword::WHERE).is_some() { + let selection = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { None @@ -10700,7 +10693,7 @@ impl<'a> Parser<'a> { None }; - let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { + let returning = if self.parse_keyword(Keyword::RETURNING) { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -10728,7 +10721,7 @@ impl<'a> Parser<'a> { } pub fn parse_insert_partition(&mut self) -> Result>, ParserError> { - if self.parse_keyword(Keyword::PARTITION).is_some() { + if self.parse_keyword(Keyword::PARTITION) { self.expect_token(&Token::LParen)?; let partition_cols = Some(self.parse_comma_separated(Parser::parse_expr)?); self.expect_token(&Token::RParen)?; @@ -10749,19 +10742,19 @@ impl<'a> Parser<'a> { let table = self.parse_table_and_joins()?; self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; - let from = if self.parse_keyword(Keyword::FROM).is_some() + let from = if self.parse_keyword(Keyword::FROM) && dialect_of!(self is GenericDialect | PostgreSqlDialect | DuckDbDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect | SQLiteDialect ) { Some(self.parse_table_and_joins()?) } else { None }; - let selection = if self.parse_keyword(Keyword::WHERE).is_some() { + let selection = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { None }; - let returning = if self.parse_keyword(Keyword::RETURNING).is_some() { + let returning = if self.parse_keyword(Keyword::RETURNING) { Some(self.parse_comma_separated(Parser::parse_select_item)?) } else { None @@ -10903,12 +10896,12 @@ impl<'a> Parser<'a> { )); } - if self.parse_keyword(Keyword::LIMIT).is_some() { + if self.parse_keyword(Keyword::LIMIT) { clauses.push(FunctionArgumentClause::Limit(self.parse_expr()?)); } if dialect_of!(self is GenericDialect | BigQueryDialect) - && self.parse_keyword(Keyword::HAVING).is_some() + && self.parse_keyword(Keyword::HAVING) { let kind = match self.expect_one_of_keywords(&[Keyword::MIN, Keyword::MAX])? { Keyword::MIN => HavingBoundKind::Min, @@ -10922,7 +10915,7 @@ impl<'a> Parser<'a> { } if dialect_of!(self is GenericDialect | MySqlDialect) - && self.parse_keyword(Keyword::SEPARATOR).is_some() + && self.parse_keyword(Keyword::SEPARATOR) { clauses.push(FunctionArgumentClause::Separator(self.parse_value()?)); } @@ -10942,8 +10935,8 @@ impl<'a> Parser<'a> { fn parse_duplicate_treatment(&mut self) -> Result, ParserError> { let loc = self.peek_token().span.start; match ( - self.parse_keyword(Keyword::ALL).is_some(), - self.parse_keyword(Keyword::DISTINCT).is_some(), + self.parse_keyword(Keyword::ALL), + self.parse_keyword(Keyword::DISTINCT), ) { (true, false) => Ok(Some(DuplicateTreatment::All)), (false, true) => Ok(Some(DuplicateTreatment::Distinct)), @@ -11029,7 +11022,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_ilike( &mut self, ) -> Result, ParserError> { - let opt_ilike = if self.parse_keyword(Keyword::ILIKE).is_some() { + let opt_ilike = if self.parse_keyword(Keyword::ILIKE) { let next_token = self.next_token(); let pattern = match next_token.token { Token::SingleQuotedString(s) => s, @@ -11048,7 +11041,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_exclude( &mut self, ) -> Result, ParserError> { - let opt_exclude = if self.parse_keyword(Keyword::EXCLUDE).is_some() { + let opt_exclude = if self.parse_keyword(Keyword::EXCLUDE) { if self.consume_token(&Token::LParen) { let columns = self.parse_comma_separated(|parser| parser.parse_identifier(false))?; @@ -11071,7 +11064,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_except( &mut self, ) -> Result, ParserError> { - let opt_except = if self.parse_keyword(Keyword::EXCEPT).is_some() { + let opt_except = if self.parse_keyword(Keyword::EXCEPT) { if self.peek_token().token == Token::LParen { let idents = self.parse_parenthesized_column_list(Mandatory, false)?; match &idents[..] { @@ -11105,7 +11098,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_rename( &mut self, ) -> Result, ParserError> { - let opt_rename = if self.parse_keyword(Keyword::RENAME).is_some() { + let opt_rename = if self.parse_keyword(Keyword::RENAME) { if self.consume_token(&Token::LParen) { let idents = self.parse_comma_separated(|parser| parser.parse_identifier_with_alias())?; @@ -11126,7 +11119,7 @@ impl<'a> Parser<'a> { pub fn parse_optional_select_item_replace( &mut self, ) -> Result, ParserError> { - let opt_replace = if self.parse_keyword(Keyword::REPLACE).is_some() { + let opt_replace = if self.parse_keyword(Keyword::REPLACE) { if self.consume_token(&Token::LParen) { let items = self.parse_comma_separated(|parser| { Ok(Box::new(parser.parse_replace_elements()?)) @@ -11145,7 +11138,7 @@ impl<'a> Parser<'a> { } pub fn parse_replace_elements(&mut self) -> Result { let expr = self.parse_expr()?; - let as_keyword = self.parse_keyword(Keyword::AS).is_some(); + let as_keyword = self.parse_keyword(Keyword::AS); let ident = self.parse_identifier(false)?; Ok(ReplaceSelectElement { expr, @@ -11157,9 +11150,9 @@ impl<'a> Parser<'a> { /// Parse ASC or DESC, returns an Option with true if ASC, false of DESC or `None` if none of /// them. pub fn parse_asc_desc(&mut self) -> Option { - if self.parse_keyword(Keyword::ASC).is_some() { + if self.parse_keyword(Keyword::ASC) { Some(true) - } else if self.parse_keyword(Keyword::DESC).is_some() { + } else if self.parse_keyword(Keyword::DESC) { Some(false) } else { None @@ -11199,19 +11192,19 @@ impl<'a> Parser<'a> { // Parse a WITH FILL clause (ClickHouse dialect) // that follow the WITH FILL keywords in a ORDER BY clause pub fn parse_with_fill(&mut self) -> Result { - let from = if self.parse_keyword(Keyword::FROM).is_some() { + let from = if self.parse_keyword(Keyword::FROM) { Some(self.parse_expr()?) } else { None }; - let to = if self.parse_keyword(Keyword::TO).is_some() { + let to = if self.parse_keyword(Keyword::TO) { Some(self.parse_expr()?) } else { None }; - let step = if self.parse_keyword(Keyword::STEP).is_some() { + let step = if self.parse_keyword(Keyword::STEP) { Some(self.parse_expr()?) } else { None @@ -11223,7 +11216,7 @@ impl<'a> Parser<'a> { // Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect) // that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier pub fn parse_interpolations(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::INTERPOLATE).is_none() { + if !self.parse_keyword(Keyword::INTERPOLATE) { return Ok(None); } @@ -11244,7 +11237,7 @@ impl<'a> Parser<'a> { // Parse a INTERPOLATE expression (ClickHouse dialect) pub fn parse_interpolation(&mut self) -> Result { let column = self.parse_identifier(false)?; - let expr = if self.parse_keyword(Keyword::AS).is_some() { + let expr = if self.parse_keyword(Keyword::AS) { Some(self.parse_expr()?) } else { None @@ -11268,7 +11261,7 @@ impl<'a> Parser<'a> { Some(TopQuantity::Constant(quantity)) }; - let percent = self.parse_keyword(Keyword::PERCENT).is_some(); + let percent = self.parse_keyword(Keyword::PERCENT); let with_ties = self.parse_keywords(&[Keyword::WITH, Keyword::TIES]); @@ -11281,7 +11274,7 @@ impl<'a> Parser<'a> { /// Parse a LIMIT clause pub fn parse_limit(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::ALL).is_some() { + if self.parse_keyword(Keyword::ALL) { Ok(None) } else { Ok(Some(self.parse_expr()?)) @@ -11291,9 +11284,9 @@ impl<'a> Parser<'a> { /// Parse an OFFSET clause pub fn parse_offset(&mut self) -> Result { let value = self.parse_expr()?; - let rows = if self.parse_keyword(Keyword::ROW).is_some() { + let rows = if self.parse_keyword(Keyword::ROW) { OffsetRows::Row - } else if self.parse_keyword(Keyword::ROWS).is_some() { + } else if self.parse_keyword(Keyword::ROWS) { OffsetRows::Rows } else { OffsetRows::None @@ -11311,11 +11304,11 @@ impl<'a> Parser<'a> { (None, false) } else { let quantity = Expr::Value(self.parse_value()?); - let percent = self.parse_keyword(Keyword::PERCENT).is_some(); + let percent = self.parse_keyword(Keyword::PERCENT); self.expect_one_of_keywords(&[Keyword::ROW, Keyword::ROWS])?; (Some(quantity), percent) }; - let with_ties = if self.parse_keyword(Keyword::ONLY).is_some() { + let with_ties = if self.parse_keyword(Keyword::ONLY) { false } else if self.parse_keywords(&[Keyword::WITH, Keyword::TIES]) { true @@ -11336,12 +11329,12 @@ impl<'a> Parser<'a> { Keyword::SHARE => LockType::Share, _ => unreachable!(), }; - let of = if self.parse_keyword(Keyword::OF).is_some() { + let of = if self.parse_keyword(Keyword::OF) { Some(self.parse_object_name(false)?) } else { None }; - let nonblock = if self.parse_keyword(Keyword::NOWAIT).is_some() { + let nonblock = if self.parse_keyword(Keyword::NOWAIT) { Some(NonBlock::Nowait) } else if self.parse_keywords(&[Keyword::SKIP, Keyword::LOCKED]) { Some(NonBlock::SkipLocked) @@ -11359,7 +11352,7 @@ impl<'a> Parser<'a> { let mut explicit_row = false; let rows = self.parse_comma_separated(|parser| { - if parser.parse_keyword(Keyword::ROW).is_some() { + if parser.parse_keyword(Keyword::ROW) { explicit_row = true; } @@ -11388,11 +11381,11 @@ impl<'a> Parser<'a> { pub fn parse_begin(&mut self) -> Result { let modifier = if !self.dialect.supports_start_transaction_modifier() { None - } else if self.parse_keyword(Keyword::DEFERRED).is_some() { + } else if self.parse_keyword(Keyword::DEFERRED) { Some(TransactionModifier::Deferred) - } else if self.parse_keyword(Keyword::IMMEDIATE).is_some() { + } else if self.parse_keyword(Keyword::IMMEDIATE) { Some(TransactionModifier::Immediate) - } else if self.parse_keyword(Keyword::EXCLUSIVE).is_some() { + } else if self.parse_keyword(Keyword::EXCLUSIVE) { Some(TransactionModifier::Exclusive) } else { None @@ -11422,7 +11415,7 @@ impl<'a> Parser<'a> { TransactionIsolationLevel::ReadCommitted } else if self.parse_keywords(&[Keyword::REPEATABLE, Keyword::READ]) { TransactionIsolationLevel::RepeatableRead - } else if self.parse_keyword(Keyword::SERIALIZABLE).is_some() { + } else if self.parse_keyword(Keyword::SERIALIZABLE) { TransactionIsolationLevel::Serializable } else { self.expected("isolation level", self.peek_token())? @@ -11462,8 +11455,8 @@ impl<'a> Parser<'a> { pub fn parse_commit_rollback_chain(&mut self) -> Result { let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]); - if self.parse_keyword(Keyword::AND).is_some() { - let chain = self.parse_keyword(Keyword::NO).is_none(); + if self.parse_keyword(Keyword::AND) { + let chain = !self.parse_keyword(Keyword::NO); self.expect_keyword(Keyword::CHAIN)?; Ok(chain) } else { @@ -11472,8 +11465,8 @@ impl<'a> Parser<'a> { } pub fn parse_rollback_savepoint(&mut self) -> Result, ParserError> { - if self.parse_keyword(Keyword::TO).is_some() { - let _ = self.parse_keyword(Keyword::SAVEPOINT).is_some(); + if self.parse_keyword(Keyword::TO) { + let _ = self.parse_keyword(Keyword::SAVEPOINT); let savepoint = self.parse_identifier(false)?; Ok(Some(savepoint)) @@ -11483,7 +11476,7 @@ impl<'a> Parser<'a> { } pub fn parse_deallocate(&mut self) -> Result { - let prepare = self.parse_keyword(Keyword::PREPARE).is_some(); + let prepare = self.parse_keyword(Keyword::PREPARE); let name = self.parse_identifier(false)?; Ok(Statement::Deallocate { name, prepare }) } @@ -11498,7 +11491,7 @@ impl<'a> Parser<'a> { } let mut using = vec![]; - if self.parse_keyword(Keyword::USING).is_some() { + if self.parse_keyword(Keyword::USING) { using.push(self.parse_expr()?); while self.consume_token(&Token::Comma) { @@ -11557,7 +11550,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::WHEN)?; let mut clause_kind = MergeClauseKind::Matched; - if self.parse_keyword(Keyword::NOT).is_some() { + if self.parse_keyword(Keyword::NOT) { clause_kind = MergeClauseKind::NotMatched; } self.expect_keyword(Keyword::MATCHED)?; @@ -11572,7 +11565,7 @@ impl<'a> Parser<'a> { clause_kind = MergeClauseKind::NotMatchedByTarget; } - let predicate = if self.parse_keyword(Keyword::AND).is_some() { + let predicate = if self.parse_keyword(Keyword::AND) { Some(self.parse_expr()?) } else { None @@ -11623,7 +11616,7 @@ impl<'a> Parser<'a> { let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?; let kind = if dialect_of!(self is BigQueryDialect | GenericDialect) - && self.parse_keyword(Keyword::ROW).is_some() + && self.parse_keyword(Keyword::ROW) { MergeInsertKind::Row } else { @@ -11649,7 +11642,7 @@ impl<'a> Parser<'a> { } pub fn parse_merge(&mut self) -> Result { - let into = self.parse_keyword(Keyword::INTO).is_some(); + let into = self.parse_keyword(Keyword::INTO); let table = self.parse_table_factor()?; @@ -11729,8 +11722,8 @@ impl<'a> Parser<'a> { let name = self.parse_object_name(false)?; let on_cluster = self.parse_optional_on_cluster()?; - let partition = if self.parse_keyword(Keyword::PARTITION).is_some() { - if self.parse_keyword(Keyword::ID).is_some() { + let partition = if self.parse_keyword(Keyword::PARTITION) { + if self.parse_keyword(Keyword::ID) { Some(Partition::Identifier(self.parse_identifier(false)?)) } else { Some(Partition::Expr(self.parse_expr()?)) @@ -11739,9 +11732,9 @@ impl<'a> Parser<'a> { None }; - let include_final = self.parse_keyword(Keyword::FINAL).is_some(); - let deduplicate = if self.parse_keyword(Keyword::DEDUPLICATE).is_some() { - if self.parse_keyword(Keyword::BY).is_some() { + let include_final = self.parse_keyword(Keyword::FINAL); + let deduplicate = if self.parse_keyword(Keyword::DEDUPLICATE) { + if self.parse_keyword(Keyword::BY) { Some(Deduplicate::ByExpression(self.parse_expr()?)) } else { Some(Deduplicate::All) @@ -11806,7 +11799,7 @@ impl<'a> Parser<'a> { } } //[ MINVALUE minvalue | NO MINVALUE ] - if self.parse_keyword(Keyword::MINVALUE).is_some() { + if self.parse_keyword(Keyword::MINVALUE) { sequence_options.push(SequenceOptions::MinValue(Some(self.parse_number()?))); } else if self.parse_keywords(&[Keyword::NO, Keyword::MINVALUE]) { sequence_options.push(SequenceOptions::MinValue(None)); @@ -11922,7 +11915,7 @@ impl<'a> Parser<'a> { loop { let attr_name = self.parse_identifier(false)?; let attr_data_type = self.parse_data_type()?; - let attr_collation = if self.parse_keyword(Keyword::COLLATE).is_some() { + let attr_collation = if self.parse_keyword(Keyword::COLLATE) { Some(self.parse_object_name(false)?) } else { None @@ -11956,9 +11949,9 @@ impl<'a> Parser<'a> { fn parse_column_position(&mut self) -> Result, ParserError> { if dialect_of!(self is MySqlDialect | GenericDialect) { - if self.parse_keyword(Keyword::FIRST).is_some() { + if self.parse_keyword(Keyword::FIRST) { Ok(Some(MySQLColumnPosition::First)) - } else if self.parse_keyword(Keyword::AFTER).is_some() { + } else if self.parse_keyword(Keyword::AFTER) { let ident = self.parse_identifier(false)?; Ok(Some(MySQLColumnPosition::After(ident))) } else { diff --git a/tests/sqlparser_custom_dialect.rs b/tests/sqlparser_custom_dialect.rs index 471dc47ea..5b29047a4 100644 --- a/tests/sqlparser_custom_dialect.rs +++ b/tests/sqlparser_custom_dialect.rs @@ -106,7 +106,7 @@ fn custom_statement_parser() -> Result<(), ParserError> { } fn parse_statement(&self, parser: &mut Parser) -> Option> { - if parser.parse_keyword(Keyword::SELECT).is_some() { + if parser.parse_keyword(Keyword::SELECT) { for _ in 0..3 { let _ = parser.next_token(); } From 0804e9959637ab59e5ae9fbf722999816a23e8f9 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Tue, 8 Oct 2024 12:58:06 +0200 Subject: [PATCH 14/23] fix: diverging hash and partialeq implementations --- src/ast/mod.rs | 9 ++++++++- src/tokenizer.rs | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 123af6522..cb7d3e003 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -128,7 +128,7 @@ where } /// An identifier, decomposed into its value or character data and the quote style. -#[derive(Debug, Clone, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Ident { @@ -147,6 +147,13 @@ impl PartialEq for Ident { } } +impl core::hash::Hash for Ident { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.quote_style.hash(state); + } +} + impl Eq for Ident {} impl Ident { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a7568176e..9d8fb84d9 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -505,7 +505,7 @@ impl Span { } /// A [Token] with [Location] attached to it -#[derive(Debug, Eq, Hash, Clone)] +#[derive(Debug, Eq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TokenWithLocation { pub token: Token, @@ -526,6 +526,12 @@ impl TokenWithLocation { } } +impl core::hash::Hash for TokenWithLocation { + fn hash(&self, state: &mut H) { + self.token.hash(state); + } +} + impl PartialEq for TokenWithLocation { fn eq(&self, other: &TokenWithLocation) -> bool { self.token == other.token From eb9ff9af36b74167fb2508522e1b9972a0fda651 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Wed, 9 Oct 2024 09:53:00 +0200 Subject: [PATCH 15/23] Update src/ast/spans.rs Co-authored-by: Ifeanyi Ubah --- src/ast/spans.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index b0df0ac15..c3af0d7d4 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -22,7 +22,7 @@ use super::{ /// /// Source spans are not guaranteed to be entirely accurate. They may /// be missing keywords or other tokens. Some nodes may not have a computable -/// span at all, in which case they return `Span::empty()`. +/// span at all, in which case they return [`Span::empty()`]. /// /// Some impl blocks may contain doc comments with information /// on which nodes are missing spans. From a93cebc18749e320016dc4659a81ae672c8726f2 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Wed, 9 Oct 2024 10:00:49 +0200 Subject: [PATCH 16/23] improve docs & un-pub union_spans --- src/ast/mod.rs | 2 +- src/ast/spans.rs | 3 ++- src/tokenizer.rs | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index cb7d3e003..a8337e8b0 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -82,7 +82,7 @@ pub mod helpers; mod operator; mod query; mod spans; -pub use spans::{union_spans, Spanned}; +pub use spans::Spanned; mod trigger; mod value; diff --git a/src/ast/spans.rs b/src/ast/spans.rs index c3af0d7d4..d7fe397fa 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1642,7 +1642,8 @@ impl Spanned for TableWithJoins { } } -pub fn union_spans>(iter: I) -> Span { +/// Given an iterator of spans, return the [Span::union] of all spans. +fn union_spans>(iter: I) -> Span { iter.reduce(|acc, item| acc.union(&item)) .unwrap_or(Span::empty()) } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 9d8fb84d9..ec6456ded 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -470,12 +470,16 @@ impl std::fmt::Debug for Span { } impl Span { + // An empty span (0, 0) -> (0, 0) + // We need a const instance for pattern matching const EMPTY: Span = Self::empty(); pub fn new(start: Location, end: Location) -> Span { Span { start, end } } + /// Returns an empty span (0, 0) -> (0, 0) + /// Empty spans represent no knowledge of source location pub const fn empty() -> Span { Span { start: Location { line: 0, column: 0 }, @@ -483,6 +487,8 @@ impl Span { } } + /// Returns the smallest Span that contains both `self` and `other` + /// If either span is [Span::empty], the other span is returned pub fn union(&self, other: &Span) -> Span { // If either span is empty, return the other // this prevents propagating (0, 0) through the tree @@ -496,6 +502,8 @@ impl Span { } } + /// Same as [Span::union] for `Option` + /// If `other` is `None`, `self` is returned pub fn union_opt(&self, other: &Option) -> Span { match other { Some(other) => self.union(other), From 734264a4efb1c83147938cc83f5ff0d27c9c8809 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Wed, 9 Oct 2024 10:02:37 +0200 Subject: [PATCH 17/23] move union_spans to top of file --- src/ast/spans.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index d7fe397fa..03aa0166b 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -18,6 +18,12 @@ use super::{ WildcardAdditionalOptions, With, WithFill, }; +/// Given an iterator of spans, return the [Span::union] of all spans. +fn union_spans>(iter: I) -> Span { + iter.reduce(|acc, item| acc.union(&item)) + .unwrap_or(Span::empty()) +} + /// A trait for AST nodes that have a source span for use in diagnostics. /// /// Source spans are not guaranteed to be entirely accurate. They may @@ -1642,12 +1648,6 @@ impl Spanned for TableWithJoins { } } -/// Given an iterator of spans, return the [Span::union] of all spans. -fn union_spans>(iter: I) -> Span { - iter.reduce(|acc, item| acc.union(&item)) - .unwrap_or(Span::empty()) -} - impl Spanned for Select { fn span(&self) -> Span { union_spans( From 441ceb19a489b494b30c83b948ce9b35e4b72164 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Wed, 9 Oct 2024 10:12:01 +0200 Subject: [PATCH 18/23] replace old tests --- src/ast/spans.rs | 101 ++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 36 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 03aa0166b..b95b2ba5f 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1680,65 +1680,94 @@ pub mod tests { } #[test] - fn test_query_span() { - let query = crate::parser::Parser::new(&GenericDialect) - .try_with_sql( - "SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id", - ) - .unwrap() - .parse_query() - .unwrap(); + fn test_join() { + let dialect = &GenericDialect; + let mut test = SpanTest::new( + dialect, + "SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id", + ); + + let query = test.0.parse_select().unwrap(); + let select_span = query.span(); + + assert_eq!( + test.get_source(select_span), + "SELECT id, name FROM users LEFT JOIN companies ON users.company_id = companies.id" + ); + + let join_span = query.from[0].joins[0].span(); + // 'LEFT JOIN' missing assert_eq!( - query.span(), - Span::new((1, 1).into(), (1, 109 - 28 + 1).into()) + test.get_source(join_span), + "companies ON users.company_id = companies.id" ); } #[test] pub fn test_union() { - let query = crate::parser::Parser::new(&GenericDialect) - .try_with_sql( - "SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source", - ) - .unwrap() - .parse_query() - .unwrap(); + let dialect = &GenericDialect; + let mut test = SpanTest::new( + dialect, + "SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source", + ); - query.span(); + let query = test.0.parse_query().unwrap(); + let select_span = query.span(); + + assert_eq!( + test.get_source(select_span), + "SELECT a FROM postgres.public.source UNION SELECT a FROM postgres.public.source" + ); } #[test] pub fn test_subquery() { - let query = crate::parser::Parser::new(&GenericDialect) - .try_with_sql("SELECT a FROM (SELECT a FROM postgres.public.source) AS b") - .unwrap() - .parse_query() - .unwrap(); + let dialect = &GenericDialect; + let mut test = SpanTest::new( + dialect, + "SELECT a FROM (SELECT a FROM postgres.public.source) AS b", + ); + + let query = test.0.parse_select().unwrap(); + let select_span = query.span(); + + assert_eq!( + test.get_source(select_span), + "SELECT a FROM (SELECT a FROM postgres.public.source) AS b" + ); + + let subquery_span = query.from[0].span(); - query.span(); + // left paren missing + assert_eq!( + test.get_source(subquery_span), + "SELECT a FROM postgres.public.source) AS b" + ); } #[test] pub fn test_cte() { - let query = crate::parser::Parser::new(&GenericDialect) - .try_with_sql("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") - .unwrap() - .parse_query() - .unwrap(); + 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 query = test.0.parse_query().unwrap(); + + let select_span = query.span(); - query.span(); + assert_eq!(test.get_source(select_span), "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"); } #[test] pub fn test_snowflake_lateral_flatten() { - let query = crate::parser::Parser::new(&SnowflakeDialect) - .try_with_sql("SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED") - .unwrap() - .parse_query() - .unwrap(); + 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 query = test.0.parse_select().unwrap(); + + let select_span = query.span(); - query.span(); + assert_eq!(test.get_source(select_span), "SELECT FLATTENED.VALUE:field::TEXT AS FIELD FROM SNOWFLAKE.SCHEMA.SOURCE AS S, LATERAL FLATTEN(INPUT => S.JSON_ARRAY) AS FLATTENED"); } #[test] From e6a434054865253a78c3f3953cc24826a0e0dd63 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Fri, 11 Oct 2024 11:05:13 +0200 Subject: [PATCH 19/23] pr feedback --- src/ast/mod.rs | 18 +++++++++++++++--- src/ast/spans.rs | 9 +++++---- src/tokenizer.rs | 14 ++++++++++---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a8337e8b0..6b1210166 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -143,14 +143,26 @@ pub struct Ident { impl PartialEq for Ident { fn eq(&self, other: &Self) -> bool { - self.value == other.value && self.quote_style == other.quote_style + let Ident { + value, + quote_style, + span: _, + } = self; + + value == &other.value && quote_style == &other.quote_style } } impl core::hash::Hash for Ident { fn hash(&self, state: &mut H) { - self.value.hash(state); - self.quote_style.hash(state); + let Ident { + value, + quote_style, + span: _, + } = self; + + value.hash(state); + quote_style.hash(state); } } diff --git a/src/ast/spans.rs b/src/ast/spans.rs index b95b2ba5f..98f94ee73 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1200,9 +1200,8 @@ impl Spanned for Subscript { upper_bound.as_ref().map(|i| i.span()), stride.as_ref().map(|i| i.span()), ] - .iter() - .flatten() - .cloned(), + .into_iter() + .flatten(), ), } } @@ -1529,7 +1528,7 @@ impl Spanned for OrderByExpr { fn span(&self) -> Span { self.expr .span() - .union_opt(&self.with_fill.as_ref().map(|f| f.span()).clone()) + .union_opt(&self.with_fill.as_ref().map(|f| f.span())) } } @@ -1673,6 +1672,8 @@ pub mod tests { Self(Parser::new(dialect).try_with_sql(sql).unwrap(), sql) } + // get the subsection of the source string that corresponds to the span + // only works on single-line strings fn get_source(&self, span: Span) -> &'a str { // lines in spans are 1-indexed &self.1[(span.start.column as usize - 1)..(span.end.column - 1) as usize] diff --git a/src/tokenizer.rs b/src/tokenizer.rs index ec6456ded..cd6521278 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -456,6 +456,7 @@ impl From<(u64, u64)> for Location { } } +/// A span of source code locations (start, end) #[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord, Copy)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Span { @@ -536,25 +537,30 @@ impl TokenWithLocation { impl core::hash::Hash for TokenWithLocation { fn hash(&self, state: &mut H) { - self.token.hash(state); + let TokenWithLocation { token, span: _ } = self; + + token.hash(state); } } impl PartialEq for TokenWithLocation { fn eq(&self, other: &TokenWithLocation) -> bool { - self.token == other.token + let TokenWithLocation { token, span: _ } = self; + + token == &other.token } } impl PartialOrd for TokenWithLocation { fn partial_cmp(&self, other: &TokenWithLocation) -> Option { - self.token.partial_cmp(&other.token) + Some(self.cmp(other)) } } impl Ord for TokenWithLocation { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.token.cmp(&other.token) + let TokenWithLocation { token, span: _ } = self; + token.cmp(&other.token) } } From 16a3f2a8eb8fb0bf10ada26ca1f6c77c9d697f88 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Fri, 11 Oct 2024 11:15:35 +0200 Subject: [PATCH 20/23] add small comment --- src/ast/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 6b1210166..bbc4540fc 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -146,6 +146,7 @@ impl PartialEq for Ident { let Ident { value, quote_style, + // backwards compat span: _, } = self; @@ -158,6 +159,7 @@ impl core::hash::Hash for Ident { let Ident { value, quote_style, + // backwards compat span: _, } = self; From 98b051dc11488101dd6ec3e88c9e1234ceb46402 Mon Sep 17 00:00:00 2001 From: Nyrox Date: Wed, 16 Oct 2024 12:15:57 +0200 Subject: [PATCH 21/23] refactor: rewrite all span implementations to pattern match exhaustively on self --- src/ast/spans.rs | 583 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 460 insertions(+), 123 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 98f94ee73..6b01fbaac 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -5,16 +5,17 @@ use crate::tokenizer::Span; use super::{ AlterColumnOperation, AlterIndexOperation, AlterTableOperation, Array, Assignment, AssignmentTarget, CloseCursor, ClusteredIndex, ColumnDef, ColumnOption, ColumnOptionDef, - ConflictTarget, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, + ConflictTarget, ConnectBy, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr, - ExprWithAlias, FromTable, Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, - FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound, IlikeSelectItem, Insert, - Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, - MatchRecognizePattern, Measure, ObjectName, OnConflict, OnConflictAction, OnInsert, OrderBy, + ExprWithAlias, Fetch, FromTable, Function, FunctionArg, FunctionArgExpr, + FunctionArgumentClause, FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound, + IlikeSelectItem, Insert, Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, + JsonPath, JsonPathElem, LateralView, MatchRecognizePattern, Measure, NamedWindowDefinition, + ObjectName, Offset, OnConflict, OnConflictAction, OnInsert, OrderBy, OrderByExpr, Partition, PivotValueSource, ProjectionSelect, Query, ReferentialAction, - RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectItem, SetExpr, - SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableConstraint, TableFactor, - TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef, + RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, + SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableConstraint, + TableFactor, TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill, }; @@ -40,28 +41,85 @@ pub trait Spanned { impl Spanned for Query { fn span(&self) -> Span { - self.body - .span() - .union_opt(&self.with.as_ref().map(|i| i.span())) + let Query { + with, + body, + order_by, + limit, + limit_by, + offset, + fetch, + locks: _, // todo + for_clause: _, // todo, mysql specific + settings: _, // todo, clickhouse specific + format_clause: _, // todo, clickhouse specific + } = self; + + union_spans( + with.iter() + .map(|i| i.span()) + .chain(core::iter::once(body.span())) + .chain(order_by.as_ref().map(|i| i.span())) + .chain(limit.as_ref().map(|i| i.span())) + .chain(limit_by.iter().map(|i| i.span())) + .chain(offset.as_ref().map(|i| i.span())) + .chain(fetch.as_ref().map(|i| i.span())), + ) + } +} + +impl Spanned for Offset { + fn span(&self) -> Span { + let Offset { + value, + rows: _, // enum + } = self; + + value.span() + } +} + +impl Spanned for Fetch { + fn span(&self) -> Span { + let Fetch { + with_ties: _, // bool + percent: _, // bool + quantity, + } = self; + + quantity.as_ref().map_or(Span::empty(), |i| i.span()) } } impl Spanned for With { fn span(&self) -> Span { + let With { + with_token, + recursive: _, // bool + cte_tables, + } = self; + union_spans( - core::iter::once(self.with_token.span) - .chain(self.cte_tables.iter().map(|item| item.span())), + core::iter::once(with_token.span).chain(cte_tables.iter().map(|item| item.span())), ) } } impl Spanned for Cte { fn span(&self) -> Span { + let Cte { + alias, + query, + from, + materialized: _, // enum + closing_paren_token, + } = self; + union_spans( - core::iter::once(self.alias.span()) - .chain(core::iter::once(self.query.span())) - .chain(self.from.iter().map(|item| item.span)) - .chain(core::iter::once(self.closing_paren_token.span)), + core::iter::once(alias.span()) + .chain(core::iter::once(query.span())) + .chain(from.iter().map(|item| item.span)) + .chain(core::iter::once(closing_paren_token.span)), ) } } @@ -90,9 +148,13 @@ impl Spanned for SetExpr { impl Spanned for Values { fn span(&self) -> Span { + let Values { + explicit_row: _, // bool, + rows, + } = self; + union_spans( - self.rows - .iter() + rows.iter() .map(|row| union_spans(row.iter().map(|expr| expr.span()))), ) } @@ -387,34 +449,87 @@ impl Spanned for Use { impl Spanned for CreateTable { fn span(&self) -> Span { + let CreateTable { + or_replace: _, // bool + temporary: _, // bool + external: _, // bool + global: _, // bool + if_not_exists: _, // bool + transient: _, // bool + volatile: _, // bool + name, + columns, + constraints, + hive_distribution: _, // hive specific + hive_formats: _, // hive specific + table_properties, + with_options, + file_format: _, // enum + location: _, // string, no span + query, + without_rowid: _, // bool + like, + clone, + engine: _, // todo + comment: _, // todo, no span + auto_increment_offset: _, // u32, no span + default_charset: _, // string, no span + collation: _, // string, no span + on_commit: _, // enum + on_cluster: _, // todo, clickhouse specific + primary_key: _, // todo, clickhouse specific + order_by: _, // todo, clickhouse specific + partition_by: _, // todo, BigQuery specific + cluster_by: _, // todo, BigQuery specific + clustered_by: _, // todo, Hive specific + options: _, // todo, BigQuery specific + strict: _, // bool + copy_grants: _, // bool + enable_schema_evolution: _, // bool + change_tracking: _, // bool + data_retention_time_in_days: _, // u64, no span + max_data_extension_time_in_days: _, // u64, no span + default_ddl_collation: _, // string, no span + with_aggregation_policy: _, // todo, Snowflake specific + with_row_access_policy: _, // todo, Snowflake specific + with_tags: _, // todo, Snowflake specific + } = self; + union_spans( - core::iter::once(self.name.span()) - .chain(self.columns.iter().map(|i| i.span())) - .chain(self.constraints.iter().map(|i| i.span())) - .chain(self.table_properties.iter().map(|i| i.span())) - .chain(self.with_options.iter().map(|i| i.span())) - .chain(self.query.iter().map(|i| i.span())) - .chain(self.like.iter().map(|i| i.span())) - .chain(self.clone.iter().map(|i| i.span())), + core::iter::once(name.span()) + .chain(columns.iter().map(|i| i.span())) + .chain(constraints.iter().map(|i| i.span())) + .chain(table_properties.iter().map(|i| i.span())) + .chain(with_options.iter().map(|i| i.span())) + .chain(query.iter().map(|i| i.span())) + .chain(like.iter().map(|i| i.span())) + .chain(clone.iter().map(|i| i.span())), ) } } impl Spanned for ColumnDef { fn span(&self) -> Span { + let ColumnDef { + name, + data_type: _, // enum + collation, + options, + } = self; + union_spans( - core::iter::once(self.name.span) - .chain(self.collation.iter().map(|i| i.span())) - .chain(self.options.iter().map(|i| i.span())), + core::iter::once(name.span) + .chain(collation.iter().map(|i| i.span())) + .chain(options.iter().map(|i| i.span())), ) } } impl Spanned for ColumnOptionDef { fn span(&self) -> Span { - self.option - .span() - .union_opt(&self.name.as_ref().map(|i| i.span)) + let ColumnOptionDef { name, option } = self; + + option.span().union_opt(&name.as_ref().map(|i| i.span)) } } @@ -498,16 +613,29 @@ impl Spanned for TableConstraint { impl Spanned for CreateIndex { fn span(&self) -> Span { + let CreateIndex { + name, + table_name, + using, + columns, + unique: _, // bool + concurrently: _, // bool + if_not_exists: _, // bool + include, + nulls_distinct: _, // bool + with, + predicate, + } = self; + union_spans( - self.name - .iter() + name.iter() .map(|i| i.span()) - .chain(core::iter::once(self.table_name.span())) - .chain(self.using.iter().map(|i| i.span)) - .chain(self.columns.iter().map(|i| i.span())) - .chain(self.include.iter().map(|i| i.span)) - .chain(self.with.iter().map(|i| i.span())) - .chain(self.predicate.iter().map(|i| i.span())), + .chain(core::iter::once(table_name.span())) + .chain(using.iter().map(|i| i.span)) + .chain(columns.iter().map(|i| i.span())) + .chain(include.iter().map(|i| i.span)) + .chain(with.iter().map(|i| i.span())) + .chain(predicate.iter().map(|i| i.span())), ) } } @@ -565,6 +693,12 @@ impl Spanned for ReferentialAction { /// # missing span impl Spanned for ConstraintCharacteristics { fn span(&self) -> Span { + let ConstraintCharacteristics { + deferrable: _, // bool + initially: _, // enum + enforced: _, // bool + } = self; + Span::empty() } } @@ -608,24 +742,30 @@ impl Spanned for CopySource { impl Spanned for Delete { fn span(&self) -> Span { + let Delete { + tables, + from, + using, + selection, + returning, + order_by, + limit, + } = self; + union_spans( - self.tables + tables .iter() .map(|i| i.span()) - .chain(core::iter::once(self.from.span())) + .chain(core::iter::once(from.span())) .chain( - self.using + using .iter() .map(|u| union_spans(u.iter().map(|i| i.span()))), ) - .chain(self.selection.iter().map(|i| i.span())) - .chain( - self.returning - .iter() - .flat_map(|i| i.iter().map(|k| k.span())), - ) - .chain(self.order_by.iter().map(|i| i.span())) - .chain(self.limit.iter().map(|i| i.span())), + .chain(selection.iter().map(|i| i.span())) + .chain(returning.iter().flat_map(|i| i.iter().map(|k| k.span()))) + .chain(order_by.iter().map(|i| i.span())) + .chain(limit.iter().map(|i| i.span())), ) } } @@ -641,9 +781,15 @@ impl Spanned for FromTable { impl Spanned for ViewColumnDef { fn span(&self) -> Span { + let ViewColumnDef { + name, + data_type: _, // todo, DataType + options, + } = self; + union_spans( - core::iter::once(self.name.span) - .chain(self.options.iter().flat_map(|i| i.iter().map(|k| k.span()))), + core::iter::once(name.span) + .chain(options.iter().flat_map(|i| i.iter().map(|k| k.span()))), ) } } @@ -683,7 +829,12 @@ impl Spanned for TableOptionsClustered { impl Spanned for ClusteredIndex { fn span(&self) -> Span { - self.name.span + let ClusteredIndex { + name, + asc: _, // bool + } = self; + + name.span } } @@ -831,23 +982,31 @@ impl Spanned for Partition { impl Spanned for ProjectionSelect { fn span(&self) -> Span { + let ProjectionSelect { + projection, + order_by, + group_by, + } = self; + union_spans( - self.projection + projection .iter() .map(|i| i.span()) - .chain(self.order_by.iter().map(|i| i.span())) - .chain(self.group_by.iter().map(|i| i.span())), + .chain(order_by.iter().map(|i| i.span())) + .chain(group_by.iter().map(|i| i.span())), ) } } impl Spanned for OrderBy { fn span(&self) -> Span { + let OrderBy { exprs, interpolate } = self; + union_spans( - self.exprs + exprs .iter() .map(|i| i.span()) - .chain(self.interpolate.iter().map(|i| i.span())), + .chain(interpolate.iter().map(|i| i.span())), ) } } @@ -869,15 +1028,17 @@ impl Spanned for GroupByExpr { impl Spanned for Interpolate { fn span(&self) -> Span { - union_spans(self.exprs.iter().flat_map(|i| i.iter().map(|e| e.span()))) + let Interpolate { exprs } = self; + + union_spans(exprs.iter().flat_map(|i| i.iter().map(|e| e.span()))) } } impl Spanned for InterpolateExpr { fn span(&self) -> Span { - self.column - .span - .union_opt(&self.expr.as_ref().map(|e| e.span())) + let InterpolateExpr { column, expr } = self; + + column.span.union_opt(&expr.as_ref().map(|e| e.span())) } } @@ -895,23 +1056,34 @@ impl Spanned for AlterIndexOperation { /// - [Insert::insert_alias] impl Spanned for Insert { fn span(&self) -> Span { + let Insert { + or: _, // enum, sqlite specific + ignore: _, // bool + into: _, // bool + table_name, + table_alias, + columns, + overwrite: _, // bool + source, + partitioned, + after_columns, + table: _, // bool + on, + returning, + replace_into: _, // bool + priority: _, // todo, mysql specific + insert_alias: _, // todo, mysql specific + } = self; + union_spans( - core::iter::once(self.table_name.span()) - .chain(self.table_alias.as_ref().map(|i| i.span)) - .chain(self.columns.iter().map(|i| i.span)) - .chain(self.source.as_ref().map(|q| q.span())) - .chain( - self.partitioned - .iter() - .flat_map(|i| i.iter().map(|k| k.span())), - ) - .chain(self.after_columns.iter().map(|i| i.span)) - .chain(self.on.as_ref().map(|i| i.span())) - .chain( - self.returning - .iter() - .flat_map(|i| i.iter().map(|k| k.span())), - ), + core::iter::once(table_name.span()) + .chain(table_alias.as_ref().map(|i| i.span)) + .chain(columns.iter().map(|i| i.span)) + .chain(source.as_ref().map(|q| q.span())) + .chain(partitioned.iter().flat_map(|i| i.iter().map(|k| k.span()))) + .chain(after_columns.iter().map(|i| i.span)) + .chain(on.as_ref().map(|i| i.span())) + .chain(returning.iter().flat_map(|i| i.iter().map(|k| k.span()))), ) } } @@ -927,9 +1099,14 @@ impl Spanned for OnInsert { impl Spanned for OnConflict { fn span(&self) -> Span { - self.action + let OnConflict { + conflict_target, + action, + } = self; + + action .span() - .union_opt(&self.conflict_target.as_ref().map(|i| i.span())) + .union_opt(&conflict_target.as_ref().map(|i| i.span())) } } @@ -957,18 +1134,25 @@ impl Spanned for OnConflictAction { impl Spanned for DoUpdate { fn span(&self) -> Span { + let DoUpdate { + assignments, + selection, + } = self; + union_spans( - self.assignments + assignments .iter() .map(|i| i.span()) - .chain(self.selection.iter().map(|i| i.span())), + .chain(selection.iter().map(|i| i.span())), ) } } impl Spanned for Assignment { fn span(&self) -> Span { - self.target.span().union(&self.value.span()) + let Assignment { target, value } = self; + + target.span().union(&value.span()) } } @@ -1209,24 +1393,43 @@ impl Spanned for Subscript { impl Spanned for ObjectName { fn span(&self) -> Span { - union_spans(self.0.iter().map(|i| i.span)) + let ObjectName(segments) = self; + + union_spans(segments.iter().map(|i| i.span)) } } impl Spanned for Array { fn span(&self) -> Span { - union_spans(self.elem.iter().map(|i| i.span())) + let Array { + elem, + named: _, // bool + } = self; + + union_spans(elem.iter().map(|i| i.span())) } } impl Spanned for Function { fn span(&self) -> Span { + let Function { + name, + parameters, + args, + filter, + null_treatment: _, // enum + over: _, // todo + within_group, + } = self; + union_spans( - self.name - .0 + name.0 .iter() .map(|i| i.span) - .chain(iter::once(self.args.span())), + .chain(iter::once(args.span())) + .chain(iter::once(parameters.span())) + .chain(filter.iter().map(|i| i.span())) + .chain(within_group.iter().map(|i| i.span())), ) } } @@ -1246,12 +1449,17 @@ impl Spanned for FunctionArguments { impl Spanned for FunctionArgumentList { fn span(&self) -> Span { + let FunctionArgumentList { + duplicate_treatment: _, // enum + args, + clauses, + } = self; + union_spans( // # todo: duplicate-treatment span - self.args - .iter() + args.iter() .map(|i| i.span()) - .chain(self.clauses.iter().map(|i| i.span())), + .chain(clauses.iter().map(|i| i.span())), ) } } @@ -1274,7 +1482,9 @@ impl Spanned for FunctionArgumentClause { /// see Spanned impl for JsonPathElem for more information impl Spanned for JsonPath { fn span(&self) -> Span { - union_spans(self.path.iter().map(|i| i.span())) + let JsonPath { path } = self; + + union_spans(path.iter().map(|i| i.span())) } } @@ -1310,13 +1520,22 @@ impl Spanned for SelectItem { impl Spanned for WildcardAdditionalOptions { fn span(&self) -> Span { + let WildcardAdditionalOptions { + wildcard_token, + opt_ilike, + opt_exclude, + opt_except, + opt_replace, + opt_rename, + } = self; + union_spans( - core::iter::once(self.wildcard_token.span) - .chain(self.opt_ilike.as_ref().map(|i| i.span())) - .chain(self.opt_exclude.as_ref().map(|i| i.span())) - .chain(self.opt_rename.as_ref().map(|i| i.span())) - .chain(self.opt_replace.as_ref().map(|i| i.span())) - .chain(self.opt_except.as_ref().map(|i| i.span())), + core::iter::once(wildcard_token.span) + .chain(opt_ilike.as_ref().map(|i| i.span())) + .chain(opt_exclude.as_ref().map(|i| i.span())) + .chain(opt_rename.as_ref().map(|i| i.span())) + .chain(opt_replace.as_ref().map(|i| i.span())) + .chain(opt_except.as_ref().map(|i| i.span())), ) } } @@ -1350,22 +1569,34 @@ impl Spanned for RenameSelectItem { impl Spanned for ExceptSelectItem { fn span(&self) -> Span { + let ExceptSelectItem { + first_element, + additional_elements, + } = self; + union_spans( - iter::once(self.first_element.span) - .chain(self.additional_elements.iter().map(|i| i.span)), + iter::once(first_element.span).chain(additional_elements.iter().map(|i| i.span)), ) } } impl Spanned for ReplaceSelectItem { fn span(&self) -> Span { - union_spans(self.items.iter().map(|i| i.span())) + let ReplaceSelectItem { items } = self; + + union_spans(items.iter().map(|i| i.span())) } } impl Spanned for ReplaceSelectElement { fn span(&self) -> Span { - self.expr.span().union(&self.column_name.span) + let ReplaceSelectElement { + expr, + column_name, + as_keyword: _, // bool + } = self; + + expr.span().union(&column_name.span) } } @@ -1499,9 +1730,9 @@ impl Spanned for PivotValueSource { impl Spanned for ExprWithAlias { fn span(&self) -> Span { - self.expr - .span() - .union_opt(&self.alias.as_ref().map(|i| i.span)) + let ExprWithAlias { expr, alias } = self; + + expr.span().union_opt(&alias.as_ref().map(|i| i.span)) } } @@ -1514,32 +1745,42 @@ impl Spanned for MatchRecognizePattern { impl Spanned for SymbolDefinition { fn span(&self) -> Span { - self.symbol.span.union(&self.definition.span()) + let SymbolDefinition { symbol, definition } = self; + + symbol.span.union(&definition.span()) } } impl Spanned for Measure { fn span(&self) -> Span { - self.expr.span().union(&self.alias.span) + let Measure { expr, alias } = self; + + expr.span().union(&alias.span) } } impl Spanned for OrderByExpr { fn span(&self) -> Span { - self.expr - .span() - .union_opt(&self.with_fill.as_ref().map(|f| f.span())) + let OrderByExpr { + expr, + asc: _, // bool + nulls_first: _, // bool + with_fill, + } = self; + + expr.span().union_opt(&with_fill.as_ref().map(|f| f.span())) } } impl Spanned for WithFill { fn span(&self) -> Span { + let WithFill { from, to, step } = self; + union_spans( - self.from - .iter() + from.iter() .map(|f| f.span()) - .chain(self.to.iter().map(|t| t.span())) - .chain(self.step.iter().map(|s| s.span())), + .chain(to.iter().map(|t| t.span())) + .chain(step.iter().map(|s| s.span())), ) } } @@ -1575,7 +1816,9 @@ impl Spanned for FunctionArgExpr { impl Spanned for TableAlias { fn span(&self) -> Span { - union_spans(iter::once(self.name.span).chain(self.columns.iter().map(|i| i.span))) + let TableAlias { name, columns } = self; + + union_spans(iter::once(name.span).chain(columns.iter().map(|i| i.span))) } } @@ -1591,7 +1834,13 @@ impl Spanned for Value { impl Spanned for Join { fn span(&self) -> Span { - self.relation.span().union(&self.join_operator.span()) + let Join { + relation, + global: _, // bool + join_operator, + } = self; + + relation.span().union(&join_operator.span()) } } @@ -1641,22 +1890,110 @@ impl Spanned for JoinConstraint { impl Spanned for TableWithJoins { fn span(&self) -> Span { + let TableWithJoins { relation, joins } = self; + + union_spans(core::iter::once(relation.span()).chain(joins.iter().map(|item| item.span()))) + } +} + +impl Spanned for Select { + fn span(&self) -> Span { + let Select { + select_token, + distinct: _, // todo + top: _, // todo, mysql specific + projection, + into, + from, + lateral_views, + prewhere, + selection, + group_by, + cluster_by, + distribute_by, + sort_by, + having, + named_window, + qualify, + window_before_qualify: _, // bool + value_table_mode: _, // todo, BigQuery specific + connect_by, + } = self; + union_spans( - core::iter::once(self.relation.span()).chain(self.joins.iter().map(|item| item.span())), + core::iter::once(select_token.span) + .chain(projection.iter().map(|item| item.span())) + .chain(into.iter().map(|item| item.span())) + .chain(from.iter().map(|item| item.span())) + .chain(lateral_views.iter().map(|item| item.span())) + .chain(prewhere.iter().map(|item| item.span())) + .chain(selection.iter().map(|item| item.span())) + .chain(core::iter::once(group_by.span())) + .chain(cluster_by.iter().map(|item| item.span())) + .chain(distribute_by.iter().map(|item| item.span())) + .chain(sort_by.iter().map(|item| item.span())) + .chain(having.iter().map(|item| item.span())) + .chain(named_window.iter().map(|item| item.span())) + .chain(qualify.iter().map(|item| item.span())) + .chain(connect_by.iter().map(|item| item.span())), ) } } -impl Spanned for Select { +impl Spanned for ConnectBy { + fn span(&self) -> Span { + let ConnectBy { + condition, + relationships, + } = self; + + union_spans( + core::iter::once(condition.span()).chain(relationships.iter().map(|item| item.span())), + ) + } +} + +impl Spanned for NamedWindowDefinition { fn span(&self) -> Span { + let NamedWindowDefinition( + ident, + _, // todo: NamedWindowExpr + ) = self; + + ident.span + } +} + +impl Spanned for LateralView { + fn span(&self) -> Span { + let LateralView { + lateral_view, + lateral_view_name, + lateral_col_alias, + outer: _, // bool + } = self; + union_spans( - core::iter::once(self.select_token.span) - .chain(self.projection.iter().map(|item| item.span())) - .chain(self.from.iter().map(|item| item.span())), + core::iter::once(lateral_view.span()) + .chain(core::iter::once(lateral_view_name.span())) + .chain(lateral_col_alias.iter().map(|i| i.span)), ) } } +impl Spanned for SelectInto { + fn span(&self) -> Span { + let SelectInto { + temporary: _, // bool + unlogged: _, // bool + table: _, // bool + name, + } = self; + + name.span() + } +} + #[cfg(test)] pub mod tests { use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect}; From d76d1e0ef49d5b4b3ba1910dea6a0d83bf36372d Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Fri, 18 Oct 2024 11:24:55 +0200 Subject: [PATCH 22/23] for_clause is mssql, not mysql --- src/ast/spans.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 6b01fbaac..13f1ba3ff 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -50,7 +50,7 @@ impl Spanned for Query { offset, fetch, locks: _, // todo - for_clause: _, // todo, mysql specific + for_clause: _, // todo, mssql specific settings: _, // todo, clickhouse specific format_clause: _, // todo, clickhouse specific } = self; From 71c27ea001741bcc729cf3f743364e7c9704b638 Mon Sep 17 00:00:00 2001 From: Mark-Oliver Junge Date: Fri, 25 Oct 2024 13:17:08 +0200 Subject: [PATCH 23/23] cargo fmt --- src/ast/spans.rs | 10 +++++----- src/parser/mod.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 13f1ba3ff..3ded54ab2 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -11,11 +11,11 @@ use super::{ FunctionArgumentClause, FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound, IlikeSelectItem, Insert, Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView, MatchRecognizePattern, Measure, NamedWindowDefinition, - ObjectName, Offset, OnConflict, OnConflictAction, OnInsert, OrderBy, - OrderByExpr, Partition, PivotValueSource, ProjectionSelect, Query, ReferentialAction, - RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, - SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableConstraint, - TableFactor, TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef, + ObjectName, Offset, OnConflict, OnConflictAction, OnInsert, OrderBy, OrderByExpr, Partition, + PivotValueSource, ProjectionSelect, Query, ReferentialAction, RenameSelectItem, + ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, + Statement, Subscript, SymbolDefinition, TableAlias, TableConstraint, TableFactor, + TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill, }; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c9aa7d8d7..433f9957b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9040,10 +9040,10 @@ impl<'a> Parser<'a> { } } self.expect_token(&Token::LParen)?; - + let query = self.parse_query()?; let closing_paren_token = self.expect_token(&Token::RParen)?; - + let alias = TableAlias { name, columns: vec![],