Skip to content
Merged
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
3 changes: 3 additions & 0 deletions fuzz/fuzz_seeds/postgres_table_inheritance_markers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SELECT * FROM ONLY (a) JOIN b * AS x ON a.id = x.id;
UPDATE ONLY t SET id = 1;
DELETE FROM t *;
4 changes: 2 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ pub use self::query::{
SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SelectModifiers,
SetExpr, SetOperator, SetQuantifier, Setting, SymbolDefinition, Table, TableAlias,
TableAliasColumnDef, TableFactor, TableFunctionArgs, TableIndexDirective,
TableIndexHintForClause, TableIndexHintType, TableIndexHints, TableIndexType, TableSample,
TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
TableIndexHintForClause, TableIndexHintType, TableIndexHints, TableIndexType, TableInheritance,
TableSample, TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier, TableSampleUnit, TableVersion,
TableWithJoins, Top, TopQuantity, UpdateTableFromKind, ValueTableMode, Values,
WildcardAdditionalOptions, With, WithFill, XmlNamespaceDefinition, XmlPassingArgument,
Expand Down
30 changes: 29 additions & 1 deletion src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,22 @@ impl fmt::Display for TableIndexDirective {
}
}

/// PostgreSQL table inheritance marker, see [`TableFactor::Table::inheritance`].
///
/// <https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM>
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableInheritance {
/// `ONLY name`, or `ONLY (name)` when `parenthesized`, excluding descendant tables.
Only {
/// Whether the name was written in parentheses.
parenthesized: bool,
},
/// `name *`, explicitly including descendant tables.
IncludeDescendants,
}

/// A table name or a parenthesized subquery with an optional alias
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -1516,6 +1532,8 @@ pub enum TableFactor {
sample: Option<TableSampleKind>,
/// Optional table-level index-selection hints or requirements.
index_directives: Vec<TableIndexDirective>,
/// PostgreSQL `ONLY` or `*` inheritance marker.
inheritance: Option<TableInheritance>,
},
/// A derived table (a parenthesized subquery), optionally `LATERAL`.
Derived {
Expand Down Expand Up @@ -2250,8 +2268,18 @@ impl fmt::Display for TableFactor {
json_path,
sample,
index_directives,
inheritance,
} => {
name.fmt(f)?;
match inheritance {
Some(TableInheritance::Only {
parenthesized: true,
}) => write!(f, "ONLY ({name})")?,
Some(TableInheritance::Only {
parenthesized: false,
}) => write!(f, "ONLY {name}")?,
Some(TableInheritance::IncludeDescendants) => write!(f, "{name} *")?,
None => name.fmt(f)?,
}
if let Some(json_path) = json_path {
json_path.fmt(f)?;
}
Expand Down
1 change: 1 addition & 0 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,7 @@ impl Spanned for TableFactor {
json_path: _,
sample: _,
index_directives: _,
inheritance: _,
} => union_spans(
name.0
.iter()
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ impl Dialect for GenericDialect {
true
}

fn supports_table_inheritance_markers(&self) -> bool {
true
}

fn supports_select_format(&self) -> bool {
true
}
Expand Down
14 changes: 14 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,20 @@ pub trait Dialect: Debug + Any {
false
}

/// Returns true if this dialect supports the `ONLY` and `*` table
/// inheritance markers on a table factor.
///
/// Example:
/// ```sql
/// SELECT * FROM ONLY parent;
/// SELECT * FROM parent *;
/// ```
///
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM)
fn supports_table_inheritance_markers(&self) -> bool {
false
}

/// Returns true if this dialect supports the `FORMAT` clause in `SELECT` statements.
///
/// Example:
Expand Down
5 changes: 5 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,4 +613,9 @@ impl Dialect for PostgreSqlDialect {
fn supports_attach_partition_of(&self) -> bool {
true
}

/// See <https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM>
fn supports_table_inheritance_markers(&self) -> bool {
true
}
}
19 changes: 19 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17435,6 +17435,10 @@ impl<'a> Parser<'a> {
// Stage reference: @mystage or @namespace.stage (e.g. Snowflake)
self.parse_snowflake_stage_table_factor()
} else {
let inheritance_markers = self.dialect.supports_table_inheritance_markers();
let only = inheritance_markers && self.parse_keyword(Keyword::ONLY);
let only_parenthesized = only && self.consume_token(&Token::LParen);

// Unquoted reserved keywords, e.g. `ON`, are not table names. The
// keyword is consumed first so that `is_table_factor` peeks past it,
// as it does at the trailing comma check.
Expand All @@ -17451,6 +17455,19 @@ impl<'a> Parser<'a> {

let name = self.parse_object_name(true)?;

let inheritance = if only {
if only_parenthesized {
self.expect_token(&Token::RParen)?;
}
Some(TableInheritance::Only {
parenthesized: only_parenthesized,
})
} else if inheritance_markers && self.consume_token(&Token::Mul) {
Some(TableInheritance::IncludeDescendants)
} else {
None
};

let json_path = match &self.peek_token_ref().token {
Token::LBracket if self.dialect.supports_partiql() => Some(self.parse_json_path()?),
_ => None,
Expand Down Expand Up @@ -17528,6 +17545,7 @@ impl<'a> Parser<'a> {
json_path,
sample,
index_directives,
inheritance,
};

while let Some(kw) = self.parse_one_of_keywords(&[Keyword::PIVOT, Keyword::UNPIVOT]) {
Expand Down Expand Up @@ -17578,6 +17596,7 @@ impl<'a> Parser<'a> {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
})
}

Expand Down
3 changes: 3 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ pub fn table(name: impl Into<String>) -> TableFactor {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}
}

Expand All @@ -406,6 +407,7 @@ pub fn table_from_name(name: ObjectName) -> TableFactor {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}
}

Expand All @@ -425,6 +427,7 @@ pub fn table_with_alias(
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}
}

Expand Down
3 changes: 3 additions & 0 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,7 @@ fn parse_table_time_travel() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![]
},]
Expand Down Expand Up @@ -1883,6 +1884,7 @@ fn parse_merge() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
table
);
Expand All @@ -1898,6 +1900,7 @@ fn parse_merge() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
source
);
Expand Down
23 changes: 23 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ fn parse_update_with_table_alias() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![],
},
Expand Down Expand Up @@ -745,6 +746,7 @@ fn parse_select_with_table_alias() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![],
}]
Expand Down Expand Up @@ -951,6 +953,7 @@ fn parse_where_delete_with_alias_statement() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
from[0].relation,
);
Expand All @@ -967,6 +970,7 @@ fn parse_where_delete_with_alias_statement() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![],
}]),
Expand Down Expand Up @@ -8227,6 +8231,7 @@ fn parse_joins_on() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global,
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -8369,6 +8374,7 @@ fn parse_joins_using() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: f(JoinConstraint::Using(vec![ObjectName::from(vec![
Expand Down Expand Up @@ -8464,6 +8470,7 @@ fn parse_natural_join() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: f(JoinConstraint::Natural),
Expand Down Expand Up @@ -10980,6 +10987,7 @@ fn parse_merge() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}
);
assert_eq!(table, table_no_into);
Expand Down Expand Up @@ -12457,6 +12465,7 @@ fn parse_pivot_table() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}),
aggregate_functions: vec![
expected_function("a", None),
Expand Down Expand Up @@ -12537,6 +12546,7 @@ fn parse_pivot_table() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}),
aggregate_functions: vec![
ExprWithAlias {
Expand Down Expand Up @@ -12623,6 +12633,7 @@ fn parse_unpivot_table() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}),
null_inclusion: None,
value: Expr::Identifier(Ident::new("quantity")),
Expand Down Expand Up @@ -12882,6 +12893,7 @@ fn parse_select_table_with_index_hints() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![],
}]
Expand Down Expand Up @@ -12911,6 +12923,7 @@ fn parse_pivot_unpivot_table() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
}),
null_inclusion: None,
value: Expr::Identifier(Ident::new("population")),
Expand Down Expand Up @@ -19000,6 +19013,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![Join {
relation: TableFactor::Table {
Expand All @@ -19013,6 +19027,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -19067,6 +19082,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![Join {
relation: TableFactor::Table {
Expand All @@ -19080,6 +19096,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: JoinOperator::Join(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -19134,6 +19151,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![Join {
relation: TableFactor::Table {
Expand All @@ -19147,6 +19165,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: JoinOperator::Left(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -19201,6 +19220,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![Join {
relation: TableFactor::Table {
Expand All @@ -19214,6 +19234,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: JoinOperator::Right(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -19268,6 +19289,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
joins: vec![Join {
relation: TableFactor::Table {
Expand All @@ -19281,6 +19303,7 @@ fn test_nested_join_without_parentheses() {
json_path: None,
sample: None,
index_directives: vec![],
inheritance: None,
},
global: false,
join_operator: JoinOperator::FullOuter(JoinConstraint::On(
Expand Down
Loading
Loading