LCOV - code coverage report
Current view: top level - src - dbutils.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.4 % 287 268
Test Date: 2026-10-21 16:35:02 Functions: 94.7 % 19 18

            Line data    Source code
       1              : //
       2              : //  dbutils.c
       3              : //  cloudsync
       4              : //
       5              : //  Created by Marco Bambini on 23/09/24.
       6              : //
       7              : 
       8              : #include <stdlib.h>
       9              : #include <inttypes.h>
      10              : 
      11              : #include "sql.h"
      12              : #include "utils.h"
      13              : #include "dbutils.h"
      14              : #include "cloudsync.h"
      15              : 
      16              : #if CLOUDSYNC_UNITTEST
      17              : char *OUT_OF_MEMORY_BUFFER = "OUT_OF_MEMORY_BUFFER";
      18              : #ifndef SQLITE_MAX_ALLOCATION_SIZE
      19              : #define SQLITE_MAX_ALLOCATION_SIZE  2147483391
      20              : #endif
      21              : #endif
      22              : 
      23              : // MARK: - Others -
      24              : 
      25              : // compares two SQLite values and returns an integer indicating the comparison result
      26        34933 : int dbutils_value_compare (dbvalue_t *lvalue, dbvalue_t *rvalue) {
      27        34933 :     if (lvalue == rvalue) return 0;
      28        34933 :     if (!lvalue) return -1;
      29        34933 :     if (!rvalue) return 1;
      30              :     
      31        34471 :     int l_type = (lvalue) ? database_value_type(lvalue) : DBTYPE_NULL;
      32        34471 :     int r_type = database_value_type(rvalue);
      33              :     
      34              :     // early exit if types differ, null is less than all types
      35        34471 :     if (l_type != r_type) return (r_type - l_type);
      36              :     
      37              :     // at this point lvalue and rvalue are of the same type
      38        34464 :     switch (l_type) {
      39              :         case DBTYPE_INTEGER: {
      40        10561 :             int64_t l_int = database_value_int(lvalue);
      41        10561 :             int64_t r_int = database_value_int(rvalue);
      42        10561 :             return (l_int < r_int) ? -1 : (l_int > r_int);
      43              :         } break;
      44              :             
      45              :         case DBTYPE_FLOAT: {
      46            4 :             double l_double = database_value_double(lvalue);
      47            4 :             double r_double = database_value_double(rvalue);
      48            4 :             return (l_double < r_double) ? -1 : (l_double > r_double);
      49              :         } break;
      50              :             
      51              :         case DBTYPE_NULL:
      52          634 :             break;
      53              :             
      54              :         case DBTYPE_TEXT: {
      55        23222 :             const char *l_text = database_value_text(lvalue);
      56        23222 :             const char *r_text = database_value_text(rvalue);
      57        23222 :             if (l_text == NULL && r_text == NULL) return 0;
      58        23222 :             if (l_text == NULL && r_text != NULL) return -1;
      59        23222 :             if (l_text != NULL && r_text == NULL) return 1;
      60        23222 :             return strcmp((const char *)l_text, (const char *)r_text);
      61              :         } break;
      62              :             
      63              :         case DBTYPE_BLOB: {
      64           43 :             const void *l_blob = database_value_blob(lvalue);
      65           43 :             const void *r_blob = database_value_blob(rvalue);
      66           43 :             if (l_blob == NULL && r_blob == NULL) return 0;
      67           43 :             if (l_blob == NULL && r_blob != NULL) return -1;
      68           43 :             if (l_blob != NULL && r_blob == NULL) return 1;
      69           43 :             int l_size = database_value_bytes(lvalue);
      70           43 :             int r_size = database_value_bytes(rvalue);
      71           43 :             int cmp = memcmp(l_blob, r_blob, (l_size < r_size) ? l_size : r_size);
      72           43 :             return (cmp != 0) ? cmp : (l_size - r_size);
      73              :         } break;
      74              :     }
      75              :     
      76          634 :     return 0;
      77        34933 : }
      78              : 
      79           28 : void dbutils_debug_value (dbvalue_t *value) {
      80           28 :     switch (database_value_type(value)) {
      81              :         case DBTYPE_INTEGER:
      82            7 :             printf("\t\tINTEGER: %" PRId64 "\n", database_value_int(value));
      83            7 :             break;
      84              :         case DBTYPE_FLOAT:
      85            7 :             printf("\t\tFLOAT: %f\n", database_value_double(value));
      86            7 :             break;
      87              :         case DBTYPE_TEXT:
      88            6 :             printf("\t\tTEXT: %s (%d)\n", database_value_text(value), database_value_bytes(value));
      89            6 :             break;
      90              :         case DBTYPE_BLOB:
      91            6 :             printf("\t\tBLOB: %p (%d)\n", (char *)database_value_blob(value), database_value_bytes(value));
      92            6 :             break;
      93              :         case DBTYPE_NULL:
      94            2 :             printf("\t\tNULL\n");
      95            2 :             break;
      96              :     }
      97           28 : }
      98              : 
      99           14 : void dbutils_debug_values (dbvalue_t **argv, int argc) {
     100           42 :     for (int i = 0; i < argc; i++) {
     101           28 :         dbutils_debug_value(argv[i]);
     102           28 :     }
     103           14 : }
     104              : 
     105              : // MARK: - Settings -
     106              : 
     107          878 : int dbutils_binary_comparison (int x, int y) {
     108          878 :     return (x == y) ? 0 : (x > y ? 1 : -1);
     109              : }
     110              : 
     111         6796 : int dbutils_settings_get_value (cloudsync_context *data, const char *key, char *buffer, size_t *blen, int64_t *intvalue) {
     112              :     DEBUG_SETTINGS("dbutils_settings_get_value key: %s", key);
     113              :     
     114              :     // if intvalue requested: buffer/blen optional
     115         6796 :     size_t buffer_len = 0;
     116         6796 :     if (intvalue) {
     117         5935 :         *intvalue = 0;
     118         5935 :     } else {
     119          861 :         if (!buffer || !blen || *blen == 0) return DBRES_MISUSE;
     120          861 :         buffer[0] = 0;
     121          861 :         buffer_len = *blen;
     122          861 :         *blen = 0;
     123              :     }
     124              :     
     125         6796 :     dbvm_t *vm = NULL;
     126         6796 :     int rc = databasevm_prepare(data, SQL_SETTINGS_GET_VALUE, (void **)&vm, 0);
     127         6796 :     if (rc != DBRES_OK) goto finalize_get_value;
     128              :     
     129         6796 :     rc = databasevm_bind_text(vm, 1, key, -1);
     130         6796 :     if (rc != DBRES_OK) goto finalize_get_value;
     131              :     
     132         6796 :     rc = databasevm_step(vm);
     133         6796 :     if (rc == DBRES_DONE) rc = DBRES_OK;
     134         3638 :     else if (rc != DBRES_ROW) goto finalize_get_value;
     135              :     
     136              :     // SQLITE_ROW case
     137         7657 :     if (rc == DBRES_ROW) {
     138         3638 :         rc = DBRES_OK;
     139              :         
     140              :         // NULL case
     141         3638 :         if (database_column_type(vm, 0) == DBTYPE_NULL) {
     142            0 :             goto finalize_get_value;
     143              :         }
     144              :         
     145              :         // INT case
     146         3638 :         if (intvalue) {
     147         2777 :             int type = database_column_type(vm, 0);
     148         2777 :             if (type == DBTYPE_TEXT) {
     149         2777 :                 const char *value = database_column_text(vm, 0);
     150         2777 :                 *intvalue = value ? strtoll(value, NULL, 10) : 0;
     151         2777 :             } else {
     152            0 :                 *intvalue = database_column_int(vm, 0);
     153              :             }
     154         2777 :             goto finalize_get_value;
     155              :         }
     156              :         
     157              :         // buffer case
     158          861 :         const char *value = database_column_text(vm, 0);
     159          861 :         size_t size = (size_t)database_column_bytes(vm, 0);
     160          861 :         if (!value || size == 0) goto finalize_get_value;
     161          861 :         if (size + 1 > buffer_len) {
     162            0 :             rc = DBRES_NOMEM;
     163            0 :         } else {
     164          861 :             memcpy(buffer, value, size);
     165          861 :             buffer[size] = '\0';
     166          861 :             *blen = size;
     167              :         }
     168          861 :     }
     169              :     
     170              : finalize_get_value:
     171         6796 :     if (rc != DBRES_OK) {
     172            0 :         DEBUG_ALWAYS("dbutils_settings_get_value error %s", database_errmsg(data));
     173            0 :     }
     174              :     
     175         6796 :     if (vm) databasevm_finalize(vm);
     176         6796 :     return rc;
     177         6796 : }
     178              : 
     179         1990 : int dbutils_settings_set_key_value (cloudsync_context *data, const char *key, const char *value) {
     180         1990 :     if (!key) return DBRES_MISUSE;
     181              :     DEBUG_SETTINGS("dbutils_settings_set_key_value key: %s value: %s", key, value);
     182              : 
     183         1990 :     int rc = DBRES_OK;
     184         1990 :     if (value) {
     185         1990 :         const char *values[] = {key, value};
     186         1990 :         DBTYPE types[] = {DBTYPE_TEXT, DBTYPE_TEXT};
     187         1990 :         int lens[] = {-1, -1};
     188         1990 :         rc = database_write(data, SQL_SETTINGS_SET_KEY_VALUE_REPLACE, values, types, lens, 2);
     189         1990 :     } else {
     190            0 :         const char *values[] = {key};
     191            0 :         DBTYPE types[] = {DBTYPE_TEXT};
     192            0 :         int lens[] = {-1};
     193            0 :         rc = database_write(data, SQL_SETTINGS_SET_KEY_VALUE_DELETE, values, types, lens, 1);
     194              :     }
     195              : 
     196         1990 :     if (rc == DBRES_OK && data) cloudsync_sync_key(data, key, value);
     197         1990 :     return rc;
     198         1990 : }
     199              : 
     200           55 : int dbutils_settings_get_int_value (cloudsync_context *data, const char *key) {
     201              :     DEBUG_SETTINGS("dbutils_settings_get_int_value key: %s", key);
     202           55 :     int64_t value = 0;
     203           55 :     if (dbutils_settings_get_value(data, key, NULL, NULL, &value) != DBRES_OK) return -1;
     204              :     
     205           55 :     return (int)value;
     206           55 : }
     207              : 
     208         5880 : int64_t dbutils_settings_get_int64_value (cloudsync_context *data, const char *key) {
     209              :     DEBUG_SETTINGS("dbutils_settings_get_int_value key: %s", key);
     210         5880 :     int64_t value = 0;
     211         5880 :     if (dbutils_settings_get_value(data, key, NULL, NULL, &value) != DBRES_OK) return -1;
     212              :     
     213         5880 :     return value;
     214         5880 : }
     215              : 
     216          861 : int dbutils_settings_check_version (cloudsync_context *data, const char *version) {
     217              :     DEBUG_SETTINGS("dbutils_settings_check_version");
     218              :     char buffer[256];
     219          861 :     size_t len = sizeof(buffer);
     220          861 :     if (dbutils_settings_get_value(data, CLOUDSYNC_KEY_LIBVERSION, buffer, &len, NULL) != DBRES_OK) return -666;
     221              :     
     222              :     int major1, minor1, patch1;
     223              :     int major2, minor2, patch2;
     224          861 :     int count1 = sscanf(buffer, "%d.%d.%d", &major1, &minor1, &patch1);
     225          861 :     int count2 = sscanf((version == NULL ? CLOUDSYNC_VERSION : version), "%d.%d.%d", &major2, &minor2, &patch2);
     226              :     
     227          861 :     if (count1 != 3 || count2 != 3) return -666;
     228              :     
     229          861 :     int res = 0;
     230          861 :     if ((res = dbutils_binary_comparison(major1, major2)) == 0) {
     231            6 :         if ((res = dbutils_binary_comparison(minor1, minor2)) == 0) {
     232            6 :             return dbutils_binary_comparison(patch1, patch2);
     233              :         }
     234            0 :     }
     235              :     
     236              :     DEBUG_SETTINGS(" %s %s (%d)", buffer, CLOUDSYNC_VERSION, res);
     237          855 :     return res;
     238          861 : }
     239              : 
     240         2548 : int dbutils_table_settings_get_value (cloudsync_context *data, const char *table, const char *column_name, const char *key, char *buffer, size_t blen) {
     241              :     DEBUG_SETTINGS("dbutils_table_settings_get_value table: %s column: %s key: %s", table, column_name, key);
     242              :         
     243         2548 :     if (!buffer || blen == 0) return DBRES_MISUSE;
     244         2548 :     buffer[0] = 0;
     245              :     
     246         2548 :     dbvm_t *vm = NULL;
     247         2548 :     int rc = databasevm_prepare(data, SQL_TABLE_SETTINGS_GET_VALUE, (void **)&vm, 0);
     248         2548 :     if (rc != DBRES_OK) goto finalize_get_value;
     249              :     
     250         2548 :     rc = databasevm_bind_text(vm, 1, table, -1);
     251         2548 :     if (rc != DBRES_OK) goto finalize_get_value;
     252              :     
     253         2548 :     rc = databasevm_bind_text(vm, 2, (column_name) ? column_name : "*", -1);
     254         2548 :     if (rc != DBRES_OK) goto finalize_get_value;
     255              :     
     256         2548 :     rc = databasevm_bind_text(vm, 3, key, -1);
     257         2548 :     if (rc != DBRES_OK) goto finalize_get_value;
     258              :     
     259         2548 :     rc = databasevm_step(vm);
     260         2548 :     if (rc == DBRES_DONE) rc = DBRES_OK;
     261           99 :     else if (rc != DBRES_ROW) goto finalize_get_value;
     262              :     
     263              :     // SQLITE_ROW case
     264         2647 :     if (rc == DBRES_ROW) {
     265           99 :         rc = DBRES_OK;
     266              : 
     267              :         // NULL case
     268           99 :         if (database_column_type(vm, 0) == DBTYPE_NULL) {
     269            0 :             goto finalize_get_value;
     270              :         }
     271              :     
     272           99 :         const char *value = database_column_text(vm, 0);
     273           99 :         size_t size = (size_t)database_column_bytes(vm, 0);
     274           99 :         if (size + 1 > blen) {
     275            0 :             rc = DBRES_NOMEM;
     276            0 :         } else {
     277           99 :             memcpy(buffer, value, size);
     278           99 :             buffer[size] = '\0';
     279              :         }
     280           99 :     }
     281              :     
     282              : finalize_get_value:   
     283         2548 :     if (rc != DBRES_OK) {
     284            0 :         DEBUG_ALWAYS("cloudsync_table_settings error %s", database_errmsg(data));
     285            0 :     }
     286         2548 :     if (vm) databasevm_finalize(vm); 
     287         2548 :     return rc;
     288         2548 : }
     289              : 
     290         1156 : int dbutils_table_settings_set_key_value (cloudsync_context *data, const char *table_name, const char *column_name, const char *key, const char *value) {
     291              :     DEBUG_SETTINGS("dbutils_table_settings_set_key_value table: %s column: %s key: %s", table_name, column_name, key);
     292              :     
     293         1156 :     int rc = DBRES_OK;
     294              :     
     295              :     // sanity check tbl_name
     296         1156 :     if (table_name == NULL) {
     297            0 :         return cloudsync_set_error(data, "cloudsync_set_table/set_column requires a non-null table parameter", DBRES_ERROR);
     298              :     }
     299              :     
     300              :     // sanity check column name
     301         1156 :     if (column_name == NULL) column_name = "*";
     302              :     
     303              :     // remove all table_name entries
     304         1156 :     if (key == NULL) {
     305            4 :         const char *values[] = {table_name};
     306            4 :         DBTYPE types[] = {DBTYPE_TEXT};
     307            4 :         int lens[] = {-1};
     308            4 :         rc = database_write(data, SQL_TABLE_SETTINGS_DELETE_ALL_FOR_TABLE, values, types, lens, 1);
     309            4 :         return rc;
     310              :     }
     311              :     
     312         1152 :     if (key && value) {
     313         1148 :         const char *values[] = {table_name, column_name, key, value};
     314         1148 :         DBTYPE types[] = {DBTYPE_TEXT, DBTYPE_TEXT, DBTYPE_TEXT, DBTYPE_TEXT};
     315         1148 :         int lens[] = {-1, -1, -1, -1};
     316         1148 :         rc = database_write(data, SQL_TABLE_SETTINGS_REPLACE, values, types, lens, 4);
     317         1148 :     }
     318              :     
     319         1152 :     if (value == NULL) {
     320            4 :         const char *values[] = {table_name, column_name, key};
     321            4 :         DBTYPE types[] = {DBTYPE_TEXT, DBTYPE_TEXT, DBTYPE_TEXT};
     322            4 :         int lens[] = {-1, -1, -1};
     323            4 :         rc = database_write(data, SQL_TABLE_SETTINGS_DELETE_ONE, values, types, lens, 3);
     324            4 :     }
     325              :     
     326              :     // unused in this version
     327              :     // cloudsync_context *data = (context) ? (cloudsync_context *)sqlite3_user_data(context) : NULL;
     328              :     // if (rc == DBRES_OK && data) cloudsync_sync_table_key(data, table, column, key, value);
     329         1152 :     return rc;
     330         1156 : }
     331              : 
     332         3223 : int64_t dbutils_table_settings_count_tables (cloudsync_context *data) {
     333              :     DEBUG_SETTINGS("dbutils_table_settings_count_tables");
     334              :     
     335         3223 :     int64_t count = 0;
     336         3223 :     int rc = database_select_int(data, SQL_TABLE_SETTINGS_COUNT_TABLES, &count);
     337         3223 :     return (rc == DBRES_OK) ? count : 0;
     338              : }
     339              : 
     340          868 : table_algo dbutils_table_settings_get_algo (cloudsync_context *data, const char *table_name) {
     341              :     DEBUG_SETTINGS("dbutils_table_settings_get_algo %s", table_name);
     342              :     
     343              :     char buffer[512];
     344          868 :     int rc = dbutils_table_settings_get_value(data, table_name, "*", "algo", buffer, sizeof(buffer));
     345          868 :     return (rc == DBRES_OK) ? cloudsync_algo_from_name(buffer) : table_algo_none;
     346              : }
     347              : 
     348         1540 : int dbutils_settings_load_callback (void *xdata, int ncols, char **values, char **names) {
     349         1540 :     cloudsync_context *data = (cloudsync_context *)xdata;
     350              : 
     351         3080 :     for (int i=0; i+1<ncols; i+=2) {
     352         1540 :         const char *key = values[i];
     353         1540 :         const char *value = values[i+1];
     354         1540 :         cloudsync_sync_key(data, key, value);
     355              :         DEBUG_SETTINGS("key: %s value: %s", key, value);
     356         1540 :     }
     357              : 
     358         1540 :     return 0;
     359              : }
     360              : 
     361           16 : int dbutils_settings_table_load_callback (void *xdata, int ncols, char **values, char **names) {
     362           16 :     cloudsync_context *data = (cloudsync_context *)xdata;
     363              : 
     364           32 :     for (int i=0; i+3<ncols; i+=4) {
     365           16 :         const char *table_name = values[i];
     366           16 :         const char *col_name = values[i+1];
     367           16 :         const char *key = values[i+2];
     368           16 :         const char *value = values[i+3];
     369              : 
     370              :         // Table-level algo setting (col_name == "*")
     371           16 :         if (strcmp(key, "algo") == 0 && col_name && strcmp(col_name, "*") == 0) {
     372              :             // Skip stale settings for tables that no longer exist
     373           12 :             if (!database_table_exists(data, table_name, cloudsync_schema(data))) {
     374              :                 DEBUG_SETTINGS("skipping stale settings for dropped table: %s", table_name);
     375            2 :                 continue;
     376              :             }
     377           10 :             table_algo algo = cloudsync_algo_from_name(value);
     378              :             char fbuf[2048];
     379           10 :             int frc = dbutils_table_settings_get_value(data, table_name, "*", "filter", fbuf, sizeof(fbuf));
     380           10 :             const char *filt = (frc == DBRES_OK && fbuf[0]) ? fbuf : NULL;
     381           10 :             if (database_create_triggers(data, table_name, algo, filt) != DBRES_OK) return DBRES_MISUSE;
     382           10 :             if (table_add_to_context(data, algo, table_name) == false) return DBRES_MISUSE;
     383              :             DEBUG_SETTINGS("load tbl_name: %s value: %s", key, value);
     384           10 :             continue;
     385              :         }
     386              : 
     387              :         // Column-level algo=block setting (col_name != "*")
     388            7 :         if (strcmp(key, "algo") == 0 && value && strcmp(value, "block") == 0 &&
     389            3 :             col_name && strcmp(col_name, "*") != 0) {
     390              :             // Read optional delimiter
     391              :             char dbuf[256];
     392            3 :             int drc = dbutils_table_settings_get_value(data, table_name, col_name, "delimiter", dbuf, sizeof(dbuf));
     393            3 :             const char *delim = (drc == DBRES_OK && dbuf[0]) ? dbuf : NULL;
     394            3 :             cloudsync_setup_block_column(data, table_name, col_name, delim, false);
     395              :             DEBUG_SETTINGS("load block column: %s.%s delimiter: %s", table_name, col_name, delim ? delim : "(default)");
     396            3 :             continue;
     397              :         }
     398            1 :     }
     399              : 
     400           16 :     return 0;
     401           16 : }
     402              : 
     403            0 : bool dbutils_settings_migrate (cloudsync_context *data) {
     404              :     // dbutils_settings_check_version comparison failed
     405              :     // so check for logic migration here (if necessary)
     406            0 :     return true;
     407              : }
     408              : 
     409          769 : int dbutils_settings_load (cloudsync_context *data) {
     410              :     DEBUG_SETTINGS("dbutils_settings_load %p", data);
     411              :     
     412              :     // load global settings
     413          769 :     const char *sql = SQL_SETTINGS_LOAD_GLOBAL;
     414          769 :     int rc = database_exec_callback(data, sql, dbutils_settings_load_callback, data);
     415          769 :     if (rc != DBRES_OK) DEBUG_ALWAYS("cloudsync_load_settings error: %s", database_errmsg(data));
     416              :     
     417              :     // load table-specific settings
     418          769 :     sql = SQL_SETTINGS_LOAD_TABLE;
     419          769 :     rc = database_exec_callback(data, sql, dbutils_settings_table_load_callback, data);
     420          769 :     if (rc != DBRES_OK) DEBUG_ALWAYS("cloudsync_load_settings error: %s", database_errmsg(data));
     421              :     
     422          769 :     return DBRES_OK;
     423              : }
     424              : 
     425          769 : int dbutils_settings_init (cloudsync_context *data) {
     426              :     DEBUG_SETTINGS("dbutils_settings_init %p", data);
     427              :         
     428              :     // check if cloudsync_settings table exists
     429          769 :     int rc = DBRES_OK;
     430          769 :     bool settings_exists = database_internal_table_exists(data, CLOUDSYNC_SETTINGS_NAME);
     431          769 :     if (settings_exists == false) {
     432              :         DEBUG_SETTINGS("cloudsync_settings does not exist (creating a new one)");
     433              :         
     434              :         // create table and fill-in initial data
     435          757 :         rc = database_exec(data, SQL_CREATE_SETTINGS_TABLE);
     436          757 :         if (rc != DBRES_OK) return rc;
     437              :         
     438              :         // library version
     439          757 :         char *sql = cloudsync_memory_mprintf(SQL_INSERT_SETTINGS_STR_FORMAT, CLOUDSYNC_KEY_LIBVERSION, CLOUDSYNC_VERSION);
     440          757 :         if (!sql) return DBRES_NOMEM;
     441          757 :         rc = database_exec(data, sql);
     442          757 :         cloudsync_memory_free(sql);
     443          757 :         if (rc != DBRES_OK) return rc;
     444              : 
     445              :         // schema version
     446              :         char sql_int[1024];
     447          757 :         snprintf(sql_int, sizeof(sql_int), SQL_INSERT_SETTINGS_INT_FORMAT, CLOUDSYNC_KEY_SCHEMAVERSION, (long long)database_schema_version(data));
     448          757 :         rc = database_exec(data, sql_int);
     449          757 :         if (rc != DBRES_OK) return rc;
     450          757 :     }
     451              :     
     452          769 :     if (database_internal_table_exists(data, CLOUDSYNC_SITEID_NAME) == false) {
     453              :         DEBUG_SETTINGS("cloudsync_site_id does not exist (creating a new one)");
     454              :         
     455              :         // create table and fill-in initial data
     456              :         // site_id is implicitly indexed
     457              :         // the rowid column is the primary key
     458          757 :         rc = database_exec(data, SQL_CREATE_SITE_ID_TABLE);
     459          757 :         if (rc != DBRES_OK) return rc;
     460              :         
     461              :         // siteid (to uniquely identify this local copy of the database)
     462              :         uint8_t site_id[UUID_LEN];
     463          757 :         if (cloudsync_uuid_v7(site_id) == -1) return DBRES_ERROR;
     464              :         
     465              :         // rowid 0 means local site_id
     466          757 :         const char *values[] = {"0", (const char *)&site_id};
     467          757 :         DBTYPE types[] = {DBTYPE_INTEGER, DBTYPE_BLOB};
     468          757 :         int lens[] = {-1, UUID_LEN};
     469          757 :         rc = database_write(data, SQL_INSERT_SITE_ID_ROWID, values, types, lens, 2);
     470          757 :         if (rc != DBRES_OK) return rc;
     471          757 :     }
     472              :     
     473              :     // check if cloudsync_table_settings table exists
     474          769 :     if (database_internal_table_exists(data, CLOUDSYNC_TABLE_SETTINGS_NAME) == false) {
     475              :         DEBUG_SETTINGS("cloudsync_table_settings does not exist (creating a new one)");
     476              :         
     477          757 :         rc = database_exec(data, SQL_CREATE_TABLE_SETTINGS_TABLE);
     478          757 :         if (rc != DBRES_OK) return rc;
     479          757 :     }
     480              :     
     481              :     // check if cloudsync_settings table exists
     482          769 :     bool schema_versions_exists = database_internal_table_exists(data, CLOUDSYNC_SCHEMA_VERSIONS_NAME);
     483          769 :     if (schema_versions_exists == false) {
     484              :         DEBUG_SETTINGS("cloudsync_schema_versions does not exist (creating a new one)");
     485              : 
     486              :         // create table
     487          757 :         rc = database_exec(data, SQL_CREATE_SCHEMA_VERSIONS_TABLE);
     488          757 :         if (rc != DBRES_OK) return rc;
     489          757 :     }
     490              : 
     491              :     // check if cloudsync_payload_fragments table exists
     492              :     // created at init time because the apply path runs under sync-only
     493              :     // credentials that lack DDL rights on server nodes
     494          769 :     if (database_internal_table_exists(data, CLOUDSYNC_PAYLOAD_FRAGMENTS_NAME) == false) {
     495              :         DEBUG_SETTINGS("cloudsync_payload_fragments does not exist (creating a new one)");
     496              : 
     497          757 :         rc = database_exec(data, SQL_PAYLOAD_FRAGMENTS_CREATE_TABLE);
     498          757 :         if (rc != DBRES_OK) return rc;
     499          757 :     }
     500              : 
     501              :     // cloudsync_settings table exists so load it
     502          769 :     dbutils_settings_load(data);
     503              :     
     504              :     // check if some process changed schema outside of the lib
     505              :     /*
     506              :     if ((settings_exists == true) && (data->schema_version != database_schema_version(data))) {
     507              :         // SOMEONE CHANGED SCHEMAs SO WE NEED TO RECHECK AUGMENTED TABLES and RELATED TRIGGERS
     508              :         assert(0);
     509              :     }
     510              :      */
     511              :     
     512          769 :     return DBRES_OK;
     513          769 : }
     514              : 
     515            2 : int dbutils_settings_cleanup (cloudsync_context *data) {
     516            2 :     return database_exec(data, SQL_SETTINGS_CLEANUP_DROP_ALL);
     517              : }
        

Generated by: LCOV version 2.5-0