@@ -146,7 +146,6 @@ struct cloudsync_context {
146146 void * aux_data ;
147147
148148 // stmts and context values
149- bool pragma_checked ; // we need to check PRAGMAs only once per transaction
150149 dbvm_t * schema_version_stmt ;
151150 dbvm_t * data_version_stmt ;
152151 dbvm_t * db_version_stmt ;
@@ -289,13 +288,15 @@ const char *cloudsync_algo_name (table_algo algo) {
289288// MARK: - DBVM Utils -
290289
291290DBVM_VALUE dbvm_execute (dbvm_t * stmt , cloudsync_context * data ) {
291+ if (!stmt ) return DBVM_VALUE_ERROR ;
292+
292293 int rc = databasevm_step (stmt );
293294 if (rc != DBRES_ROW && rc != DBRES_DONE ) {
294295 if (data ) DEBUG_DBERROR (rc , "stmt_execute" , data );
295296 databasevm_reset (stmt );
296297 return DBVM_VALUE_ERROR ;
297298 }
298-
299+
299300 DBVM_VALUE result = DBVM_VALUE_CHANGED ;
300301 if (stmt == data -> data_version_stmt ) {
301302 int version = (int )database_column_int (stmt , 0 );
@@ -399,12 +400,17 @@ int cloudsync_dbversion_rebuild (cloudsync_context *data) {
399400int cloudsync_dbversion_rerun (cloudsync_context * data ) {
400401 DBVM_VALUE schema_changed = dbvm_execute (data -> schema_version_stmt , data );
401402 if (schema_changed == DBVM_VALUE_ERROR ) return -1 ;
402-
403+
403404 if (schema_changed == DBVM_VALUE_CHANGED ) {
404405 int rc = cloudsync_dbversion_rebuild (data );
405406 if (rc != DBRES_OK ) return -1 ;
406407 }
407-
408+
409+ if (!data -> db_version_stmt ) {
410+ data -> db_version = CLOUDSYNC_MIN_DB_VERSION ;
411+ return 0 ;
412+ }
413+
408414 DBVM_VALUE rc = dbvm_execute (data -> db_version_stmt , data );
409415 if (rc == DBVM_VALUE_ERROR ) return -1 ;
410416 return 0 ;
@@ -593,7 +599,7 @@ void cloudsync_set_auxdata (cloudsync_context *data, void *xdata) {
593599}
594600
595601void cloudsync_set_schema (cloudsync_context * data , const char * schema ) {
596- if (data -> current_schema == schema ) return ;
602+ if (data -> current_schema && schema && strcmp ( data -> current_schema , schema ) == 0 ) return ;
597603 if (data -> current_schema ) cloudsync_memory_free (data -> current_schema );
598604 data -> current_schema = NULL ;
599605 if (schema ) data -> current_schema = cloudsync_string_dup_lowercase (schema );
@@ -782,7 +788,7 @@ int table_add_stmts (cloudsync_table_context *table, int ncols) {
782788 if (rc != DBRES_OK ) goto cleanup ;
783789
784790 // precompile the insert local sentinel statement
785- sql = cloudsync_memory_mprintf (SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION , table -> meta_ref , CLOUDSYNC_TOMBSTONE_VALUE );
791+ 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 );
786792 if (!sql ) {rc = DBRES_NOMEM ; goto cleanup ;}
787793 DEBUG_SQL ("meta_sentinel_insert_stmt: %s" , sql );
788794
@@ -954,37 +960,44 @@ int table_remove (cloudsync_context *data, cloudsync_table_context *table) {
954960int table_add_to_context_cb (void * xdata , int ncols , char * * values , char * * names ) {
955961 cloudsync_table_context * table = (cloudsync_table_context * )xdata ;
956962 cloudsync_context * data = table -> context ;
957-
963+
958964 int index = table -> ncols ;
959965 for (int i = 0 ; i < ncols ; i += 2 ) {
960966 const char * name = values [i ];
961967 int cid = (int )strtol (values [i + 1 ], NULL , 0 );
962-
968+
963969 table -> col_id [index ] = cid ;
964970 table -> col_name [index ] = cloudsync_string_dup_lowercase (name );
965- if (!table -> col_name [index ]) return 1 ;
966-
971+ if (!table -> col_name [index ]) goto error ;
972+
967973 char * sql = table_build_mergeinsert_sql (table , name );
968- if (!sql ) return DBRES_NOMEM ;
974+ if (!sql ) goto error ;
969975 DEBUG_SQL ("col_merge_stmt[%d]: %s" , index , sql );
970-
976+
971977 int rc = databasevm_prepare (data , sql , (void * * )& table -> col_merge_stmt [index ], DBFLAG_PERSISTENT );
972978 cloudsync_memory_free (sql );
973- if (rc != DBRES_OK ) return rc ;
974- if (!table -> col_merge_stmt [index ]) return DBRES_MISUSE ;
975-
979+ if (rc != DBRES_OK ) goto error ;
980+ if (!table -> col_merge_stmt [index ]) goto error ;
981+
976982 sql = table_build_value_sql (table , name );
977- if (!sql ) return DBRES_NOMEM ;
983+ if (!sql ) goto error ;
978984 DEBUG_SQL ("col_value_stmt[%d]: %s" , index , sql );
979-
985+
980986 rc = databasevm_prepare (data , sql , (void * * )& table -> col_value_stmt [index ], DBFLAG_PERSISTENT );
981987 cloudsync_memory_free (sql );
982- if (rc != DBRES_OK ) return rc ;
983- if (!table -> col_value_stmt [index ]) return DBRES_MISUSE ;
988+ if (rc != DBRES_OK ) goto error ;
989+ if (!table -> col_value_stmt [index ]) goto error ;
984990 }
985991 table -> ncols += 1 ;
986-
992+
987993 return 0 ;
994+
995+ error :
996+ // clean up partially-initialized entry at index
997+ if (table -> col_name [index ]) {cloudsync_memory_free (table -> col_name [index ]); table -> col_name [index ] = NULL ;}
998+ if (table -> col_merge_stmt [index ]) {databasevm_finalize (table -> col_merge_stmt [index ]); table -> col_merge_stmt [index ] = NULL ;}
999+ if (table -> col_value_stmt [index ]) {databasevm_finalize (table -> col_value_stmt [index ]); table -> col_value_stmt [index ] = NULL ;}
1000+ return 1 ;
9881001}
9891002
9901003bool table_ensure_capacity (cloudsync_context * data ) {
@@ -1026,7 +1039,7 @@ bool table_add_to_context (cloudsync_context *data, table_algo algo, const char
10261039 table -> npks = count ;
10271040 if (table -> npks == 0 ) {
10281041 #if CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
1029- return false ;
1042+ goto abort_add_table ;
10301043 #else
10311044 table -> rowid_only = true;
10321045 table -> npks = 1 ; // rowid
@@ -1073,7 +1086,8 @@ bool table_add_to_context (cloudsync_context *data, table_algo algo, const char
10731086
10741087dbvm_t * cloudsync_colvalue_stmt (cloudsync_context * data , const char * tbl_name , bool * persistent ) {
10751088 dbvm_t * vm = NULL ;
1076-
1089+ * persistent = false;
1090+
10771091 cloudsync_table_context * table = table_lookup (data , tbl_name );
10781092 if (table ) {
10791093 char * col_name = NULL ;
@@ -1116,7 +1130,7 @@ const char *table_colname (cloudsync_table_context *table, int index) {
11161130bool table_pk_exists (cloudsync_table_context * table , const char * value , size_t len ) {
11171131 // check if a row with the same primary key already exists
11181132 // if so, this means the row might have been previously deleted (sentinel)
1119- return (bool ) dbvm_count (table -> meta_pkexists_stmt , value , len , DBTYPE_BLOB );
1133+ return (dbvm_count (table -> meta_pkexists_stmt , value , len , DBTYPE_BLOB ) > 0 );
11201134}
11211135
11221136char * * table_pknames (cloudsync_table_context * table ) {
@@ -1642,6 +1656,10 @@ int merge_did_cid_win (cloudsync_context *data, cloudsync_table_context *table,
16421656 rc = databasevm_step (vm );
16431657 if (rc == DBRES_ROW ) {
16441658 const void * local_site_id = database_column_blob (vm , 0 );
1659+ if (!local_site_id ) {
1660+ dbvm_reset (vm );
1661+ return cloudsync_set_error (data , "NULL site_id in cloudsync table, table is probably corrupted" , DBRES_ERROR );
1662+ }
16451663 ret = memcmp (site_id , local_site_id , site_len );
16461664 * didwin_flag = (ret > 0 );
16471665 dbvm_reset (vm );
@@ -2222,6 +2240,7 @@ int cloudsync_refill_metatable (cloudsync_context *data, const char *table_name)
22222240 rc = databasevm_step (vm );
22232241 if (rc == DBRES_ROW ) {
22242242 const char * pk = (const char * )database_column_text (vm , 0 );
2243+ if (!pk ) { rc = DBRES_ERROR ; break ; }
22252244 size_t pklen = strlen (pk );
22262245 rc = local_mark_insert_or_update_meta (table , pk , pklen , col_name , db_version , cloudsync_bumpseq (data ));
22272246 } else if (rc == DBRES_DONE ) {
@@ -2761,11 +2780,8 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
27612780 if (rc != DBRES_OK ) {
27622781 merge_pending_free_entries (& batch );
27632782 data -> pending_batch = NULL ;
2764- if (batch .cached_vm ) { databasevm_finalize (batch .cached_vm ); batch .cached_vm = NULL ; }
2765- if (batch .cached_col_names ) { cloudsync_memory_free (batch .cached_col_names ); batch .cached_col_names = NULL ; }
2766- if (batch .entries ) { cloudsync_memory_free (batch .entries ); batch .entries = NULL ; }
2767- if (clone ) cloudsync_memory_free (clone );
2768- return cloudsync_set_error (data , "Error on cloudsync_payload_apply: unable to release a savepoint" , rc );
2783+ cloudsync_set_error (data , "Error on cloudsync_payload_apply: unable to release a savepoint" , rc );
2784+ goto cleanup ;
27692785 }
27702786 in_savepoint = false;
27712787 }
@@ -2775,11 +2791,8 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
27752791 if (rc != DBRES_OK ) {
27762792 merge_pending_free_entries (& batch );
27772793 data -> pending_batch = NULL ;
2778- if (batch .cached_vm ) { databasevm_finalize (batch .cached_vm ); batch .cached_vm = NULL ; }
2779- if (batch .cached_col_names ) { cloudsync_memory_free (batch .cached_col_names ); batch .cached_col_names = NULL ; }
2780- if (batch .entries ) { cloudsync_memory_free (batch .entries ); batch .entries = NULL ; }
2781- if (clone ) cloudsync_memory_free (clone );
2782- return cloudsync_set_error (data , "Error on cloudsync_payload_apply: unable to start a transaction" , rc );
2794+ cloudsync_set_error (data , "Error on cloudsync_payload_apply: unable to start a transaction" , rc );
2795+ goto cleanup ;
27832796 }
27842797 in_savepoint = true;
27852798 }
@@ -2812,9 +2825,6 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
28122825 if (flush_rc != DBRES_OK && rc == DBRES_OK ) rc = flush_rc ;
28132826 }
28142827 data -> pending_batch = NULL ;
2815- if (batch .cached_vm ) databasevm_finalize (batch .cached_vm );
2816- if (batch .cached_col_names ) cloudsync_memory_free (batch .cached_col_names );
2817- if (batch .entries ) cloudsync_memory_free (batch .entries );
28182828
28192829 if (in_savepoint ) {
28202830 int rc1 = database_commit_savepoint (data , "cloudsync_payload_apply" );
@@ -2841,6 +2851,11 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
28412851 }
28422852
28432853cleanup :
2854+ // cleanup merge_pending_batch
2855+ if (batch .cached_vm ) { databasevm_finalize (batch .cached_vm ); batch .cached_vm = NULL ; }
2856+ if (batch .cached_col_names ) { cloudsync_memory_free (batch .cached_col_names ); batch .cached_col_names = NULL ; }
2857+ if (batch .entries ) { cloudsync_memory_free (batch .entries ); batch .entries = NULL ; }
2858+
28442859 // cleanup vm
28452860 if (vm ) databasevm_finalize (vm );
28462861
@@ -2876,7 +2891,7 @@ int cloudsync_payload_get (cloudsync_context *data, char **blob, int *blob_size,
28762891 if (rc != DBRES_OK ) return rc ;
28772892
28782893 // exit if there is no data to send
2879- if (blob == NULL || * blob_size == 0 ) return DBRES_OK ;
2894+ if (* blob == NULL || * blob_size == 0 ) return DBRES_OK ;
28802895 return rc ;
28812896}
28822897
0 commit comments