@@ -115,7 +115,6 @@ struct cloudsync_context {
115115 void * aux_data ;
116116
117117 // stmts and context values
118- bool pragma_checked ; // we need to check PRAGMAs only once per transaction
119118 dbvm_t * schema_version_stmt ;
120119 dbvm_t * data_version_stmt ;
121120 dbvm_t * db_version_stmt ;
@@ -255,13 +254,15 @@ const char *cloudsync_algo_name (table_algo algo) {
255254// MARK: - DBVM Utils -
256255
257256DBVM_VALUE dbvm_execute (dbvm_t * stmt , cloudsync_context * data ) {
257+ if (!stmt ) return DBVM_VALUE_ERROR ;
258+
258259 int rc = databasevm_step (stmt );
259260 if (rc != DBRES_ROW && rc != DBRES_DONE ) {
260261 if (data ) DEBUG_DBERROR (rc , "stmt_execute" , data );
261262 databasevm_reset (stmt );
262263 return DBVM_VALUE_ERROR ;
263264 }
264-
265+
265266 DBVM_VALUE result = DBVM_VALUE_CHANGED ;
266267 if (stmt == data -> data_version_stmt ) {
267268 int version = (int )database_column_int (stmt , 0 );
@@ -365,12 +366,17 @@ int cloudsync_dbversion_rebuild (cloudsync_context *data) {
365366int cloudsync_dbversion_rerun (cloudsync_context * data ) {
366367 DBVM_VALUE schema_changed = dbvm_execute (data -> schema_version_stmt , data );
367368 if (schema_changed == DBVM_VALUE_ERROR ) return -1 ;
368-
369+
369370 if (schema_changed == DBVM_VALUE_CHANGED ) {
370371 int rc = cloudsync_dbversion_rebuild (data );
371372 if (rc != DBRES_OK ) return -1 ;
372373 }
373-
374+
375+ if (!data -> db_version_stmt ) {
376+ data -> db_version = CLOUDSYNC_MIN_DB_VERSION ;
377+ return 0 ;
378+ }
379+
374380 DBVM_VALUE rc = dbvm_execute (data -> db_version_stmt , data );
375381 if (rc == DBVM_VALUE_ERROR ) return -1 ;
376382 return 0 ;
@@ -559,7 +565,7 @@ void cloudsync_set_auxdata (cloudsync_context *data, void *xdata) {
559565}
560566
561567void cloudsync_set_schema (cloudsync_context * data , const char * schema ) {
562- if (data -> current_schema == schema ) return ;
568+ if (data -> current_schema && schema && strcmp ( data -> current_schema , schema ) == 0 ) return ;
563569 if (data -> current_schema ) cloudsync_memory_free (data -> current_schema );
564570 data -> current_schema = NULL ;
565571 if (schema ) data -> current_schema = cloudsync_string_dup_lowercase (schema );
@@ -748,7 +754,7 @@ int table_add_stmts (cloudsync_table_context *table, int ncols) {
748754 if (rc != DBRES_OK ) goto cleanup ;
749755
750756 // precompile the insert local sentinel statement
751- sql = cloudsync_memory_mprintf (SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION , table -> meta_ref , CLOUDSYNC_TOMBSTONE_VALUE );
757+ sql = cloudsync_memory_mprintf (SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION , table -> meta_ref , CLOUDSYNC_TOMBSTONE_VALUE , table -> meta_ref , table -> meta_ref , table -> meta_ref );
752758 if (!sql ) {rc = DBRES_NOMEM ; goto cleanup ;}
753759 DEBUG_SQL ("meta_sentinel_insert_stmt: %s" , sql );
754760
@@ -920,37 +926,44 @@ int table_remove (cloudsync_context *data, cloudsync_table_context *table) {
920926int table_add_to_context_cb (void * xdata , int ncols , char * * values , char * * names ) {
921927 cloudsync_table_context * table = (cloudsync_table_context * )xdata ;
922928 cloudsync_context * data = table -> context ;
923-
929+
924930 int index = table -> ncols ;
925931 for (int i = 0 ; i < ncols ; i += 2 ) {
926932 const char * name = values [i ];
927933 int cid = (int )strtol (values [i + 1 ], NULL , 0 );
928-
934+
929935 table -> col_id [index ] = cid ;
930936 table -> col_name [index ] = cloudsync_string_dup_lowercase (name );
931- if (!table -> col_name [index ]) return 1 ;
932-
937+ if (!table -> col_name [index ]) goto error ;
938+
933939 char * sql = table_build_mergeinsert_sql (table , name );
934- if (!sql ) return DBRES_NOMEM ;
940+ if (!sql ) goto error ;
935941 DEBUG_SQL ("col_merge_stmt[%d]: %s" , index , sql );
936-
942+
937943 int rc = databasevm_prepare (data , sql , (void * * )& table -> col_merge_stmt [index ], DBFLAG_PERSISTENT );
938944 cloudsync_memory_free (sql );
939- if (rc != DBRES_OK ) return rc ;
940- if (!table -> col_merge_stmt [index ]) return DBRES_MISUSE ;
941-
945+ if (rc != DBRES_OK ) goto error ;
946+ if (!table -> col_merge_stmt [index ]) goto error ;
947+
942948 sql = table_build_value_sql (table , name );
943- if (!sql ) return DBRES_NOMEM ;
949+ if (!sql ) goto error ;
944950 DEBUG_SQL ("col_value_stmt[%d]: %s" , index , sql );
945-
951+
946952 rc = databasevm_prepare (data , sql , (void * * )& table -> col_value_stmt [index ], DBFLAG_PERSISTENT );
947953 cloudsync_memory_free (sql );
948- if (rc != DBRES_OK ) return rc ;
949- if (!table -> col_value_stmt [index ]) return DBRES_MISUSE ;
954+ if (rc != DBRES_OK ) goto error ;
955+ if (!table -> col_value_stmt [index ]) goto error ;
950956 }
951957 table -> ncols += 1 ;
952-
958+
953959 return 0 ;
960+
961+ error :
962+ // clean up partially-initialized entry at index
963+ if (table -> col_name [index ]) {cloudsync_memory_free (table -> col_name [index ]); table -> col_name [index ] = NULL ;}
964+ if (table -> col_merge_stmt [index ]) {databasevm_finalize (table -> col_merge_stmt [index ]); table -> col_merge_stmt [index ] = NULL ;}
965+ if (table -> col_value_stmt [index ]) {databasevm_finalize (table -> col_value_stmt [index ]); table -> col_value_stmt [index ] = NULL ;}
966+ return 1 ;
954967}
955968
956969bool table_ensure_capacity (cloudsync_context * data ) {
@@ -992,7 +1005,7 @@ bool table_add_to_context (cloudsync_context *data, table_algo algo, const char
9921005 table -> npks = count ;
9931006 if (table -> npks == 0 ) {
9941007 #if CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
995- return false ;
1008+ goto abort_add_table ;
9961009 #else
9971010 table -> rowid_only = true;
9981011 table -> npks = 1 ; // rowid
@@ -1039,7 +1052,8 @@ bool table_add_to_context (cloudsync_context *data, table_algo algo, const char
10391052
10401053dbvm_t * cloudsync_colvalue_stmt (cloudsync_context * data , const char * tbl_name , bool * persistent ) {
10411054 dbvm_t * vm = NULL ;
1042-
1055+ * persistent = false;
1056+
10431057 cloudsync_table_context * table = table_lookup (data , tbl_name );
10441058 if (table ) {
10451059 char * col_name = NULL ;
@@ -1082,7 +1096,7 @@ const char *table_colname (cloudsync_table_context *table, int index) {
10821096bool table_pk_exists (cloudsync_table_context * table , const char * value , size_t len ) {
10831097 // check if a row with the same primary key already exists
10841098 // if so, this means the row might have been previously deleted (sentinel)
1085- return (bool ) dbvm_count (table -> meta_pkexists_stmt , value , len , DBTYPE_BLOB );
1099+ return (dbvm_count (table -> meta_pkexists_stmt , value , len , DBTYPE_BLOB ) > 0 );
10861100}
10871101
10881102char * * table_pknames (cloudsync_table_context * table ) {
@@ -1373,6 +1387,10 @@ int merge_did_cid_win (cloudsync_context *data, cloudsync_table_context *table,
13731387 rc = databasevm_step (vm );
13741388 if (rc == DBRES_ROW ) {
13751389 const void * local_site_id = database_column_blob (vm , 0 );
1390+ if (!local_site_id ) {
1391+ dbvm_reset (vm );
1392+ return cloudsync_set_error (data , "NULL site_id in cloudsync table, table is probably corrupted" , DBRES_ERROR );
1393+ }
13761394 ret = memcmp (site_id , local_site_id , site_len );
13771395 * didwin_flag = (ret > 0 );
13781396 dbvm_reset (vm );
@@ -1929,6 +1947,7 @@ int cloudsync_refill_metatable (cloudsync_context *data, const char *table_name)
19291947 rc = databasevm_step (vm );
19301948 if (rc == DBRES_ROW ) {
19311949 const char * pk = (const char * )database_column_text (vm , 0 );
1950+ if (!pk ) { rc = DBRES_ERROR ; break ; }
19321951 size_t pklen = strlen (pk );
19331952 rc = local_mark_insert_or_update_meta (table , pk , pklen , col_name , db_version , cloudsync_bumpseq (data ));
19341953 } else if (rc == DBRES_DONE ) {
@@ -2448,8 +2467,8 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
24482467 if (in_savepoint && db_version_changed ) {
24492468 rc = database_commit_savepoint (data , "cloudsync_payload_apply" );
24502469 if (rc != DBRES_OK ) {
2451- if ( clone ) cloudsync_memory_free ( clone );
2452- return cloudsync_set_error ( data , "Error on cloudsync_payload_apply: unable to release a savepoint" , rc ) ;
2470+ cloudsync_set_error ( data , "Error on cloudsync_payload_apply: unable to release a savepoint" , rc );
2471+ goto cleanup ;
24532472 }
24542473 in_savepoint = false;
24552474 }
@@ -2459,8 +2478,8 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
24592478 if (!in_transaction && db_version_changed ) {
24602479 rc = database_begin_savepoint (data , "cloudsync_payload_apply" );
24612480 if (rc != DBRES_OK ) {
2462- if ( clone ) cloudsync_memory_free ( clone );
2463- return cloudsync_set_error ( data , "Error on cloudsync_payload_apply: unable to start a transaction" , rc ) ;
2481+ cloudsync_set_error ( data , "Error on cloudsync_payload_apply: unable to start a transaction" , rc );
2482+ goto cleanup ;
24642483 }
24652484 last_payload_db_version = decoded_context .db_version ;
24662485 in_savepoint = true;
@@ -2548,7 +2567,7 @@ int cloudsync_payload_get (cloudsync_context *data, char **blob, int *blob_size,
25482567 if (rc != DBRES_OK ) return rc ;
25492568
25502569 // exit if there is no data to send
2551- if (blob == NULL || * blob_size == 0 ) return DBRES_OK ;
2570+ if (* blob == NULL || * blob_size == 0 ) return DBRES_OK ;
25522571 return rc ;
25532572}
25542573
0 commit comments