You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2025/12/02 10:13:49 UTC
(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2113-367aa6e8d0fe696c16dbeb9a89f7305860e2e7c2 created (now defe9396)
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a change to branch gh-readonly-queue/main/pr-2113-367aa6e8d0fe696c16dbeb9a89f7305860e2e7c2
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
at defe9396 Introduce Oracle dialect (#2113)
This branch includes the following new commits:
new defe9396 Introduce Oracle dialect (#2113)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org
(datafusion-sqlparser-rs) 01/01: Introduce Oracle dialect (#2113)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch gh-readonly-queue/main/pr-2113-367aa6e8d0fe696c16dbeb9a89f7305860e2e7c2
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit defe9396e52b889bb1f0b0606d9df3dfae351e18
Author: xitep <xi...@users.noreply.github.com>
AuthorDate: Tue Dec 2 11:13:24 2025 +0100
Introduce Oracle dialect (#2113)
---
examples/cli.rs | 1 +
src/dialect/mod.rs | 3 ++
src/dialect/oracle.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++
src/keywords.rs | 9 ++++++
src/parser/mod.rs | 2 +-
src/test_utils.rs | 1 +
tests/sqlparser_common.rs | 14 +++++---
7 files changed, 105 insertions(+), 6 deletions(-)
diff --git a/examples/cli.rs b/examples/cli.rs
index 08a40a6d..3c4299b2 100644
--- a/examples/cli.rs
+++ b/examples/cli.rs
@@ -58,6 +58,7 @@ $ cargo run --example cli - [--dialectname]
"--clickhouse" => Box::new(ClickHouseDialect {}),
"--duckdb" => Box::new(DuckDbDialect {}),
"--sqlite" => Box::new(SQLiteDialect {}),
+ "--oracle" => Box::new(OracleDialect {}),
"--generic" | "" => Box::new(GenericDialect {}),
s => panic!("Unexpected parameter: {s}"),
};
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index ef4e1cdd..83c6da48 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -24,6 +24,7 @@ mod generic;
mod hive;
mod mssql;
mod mysql;
+mod oracle;
mod postgresql;
mod redshift;
mod snowflake;
@@ -45,6 +46,7 @@ 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;
@@ -1260,6 +1262,7 @@ pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect
"ansi" => Some(Box::new(AnsiDialect {})),
"duckdb" => Some(Box::new(DuckDbDialect {})),
"databricks" => Some(Box::new(DatabricksDialect {})),
+ "oracle" => Some(Box::new(OracleDialect {})),
_ => None,
}
}
diff --git a/src/dialect/oracle.rs b/src/dialect/oracle.rs
new file mode 100644
index 00000000..0d6aee5e
--- /dev/null
+++ b/src/dialect/oracle.rs
@@ -0,0 +1,81 @@
+// 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 super::Dialect;
+
+/// A [`Dialect`] for [Oracle Databases](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/index.html)
+#[derive(Debug)]
+pub struct OracleDialect;
+
+impl Dialect for OracleDialect {
+ // ~ appears not to be called anywhere
+ fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
+ Some('"')
+ }
+
+ fn is_delimited_identifier_start(&self, ch: char) -> bool {
+ ch == '"'
+ }
+
+ fn is_identifier_start(&self, ch: char) -> bool {
+ ch.is_alphabetic()
+ }
+
+ fn is_identifier_part(&self, ch: char) -> bool {
+ ch.is_alphanumeric() || ch == '_' || ch == '$' || ch == '#' || ch == '@'
+ }
+
+ fn supports_outer_join_operator(&self) -> bool {
+ true
+ }
+
+ fn supports_connect_by(&self) -> bool {
+ true
+ }
+
+ fn supports_execute_immediate(&self) -> bool {
+ true
+ }
+
+ fn supports_match_recognize(&self) -> bool {
+ true
+ }
+
+ fn supports_window_function_null_treatment_arg(&self) -> bool {
+ true
+ }
+
+ fn supports_boolean_literals(&self) -> bool {
+ false
+ }
+
+ fn supports_comment_on(&self) -> bool {
+ true
+ }
+
+ fn supports_create_table_select(&self) -> bool {
+ true
+ }
+
+ fn supports_set_stmt_without_operator(&self) -> bool {
+ true
+ }
+
+ fn supports_group_by_expr(&self) -> bool {
+ true
+ }
+}
diff --git a/src/keywords.rs b/src/keywords.rs
index 834d3495..827df1ce 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -220,6 +220,7 @@ define_keywords!(
COMMITTED,
COMMUTATOR,
COMPATIBLE,
+ COMPRESS,
COMPRESSION,
COMPUPDATE,
COMPUTE,
@@ -464,6 +465,7 @@ define_keywords!(
IAM_ROLE,
ICEBERG,
ID,
+ IDENTIFIED,
IDENTITY,
IDENTITY_INSERT,
IF,
@@ -567,6 +569,7 @@ define_keywords!(
LOG,
LOGIN,
LOGS,
+ LONG,
LONGBLOB,
LONGTEXT,
LOWCARDINALITY,
@@ -652,6 +655,7 @@ define_keywords!(
NFKD,
NO,
NOBYPASSRLS,
+ NOCOMPRESS,
NOCREATEDB,
NOCREATEROLE,
NOINHERIT,
@@ -675,6 +679,7 @@ define_keywords!(
NULLABLE,
NULLIF,
NULLS,
+ NUMBER,
NUMERIC,
NVARCHAR,
OBJECT,
@@ -741,6 +746,7 @@ define_keywords!(
PAST,
PATH,
PATTERN,
+ PCTFREE,
PER,
PERCENT,
PERCENTILE_CONT,
@@ -913,6 +919,7 @@ define_keywords!(
SIGNED,
SIMILAR,
SIMPLE,
+ SIZE,
SKIP,
SLOW,
SMALLINT,
@@ -974,6 +981,7 @@ define_keywords!(
SWAP,
SYMMETRIC,
SYNC,
+ SYNONYM,
SYSTEM,
SYSTEM_TIME,
SYSTEM_USER,
@@ -1085,6 +1093,7 @@ define_keywords!(
VARBINARY,
VARBIT,
VARCHAR,
+ VARCHAR2,
VARIABLE,
VARIABLES,
VARYING,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 13c3c5b3..b2fa3b16 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -12247,7 +12247,7 @@ impl<'a> Parser<'a> {
let (tables, with_from_keyword) = if !self.parse_keyword(Keyword::FROM) {
// `FROM` keyword is optional in BigQuery SQL.
// https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#delete_statement
- if dialect_of!(self is BigQueryDialect | GenericDialect) {
+ if dialect_of!(self is BigQueryDialect | OracleDialect | GenericDialect) {
(vec![], false)
} else {
let tables = self.parse_comma_separated(|p| p.parse_object_name(false))?;
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 73d29312..9ba5960e 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -291,6 +291,7 @@ pub fn all_dialects() -> TestedDialects {
Box::new(DuckDbDialect {}),
Box::new(DatabricksDialect {}),
Box::new(ClickHouseDialect {}),
+ Box::new(OracleDialect {}),
])
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 91952b8c..ccad67e3 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -34,8 +34,8 @@ use sqlparser::ast::TableFactor::{Pivot, Unpivot};
use sqlparser::ast::*;
use sqlparser::dialect::{
AnsiDialect, BigQueryDialect, ClickHouseDialect, DatabricksDialect, Dialect, DuckDbDialect,
- GenericDialect, HiveDialect, MsSqlDialect, MySqlDialect, PostgreSqlDialect, RedshiftSqlDialect,
- SQLiteDialect, SnowflakeDialect,
+ GenericDialect, HiveDialect, MsSqlDialect, MySqlDialect, OracleDialect, PostgreSqlDialect,
+ RedshiftSqlDialect, SQLiteDialect, SnowflakeDialect,
};
use sqlparser::keywords::{Keyword, ALL_KEYWORDS};
use sqlparser::parser::{Parser, ParserError, ParserOptions};
@@ -712,7 +712,9 @@ fn parse_delete_statement() {
fn parse_delete_without_from_error() {
let sql = "DELETE \"table\" WHERE 1";
- let dialects = all_dialects_except(|d| d.is::<BigQueryDialect>() || d.is::<GenericDialect>());
+ let dialects = all_dialects_except(|d| {
+ d.is::<BigQueryDialect>() || d.is::<OracleDialect>() || d.is::<GenericDialect>()
+ });
let res = dialects.parse_sql_statements(sql);
assert_eq!(
ParserError::ParserError("Expected: FROM, found: WHERE".to_string()),
@@ -723,7 +725,9 @@ fn parse_delete_without_from_error() {
#[test]
fn parse_delete_statement_for_multi_tables() {
let sql = "DELETE schema1.table1, schema2.table2 FROM schema1.table1 JOIN schema2.table2 ON schema2.table2.col1 = schema1.table1.col1 WHERE schema2.table2.col2 = 1";
- let dialects = all_dialects_except(|d| d.is::<BigQueryDialect>() || d.is::<GenericDialect>());
+ let dialects = all_dialects_except(|d| {
+ d.is::<BigQueryDialect>() || d.is::<OracleDialect>() || d.is::<GenericDialect>()
+ });
match dialects.verified_stmt(sql) {
Statement::Delete(Delete {
tables,
@@ -12943,7 +12947,7 @@ fn test_match_recognize_patterns() {
fn check(pattern: &str, expect: MatchRecognizePattern) {
let select =
all_dialects_where(|d| d.supports_match_recognize()).verified_only_select(&format!(
- "SELECT * FROM my_table MATCH_RECOGNIZE(PATTERN ({pattern}) DEFINE DUMMY AS true)" // "select * from my_table match_recognize ("
+ "SELECT * FROM my_table MATCH_RECOGNIZE(PATTERN ({pattern}) DEFINE DUMMY AS 1 = 1)" // "select * from my_table match_recognize ("
));
let TableFactor::MatchRecognize {
pattern: actual, ..
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org