Skip to content

Commit 94919ba

Browse files
committed
Simplify the code transforming (mytable) AS alias -> (mytable AS alias) and update the comments
1 parent 7cf83c5 commit 94919ba

File tree

3 files changed

+52
-109
lines changed

3 files changed

+52
-109
lines changed

src/ast/query.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,11 @@ pub enum TableFactor {
235235
subquery: Box<Query>,
236236
alias: Option<TableAlias>,
237237
},
238-
/// Represents a parenthesized table factor. The SQL spec only allows a
239-
/// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
240-
/// possibly several times, but the parser also accepts the non-standard
241-
/// nesting of bare tables (`table_with_joins.joins.is_empty()`), so the
242-
/// name `NestedJoin` is a bit of misnomer.
238+
/// The inner `TableWithJoins` can have no joins only if its
239+
/// `relation` is itself a `TableFactor::NestedJoin`.
240+
/// Some dialects allow nesting lone `Table`/`Derived` in parens,
241+
/// e.g. `FROM (mytable)`, but we don't expose the presence of these
242+
/// extraneous parens in the AST.
243243
NestedJoin(Box<TableWithJoins>),
244244
}
245245

src/parser.rs

+46-103
Original file line numberDiff line numberDiff line change
@@ -2065,87 +2065,6 @@ impl<'a> Parser<'a> {
20652065
Ok(TableWithJoins { relation, joins })
20662066
}
20672067

2068-
fn add_alias_to_single_table_in_parenthesis(
2069-
&self,
2070-
table_facor: TableFactor,
2071-
consumed_alias: TableAlias,
2072-
) -> Result<TableFactor, ParserError> {
2073-
match table_facor {
2074-
// Add the alias to dervied table
2075-
TableFactor::Derived {
2076-
lateral,
2077-
subquery,
2078-
alias,
2079-
} => match alias {
2080-
None => Ok(TableFactor::Derived {
2081-
lateral,
2082-
subquery,
2083-
alias: Some(consumed_alias),
2084-
}),
2085-
// "Select * from (table1 as alias1) as alias1" - it prohabited
2086-
Some(alias) => Err(ParserError::ParserError(format!(
2087-
"duplicate alias {}",
2088-
alias
2089-
))),
2090-
},
2091-
// Add The alias to the table
2092-
TableFactor::Table {
2093-
name,
2094-
alias,
2095-
args,
2096-
with_hints,
2097-
} => match alias {
2098-
None => Ok(TableFactor::Table {
2099-
name,
2100-
alias: Some(consumed_alias),
2101-
args,
2102-
with_hints,
2103-
}),
2104-
// "Select * from (table1 as alias1) as alias1" - it prohabited
2105-
Some(alias) => Err(ParserError::ParserError(format!(
2106-
"duplicate alias {}",
2107-
alias
2108-
))),
2109-
},
2110-
TableFactor::NestedJoin(_) => Err(ParserError::ParserError(
2111-
"aliasing joins is not allowed".to_owned(),
2112-
)),
2113-
}
2114-
}
2115-
2116-
fn remove_redundent_parenthesis(
2117-
&mut self,
2118-
table_and_joins: TableWithJoins,
2119-
) -> Result<TableFactor, ParserError> {
2120-
let table_factor = table_and_joins.relation;
2121-
2122-
// check if we have alias after the parenthesis
2123-
let alias = match self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)? {
2124-
None => {
2125-
return Ok(table_factor);
2126-
}
2127-
Some(alias) => alias,
2128-
};
2129-
2130-
// if we have alias, we attached it to the single table that inside parenthesis
2131-
self.add_alias_to_single_table_in_parenthesis(table_factor, alias)
2132-
}
2133-
2134-
fn validate_nested_join(&self, table_and_joins: &TableWithJoins) -> Result<(), ParserError> {
2135-
match table_and_joins.relation {
2136-
TableFactor::NestedJoin { .. } => (),
2137-
_ => {
2138-
if table_and_joins.joins.is_empty() {
2139-
// validate thats indeed join and not dervied
2140-
// or nested table
2141-
self.expected("joined table", self.peek_token())?
2142-
}
2143-
}
2144-
}
2145-
2146-
Ok(())
2147-
}
2148-
21492068
/// A table name or a parenthesized subquery, followed by optional `[AS] alias`
21502069
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
21512070
if self.parse_keyword(Keyword::LATERAL) {
@@ -2185,31 +2104,55 @@ impl<'a> Parser<'a> {
21852104
// recently consumed does not start a derived table (cases 1, 2, or 4).
21862105
// `maybe_parse` will ignore such an error and rewind to be after the opening '('.
21872106

2188-
// Inside the parentheses we expect to find a table factor
2189-
// followed by some joins or another level of nesting.
2190-
let table_and_joins = self.parse_table_and_joins()?;
2191-
self.expect_token(&Token::RParen)?;
2107+
// Inside the parentheses we expect to find an (A) table factor
2108+
// followed by some joins or (B) another level of nesting.
2109+
let mut table_and_joins = self.parse_table_and_joins()?;
21922110

2193-
// The SQL spec prohibits derived and bare tables from appearing
2194-
// alone in parentheses. But as some databases
2195-
// (e.g. Snowflake) allow such syntax - it's can be allowed
2196-
// for specfic dialect.
2197-
if self.dialect.alllow_single_table_in_parenthesis() {
2198-
if table_and_joins.joins.is_empty() {
2199-
// In case the DB's like snowflake that allowed single dervied or bare
2200-
// table in parenthesis (for example : `Select * from (a) as b` )
2201-
// the parser will parse it as Nested join, but if it's actually a single table
2202-
// we don't want to treat such case as join , because we don't actually join
2203-
// any tables.
2204-
let table_factor = self.remove_redundent_parenthesis(table_and_joins)?;
2205-
Ok(table_factor)
2206-
} else {
2207-
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
2111+
if !table_and_joins.joins.is_empty() {
2112+
self.expect_token(&Token::RParen)?;
2113+
Ok(TableFactor::NestedJoin(Box::new(table_and_joins))) // (A)
2114+
} else if let TableFactor::NestedJoin(_) = &table_and_joins.relation {
2115+
// (B): `table_and_joins` (what we found inside the parentheses)
2116+
// is a nested join `(foo JOIN bar)`, not followed by other joins.
2117+
self.expect_token(&Token::RParen)?;
2118+
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
2119+
} else if self.dialect.alllow_single_table_in_parenthesis() {
2120+
// Dialect-specific behavior: Snowflake diverges from the
2121+
// standard and most of other implementations by allowing
2122+
// extra parentheses not only around a join (B), but around
2123+
// lone table names (e.g. `FROM (mytable [AS alias])`) and
2124+
// around derived tables (e.g. `FROM ((SELECT ...) [AS alias])`
2125+
// as well.
2126+
self.expect_token(&Token::RParen)?;
2127+
2128+
if let Some(outer_alias) =
2129+
self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?
2130+
{
2131+
// Snowflake also allows specifying an alias *after* parens
2132+
// e.g. `FROM (mytable) AS alias`
2133+
match &mut table_and_joins.relation {
2134+
TableFactor::Derived { alias, .. } | TableFactor::Table { alias, .. } => {
2135+
// but not `FROM (mytable AS alias1) AS alias2`.
2136+
if let Some(inner_alias) = alias {
2137+
return Err(ParserError::ParserError(format!(
2138+
"duplicate alias {}",
2139+
inner_alias
2140+
)));
2141+
}
2142+
// Act as if the alias was specified normally next
2143+
// to the table name: `(mytable) AS alias` ->
2144+
// `(mytable AS alias)`
2145+
alias.replace(outer_alias);
2146+
}
2147+
TableFactor::NestedJoin(_) => unreachable!(),
2148+
};
22082149
}
2150+
// Do not store the extra set of parens in the AST
2151+
Ok(table_and_joins.relation)
22092152
} else {
2210-
// Defualt behaviuor
2211-
self.validate_nested_join(&table_and_joins)?;
2212-
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
2153+
// The SQL spec prohibits derived tables and bare tables from
2154+
// appearing alone in parentheses (e.g. `FROM (mytable)`)
2155+
self.expected("joined table", self.peek_token())
22132156
}
22142157
} else {
22152158
let name = self.parse_object_name()?;

tests/sqlparser_common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2277,7 +2277,7 @@ fn parse_join_nesting() {
22772277
// Nesting a subquery in parentheses is non-standard, but supported in Snowflake SQL
22782278
let res = parse_sql_statements("SELECT * FROM ((SELECT 1) AS t)");
22792279
assert_eq!(
2280-
ParserError::ParserError("Expected joined table, found: EOF".to_string()),
2280+
ParserError::ParserError("Expected joined table, found: )".to_string()),
22812281
res.unwrap_err()
22822282
);
22832283
}

0 commit comments

Comments
 (0)