Skip to content

Commit a737aaf

Browse files
PostgreSQL: Support ONLY and * table inheritance markers
1 parent b22bf61 commit a737aaf

14 files changed

Lines changed: 237 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
@@ -2056,6 +2056,7 @@ impl Spanned for TableFactor {
20562056
json_path: _,
20572057
sample: _,
20582058
index_directives: _,
2059+
inheritance: _,
20592060
} => union_spans(
20602061
name.0
20612062
.iter()

‎src/dialect/generic.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ impl Dialect for GenericDialect {
329329
true
330330
}
331331

332+
fn supports_table_inheritance_markers(&self) -> bool {
333+
true
334+
}
335+
332336
fn supports_select_format(&self) -> bool {
333337
true
334338
}

‎src/dialect/mod.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,6 +2118,20 @@ pub trait Dialect: Debug + Any {
21182118
false
21192119
}
21202120

2121+
/// Returns true if this dialect supports the `ONLY` and `*` table
2122+
/// inheritance markers on a table factor.
2123+
///
2124+
/// Example:
2125+
/// ```sql
2126+
/// SELECT * FROM ONLY parent;
2127+
/// SELECT * FROM parent *;
2128+
/// ```
2129+
///
2130+
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM)
2131+
fn supports_table_inheritance_markers(&self) -> bool {
2132+
false
2133+
}
2134+
21212135
/// Returns true if this dialect supports the `FORMAT` clause in `SELECT` statements.
21222136
///
21232137
/// Example:

‎src/dialect/postgresql.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,4 +587,9 @@ impl Dialect for PostgreSqlDialect {
587587
fn supports_attach_partition_of(&self) -> bool {
588588
true
589589
}
590+
591+
/// See <https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM>
592+
fn supports_table_inheritance_markers(&self) -> bool {
593+
true
594+
}
590595
}

‎src/parser/mod.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17447,6 +17447,10 @@ impl<'a> Parser<'a> {
1744717447
// Stage reference: @mystage or @namespace.stage (e.g. Snowflake)
1744817448
self.parse_snowflake_stage_table_factor()
1744917449
} else {
17450+
let inheritance_markers = self.dialect.supports_table_inheritance_markers();
17451+
let only = inheritance_markers && self.parse_keyword(Keyword::ONLY);
17452+
let only_parenthesized = only && self.consume_token(&Token::LParen);
17453+
1745017454
// Unquoted reserved keywords, e.g. `ON`, are not table names. The
1745117455
// keyword is consumed first so that `is_table_factor` peeks past it,
1745217456
// as it does at the trailing comma check.
@@ -17463,6 +17467,19 @@ impl<'a> Parser<'a> {
1746317467

1746417468
let name = self.parse_object_name(true)?;
1746517469

17470+
let inheritance = if only {
17471+
if only_parenthesized {
17472+
self.expect_token(&Token::RParen)?;
17473+
}
17474+
Some(TableInheritance::Only {
17475+
parenthesized: only_parenthesized,
17476+
})
17477+
} else if inheritance_markers && self.consume_token(&Token::Mul) {
17478+
Some(TableInheritance::IncludeDescendants)
17479+
} else {
17480+
None
17481+
};
17482+
1746617483
let json_path = match &self.peek_token_ref().token {
1746717484
Token::LBracket if self.dialect.supports_partiql() => Some(self.parse_json_path()?),
1746817485
_ => None,
@@ -17540,6 +17557,7 @@ impl<'a> Parser<'a> {
1754017557
json_path,
1754117558
sample,
1754217559
index_directives,
17560+
inheritance,
1754317561
};
1754417562

1754517563
while let Some(kw) = self.parse_one_of_keywords(&[Keyword::PIVOT, Keyword::UNPIVOT]) {
@@ -17590,6 +17608,7 @@ impl<'a> Parser<'a> {
1759017608
json_path: None,
1759117609
sample: None,
1759217610
index_directives: vec![],
17611+
inheritance: None,
1759317612
})
1759417613
}
1759517614

‎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)