Skip to content

Improve comments on Dialect #1366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 80 additions & 10 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ macro_rules! dialect_of {
/// Encapsulates the differences between SQL implementations.
///
/// # 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
/// encapsulates the parsing differences between dialects.
///
Expand Down Expand Up @@ -114,16 +115,20 @@ pub trait Dialect: Debug + Any {
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '`'
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the use of whitespace between functions was inconsistent -- sometimes there was a space and sometimes not. Thus I made it all consistent with my personal preference (put a space between functions0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I really wish rustfmt would fix this to be consistent.

/// Return the character used to quote identifiers.
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
None
}

/// Determine if quoted characters are proper for identifier
fn is_proper_identifier_inside_quotes(&self, mut _chars: Peekable<Chars<'_>>) -> bool {
true
}

/// Determine if a character is a valid start character for an unquoted identifier
fn is_identifier_start(&self, ch: char) -> bool;

/// Determine if a character is a valid unquoted identifier character
fn is_identifier_part(&self, ch: char) -> bool;

Expand Down Expand Up @@ -168,6 +173,7 @@ pub trait Dialect: Debug + Any {
fn supports_filter_during_aggregation(&self) -> bool {
false
}

/// Returns true if the dialect supports referencing another named window
/// within a window clause declaration.
///
Expand All @@ -179,45 +185,55 @@ pub trait Dialect: Debug + Any {
fn supports_window_clause_named_window_reference(&self) -> bool {
false
}

/// 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`]
///
/// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function
fn supports_within_after_array_aggregation(&self) -> bool {
false
}

/// Returns true if the dialects supports `group sets, roll up, or cube` expressions.
fn supports_group_by_expr(&self) -> bool {
false
}

/// Returns true if the dialect supports CONNECT BY.
fn supports_connect_by(&self) -> bool {
false
}

/// Returns true if the dialect supports the MATCH_RECOGNIZE operation.
fn supports_match_recognize(&self) -> bool {
false
}

/// Returns true if the dialect supports `(NOT) IN ()` expressions
fn supports_in_empty_list(&self) -> bool {
false
}

/// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
fn supports_start_transaction_modifier(&self) -> bool {
false
}

/// 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 {
false
}

/// 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 {
false
}

/// 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.
///
/// i.e The following syntax returns true
/// ```sql
/// FIRST_VALUE(a IGNORE NULLS) OVER ()
Expand All @@ -229,16 +245,19 @@ pub trait Dialect: Debug + Any {
fn supports_window_function_null_treatment_arg(&self) -> bool {
false
}

/// Returns true if the dialect supports defining structs or objects using a
/// syntax like `{'x': 1, 'y': 2, 'z': 3}`.
fn supports_dictionary_syntax(&self) -> bool {
false
}

/// Returns true if the dialect supports defining object using the
/// syntax like `Map {1: 10, 2: 20}`.
fn support_map_literal_syntax(&self) -> bool {
false
}

/// Returns true if the dialect supports lambda functions, for example:
///
/// ```sql
Expand All @@ -247,6 +266,7 @@ pub trait Dialect: Debug + Any {
fn supports_lambda_functions(&self) -> bool {
false
}

/// Returns true if the dialect supports multiple variable assignment
/// using parentheses in a `SET` variable declaration.
///
Expand All @@ -256,6 +276,7 @@ pub trait Dialect: Debug + Any {
fn supports_parenthesized_set_variables(&self) -> bool {
false
}

/// Returns true if the dialect supports an `EXCEPT` clause following a
/// wildcard in a select list.
///
Expand All @@ -266,30 +287,40 @@ pub trait Dialect: Debug + Any {
fn supports_select_wildcard_except(&self) -> bool {
false
}

/// Returns true if the dialect has a CONVERT function which accepts a type first
/// and an expression second, e.g. `CONVERT(varchar, 1)`
fn convert_type_before_value(&self) -> bool {
false
}

/// Returns true if the dialect supports triple quoted string
/// e.g. `"""abc"""`
fn supports_triple_quoted_string(&self) -> bool {
false
}

/// Dialect-specific prefix parser override
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
// return None to fall back to the default behavior
None
}

/// Does the dialect support trailing commas around the query?
fn supports_trailing_commas(&self) -> bool {
false
}

/// Does the dialect support trailing commas in the projection list?
fn supports_projection_trailing_commas(&self) -> bool {
self.supports_trailing_commas()
}

/// 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(
&self,
_parser: &mut Parser,
Expand All @@ -299,24 +330,33 @@ pub trait Dialect: Debug + Any {
// return None to fall back to the default behavior
None
}

/// 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>> {
// return None to fall back to the default behavior
None
}

/// Get the precedence of the next token. This "full" method means all precedence logic and remain
/// in the dialect. while still allowing overriding the `get_next_precedence` method with the option to
/// fallback to the default behavior.
/// Get the precedence of the next token, looking at the full token stream.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this, sorry my comment was so broken.

I'm not sure "full token stream" is really the right distinction, my name was probably poor.

If we didn't might breaking the API, we could probably call the above get_next_precedence_opt - the only real difference is that it returns an Option so can fallback to the default behaviour.

Or we could call this method get_next_precedence_default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't yet released this PR so we can change the name without any API breakages yet

Any chance you can make a PR with a proposed name change?

Copy link
Contributor Author

@alamb alamb Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samuelcolvin made a PR here: #1378 ❤️

///
/// 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> {
if let Some(precedence) = self.get_next_precedence(parser) {
return precedence;
}

let token = parser.peek_token();
debug!("get_next_precedence() {:?}", token);
debug!("get_next_precedence_full() {:?}", token);
match token.token {
Token::Word(w) if w.keyword == Keyword::OR => Ok(OR_PREC),
Token::Word(w) if w.keyword == Keyword::AND => Ok(AND_PREC),
Expand Down Expand Up @@ -408,37 +448,67 @@ pub trait Dialect: Debug + Any {
}

/// 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>> {
// return None to fall back to the default behavior
None
}

/// The following precedence values are used directly by `Parse` or in dialects,
/// so have to be made public by the dialect.
// The following precedence values are used directly by `Parse` or in dialects,
// so have to be made public by the dialect.

/// Return the precedence of the `::` operator.
///
/// Default is 50.
fn prec_double_colon(&self) -> u8 {
DOUBLE_COLON_PREC
}

/// Return the precedence of `*`, `/`, and `%` operators.
///
/// Default is 40.
fn prec_mul_div_mod_op(&self) -> u8 {
MUL_DIV_MOD_OP_PREC
}

/// Return the precedence of the `+` and `-` operators.
///
/// Default is 30.
fn prec_plus_minus(&self) -> u8 {
PLUS_MINUS_PREC
}

/// Return the precedence of the `BETWEEN` operator.
///
/// For example `BETWEEN <low> AND <high>`
///
/// Default is 22.
fn prec_between(&self) -> u8 {
BETWEEN_PREC
}

/// Return the precedence of the `LIKE` operator.
///
/// Default is 19.
fn prec_like(&self) -> u8 {
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 {
UNARY_NOT_PREC
}

/// Return the default (unknown) precedence.
///
/// Default is 0.
fn prec_unknown(&self) -> u8 {
UNKNOWN_PREC
}
Expand Down
Loading