From cb582c1623397a918adca7125b2cb1753eb63f9f Mon Sep 17 00:00:00 2001 From: Andrea Donetti Date: Wed, 25 Feb 2026 22:27:36 -0600 Subject: [PATCH] fix(sqlite): PRIVATE functions used inside triggers require SQLITE_INNOCUOUS ... otherwise the cloudsync_init function returns this error: table_add_stmts error: 1 unsafe use of cloudsync_is_sync() Runtime error: An error occurred while adding test_sync table information to global context (unsafe use of cloudsync_is_sync()) (21) --- src/cloudsync.h | 2 +- src/sqlite/cloudsync_sqlite.c | 28 ++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/cloudsync.h b/src/cloudsync.h index 8985432..84dfe4a 100644 --- a/src/cloudsync.h +++ b/src/cloudsync.h @@ -17,7 +17,7 @@ extern "C" { #endif -#define CLOUDSYNC_VERSION "0.9.111" +#define CLOUDSYNC_VERSION "0.9.112" #define CLOUDSYNC_MAX_TABLENAME_LEN 512 #define CLOUDSYNC_VALUE_NOTSET -1 diff --git a/src/sqlite/cloudsync_sqlite.c b/src/sqlite/cloudsync_sqlite.c index 8157fd6..08268b3 100644 --- a/src/sqlite/cloudsync_sqlite.c +++ b/src/sqlite/cloudsync_sqlite.c @@ -938,11 +938,23 @@ int dbsync_register_pure_function (sqlite3 *db, const char *name, void (*xfunc)( return dbsync_register_with_flags(db, name, xfunc, NULL, NULL, nargs, FLAGS_PURE, pzErrMsg, ctx, ctx_free); } +int dbsync_register_trigger_function (sqlite3 *db, const char *name, void (*xfunc)(sqlite3_context*,int,sqlite3_value**), int nargs, char **pzErrMsg, void *ctx, void (*ctx_free)(void *)) { + const int FLAGS_TRIGGER = SQLITE_UTF8 | SQLITE_INNOCUOUS; + DEBUG_DBFUNCTION("dbsync_register_trigger_function %s", name); + return dbsync_register_with_flags(db, name, xfunc, NULL, NULL, nargs, FLAGS_TRIGGER, pzErrMsg, ctx, ctx_free); +} + int dbsync_register_aggregate (sqlite3 *db, const char *name, void (*xstep)(sqlite3_context*,int,sqlite3_value**), void (*xfinal)(sqlite3_context*), int nargs, char **pzErrMsg, void *ctx, void (*ctx_free)(void *)) { DEBUG_DBFUNCTION("dbsync_register_aggregate %s", name); return dbsync_register(db, name, NULL, xstep, xfinal, nargs, pzErrMsg, ctx, ctx_free); } +int dbsync_register_trigger_aggregate (sqlite3 *db, const char *name, void (*xstep)(sqlite3_context*,int,sqlite3_value**), void (*xfinal)(sqlite3_context*), int nargs, char **pzErrMsg, void *ctx, void (*ctx_free)(void *)) { + const int FLAGS_TRIGGER = SQLITE_UTF8 | SQLITE_INNOCUOUS; + DEBUG_DBFUNCTION("dbsync_register_trigger_aggregate %s", name); + return dbsync_register_with_flags(db, name, NULL, xstep, xfinal, nargs, FLAGS_TRIGGER, pzErrMsg, ctx, ctx_free); +} + // MARK: - Row Filter - void dbsync_set_filter (sqlite3_context *context, int argc, sqlite3_value **argv) { @@ -1117,17 +1129,17 @@ int dbsync_register_functions (sqlite3 *db, char **pzErrMsg) { if (rc != SQLITE_OK) return rc; #endif - // PRIVATE functions - rc = dbsync_register_function(db, "cloudsync_is_sync", dbsync_is_sync, 1, pzErrMsg, ctx, NULL); + // PRIVATE functions (used inside triggers — require SQLITE_INNOCUOUS) + rc = dbsync_register_trigger_function(db, "cloudsync_is_sync", dbsync_is_sync, 1, pzErrMsg, ctx, NULL); if (rc != SQLITE_OK) return rc; - - rc = dbsync_register_function(db, "cloudsync_insert", dbsync_insert, -1, pzErrMsg, ctx, NULL); + + rc = dbsync_register_trigger_function(db, "cloudsync_insert", dbsync_insert, -1, pzErrMsg, ctx, NULL); if (rc != SQLITE_OK) return rc; - - rc = dbsync_register_aggregate(db, "cloudsync_update", dbsync_update_step, dbsync_update_final, 3, pzErrMsg, ctx, NULL); + + rc = dbsync_register_trigger_aggregate(db, "cloudsync_update", dbsync_update_step, dbsync_update_final, 3, pzErrMsg, ctx, NULL); if (rc != SQLITE_OK) return rc; - - rc = dbsync_register_function(db, "cloudsync_delete", dbsync_delete, -1, pzErrMsg, ctx, NULL); + + rc = dbsync_register_trigger_function(db, "cloudsync_delete", dbsync_delete, -1, pzErrMsg, ctx, NULL); if (rc != SQLITE_OK) return rc; rc = dbsync_register_function(db, "cloudsync_col_value", dbsync_col_value, 3, pzErrMsg, ctx, NULL);