Skip to content

Commit 7355eff

Browse files
committed
support the single table in parnes with alias in snowflake by dialect
1 parent f500a42 commit 7355eff

File tree

6 files changed

+240
-69
lines changed

6 files changed

+240
-69
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ Cargo.lock
1212

1313
# IDEs
1414
.idea
15+
.vscode

src/parser.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,14 +2116,58 @@ impl<'a> Parser<'a> {
21162116
// recently consumed does not start a derived table (cases 1, 2, or 4).
21172117
// `maybe_parse` will ignore such an error and rewind to be after the opening '('.
21182118

2119-
// Inside the parentheses we expect to find a table factor
2120-
// followed by some joins or another level of nesting.
2121-
let table_and_joins = self.parse_table_and_joins()?;
2122-
self.expect_token(&Token::RParen)?;
2123-
// The SQL spec prohibits derived and bare tables from appearing
2124-
// alone in parentheses. We don't enforce this as some databases
2125-
// (e.g. Snowflake) allow such syntax.
2126-
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
2119+
// Inside the parentheses we expect to find an (A) table factor
2120+
// followed by some joins or (B) another level of nesting.
2121+
let mut table_and_joins = self.parse_table_and_joins()?;
2122+
2123+
if !table_and_joins.joins.is_empty() {
2124+
self.expect_token(&Token::RParen)?;
2125+
Ok(TableFactor::NestedJoin(Box::new(table_and_joins))) // (A)
2126+
} else if let TableFactor::NestedJoin(_) = &table_and_joins.relation {
2127+
// (B): `table_and_joins` (what we found inside the parentheses)
2128+
// is a nested join `(foo JOIN bar)`, not followed by other joins.
2129+
self.expect_token(&Token::RParen)?;
2130+
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
2131+
} else if dialect_of!(self is SnowflakeDialect) {
2132+
// Dialect-specific behavior: Snowflake diverges from the
2133+
// standard and most of other implementations by allowing
2134+
// extra parentheses not only around a join (B), but around
2135+
// lone table names (e.g. `FROM (mytable [AS alias])`) and
2136+
// around derived tables (e.g. `FROM ((SELECT ...) [AS alias])`
2137+
// as well.
2138+
self.expect_token(&Token::RParen)?;
2139+
2140+
if let Some(outer_alias) =
2141+
self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?
2142+
{
2143+
// Snowflake also allows specifying an alias *after* parens
2144+
// e.g. `FROM (mytable) AS alias`
2145+
match &mut table_and_joins.relation {
2146+
TableFactor::Derived { alias, .. }
2147+
| TableFactor::Table { alias, .. }
2148+
| TableFactor::TableFunction { alias, .. } => {
2149+
// but not `FROM (mytable AS alias1) AS alias2`.
2150+
if let Some(inner_alias) = alias {
2151+
return Err(ParserError::ParserError(format!(
2152+
"duplicate alias {}",
2153+
inner_alias
2154+
)));
2155+
}
2156+
// Act as if the alias was specified normally next
2157+
// to the table name: `(mytable) AS alias` ->
2158+
// `(mytable AS alias)`
2159+
alias.replace(outer_alias);
2160+
}
2161+
TableFactor::NestedJoin(_) => unreachable!(),
2162+
};
2163+
}
2164+
// Do not store the extra set of parens in the AST
2165+
Ok(table_and_joins.relation)
2166+
} else {
2167+
// The SQL spec prohibits derived tables and bare tables from
2168+
// appearing alone in parentheses (e.g. `FROM (mytable)`)
2169+
self.expected("joined table", self.peek_token())
2170+
}
21272171
} else {
21282172
let name = self.parse_object_name()?;
21292173
// Postgres, MSSQL: table-valued functions:

src/test_utils.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,38 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
143143
pub fn number(n: &'static str) -> Value {
144144
Value::Number(n.parse().unwrap())
145145
}
146+
147+
fn table_alias(alias: &str) -> TableAlias {
148+
TableAlias {
149+
name: Ident {
150+
value: alias.to_owned(),
151+
quote_style: None,
152+
},
153+
columns: Vec::new(),
154+
}
155+
}
156+
157+
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
158+
TableFactor::Table {
159+
name: ObjectName(vec![Ident::new(name.into())]),
160+
alias: Some(table_alias(&alias.into())),
161+
args: vec![],
162+
with_hints: vec![],
163+
}
164+
}
165+
166+
pub fn table(name: impl Into<String>) -> TableFactor {
167+
TableFactor::Table {
168+
name: ObjectName(vec![Ident::new(name.into())]),
169+
alias: None,
170+
args: vec![],
171+
with_hints: vec![],
172+
}
173+
}
174+
175+
pub fn join(relation: TableFactor) -> Join {
176+
Join {
177+
relation,
178+
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
179+
}
180+
}

tests/macros/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
12+
13+
macro_rules! nest {
14+
($base:expr $(, $join:expr)*) => {
15+
TableFactor::NestedJoin(Box::new(TableWithJoins {
16+
relation: $base,
17+
joins: vec![$(join($join)),*]
18+
}))
19+
};
20+
}

tests/sqlparser_common.rs

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
//! sqlparser regardless of the chosen dialect (i.e. it doesn't conflict with
1919
//! dialect-specific parsing rules).
2020
21-
use matches::assert_matches;
21+
#[macro_use]
22+
#[path = "macros/mod.rs"]
23+
mod macros;
2224

25+
use matches::assert_matches;
2326
use sqlparser::ast::*;
27+
2428
use sqlparser::dialect::keywords::ALL_KEYWORDS;
2529
use sqlparser::parser::ParserError;
26-
use sqlparser::test_utils::{all_dialects, expr_from_projection, number, only};
30+
use sqlparser::test_utils::{all_dialects, expr_from_projection, join, number, only, table};
2731

2832
#[test]
2933
fn parse_insert_values() {
@@ -2282,31 +2286,6 @@ fn parse_complex_join() {
22822286

22832287
#[test]
22842288
fn parse_join_nesting() {
2285-
fn table(name: impl Into<String>) -> TableFactor {
2286-
TableFactor::Table {
2287-
name: ObjectName(vec![Ident::new(name.into())]),
2288-
alias: None,
2289-
args: vec![],
2290-
with_hints: vec![],
2291-
}
2292-
}
2293-
2294-
fn join(relation: TableFactor) -> Join {
2295-
Join {
2296-
relation,
2297-
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
2298-
}
2299-
}
2300-
2301-
macro_rules! nest {
2302-
($base:expr $(, $join:expr)*) => {
2303-
TableFactor::NestedJoin(Box::new(TableWithJoins {
2304-
relation: $base,
2305-
joins: vec![$(join($join)),*]
2306-
}))
2307-
};
2308-
}
2309-
23102289
let sql = "SELECT * FROM a NATURAL JOIN (b NATURAL JOIN (c NATURAL JOIN d NATURAL JOIN e)) \
23112290
NATURAL JOIN (f NATURAL JOIN (g NATURAL JOIN h))";
23122291
assert_eq!(
@@ -2337,20 +2316,6 @@ fn parse_join_nesting() {
23372316
from.joins,
23382317
vec![join(nest!(nest!(nest!(table("b"), table("c")))))]
23392318
);
2340-
2341-
// Parenthesized table names are non-standard, but supported in Snowflake SQL
2342-
let sql = "SELECT * FROM (a NATURAL JOIN (b))";
2343-
let select = verified_only_select(sql);
2344-
let from = only(select.from);
2345-
2346-
assert_eq!(from.relation, nest!(table("a"), nest!(table("b"))));
2347-
2348-
// Double parentheses around table names are non-standard, but supported in Snowflake SQL
2349-
let sql = "SELECT * FROM (a NATURAL JOIN ((b)))";
2350-
let select = verified_only_select(sql);
2351-
let from = only(select.from);
2352-
2353-
assert_eq!(from.relation, nest!(table("a"), nest!(nest!(table("b")))));
23542319
}
23552320

23562321
#[test]
@@ -2492,26 +2457,6 @@ fn parse_derived_tables() {
24922457
}],
24932458
}))
24942459
);
2495-
2496-
// Nesting a subquery in parentheses is non-standard, but supported in Snowflake SQL
2497-
let sql = "SELECT * FROM ((SELECT 1) AS t)";
2498-
let select = verified_only_select(sql);
2499-
let from = only(select.from);
2500-
2501-
assert_eq!(
2502-
from.relation,
2503-
TableFactor::NestedJoin(Box::new(TableWithJoins {
2504-
relation: TableFactor::Derived {
2505-
lateral: false,
2506-
subquery: Box::new(verified_query("SELECT 1")),
2507-
alias: Some(TableAlias {
2508-
name: "t".into(),
2509-
columns: vec![],
2510-
})
2511-
},
2512-
joins: Vec::new(),
2513-
}))
2514-
);
25152460
}
25162461

25172462
#[test]

tests/sqlparser_snowflake.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@
99
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
12+
13+
#[macro_use]
14+
#[path = "macros/mod.rs"]
15+
mod macros;
16+
1217
use sqlparser::ast::*;
1318
use sqlparser::dialect::{GenericDialect, SnowflakeDialect};
19+
use sqlparser::parser::ParserError;
1420
use sqlparser::test_utils::*;
1521

1622
#[test]
@@ -24,6 +30,126 @@ fn test_snowflake_create_table() {
2430
}
2531
}
2632

33+
fn get_from_section_from_select_query(query: &str) -> Vec<TableWithJoins> {
34+
let statement = snowflake().parse_sql_statements(query).unwrap()[0].clone();
35+
36+
let query = match statement {
37+
Statement::Query(query) => query,
38+
_ => panic!("Not a query"),
39+
};
40+
41+
let select = match query.body {
42+
SetExpr::Select(select) => select,
43+
_ => panic!("not a select query"),
44+
};
45+
46+
select.from.clone()
47+
}
48+
49+
#[test]
50+
fn test_sf_derives_single_table_in_parenthesis() {
51+
let from = get_from_section_from_select_query("SELECT * FROM ((SELECT 1) AS t)");
52+
assert_eq!(
53+
only(from).relation,
54+
TableFactor::Derived {
55+
lateral: false,
56+
subquery: Box::new(snowflake().verified_query("SELECT 1")),
57+
alias: Some(TableAlias {
58+
name: "t".into(),
59+
columns: vec![],
60+
})
61+
}
62+
);
63+
64+
let from = get_from_section_from_select_query("SELECT * FROM (((SELECT 1) AS t))");
65+
66+
assert_eq!(
67+
only(from).relation,
68+
TableFactor::Derived {
69+
lateral: false,
70+
subquery: Box::new(snowflake().verified_query("SELECT 1")),
71+
alias: Some(TableAlias {
72+
name: "t".into(),
73+
columns: vec![],
74+
})
75+
}
76+
);
77+
}
78+
79+
#[test]
80+
fn test_single_table_in_parenthesis() {
81+
//Parenthesized table names are non-standard, but supported in Snowflake SQL
82+
83+
let from = get_from_section_from_select_query("SELECT * FROM (a NATURAL JOIN (b))");
84+
assert_eq!(only(from).relation, nest!(table("a"), table("b")));
85+
86+
let from = get_from_section_from_select_query("SELECT * FROM (a NATURAL JOIN ((b)))");
87+
assert_eq!(only(from).relation, nest!(table("a"), table("b")));
88+
}
89+
90+
#[test]
91+
fn test_single_table_in_parenthesis_with_alias() {
92+
let sql = "SELECT * FROM (a NATURAL JOIN (b) c )";
93+
let table_with_joins = only(get_from_section_from_select_query(sql));
94+
assert_eq!(
95+
table_with_joins.relation,
96+
nest!(table("a"), table_with_alias("b", "c"))
97+
);
98+
99+
let sql = "SELECT * FROM (a NATURAL JOIN ((b)) c )";
100+
let table_with_joins = only(get_from_section_from_select_query(sql));
101+
assert_eq!(
102+
table_with_joins.relation,
103+
nest!(table("a"), table_with_alias("b", "c"))
104+
);
105+
106+
let sql = "SELECT * FROM (a NATURAL JOIN ( (b) c ) )";
107+
let table_with_joins = only(get_from_section_from_select_query(sql));
108+
assert_eq!(
109+
table_with_joins.relation,
110+
nest!(table("a"), table_with_alias("b", "c"))
111+
);
112+
113+
let sql = "SELECT * FROM (a NATURAL JOIN ( (b) as c ) )";
114+
let table_with_joins = only(get_from_section_from_select_query(sql));
115+
assert_eq!(
116+
table_with_joins.relation,
117+
nest!(table("a"), table_with_alias("b", "c"))
118+
);
119+
120+
let sql = "SELECT * FROM (a alias1 NATURAL JOIN ( (b) c ) )";
121+
let table_with_joins = only(get_from_section_from_select_query(sql));
122+
assert_eq!(
123+
table_with_joins.relation,
124+
nest!(table_with_alias("a", "alias1"), table_with_alias("b", "c"))
125+
);
126+
127+
let sql = "SELECT * FROM (a as alias1 NATURAL JOIN ( (b) as c ) )";
128+
let table_with_joins = only(get_from_section_from_select_query(sql));
129+
assert_eq!(
130+
table_with_joins.relation,
131+
nest!(table_with_alias("a", "alias1"), table_with_alias("b", "c"))
132+
);
133+
134+
let res = snowflake().parse_sql_statements("SELECT * FROM (a NATURAL JOIN b) c");
135+
assert_eq!(
136+
ParserError::ParserError("Expected end of statement, found: c".to_string()),
137+
res.unwrap_err()
138+
);
139+
140+
let res = snowflake().parse_sql_statements("SELECT * FROM (a b) c");
141+
assert_eq!(
142+
ParserError::ParserError("duplicate alias b".to_string()),
143+
res.unwrap_err()
144+
);
145+
}
146+
147+
fn snowflake() -> TestedDialects {
148+
TestedDialects {
149+
dialects: vec![Box::new(SnowflakeDialect {})],
150+
}
151+
}
152+
27153
fn snowflake_and_generic() -> TestedDialects {
28154
TestedDialects {
29155
dialects: vec![Box::new(SnowflakeDialect {}), Box::new(GenericDialect {})],

0 commit comments

Comments
 (0)