From 272dadc4bc39350f02e79152e42fe65c6a084bec Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Thu, 13 Nov 2025 11:15:08 +0200 Subject: [PATCH] Support DELETE ... RETURNING I didn't end up having to use the RowSet instructions for this after all. Maybe there's some edge cases where it's required -- sqlite uses ephemeral tables or rowsets in all RETURNING handling, but I haven't found a need to do that yet. --- core/translate/delete.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/core/translate/delete.rs b/core/translate/delete.rs index c8f161fab..e853f8142 100644 --- a/core/translate/delete.rs +++ b/core/translate/delete.rs @@ -1,5 +1,6 @@ use crate::schema::{Schema, Table}; use crate::translate::emitter::{emit_program, Resolver}; +use crate::translate::expr::process_returning_clause; use crate::translate::optimizer::optimize_plan; use crate::translate::plan::{DeletePlan, Operation, Plan}; use crate::translate::planner::{parse_limit, parse_where}; @@ -36,22 +37,13 @@ pub fn translate_delete( ); } - // FIXME: SQLite's DELETE ... RETURNING reads the table's rowids into a RowSet first, - // and only after that it opens the table for writing and deletes the rows. It uses - // a couple of instructions that we already implement (i.e.: RowSetAdd, RowSetRead, - // RowSetTest), but for now we don't have an implementation of DELETE ... RETURNING. - if !returning.is_empty() { - crate::bail_parse_error!("RETURNING currently not implemented for DELETE statements."); - } - let result_columns = vec![]; - let mut delete_plan = prepare_delete_plan( &mut program, resolver.schema, tbl_name, where_clause, limit, - result_columns, + returning, connection, )?; optimize_plan(&mut program, &mut delete_plan, resolver.schema)?; @@ -74,7 +66,7 @@ pub fn prepare_delete_plan( tbl_name: String, where_clause: Option>, limit: Option, - result_columns: Vec, + mut returning: Vec, connection: &Arc, ) -> Result { let table = match schema.get_table(&tbl_name) { @@ -131,6 +123,9 @@ pub fn prepare_delete_plan( connection, )?; + let result_columns = + process_returning_clause(&mut returning, &mut table_references, connection)?; + // Parse the LIMIT/OFFSET clause let (resolved_limit, resolved_offset) = limit.map_or(Ok((None, None)), |l| parse_limit(l, connection))?;