Skip to content

Commit 2d00ea7

Browse files
thomas-jeepebenesch
authored andcommitted
Add lateral derived support
1 parent fe10fac commit 2d00ea7

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

src/sqlast/query.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub enum TableFactor {
209209
with_hints: Vec<ASTNode>,
210210
},
211211
Derived {
212+
lateral: bool,
212213
subquery: Box<SQLQuery>,
213214
alias: Option<SQLIdent>,
214215
},
@@ -235,8 +236,16 @@ impl ToString for TableFactor {
235236
}
236237
s
237238
}
238-
TableFactor::Derived { subquery, alias } => {
239-
let mut s = format!("({})", subquery.to_string());
239+
TableFactor::Derived {
240+
lateral,
241+
subquery,
242+
alias,
243+
} => {
244+
let mut s = String::new();
245+
if *lateral {
246+
s += "LATERAL ";
247+
}
248+
s += &format!("({})", subquery.to_string());
240249
if let Some(alias) = alias {
241250
s += &format!(" AS {}", alias);
242251
}

src/sqlparser.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1464,11 +1464,18 @@ impl Parser {
14641464

14651465
/// A table name or a parenthesized subquery, followed by optional `[AS] alias`
14661466
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
1467+
let lateral = self.parse_keyword("LATERAL");
14671468
if self.consume_token(&Token::LParen) {
14681469
let subquery = Box::new(self.parse_query()?);
14691470
self.expect_token(&Token::RParen)?;
14701471
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1471-
Ok(TableFactor::Derived { subquery, alias })
1472+
Ok(TableFactor::Derived {
1473+
lateral,
1474+
subquery,
1475+
alias,
1476+
})
1477+
} else if lateral {
1478+
self.expected("subquery after LATERAL", self.peek_token())
14721479
} else {
14731480
let name = self.parse_object_name()?;
14741481
// Postgres, MSSQL: table-valued functions:

tests/sqlparser_common.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,50 @@ fn parse_fetch_variations() {
15691569
);
15701570
}
15711571

1572+
#[test]
1573+
fn lateral_derived() {
1574+
fn chk(lateral_in: bool) {
1575+
let lateral_str = if lateral_in { "LATERAL " } else { "" };
1576+
let sql = format!(
1577+
"SELECT * FROM customer LEFT JOIN {}\
1578+
(SELECT * FROM order WHERE order.customer = customer.id LIMIT 3) AS order ON true",
1579+
lateral_str
1580+
);
1581+
let select = verified_only_select(&sql);
1582+
assert_eq!(select.joins.len(), 1);
1583+
assert_eq!(
1584+
select.joins[0].join_operator,
1585+
JoinOperator::LeftOuter(JoinConstraint::On(ASTNode::SQLValue(Value::Boolean(true))))
1586+
);
1587+
if let TableFactor::Derived {
1588+
lateral,
1589+
ref subquery,
1590+
ref alias,
1591+
} = select.joins[0].relation
1592+
{
1593+
assert_eq!(lateral_in, lateral);
1594+
assert_eq!(Some("order".to_string()), *alias);
1595+
assert_eq!(
1596+
subquery.to_string(),
1597+
"SELECT * FROM order WHERE order.customer = customer.id LIMIT 3"
1598+
);
1599+
} else {
1600+
unreachable!()
1601+
}
1602+
}
1603+
chk(false);
1604+
chk(true);
1605+
1606+
let sql = "SELECT * FROM customer LEFT JOIN LATERAL generate_series(1, customer.id)";
1607+
let res = parse_sql_statements(sql);
1608+
assert_eq!(
1609+
ParserError::ParserError(
1610+
"Expected subquery after LATERAL, found: generate_series".to_string()
1611+
),
1612+
res.unwrap_err()
1613+
);
1614+
}
1615+
15721616
#[test]
15731617
#[should_panic(
15741618
expected = "Parse results with GenericSqlDialect are different from PostgreSqlDialect"

0 commit comments

Comments
 (0)