@@ -3150,6 +3150,90 @@ void cloudsync_commit_alter (sqlite3_context *context, int argc, sqlite3_value *
31503150 }
31513151}
31523152
3153+ /**
3154+ * Cleanup all local data from cloudsync-enabled tables, so the database can be safely reused
3155+ * by another user without exposing any data from the previous session.
3156+ *
3157+ * Warning: this function deletes all data from the tables. Use with caution.
3158+ */
3159+ void cloudsync_logout (sqlite3_context * context , int argc , sqlite3_value * * argv ) {
3160+ bool completed = false;
3161+ char * errmsg = NULL ;
3162+ sqlite3 * db = sqlite3_context_db_handle (context );
3163+
3164+ // if the network layer is enabled, remove the token or apikey
3165+ #ifndef CLOUDSYNC_OMIT_NETWORK
3166+ sqlite3_exec (db , "SELECT cloudsync_network_set_token('');" , NULL , NULL , NULL );
3167+ #endif
3168+
3169+ // get the list of cloudsync-enabled tables
3170+ char * sql = "SELECT tbl_name, key, value FROM cloudsync_table_settings;" ;
3171+ char * * result = NULL ;
3172+ int nrows , ncols ;
3173+ int rc = sqlite3_get_table (db , sql , & result , & nrows , & ncols , NULL );
3174+ if (rc != SQLITE_OK ) {
3175+ errmsg = cloudsync_memory_mprintf ("Unable to get current cloudsync configuration. %s" , sqlite3_errmsg (db ));
3176+ goto finalize ;
3177+ }
3178+
3179+ // run everything in a savepoint
3180+ rc = sqlite3_exec (db , "SAVEPOINT cloudsync_logout_sp;" , NULL , NULL , NULL );
3181+ if (rc != SQLITE_OK ) {
3182+ errmsg = cloudsync_memory_mprintf ("Unable to create cloudsync_logout savepoint. %s" , sqlite3_errmsg (db ));
3183+ return ;
3184+ }
3185+
3186+ // disable cloudsync for all the previously enabled tables: cloudsync_cleanup('*')
3187+ rc = sqlite3_exec (db , "SELECT cloudsync_cleanup('*')" , NULL , NULL , NULL );
3188+ if (rc != SQLITE_OK ) {
3189+ errmsg = cloudsync_memory_mprintf ("Unable to cleanup current cloudsync configuration. %s" , sqlite3_errmsg (db ));
3190+ goto finalize ;
3191+ }
3192+
3193+ // delete all the local data for each previously enabled table
3194+ // re-enable cloudsync on previously enabled tables
3195+ for (int i = 1 ; i <= nrows ; i ++ ) {
3196+ char * tbl_name = result [i * ncols + 0 ];
3197+ char * key = result [i * ncols + 1 ];
3198+ char * value = result [i * ncols + 2 ];
3199+
3200+ if (strcmp (key , "algo" ) != 0 ) continue ;
3201+
3202+ sql = cloudsync_memory_mprintf ("DELETE FROM \"%w\";" , tbl_name );
3203+ rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
3204+ cloudsync_memory_free (sql );
3205+ if (rc != SQLITE_OK ) {
3206+ errmsg = cloudsync_memory_mprintf ("Unable to delete data from table %s. %s" , tbl_name , sqlite3_errmsg (db ));
3207+ goto finalize ;
3208+ }
3209+
3210+ sql = cloudsync_memory_mprintf ("SELECT cloudsync_init(\"%w\", \"%w\", 1);" , tbl_name , value );
3211+ rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
3212+ cloudsync_memory_free (sql );
3213+ if (rc != SQLITE_OK ) {
3214+ errmsg = cloudsync_memory_mprintf ("Unable to enable cloudsync on table %s. %s" , tbl_name , sqlite3_errmsg (db ));
3215+ goto finalize ;
3216+ }
3217+ }
3218+
3219+ completed = true;
3220+
3221+ finalize :
3222+ if (completed ) {
3223+ sqlite3_exec (db , "RELEASE cloudsync_logout_sp;" , NULL , NULL , NULL );
3224+ } else {
3225+ // cleanup:
3226+ // ROLLBACK TO command reverts the state of the database back to what it was just after the corresponding SAVEPOINT
3227+ // then RELEASE to remove the SAVEPOINT from the transaction stack
3228+ sqlite3_exec (db , "ROLLBACK TO cloudsync_logout_sp;" , NULL , NULL , NULL );
3229+ sqlite3_exec (db , "RELEASE cloudsync_logout_sp;" , NULL , NULL , NULL );
3230+ sqlite3_result_error (context , errmsg , -1 );
3231+ sqlite3_result_error_code (context , rc );
3232+ }
3233+ sqlite3_free_table (result );
3234+ cloudsync_memory_free (errmsg );
3235+ }
3236+
31533237// MARK: - Main Entrypoint -
31543238
31553239APIEXPORT int sqlite3_cloudsync_init (sqlite3 * db , char * * pzErrMsg , const sqlite3_api_routines * pApi ) {
@@ -3268,6 +3352,9 @@ APIEXPORT int sqlite3_cloudsync_init (sqlite3 *db, char **pzErrMsg, const sqlite
32683352 rc = dbutils_register_function (db , "cloudsync_seq" , cloudsync_seq , 0 , pzErrMsg , ctx , NULL );
32693353 if (rc != SQLITE_OK ) return rc ;
32703354
3355+ rc = dbutils_register_function (db , "cloudsync_logout" , cloudsync_logout , 0 , pzErrMsg , ctx , NULL );
3356+ if (rc != SQLITE_OK ) return rc ;
3357+
32713358 // NETWORK LAYER
32723359 #ifndef CLOUDSYNC_OMIT_NETWORK
32733360 rc = cloudsync_network_register (db , pzErrMsg , ctx );
0 commit comments