Preserve optional AS keyword in aliases (#2103)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run

This commit is contained in:
xitep 2025-11-25 16:54:42 +01:00 committed by GitHub
parent 2b8e99c665
commit 2ceae006a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 202 additions and 269 deletions

View file

@ -1902,7 +1902,7 @@ impl fmt::Display for TableFactor {
write!(f, " {sample}")?;
}
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
if !index_hints.is_empty() {
write!(f, " {}", display_separated(index_hints, " "))?;
@ -1932,7 +1932,7 @@ impl fmt::Display for TableFactor {
NewLine.fmt(f)?;
f.write_str(")")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -1948,14 +1948,14 @@ impl fmt::Display for TableFactor {
write!(f, "{name}")?;
write!(f, "({})", display_comma_separated(args))?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::TableFunction { expr, alias } => {
write!(f, "TABLE({expr})")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -1973,13 +1973,13 @@ impl fmt::Display for TableFactor {
}
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
if *with_offset {
write!(f, " WITH OFFSET")?;
}
if let Some(alias) = with_offset_alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -1995,7 +1995,7 @@ impl fmt::Display for TableFactor {
columns = display_comma_separated(columns)
)?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -2014,7 +2014,7 @@ impl fmt::Display for TableFactor {
write!(f, " WITH ({})", display_comma_separated(columns))?;
}
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -2024,7 +2024,7 @@ impl fmt::Display for TableFactor {
} => {
write!(f, "({table_with_joins})")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -2051,8 +2051,8 @@ impl fmt::Display for TableFactor {
write!(f, " DEFAULT ON NULL ({expr})")?;
}
write!(f, ")")?;
if alias.is_some() {
write!(f, " AS {}", alias.as_ref().unwrap())?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
@ -2075,8 +2075,8 @@ impl fmt::Display for TableFactor {
name,
display_comma_separated(columns)
)?;
if alias.is_some() {
write!(f, " AS {}", alias.as_ref().unwrap())?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
@ -2109,8 +2109,8 @@ impl fmt::Display for TableFactor {
}
write!(f, "PATTERN ({pattern}) ")?;
write!(f, "DEFINE {})", display_comma_separated(symbols))?;
if alias.is_some() {
write!(f, " AS {}", alias.as_ref().unwrap())?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
@ -2135,7 +2135,7 @@ impl fmt::Display for TableFactor {
columns = display_comma_separated(columns)
)?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
}
@ -2168,7 +2168,7 @@ impl fmt::Display for TableFactor {
write!(f, ")")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
write!(f, " {alias}")?;
}
Ok(())
@ -2181,13 +2181,17 @@ impl fmt::Display for TableFactor {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableAlias {
/// Tells whether the alias was introduced with an explicit, preceding "AS"
/// keyword, e.g. `AS name`. Typically, the keyword is preceding the name
/// (e.g. `.. FROM table AS t ..`).
pub explicit: bool,
pub name: Ident,
pub columns: Vec<TableAliasColumnDef>,
}
impl fmt::Display for TableAlias {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)?;
write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
if !self.columns.is_empty() {
write!(f, " ({})", display_comma_separated(&self.columns))?;
}

View file

@ -15,10 +15,13 @@
// specific language governing permissions and limitations
// under the License.
use crate::ast::{
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
ExportData, Owner, TypedString,
use crate::{
ast::{
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
ExportData, Owner, TypedString,
},
tokenizer::TokenWithSpan,
};
use core::iter;
@ -96,6 +99,12 @@ pub trait Spanned {
fn span(&self) -> Span;
}
impl Spanned for TokenWithSpan {
fn span(&self) -> Span {
self.span
}
}
impl Spanned for Query {
fn span(&self) -> Span {
let Query {
@ -2079,9 +2088,12 @@ impl Spanned for FunctionArgExpr {
impl Spanned for TableAlias {
fn span(&self) -> Span {
let TableAlias { name, columns } = self;
union_spans(iter::once(name.span).chain(columns.iter().map(|i| i.span())))
let TableAlias {
explicit: _,
name,
columns,
} = self;
union_spans(core::iter::once(name.span).chain(columns.iter().map(Spanned::span)))
}
}

View file

@ -11140,10 +11140,15 @@ impl<'a> Parser<'a> {
fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
parser.dialect.is_table_factor_alias(explicit, kw, parser)
}
let explicit = self.peek_keyword(Keyword::AS);
match self.parse_optional_alias_inner(None, validator)? {
Some(name) => {
let columns = self.parse_table_alias_column_defs()?;
Ok(Some(TableAlias { name, columns }))
Ok(Some(TableAlias {
explicit,
name,
columns,
}))
}
None => Ok(None),
}
@ -12775,6 +12780,7 @@ impl<'a> Parser<'a> {
let closing_paren_token = self.expect_token(&Token::RParen)?;
let alias = TableAlias {
explicit: false,
name,
columns: vec![],
};
@ -12801,7 +12807,11 @@ impl<'a> Parser<'a> {
let query = self.parse_query()?;
let closing_paren_token = self.expect_token(&Token::RParen)?;
let alias = TableAlias { name, columns };
let alias = TableAlias {
explicit: false,
name,
columns,
};
Cte {
alias,
query,

View file

@ -368,8 +368,9 @@ pub fn single_quoted_string(s: impl Into<String>) -> Value {
Value::SingleQuotedString(s.into())
}
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
pub fn table_alias(explicit: bool, name: impl Into<String>) -> Option<TableAlias> {
Some(TableAlias {
explicit,
name: Ident::new(name),
columns: vec![],
})
@ -405,13 +406,14 @@ pub fn table_from_name(name: ObjectName) -> TableFactor {
}
}
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
pub fn table_with_alias(
name: impl Into<String>,
with_as_keyword: bool,
alias: impl Into<String>,
) -> TableFactor {
TableFactor::Table {
name: ObjectName::from(vec![Ident::new(name)]),
alias: Some(TableAlias {
name: Ident::new(alias),
columns: vec![],
}),
alias: table_alias(with_as_keyword, alias),
args: None,
with_hints: vec![],
version: None,