Merge 'Throw an error in case duplicate CTE names are found' from Rohith Suresh

* Fixes bug #3674
* With this fix:
```
turso>  WITH t AS (SELECT 1), t AS (SELECT 2) SELECT * FROM x;
  × Parse error: duplicate WITH table name: t
```

Reviewed-by: Preston Thorpe <preston@turso.tech>
Reviewed-by: Mikaël Francoeur (@LeMikaelF)

Closes #3719
This commit is contained in:
Pekka Enberg
2025-11-01 11:12:10 +02:00
committed by GitHub
2 changed files with 16 additions and 2 deletions

View File

@@ -644,12 +644,13 @@ pub fn parse_from(
return Ok(());
}
let mut ctes_as_subqueries = vec![];
let mut ctes_as_subqueries: Vec<JoinedTable> = vec![];
if let Some(with) = with {
if with.recursive {
crate::bail_parse_error!("Recursive CTEs are not yet supported");
}
for cte in with.ctes {
if cte.materialized == Materialized::Yes {
crate::bail_parse_error!("Materialized CTEs are not yet supported");
@@ -662,6 +663,13 @@ pub fn parse_from(
// TODO: sqlite actually allows overriding a catalog table with a CTE.
// We should carry over the 'Scope' struct to all of our identifier resolution.
let cte_name_normalized = normalize_ident(cte.tbl_name.as_str());
if ctes_as_subqueries
.iter()
.any(|t| t.table.get_name() == cte_name_normalized)
{
crate::bail_parse_error!("duplicate WITH table name: {}", cte.tbl_name.as_str());
}
if resolver.schema.get_table(&cte_name_normalized).is_some() {
crate::bail_parse_error!(
"CTE name {} conflicts with catalog table name",
@@ -702,6 +710,7 @@ pub fn parse_from(
let Plan::Select(cte_plan) = cte_plan else {
crate::bail_parse_error!("Only SELECT queries are currently supported in CTEs");
};
ctes_as_subqueries.push(JoinedTable::new_subquery(
cte_name_normalized,
cte_plan,

View File

@@ -1112,4 +1112,9 @@ do_execsql_test_on_specific_db {:memory:} group-by-limit-0 {
CREATE TABLE t(a);
INSERT INTO t VALUES (1), (2), (3);
SELECT a, COUNT(*) FROM t GROUP BY a LIMIT 0;
} {}
} {}
do_execsql_test_in_memory_any_error duplicate-with-cte-name {
CREATE TABLE t2(x INTEGER);
WITH t as (SELECT 1), t as (SELECT 2) SELECT * FROM t2;
}