Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,8 @@ pub struct TableAlias {
pub name: Ident,
/// Optional column aliases declared in parentheses after the table alias.
pub columns: Vec<TableAliasColumnDef>,
/// Optional PartiQL index alias declared with `AT`.
pub at: Option<Ident>,
}

impl fmt::Display for TableAlias {
Expand All @@ -2535,6 +2537,9 @@ impl fmt::Display for TableAlias {
if !self.columns.is_empty() {
write!(f, " ({})", display_comma_separated(&self.columns))?;
}
if let Some(at) = &self.at {
write!(f, " AT {at}")?;
}
Ok(())
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2178,8 +2178,13 @@ impl Spanned for TableAlias {
explicit: _,
name,
columns,
at,
} = self;
union_spans(core::iter::once(name.span).chain(columns.iter().map(Spanned::span)))
union_spans(
core::iter::once(name.span)
.chain(columns.iter().map(Spanned::span))
.chain(at.iter().map(|at| at.span)),
)
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12809,10 +12809,16 @@ impl<'a> Parser<'a> {
match self.parse_optional_alias_inner(None, validator)? {
Some(name) => {
let columns = self.parse_table_alias_column_defs()?;
let at = if self.dialect.supports_partiql() && self.parse_keyword(Keyword::AT) {
Some(self.parse_identifier()?)
} else {
None
};
Ok(Some(TableAlias {
explicit,
name,
columns,
at,
}))
}
None => Ok(None),
Expand Down Expand Up @@ -14461,6 +14467,7 @@ impl<'a> Parser<'a> {
explicit: false,
name,
columns: vec![],
at: None,
},
query,
from: None,
Expand Down Expand Up @@ -14505,6 +14512,7 @@ impl<'a> Parser<'a> {
explicit: false,
name,
columns,
at: None,
},
query,
from: None,
Expand Down
1 change: 1 addition & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ pub fn table_alias(explicit: bool, name: impl Into<String>) -> Option<TableAlias
explicit,
name: Ident::new(name),
columns: vec![],
at: None,
})
}

Expand Down
4 changes: 4 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ fn parse_select_with_table_alias() {
TableAliasColumnDef::from_name("B"),
TableAliasColumnDef::from_name("C"),
],
at: None,
}),
args: None,
with_hints: vec![],
Expand Down Expand Up @@ -7858,6 +7859,7 @@ fn parse_recursive_cte() {
span: Span::empty(),
},
columns: vec![TableAliasColumnDef::from_name("val")],
at: None,
},
query: Box::new(cte_query),
from: None,
Expand Down Expand Up @@ -11343,6 +11345,7 @@ fn parse_pivot_table() {
TableAliasColumnDef::from_name("c"),
TableAliasColumnDef::from_name("d"),
],
at: None,
})
}
);
Expand Down Expand Up @@ -11481,6 +11484,7 @@ fn parse_unpivot_table() {
.into_iter()
.map(TableAliasColumnDef::from_name)
.collect(),
at: None,
}),
};
pretty_assertions::assert_eq!(verified_only_select(sql).from[0].relation, base_unpivot);
Expand Down
3 changes: 2 additions & 1 deletion tests/sqlparser_mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ fn parse_mssql_delimited_identifiers() {
&Some(TableAlias {
explicit: false,
name: Ident::with_quote('[', "WHERE"),
columns: vec![]
columns: vec![],
at: None,
})
);
}
Expand Down
24 changes: 24 additions & 0 deletions tests/sqlparser_redshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,27 @@ fn test_null_treatment_inside_and_outside_window_function() {
redshift().verified_stmt("SELECT FIRST_VALUE(1 IGNORE NULLS) OVER () FROM (SELECT 1) t");
redshift().verified_stmt("SELECT FIRST_VALUE(1) IGNORE NULLS OVER () FROM (SELECT 1) t");
}

#[test]
fn test_partiql_from_alias_with_at_index() {
redshift().verified_stmt("SELECT * FROM lineitem AS l (a, b, c) AT idx");

let sql =
"SELECT index, val FROM (SELECT array('AAA', 'BBB') AS val) AS b, b.val AS val AT index";
let select = redshift().verified_only_select(sql);

match &select.from[1].relation {
TableFactor::Table { name, alias, .. } => {
assert_eq!(
name,
&ObjectName::from(vec![Ident::new("b"), Ident::new("val")])
);
assert_eq!(alias.as_ref().map(|a| &a.name), Some(&Ident::new("val")));
assert_eq!(
alias.as_ref().and_then(|a| a.at.as_ref()),
Some(&Ident::new("index"))
);
}
_ => panic!("expected table factor"),
}
}
Loading