Skip to content

Commit 04fbade

Browse files
authored
Consolidate and document SQL AST shims (#22094)
## Which issue does this PR close? - Related to #22069 ## Rationale for this change While upgrading sqlparser, it was not clear why there were feature gates for the `sql` feature: https://github.com/apache/datafusion/pull/22069/changes#r3204705488 There is a mode to avoid the `sqlparser` dependency, added by @timsaucer in - #17332 I think this feature makes sense but it is a little hard to understand because it is implemented with a bunch of `#[cfg(not(feature = "sql"))]` and there is no central place that explains the design. ## What changes are included in this PR? 1. Consolidate the SQL AST shim structures in a separate module 2. Document the design so it is easier to understand ## Are these changes tested? Yes by CI ## Are there any user-facing changes? <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. -->
1 parent 526ed6c commit 04fbade

5 files changed

Lines changed: 155 additions & 119 deletions

File tree

datafusion/expr/src/expr.rs

Lines changed: 7 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ use datafusion_common::{
4646
use datafusion_expr_common::placement::ExpressionPlacement;
4747
use datafusion_functions_window_common::field::WindowUDFFieldArgs;
4848
#[cfg(feature = "sql")]
49-
use sqlparser::ast::{
49+
pub use sqlparser::ast::{
50+
ExceptSelectItem, ExcludeSelectItem, IlikeSelectItem, RenameSelectItem,
51+
ReplaceSelectElement,
52+
};
53+
// Use shims for sqlparser types when the sql feature is disabled.
54+
#[cfg(not(feature = "sql"))]
55+
pub use crate::sql::{
5056
ExceptSelectItem, ExcludeSelectItem, IlikeSelectItem, RenameSelectItem,
5157
ReplaceSelectElement,
5258
};
@@ -1416,63 +1422,6 @@ impl Lambda {
14161422
}
14171423
}
14181424

1419-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1420-
#[cfg(not(feature = "sql"))]
1421-
pub struct IlikeSelectItem {
1422-
pub pattern: String,
1423-
}
1424-
#[cfg(not(feature = "sql"))]
1425-
impl Display for IlikeSelectItem {
1426-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1427-
write!(f, "ILIKE '{}'", &self.pattern)?;
1428-
Ok(())
1429-
}
1430-
}
1431-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1432-
#[cfg(not(feature = "sql"))]
1433-
pub enum ExcludeSelectItem {
1434-
Single(Ident),
1435-
Multiple(Vec<Ident>),
1436-
}
1437-
#[cfg(not(feature = "sql"))]
1438-
impl Display for ExcludeSelectItem {
1439-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1440-
write!(f, "EXCLUDE")?;
1441-
match self {
1442-
Self::Single(column) => {
1443-
write!(f, " {column}")?;
1444-
}
1445-
Self::Multiple(columns) => {
1446-
write!(f, " ({})", display_comma_separated(columns))?;
1447-
}
1448-
}
1449-
Ok(())
1450-
}
1451-
}
1452-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1453-
#[cfg(not(feature = "sql"))]
1454-
pub struct ExceptSelectItem {
1455-
pub first_element: Ident,
1456-
pub additional_elements: Vec<Ident>,
1457-
}
1458-
#[cfg(not(feature = "sql"))]
1459-
impl Display for ExceptSelectItem {
1460-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1461-
write!(f, "EXCEPT ")?;
1462-
if self.additional_elements.is_empty() {
1463-
write!(f, "({})", self.first_element)?;
1464-
} else {
1465-
write!(
1466-
f,
1467-
"({}, {})",
1468-
self.first_element,
1469-
display_comma_separated(&self.additional_elements)
1470-
)?;
1471-
}
1472-
Ok(())
1473-
}
1474-
}
1475-
14761425
pub fn display_comma_separated<T>(slice: &[T]) -> String
14771426
where
14781427
T: Display,
@@ -1481,64 +1430,6 @@ where
14811430
slice.iter().map(|v| format!("{v}")).join(", ")
14821431
}
14831432

1484-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1485-
#[cfg(not(feature = "sql"))]
1486-
pub enum RenameSelectItem {
1487-
Single(String),
1488-
Multiple(Vec<String>),
1489-
}
1490-
#[cfg(not(feature = "sql"))]
1491-
impl Display for RenameSelectItem {
1492-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1493-
write!(f, "RENAME")?;
1494-
match self {
1495-
Self::Single(column) => {
1496-
write!(f, " {column}")?;
1497-
}
1498-
Self::Multiple(columns) => {
1499-
write!(f, " ({})", display_comma_separated(columns))?;
1500-
}
1501-
}
1502-
Ok(())
1503-
}
1504-
}
1505-
1506-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1507-
#[cfg(not(feature = "sql"))]
1508-
pub struct Ident {
1509-
/// The value of the identifier without quotes.
1510-
pub value: String,
1511-
/// The starting quote if any. Valid quote characters are the single quote,
1512-
/// double quote, backtick, and opening square bracket.
1513-
pub quote_style: Option<char>,
1514-
/// The span of the identifier in the original SQL string.
1515-
pub span: String,
1516-
}
1517-
#[cfg(not(feature = "sql"))]
1518-
impl Display for Ident {
1519-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1520-
write!(f, "[{}]", self.value)
1521-
}
1522-
}
1523-
1524-
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1525-
#[cfg(not(feature = "sql"))]
1526-
pub struct ReplaceSelectElement {
1527-
pub expr: String,
1528-
pub column_name: Ident,
1529-
pub as_keyword: bool,
1530-
}
1531-
#[cfg(not(feature = "sql"))]
1532-
impl Display for ReplaceSelectElement {
1533-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1534-
if self.as_keyword {
1535-
write!(f, "{} AS {}", self.expr, self.column_name)
1536-
} else {
1537-
write!(f, "{} {}", self.expr, self.column_name)
1538-
}
1539-
}
1540-
}
1541-
15421433
/// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`.
15431434
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Default)]
15441435
pub struct WildcardOptions {

datafusion/expr/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub mod statistics {
8080
mod predicate_bounds;
8181
pub mod preimage;
8282
pub mod ptr_eq;
83+
#[cfg(not(feature = "sql"))]
84+
pub mod sql;
8385
pub mod test;
8486
pub mod tree_node;
8587
pub mod type_coercion;

datafusion/expr/src/logical_plan/ddl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ use std::{
2424
hash::{Hash, Hasher},
2525
};
2626

27-
#[cfg(not(feature = "sql"))]
28-
use crate::expr::Ident;
2927
use crate::expr::Sort;
28+
#[cfg(not(feature = "sql"))]
29+
use crate::sql::Ident;
3030
use arrow::datatypes::DataType;
3131
use datafusion_common::tree_node::{Transformed, TreeNodeContainer, TreeNodeRecursion};
3232
use datafusion_common::{

datafusion/expr/src/sql.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
//! Local copies of [`sqlparser::ast`] structures
19+
//!
20+
//! These types are used when the `sql` feature is disabled. When `sql` is
21+
//! enabled, the upstream types from [`sqlparser`] are used instead.
22+
//!
23+
//! These definitions should be structurally compatible with the upstream
24+
//! `sqlparser` types, so that code which switches between them via `cfg` keeps
25+
//! compiling.
26+
//!
27+
//! See [#17332](https://github.com/apache/datafusion/pull/17332) for
28+
//! more detail.
29+
30+
use crate::expr::display_comma_separated;
31+
use std::fmt;
32+
use std::fmt::{Display, Formatter};
33+
34+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
35+
pub struct IlikeSelectItem {
36+
pub pattern: String,
37+
}
38+
39+
impl Display for IlikeSelectItem {
40+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
41+
write!(f, "ILIKE '{}'", &self.pattern)?;
42+
Ok(())
43+
}
44+
}
45+
46+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
47+
pub enum ExcludeSelectItem {
48+
Single(Ident),
49+
Multiple(Vec<Ident>),
50+
}
51+
52+
impl Display for ExcludeSelectItem {
53+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
54+
write!(f, "EXCLUDE")?;
55+
match self {
56+
Self::Single(column) => {
57+
write!(f, " {column}")?;
58+
}
59+
Self::Multiple(columns) => {
60+
write!(f, " ({})", display_comma_separated(columns))?;
61+
}
62+
}
63+
Ok(())
64+
}
65+
}
66+
67+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
68+
pub struct ExceptSelectItem {
69+
pub first_element: Ident,
70+
pub additional_elements: Vec<Ident>,
71+
}
72+
73+
impl Display for ExceptSelectItem {
74+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
75+
write!(f, "EXCEPT ")?;
76+
if self.additional_elements.is_empty() {
77+
write!(f, "({})", self.first_element)?;
78+
} else {
79+
write!(
80+
f,
81+
"({}, {})",
82+
self.first_element,
83+
display_comma_separated(&self.additional_elements)
84+
)?;
85+
}
86+
Ok(())
87+
}
88+
}
89+
90+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
91+
pub enum RenameSelectItem {
92+
Single(String),
93+
Multiple(Vec<String>),
94+
}
95+
96+
impl Display for RenameSelectItem {
97+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
98+
write!(f, "RENAME")?;
99+
match self {
100+
Self::Single(column) => {
101+
write!(f, " {column}")?;
102+
}
103+
Self::Multiple(columns) => {
104+
write!(f, " ({})", display_comma_separated(columns))?;
105+
}
106+
}
107+
Ok(())
108+
}
109+
}
110+
111+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
112+
pub struct Ident {
113+
/// The value of the identifier without quotes.
114+
pub value: String,
115+
/// The starting quote if any. Valid quote characters are the single quote,
116+
/// double quote, backtick, and opening square bracket.
117+
pub quote_style: Option<char>,
118+
/// The span of the identifier in the original SQL string.
119+
pub span: String,
120+
}
121+
122+
impl Display for Ident {
123+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
124+
write!(f, "[{}]", self.value)
125+
}
126+
}
127+
128+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
129+
pub struct ReplaceSelectElement {
130+
pub expr: String,
131+
pub column_name: Ident,
132+
pub as_keyword: bool,
133+
}
134+
135+
impl Display for ReplaceSelectElement {
136+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
137+
if self.as_keyword {
138+
write!(f, "{} AS {}", self.expr, self.column_name)
139+
} else {
140+
write!(f, "{} {}", self.expr, self.column_name)
141+
}
142+
}
143+
}

datafusion/expr/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use datafusion_common::{
3939
};
4040

4141
#[cfg(not(feature = "sql"))]
42-
use crate::expr::{ExceptSelectItem, ExcludeSelectItem};
42+
use crate::sql::{ExceptSelectItem, ExcludeSelectItem};
4343
use indexmap::IndexSet;
4444
#[cfg(feature = "sql")]
4545
use sqlparser::ast::{ExceptSelectItem, ExcludeSelectItem};

0 commit comments

Comments
 (0)