Skip to content

Commit 959d911

Browse files
committed
feat: add the cloudsync_logout function
also add a test for this function
1 parent 3bb413e commit 959d911

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/cloudsync.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

31553239
APIEXPORT 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);

test/unit.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,25 @@ bool do_test_functions (sqlite3 *db, bool print_results) {
994994
if (print_results) printf("New uuid: %s\n", uuid);
995995
cloudsync_memory_free(uuid);
996996

997+
rc = sqlite3_exec(db, "SELECT cloudsync_init('*');", NULL, NULL, NULL);
998+
if (rc != SQLITE_OK) goto abort_test_functions;
999+
rc = sqlite3_exec(db, "INSERT INTO tbl1 (col1, col2) VALUES ('abc123', 'qwe321');", NULL, NULL, NULL);
1000+
sqlite3_int64 nrows1 = dbutils_int_select(db, "SELECT count(*) FROM tbl1;");
1001+
if (nrows1 != 1) goto abort_test_functions;
1002+
char *siteid1 = dbutils_text_select(db, "SELECT hex(cloudsync_siteid());");
1003+
sqlite3_int64 nmaster1 = dbutils_int_select(db, "SELECT count(*) FROM sqlite_master;");
1004+
rc = sqlite3_exec(db, "SELECT cloudsync_logout();", NULL, NULL, NULL);
1005+
char *siteid2 = dbutils_text_select(db, "SELECT hex(cloudsync_siteid());");
1006+
sqlite3_int64 nmaster2 = dbutils_int_select(db, "SELECT count(*) FROM sqlite_master;");
1007+
sqlite3_int64 nrows2 = dbutils_int_select(db, "SELECT count(*) FROM tbl1;");
1008+
int siteidcmp = strcmp(siteid1, siteid2);
1009+
cloudsync_memory_free(siteid1);
1010+
cloudsync_memory_free(siteid2);
1011+
if (rc != SQLITE_OK) goto abort_test_functions;
1012+
if (siteidcmp == 0) goto abort_test_functions;
1013+
if (nmaster1 != nmaster2) goto abort_test_functions;
1014+
if (nrows2 != 0) goto abort_test_functions;
1015+
9971016
return true;
9981017

9991018
abort_test_functions:

0 commit comments

Comments
 (0)