From 5dddc165f5c238ff77b2af4e540315b2a86a9a3a Mon Sep 17 00:00:00 2001
From: "pavel.uhanov" <pavel.uhanov@demlabs.net>
Date: Thu, 11 Jul 2024 12:35:56 +0000
Subject: [PATCH] hotfix-12350

---
 global-db/dap_global_db_driver_sqlite.c | 210 ++++++++++++++----------
 global-db/test/dap_global_db_test.c     |  14 +-
 2 files changed, 132 insertions(+), 92 deletions(-)

diff --git a/global-db/dap_global_db_driver_sqlite.c b/global-db/dap_global_db_driver_sqlite.c
index 20c8ffdf9..54116a9bb 100644
--- a/global-db/dap_global_db_driver_sqlite.c
+++ b/global-db/dap_global_db_driver_sqlite.c
@@ -57,6 +57,8 @@ extern int g_dap_global_db_debug_more;                         /* Enable extensi
 
 static char s_filename_db [MAX_PATH];
 
+static const char s_attempts_count = 7;
+static const int s_sleep_period = 500 * 1000;  /* Wait 0.5 sec */;
 static bool s_db_inited = false;
 static dap_list_t *s_conn_list = NULL;  // list of all connections
 static _Thread_local conn_list_item_t *s_conn = NULL;  // local connection
@@ -76,7 +78,7 @@ sqlite3* s_db_sqlite_open(const char *a_filename_utf8, int a_flags, char **a_err
     int l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags, NULL); // SQLITE_OPEN_FULLMUTEX by default set with sqlite3_config SERIALIZED
     // if unable to open the database file
     if(l_rc == SQLITE_CANTOPEN) {
-        log_it(L_WARNING,"No database on path %s, creating one from scratch", a_filename_utf8);
+        log_it(L_DEBUG,"No database on path %s, creating one from scratch", a_filename_utf8);
         if(l_db)
             sqlite3_close(l_db);
         // try to create database
@@ -127,24 +129,72 @@ static void s_db_sqlite_clean(conn_list_item_t *a_conn, size_t a_count, ... ) {
 /**
  * @brief One step to sqlite3_stmt with 7 try is sql bust
  * @param a_stmt sqlite3_stmt to step
+ * @param a_error_msg module name
  * @return result code
  */
-static int s_db_sqlite_step(sqlite3_stmt *a_stmt)
+static int s_db_sqlite_step(sqlite3_stmt *a_stmt, const char *a_error_msg)
 {
     dap_return_val_if_pass(!a_stmt, SQLITE_ERROR);
     int l_ret = 0;
-    for ( int i = 7; i--; ) {
+    for ( char i = s_attempts_count; i--; ) {
         l_ret = sqlite3_step(a_stmt);
-        if (l_ret != SQLITE_BUSY)
+        if (l_ret != SQLITE_BUSY && l_ret != SQLITE_LOCKED)
             break;
-        dap_usleep(500 * 1000);  /* Wait 0.5 sec */
+        dap_usleep(s_sleep_period);
     }
+    debug_if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE, L_DEBUG, "SQLite step in %s error %d(%s)", a_error_msg ? a_error_msg : "", l_ret, sqlite3_errstr(l_ret));
+    return l_ret;
+}
+
+/**
+ * @brief One step to sqlite3_stmt with 7 try is sql bust
+ * @param a_db a pointer to an instance of SQLite connection
+ * @param a_str_query SQL query string
+ * @param a_stmt pointer to generate sqlite3_stmt
+ * @param a_error_msg module name
+ * @return result code
+ */
+static int s_db_sqlite_prepare(sqlite3 *a_db, const char *a_str_query, sqlite3_stmt **a_stmt, const char *a_error_msg)
+{
+    dap_return_val_if_pass(!a_stmt || !a_str_query || !a_stmt, SQLITE_ERROR);
+    int l_ret = 0;
+    for (char i = s_attempts_count; i--; ) {
+        l_ret = sqlite3_prepare_v2(a_db, a_str_query, -1, a_stmt, NULL);
+        if (l_ret != SQLITE_BUSY && l_ret != SQLITE_LOCKED)
+            break;
+        dap_usleep(s_sleep_period);
+    }
+    debug_if(l_ret != SQLITE_OK, L_DEBUG, "SQLite prepare %s error %d(%s)", a_error_msg ? a_error_msg : "", sqlite3_errcode(a_db), sqlite3_errmsg(a_db));
+    return l_ret;
+}
+
+/**
+ * @brief One step to sqlite3_stmt with 7 try is sql bust
+ * @param a_stmt sqlite3_stmt to step
+ * @param a_pos blob element position in query
+ * @param a_data blob data
+ * @param a_data_size blob data size
+ * @param a_destructor SQL destructor type
+ * @param a_error_msg module name
+ * @return result code
+ */
+static int s_db_sqlite_bind_blob64(sqlite3_stmt *a_stmt, int a_pos, const void *a_data, sqlite3_uint64 a_data_size, sqlite3_destructor_type a_destructor, const char *a_error_msg)
+{
+    dap_return_val_if_pass(!a_stmt || !a_data || !a_data_size || a_pos < 0, SQLITE_ERROR);
+    int l_ret = 0;
+    for ( char i = s_attempts_count; i--; ) {
+        l_ret = sqlite3_bind_blob64(a_stmt, a_pos, a_data, a_data_size, a_destructor);
+        if (l_ret != SQLITE_BUSY && l_ret != SQLITE_LOCKED)
+            break;
+        dap_usleep(s_sleep_period);
+    }
+    debug_if(l_ret != SQLITE_OK, L_DEBUG, "SQLite bind blob64 %s error %d(%s)", a_error_msg ? a_error_msg : "", l_ret, sqlite3_errstr(l_ret));
     return l_ret;
 }
 
 /**
  * @brief Executes SQL statements.
- * @param a_conn a pointer to an instance of SQLite connection
+ * @param a_db a pointer to an instance of SQLite connection
  * @param a_query the SQL statement
  * @param a_hash pointer to data hash
  * @param a_value pointer to data
@@ -152,48 +202,28 @@ static int s_db_sqlite_step(sqlite3_stmt *a_stmt)
  * @param a_sign record sign
  * @return result code.
  */
-static int s_db_sqlite_exec(sqlite3 *a_conn, const char *a_query, dap_global_db_driver_hash_t *a_hash, byte_t *a_value, size_t a_value_len, dap_sign_t *a_sign)
+static int s_db_sqlite_exec(sqlite3 *a_db, const char *a_query, dap_global_db_driver_hash_t *a_hash, byte_t *a_value, size_t a_value_len, dap_sign_t *a_sign)
 {
+    dap_return_val_if_pass(!a_db || !a_query, SQLITE_ERROR);
     int l_ret = 0;
     sqlite3_stmt *l_stmt = NULL;
     if (
-        (l_ret = sqlite3_prepare_v2(a_conn, a_query, -1, &l_stmt, NULL)) != SQLITE_OK ||
-        (a_hash && (l_ret = sqlite3_bind_blob64(l_stmt, 1, a_hash, sizeof(*a_hash), SQLITE_STATIC)) != SQLITE_OK) ||
-        (a_value && (l_ret = sqlite3_bind_blob64(l_stmt, 2, a_value, a_value_len, SQLITE_STATIC)) != SQLITE_OK) ||
-        (a_sign && (l_ret = sqlite3_bind_blob64(l_stmt, 3, a_sign, dap_sign_get_size(a_sign), SQLITE_STATIC)) != SQLITE_OK)
+        (l_ret = s_db_sqlite_prepare(a_db, a_query, &l_stmt, a_query)) != SQLITE_OK ||
+        (a_hash && (l_ret = s_db_sqlite_bind_blob64(l_stmt, 1, a_hash, sizeof(*a_hash), SQLITE_STATIC, a_query)) != SQLITE_OK) ||
+        (a_value && (l_ret = s_db_sqlite_bind_blob64(l_stmt, 2, a_value, a_value_len, SQLITE_STATIC, a_query)) != SQLITE_OK) ||
+        (a_sign && (l_ret = s_db_sqlite_bind_blob64(l_stmt, 3, a_sign, dap_sign_get_size(a_sign), SQLITE_STATIC, a_query)) != SQLITE_OK)
         ) {
-        log_it(L_ERROR, "SQL error execute query %s %d(%s)", a_query, sqlite3_errcode(a_conn), sqlite3_errmsg(a_conn));
+        sqlite3_finalize(l_stmt);
         return l_ret;
     }
-    l_ret = s_db_sqlite_step(l_stmt);
+    l_ret = s_db_sqlite_step(l_stmt, a_query);
     sqlite3_finalize(l_stmt);
     if (l_ret != SQLITE_DONE && l_ret != SQLITE_ROW) {
-        log_it(L_ERROR, "SQL error %d(%s)", sqlite3_errcode(a_conn), sqlite3_errmsg(a_conn));
         return l_ret;
     }
     return SQLITE_OK;
 }
 
-/**
- * @brief Connection configuration
- * @param a_conn connection
- */
-static inline void s_db_sqlite_prepare_connection(sqlite3 *a_conn)
-{
-// sanity check
-    dap_return_if_pass(!a_conn);
-// func work
-    if((s_db_sqlite_exec(a_conn, "PRAGMA synchronous = NORMAL", NULL, NULL, 0, NULL)))
-        log_it(L_ERROR, "can't set new synchronous mode\n");
-    if(s_db_sqlite_exec(a_conn, "PRAGMA journal_mode = OFF", NULL, NULL, 0, NULL))
-        log_it(L_ERROR, "can't set new journal mode\n");
-    if(s_db_sqlite_exec(a_conn, "PRAGMA page_size = 4096", NULL, NULL, 0, NULL))
-        log_it(L_ERROR, "can't set page_size\n");
-// vacuum need?
-    // if(s_db_sqlite_exec(a_conn, "PRAGMA auto_vacuum = INCREMENTAL", NULL, NULL, 0, NULL))
-    //     log_it(L_ERROR, "can't set autovacuum mode\n");
-}
-
 /**
  * @brief Prepare connection item
  * @param a_trans outstanding transaction flag
@@ -221,7 +251,6 @@ static conn_list_item_t *s_db_sqlite_get_connection(bool a_trans)
             pthread_rwlock_unlock(&s_conn_list_rwlock);
             return NULL;
         }
-        s_db_sqlite_prepare_connection(s_conn->conn);
         s_conn->idx = l_conn_idx++;
         log_it(L_DEBUG, "SQL connection #%d is created @%p", s_conn->idx, s_conn);
         s_conn_list = dap_list_append(s_conn_list, s_conn);
@@ -349,7 +378,7 @@ static int s_db_sqlite_fill_one_item(const char *a_group, dap_store_obj_t *a_obj
 // sanity check
     dap_return_val_if_pass(!a_group || !a_obj || !a_stmt, SQLITE_ERROR);
 // preparing
-    int l_ret = s_db_sqlite_step(a_stmt);
+    int l_ret = s_db_sqlite_step(a_stmt, "fill one item");
     if(l_ret != SQLITE_ROW)
         goto clean_and_ret;
     a_obj->group = dap_strdup(a_group);
@@ -409,8 +438,7 @@ static dap_store_obj_t* s_db_sqlite_read_last_store_obj(const char *a_group, boo
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK) {
-        log_it(L_ERROR, "SQLite last read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, "last read")!= SQLITE_OK) {
         goto clean_and_ret;
     }
 // memory alloc
@@ -446,6 +474,7 @@ static dap_global_db_pkt_pack_t *s_db_sqlite_get_by_hash(const char *a_group, da
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !a_hashes || !a_count || !(l_conn = s_db_sqlite_get_connection(false)), NULL);
 // preparing
+    const char *l_error_msg = "get by hash";
     dap_global_db_pkt_pack_t *l_ret = NULL;
     sqlite3_stmt *l_stmt_count = NULL, *l_stmt = NULL, *l_stmt_size = NULL;
     char *l_blob_str = DAP_NEW_Z_SIZE(char, a_count * 2);
@@ -474,24 +503,21 @@ static dap_global_db_pkt_pack_t *s_db_sqlite_get_by_hash(const char *a_group, da
         log_it(L_ERROR, "Error in SQL request forming");
         goto clean_and_ret;
     }
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_prepare_v2(l_conn->conn, l_str_query_size, -1, &l_stmt_size, NULL)!= SQLITE_OK ||
-        sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_prepare(l_conn->conn, l_str_query_size, &l_stmt_size, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, l_error_msg)!= SQLITE_OK)
     {
-        log_it(L_ERROR, "SQLite get by hash error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
     for (size_t i = 1; i <= a_count; ++i) {
-        if( sqlite3_bind_blob64(l_stmt_count, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC) != SQLITE_OK ||
-            sqlite3_bind_blob64(l_stmt_size, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC) != SQLITE_OK ||
-            sqlite3_bind_blob64(l_stmt, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC) != SQLITE_OK)
+        if( s_db_sqlite_bind_blob64(l_stmt_count, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+            s_db_sqlite_bind_blob64(l_stmt_size, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+            s_db_sqlite_bind_blob64(l_stmt, i, a_hashes + i - 1, sizeof(*a_hashes), SQLITE_STATIC, l_error_msg) != SQLITE_OK)
         {
-            log_it(L_ERROR, "SQLite get by hash error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
             goto clean_and_ret;
         }
     }
-    if (s_db_sqlite_step(l_stmt_count) != SQLITE_ROW || s_db_sqlite_step(l_stmt_size) != SQLITE_ROW) {
-        log_it(L_ERROR, "SQLite get by hash error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
+    if (s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW || s_db_sqlite_step(l_stmt_size, l_error_msg) != SQLITE_ROW) {
         goto clean_and_ret;
     }
 // memory alloc
@@ -505,7 +531,7 @@ static dap_global_db_pkt_pack_t *s_db_sqlite_get_by_hash(const char *a_group, da
     size_t l_data_size = l_count * (sizeof(dap_global_db_pkt_t) + l_group_name_len + 1) + l_size;
     DAP_NEW_Z_SIZE_RET_VAL(l_ret, dap_global_db_pkt_pack_t, sizeof(dap_global_db_pkt_pack_t) + l_data_size, NULL, l_str_query_count, l_str_query);
 // data forming
-    for (size_t i = 0; i < l_count && l_ret->data_size < l_data_size && s_db_sqlite_step(l_stmt) == SQLITE_ROW; ++i) {
+    for (size_t i = 0; i < l_count && l_ret->data_size < l_data_size && s_db_sqlite_step(l_stmt, l_error_msg) == SQLITE_ROW; ++i) {
         dap_global_db_pkt_t *l_cur_pkt = (dap_global_db_pkt_t *)(l_ret->data + l_ret->data_size);
         size_t l_count_col = sqlite3_column_count(l_stmt);
         l_cur_pkt->group_len = l_group_name_len;
@@ -576,6 +602,7 @@ static dap_global_db_hash_pkt_t *s_db_sqlite_read_hashes(const char *a_group, da
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), NULL);
 // preparing
+    const char *l_error_msg = "hashes read";
     dap_global_db_hash_pkt_t *l_ret = NULL;
     sqlite3_stmt *l_stmt_count = NULL, *l_stmt = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -592,13 +619,12 @@ static dap_global_db_hash_pkt_t *s_db_sqlite_read_hashes(const char *a_group, da
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC) != SQLITE_OK ||
-        sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC) != SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite hashes read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
 // memory alloc
@@ -619,7 +645,7 @@ static dap_global_db_hash_pkt_t *s_db_sqlite_read_hashes(const char *a_group, da
     byte_t *l_curr_point = l_ret->group_n_hashses + l_ret->group_name_len;
     memcpy(l_ret->group_n_hashses, a_group, l_group_name_len);
     int l_count_col = sqlite3_column_count(l_stmt);
-    for(;l_count_out < l_count && s_db_sqlite_step(l_stmt) == SQLITE_ROW && sqlite3_column_type(l_stmt, 0) == SQLITE_BLOB; ++l_count_out) {
+    for(;l_count_out < l_count && s_db_sqlite_step(l_stmt, l_error_msg) == SQLITE_ROW && sqlite3_column_type(l_stmt, 0) == SQLITE_BLOB; ++l_count_out) {
         byte_t *l_current_hash = (byte_t*) sqlite3_column_blob(l_stmt, 0);
         memcpy(l_curr_point, l_current_hash, sizeof(dap_global_db_driver_hash_t));
         l_curr_point += sizeof(dap_global_db_driver_hash_t);
@@ -645,6 +671,7 @@ static dap_store_obj_t* s_db_sqlite_read_cond_store_obj(const char *a_group, dap
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), NULL);
 // preparing
+    const char *l_error_msg = "conditional read";
     dap_store_obj_t *l_ret = NULL;
     sqlite3_stmt *l_stmt_count = NULL, *l_stmt = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -664,13 +691,12 @@ static dap_store_obj_t* s_db_sqlite_read_cond_store_obj(const char *a_group, dap
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC) != SQLITE_OK ||
-        sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC) != SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite conditional read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
 // memory alloc
@@ -714,6 +740,7 @@ static dap_store_obj_t* s_db_sqlite_read_store_obj(const char *a_group, const ch
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), NULL);
 // func work
+    const char *l_error_msg = "read";
     dap_store_obj_t *l_ret = NULL;
     sqlite3_stmt *l_stmt_count = NULL, *l_stmt = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -735,11 +762,10 @@ static dap_store_obj_t* s_db_sqlite_read_store_obj(const char *a_group, const ch
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
 // memory alloc
@@ -777,6 +803,7 @@ static dap_list_t *s_db_sqlite_get_groups_by_mask(const char *a_group_mask)
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group_mask || !(l_conn = s_db_sqlite_get_connection(false)), NULL);
 // preparing
+    const char *l_error_msg = "get groups";
     dap_list_t* l_ret = NULL;
     sqlite3_stmt *l_stmt = NULL;
     char *l_mask = NULL;
@@ -786,13 +813,12 @@ static dap_list_t *s_db_sqlite_get_groups_by_mask(const char *a_group_mask)
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query, -1, &l_stmt, NULL)!= SQLITE_OK) {
-        log_it(L_ERROR, "SQLite get groups error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query, &l_stmt, l_error_msg)!= SQLITE_OK) {
         goto clean_and_ret;
     }
     l_mask = dap_str_replace_char(a_group_mask, '.', '_');
     int l_ret_code = 0;
-    for (l_ret_code = s_db_sqlite_step(l_stmt); l_ret_code == SQLITE_ROW && sqlite3_column_type(l_stmt, 0) == SQLITE_TEXT; l_ret_code = s_db_sqlite_step(l_stmt)) {
+    for (l_ret_code = s_db_sqlite_step(l_stmt, l_error_msg); l_ret_code == SQLITE_ROW && sqlite3_column_type(l_stmt, 0) == SQLITE_TEXT; l_ret_code = s_db_sqlite_step(l_stmt, l_error_msg)) {
         const char *l_table_name = (const char *)sqlite3_column_text(l_stmt, 0);
         if (dap_global_db_group_match_mask(l_table_name, l_mask))
             l_ret = dap_list_prepend(l_ret, dap_str_replace_char(l_table_name, '_', '.'));
@@ -819,6 +845,7 @@ static size_t s_db_sqlite_read_count_store(const char *a_group, dap_global_db_dr
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), 0);
 // preparing
+    const char *l_error_msg = "count read";
     size_t l_ret = 0;
     sqlite3_stmt *l_stmt_count = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -832,11 +859,10 @@ static size_t s_db_sqlite_read_count_store(const char *a_group, dap_global_db_dr
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC) != SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt_count, 1, &a_hash_from, sizeof(a_hash_from), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite count read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
     l_ret = sqlite3_column_int64(l_stmt_count, 0);
@@ -857,6 +883,7 @@ static bool s_db_sqlite_is_hash(const char *a_group, dap_global_db_driver_hash_t
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), false);
 // preparing
+    const char *l_error_msg = "is hash read";
     bool l_ret = false;
     sqlite3_stmt *l_stmt_count = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -869,11 +896,10 @@ static bool s_db_sqlite_is_hash(const char *a_group, dap_global_db_driver_hash_t
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        sqlite3_bind_blob64(l_stmt_count, 1, &a_hash, sizeof(a_hash), SQLITE_STATIC) != SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_bind_blob64(l_stmt_count, 1, &a_hash, sizeof(a_hash), SQLITE_STATIC, l_error_msg) != SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite is hash read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
     l_ret = (bool)sqlite3_column_int64(l_stmt_count, 0);
@@ -894,6 +920,7 @@ static bool s_db_sqlite_is_obj(const char *a_group, const char *a_key)
     conn_list_item_t *l_conn = NULL;
     dap_return_val_if_pass(!a_group || !(l_conn = s_db_sqlite_get_connection(false)), false);
 // preparing
+    const char *l_error_msg = "is obj read";
     bool l_ret = false;
     sqlite3_stmt *l_stmt_count = NULL;
     char *l_table_name = dap_str_replace_char(a_group, '.', '_');
@@ -906,10 +933,9 @@ static bool s_db_sqlite_is_obj(const char *a_group, const char *a_key)
         goto clean_and_ret;
     }
     
-    if(sqlite3_prepare_v2(l_conn->conn, l_str_query_count, -1, &l_stmt_count, NULL)!= SQLITE_OK ||
-        s_db_sqlite_step(l_stmt_count) != SQLITE_ROW)
+    if(s_db_sqlite_prepare(l_conn->conn, l_str_query_count, &l_stmt_count, l_error_msg)!= SQLITE_OK ||
+        s_db_sqlite_step(l_stmt_count, l_error_msg) != SQLITE_ROW)
     {
-        log_it(L_ERROR, "SQLite is obj read error %d(%s)", sqlite3_errcode(l_conn->conn), sqlite3_errmsg(l_conn->conn));
         goto clean_and_ret;
     }
     l_ret = (bool)sqlite3_column_int64(l_stmt_count, 0);
@@ -941,7 +967,6 @@ static int s_db_sqlite_flush()
 #ifndef _WIN32
     sync();
 #endif
-    s_db_sqlite_prepare_connection(l_conn->conn);
     s_db_sqlite_free_connection(l_conn, false);
     s_db_sqlite_free_connection(l_conn, true);
     return 0;
@@ -1004,7 +1029,6 @@ int dap_global_db_driver_sqlite_init(const char *a_filename_db, dap_global_db_dr
     dap_return_val_if_pass_err(s_db_inited, -2, "SQLite driver already init")
 // func work
     int l_ret = -1, l_errno = errno;
-    sqlite3 *l_conn = NULL;
     char l_errbuf[255] = {0}, *l_error_message = NULL;
     if ( sqlite3_threadsafe() && !sqlite3_config(SQLITE_CONFIG_MULTITHREAD) )
         l_ret = sqlite3_initialize();
@@ -1033,9 +1057,7 @@ int dap_global_db_driver_sqlite_init(const char *a_filename_db, dap_global_db_dr
             log_it(L_NOTICE, "Directory created");
     }
     DAP_DEL_Z(l_filename_dir);
-    // *PRAGMA page_size = bytes; // page size DB; it is reasonable to make it equal to the size of the disk cluster 4096
-    // *PRAGMA cache_size = -kibibytes; // by default it is equal to 2000 pages of database
-    //
+
     a_drv_callback->apply_store_obj         = s_db_sqlite_apply_store_obj;
     a_drv_callback->read_store_obj          = s_db_sqlite_read_store_obj;
     a_drv_callback->read_cond_store_obj     = s_db_sqlite_read_cond_store_obj;
@@ -1051,5 +1073,23 @@ int dap_global_db_driver_sqlite_init(const char *a_filename_db, dap_global_db_dr
     a_drv_callback->read_hashes             = s_db_sqlite_read_hashes;
     a_drv_callback->is_hash                 = s_db_sqlite_is_hash;
     s_db_inited = true;
+
+    conn_list_item_t *l_conn = s_db_sqlite_get_connection(false);
+    if (!l_conn) {
+        log_it(L_ERROR, "Can't create base connection\n");
+        s_db_inited = false;
+        return -3;
+    }
+
+    if((s_db_sqlite_exec(l_conn->conn, "PRAGMA synchronous = NORMAL", NULL, NULL, 0, NULL)))
+        log_it(L_ERROR, "can't set new synchronous mode\n");
+    if(s_db_sqlite_exec(l_conn->conn, "PRAGMA journal_mode = OFF", NULL, NULL, 0, NULL))
+        log_it(L_ERROR, "can't set new journal mode\n");
+    if(s_db_sqlite_exec(l_conn->conn, "PRAGMA page_size = 4096", NULL, NULL, 0, NULL))
+        log_it(L_ERROR, "can't set page_size\n");
+    // vacuum need?
+    // if(s_db_sqlite_exec(l_conn, "PRAGMA auto_vacuum = INCREMENTAL", NULL, NULL, 0, NULL))
+    //     log_it(L_ERROR, "can't set autovacuum mode\n");
+    s_db_sqlite_free_connection(l_conn, false);
     return l_ret;
 }
diff --git a/global-db/test/dap_global_db_test.c b/global-db/test/dap_global_db_test.c
index e07a1eb34..2a9cae7a7 100644
--- a/global-db/test/dap_global_db_test.c
+++ b/global-db/test/dap_global_db_test.c
@@ -116,7 +116,7 @@ static int s_test_write(size_t a_count)
         l_time = get_cur_time_msec();
         ret = dap_global_db_driver_add(&l_store_obj, 1);
         s_write += get_cur_time_msec() - l_time;
-        dap_assert_PIF(!ret, "Write record to DB is ok");
+        dap_assert_PIF(!ret, "Write record to DB");
 
         // rewrite block
         if ( i < l_rewrite_count) {
@@ -131,7 +131,7 @@ static int s_test_write(size_t a_count)
             l_time = get_cur_time_msec();
             ret = dap_global_db_driver_add(&l_store_obj, 1);
             s_write += get_cur_time_msec() - l_time;
-            dap_assert_PIF(!ret, "Rewrite with key conflict record to DB is ok");
+            dap_assert_PIF(!ret, "Rewrite with key conflict record to DB");
         }
 
         l_store_obj.group = DAP_DB$T_GROUP_WRONG;
@@ -141,7 +141,7 @@ static int s_test_write(size_t a_count)
         l_time = get_cur_time_msec();
         ret = dap_global_db_driver_add(&l_store_obj, 1);
         s_write += get_cur_time_msec() - l_time;
-        dap_assert_PIF(!ret, "Write record to wrong group DB is ok");
+        dap_assert_PIF(!ret, "Write record to wrong group DB");
         DAP_DEL_Z(l_store_obj.sign);
     }
     dap_enc_key_delete(l_enc_key);
@@ -166,8 +166,8 @@ static int s_test_read(size_t a_count)
         dap_assert_PIF(l_store_obj, "Record-Not-Found");
         if (l_store_obj->sign)  // to test rewriting with hash conflict some records wiwthout sign
             dap_assert_PIF(dap_global_db_pkt_check_sign_crc(l_store_obj), "Record sign not verified");
-        dap_assert_PIF(!strcmp(DAP_DB$T_GROUP, l_store_obj->group), "Wrong group");
-        dap_assert_PIF(!strcmp(l_key, l_store_obj->key), "Wrong group");
+        dap_assert_PIF(!strcmp(DAP_DB$T_GROUP, l_store_obj->group), "Check group name");
+        dap_assert_PIF(!strcmp(l_key, l_store_obj->key), "Check key name");
 
         prec = (dap_db_test_record_t *) l_store_obj->value;
         dap_test_msg("Retrieved object: [%s, %s, %zu octets]", l_store_obj->group, l_store_obj->key,
@@ -502,7 +502,7 @@ static void s_test_tx_start_end(size_t a_count, bool a_missing_allow)
     s_tx_start_end += get_cur_time_msec() - l_time;
 
     if (!a_missing_allow) {
-        dap_assert_PIF(!ret || ret == DAP_GLOBAL_DB_RC_NOT_FOUND, "Erased records from DB is ok");
+        dap_assert_PIF(!ret || ret == DAP_GLOBAL_DB_RC_NOT_FOUND, "Erased records from DB");
         dap_assert_PIF(a_count - l_count + dap_global_db_driver_hash_is_blank(&l_hash_last) == dap_global_db_driver_count(DAP_DB$T_GROUP, (dap_global_db_driver_hash_t){0}, true), "Wrong records count after erasing");
     }
     // restore erased records
@@ -514,7 +514,7 @@ static void s_test_tx_start_end(size_t a_count, bool a_missing_allow)
     ret = dap_global_db_driver_apply(l_objs, l_count);
     s_tx_start_end += get_cur_time_msec() - l_time;
 
-    dap_assert_PIF(!ret, "Restore records to DB is ok");
+    dap_assert_PIF(!ret, "Restore records to DB");
     if (!a_missing_allow) {
         dap_assert_PIF(a_count == dap_global_db_driver_count(DAP_DB$T_GROUP, (dap_global_db_driver_hash_t){0}, true), "Wrong records count after restoring");
     }
-- 
GitLab