From 50f5c3a246145135e4c428685d6c05acf0a157a5 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 15 Apr 2026 08:41:28 -0400 Subject: [PATCH 1/2] Redshift: PartiQL AT --- src/ast/query.rs | 5 +++++ src/ast/spans.rs | 7 ++++++- src/parser/mod.rs | 8 ++++++++ src/test_utils.rs | 1 + tests/sqlparser_common.rs | 4 ++++ tests/sqlparser_mssql.rs | 3 ++- tests/sqlparser_redshift.rs | 24 ++++++++++++++++++++++++ 7 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index 49ba86f1f7..36e858a929 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -2527,6 +2527,8 @@ pub struct TableAlias { pub name: Ident, /// Optional column aliases declared in parentheses after the table alias. pub columns: Vec, + /// Optional PartiQL index alias declared with `AT`. + pub at: Option, } impl fmt::Display for TableAlias { @@ -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(()) } } diff --git a/src/ast/spans.rs b/src/ast/spans.rs index e7a8f94f2f..8b775a118d 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -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)), + ) } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a5526723b5..7589480d65 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -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), @@ -14461,6 +14467,7 @@ impl<'a> Parser<'a> { explicit: false, name, columns: vec![], + at: None, }, query, from: None, @@ -14505,6 +14512,7 @@ impl<'a> Parser<'a> { explicit: false, name, columns, + at: None, }, query, from: None, diff --git a/src/test_utils.rs b/src/test_utils.rs index 9ba5960e83..669ea1ecdb 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -374,6 +374,7 @@ pub fn table_alias(explicit: bool, name: impl Into) -> Option { + 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"), + } +} From fe58eb422ecf38249fa91f4f56dd3c09663d5945 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 15 Apr 2026 08:45:45 -0400 Subject: [PATCH 2/2] Redshift: PartiQL AT --- tests/sqlparser_redshift.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index 7bf99bfcf2..e75267f099 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -521,7 +521,7 @@ fn test_null_treatment_inside_and_outside_window_function() { #[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);