support NATURAL JOIN

This commit is contained in:
jussisaurio
2024-11-30 10:34:11 +02:00
parent bed932c186
commit 81b6605453
3 changed files with 50 additions and 7 deletions

View File

@@ -62,6 +62,7 @@ This document describes the SQLite compatibility status of Limbo:
| SELECT ... INNER JOIN | Partial | |
| SELECT ... OUTER JOIN | Partial | |
| SELECT ... JOIN USING | Yes | |
| SELECT ... NATURAL JOIN | Yes | |
| UPDATE | No | |
| UPSERT | No | |
| VACUUM | No | |

View File

@@ -582,19 +582,54 @@ fn parse_join(
tables.push(table.clone());
let outer = match operator {
let (outer, natural) = match operator {
ast::JoinOperator::TypedJoin(Some(join_type)) => {
if join_type == JoinType::LEFT | JoinType::OUTER {
true
} else {
join_type == JoinType::RIGHT | JoinType::OUTER
}
let is_outer = join_type.contains(JoinType::OUTER);
let is_natural = join_type.contains(JoinType::NATURAL);
(is_outer, is_natural)
}
_ => false,
_ => (false, false),
};
let mut using = None;
let mut predicates = None;
if natural && constraint.is_some() {
crate::bail_parse_error!("NATURAL JOIN cannot be combined with ON or USING clause");
}
let constraint = if natural {
// NATURAL JOIN is first transformed into a USING join with the common columns
let left_table = &tables[table_index - 1];
let right_table = &tables[table_index];
let left_cols = &left_table.table.columns;
let right_cols = &right_table.table.columns;
let mut distinct_names = None;
// TODO: O(n^2) maybe not great for large tables
for left_col in left_cols.iter() {
for right_col in right_cols.iter() {
if left_col.name == right_col.name {
if distinct_names.is_none() {
distinct_names =
Some(ast::DistinctNames::new(ast::Name(left_col.name.clone())));
} else {
distinct_names
.as_mut()
.unwrap()
.insert(ast::Name(left_col.name.clone()))
.unwrap();
}
}
}
}
if distinct_names.is_none() {
crate::bail_parse_error!("No columns found to NATURAL join on");
}
Some(ast::JoinConstraint::Using(distinct_names.unwrap()))
} else {
constraint
};
if let Some(constraint) = constraint {
match constraint {
ast::JoinConstraint::On(expr) => {

View File

@@ -220,4 +220,11 @@ do_execsql_test join-using {
select * from users join products using (id) limit 3;
} {"1|Jamie|Foster|dylan00@example.com|496-522-9493|62375 Johnson Rest Suite 322|West Lauriestad|IL|35865|94|hat|79.0
2|Cindy|Salazar|williamsrebecca@example.com|287-934-1135|75615 Stacey Shore|South Stephanie|NC|85181|37|cap|82.0
3|Tommy|Perry|warechristopher@example.org|001-288-554-8139x0276|2896 Paul Fall Apt. 972|Michaelborough|VA|15691|18|shirt|18.0"}
# NATURAL JOIN desugars to JOIN USING (common_column1, common_column2...)
do_execsql_test join-using {
select * from users natural join products limit 3;
} {"1|Jamie|Foster|dylan00@example.com|496-522-9493|62375 Johnson Rest Suite 322|West Lauriestad|IL|35865|94|hat|79.0
2|Cindy|Salazar|williamsrebecca@example.com|287-934-1135|75615 Stacey Shore|South Stephanie|NC|85181|37|cap|82.0
3|Tommy|Perry|warechristopher@example.org|001-288-554-8139x0276|2896 Paul Fall Apt. 972|Michaelborough|VA|15691|18|shirt|18.0"}