From e44f931dba25edc377394167d0bdf0742e162c9c Mon Sep 17 00:00:00 2001 From: Matt <1009003+tantaman@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:30:26 -0400 Subject: [PATCH 1/2] after_delete module --- core/rs/core/src/local_writes/after_delete.rs | 45 +++++++++++++++++++ core/rs/core/src/local_writes/mod.rs | 1 + 2 files changed, 46 insertions(+) create mode 100644 core/rs/core/src/local_writes/after_delete.rs diff --git a/core/rs/core/src/local_writes/after_delete.rs b/core/rs/core/src/local_writes/after_delete.rs new file mode 100644 index 000000000..47ab0457f --- /dev/null +++ b/core/rs/core/src/local_writes/after_delete.rs @@ -0,0 +1,45 @@ +use alloc::string::String; +use core::ffi::c_int; +use sqlite::sqlite3; +use sqlite::value; +use sqlite::Context; +use sqlite::ResultCode; +use sqlite_nostd as sqlite; + +use crate::db_version; +use crate::{c::crsql_ExtData, tableinfo::TableInfo}; + +use super::bump_seq; +use super::trigger_fn_preamble; + +/** + * crsql_after_delete("table", old_pk_values...) + */ +#[no_mangle] +pub unsafe extern "C" fn crsql_after_delete( + ctx: *mut sqlite::context, + argc: c_int, + argv: *mut *mut sqlite::value, +) { + let result = trigger_fn_preamble(ctx, argc, argv, |table_info, values, ext_data| { + after_delete(ctx.db_handle(), ext_data, table_info, &values[1..]) + }); + + match result { + Ok(_) => { + ctx.result_int64(0); + } + Err(msg) => { + ctx.result_error(&msg); + } + } +} + +fn after_delete( + db: *mut sqlite3, + ext_data: *mut crsql_ExtData, + tbl_info: &TableInfo, + pks_old: &[*mut value], +) -> Result { + Ok(ResultCode::OK) +} diff --git a/core/rs/core/src/local_writes/mod.rs b/core/rs/core/src/local_writes/mod.rs index 6f8bce517..9fbcc7620 100644 --- a/core/rs/core/src/local_writes/mod.rs +++ b/core/rs/core/src/local_writes/mod.rs @@ -16,6 +16,7 @@ use sqlite_nostd::ResultCode; use crate::tableinfo::{crsql_ensure_table_infos_are_up_to_date, ColumnInfo, TableInfo}; +mod after_delete; mod after_insert; mod after_update; From 939c0bb819c7d9faddde9db9eca0723c52bb208f Mon Sep 17 00:00:00 2001 From: Matt <1009003+tantaman@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:00:35 -0400 Subject: [PATCH 2/2] after_delete trigger fn wired and completed --- core/rs/core/src/local_writes/after_delete.rs | 37 ++++++++++++++++++- core/rs/core/src/triggers.rs | 26 +------------ core/src/crsqlite.c | 5 +++ core/src/rust.h | 2 + 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/core/rs/core/src/local_writes/after_delete.rs b/core/rs/core/src/local_writes/after_delete.rs index 47ab0457f..9cf7b7a9e 100644 --- a/core/rs/core/src/local_writes/after_delete.rs +++ b/core/rs/core/src/local_writes/after_delete.rs @@ -41,5 +41,40 @@ fn after_delete( tbl_info: &TableInfo, pks_old: &[*mut value], ) -> Result { - Ok(ResultCode::OK) + let db_version = crate::db_version::next_db_version(db, ext_data, None)?; + let seq = bump_seq(ext_data); + + let mark_locally_deleted_stmt_ref = tbl_info + .get_mark_locally_deleted_stmt(db) + .or_else(|_e| Err("failed to get mark_locally_deleted_stmt"))?; + let mark_locally_deleted_stmt = mark_locally_deleted_stmt_ref + .as_ref() + .ok_or("Failed to deref sentinel stmt")?; + for (i, pk) in pks_old.iter().enumerate() { + mark_locally_deleted_stmt + .bind_value(i as i32 + 1, *pk) + .or_else(|_e| Err("failed to bind pks to mark_locally_deleted_stmt"))?; + } + mark_locally_deleted_stmt + .bind_int64(pks_old.len() as i32 + 1, db_version) + .and_then(|_| mark_locally_deleted_stmt.bind_int(pks_old.len() as i32 + 2, seq)) + .and_then(|_| mark_locally_deleted_stmt.bind_int64(pks_old.len() as i32 + 3, db_version)) + .and_then(|_| mark_locally_deleted_stmt.bind_int(pks_old.len() as i32 + 4, seq)) + .or_else(|_| Err("failed binding to mark locally deleted stmt"))?; + super::step_trigger_stmt(mark_locally_deleted_stmt)?; + + // now actually delete the row metadata + let drop_clocks_stmt_ref = tbl_info + .get_merge_delete_drop_clocks_stmt(db) + .or_else(|_e| Err("failed to get mark_locally_deleted_stmt"))?; + let drop_clocks_stmt = drop_clocks_stmt_ref + .as_ref() + .ok_or("Failed to deref sentinel stmt")?; + + for (i, pk) in pks_old.iter().enumerate() { + drop_clocks_stmt + .bind_value(i as i32 + 1, *pk) + .or_else(|_e| Err("failed to bind pks to mark_locally_deleted_stmt"))?; + } + super::step_trigger_stmt(drop_clocks_stmt) } diff --git a/core/rs/core/src/triggers.rs b/core/rs/core/src/triggers.rs index d8f477990..130077bbe 100644 --- a/core/rs/core/src/triggers.rs +++ b/core/rs/core/src/triggers.rs @@ -84,39 +84,15 @@ fn create_delete_trigger( ) -> Result { let table_name = &table_info.tbl_name; let pk_columns = &table_info.pks; - let pk_list = crate::util::as_identifier_list(pk_columns, None)?; let pk_old_list = crate::util::as_identifier_list(pk_columns, Some("OLD."))?; - let pk_where_list = crate::util::pk_where_list(pk_columns, Some("OLD."))?; let create_trigger_sql = format!( "CREATE TRIGGER IF NOT EXISTS \"{table_name}__crsql_dtrig\" AFTER DELETE ON \"{table_name}\" WHEN crsql_internal_sync_bit() = 0 BEGIN - INSERT INTO \"{table_name}__crsql_clock\" ( - {pk_list}, - __crsql_col_name, - __crsql_col_version, - __crsql_db_version, - __crsql_seq, - __crsql_site_id - ) SELECT - {pk_old_list}, - '{sentinel}', - 2, - crsql_next_db_version(), - crsql_increment_and_get_seq(), - NULL WHERE true - ON CONFLICT DO UPDATE SET - __crsql_col_version = 1 + __crsql_col_version, - __crsql_db_version = crsql_next_db_version(), - __crsql_seq = crsql_get_seq() - 1, - __crsql_site_id = NULL; - DELETE FROM \"{table_name}__crsql_clock\" - WHERE {pk_where_list} AND __crsql_col_name != '{sentinel}'; + VALUES (crsql_after_delete('{}', {pk_old_list})); END;", table_name = crate::util::escape_ident(table_name), - sentinel = crate::c::DELETE_SENTINEL, - pk_where_list = pk_where_list, pk_old_list = pk_old_list ); diff --git a/core/src/crsqlite.c b/core/src/crsqlite.c index eacbd3216..58fff133d 100644 --- a/core/src/crsqlite.c +++ b/core/src/crsqlite.c @@ -412,6 +412,11 @@ __declspec(dllexport) SQLITE_UTF8 | SQLITE_INNOCUOUS, pExtData, crsql_after_insert, 0, 0); } + if (rc == SQLITE_OK) { + rc = sqlite3_create_function(db, "crsql_after_delete", -1, + SQLITE_UTF8 | SQLITE_INNOCUOUS, pExtData, + crsql_after_delete, 0, 0); + } if (rc == SQLITE_OK) { rc = sqlite3_create_function(db, "crsql_rows_impacted", 0, diff --git a/core/src/rust.h b/core/src/rust.h index 706b2c269..2431bafdc 100644 --- a/core/src/rust.h +++ b/core/src/rust.h @@ -31,4 +31,6 @@ void crsql_after_update(sqlite3_context *context, int argc, sqlite3_value **argv); void crsql_after_insert(sqlite3_context *context, int argc, sqlite3_value **argv); +void crsql_after_delete(sqlite3_context *context, int argc, + sqlite3_value **argv); #endif