mod ansi;
mod bigquery;
mod clickhouse;
mod databricks;
mod duckdb;
mod generic;
mod hive;
mod mssql;
mod mysql;
mod oracle;
mod postgresql;
mod redshift;
mod snowflake;
mod sqlite;
use core::any::{Any, TypeId};
use core::fmt::Debug;
use core::iter::Peekable;
use core::str::Chars;
use log::debug;
pub use self::ansi::AnsiDialect;
pub use self::bigquery::BigQueryDialect;
pub use self::clickhouse::ClickHouseDialect;
pub use self::databricks::DatabricksDialect;
pub use self::duckdb::DuckDbDialect;
pub use self::generic::GenericDialect;
pub use self::hive::HiveDialect;
pub use self::mssql::MsSqlDialect;
pub use self::mysql::MySqlDialect;
pub use self::oracle::OracleDialect;
pub use self::postgresql::PostgreSqlDialect;
pub use self::redshift::RedshiftSqlDialect;
pub use self::snowflake::SnowflakeDialect;
pub use self::sqlite::SQLiteDialect;
#[cfg(feature = "derive-dialect")]
pub use sqlparser_derive::derive_dialect;
use crate::ast::{ColumnOption, Expr, GranteesType, Ident, ObjectNamePart, Statement};
pub use crate::keywords;
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
use crate::tokenizer::Token;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
macro_rules! dialect_of {
( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
($($parsed_dialect.dialect.is::<$dialect_type>())||+)
};
}
macro_rules! dialect_is {
($dialect:ident is $($dialect_type:ty)|+) => {
($($dialect.is::<$dialect_type>())||+)
}
}
pub trait Dialect: Debug + Any {
fn dialect(&self) -> TypeId {
self.type_id()
}
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '`'
}
fn is_nested_delimited_identifier_start(&self, _ch: char) -> bool {
false
}
fn peek_nested_delimited_identifier_quotes(
&self,
mut _chars: Peekable<Chars<'_>>,
) -> Option<(char, Option<char>)> {
None
}
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
None
}
fn is_identifier_start(&self, ch: char) -> bool;
fn is_identifier_part(&self, ch: char) -> bool;
fn is_custom_operator_part(&self, _ch: char) -> bool {
false
}
fn supports_string_literal_backslash_escape(&self) -> bool {
false
}
fn ignores_wildcard_escapes(&self) -> bool {
false
}
fn supports_unicode_string_literal(&self) -> bool {
false
}
fn supports_filter_during_aggregation(&self) -> bool {
false
}
fn supports_window_clause_named_window_reference(&self) -> bool {
false
}
fn supports_within_after_array_aggregation(&self) -> bool {
false
}
fn supports_group_by_expr(&self) -> bool {
false
}
fn supports_group_by_with_modifier(&self) -> bool {
false
}
fn supports_left_associative_joins_without_parens(&self) -> bool {
true
}
fn supports_outer_join_operator(&self) -> bool {
false
}
fn supports_cross_join_constraint(&self) -> bool {
false
}
fn supports_connect_by(&self) -> bool {
false
}
fn supports_execute_immediate(&self) -> bool {
false
}
fn supports_match_recognize(&self) -> bool {
false
}
fn supports_in_empty_list(&self) -> bool {
false
}
fn supports_start_transaction_modifier(&self) -> bool {
false
}
fn supports_end_transaction_modifier(&self) -> bool {
false
}
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
false
}
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
false
}
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
false
}
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
true
}
fn supports_named_fn_args_with_expr_name(&self) -> bool {
false
}
fn supports_numeric_prefix(&self) -> bool {
false
}
fn supports_numeric_literal_underscores(&self) -> bool {
false
}
fn supports_window_function_null_treatment_arg(&self) -> bool {
false
}
fn supports_dictionary_syntax(&self) -> bool {
false
}
fn support_map_literal_syntax(&self) -> bool {
false
}
fn supports_lambda_functions(&self) -> bool {
false
}
fn supports_parenthesized_set_variables(&self) -> bool {
false
}
fn supports_comma_separated_set_assignments(&self) -> bool {
false
}
fn supports_select_wildcard_except(&self) -> bool {
false
}
fn convert_type_before_value(&self) -> bool {
false
}
fn supports_triple_quoted_string(&self) -> bool {
false
}
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
None
}
fn supports_trailing_commas(&self) -> bool {
false
}
fn supports_limit_comma(&self) -> bool {
false
}
fn supports_string_literal_concatenation(&self) -> bool {
false
}
fn supports_string_literal_concatenation_with_newline(&self) -> bool {
false
}
fn supports_projection_trailing_commas(&self) -> bool {
self.supports_trailing_commas()
}
fn supports_from_trailing_commas(&self) -> bool {
false
}
fn supports_column_definition_trailing_commas(&self) -> bool {
false
}
fn supports_object_name_double_dot_notation(&self) -> bool {
false
}
fn supports_struct_literal(&self) -> bool {
false
}
fn supports_empty_projections(&self) -> bool {
false
}
fn supports_select_expr_star(&self) -> bool {
false
}
fn supports_from_first_select(&self) -> bool {
false
}
fn supports_pipe_operator(&self) -> bool {
false
}
fn supports_user_host_grantee(&self) -> bool {
false
}
fn supports_match_against(&self) -> bool {
false
}
fn supports_select_wildcard_exclude(&self) -> bool {
false
}
fn supports_select_exclude(&self) -> bool {
false
}
fn supports_create_table_multi_schema_info_sources(&self) -> bool {
false
}
fn supports_select_modifiers(&self) -> bool {
false
}
fn parse_infix(
&self,
_parser: &mut Parser,
_expr: &Expr,
_precedence: u8,
) -> Option<Result<Expr, ParserError>> {
None
}
fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
None
}
fn get_next_precedence_default(&self, parser: &Parser) -> Result<u8, ParserError> {
if let Some(precedence) = self.get_next_precedence(parser) {
return precedence;
}
macro_rules! p {
($precedence:ident) => {
self.prec_value(Precedence::$precedence)
};
}
let token = parser.peek_token();
debug!("get_next_precedence_full() {token:?}");
match token.token {
Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
Token::Word(w) if w.keyword == Keyword::AT => {
match (
parser.peek_nth_token(1).token,
parser.peek_nth_token(2).token,
) {
(Token::Word(w), Token::Word(w2))
if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
{
Ok(p!(AtTz))
}
_ => Ok(self.prec_unknown()),
}
}
Token::Word(w) if w.keyword == Keyword::NOT => match parser.peek_nth_token(1).token {
Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
Token::Word(w)
if w.keyword == Keyword::NULL && !parser.in_column_definition_state() =>
{
Ok(p!(Is))
}
_ => Ok(self.prec_unknown()),
},
Token::Word(w) if w.keyword == Keyword::NOTNULL && self.supports_notnull_operator() => {
Ok(p!(Is))
}
Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::OVERLAPS => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
Token::Period => Ok(p!(Period)),
Token::Assignment
| Token::Eq
| Token::Lt
| Token::LtEq
| Token::Neq
| Token::Gt
| Token::GtEq
| Token::DoubleEq
| Token::Tilde
| Token::TildeAsterisk
| Token::ExclamationMarkTilde
| Token::ExclamationMarkTildeAsterisk
| Token::DoubleTilde
| Token::DoubleTildeAsterisk
| Token::ExclamationMarkDoubleTilde
| Token::ExclamationMarkDoubleTildeAsterisk
| Token::Spaceship => Ok(p!(Eq)),
Token::Pipe
| Token::QuestionMarkDash
| Token::DoubleSharp
| Token::Overlap
| Token::AmpersandLeftAngleBracket
| Token::AmpersandRightAngleBracket
| Token::QuestionMarkDashVerticalBar
| Token::AmpersandLeftAngleBracketVerticalBar
| Token::VerticalBarAmpersandRightAngleBracket
| Token::TwoWayArrow
| Token::LeftAngleBracketCaret
| Token::RightAngleBracketCaret
| Token::QuestionMarkSharp
| Token::QuestionMarkDoubleVerticalBar
| Token::QuestionPipe
| Token::TildeEqual
| Token::AtSign
| Token::ShiftLeftVerticalBar
| Token::VerticalBarShiftRight => Ok(p!(Pipe)),
Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
Token::Ampersand => Ok(p!(Ampersand)),
Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
Ok(p!(MulDivModOp))
}
Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
Ok(p!(DoubleColon))
}
Token::Colon => match parser.peek_nth_token(1).token {
Token::SingleQuotedString(_) | Token::Number(_, _) => Ok(self.prec_unknown()),
_ => Ok(p!(Colon)),
},
Token::Arrow
| Token::LongArrow
| Token::HashArrow
| Token::HashLongArrow
| Token::AtArrow
| Token::ArrowAt
| Token::HashMinus
| Token::AtQuestion
| Token::AtAt
| Token::Question
| Token::QuestionAnd
| Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
_ => Ok(self.prec_unknown()),
}
}
fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
None
}
fn parse_column_option(
&self,
_parser: &mut Parser,
) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
Ok(None)
}
fn prec_value(&self, prec: Precedence) -> u8 {
match prec {
Precedence::Period => 100,
Precedence::DoubleColon => 50,
Precedence::AtTz => 41,
Precedence::MulDivModOp => 40,
Precedence::PlusMinus => 30,
Precedence::Xor => 24,
Precedence::Ampersand => 23,
Precedence::Caret => 22,
Precedence::Pipe => 21,
Precedence::Colon => 21,
Precedence::Between => 20,
Precedence::Eq => 20,
Precedence::Like => 19,
Precedence::Is => 17,
Precedence::PgOther => 16,
Precedence::UnaryNot => 15,
Precedence::And => 10,
Precedence::Or => 5,
}
}
fn prec_unknown(&self) -> u8 {
0
}
fn describe_requires_table_keyword(&self) -> bool {
false
}
fn allow_extract_custom(&self) -> bool {
false
}
fn allow_extract_single_quotes(&self) -> bool {
false
}
fn supports_extract_comma_syntax(&self) -> bool {
false
}
fn supports_subquery_as_function_arg(&self) -> bool {
false
}
fn supports_create_view_comment_syntax(&self) -> bool {
false
}
fn supports_array_typedef_without_element_type(&self) -> bool {
false
}
fn supports_parens_around_table_factor(&self) -> bool {
false
}
fn supports_values_as_table_factor(&self) -> bool {
false
}
fn supports_dollar_placeholder(&self) -> bool {
false
}
fn supports_create_index_with_clause(&self) -> bool {
false
}
fn require_interval_qualifier(&self) -> bool {
false
}
fn supports_explain_with_utility_options(&self) -> bool {
false
}
fn supports_asc_desc_in_column_definition(&self) -> bool {
false
}
fn supports_factorial_operator(&self) -> bool {
false
}
fn supports_bitwise_shift_operators(&self) -> bool {
false
}
fn supports_nested_comments(&self) -> bool {
false
}
fn supports_multiline_comment_hints(&self) -> bool {
false
}
fn supports_eq_alias_assignment(&self) -> bool {
false
}
fn supports_try_convert(&self) -> bool {
false
}
fn supports_bang_not_operator(&self) -> bool {
false
}
fn supports_listen_notify(&self) -> bool {
false
}
fn supports_load_data(&self) -> bool {
false
}
fn supports_load_extension(&self) -> bool {
false
}
fn supports_top_before_distinct(&self) -> bool {
false
}
fn supports_boolean_literals(&self) -> bool {
true
}
fn supports_show_like_before_in(&self) -> bool {
false
}
fn supports_comment_on(&self) -> bool {
false
}
fn supports_create_table_select(&self) -> bool {
false
}
fn supports_partiql(&self) -> bool {
false
}
fn supports_constraint_keyword_without_name(&self) -> bool {
false
}
fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
keywords::RESERVED_FOR_IDENTIFIER.contains(&kw)
}
fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
&[]
}
fn get_reserved_grantees_types(&self) -> &[GranteesType] {
&[]
}
fn supports_table_sample_before_alias(&self) -> bool {
false
}
fn supports_insert_set(&self) -> bool {
false
}
fn supports_insert_table_function(&self) -> bool {
false
}
fn supports_insert_format(&self) -> bool {
false
}
fn supports_set_stmt_without_operator(&self) -> bool {
false
}
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
explicit || self.is_column_alias(kw, parser)
}
fn is_table_factor(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
!keywords::RESERVED_FOR_TABLE_FACTOR.contains(kw)
}
fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
}
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
explicit || self.is_table_alias(kw, parser)
}
fn supports_table_versioning(&self) -> bool {
false
}
fn supports_string_escape_constant(&self) -> bool {
false
}
fn supports_table_hints(&self) -> bool {
false
}
fn requires_single_line_comment_whitespace(&self) -> bool {
false
}
fn supports_array_typedef_with_brackets(&self) -> bool {
false
}
fn supports_geometric_types(&self) -> bool {
false
}
fn supports_order_by_all(&self) -> bool {
false
}
fn supports_set_names(&self) -> bool {
false
}
fn supports_space_separated_column_options(&self) -> bool {
false
}
fn supports_alter_column_type_using(&self) -> bool {
false
}
fn supports_comma_separated_drop_column_list(&self) -> bool {
false
}
fn is_identifier_generating_function_name(
&self,
_ident: &Ident,
_name_parts: &[ObjectNamePart],
) -> bool {
false
}
fn supports_notnull_operator(&self) -> bool {
false
}
fn supports_data_type_signed_suffix(&self) -> bool {
false
}
fn supports_interval_options(&self) -> bool {
false
}
fn supports_create_table_like_parenthesized(&self) -> bool {
false
}
fn supports_semantic_view_table_factor(&self) -> bool {
false
}
fn supports_quote_delimited_string(&self) -> bool {
false
}
fn supports_comment_optimizer_hint(&self) -> bool {
false
}
fn supports_double_ampersand_operator(&self) -> bool {
false
}
fn supports_binary_kw_as_cast(&self) -> bool {
false
}
fn supports_select_wildcard_replace(&self) -> bool {
false
}
fn supports_select_wildcard_ilike(&self) -> bool {
false
}
fn supports_select_wildcard_rename(&self) -> bool {
false
}
fn supports_optimize_table(&self) -> bool {
false
}
fn supports_install(&self) -> bool {
false
}
fn supports_detach(&self) -> bool {
false
}
fn supports_prewhere(&self) -> bool {
false
}
fn supports_with_fill(&self) -> bool {
false
}
fn supports_limit_by(&self) -> bool {
false
}
fn supports_interpolate(&self) -> bool {
false
}
fn supports_settings(&self) -> bool {
false
}
fn supports_select_format(&self) -> bool {
false
}
}
#[derive(Debug, Clone, Copy)]
pub enum Precedence {
Period,
DoubleColon,
AtTz,
MulDivModOp,
PlusMinus,
Xor,
Ampersand,
Caret,
Pipe,
Colon,
Between,
Eq,
Like,
Is,
PgOther,
UnaryNot,
And,
Or,
}
impl dyn Dialect {
#[inline]
pub fn is<T: Dialect>(&self) -> bool {
TypeId::of::<T>() == self.dialect()
}
}
pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
let dialect_name = dialect_name.as_ref();
match dialect_name.to_lowercase().as_str() {
"generic" => Some(Box::new(GenericDialect)),
"mysql" => Some(Box::new(MySqlDialect {})),
"postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
"hive" => Some(Box::new(HiveDialect {})),
"sqlite" => Some(Box::new(SQLiteDialect {})),
"snowflake" => Some(Box::new(SnowflakeDialect)),
"redshift" => Some(Box::new(RedshiftSqlDialect {})),
"mssql" => Some(Box::new(MsSqlDialect {})),
"clickhouse" => Some(Box::new(ClickHouseDialect {})),
"bigquery" => Some(Box::new(BigQueryDialect)),
"ansi" => Some(Box::new(AnsiDialect {})),
"duckdb" => Some(Box::new(DuckDbDialect {})),
"databricks" => Some(Box::new(DatabricksDialect {})),
"oracle" => Some(Box::new(OracleDialect {})),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
struct DialectHolder<'a> {
dialect: &'a dyn Dialect,
}
#[test]
fn test_is_dialect() {
let generic_dialect: &dyn Dialect = &GenericDialect {};
let ansi_dialect: &dyn Dialect = &AnsiDialect {};
let generic_holder = DialectHolder {
dialect: generic_dialect,
};
let ansi_holder = DialectHolder {
dialect: ansi_dialect,
};
assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
assert!(!dialect_of!(generic_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
}
#[test]
fn test_dialect_from_str() {
assert!(parse_dialect("generic").is::<GenericDialect>());
assert!(parse_dialect("mysql").is::<MySqlDialect>());
assert!(parse_dialect("MySql").is::<MySqlDialect>());
assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
assert!(parse_dialect("hive").is::<HiveDialect>());
assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
assert!(parse_dialect("ansi").is::<AnsiDialect>());
assert!(parse_dialect("ANSI").is::<AnsiDialect>());
assert!(parse_dialect("duckdb").is::<DuckDbDialect>());
assert!(parse_dialect("DuckDb").is::<DuckDbDialect>());
assert!(parse_dialect("DataBricks").is::<DatabricksDialect>());
assert!(parse_dialect("databricks").is::<DatabricksDialect>());
assert!(dialect_from_str("Unknown").is_none());
assert!(dialect_from_str("").is_none());
}
fn parse_dialect(v: &str) -> Box<dyn Dialect> {
dialect_from_str(v).unwrap()
}
#[test]
#[cfg(feature = "derive-dialect")]
fn test_dialect_override() {
derive_dialect!(EnhancedGenericDialect, GenericDialect,
preserve_type_id = true,
overrides = {
supports_order_by_all = true,
supports_nested_comments = true,
supports_triple_quoted_string = true,
},
);
let dialect = EnhancedGenericDialect::new();
assert!(dialect.supports_order_by_all());
assert!(dialect.supports_nested_comments());
assert!(dialect.supports_triple_quoted_string());
let d: &dyn Dialect = &dialect;
assert!(d.is::<GenericDialect>());
}
#[test]
fn identifier_quote_style() {
let tests: Vec<(&dyn Dialect, &str, Option<char>)> = vec![
(&GenericDialect {}, "id", None),
(&SQLiteDialect {}, "id", Some('`')),
(&PostgreSqlDialect {}, "id", Some('"')),
];
for (dialect, ident, expected) in tests {
let actual = dialect.identifier_quote_style(ident);
assert_eq!(actual, expected);
}
}
#[test]
fn parse_with_wrapped_dialect() {
#[derive(Debug)]
struct WrappedDialect(MySqlDialect);
impl Dialect for WrappedDialect {
fn dialect(&self) -> std::any::TypeId {
self.0.dialect()
}
fn is_identifier_start(&self, ch: char) -> bool {
self.0.is_identifier_start(ch)
}
fn is_delimited_identifier_start(&self, ch: char) -> bool {
self.0.is_delimited_identifier_start(ch)
}
fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
self.0.is_nested_delimited_identifier_start(ch)
}
fn peek_nested_delimited_identifier_quotes(
&self,
chars: std::iter::Peekable<std::str::Chars<'_>>,
) -> Option<(char, Option<char>)> {
self.0.peek_nested_delimited_identifier_quotes(chars)
}
fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
self.0.identifier_quote_style(identifier)
}
fn supports_string_literal_backslash_escape(&self) -> bool {
self.0.supports_string_literal_backslash_escape()
}
fn supports_filter_during_aggregation(&self) -> bool {
self.0.supports_filter_during_aggregation()
}
fn supports_within_after_array_aggregation(&self) -> bool {
self.0.supports_within_after_array_aggregation()
}
fn supports_group_by_expr(&self) -> bool {
self.0.supports_group_by_expr()
}
fn supports_in_empty_list(&self) -> bool {
self.0.supports_in_empty_list()
}
fn convert_type_before_value(&self) -> bool {
self.0.convert_type_before_value()
}
fn parse_prefix(
&self,
parser: &mut sqlparser::parser::Parser,
) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
self.0.parse_prefix(parser)
}
fn parse_infix(
&self,
parser: &mut sqlparser::parser::Parser,
expr: &Expr,
precedence: u8,
) -> Option<Result<Expr, sqlparser::parser::ParserError>> {
self.0.parse_infix(parser, expr, precedence)
}
fn get_next_precedence(
&self,
parser: &sqlparser::parser::Parser,
) -> Option<Result<u8, sqlparser::parser::ParserError>> {
self.0.get_next_precedence(parser)
}
fn parse_statement(
&self,
parser: &mut sqlparser::parser::Parser,
) -> Option<Result<Statement, sqlparser::parser::ParserError>> {
self.0.parse_statement(parser)
}
fn is_identifier_part(&self, ch: char) -> bool {
self.0.is_identifier_part(ch)
}
}
#[allow(clippy::needless_raw_string_hashes)]
let statement = r#"SELECT 'Wayne\'s World'"#;
let res1 = Parser::parse_sql(&MySqlDialect {}, statement);
let res2 = Parser::parse_sql(&WrappedDialect(MySqlDialect {}), statement);
assert!(res1.is_ok());
assert_eq!(res1, res2);
}
}