Improve comments on Dialect (#1366)

This commit is contained in:
Andrew Lamb 2024-08-06 08:23:07 -04:00 committed by GitHub
parent a5480ae498
commit da484c57c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -66,7 +66,8 @@ macro_rules! dialect_of {
/// Encapsulates the differences between SQL implementations. /// Encapsulates the differences between SQL implementations.
/// ///
/// # SQL Dialects /// # SQL Dialects
/// SQL implementations deviatiate from one another, either due to ///
/// SQL implementations deviate from one another, either due to
/// custom extensions or various historical reasons. This trait /// custom extensions or various historical reasons. This trait
/// encapsulates the parsing differences between dialects. /// encapsulates the parsing differences between dialects.
/// ///
@ -114,16 +115,20 @@ pub trait Dialect: Debug + Any {
fn is_delimited_identifier_start(&self, ch: char) -> bool { fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '`' ch == '"' || ch == '`'
} }
/// Return the character used to quote identifiers. /// Return the character used to quote identifiers.
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> { fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
None None
} }
/// Determine if quoted characters are proper for identifier /// Determine if quoted characters are proper for identifier
fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool { fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
true true
} }
/// Determine if a character is a valid start character for an unquoted identifier /// Determine if a character is a valid start character for an unquoted identifier
fn is_identifier_start(&self, ch: char) -> bool; fn is_identifier_start(&self, ch: char) -> bool;
/// Determine if a character is a valid unquoted identifier character /// Determine if a character is a valid unquoted identifier character
fn is_identifier_part(&self, ch: char) -> bool; fn is_identifier_part(&self, ch: char) -> bool;
@ -168,6 +173,7 @@ pub trait Dialect: Debug + Any {
fn supports_filter_during_aggregation(&self) -> bool { fn supports_filter_during_aggregation(&self) -> bool {
false false
} }
/// Returns true if the dialect supports referencing another named window /// Returns true if the dialect supports referencing another named window
/// within a window clause declaration. /// within a window clause declaration.
/// ///
@ -179,6 +185,7 @@ pub trait Dialect: Debug + Any {
fn supports_window_clause_named_window_reference(&self) -> bool { fn supports_window_clause_named_window_reference(&self) -> bool {
false false
} }
/// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions. /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions.
/// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`] /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`]
/// ///
@ -186,38 +193,47 @@ pub trait Dialect: Debug + Any {
fn supports_within_after_array_aggregation(&self) -> bool { fn supports_within_after_array_aggregation(&self) -> bool {
false false
} }
/// Returns true if the dialects supports `group sets, roll up, or cube` expressions. /// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
fn supports_group_by_expr(&self) -> bool { fn supports_group_by_expr(&self) -> bool {
false false
} }
/// Returns true if the dialect supports CONNECT BY. /// Returns true if the dialect supports CONNECT BY.
fn supports_connect_by(&self) -> bool { fn supports_connect_by(&self) -> bool {
false false
} }
/// Returns true if the dialect supports the MATCH_RECOGNIZE operation. /// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
fn supports_match_recognize(&self) -> bool { fn supports_match_recognize(&self) -> bool {
false false
} }
/// Returns true if the dialect supports `(NOT) IN ()` expressions /// Returns true if the dialect supports `(NOT) IN ()` expressions
fn supports_in_empty_list(&self) -> bool { fn supports_in_empty_list(&self) -> bool {
false false
} }
/// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements /// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
fn supports_start_transaction_modifier(&self) -> bool { fn supports_start_transaction_modifier(&self) -> bool {
false false
} }
/// Returns true if the dialect supports named arguments of the form FUN(a = '1', b = '2'). /// Returns true if the dialect supports named arguments of the form FUN(a = '1', b = '2').
fn supports_named_fn_args_with_eq_operator(&self) -> bool { fn supports_named_fn_args_with_eq_operator(&self) -> bool {
false false
} }
/// Returns true if the dialect supports identifiers starting with a numeric /// Returns true if the dialect supports identifiers starting with a numeric
/// prefix such as tables named: `59901_user_login` /// prefix such as tables named `59901_user_login`
fn supports_numeric_prefix(&self) -> bool { fn supports_numeric_prefix(&self) -> bool {
false false
} }
/// Returns true if the dialects supports specifying null treatment /// Returns true if the dialects supports specifying null treatment
/// as part of a window function's parameter list. As opposed /// as part of a window function's parameter list as opposed
/// to after the parameter list. /// to after the parameter list.
///
/// i.e The following syntax returns true /// i.e The following syntax returns true
/// ```sql /// ```sql
/// FIRST_VALUE(a IGNORE NULLS) OVER () /// FIRST_VALUE(a IGNORE NULLS) OVER ()
@ -229,16 +245,19 @@ pub trait Dialect: Debug + Any {
fn supports_window_function_null_treatment_arg(&self) -> bool { fn supports_window_function_null_treatment_arg(&self) -> bool {
false false
} }
/// Returns true if the dialect supports defining structs or objects using a /// Returns true if the dialect supports defining structs or objects using a
/// syntax like `{'x': 1, 'y': 2, 'z': 3}`. /// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
fn supports_dictionary_syntax(&self) -> bool { fn supports_dictionary_syntax(&self) -> bool {
false false
} }
/// Returns true if the dialect supports defining object using the /// Returns true if the dialect supports defining object using the
/// syntax like `Map {1: 10, 2: 20}`. /// syntax like `Map {1: 10, 2: 20}`.
fn support_map_literal_syntax(&self) -> bool { fn support_map_literal_syntax(&self) -> bool {
false false
} }
/// Returns true if the dialect supports lambda functions, for example: /// Returns true if the dialect supports lambda functions, for example:
/// ///
/// ```sql /// ```sql
@ -247,6 +266,7 @@ pub trait Dialect: Debug + Any {
fn supports_lambda_functions(&self) -> bool { fn supports_lambda_functions(&self) -> bool {
false false
} }
/// Returns true if the dialect supports multiple variable assignment /// Returns true if the dialect supports multiple variable assignment
/// using parentheses in a `SET` variable declaration. /// using parentheses in a `SET` variable declaration.
/// ///
@ -256,6 +276,7 @@ pub trait Dialect: Debug + Any {
fn supports_parenthesized_set_variables(&self) -> bool { fn supports_parenthesized_set_variables(&self) -> bool {
false false
} }
/// Returns true if the dialect supports an `EXCEPT` clause following a /// Returns true if the dialect supports an `EXCEPT` clause following a
/// wildcard in a select list. /// wildcard in a select list.
/// ///
@ -266,30 +287,40 @@ pub trait Dialect: Debug + Any {
fn supports_select_wildcard_except(&self) -> bool { fn supports_select_wildcard_except(&self) -> bool {
false false
} }
/// Returns true if the dialect has a CONVERT function which accepts a type first /// Returns true if the dialect has a CONVERT function which accepts a type first
/// and an expression second, e.g. `CONVERT(varchar, 1)` /// and an expression second, e.g. `CONVERT(varchar, 1)`
fn convert_type_before_value(&self) -> bool { fn convert_type_before_value(&self) -> bool {
false false
} }
/// Returns true if the dialect supports triple quoted string /// Returns true if the dialect supports triple quoted string
/// e.g. `"""abc"""` /// e.g. `"""abc"""`
fn supports_triple_quoted_string(&self) -> bool { fn supports_triple_quoted_string(&self) -> bool {
false false
} }
/// Dialect-specific prefix parser override /// Dialect-specific prefix parser override
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> { fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
// return None to fall back to the default behavior // return None to fall back to the default behavior
None None
} }
/// Does the dialect support trailing commas around the query? /// Does the dialect support trailing commas around the query?
fn supports_trailing_commas(&self) -> bool { fn supports_trailing_commas(&self) -> bool {
false false
} }
/// Does the dialect support trailing commas in the projection list? /// Does the dialect support trailing commas in the projection list?
fn supports_projection_trailing_commas(&self) -> bool { fn supports_projection_trailing_commas(&self) -> bool {
self.supports_trailing_commas() self.supports_trailing_commas()
} }
/// Dialect-specific infix parser override /// Dialect-specific infix parser override
///
/// This method is called to parse the next infix expression.
///
/// If `None` is returned, falls back to the default behavior.
fn parse_infix( fn parse_infix(
&self, &self,
_parser: &mut Parser, _parser: &mut Parser,
@ -299,24 +330,33 @@ pub trait Dialect: Debug + Any {
// return None to fall back to the default behavior // return None to fall back to the default behavior
None None
} }
/// Dialect-specific precedence override /// Dialect-specific precedence override
///
/// This method is called to get the precedence of the next token.
///
/// If `None` is returned, falls back to the default behavior.
fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> { fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
// return None to fall back to the default behavior // return None to fall back to the default behavior
None None
} }
/// Get the precedence of the next token. This "full" method means all precedence logic and remain /// Get the precedence of the next token, looking at the full token stream.
/// in the dialect. while still allowing overriding the `get_next_precedence` method with the option to
/// fallback to the default behavior.
/// ///
/// Higher number => higher precedence /// A higher number => higher precedence
///
/// See [`Self::get_next_precedence`] to override the behavior for just the
/// next token.
///
/// The default implementation is used for many dialects, but can be
/// overridden to provide dialect-specific behavior.
fn get_next_precedence_full(&self, parser: &Parser) -> Result<u8, ParserError> { fn get_next_precedence_full(&self, parser: &Parser) -> Result<u8, ParserError> {
if let Some(precedence) = self.get_next_precedence(parser) { if let Some(precedence) = self.get_next_precedence(parser) {
return precedence; return precedence;
} }
let token = parser.peek_token(); let token = parser.peek_token();
debug!("get_next_precedence() {:?}", token); debug!("get_next_precedence_full() {:?}", token);
match token.token { match token.token {
Token::Word(w) if w.keyword == Keyword::OR => Ok(OR_PREC), Token::Word(w) if w.keyword == Keyword::OR => Ok(OR_PREC),
Token::Word(w) if w.keyword == Keyword::AND => Ok(AND_PREC), Token::Word(w) if w.keyword == Keyword::AND => Ok(AND_PREC),
@ -408,37 +448,67 @@ pub trait Dialect: Debug + Any {
} }
/// Dialect-specific statement parser override /// Dialect-specific statement parser override
///
/// This method is called to parse the next statement.
///
/// If `None` is returned, falls back to the default behavior.
fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> { fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
// return None to fall back to the default behavior // return None to fall back to the default behavior
None None
} }
/// The following precedence values are used directly by `Parse` or in dialects, // The following precedence values are used directly by `Parse` or in dialects,
/// so have to be made public by the dialect. // so have to be made public by the dialect.
/// Return the precedence of the `::` operator.
///
/// Default is 50.
fn prec_double_colon(&self) -> u8 { fn prec_double_colon(&self) -> u8 {
DOUBLE_COLON_PREC DOUBLE_COLON_PREC
} }
/// Return the precedence of `*`, `/`, and `%` operators.
///
/// Default is 40.
fn prec_mul_div_mod_op(&self) -> u8 { fn prec_mul_div_mod_op(&self) -> u8 {
MUL_DIV_MOD_OP_PREC MUL_DIV_MOD_OP_PREC
} }
/// Return the precedence of the `+` and `-` operators.
///
/// Default is 30.
fn prec_plus_minus(&self) -> u8 { fn prec_plus_minus(&self) -> u8 {
PLUS_MINUS_PREC PLUS_MINUS_PREC
} }
/// Return the precedence of the `BETWEEN` operator.
///
/// For example `BETWEEN <low> AND <high>`
///
/// Default is 22.
fn prec_between(&self) -> u8 { fn prec_between(&self) -> u8 {
BETWEEN_PREC BETWEEN_PREC
} }
/// Return the precedence of the `LIKE` operator.
///
/// Default is 19.
fn prec_like(&self) -> u8 { fn prec_like(&self) -> u8 {
LIKE_PREC LIKE_PREC
} }
/// Return the precedence of the unary `NOT` operator.
///
/// For example `NOT (a OR b)`
///
/// Default is 15.
fn prec_unary_not(&self) -> u8 { fn prec_unary_not(&self) -> u8 {
UNARY_NOT_PREC UNARY_NOT_PREC
} }
/// Return the default (unknown) precedence.
///
/// Default is 0.
fn prec_unknown(&self) -> u8 { fn prec_unknown(&self) -> u8 {
UNKNOWN_PREC UNKNOWN_PREC
} }