diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index d342276e4..3bec6ceba 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -33,7 +33,21 @@ use crate::keywords::Keyword; use crate::parser::{Parser, ParserError}; use crate::tokenizer::Token; -use super::keywords::RESERVED_FOR_IDENTIFIER; +use super::keywords::{self, RESERVED_FOR_IDENTIFIER}; + +/// Keywords in [`keywords::RESERVED_FOR_TABLE_ALIAS`] because of other dialects, yet are safe for aliasing in PostgreSQL. +/// See . +const RESERVED_EXCLUSIONS_FOR_TABLE_ALIAS: &[Keyword] = &[ + Keyword::CLUSTER, + Keyword::DISTRIBUTE, + Keyword::EXPLAIN, + Keyword::MINUS, + Keyword::SAMPLE, + Keyword::SORT, + Keyword::START, + Keyword::TOP, + Keyword::VIEW, +]; /// A [`Dialect`] for [PostgreSQL](https://www.postgresql.org/) #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -91,6 +105,11 @@ impl Dialect for PostgreSqlDialect { } } + fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool { + !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw) + || RESERVED_EXCLUSIONS_FOR_TABLE_ALIAS.contains(kw) + } + /// See fn is_custom_operator_part(&self, ch: char) -> bool { matches!( diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 57a5400f7..17f8343be 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -9852,3 +9852,26 @@ fn parse_alter_table_constraint_check_no_inherit() { } pg_and_generic().verified_stmt("ALTER TABLE docs ADD CONSTRAINT c CHECK (id > 0) NO INHERIT"); } + +#[test] +fn parse_non_reserved_keywords_as_table_alias() { + // PostgreSQL allows these keywords as explicit table aliases. + for kw in [ + "cluster", + "distribute", + "explain", + "minus", + "sample", + "sort", + "start", + "top", + "view", + ] { + pg().verified_stmt(&format!( + "SELECT * FROM tbl_name AS {kw} JOIN tbl_name_2 ON {kw}.id = tbl_name_2.id" + )); + pg().verified_stmt(&format!( + "SELECT * FROM tbl_name {kw} JOIN tbl_name_2 ON {kw}.id = tbl_name_2.id" + )); + } +}