Skip to content

Commit 8abb21c

Browse files
committed
Implicit aliases
Right now sqlparser-rs inject the "AS" keyword in front of aliases unconditionally. As reported by #1875 or #1784 this leads to problems on Oracle databases. This patch preserves the original absence or presentce of the keyword in table-factor position. I dubbed the former "implicit" and the latter "explicit." 1. Some more effort could be invested to apply the same behavior for select-items (ie. projections in queries) and/or further nodes of the AST with an alias which "AS" keyword is optional. To unify the implementation within the parser and make it easier for clients, alias would beg to be exposed not as pure `Ident`s, but maybe presented as something as: ```rust struct Alias { explicit: bool, name: Ident, } impl Deref for Alias { type Target = Ident; ... } impl From<Alias> for Ident { ... } ``` 2. The parser _could_ be instructed / configured (either by `ParserOptions` or through a `Dialect` setting) to always produce "explicit" alias tokens. This would then always produce the "AS" keyword when render via `Display`. Idealy, we'd have `Visitor::visit_alias` and clients could just apply their own setting quite easily.
1 parent 2b8e99c commit 8abb21c

10 files changed

Lines changed: 202 additions & 269 deletions

src/ast/query.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,7 +1902,7 @@ impl fmt::Display for TableFactor {
19021902
write!(f, " {sample}")?;
19031903
}
19041904
if let Some(alias) = alias {
1905-
write!(f, " AS {alias}")?;
1905+
write!(f, " {alias}")?;
19061906
}
19071907
if !index_hints.is_empty() {
19081908
write!(f, " {}", display_separated(index_hints, " "))?;
@@ -1932,7 +1932,7 @@ impl fmt::Display for TableFactor {
19321932
NewLine.fmt(f)?;
19331933
f.write_str(")")?;
19341934
if let Some(alias) = alias {
1935-
write!(f, " AS {alias}")?;
1935+
write!(f, " {alias}")?;
19361936
}
19371937
Ok(())
19381938
}
@@ -1948,14 +1948,14 @@ impl fmt::Display for TableFactor {
19481948
write!(f, "{name}")?;
19491949
write!(f, "({})", display_comma_separated(args))?;
19501950
if let Some(alias) = alias {
1951-
write!(f, " AS {alias}")?;
1951+
write!(f, " {alias}")?;
19521952
}
19531953
Ok(())
19541954
}
19551955
TableFactor::TableFunction { expr, alias } => {
19561956
write!(f, "TABLE({expr})")?;
19571957
if let Some(alias) = alias {
1958-
write!(f, " AS {alias}")?;
1958+
write!(f, " {alias}")?;
19591959
}
19601960
Ok(())
19611961
}
@@ -1973,13 +1973,13 @@ impl fmt::Display for TableFactor {
19731973
}
19741974

19751975
if let Some(alias) = alias {
1976-
write!(f, " AS {alias}")?;
1976+
write!(f, " {alias}")?;
19771977
}
19781978
if *with_offset {
19791979
write!(f, " WITH OFFSET")?;
19801980
}
19811981
if let Some(alias) = with_offset_alias {
1982-
write!(f, " AS {alias}")?;
1982+
write!(f, " {alias}")?;
19831983
}
19841984
Ok(())
19851985
}
@@ -1995,7 +1995,7 @@ impl fmt::Display for TableFactor {
19951995
columns = display_comma_separated(columns)
19961996
)?;
19971997
if let Some(alias) = alias {
1998-
write!(f, " AS {alias}")?;
1998+
write!(f, " {alias}")?;
19991999
}
20002000
Ok(())
20012001
}
@@ -2014,7 +2014,7 @@ impl fmt::Display for TableFactor {
20142014
write!(f, " WITH ({})", display_comma_separated(columns))?;
20152015
}
20162016
if let Some(alias) = alias {
2017-
write!(f, " AS {alias}")?;
2017+
write!(f, " {alias}")?;
20182018
}
20192019
Ok(())
20202020
}
@@ -2024,7 +2024,7 @@ impl fmt::Display for TableFactor {
20242024
} => {
20252025
write!(f, "({table_with_joins})")?;
20262026
if let Some(alias) = alias {
2027-
write!(f, " AS {alias}")?;
2027+
write!(f, " {alias}")?;
20282028
}
20292029
Ok(())
20302030
}
@@ -2051,8 +2051,8 @@ impl fmt::Display for TableFactor {
20512051
write!(f, " DEFAULT ON NULL ({expr})")?;
20522052
}
20532053
write!(f, ")")?;
2054-
if alias.is_some() {
2055-
write!(f, " AS {}", alias.as_ref().unwrap())?;
2054+
if let Some(alias) = alias {
2055+
write!(f, " {alias}")?;
20562056
}
20572057
Ok(())
20582058
}
@@ -2075,8 +2075,8 @@ impl fmt::Display for TableFactor {
20752075
name,
20762076
display_comma_separated(columns)
20772077
)?;
2078-
if alias.is_some() {
2079-
write!(f, " AS {}", alias.as_ref().unwrap())?;
2078+
if let Some(alias) = alias {
2079+
write!(f, " {alias}")?;
20802080
}
20812081
Ok(())
20822082
}
@@ -2109,8 +2109,8 @@ impl fmt::Display for TableFactor {
21092109
}
21102110
write!(f, "PATTERN ({pattern}) ")?;
21112111
write!(f, "DEFINE {})", display_comma_separated(symbols))?;
2112-
if alias.is_some() {
2113-
write!(f, " AS {}", alias.as_ref().unwrap())?;
2112+
if let Some(alias) = alias {
2113+
write!(f, " {alias}")?;
21142114
}
21152115
Ok(())
21162116
}
@@ -2135,7 +2135,7 @@ impl fmt::Display for TableFactor {
21352135
columns = display_comma_separated(columns)
21362136
)?;
21372137
if let Some(alias) = alias {
2138-
write!(f, " AS {alias}")?;
2138+
write!(f, " {alias}")?;
21392139
}
21402140
Ok(())
21412141
}
@@ -2168,7 +2168,7 @@ impl fmt::Display for TableFactor {
21682168
write!(f, ")")?;
21692169

21702170
if let Some(alias) = alias {
2171-
write!(f, " AS {alias}")?;
2171+
write!(f, " {alias}")?;
21722172
}
21732173

21742174
Ok(())
@@ -2181,13 +2181,17 @@ impl fmt::Display for TableFactor {
21812181
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21822182
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
21832183
pub struct TableAlias {
2184+
/// Tells whether the alias was introduced with an explicit, preceding "AS"
2185+
/// keyword, e.g. `AS name`. Typically, the keyword is preceding the name
2186+
/// (e.g. `.. FROM table AS t ..`).
2187+
pub explicit: bool,
21842188
pub name: Ident,
21852189
pub columns: Vec<TableAliasColumnDef>,
21862190
}
21872191

21882192
impl fmt::Display for TableAlias {
21892193
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2190-
write!(f, "{}", self.name)?;
2194+
write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
21912195
if !self.columns.is_empty() {
21922196
write!(f, " ({})", display_comma_separated(&self.columns))?;
21932197
}

src/ast/spans.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use crate::ast::{
19-
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
20-
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
21-
ExportData, Owner, TypedString,
18+
use crate::{
19+
ast::{
20+
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
21+
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
22+
ExportData, Owner, TypedString,
23+
},
24+
tokenizer::TokenWithSpan,
2225
};
2326
use core::iter;
2427

@@ -96,6 +99,12 @@ pub trait Spanned {
9699
fn span(&self) -> Span;
97100
}
98101

102+
impl Spanned for TokenWithSpan {
103+
fn span(&self) -> Span {
104+
self.span
105+
}
106+
}
107+
99108
impl Spanned for Query {
100109
fn span(&self) -> Span {
101110
let Query {
@@ -2079,9 +2088,12 @@ impl Spanned for FunctionArgExpr {
20792088

20802089
impl Spanned for TableAlias {
20812090
fn span(&self) -> Span {
2082-
let TableAlias { name, columns } = self;
2083-
2084-
union_spans(iter::once(name.span).chain(columns.iter().map(|i| i.span())))
2091+
let TableAlias {
2092+
explicit: _,
2093+
name,
2094+
columns,
2095+
} = self;
2096+
union_spans(core::iter::once(name.span).chain(columns.iter().map(Spanned::span)))
20852097
}
20862098
}
20872099

src/parser/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11140,10 +11140,15 @@ impl<'a> Parser<'a> {
1114011140
fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
1114111141
parser.dialect.is_table_factor_alias(explicit, kw, parser)
1114211142
}
11143+
let explicit = self.peek_keyword(Keyword::AS);
1114311144
match self.parse_optional_alias_inner(None, validator)? {
1114411145
Some(name) => {
1114511146
let columns = self.parse_table_alias_column_defs()?;
11146-
Ok(Some(TableAlias { name, columns }))
11147+
Ok(Some(TableAlias {
11148+
explicit,
11149+
name,
11150+
columns,
11151+
}))
1114711152
}
1114811153
None => Ok(None),
1114911154
}
@@ -12775,6 +12780,7 @@ impl<'a> Parser<'a> {
1277512780
let closing_paren_token = self.expect_token(&Token::RParen)?;
1277612781

1277712782
let alias = TableAlias {
12783+
explicit: false,
1277812784
name,
1277912785
columns: vec![],
1278012786
};
@@ -12801,7 +12807,11 @@ impl<'a> Parser<'a> {
1280112807
let query = self.parse_query()?;
1280212808
let closing_paren_token = self.expect_token(&Token::RParen)?;
1280312809

12804-
let alias = TableAlias { name, columns };
12810+
let alias = TableAlias {
12811+
explicit: false,
12812+
name,
12813+
columns,
12814+
};
1280512815
Cte {
1280612816
alias,
1280712817
query,

src/test_utils.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,9 @@ pub fn single_quoted_string(s: impl Into<String>) -> Value {
368368
Value::SingleQuotedString(s.into())
369369
}
370370

371-
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
371+
pub fn table_alias(explicit: bool, name: impl Into<String>) -> Option<TableAlias> {
372372
Some(TableAlias {
373+
explicit,
373374
name: Ident::new(name),
374375
columns: vec![],
375376
})
@@ -405,13 +406,14 @@ pub fn table_from_name(name: ObjectName) -> TableFactor {
405406
}
406407
}
407408

408-
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
409+
pub fn table_with_alias(
410+
name: impl Into<String>,
411+
with_as_keyword: bool,
412+
alias: impl Into<String>,
413+
) -> TableFactor {
409414
TableFactor::Table {
410415
name: ObjectName::from(vec![Ident::new(name)]),
411-
alias: Some(TableAlias {
412-
name: Ident::new(alias),
413-
columns: vec![],
414-
}),
416+
alias: table_alias(with_as_keyword, alias),
415417
args: None,
416418
with_hints: vec![],
417419
version: None,

tests/sqlparser_bigquery.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,7 @@ fn parse_table_identifiers() {
16901690
fn parse_hyphenated_table_identifiers() {
16911691
bigquery().one_statement_parses_to(
16921692
"select * from foo-bar f join baz-qux b on f.id = b.id",
1693-
"SELECT * FROM foo-bar AS f JOIN baz-qux AS b ON f.id = b.id",
1693+
"SELECT * FROM foo-bar f JOIN baz-qux b ON f.id = b.id",
16941694
);
16951695

16961696
assert_eq!(
@@ -1766,7 +1766,7 @@ fn parse_join_constraint_unnest_alias() {
17661766
.joins,
17671767
vec![Join {
17681768
relation: TableFactor::UNNEST {
1769-
alias: table_alias("f"),
1769+
alias: table_alias(true, "f"),
17701770
array_exprs: vec![Expr::CompoundIdentifier(vec![
17711771
Ident::new("t1"),
17721772
Ident::new("a")
@@ -1841,10 +1841,7 @@ fn parse_merge() {
18411841
assert_eq!(
18421842
TableFactor::Table {
18431843
name: ObjectName::from(vec![Ident::new("inventory")]),
1844-
alias: Some(TableAlias {
1845-
name: Ident::new("T"),
1846-
columns: vec![],
1847-
}),
1844+
alias: table_alias(true, "T"),
18481845
args: Default::default(),
18491846
with_hints: Default::default(),
18501847
version: Default::default(),
@@ -1859,10 +1856,7 @@ fn parse_merge() {
18591856
assert_eq!(
18601857
TableFactor::Table {
18611858
name: ObjectName::from(vec![Ident::new("newArrivals")]),
1862-
alias: Some(TableAlias {
1863-
name: Ident::new("S"),
1864-
columns: vec![],
1865-
}),
1859+
alias: table_alias(true, "S"),
18661860
args: Default::default(),
18671861
with_hints: Default::default(),
18681862
version: Default::default(),

0 commit comments

Comments
 (0)