Skip to content

Commit 1f6da84

Browse files
thomas-jeepebenesch
authored andcommitted
Add lateral derived support
1 parent 8168dff commit 1f6da84

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
@@ -1559,6 +1559,50 @@ fn parse_fetch_variations() {
15591559
);
15601560
}
15611561

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

0 commit comments

Comments
 (0)