Add lateral derived support

This commit is contained in:
Justin Haug 2019-05-23 17:18:15 -04:00 committed by Nikhil Benesch
parent fe10fac0ad
commit 2d00ea7187
No known key found for this signature in database
GPG key ID: F7386C5DEADABA7F
3 changed files with 63 additions and 3 deletions

View file

@ -209,6 +209,7 @@ pub enum TableFactor {
with_hints: Vec<ASTNode>,
},
Derived {
lateral: bool,
subquery: Box<SQLQuery>,
alias: Option<SQLIdent>,
},
@ -235,8 +236,16 @@ impl ToString for TableFactor {
}
s
}
TableFactor::Derived { subquery, alias } => {
let mut s = format!("({})", subquery.to_string());
TableFactor::Derived {
lateral,
subquery,
alias,
} => {
let mut s = String::new();
if *lateral {
s += "LATERAL ";
}
s += &format!("({})", subquery.to_string());
if let Some(alias) = alias {
s += &format!(" AS {}", alias);
}

View file

@ -1464,11 +1464,18 @@ impl Parser {
/// A table name or a parenthesized subquery, followed by optional `[AS] alias`
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
let lateral = self.parse_keyword("LATERAL");
if self.consume_token(&Token::LParen) {
let subquery = Box::new(self.parse_query()?);
self.expect_token(&Token::RParen)?;
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
Ok(TableFactor::Derived { subquery, alias })
Ok(TableFactor::Derived {
lateral,
subquery,
alias,
})
} else if lateral {
self.expected("subquery after LATERAL", self.peek_token())
} else {
let name = self.parse_object_name()?;
// Postgres, MSSQL: table-valued functions:

View file

@ -1569,6 +1569,50 @@ fn parse_fetch_variations() {
);
}
#[test]
fn lateral_derived() {
fn chk(lateral_in: bool) {
let lateral_str = if lateral_in { "LATERAL " } else { "" };
let sql = format!(
"SELECT * FROM customer LEFT JOIN {}\
(SELECT * FROM order WHERE order.customer = customer.id LIMIT 3) AS order ON true",
lateral_str
);
let select = verified_only_select(&sql);
assert_eq!(select.joins.len(), 1);
assert_eq!(
select.joins[0].join_operator,
JoinOperator::LeftOuter(JoinConstraint::On(ASTNode::SQLValue(Value::Boolean(true))))
);
if let TableFactor::Derived {
lateral,
ref subquery,
ref alias,
} = select.joins[0].relation
{
assert_eq!(lateral_in, lateral);
assert_eq!(Some("order".to_string()), *alias);
assert_eq!(
subquery.to_string(),
"SELECT * FROM order WHERE order.customer = customer.id LIMIT 3"
);
} else {
unreachable!()
}
}
chk(false);
chk(true);
let sql = "SELECT * FROM customer LEFT JOIN LATERAL generate_series(1, customer.id)";
let res = parse_sql_statements(sql);
assert_eq!(
ParserError::ParserError(
"Expected subquery after LATERAL, found: generate_series".to_string()
),
res.unwrap_err()
);
}
#[test]
#[should_panic(
expected = "Parse results with GenericSqlDialect are different from PostgreSqlDialect"