Skip to content

Commit 7d1fb60

Browse files
committed
New architecture WP 4
1 parent 9ff3fa4 commit 7d1fb60

File tree

7 files changed

+496
-371
lines changed

7 files changed

+496
-371
lines changed

src/cloudsync.c

Lines changed: 277 additions & 329 deletions
Large diffs are not rendered by default.

src/cloudsync.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ extern "C" {
1919

2020
#define CLOUDSYNC_VERSION "0.9.0"
2121

22-
typedef struct cloudsync_pk_decode_bind_context cloudsync_pk_decode_bind_context;
23-
2422
// CLOUDSYNC CONTEXT
2523
typedef struct cloudsync_context cloudsync_context;
2624

@@ -29,25 +27,24 @@ const char *cloudsync_context_init (cloudsync_context *data, void *db, void *db_
2927
void cloudsync_context_free (void *ctx);
3028

3129
// OK
32-
int cloudsync_cleanup (db_t *db, cloudsync_context *data, const char *table_name);
30+
int cloudsync_cleanup (cloudsync_context *data, const char *table_name);
3331
int cloudsync_init_table (cloudsync_context *data, const char *table_name, const char *algo_name, bool skip_int_pk_check);
3432

3533
int cloudsync_terminate (cloudsync_context *data);
3634
int cloudsync_insync (cloudsync_context *data);
3735
int cloudsync_bumpseq (cloudsync_context *data);
3836
void *cloudsync_siteid (cloudsync_context *data);
3937
void cloudsync_reset_siteid (cloudsync_context *data);
40-
38+
db_int64 cloudsync_dbversion_next (cloudsync_context *data, db_int64 merging_version);
4139
db_int64 cloudsync_dbversion (cloudsync_context *data);
42-
void cloudsync_update_schema_hash (cloudsync_context *data, void *db);
40+
void cloudsync_update_schema_hash (cloudsync_context *data);
41+
int cloudsync_dbversion_check_uptodate (cloudsync_context *data);
4342

4443
void *cloudsync_db (cloudsync_context *data);
4544
void *cloudsync_dbcontext (cloudsync_context *data);
4645
void cloudsync_set_db (cloudsync_context *data, void *value);
4746
void cloudsync_set_dbcontext (cloudsync_context *data, void *value);
48-
49-
int cloudsync_dbversion_check_uptodate (db_t *db, cloudsync_context *data);
50-
db_int64 cloudsync_dbversion_next (db_t *db, cloudsync_context *data, db_int64 merging_version);
47+
const char *cloudsync_errmsg (cloudsync_context *data);
5148

5249
int cloudsync_commit_hook (void *ctx);
5350
void cloudsync_rollback_hook (void *ctx);
@@ -75,6 +72,7 @@ const char *table_colname (cloudsync_table_context *table, int index);
7572

7673
char **table_pknames (cloudsync_table_context *table);
7774
void table_set_pknames (cloudsync_table_context *table, char **pknames);
75+
bool table_algo_isgos (cloudsync_table_context *table);
7876

7977
int table_remove (cloudsync_context *data, cloudsync_table_context *table);
8078
void table_free (cloudsync_table_context *table);

src/cloudsync_private.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,28 @@ typedef enum {
2929
CLOUDSYNC_PAYLOAD_APPLY_CLEANUP = 3
3030
} CLOUDSYNC_PAYLOAD_APPLY_STEPS;
3131

32-
int cloudsync_merge_insert (sqlite3_vtab *vtab, int argc, sqlite3_value **argv, sqlite3_int64 *rowid);
32+
33+
// used by vtab.c
34+
int merge_insert_col (cloudsync_context *data, cloudsync_table_context *table, const char *pk, int pklen, const char *col_name, dbvalue_t *col_value, db_int64 col_version, db_int64 db_version, const char *site_id, int site_len, db_int64 seq, db_int64 *rowid);
35+
36+
int merge_insert (cloudsync_context *data, cloudsync_table_context *table, const char *insert_pk, int insert_pk_len, db_int64 insert_cl, const char *insert_name, dbvalue_t *insert_value, db_int64 insert_col_version, db_int64 insert_db_version, const char *insert_site_id, int insert_site_id_len, db_int64 insert_seq, db_int64 *rowid);
37+
38+
typedef struct cloudsync_pk_decode_bind_context cloudsync_pk_decode_bind_context;
39+
3340
void cloudsync_sync_key (cloudsync_context *data, const char *key, const char *value);
3441

3542
// used by network layer
3643
void *cloudsync_get_auxdata (sqlite3_context *context);
3744
void cloudsync_set_auxdata (sqlite3_context *context, void *xdata);
3845
int cloudsync_payload_apply (sqlite3_context *context, const char *payload, int blen);
39-
int cloudsync_payload_get (cloudsync_context *data, char **blob, int *blob_size, int *db_version, int *seq, sqlite3_int64 *new_db_version, sqlite3_int64 *new_seq);
46+
int cloudsync_payload_get (cloudsync_context *data, char **blob, int *blob_size, int *db_version, int *seq, db_int64 *new_db_version, db_int64 *new_seq);
4047

4148
// used by core
4249
typedef bool (*cloudsync_payload_apply_callback_t)(void **xdata, cloudsync_pk_decode_bind_context *decoded_change, sqlite3 *db, cloudsync_context *data, int step, int rc);
43-
void cloudsync_set_payload_apply_callback(sqlite3 *db, cloudsync_payload_apply_callback_t callback);
50+
void cloudsync_set_payload_apply_callback(db_t *db, cloudsync_payload_apply_callback_t callback);
4451

45-
bool cloudsync_config_exists (sqlite3 *db);
46-
sqlite3_stmt *cloudsync_colvalue_stmt (sqlite3 *db, cloudsync_context *data, const char *tbl_name, bool *persistent);
52+
bool cloudsync_config_exists (db_t *db);
53+
dbvm_t *cloudsync_colvalue_stmt (db_t *db, cloudsync_context *data, const char *tbl_name, bool *persistent);
4754
char *cloudsync_pk_context_tbl (cloudsync_pk_decode_bind_context *ctx, int64_t *tbl_len);
4855
void *cloudsync_pk_context_pk (cloudsync_pk_decode_bind_context *ctx, int64_t *pk_len);
4956
char *cloudsync_pk_context_colname (cloudsync_pk_decode_bind_context *ctx, int64_t *colname_len);

src/cloudsync_sqlite.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ typedef struct {
4545
} cloudsync_update_payload;
4646

4747
// TODO: REMOVE
48-
int local_mark_insert_sentinel_meta (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen, sqlite3_int64 db_version, int seq);
49-
int local_update_sentinel (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen, sqlite3_int64 db_version, int seq);
50-
int local_mark_insert_or_update_meta (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen, const char *col_name, sqlite3_int64 db_version, int seq);
51-
int local_mark_delete_meta (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen, sqlite3_int64 db_version, int seq);
52-
int local_drop_meta (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen);
53-
int local_update_move_meta (sqlite3 *db, cloudsync_table_context *table, const char *pk, size_t pklen, const char *pk2, size_t pklen2, sqlite3_int64 db_version);
48+
int local_mark_insert_sentinel_meta (cloudsync_table_context *table, const char *pk, size_t pklen, db_int64 db_version, int seq);
49+
int local_update_sentinel (cloudsync_table_context *table, const char *pk, size_t pklen, db_int64 db_version, int seq);
50+
int local_mark_insert_or_update_meta (cloudsync_table_context *table, const char *pk, size_t pklen, const char *col_name, db_int64 db_version, int seq);
51+
int local_mark_delete_meta (cloudsync_table_context *table, const char *pk, size_t pklen, db_int64 db_version, int seq);
52+
int local_drop_meta (cloudsync_table_context *table, const char *pk, size_t pklen);
53+
int local_update_move_meta (cloudsync_table_context *table, const char *pk, size_t pklen, const char *pk2, size_t pklen2, db_int64 db_version);
54+
55+
56+
5457
int cloudsync_finalize_alter (sqlite3_context *context, cloudsync_context *data, cloudsync_table_context *table);
5558

5659
void cloudsync_payload_encode_step (sqlite3_context *context, int argc, sqlite3_value **argv);
@@ -80,11 +83,11 @@ void dbsync_db_version (sqlite3_context *context, int argc, sqlite3_value **argv
8083
UNUSED_PARAMETER(argv);
8184

8285
// retrieve context
83-
sqlite3 *db = sqlite3_context_db_handle(context);
8486
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
8587

86-
int rc = cloudsync_dbversion_check_uptodate(db, data);
88+
int rc = cloudsync_dbversion_check_uptodate(data);
8789
if (rc != SQLITE_OK) {
90+
sqlite3 *db = sqlite3_context_db_handle(context);
8891
dbutils_set_error(context, "Unable to retrieve db_version (%s).", database_errmsg(db));
8992
return;
9093
}
@@ -96,12 +99,12 @@ void dbsync_db_version_next (sqlite3_context *context, int argc, sqlite3_value *
9699
DEBUG_FUNCTION("cloudsync_db_version_next");
97100

98101
// retrieve context
99-
sqlite3 *db = sqlite3_context_db_handle(context);
100102
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
101103

102104
sqlite3_int64 merging_version = (argc == 1) ? database_value_int(argv[0]) : CLOUDSYNC_VALUE_NOTSET;
103-
sqlite3_int64 value = cloudsync_dbversion_next(db, data, merging_version);
105+
sqlite3_int64 value = cloudsync_dbversion_next(data, merging_version);
104106
if (value == -1) {
107+
sqlite3 *db = sqlite3_context_db_handle(context);
105108
dbutils_set_error(context, "Unable to retrieve next_db_version (%s).", database_errmsg(db));
106109
return;
107110
}
@@ -321,7 +324,7 @@ void dbsync_insert (sqlite3_context *context, int argc, sqlite3_value **argv) {
321324
}
322325

323326
// compute the next database version for tracking changes
324-
db_int64 db_version = cloudsync_dbversion_next(db, data, CLOUDSYNC_VALUE_NOTSET);
327+
db_int64 db_version = cloudsync_dbversion_next(data, CLOUDSYNC_VALUE_NOTSET);
325328

326329
// check if a row with the same primary key already exists
327330
// if so, this means the row might have been previously deleted (sentinel)
@@ -330,18 +333,18 @@ void dbsync_insert (sqlite3_context *context, int argc, sqlite3_value **argv) {
330333

331334
if (table_count_cols(table) == 0) {
332335
// if there are no columns other than primary keys, insert a sentinel record
333-
rc = local_mark_insert_sentinel_meta(db, table, pk, pklen, db_version, cloudsync_bumpseq(data));
336+
rc = local_mark_insert_sentinel_meta(table, pk, pklen, db_version, cloudsync_bumpseq(data));
334337
if (rc != SQLITE_OK) goto cleanup;
335338
} else if (pk_exists){
336339
// if a row with the same primary key already exists, update the sentinel record
337-
rc = local_update_sentinel(db, table, pk, pklen, db_version, cloudsync_bumpseq(data));
340+
rc = local_update_sentinel(table, pk, pklen, db_version, cloudsync_bumpseq(data));
338341
if (rc != SQLITE_OK) goto cleanup;
339342
}
340343

341344
// process each non-primary key column for insert or update
342345
for (int i=0; i<table_count_cols(table); ++i) {
343346
// mark the column as inserted or updated in the metadata
344-
rc = local_mark_insert_or_update_meta(db, table, pk, pklen, table_colname(table, i), db_version, cloudsync_bumpseq(data));
347+
rc = local_mark_insert_or_update_meta(table, pk, pklen, table_colname(table, i), db_version, cloudsync_bumpseq(data));
345348
if (rc != SQLITE_OK) goto cleanup;
346349
}
347350

@@ -368,7 +371,7 @@ void dbsync_delete (sqlite3_context *context, int argc, sqlite3_value **argv) {
368371
}
369372

370373
// compute the next database version for tracking changes
371-
db_int64 db_version = cloudsync_dbversion_next(db, data, CLOUDSYNC_VALUE_NOTSET);
374+
db_int64 db_version = cloudsync_dbversion_next(data, CLOUDSYNC_VALUE_NOTSET);
372375
int rc = SQLITE_OK;
373376

374377
// encode the primary key values into a buffer
@@ -381,11 +384,11 @@ void dbsync_delete (sqlite3_context *context, int argc, sqlite3_value **argv) {
381384
}
382385

383386
// mark the row as deleted by inserting a delete sentinel into the metadata
384-
rc = local_mark_delete_meta(db, table, pk, pklen, db_version, cloudsync_bumpseq(data));
387+
rc = local_mark_delete_meta(table, pk, pklen, db_version, cloudsync_bumpseq(data));
385388
if (rc != SQLITE_OK) goto cleanup;
386389

387390
// remove any metadata related to the old rows associated with this primary key
388-
rc = local_drop_meta(db, table, pk, pklen);
391+
rc = local_drop_meta(table, pk, pklen);
389392
if (rc != SQLITE_OK) goto cleanup;
390393

391394
cleanup:
@@ -476,7 +479,7 @@ void dbsync_update_final (sqlite3_context *context) {
476479
}
477480

478481
// compute the next database version for tracking changes
479-
db_int64 db_version = cloudsync_dbversion_next(db, data, CLOUDSYNC_VALUE_NOTSET);
482+
db_int64 db_version = cloudsync_dbversion_next(data, CLOUDSYNC_VALUE_NOTSET);
480483
int rc = SQLITE_OK;
481484

482485
// Check if the primary key(s) have changed
@@ -515,17 +518,17 @@ void dbsync_update_final (sqlite3_context *context) {
515518
}
516519

517520
// mark the rows with the old primary key as deleted in the metadata (old row handling)
518-
rc = local_mark_delete_meta(db, table, oldpk, oldpklen, db_version, cloudsync_bumpseq(data));
521+
rc = local_mark_delete_meta(table, oldpk, oldpklen, db_version, cloudsync_bumpseq(data));
519522
if (rc != SQLITE_OK) goto cleanup;
520523

521524
// move non-sentinel metadata entries from OLD primary key to NEW primary key
522525
// handles the case where some metadata is retained across primary key change
523526
// see https://github.com/sqliteai/sqlite-sync/blob/main/docs/PriKey.md for more details
524-
rc = local_update_move_meta(db, table, pk, pklen, oldpk, oldpklen, db_version);
527+
rc = local_update_move_meta(table, pk, pklen, oldpk, oldpklen, db_version);
525528
if (rc != SQLITE_OK) goto cleanup;
526529

527530
// mark a new sentinel row with the new primary key in the metadata
528-
rc = local_mark_insert_sentinel_meta(db, table, pk, pklen, db_version, cloudsync_bumpseq(data));
531+
rc = local_mark_insert_sentinel_meta(table, pk, pklen, db_version, cloudsync_bumpseq(data));
529532
if (rc != SQLITE_OK) goto cleanup;
530533

531534
// free memory if the OLD primary key was dynamically allocated
@@ -540,7 +543,7 @@ void dbsync_update_final (sqlite3_context *context) {
540543
if (dbutils_value_compare(payload->old_values[col_index], payload->new_values[col_index]) != 0) {
541544
// if a column value has changed, mark it as updated in the metadata
542545
// columns are in cid order
543-
rc = local_mark_insert_or_update_meta(db, table, pk, pklen, table_colname(table, i), db_version, cloudsync_bumpseq(data));
546+
rc = local_mark_insert_or_update_meta(table, pk, pklen, table_colname(table, i), db_version, cloudsync_bumpseq(data));
544547
if (rc != SQLITE_OK) goto cleanup;
545548
}
546549
}
@@ -560,9 +563,7 @@ void dbsync_cleanup (sqlite3_context *context, int argc, sqlite3_value **argv) {
560563

561564
const char *table = (const char *)database_value_text(argv[0]);
562565
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
563-
sqlite3 *db = sqlite3_context_db_handle(context);
564-
565-
cloudsync_cleanup(db, data, table);
566+
cloudsync_cleanup(data, table);
566567
}
567568

568569
void dbsync_enable_disable (sqlite3_context *context, const char *table_name, bool value) {
@@ -639,7 +640,7 @@ void dbsync_init (sqlite3_context *context, const char *table, const char *algo,
639640
return;
640641
}
641642

642-
cloudsync_update_schema_hash(data, db);
643+
cloudsync_update_schema_hash(data);
643644

644645
// returns site_id as TEXT
645646
char buffer[UUID_STR_MAXLEN];
@@ -784,8 +785,7 @@ void dbsync_commit_alter (sqlite3_context *context, int argc, sqlite3_value **ar
784785
goto rollback_finalize_alter;
785786
}
786787

787-
cloudsync_update_schema_hash(data, db);
788-
788+
cloudsync_update_schema_hash(data);
789789
return;
790790

791791
rollback_finalize_alter:

src/database.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ int database_step (dbvm_t *vm);
5050
void database_finalize (dbvm_t *vm); // NO RET
5151
void database_reset (dbvm_t *vm); // NO RET
5252
void database_clear_bindings (dbvm_t *vm); // NO RET
53+
const char *database_sql (dbvm_t *vm);
5354

5455
int database_bind_blob (dbvm_t *vm, int index, const void *value, db_uint64 size); // SQLITE_OK
5556
int database_bind_double (dbvm_t *vm, int index, double value); // SQLITE_OK
@@ -98,4 +99,8 @@ char *dbmem_mprintf(const char *format, ...);
9899
void dbmem_free (void *ptr);
99100
db_uint64 dbmem_size (void *ptr);
100101

102+
int database_pk_names (dbvm_t *vm, const char *table_name, char ***names, int *count);
103+
char *sql_build_drop_table (const char *table_name, char *buffer, int bsize, bool is_meta);
104+
105+
101106
#endif

src/database_sqlite.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "cloudsync.h"
99
#include "database.h"
10+
#include "utils.h"
11+
1012
#include <string.h>
1113

1214
#ifndef SQLITE_CORE
@@ -64,6 +66,85 @@ void database_clear_bindings (dbvm_t *vm) {
6466
sqlite3_clear_bindings((sqlite3_stmt *)vm);
6567
}
6668

69+
const char *database_sql (dbvm_t *vm) {
70+
return sqlite3_expanded_sql((sqlite3_stmt *)vm);
71+
}
72+
73+
int database_pk_rowid (db_t *db, const char *table_name, char ***names, int *count) {
74+
char buffer[2048];
75+
char *sql = sqlite3_snprintf(sizeof(buffer), buffer, "SELECT rowid FROM %Q LIMIT 0;", table_name);
76+
if (!sql) return SQLITE_NOMEM;
77+
78+
sqlite3_stmt *vm = NULL;
79+
int rc = sqlite3_prepare_v2(db, sql, -1, &vm, NULL);
80+
if (rc != SQLITE_OK) goto cleanup;
81+
82+
if (rc == SQLITE_OK) {
83+
char **r = (char**)dbmem_alloc(sizeof(char*));
84+
if (!r) return SQLITE_NOMEM;
85+
r[0] = cloudsync_string_dup("rowid", false);
86+
*names = r;
87+
*count = 1;
88+
} else {
89+
// WITHOUT ROWID + no declared PKs => return empty set
90+
*names = NULL;
91+
*count = 0;
92+
rc = SQLITE_OK;
93+
}
94+
95+
cleanup:
96+
if (vm) sqlite3_finalize(vm);
97+
return rc;
98+
}
99+
100+
int database_pk_names (db_t *db, const char *table_name, char ***names, int *count) {
101+
char buffer[2048];
102+
char *sql = sqlite3_snprintf(sizeof(buffer), buffer, "SELECT name FROM pragma_table_info(%Q) WHERE pk > 0 ORDER BY pk;", table_name);
103+
if (!sql) return SQLITE_NOMEM;
104+
105+
sqlite3_stmt *vm = NULL;
106+
int rc = sqlite3_prepare_v2(db, sql, -1, &vm, NULL);
107+
if (rc != SQLITE_OK) goto cleanup;
108+
109+
// count PK columns
110+
int rows = 0;
111+
while ((rc = sqlite3_step(vm)) == SQLITE_ROW) rows++;
112+
if (rc != SQLITE_DONE) goto cleanup;
113+
114+
if (rows == 0) {
115+
sqlite3_finalize(vm);
116+
// no declared PKs so check for rowid availability
117+
return database_pk_rowid(db, table_name, names, count);
118+
}
119+
120+
// reset vm to read PKs again
121+
rc = sqlite3_reset(vm);
122+
if (rc != SQLITE_OK) goto cleanup;
123+
124+
// allocate array
125+
char **r = (char**)dbmem_alloc(sizeof(char*) * rows);
126+
if (!r) {rc = SQLITE_NOMEM; goto cleanup;}
127+
128+
int i = 0;
129+
while ((rc = sqlite3_step(vm)) == SQLITE_ROW) {
130+
const char *txt = (const char*)sqlite3_column_text(vm, 0);
131+
if (!txt) {rc = SQLITE_ERROR; goto cleanup;}
132+
r[i] = cloudsync_string_dup(txt, false);
133+
if (!r[i]) { rc = SQLITE_NOMEM; goto cleanup;}
134+
i++;
135+
}
136+
if (rc == SQLITE_DONE) rc = SQLITE_OK;
137+
138+
*names = r;
139+
*count = rows;
140+
141+
cleanup:
142+
if (vm) sqlite3_finalize(vm);
143+
return rc;
144+
}
145+
146+
// MARK: -
147+
67148
int database_bind_blob (dbvm_t *vm, int index, const void *value, db_uint64 size) {
68149
return sqlite3_bind_blob64((sqlite3_stmt *)vm, index, value, size, SQLITE_STATIC);
69150
}
@@ -88,6 +169,20 @@ int database_bind_value (dbvm_t *vm, int index, dbvalue_t *value) {
88169
return sqlite3_bind_value((sqlite3_stmt *)vm, index, (const sqlite3_value *)value);
89170
}
90171

172+
// MARK: - SQL -
173+
174+
char *sql_build_drop_table (const char *table_name, char *buffer, int bsize, bool is_meta) {
175+
char *sql = NULL;
176+
177+
if (is_meta) {
178+
sql = sqlite3_snprintf(bsize, buffer, "DROP TABLE IF EXISTS \"%w_cloudsync\";", table_name);
179+
} else {
180+
sql = sqlite3_snprintf(bsize, buffer, "DROP TABLE IF EXISTS \"%w\";", table_name);
181+
}
182+
183+
return sql;
184+
}
185+
91186
// MARK: - VALUE -
92187

93188
const void *database_value_blob (dbvalue_t *value) {

0 commit comments

Comments
 (0)