Skip to content

Commit a368259

Browse files
PostgreSQL: Support ONLY and * table inheritance markers (#2770)
1 parent 087b1fc commit a368259

14 files changed

Lines changed: 265 additions & 7 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SELECT * FROM ONLY (a) JOIN b * AS x ON a.id = x.id;
2+
UPDATE ONLY t SET id = 1;
3+
DELETE FROM t *;

‎src/ast/mod.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ pub use self::query::{
112112
SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SelectModifiers,
113113
SetExpr, SetOperator, SetQuantifier, Setting, SymbolDefinition, Table, TableAlias,
114114
TableAliasColumnDef, TableFactor, TableFunctionArgs, TableIndexDirective,
115-
TableIndexHintForClause, TableIndexHintType, TableIndexHints, TableIndexType, TableSample,
116-
TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
115+
TableIndexHintForClause, TableIndexHintType, TableIndexHints, TableIndexType, TableInheritance,
116+
TableSample, TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
117117
TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier, TableSampleUnit, TableVersion,
118118
TableWithJoins, Top, TopQuantity, UpdateTableFromKind, ValueTableMode, Values,
119119
WildcardAdditionalOptions, With, WithFill, XmlNamespaceDefinition, XmlPassingArgument,

‎src/ast/query.rs‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,22 @@ impl fmt::Display for TableIndexDirective {
14771477
}
14781478
}
14791479

1480+
/// PostgreSQL table inheritance marker, see [`TableFactor::Table::inheritance`].
1481+
///
1482+
/// <https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM>
1483+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1484+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1485+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1486+
pub enum TableInheritance {
1487+
/// `ONLY name`, or `ONLY (name)` when `parenthesized`, excluding descendant tables.
1488+
Only {
1489+
/// Whether the name was written in parentheses.
1490+
parenthesized: bool,
1491+
},
1492+
/// `name *`, explicitly including descendant tables.
1493+
IncludeDescendants,
1494+
}
1495+
14801496
/// A table name or a parenthesized subquery with an optional alias
14811497
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
14821498
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -1516,6 +1532,8 @@ pub enum TableFactor {
15161532
sample: Option<TableSampleKind>,
15171533
/// Optional table-level index-selection hints or requirements.
15181534
index_directives: Vec<TableIndexDirective>,
1535+
/// PostgreSQL `ONLY` or `*` inheritance marker.
1536+
inheritance: Option<TableInheritance>,
15191537
},
15201538
/// A derived table (a parenthesized subquery), optionally `LATERAL`.
15211539
Derived {
@@ -2250,8 +2268,18 @@ impl fmt::Display for TableFactor {
22502268
json_path,
22512269
sample,
22522270
index_directives,
2271+
inheritance,
22532272
} => {
2254-
name.fmt(f)?;
2273+
match inheritance {
2274+
Some(TableInheritance::Only {
2275+
parenthesized: true,
2276+
}) => write!(f, "ONLY ({name})")?,
2277+
Some(TableInheritance::Only {
2278+
parenthesized: false,
2279+
}) => write!(f, "ONLY {name}")?,
2280+
Some(TableInheritance::IncludeDescendants) => write!(f, "{name} *")?,
2281+
None => name.fmt(f)?,
2282+
}
22552283
if let Some(json_path) = json_path {
22562284
json_path.fmt(f)?;
22572285
}

‎src/ast/spans.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,7 @@ impl Spanned for TableFactor {
20592059
json_path: _,
20602060
sample: _,
20612061
index_directives: _,
2062+
inheritance: _,
20622063
} => union_spans(
20632064
name.0
20642065
.iter()

‎src/dialect/generic.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,10 @@ impl Dialect for GenericDialect {
333333
true
334334
}
335335

336+
fn supports_table_inheritance_markers(&self) -> bool {
337+
true
338+
}
339+
336340
fn supports_select_format(&self) -> bool {
337341
true
338342
}

‎src/dialect/mod.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,20 @@ pub trait Dialect: Debug + Any {
21742174
false
21752175
}
21762176

2177+
/// Returns true if this dialect supports the `ONLY` and `*` table
2178+
/// inheritance markers on a table factor.
2179+
///
2180+
/// Example:
2181+
/// ```sql
2182+
/// SELECT * FROM ONLY parent;
2183+
/// SELECT * FROM parent *;
2184+
/// ```
2185+
///
2186+
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM)
2187+
fn supports_table_inheritance_markers(&self) -> bool {
2188+
false
2189+
}
2190+
21772191
/// Returns true if this dialect supports the `FORMAT` clause in `SELECT` statements.
21782192
///
21792193
/// Example:

‎src/dialect/postgresql.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,4 +613,9 @@ impl Dialect for PostgreSqlDialect {
613613
fn supports_attach_partition_of(&self) -> bool {
614614
true
615615
}
616+
617+
/// See <https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM>
618+
fn supports_table_inheritance_markers(&self) -> bool {
619+
true
620+
}
616621
}

‎src/parser/mod.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17437,6 +17437,10 @@ impl<'a> Parser<'a> {
1743717437
// Stage reference: @mystage or @namespace.stage (e.g. Snowflake)
1743817438
self.parse_snowflake_stage_table_factor()
1743917439
} else {
17440+
let inheritance_markers = self.dialect.supports_table_inheritance_markers();
17441+
let only = inheritance_markers && self.parse_keyword(Keyword::ONLY);
17442+
let only_parenthesized = only && self.consume_token(&Token::LParen);
17443+
1744017444
// Unquoted reserved keywords, e.g. `ON`, are not table names. The
1744117445
// keyword is consumed first so that `is_table_factor` peeks past it,
1744217446
// as it does at the trailing comma check.
@@ -17453,6 +17457,19 @@ impl<'a> Parser<'a> {
1745317457

1745417458
let name = self.parse_object_name(true)?;
1745517459

17460+
let inheritance = if only {
17461+
if only_parenthesized {
17462+
self.expect_token(&Token::RParen)?;
17463+
}
17464+
Some(TableInheritance::Only {
17465+
parenthesized: only_parenthesized,
17466+
})
17467+
} else if inheritance_markers && self.consume_token(&Token::Mul) {
17468+
Some(TableInheritance::IncludeDescendants)
17469+
} else {
17470+
None
17471+
};
17472+
1745617473
let json_path = match &self.peek_token_ref().token {
1745717474
Token::LBracket if self.dialect.supports_partiql() => Some(self.parse_json_path()?),
1745817475
_ => None,
@@ -17530,6 +17547,7 @@ impl<'a> Parser<'a> {
1753017547
json_path,
1753117548
sample,
1753217549
index_directives,
17550+
inheritance,
1753317551
};
1753417552

1753517553
while let Some(kw) = self.parse_one_of_keywords(&[Keyword::PIVOT, Keyword::UNPIVOT]) {
@@ -17580,6 +17598,7 @@ impl<'a> Parser<'a> {
1758017598
json_path: None,
1758117599
sample: None,
1758217600
index_directives: vec![],
17601+
inheritance: None,
1758317602
})
1758417603
}
1758517604

‎src/test_utils.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ pub fn table(name: impl Into<String>) -> TableFactor {
391391
json_path: None,
392392
sample: None,
393393
index_directives: vec![],
394+
inheritance: None,
394395
}
395396
}
396397

@@ -406,6 +407,7 @@ pub fn table_from_name(name: ObjectName) -> TableFactor {
406407
json_path: None,
407408
sample: None,
408409
index_directives: vec![],
410+
inheritance: None,
409411
}
410412
}
411413

@@ -425,6 +427,7 @@ pub fn table_with_alias(
425427
json_path: None,
426428
sample: None,
427429
index_directives: vec![],
430+
inheritance: None,
428431
}
429432
}
430433

‎tests/sqlparser_bigquery.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,7 @@ fn parse_table_time_travel() {
17681768
json_path: None,
17691769
sample: None,
17701770
index_directives: vec![],
1771+
inheritance: None,
17711772
},
17721773
joins: vec![]
17731774
},]
@@ -1883,6 +1884,7 @@ fn parse_merge() {
18831884
json_path: None,
18841885
sample: None,
18851886
index_directives: vec![],
1887+
inheritance: None,
18861888
},
18871889
table
18881890
);
@@ -1898,6 +1900,7 @@ fn parse_merge() {
18981900
json_path: None,
18991901
sample: None,
19001902
index_directives: vec![],
1903+
inheritance: None,
19011904
},
19021905
source
19031906
);

0 commit comments

Comments
 (0)