Skip to content

Commit d169569

Browse files
thomas-jeepebenesch
authored andcommitted
Add lateral derived support
1 parent 01c7850 commit d169569

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
@@ -1390,11 +1390,18 @@ impl Parser {
13901390

13911391
/// A table name or a parenthesized subquery, followed by optional `[AS] alias`
13921392
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
1393+
let lateral = self.parse_keyword("LATERAL");
13931394
if self.consume_token(&Token::LParen) {
13941395
let subquery = Box::new(self.parse_query()?);
13951396
self.expect_token(&Token::RParen)?;
13961397
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1397-
Ok(TableFactor::Derived { subquery, alias })
1398+
Ok(TableFactor::Derived {
1399+
lateral,
1400+
subquery,
1401+
alias,
1402+
})
1403+
} else if lateral {
1404+
self.expected("subquery after LATERAL", self.peek_token())
13981405
} else {
13991406
let name = self.parse_object_name()?;
14001407
// Postgres, MSSQL: table-valued functions:

tests/sqlparser_common.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,50 @@ fn parse_fetch_variations() {
13901390
);
13911391
}
13921392

1393+
#[test]
1394+
fn lateral_derived() {
1395+
fn chk(lateral_in: bool) {
1396+
let lateral_str = if lateral_in { "LATERAL " } else { "" };
1397+
let sql = format!(
1398+
"SELECT * FROM customer LEFT JOIN {}\
1399+
(SELECT * FROM order WHERE order.customer = customer.id LIMIT 3) AS order ON true",
1400+
lateral_str
1401+
);
1402+
let select = verified_only_select(&sql);
1403+
assert_eq!(select.joins.len(), 1);
1404+
assert_eq!(
1405+
select.joins[0].join_operator,
1406+
JoinOperator::LeftOuter(JoinConstraint::On(ASTNode::SQLValue(Value::Boolean(true))))
1407+
);
1408+
if let TableFactor::Derived {
1409+
lateral,
1410+
ref subquery,
1411+
ref alias,
1412+
} = select.joins[0].relation
1413+
{
1414+
assert_eq!(lateral_in, lateral);
1415+
assert_eq!(Some("order".to_string()), *alias);
1416+
assert_eq!(
1417+
subquery.to_string(),
1418+
"SELECT * FROM order WHERE order.customer = customer.id LIMIT 3"
1419+
);
1420+
} else {
1421+
unreachable!()
1422+
}
1423+
}
1424+
chk(false);
1425+
chk(true);
1426+
1427+
let sql = "SELECT * FROM customer LEFT JOIN LATERAL generate_series(1, customer.id)";
1428+
let res = parse_sql_statements(sql);
1429+
assert_eq!(
1430+
ParserError::ParserError(
1431+
"Expected subquery after LATERAL, found: generate_series".to_string()
1432+
),
1433+
res.unwrap_err()
1434+
);
1435+
}
1436+
13931437
#[test]
13941438
#[should_panic(
13951439
expected = "Parse results with GenericSqlDialect are different from PostgreSqlDialect"

0 commit comments

Comments
 (0)