Skip to content

move primitive dialect configuration into a struct #1431

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let sql = "SELECT a, b, 123, myfunc(b) \
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";

let dialect = GenericDialect {}; // or AnsiDialect, or your own dialect ...
let dialect = GenericDialect::default(); // or AnsiDialect, or your own dialect ...

let ast = Parser::parse_sql(&dialect, sql).unwrap();

Expand Down
24 changes: 12 additions & 12 deletions examples/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ $ cargo run --feature json_example --example cli FILENAME.sql [--dialectname]
);

let dialect: Box<dyn Dialect> = match std::env::args().nth(2).unwrap_or_default().as_ref() {
"--ansi" => Box::new(AnsiDialect {}),
"--bigquery" => Box::new(BigQueryDialect {}),
"--postgres" => Box::new(PostgreSqlDialect {}),
"--ms" => Box::new(MsSqlDialect {}),
"--mysql" => Box::new(MySqlDialect {}),
"--snowflake" => Box::new(SnowflakeDialect {}),
"--hive" => Box::new(HiveDialect {}),
"--redshift" => Box::new(RedshiftSqlDialect {}),
"--clickhouse" => Box::new(ClickHouseDialect {}),
"--duckdb" => Box::new(DuckDbDialect {}),
"--sqlite" => Box::new(SQLiteDialect {}),
"--generic" | "" => Box::new(GenericDialect {}),
"--ansi" => Box::new(AnsiDialect::default()),
"--bigquery" => Box::new(BigQueryDialect::default()),
"--postgres" => Box::new(PostgreSqlDialect::default()),
"--ms" => Box::new(MsSqlDialect::default()),
"--mysql" => Box::new(MySqlDialect::default()),
"--snowflake" => Box::new(SnowflakeDialect::default()),
"--hive" => Box::new(HiveDialect::default()),
"--redshift" => Box::new(RedshiftSqlDialect::default()),
"--clickhouse" => Box::new(ClickHouseDialect::default()),
"--duckdb" => Box::new(DuckDbDialect::default()),
"--sqlite" => Box::new(SQLiteDialect::default()),
"--generic" | "" => Box::new(GenericDialect::default()),
s => panic!("Unexpected parameter: {s}"),
};

Expand Down
2 changes: 1 addition & 1 deletion examples/parse_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";

let dialect = GenericDialect {};
let dialect = GenericDialect::default();

let ast = Parser::parse_sql(&dialect, sql).unwrap();

Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/fuzz_parse_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use sqlparser::parser::Parser;
fn main() {
loop {
fuzz!(|data: String| {
let dialect = GenericDialect {};
let dialect = GenericDialect::default();
let _ = Parser::parse_sql(&dialect, &data);
});
}
Expand Down
2 changes: 1 addition & 1 deletion sqlparser_bench/benches/sqlparser_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use sqlparser::parser::Parser;

fn basic_queries(c: &mut Criterion) {
let mut group = c.benchmark_group("sqlparser-rs parsing benchmark");
let dialect = GenericDialect {};
let dialect = GenericDialect::default();

let string = "SELECT * FROM table WHERE 1 = 1";
group.bench_function("sqlparser::select", |b| {
Expand Down
20 changes: 10 additions & 10 deletions src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ visit_noop!(bigdecimal::BigDecimal);
/// }
///
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
/// let statements = Parser::parse_sql(&GenericDialect::default(), sql)
/// .unwrap();
///
/// // Drive the visitor through the AST
Expand Down Expand Up @@ -266,7 +266,7 @@ pub trait Visitor {
/// }
///
/// let sql = "SELECT to_replace FROM foo where to_replace IN (SELECT to_replace FROM bar)";
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();
/// let mut statements = Parser::parse_sql(&GenericDialect::default(), sql).unwrap();
///
/// // Drive the visitor through the AST
/// statements.visit(&mut Replacer);
Expand Down Expand Up @@ -361,7 +361,7 @@ impl<E, F: FnMut(&mut ObjectName) -> ControlFlow<E>> VisitorMut for RelationVisi
/// # use sqlparser::ast::{visit_relations};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
/// let statements = Parser::parse_sql(&GenericDialect::default(), sql)
/// .unwrap();
///
/// // visit statements, capturing relations (table names)
Expand Down Expand Up @@ -401,7 +401,7 @@ where
/// # use sqlparser::ast::{ObjectName, visit_relations_mut};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT a FROM foo";
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql)
/// let mut statements = Parser::parse_sql(&GenericDialect::default(), sql)
/// .unwrap();
///
/// // visit statements, renaming table foo to bar
Expand Down Expand Up @@ -449,7 +449,7 @@ impl<E, F: FnMut(&mut Expr) -> ControlFlow<E>> VisitorMut for ExprVisitor<F> {
/// # use sqlparser::ast::{visit_expressions};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
/// let statements = Parser::parse_sql(&GenericDialect::default(), sql)
/// .unwrap();
///
/// // visit all expressions
Expand Down Expand Up @@ -493,7 +493,7 @@ where
/// # use sqlparser::ast::{Expr, visit_expressions_mut, visit_statements_mut};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT (SELECT y FROM z LIMIT 9) FROM t LIMIT 3";
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();
/// let mut statements = Parser::parse_sql(&GenericDialect::default(), sql).unwrap();
///
/// // Remove all select limits in sub-queries
/// visit_expressions_mut(&mut statements, |expr| {
Expand All @@ -518,7 +518,7 @@ where
/// # use sqlparser::ast::*;
/// # use core::ops::ControlFlow;
/// let sql = "SELECT x, y FROM t";
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();
/// let mut statements = Parser::parse_sql(&GenericDialect::default(), sql).unwrap();
///
/// visit_expressions_mut(&mut statements, |expr| {
/// if matches!(expr, Expr::Identifier(col_name) if col_name.value == "x") {
Expand Down Expand Up @@ -579,7 +579,7 @@ impl<E, F: FnMut(&mut Statement) -> ControlFlow<E>> VisitorMut for StatementVisi
/// # use sqlparser::ast::{visit_statements};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar); CREATE TABLE baz(q int)";
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
/// let statements = Parser::parse_sql(&GenericDialect::default(), sql)
/// .unwrap();
///
/// // visit all statements
Expand Down Expand Up @@ -616,7 +616,7 @@ where
/// # use sqlparser::ast::{Statement, visit_statements_mut};
/// # use core::ops::ControlFlow;
/// let sql = "SELECT x FROM foo LIMIT 9+$limit; SELECT * FROM t LIMIT f()";
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();
/// let mut statements = Parser::parse_sql(&GenericDialect::default(), sql).unwrap();
///
/// // Remove all select limits in outer statements (not in sub-queries)
/// visit_statements_mut(&mut statements, |stmt| {
Expand Down Expand Up @@ -715,7 +715,7 @@ mod tests {
}

fn do_visit(sql: &str) -> Vec<String> {
let dialect = GenericDialect {};
let dialect = GenericDialect::default();
let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap();
let s = Parser::new(&dialect)
.with_tokens(tokens)
Expand Down
21 changes: 15 additions & 6 deletions src/dialect/ansi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::dialect::Dialect;
use crate::dialect::{Dialect, DialectFlags};

/// A [`Dialect`] for [ANSI SQL](https://en.wikipedia.org/wiki/SQL:2011).
#[derive(Debug)]
pub struct AnsiDialect {}
pub struct AnsiDialect(DialectFlags);

impl Default for AnsiDialect {
fn default() -> Self {
Self(DialectFlags {
require_interval_qualifier: true,
..Default::default()
})
}
}

impl Dialect for AnsiDialect {
fn flags(&self) -> &DialectFlags {
&self.0
}

fn is_identifier_start(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase()
}

fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
}

fn require_interval_qualifier(&self) -> bool {
true
}
}
66 changes: 29 additions & 37 deletions src/dialect/bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,39 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::dialect::Dialect;
use crate::dialect::{Dialect, DialectFlags};

/// A [`Dialect`] for [Google Bigquery](https://cloud.google.com/bigquery/)
#[derive(Debug, Default)]
pub struct BigQueryDialect;
#[derive(Debug)]
pub struct BigQueryDialect(DialectFlags);

impl Default for BigQueryDialect {
fn default() -> Self {
Self(DialectFlags {
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals
supports_triple_quoted_string: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions#first_value
supports_window_function_null_treatment_arg: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#escape_sequences
supports_string_literal_backslash_escape: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/window-function-calls#ref_named_window
supports_window_clause_named_window_reference: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#set
supports_parenthesized_set_variables: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_except
supports_select_wildcard_except: true,
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#interval_type
require_interval_qualifier: true,
..Default::default()
})
}
}

impl Dialect for BigQueryDialect {
fn flags(&self) -> &DialectFlags {
&self.0
}

// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#identifiers
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`'
Expand All @@ -33,38 +59,4 @@ impl Dialect for BigQueryDialect {
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
}

/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
fn supports_triple_quoted_string(&self) -> bool {
true
}

/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions#first_value)
fn supports_window_function_null_treatment_arg(&self) -> bool {
true
}

// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#escape_sequences
fn supports_string_literal_backslash_escape(&self) -> bool {
true
}

/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/window-function-calls#ref_named_window)
fn supports_window_clause_named_window_reference(&self) -> bool {
true
}

/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#set)
fn supports_parenthesized_set_variables(&self) -> bool {
true
}

// See https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_except
fn supports_select_wildcard_except(&self) -> bool {
true
}

fn require_interval_qualifier(&self) -> bool {
true
}
}
36 changes: 18 additions & 18 deletions src/dialect/clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::dialect::Dialect;
use crate::dialect::{Dialect, DialectFlags};

// A [`Dialect`] for [ClickHouse](https://clickhouse.com/).
#[derive(Debug)]
pub struct ClickHouseDialect {}
pub struct ClickHouseDialect(DialectFlags);

impl Default for ClickHouseDialect {
fn default() -> Self {
Self(DialectFlags {
supports_string_literal_backslash_escape: true,
supports_select_wildcard_except: true,
describe_requires_table_keyword: true,
require_interval_qualifier: true,
..Default::default()
})
}
}

impl Dialect for ClickHouseDialect {
fn flags(&self) -> &DialectFlags {
&self.0
}

fn is_identifier_start(&self, ch: char) -> bool {
// See https://clickhouse.com/docs/en/sql-reference/syntax/#syntax-identifiers
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
Expand All @@ -25,20 +41,4 @@ impl Dialect for ClickHouseDialect {
fn is_identifier_part(&self, ch: char) -> bool {
self.is_identifier_start(ch) || ch.is_ascii_digit()
}

fn supports_string_literal_backslash_escape(&self) -> bool {
true
}

fn supports_select_wildcard_except(&self) -> bool {
true
}

fn describe_requires_table_keyword(&self) -> bool {
true
}

fn require_interval_qualifier(&self) -> bool {
true
}
}
48 changes: 22 additions & 26 deletions src/dialect/databricks.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
use crate::dialect::Dialect;
use crate::dialect::{Dialect, DialectFlags};

/// A [`Dialect`] for [Databricks SQL](https://www.databricks.com/)
///
/// See <https://docs.databricks.com/en/sql/language-manual/index.html>.
#[derive(Debug, Default)]
pub struct DatabricksDialect;
#[derive(Debug)]
pub struct DatabricksDialect(DialectFlags);

impl Default for DatabricksDialect {
fn default() -> Self {
Self(DialectFlags {
supports_filter_during_aggregation: true,
// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-groupby.html
supports_group_by_expr: true,
supports_lambda_functions: true,
// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select.html#syntax
supports_select_wildcard_except: true,
require_interval_qualifier: true,
..Default::default()
})
}
}

/// see <https://docs.databricks.com/en/sql/language-manual/sql-ref-identifiers.html>
impl Dialect for DatabricksDialect {
// see https://docs.databricks.com/en/sql/language-manual/sql-ref-identifiers.html
fn flags(&self) -> &DialectFlags {
&self.0
}

fn is_delimited_identifier_start(&self, ch: char) -> bool {
matches!(ch, '`')
Expand All @@ -20,26 +38,4 @@ impl Dialect for DatabricksDialect {
fn is_identifier_part(&self, ch: char) -> bool {
matches!(ch, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')
}

fn supports_filter_during_aggregation(&self) -> bool {
true
}

// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-groupby.html
fn supports_group_by_expr(&self) -> bool {
true
}

fn supports_lambda_functions(&self) -> bool {
true
}

// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select.html#syntax
fn supports_select_wildcard_except(&self) -> bool {
true
}

fn require_interval_qualifier(&self) -> bool {
true
}
}
Loading
Loading