Skip to content

Commit e6a8c0a

Browse files
committed
Merge branch 'main' into new-integration-test
2 parents 180285d + 7c2403e commit e6a8c0a

File tree

7 files changed

+96
-30
lines changed

7 files changed

+96
-30
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<<<<<<< HEAD:src/android_cert.h
12
/*
23
##
34
## Bundle of CA Root Certificates
@@ -22,6 +23,29 @@
2223
*/
2324

2425
static const char cacert_pem[] = "\n"
26+
=======
27+
static const char cacert_pem[] = "##\n"
28+
"## Bundle of CA Root Certificates\n"
29+
"##\n"
30+
"## Certificate data from Mozilla as of: Tue May 20 03:12:02 2025 GMT\n"
31+
"##\n"
32+
"## Find updated versions here: https://curl.se/docs/caextract.html\n"
33+
"##\n"
34+
"## This is a bundle of X.509 certificates of public Certificate Authorities\n"
35+
"## (CA). These were automatically extracted from Mozilla's root certificates\n"
36+
"## file (certdata.txt). This file can be found in the mozilla source tree:\n"
37+
"## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt\n"
38+
"##\n"
39+
"## It contains the certificates in PEM format and therefore\n"
40+
"## can be directly used with curl / libcurl / php_curl, or with\n"
41+
"## an Apache+mod_ssl webserver for SSL client authentication.\n"
42+
"## Just configure this file as the SSLCACertificateFile.\n"
43+
"##\n"
44+
"## Conversion done with mk-ca-bundle.pl version 1.29.\n"
45+
"## SHA256: 8944ec6b572b577daee4fc681a425881f841ec2660e4cb5f0eee727f84620697\n"
46+
"##\n"
47+
"\n"
48+
>>>>>>> main:src/cacert.h
2549
"\n"
2650
"Entrust Root Certification Authority\n"
2751
"====================================\n"
@@ -3480,5 +3504,9 @@ static const char cacert_pem[] = "\n"
34803504
"S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/\n"
34813505
"HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L\n"
34823506
"+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==\n"
3507+
<<<<<<< HEAD:src/android_cert.h
34833508
"-----END CERTIFICATE-----\n"
34843509
"";
3510+
=======
3511+
"-----END CERTIFICATE-----\n";
3512+
>>>>>>> main:src/cacert.h

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/cloudsync.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "sqlite3.h"
1717
#endif
1818

19-
#define CLOUDSYNC_VERSION "0.8.0"
19+
#define CLOUDSYNC_VERSION "0.8.2"
2020

2121
int sqlite3_cloudsync_init (sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
2222

src/dbutils.c

Lines changed: 23 additions & 5 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

@@ -197,6 +199,7 @@ int dbutils_blob_int_int_select (sqlite3 *db, const char *sql, char **blob, int
197199
}
198200

199201
sqlite3_int64 dbutils_select (sqlite3 *db, const char *sql, const char **values, int types[], int lens[], int count, int expected_type) {
202+
// used only in unit-test
200203
DATABASE_RESULT results[1] = {0};
201204
int expected_types[1] = {expected_type};
202205
dbutils_exec(NULL, db, sql, values, types, lens, count, results, expected_types, 1);
@@ -396,6 +399,9 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
396399
if (count > 128) {
397400
dbutils_context_result_error(context, "No more than 128 columns can be used to form a composite primary key");
398401
return false;
402+
} else if (count == -1) {
403+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
404+
return false;
399405
}
400406

401407
#if CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
@@ -417,13 +423,21 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
417423
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);
418424
return false;
419425
}
426+
if (count2 == -1) {
427+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
428+
return false;
429+
}
420430
}
421431
}
422432

423433
// if user declared explicit primary key(s) then make sure they are all declared as NOT NULL
424434
if (count > 0) {
425435
sql = sqlite3_snprintf((int)blen, buffer, "SELECT count(*) FROM pragma_table_info('%w') WHERE pk>0 AND \"notnull\"=1;", name);
426436
sqlite3_int64 count2 = dbutils_int_select(db, sql);
437+
if (count2 == -1) {
438+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
439+
return false;
440+
}
427441
if (count != count2) {
428442
dbutils_context_result_error(context, "All primary keys must be explicitly declared as NOT NULL (table %s)", name);
429443
return false;
@@ -434,6 +448,10 @@ bool dbutils_table_sanity_check (sqlite3 *db, sqlite3_context *context, const ch
434448
// Otherwise, col_merge_stmt would fail if changes to other columns are inserted first.
435449
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);
436450
sqlite3_int64 count3 = dbutils_int_select(db, sql);
451+
if (count3 == -1) {
452+
dbutils_context_result_error(context, "%s", sqlite3_errmsg(db));
453+
return false;
454+
}
437455
if (count3 > 0) {
438456
dbutils_context_result_error(context, "All non-primary key columns declared as NOT NULL must have a DEFAULT value. (table %s)", name);
439457
return false;
@@ -1026,7 +1044,7 @@ int dbutils_settings_init (sqlite3 *db, void *cloudsync_data, sqlite3_context *c
10261044
// check if some process changed schema outside of the lib
10271045
/*
10281046
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
1047+
// SOMEONE CHANGED SCHEMAs SO WE NEED TO RECHECK AUGMENTED TABLES and RELATED TRIGGERS
10301048
assert(0);
10311049
}
10321050
*/
@@ -1072,7 +1090,7 @@ bool dbutils_check_schema_hash (sqlite3 *db, sqlite3_uint64 hash) {
10721090
char sql[1024];
10731091
snprintf(sql, sizeof(sql), "SELECT 1 FROM cloudsync_schema_versions WHERE hash = (%lld)", hash);
10741092

1075-
return dbutils_int_select(db, sql) == 1;
1093+
return (dbutils_int_select(db, sql) == 1);
10761094
}
10771095

10781096

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 *));

src/network.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
#include "cloudsync_private.h"
1616

1717
#ifdef __ANDROID__
18-
#include "android_cert.h"
19-
static size_t cacert_len = 0;
18+
#include "cacert.h"
19+
static size_t cacert_len = sizeof(cacert_pem) - 1;
2020
#endif
2121

2222
#define CLOUDSYNC_ENDPOINT_PREFIX "v1/cloudsync"
@@ -119,10 +119,11 @@ static NETWORK_RESULT network_receive_buffer (network_data *data, const char *en
119119

120120
// set PEM
121121
#ifdef __ANDROID__
122-
struct curl_blob pem_blob;
123-
pem_blob.data = cacert_pem;
124-
pem_blob.len = cacert_len;
125-
pem_blob.flags = CURL_BLOB_NOCOPY;
122+
struct curl_blob pem_blob = {
123+
.data = (void *)cacert_pem,
124+
.len = cacert_len,
125+
.flags = CURL_BLOB_NOCOPY
126+
};
126127
curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &pem_blob);
127128
#endif
128129

@@ -208,10 +209,11 @@ static bool network_send_buffer (network_data *data, const char *endpoint, const
208209

209210
// set PEM
210211
#ifdef __ANDROID__
211-
struct curl_blob pem_blob;
212-
pem_blob.data = cacert_pem;
213-
pem_blob.len = cacert_len;
214-
pem_blob.flags = CURL_BLOB_NOCOPY;
212+
struct curl_blob pem_blob = {
213+
.data = (void *)cacert_pem,
214+
.len = cacert_len,
215+
.flags = CURL_BLOB_NOCOPY
216+
};
215217
curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &pem_blob);
216218
#endif
217219

@@ -685,12 +687,15 @@ void cloudsync_network_sync (sqlite3_context *context, int wait_ms, int max_retr
685687
cloudsync_network_send_changes(context, 0, NULL);
686688

687689
int retries = 0;
690+
int nrows = 0;
688691
while (retries < max_retries) {
689-
int nrows = cloudsync_network_check_internal(context);
692+
nrows = cloudsync_network_check_internal(context);
690693
if (nrows > 0) break;
691694
else sqlite3_sleep(wait_ms);
692695
retries++;
693696
}
697+
698+
sqlite3_result_int(context, nrows);
694699
}
695700

696701
void cloudsync_network_sync0 (sqlite3_context *context, int argc, sqlite3_value **argv) {
@@ -759,10 +764,6 @@ int cloudsync_network_register (sqlite3 *db, char **pzErrMsg, void *ctx) {
759764
rc = dbutils_register_function(db, "cloudsync_network_reset_sync_version", cloudsync_network_reset_sync_version, 0, pzErrMsg, ctx, NULL);
760765
if (rc != SQLITE_OK) return rc;
761766

762-
#ifdef __ANDROID__
763-
cacert_len = strlen(cacert_pem);
764-
#endif
765-
766767
return rc;
767768
}
768769
#endif

test/unit.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -921,8 +921,8 @@ bool do_test_vtab(sqlite3 *db) {
921921
}
922922

923923
bool do_test_functions (sqlite3 *db, bool print_results) {
924-
int size = 0;
925-
char *site_id = dbutils_blob_select(db, "SELECT cloudsync_siteid();", &size);
924+
int size = 0, rc2;
925+
char *site_id = dbutils_blob_select(db, "SELECT cloudsync_siteid();", &size, NULL, &rc2);
926926
if (site_id == NULL || size != 16) goto abort_test_functions;
927927
cloudsync_memory_free(site_id);
928928

@@ -3042,8 +3042,8 @@ bool do_test_network_encode_decode (int nclients, bool print_result, bool cleanu
30423042
for (int j=0; j<nclients; ++j) {
30433043
if (target == j) continue;
30443044

3045-
int blob_size = 0;
3046-
char *blob = dbutils_blob_select (db[target], src_sql, &blob_size);
3045+
int blob_size = 0, rc;
3046+
char *blob = dbutils_blob_select (db[target], src_sql, &blob_size, NULL, &rc);
30473047
if (!blob) goto finalize;
30483048

30493049
const char *values[] = {blob};

0 commit comments

Comments
 (0)