@@ -71,8 +71,6 @@ SQLITE_EXTENSION_INIT1
7171#define CLOUDSYNC_PAYLOAD_MINBUF_SIZE 512*1024
7272#define CLOUDSYNC_PAYLOAD_VERSION 1
7373#define CLOUDSYNC_PAYLOAD_SIGNATURE 'CLSY'
74- #define CLOUDSYNC_PK_INDEX_DBVERSION 5
75- #define CLOUDSYNC_PK_INDEX_SEQ 8
7674
7775#ifndef MAX
7876#define MAX (a , b ) (((a)>(b))?(a):(b))
@@ -93,12 +91,17 @@ typedef enum {
9391 CLOUDSYNC_STMT_VALUE_CHANGED = 1 ,
9492} CLOUDSYNC_STMT_VALUE ;
9593
96- typedef struct {
97- sqlite3_stmt * vm ;
98- int64_t dbversion ;
99- int64_t seq ;
100- int64_t tmp_dbversion ;
101- } cloudsync_pk_decode_bind_context ;
94+ typedef enum {
95+ CLOUDSYNC_PK_INDEX_TBL = 0 ,
96+ CLOUDSYNC_PK_INDEX_PK = 1 ,
97+ CLOUDSYNC_PK_INDEX_COLNAME = 2 ,
98+ CLOUDSYNC_PK_INDEX_COLVALUE = 3 ,
99+ CLOUDSYNC_PK_INDEX_COLVERSION = 4 ,
100+ CLOUDSYNC_PK_INDEX_DBVERSION = 5 ,
101+ CLOUDSYNC_PK_INDEX_SITEID = 6 ,
102+ CLOUDSYNC_PK_INDEX_CL = 7 ,
103+ CLOUDSYNC_PK_INDEX_SEQ = 8
104+ } CLOUDSYNC_PK_INDEX ;
102105
103106typedef struct {
104107 sqlite3_context * context ;
@@ -215,6 +218,8 @@ int db_version_rebuild_stmt (sqlite3 *db, cloudsync_context *data);
215218int cloudsync_load_siteid (sqlite3 * db , cloudsync_context * data );
216219int 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 );
217220
221+ static cloudsync_payload_apply_callback_t payload_apply_callback ;
222+
218223// MARK: - STMT Utils -
219224
220225CLOUDSYNC_STMT_VALUE stmt_execute (sqlite3_stmt * stmt , cloudsync_context * data ) {
@@ -1927,32 +1932,55 @@ int cloudsync_pk_decode_bind_callback (void *xdata, int index, int type, int64_t
19271932 cloudsync_pk_decode_bind_context * decode_context = (cloudsync_pk_decode_bind_context * )xdata ;
19281933 int rc = pk_decode_bind_callback (decode_context -> vm , index , type , ival , dval , pval );
19291934
1930- if (rc == SQLITE_OK && type == SQLITE_INTEGER ) {
1935+ if (rc == SQLITE_OK ) {
19311936 // the dbversion index is smaller than seq index, so it is processed first
19321937 // when processing the dbversion column: save the value to the tmp_dbversion field
19331938 // when processing the seq column: update the dbversion and seq fields only if the current dbversion is greater than the last max value
19341939 switch (index ) {
1940+ case CLOUDSYNC_PK_INDEX_TBL :
1941+ if (type == SQLITE_TEXT ) {
1942+ decode_context -> tbl = pval ;
1943+ decode_context -> tbl_len = ival ;
1944+ }
1945+ break ;
1946+ case CLOUDSYNC_PK_INDEX_PK :
1947+ if (type == SQLITE_BLOB ) {
1948+ decode_context -> pk = pval ;
1949+ decode_context -> pk_len = ival ;
1950+ }
1951+ break ;
1952+ case CLOUDSYNC_PK_INDEX_COLNAME :
1953+ if (type == SQLITE_TEXT ) {
1954+ decode_context -> col_name = pval ;
1955+ decode_context -> col_name_len = ival ;
1956+ }
1957+ break ;
1958+ case CLOUDSYNC_PK_INDEX_COLVERSION :
1959+ if (type == SQLITE_INTEGER ) decode_context -> col_version = ival ;
1960+ break ;
19351961 case CLOUDSYNC_PK_INDEX_DBVERSION :
1936- decode_context -> tmp_dbversion = ival ;
1962+ if ( type == SQLITE_INTEGER ) decode_context -> db_version = ival ;
19371963 break ;
1938- case CLOUDSYNC_PK_INDEX_SEQ :
1939- // when the dbversion field is incremented the seq val must be updated too
1940- // because the current decode_context->seq field refers to the previous dbversion
1941- if (decode_context -> tmp_dbversion > decode_context -> dbversion ) {
1942- decode_context -> dbversion = decode_context -> tmp_dbversion ;
1943- decode_context -> seq = ival ;
1944- } else if (decode_context -> tmp_dbversion == decode_context -> dbversion ) {
1945- decode_context -> seq = MAX (decode_context -> seq , ival );
1964+ case CLOUDSYNC_PK_INDEX_SITEID :
1965+ if (type == SQLITE_BLOB ) {
1966+ decode_context -> site_id = pval ;
1967+ decode_context -> site_id_len = ival ;
19461968 }
1947- // reset the tmp_dbversion value before processing the next row
1948- decode_context -> tmp_dbversion = 0 ;
1969+ break ;
1970+ case CLOUDSYNC_PK_INDEX_CL :
1971+ if (type == SQLITE_INTEGER ) decode_context -> cl = ival ;
1972+ break ;
1973+ case CLOUDSYNC_PK_INDEX_SEQ :
1974+ if (type == SQLITE_INTEGER ) decode_context -> seq = ival ;
19491975 break ;
19501976 }
19511977 }
19521978
19531979 return rc ;
19541980}
19551981
1982+ // #ifndef CLOUDSYNC_OMIT_RLS_VALIDATION
1983+
19561984int cloudsync_payload_apply (sqlite3_context * context , const char * payload , int blen ) {
19571985 // decode header
19581986 cloudsync_network_header header ;
@@ -2016,31 +2044,47 @@ int cloudsync_payload_apply (sqlite3_context *context, const char *payload, int
20162044 uint32_t nrows = header .nrows ;
20172045 int dbversion = dbutils_settings_get_int_value (db , CLOUDSYNC_KEY_CHECK_DBVERSION );
20182046 int seq = dbutils_settings_get_int_value (db , CLOUDSYNC_KEY_CHECK_SEQ );
2019- cloudsync_pk_decode_bind_context xdata = {.vm = vm , .dbversion = dbversion , .seq = seq , .tmp_dbversion = 0 };
2047+ cloudsync_pk_decode_bind_context decoded_context = {.vm = vm };
2048+ void * payload_apply_xdata = NULL ;
2049+
20202050 for (uint32_t i = 0 ; i < nrows ; ++ i ) {
20212051 size_t seek = 0 ;
2022- pk_decode ((char * )buffer , blen , ncols , & seek , cloudsync_pk_decode_bind_callback , & xdata );
2052+ pk_decode ((char * )buffer , blen , ncols , & seek , cloudsync_pk_decode_bind_callback , & decoded_context );
20232053 // n is the pk_decode return value, I don't think I should assert here because in any case the next sqlite3_step would fail
20242054 // assert(n == ncols);
20252055
2026- rc = sqlite3_step (vm );
2027- if (rc != SQLITE_DONE ) break ;
2056+ bool approved = true;
2057+ if (payload_apply_callback ) approved = payload_apply_callback (& payload_apply_xdata , & decoded_context , db , data , CLOUDSYNC_PAYLOAD_APPLY_WILL_APPLY , SQLITE_OK );
2058+
2059+ if (approved ) {
2060+ rc = sqlite3_step (vm );
2061+ if (rc != SQLITE_DONE ) {
2062+ // don't "break;", the error can be due to a RLS policy.
2063+ // in case of error we try to apply the following changes
2064+ printf ("cloudsync_payload_apply error in step: (%d) %s\n" , rc , sqlite3_errmsg (db ));
2065+ }
2066+ }
2067+
2068+ if (payload_apply_callback ) payload_apply_callback (& payload_apply_xdata , & decoded_context , db , data , CLOUDSYNC_PAYLOAD_APPLY_DID_APPLY , rc );
20282069
20292070 buffer += seek ;
20302071 blen -= seek ;
20312072 stmt_reset (vm );
20322073 }
2033-
2074+
2075+ if (payload_apply_callback ) payload_apply_callback (& payload_apply_xdata , & decoded_context , db , data , CLOUDSYNC_PAYLOAD_APPLY_CLEANUP , rc );
2076+
20342077 if (rc == SQLITE_DONE ) rc = SQLITE_OK ;
20352078 if (rc == SQLITE_OK ) {
20362079 char buf [256 ];
2037- if (xdata . dbversion ! = dbversion ) {
2038- snprintf (buf , sizeof (buf ), "%lld" , xdata . dbversion );
2080+ if (decoded_context . db_version > = dbversion ) {
2081+ snprintf (buf , sizeof (buf ), "%lld" , decoded_context . db_version );
20392082 dbutils_settings_set_key_value (db , context , CLOUDSYNC_KEY_CHECK_DBVERSION , buf );
2040- }
2041- if (xdata .seq != seq ) {
2042- snprintf (buf , sizeof (buf ), "%lld" , xdata .seq );
2043- dbutils_settings_set_key_value (db , context , CLOUDSYNC_KEY_CHECK_SEQ , buf );
2083+
2084+ if (decoded_context .seq != seq ) {
2085+ snprintf (buf , sizeof (buf ), "%lld" , decoded_context .seq );
2086+ dbutils_settings_set_key_value (db , context , CLOUDSYNC_KEY_CHECK_SEQ , buf );
2087+ }
20442088 }
20452089 }
20462090
@@ -2061,6 +2105,30 @@ int cloudsync_payload_apply (sqlite3_context *context, const char *payload, int
20612105 return nrows ;
20622106}
20632107
2108+ void cloudsync_payload_apply_callback (cloudsync_payload_apply_callback_t callback ) {
2109+ payload_apply_callback = callback ;
2110+ }
2111+
2112+ sqlite3_stmt * cloudsync_col_value_stmt (sqlite3 * db , cloudsync_context * data , const char * tbl_name , bool * persistent ) {
2113+ sqlite3_stmt * vm ;
2114+
2115+ cloudsync_table_context * table = table_lookup (data , tbl_name , false);
2116+ char * col_name = NULL ;
2117+ if (table -> ncols > 0 ) {
2118+ col_name = table -> col_name [0 ];
2119+ // retrieve col_value precompiled statement
2120+ vm = table_column_lookup (table , col_name , false, NULL );
2121+ * persistent = true;
2122+ } else {
2123+ char * sql = table_build_value_sql (db , table , "*" );
2124+ sqlite3_prepare_v2 (db , sql , -1 , & vm , NULL );
2125+ cloudsync_memory_free (sql );
2126+ * persistent = false;
2127+ }
2128+
2129+ return vm ;
2130+ }
2131+
20642132void cloudsync_network_decode (sqlite3_context * context , int argc , sqlite3_value * * argv ) {
20652133 DEBUG_FUNCTION ("cloudsync_network_decode" );
20662134 //debug_values(argc, argv);
0 commit comments