From 7ff24bee75007d4c19dcd6ed7cc2683b9644e95d Mon Sep 17 00:00:00 2001 From: finchxxia <13153363548@163.com> Date: Thu, 18 Jun 2026 12:53:44 +0800 Subject: [PATCH] Doris: Add dialect skeleton --- examples/cli.rs | 1 + src/dialect/doris.rs | 53 ++++++++++++++++++++++++++++++++++++++ src/dialect/mod.rs | 5 ++++ src/test_utils.rs | 1 + tests/sqlparser_doris.rs | 55 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 src/dialect/doris.rs create mode 100644 tests/sqlparser_doris.rs diff --git a/examples/cli.rs b/examples/cli.rs index 3c4299b209..e5643dc0be 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -52,6 +52,7 @@ $ cargo run --example cli - [--dialectname] "--postgres" => Box::new(PostgreSqlDialect {}), "--ms" => Box::new(MsSqlDialect {}), "--mysql" => Box::new(MySqlDialect {}), + "--doris" => Box::new(DorisDialect {}), "--snowflake" => Box::new(SnowflakeDialect {}), "--hive" => Box::new(HiveDialect {}), "--redshift" => Box::new(RedshiftSqlDialect {}), diff --git a/src/dialect/doris.rs b/src/dialect/doris.rs new file mode 100644 index 0000000000..17911fd7ab --- /dev/null +++ b/src/dialect/doris.rs @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use crate::dialect::Dialect; + +/// A [`Dialect`] for [Apache Doris](https://doris.apache.org/). +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DorisDialect {} + +impl Dialect for DorisDialect { + fn is_delimited_identifier_start(&self, ch: char) -> bool { + ch == '`' + } + + fn identifier_quote_style(&self, _identifier: &str) -> Option { + Some('`') + } + + fn is_identifier_start(&self, ch: char) -> bool { + ch.is_ascii_alphabetic() || ch == '_' || !ch.is_ascii() + } + + 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 ignores_wildcard_escapes(&self) -> bool { + true + } + + fn supports_numeric_prefix(&self) -> bool { + true + } +} diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index efabfeb1f4..4b6d3673ad 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -19,6 +19,7 @@ mod ansi; mod bigquery; mod clickhouse; mod databricks; +mod doris; mod duckdb; mod generic; mod hive; @@ -43,6 +44,7 @@ pub use self::ansi::AnsiDialect; pub use self::bigquery::BigQueryDialect; pub use self::clickhouse::ClickHouseDialect; pub use self::databricks::DatabricksDialect; +pub use self::doris::DorisDialect; pub use self::duckdb::DuckDbDialect; pub use self::generic::GenericDialect; pub use self::hive::HiveDialect; @@ -1908,6 +1910,7 @@ pub fn dialect_from_str(dialect_name: impl AsRef) -> Option Some(Box::new(BigQueryDialect)), "ansi" => Some(Box::new(AnsiDialect {})), "duckdb" => Some(Box::new(DuckDbDialect {})), + "doris" => Some(Box::new(DorisDialect {})), "databricks" => Some(Box::new(DatabricksDialect {})), "spark" | "sparksql" => Some(Box::new(SparkSqlDialect {})), "oracle" => Some(Box::new(OracleDialect {})), @@ -1963,6 +1966,8 @@ mod tests { assert!(parse_dialect("ANSI").is::()); assert!(parse_dialect("duckdb").is::()); assert!(parse_dialect("DuckDb").is::()); + assert!(parse_dialect("doris").is::()); + assert!(parse_dialect("Doris").is::()); assert!(parse_dialect("DataBricks").is::()); assert!(parse_dialect("databricks").is::()); assert!(parse_dialect("teradata").is::()); diff --git a/src/test_utils.rs b/src/test_utils.rs index c4d1d0db2e..e19f28d202 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -286,6 +286,7 @@ pub fn all_dialects() -> TestedDialects { Box::new(HiveDialect {}), Box::new(RedshiftSqlDialect {}), Box::new(MySqlDialect {}), + Box::new(DorisDialect {}), Box::new(BigQueryDialect {}), Box::new(SQLiteDialect {}), Box::new(DuckDbDialect {}), diff --git a/tests/sqlparser_doris.rs b/tests/sqlparser_doris.rs new file mode 100644 index 0000000000..31ed99864f --- /dev/null +++ b/tests/sqlparser_doris.rs @@ -0,0 +1,55 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#![warn(clippy::all)] +//! Test SQL syntax specific to Apache Doris. + +#[macro_use] +mod test_utils; + +use sqlparser::dialect::{Dialect, DorisDialect, GenericDialect}; +use test_utils::*; + +fn doris() -> TestedDialects { + TestedDialects::new(vec![Box::new(DorisDialect {})]) +} + +fn doris_and_generic() -> TestedDialects { + TestedDialects::new(vec![Box::new(DorisDialect {}), Box::new(GenericDialect {})]) +} + +#[test] +fn doris_identifier_and_string_literal_gates() { + let dialect = DorisDialect {}; + assert_eq!(dialect.identifier_quote_style("identifier"), Some('`')); + assert!(dialect.is_delimited_identifier_start('`')); + assert!(dialect.supports_string_literal_backslash_escape()); + assert!(dialect.ignores_wildcard_escapes()); + assert!(dialect.supports_numeric_prefix()); +} + +#[test] +fn parse_doris_strings_and_identifiers() { + doris().verified_stmt( + r#"SELECT "double quoted string", 'single quoted string', `select` FROM `db`.`table`"#, + ); +} + +#[test] +fn doris_and_generic_parse_common_sql_identically() { + doris_and_generic().verified_stmt("SELECT 1 AS properties FROM t"); +}