Skip to content

Commit 40f017c

Browse files
committed
Improved error handling
1 parent bce62b6 commit 40f017c

File tree

3 files changed

+46
-17
lines changed

3 files changed

+46
-17
lines changed

src/cloudsync.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ struct cloudsync_pk_decode_bind_context {
163163
};
164164

165165
struct cloudsync_context {
166+
sqlite3_context *sqlite_ctx;
167+
166168
char *libversion;
167169
uint8_t site_id[UUID_LEN];
168170
int insync;
@@ -379,7 +381,12 @@ int db_version_rebuild_stmt (sqlite3 *db, cloudsync_context *data) {
379381
data->db_version_stmt = NULL;
380382
}
381383

382-
if (dbutils_table_settings_count_tables(db) == 0) return SQLITE_OK;
384+
sqlite3_int64 count = dbutils_table_settings_count_tables(db);
385+
if (count == 0) return SQLITE_OK;
386+
else if (count == -1) {
387+
dbutils_context_result_error(data->sqlite_ctx, "%s", sqlite3_errmsg(db));
388+
return SQLITE_ERROR;
389+
}
383390

384391
char *sql = db_version_build_query(db);
385392
if (!sql) return SQLITE_NOMEM;
@@ -912,6 +919,11 @@ bool table_add_to_context (sqlite3 *db, cloudsync_context *data, table_algo algo
912919
if (!sql) goto abort_add_table;
913920
table->npks = (int)dbutils_int_select(db, sql);
914921
cloudsync_memory_free(sql);
922+
if (table->npks == -1) {
923+
dbutils_context_result_error(data->sqlite_ctx, "%s", sqlite3_errmsg(db));
924+
goto abort_add_table;
925+
}
926+
915927
if (table->npks == 0) {
916928
#if CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
917929
return false;
@@ -925,6 +937,10 @@ bool table_add_to_context (sqlite3 *db, cloudsync_context *data, table_algo algo
925937
if (!sql) goto abort_add_table;
926938
int64_t ncols = (int64_t)dbutils_int_select(db, sql);
927939
cloudsync_memory_free(sql);
940+
if (ncols == -1) {
941+
dbutils_context_result_error(data->sqlite_ctx, "%s", sqlite3_errmsg(db));
942+
goto abort_add_table;
943+
}
928944

929945
int rc = table_add_stmts(db, table, (int)ncols);
930946
if (rc != SQLITE_OK) goto abort_add_table;
@@ -1511,6 +1527,7 @@ const char *cloudsync_context_init (sqlite3 *db, cloudsync_context *data, sqlite
15111527
if (stmts_add_tocontext(db, data) != SQLITE_OK) return NULL;
15121528
if (cloudsync_load_siteid(db, data) != SQLITE_OK) return NULL;
15131529

1530+
data->sqlite_ctx = context;
15141531
data->schema_hash = dbutils_schema_hash(db);
15151532
}
15161533

@@ -2828,9 +2845,9 @@ int cloudsync_load_siteid (sqlite3 *db, cloudsync_context *data) {
28282845
if (data->site_id[0] != 0) return SQLITE_OK;
28292846

28302847
// load site_id
2831-
int size;
2832-
char *buffer = dbutils_blob_select(db, "SELECT site_id FROM cloudsync_site_id WHERE rowid=0;", &size);
2833-
if (!buffer) return SQLITE_NOMEM;
2848+
int size, rc;
2849+
char *buffer = dbutils_blob_select(db, "SELECT site_id FROM cloudsync_site_id WHERE rowid=0;", &size, data->sqlite_ctx, &rc);
2850+
if (!buffer) return rc;
28342851
if (size != UUID_LEN) return SQLITE_MISUSE;
28352852

28362853
memcpy(data->site_id, buffer, UUID_LEN);
@@ -2950,6 +2967,8 @@ int cloudsync_init_all (sqlite3_context *context, const char *algo_name, bool sk
29502967

29512968
void cloudsync_init (sqlite3_context *context, const char *table, const char *algo, bool skip_int_pk_check) {
29522969
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
2970+
data->sqlite_ctx = context;
2971+
29532972
sqlite3 *db = sqlite3_context_db_handle(context);
29542973
int rc = sqlite3_exec(db, "SAVEPOINT cloudsync_init;", NULL, NULL, NULL);
29552974
if (rc != SQLITE_OK) {

src/dbutils.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,11 @@ int dbutils_write_simple (sqlite3 *db, const char *sql) {
164164
}
165165

166166
sqlite3_int64 dbutils_int_select (sqlite3 *db, const char *sql) {
167+
// used only for cound(*), hash, or 1, so return -1 to signal an error
167168
DATABASE_RESULT results[1] = {0};
168169
int expected_types[1] = {SQLITE_INTEGER};
169170
dbutils_exec(NULL, db, sql, NULL, NULL, NULL, 0, results, expected_types, 1);
170-
return results[0].value.intValue;
171+
return (results[0].rc == SQLITE_OK) ? results[0].value.intValue : -1;
171172
}
172173

173174
char *dbutils_text_select (sqlite3 *db, const char *sql) {
@@ -177,11 +178,12 @@ char *dbutils_text_select (sqlite3 *db, const char *sql) {
177178
return results[0].value.stringValue;
178179
}
179180

180-
char *dbutils_blob_select (sqlite3 *db, const char *sql, int *size) {
181+
char *dbutils_blob_select (sqlite3 *db, const char *sql, int *size, sqlite3_context *context, int *rc) {
181182
DATABASE_RESULT results[1] = {0};
182183
int expected_types[1] = {SQLITE_BLOB};
183-
dbutils_exec(NULL, db, sql, NULL, NULL, NULL, 0, results, expected_types, 1);
184+
dbutils_exec(context, db, sql, NULL, NULL, NULL, 0, results, expected_types, 1);
184185
*size = results[0].len;
186+
*rc = results[0].rc;
185187
return results[0].value.stringValue;
186188
}
187189

@@ -196,13 +198,6 @@ int dbutils_blob_int_int_select (sqlite3 *db, const char *sql, char **blob, int
196198
return results[0].rc;
197199
}
198200

199-
sqlite3_int64 dbutils_select (sqlite3 *db, const char *sql, const char **values, int types[], int lens[], int count, int expected_type) {
200-
DATABASE_RESULT results[1] = {0};
201-
int expected_types[1] = {expected_type};
202-
dbutils_exec(NULL, db, sql, values, types, lens, count, results, expected_types, 1);
203-
return results[0].value.intValue;
204-
}
205-
206201
// MARK: -
207202

208203
// compares two SQLite values and returns an integer indicating the comparison result
@@ -396,6 +391,9 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
396391
if (count > 128) {
397392
dbutils_context_result_error(context, "No more than 128 columns can be used to form a composite primary key");
398393
return false;
394+
} else if (count == -1) {
395+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
396+
return false;
399397
}
400398

401399
#if CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
@@ -417,13 +415,21 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
417415
dbutils_context_result_error(context, "Table %s uses an single-column INTEGER primary key. For CRDT replication, primary keys must be globally unique. Consider using a TEXT primary key with UUIDs or ULID to avoid conflicts across nodes. If you understand the risk and still want to use this INTEGER primary key, set the third argument of the cloudsync_init function to 1 to skip this check.", name);
418416
return false;
419417
}
418+
if (count2 == -1) {
419+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
420+
return false;
421+
}
420422
}
421423
}
422424

423425
// if user declared explicit primary key(s) then make sure they are all declared as NOT NULL
424426
if (count > 0) {
425427
sql = sqlite3_snprintf((int)blen, buffer, "SELECT count(*) FROM pragma_table_info('%w') WHERE pk>0 AND \"notnull\"=1;", name);
426428
sqlite3_int64 count2 = dbutils_int_select(db, sql);
429+
if (count2 == -1) {
430+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
431+
return false;
432+
}
427433
if (count != count2) {
428434
dbutils_context_result_error(context, "All primary keys must be explicitly declared as NOT NULL (table %s)", name);
429435
return false;
@@ -434,6 +440,10 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
434440
// Otherwise, col_merge_stmt would fail if changes to other columns are inserted first.
435441
sql = sqlite3_snprintf((int)blen, buffer, "SELECT count(*) FROM pragma_table_info('%w') WHERE pk=0 AND \"notnull\"=1 AND \"dflt_value\" IS NULL;", name);
436442
sqlite3_int64 count3 = dbutils_int_select(db, sql);
443+
if (count3 == -1) {
444+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
445+
return false;
446+
}
437447
if (count3 > 0) {
438448
dbutils_context_result_error(context, "All non-primary key columns declared as NOT NULL must have a DEFAULT value. (table %s)", name);
439449
return false;
@@ -1026,7 +1036,7 @@ int dbutils_settings_init (sqlite3 *db, void *cloudsync_data, sqlite3_context *c
10261036
// check if some process changed schema outside of the lib
10271037
/*
10281038
if ((settings_exists == true) && (data->schema_version != dbutils_schema_version(db))) {
1029-
// TODO: SOMEONE CHANGED SCHEMAs SO WE NEED TO RECHECK AUGMENTED TABLES and RELATED TRIGGERS
1039+
// SOMEONE CHANGED SCHEMAs SO WE NEED TO RECHECK AUGMENTED TABLES and RELATED TRIGGERS
10301040
assert(0);
10311041
}
10321042
*/
@@ -1072,7 +1082,7 @@ bool dbutils_check_schema_hash (sqlite3 *db, sqlite3_uint64 hash) {
10721082
char sql[1024];
10731083
snprintf(sql, sizeof(sql), "SELECT 1 FROM cloudsync_schema_versions WHERE hash = (%lld)", hash);
10741084

1075-
return dbutils_int_select(db, sql) == 1;
1085+
return (dbutils_int_select(db, sql) == 1);
10761086
}
10771087

10781088

src/dbutils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ int dbutils_write_simple (sqlite3 *db, const char *sql);
3131
int dbutils_write (sqlite3 *db, sqlite3_context *context, const char *sql, const char **values, int types[], int len[], int count);
3232
sqlite3_int64 dbutils_int_select (sqlite3 *db, const char *sql);
3333
char *dbutils_text_select (sqlite3 *db, const char *sql);
34-
char *dbutils_blob_select (sqlite3 *db, const char *sql, int *size);
34+
char *dbutils_blob_select (sqlite3 *db, const char *sql, int *size, sqlite3_context *context, int *rc);
3535
int dbutils_blob_int_int_select (sqlite3 *db, const char *sql, char **blob, int *size, sqlite3_int64 *int1, sqlite3_int64 *int2);
3636

3737
int dbutils_register_function (sqlite3 *db, const char *name, void (*ptr)(sqlite3_context*,int,sqlite3_value**), int nargs, char **pzErrMsg, void *ctx, void (*ctx_free)(void *));

0 commit comments

Comments
 (0)