From 15c856219cf0ff9217e6a989e3d86b4cf0dffc8a Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Mon, 27 Sep 2021 19:20:43 +0300 Subject: [PATCH] [+] PostgreSQL driver base --- dap-sdk/crypto/include/dap_hash.h | 22 +- dap-sdk/net/core/dap_events_socket.c | 2 +- modules/chain/dap_chain_ledger.c | 3 +- modules/global-db/CMakeLists.txt | 30 +- .../global-db/dap_chain_global_db_driver.c | 5 + .../dap_chain_global_db_driver_mdbx.c | 1 + .../dap_chain_global_db_driver_pgsql.c | 997 ++++++++++++++++++ .../dap_chain_global_db_driver_pgsql.h | 8 + modules/net/dap_chain_node_cli.c | 2 +- modules/net/dap_chain_node_cli_cmd_tx.c | 2 +- modules/type/dag/dap_chain_cs_dag.c | 7 +- 11 files changed, 1039 insertions(+), 40 deletions(-) create mode 100644 modules/global-db/dap_chain_global_db_driver_pgsql.c create mode 100644 modules/global-db/include/dap_chain_global_db_driver_pgsql.h diff --git a/dap-sdk/crypto/include/dap_hash.h b/dap-sdk/crypto/include/dap_hash.h index c8804a1bc1..f247fa5b58 100755 --- a/dap-sdk/crypto/include/dap_hash.h +++ b/dap-sdk/crypto/include/dap_hash.h @@ -36,7 +36,7 @@ #define DAP_HASH_FAST_SIZE 32 #define DAP_CHAIN_HASH_FAST_SIZE 32 -#define DAP_CHAIN_HASH_FAST_STR_SIZE (DAP_CHAIN_HASH_FAST_SIZE * 2 + 3) +#define DAP_CHAIN_HASH_FAST_STR_SIZE (DAP_CHAIN_HASH_FAST_SIZE * 2 + 2 /* heading 0x */ + 1 /*trailing zero*/) #define DAP_CHAIN_HASH_MAX_SIZE 63 typedef enum dap_hash_type { @@ -100,36 +100,32 @@ static inline bool dap_hash_fast_is_blank( dap_hash_fast_t *a_hash ) DAP_STATIC_INLINE int dap_chain_hash_fast_to_str( dap_hash_fast_t *a_hash, char *a_str, size_t a_str_max ) { - if(!a_str ) + if(! a_hash ) return -1; if(! a_str ) return -2; - if( a_str_max < (DAP_CHAIN_HASH_FAST_SIZE * 2 + 2) ) + if( a_str_max < DAP_CHAIN_HASH_FAST_STR_SIZE ) return -3; a_str[0] = '0'; a_str[1] = 'x'; - a_str[ DAP_CHAIN_HASH_FAST_SIZE * 2 + 2] = 0; + a_str[ DAP_CHAIN_HASH_FAST_STR_SIZE - 1 ] = 0; dap_htoa64((a_str + 2), a_hash->raw, DAP_CHAIN_HASH_FAST_SIZE); - return DAP_CHAIN_HASH_FAST_SIZE * 2 + 2; + return DAP_CHAIN_HASH_FAST_STR_SIZE; } -DAP_STATIC_INLINE int dap_hash_fast_to_str(dap_hash_fast_t *a_hash, char *a_str, size_t a_str_max){ - return dap_chain_hash_fast_to_str(a_hash,a_str,a_str_max); -} +#define dap_hash_fast_to_str dap_chain_hash_fast_to_str DAP_STATIC_INLINE char *dap_chain_hash_fast_to_str_new(dap_hash_fast_t * a_hash) { - const size_t c_hash_str_size = sizeof(*a_hash)*2 +1 /*trailing zero*/ +2 /* heading 0x */+4/*just to be sure*/ ; + const size_t c_hash_str_size = DAP_CHAIN_HASH_FAST_STR_SIZE; char * ret = DAP_NEW_Z_SIZE(char, c_hash_str_size); if(dap_chain_hash_fast_to_str( a_hash, ret, c_hash_str_size ) < 0 ) DAP_DEL_Z(ret); return ret; } -DAP_STATIC_INLINE char *dap_hash_fast_to_str_new(dap_hash_fast_t * a_hash) -{ - return dap_chain_hash_fast_to_str_new(a_hash); -} +#define dap_hash_fast_to_str_new dap_chain_hash_fast_to_str_new + #ifdef __cplusplus } #endif diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c index 982eccfb68..dc53aa3411 100644 --- a/dap-sdk/net/core/dap_events_socket.c +++ b/dap-sdk/net/core/dap_events_socket.c @@ -2117,7 +2117,7 @@ size_t dap_events_socket_write_unsafe(dap_events_socket_t *a_es, const void * a_ a_es->buf_out = DAP_REALLOC(a_es->buf_out, l_new_size); a_es->buf_out_size_max = l_new_size; } - } + } a_data_size = (a_es->buf_out_size + a_data_size < a_es->buf_out_size_max) ? a_data_size : (a_es->buf_out_size_max - a_es->buf_out_size); memcpy(a_es->buf_out + a_es->buf_out_size, a_data, a_data_size); a_es->buf_out_size += a_data_size; diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index d9eaf907ae..69d885f18e 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -290,8 +290,7 @@ int dap_chain_ledger_token_decl_add_check(dap_ledger_t * a_ledger, dap_chain_da HASH_FIND_STR(PVT(a_ledger)->tokens,a_token->ticker,l_token_item); pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock); if ( l_token_item != NULL ){ - if(s_debug_more) - log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker); + log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker); return -3; } // Checks passed diff --git a/modules/global-db/CMakeLists.txt b/modules/global-db/CMakeLists.txt index 7ab3deeefb..31122a6cd4 100644 --- a/modules/global-db/CMakeLists.txt +++ b/modules/global-db/CMakeLists.txt @@ -1,31 +1,23 @@ cmake_minimum_required(VERSION 3.1) project (dap_chain_global_db C) - -set(DAP_CHAIN_GLOBAL_DB_SRC - dap_chain_global_db.c - dap_chain_global_db_driver.c - dap_chain_global_db_driver_cdb.c - dap_chain_global_db_driver_sqlite.c - dap_chain_global_db_hist.c - dap_chain_global_db_remote.c - ) -set(DAP_CHAIN_GLOBAL_DB_HDR - include/dap_chain_global_db.h - include/dap_chain_global_db_driver.h - include/dap_chain_global_db_driver_cdb.h - include/dap_chain_global_db_driver_sqlite.h - include/dap_chain_global_db_hist.h - include/dap_chain_global_db_remote.h - ) + +set(BUILD_WITH_GDB_DRIVER_PGSQL ON) + +file(GLOB DAP_CHAIN_GLOBAL_DB_SRC *.c) +file(GLOB DAP_CHAIN_GLOBAL_DB_HDR include/*.h) + set(DAP_CHAIN_GLOBAL_DB_LIBS dap_core dap_crypto dap_chain sqlite3 dap_cuttdb json-c) if(BUILD_WITH_GDB_DRIVER_MDBX) - set(DAP_CHAIN_GLOBAL_DB_SRC ${DAP_CHAIN_GLOBAL_DB_SRC} dap_chain_global_db_driver_mdbx.c) - set(DAP_CHAIN_GLOBAL_DB_HDR ${DAP_CHAIN_GLOBAL_DB_HDR} include/dap_chain_global_db_driver_mdbx.h) set(DAP_CHAIN_GLOBAL_DB_LIBS ${DAP_CHAIN_GLOBAL_DB_LIBS} mdbx-static) add_definitions ("-DDAP_CHAIN_GDB_ENGINE_MDBX") endif() +if(BUILD_WITH_GDB_DRIVER_PGSQL) + set(DAP_CHAIN_GLOBAL_DB_LIBS ${DAP_CHAIN_GLOBAL_DB_LIBS} pq) + add_definitions ("-DDAP_CHAIN_GDB_ENGINE_PGSQL") +endif() + add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_GLOBAL_DB_SRC} ${DAP_CHAIN_GLOBAL_DB_HDR}) target_link_libraries(${PROJECT_NAME} ${DAP_CHAIN_GLOBAL_DB_LIBS}) diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c index ed6511d71d..2acb41cae4 100644 --- a/modules/global-db/dap_chain_global_db_driver.c +++ b/modules/global-db/dap_chain_global_db_driver.c @@ -38,6 +38,7 @@ #include "dap_chain_global_db_driver_sqlite.h" #include "dap_chain_global_db_driver_cdb.h" #include "dap_chain_global_db_driver_mdbx.h" +#include "dap_chain_global_db_driver_pgsql.h" #include "dap_chain_global_db_driver.h" #define LOG_TAG "db_driver" @@ -103,6 +104,10 @@ int dap_db_driver_init(const char *a_driver_name, const char *a_filename_db) #ifdef DAP_CHAIN_GDB_ENGINE_MDBX else if(!dap_strcmp(s_used_driver, "mdbx")) l_ret = dap_db_driver_mdbx_init(l_db_path_ext, &s_drv_callback); +#endif +#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL + else if(!dap_strcmp(s_used_driver, "pgsql")) + l_ret = dap_db_driver_pgsql_init(l_db_path_ext, &s_drv_callback); #endif else log_it(L_ERROR, "Unknown global_db driver \"%s\"", a_driver_name); diff --git a/modules/global-db/dap_chain_global_db_driver_mdbx.c b/modules/global-db/dap_chain_global_db_driver_mdbx.c index da15504224..91151f0b2c 100644 --- a/modules/global-db/dap_chain_global_db_driver_mdbx.c +++ b/modules/global-db/dap_chain_global_db_driver_mdbx.c @@ -200,5 +200,6 @@ static int s_driver_callback_apply_store_obj(pdap_store_obj_t a_store_obj) return -1; } int ret = 0; + return ret; } diff --git a/modules/global-db/dap_chain_global_db_driver_pgsql.c b/modules/global-db/dap_chain_global_db_driver_pgsql.c new file mode 100644 index 0000000000..fc56c2fc32 --- /dev/null +++ b/modules/global-db/dap_chain_global_db_driver_pgsql.c @@ -0,0 +1,997 @@ +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * CellFrame https://cellframe.net + * Sources https://gitlab.demlabs.net/cellframe + * Copyright (c) 2017-2019 + * All rights reserved. + + This file is part of CellFrame SDK the open source project + + CellFrame SDK is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CellFrame SDK is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stddef.h> +#include <string.h> +#include <pthread.h> +#include <errno.h> + +#ifdef DAP_OS_UNIX +#include <unistd.h> +#endif +#include "dap_common.h" +#include "dap_hash.h" +#include "dap_file_utils.h" +#include "dap_strfuncs.h" +#include "dap_file_utils.h" +#include "dap_chain_global_db_driver_pgsql.h" + +#define LOG_TAG "db_pgsql" + +static PGconn *s_conn_pool; +static pthread_rwlock_t s_db_rwlock = PTHREAD_RWLOCK_INITIALIZER; + +/** + * SQLite library initialization, no thread safe + * + * return 0 if Ok, else error code >0 + */ +int dap_db_driver_pgsql_init(const char *a_filename_dir, dap_db_driver_callbacks_t *a_drv_callback) +{ + // Check paths and create them if nessesary + if(!dap_dir_test(a_filename_dir)){ + log_it(L_NOTICE, "No directory %s, trying to create...", a_filename_dir); + int l_mkdir_ret = dap_mkdir_with_parents(a_filename_dir); + int l_errno = errno; + if(!dap_dir_test(a_filename_dir)){ + char l_errbuf[255]; + l_errbuf[0] = '\0'; + strerror_r(l_errno,l_errbuf,sizeof(l_errbuf)); + log_it(L_ERROR, "Can't create directory, error code %d, error string \"%s\"", l_mkdir_ret, l_errbuf); + return -1; + }else + log_it(L_NOTICE,"Directory created"); + } + dap_hash_fast_t l_dir_hash; + dap_chain_hash_fast_from_str(a_filename_dir, &l_dir_hash); + char *l_db_name = dap_hash_fast_to_str_new(&l_dir_hash); + // Open PostgreSQL database, create if nessesary + const char *l_base_conn_str = "dbname = postgres"; + char *l_error_message = NULL; + PGconn *l_base_conn = PQconnectdb(l_base_conn_str); + if (PQstatus(l_base_conn) != CONNECTION_OK) { + l_error_message = PQerrorMessage(l_base_conn); + log_it(L_ERROR, "Can't init PostgreSQL database: \"%s\"", l_error_message); + DAP_DELETE(l_error_message); + return -2; + } + char *l_query_str = dap_strdup_printf("SELECT EXISTS (SELECT * FROM pg_database WHERE datname = 'ololo')");//, l_db_name); + PGresult *l_res = PQexec(l_base_conn, l_query_str); + if (PQresultStatus(l_res) != PGRES_TUPLES_OK) { + log_it(L_ERROR, "Can't read PostgreSQL database: \"%s\"", PQresultErrorMessage(l_res)); + return -3; + } + return 0; +} +#if 0 +a_drv_callback->apply_store_obj = dap_db_driver_sqlite_apply_store_obj; +a_drv_callback->read_store_obj = dap_db_driver_sqlite_read_store_obj; +a_drv_callback->read_cond_store_obj = dap_db_driver_sqlite_read_cond_store_obj; +a_drv_callback->read_last_store_obj = dap_db_driver_sqlite_read_last_store_obj; +a_drv_callback->transaction_start = dap_db_driver_sqlite_start_transaction; +a_drv_callback->transaction_end = dap_db_driver_sqlite_end_transaction; +a_drv_callback->get_groups_by_mask = dap_db_driver_sqlite_get_groups_by_mask; +a_drv_callback->read_count_store = dap_db_driver_sqlite_read_count_store; +a_drv_callback->is_obj = dap_db_driver_sqlite_is_obj; +a_drv_callback->deinit = dap_db_driver_sqlite_deinit; +a_drv_callback->flush = dap_db_driver_sqlite_flush; + +/* Set always-secure search path, so malicious users can't take +control. */ +res = PQexec(conn, +"SELECT pg_catalog.set_config('search_path', '', +false)"); +if (PQresultStatus(res) != PGRES_TUPLES_OK) +{ +fprintf(stderr, "SET failed: %s", PQerrorMessage(conn)); +PQclear(res); +exit_nicely(conn); +} +/* +* Should PQclear PGresult whenever it is no longer needed to +avoid memory +* leaks +*/ +PQclear(res); +/* +* Our test case here involves using a cursor, for which we +must be inside +* a transaction block. We could do the whole thing with a +single +* PQexec() of "select * from pg_database", but that's too +trivial to make +* a good example. +*/ +/* Start a transaction block */ +res = PQexec(conn, "BEGIN"); +if (PQresultStatus(res) != PGRES_COMMAND_OK) +{ +fprintf(stderr, "BEGIN command failed: %s", +PQerrorMessage(conn)); +PQclear(res); +exit_nicely(conn); +} +893 +libpq — C Library +PQclear(res); +/* +* Fetch rows from pg_database, the system catalog of databases +*/ +res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from +pg_database"); +if (PQresultStatus(res) != PGRES_COMMAND_OK) +{ +fprintf(stderr, "DECLARE CURSOR failed: %s", +PQerrorMessage(conn)); +PQclear(res); +exit_nicely(conn); +} +PQclear(res); +res = PQexec(conn, "FETCH ALL in myportal"); +if (PQresultStatus(res) != PGRES_TUPLES_OK) +{ +fprintf(stderr, "FETCH ALL failed: %s", +PQerrorMessage(conn)); +PQclear(res); +exit_nicely(conn); +} +/* first, print out the attribute names */ +nFields = PQnfields(res); +for (i = 0; i < nFields; i++) +printf("%-15s", PQfname(res, i)); +printf("\n\n"); +/* next, print out the rows */ +for (i = 0; i < PQntuples(res); i++) +{ +for (j = 0; j < nFields; j++) +printf("%-15s", PQgetvalue(res, i, j)); +printf("\n"); +} +PQclear(res); +/* close the portal ... we don't bother to check for errors ... +*/ +res = PQexec(conn, "CLOSE myportal"); +PQclear(res); +/* end the transaction */ +res = PQexec(conn, "END"); +PQclear(res); +/* close the connection to the database and cleanup */ +PQfinish(conn); +return 0; +} + + +int dap_db_driver_sqlite_deinit(void) +{ + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return -666; + } + dap_db_driver_sqlite_close(s_db); + pthread_rwlock_unlock(&s_db_rwlock); + s_db = NULL; + return sqlite3_shutdown(); +} + +// additional function for sqlite to convert byte to number +static void byte_to_bin(sqlite3_context *l_context, int a_argc, sqlite3_value **a_argv) +{ + const unsigned char *l_text; + if(a_argc != 1) + sqlite3_result_null(l_context); + l_text = (const unsigned char *) sqlite3_value_blob(a_argv[0]); + if(l_text && l_text[0]) + { + int l_result = (int) l_text[0]; + sqlite3_result_int(l_context, l_result); + return; + } + sqlite3_result_null(l_context); +} + +/** + * Open SQLite database + * a_filename_utf8 - database file name + * a_flags - database access flags (SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) + * a_error_message[out] - Error messages (the memory requires deletion via sqlite_free ()) + * + * return: database identifier, NULL when an error occurs. + */ +sqlite3* dap_db_driver_sqlite_open(const char *a_filename_utf8, int a_flags, char **a_error_message) +{ + sqlite3 *l_db = NULL; + + int l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX, NULL); + // 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); + if(l_db) + sqlite3_close(l_db); + // try to create database + l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX| SQLITE_OPEN_CREATE, NULL); + } + + if(l_rc != SQLITE_OK) { + log_it(L_CRITICAL,"Can't open database on path %s (code %d: \"%s\" )", a_filename_utf8, l_rc, sqlite3_errstr(l_rc)); + if(a_error_message) + *a_error_message = sqlite3_mprintf("Can't open database: %s\n", sqlite3_errmsg(l_db)); + sqlite3_close(l_db); + return NULL; + } + // added user functions + sqlite3_create_function(l_db, "byte_to_bin", 1, SQLITE_UTF8, NULL, &byte_to_bin, NULL, NULL); + return l_db; +} + +/** + * Close the database + */ +void dap_db_driver_sqlite_close(sqlite3 *l_db) +{ + if(l_db) + sqlite3_close(l_db); +} +/* + * Clear the memory allocated via sqlite3_mprintf() + */ +void dap_db_driver_sqlite_free(char *memory) +{ + if(memory) + sqlite3_free(memory); +} + +/** + * Set specific pragma statements + * www.sqlite.org/pragma.html + * + *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 + *PRAGMA encoding = "UTF-8"; // default = UTF-8 + *PRAGMA foreign_keys = 1; // default = 0 + *PRAGMA journal_mode = DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF; + *PRAGMA synchronous = 0 | OFF | 1 | NORMAL | 2 | FULL; + */ +bool dap_db_driver_sqlite_set_pragma(sqlite3 *a_db, char *a_param, char *a_mode) +{ + if(!a_param || !a_mode) + { + printf("[sqlite_set_pragma] err!!! no param or mode\n"); + return false; + } + char *l_str_query = sqlite3_mprintf("PRAGMA %s = %s", a_param, a_mode); + int l_rc = dap_db_driver_sqlite_exec(a_db, l_str_query, NULL); // default synchronous=FULL + sqlite3_free(l_str_query); + if(l_rc == SQLITE_OK) + return true; + return false; +} + +int dap_db_driver_sqlite_flush() +{ + log_it(L_DEBUG, "Start flush sqlite data base."); + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return -666; + } + dap_db_driver_sqlite_close(s_db); + char *l_error_message = NULL; + s_db = dap_db_driver_sqlite_open(s_filename_db, SQLITE_OPEN_READWRITE, &l_error_message); + if(!s_db) { + pthread_rwlock_unlock(&s_db_rwlock); + log_it(L_ERROR, "Can't init sqlite err: \"%s\"", l_error_message? l_error_message: "UNKNOWN"); + dap_db_driver_sqlite_free(l_error_message); + return -3; + } +#ifndef _WIN32 + sync(); +#endif + if(!dap_db_driver_sqlite_set_pragma(s_db, "synchronous", "NORMAL")) // 0 | OFF | 1 | NORMAL | 2 | FULL + log_it(L_WARNING, "Can't set new synchronous mode\n"); + if(!dap_db_driver_sqlite_set_pragma(s_db, "journal_mode", "OFF")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF + log_it(L_WARNING, "Can't set new journal mode\n"); + + if(!dap_db_driver_sqlite_set_pragma(s_db, "page_size", "1024")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF + log_it(L_WARNING, "Can't set page_size\n"); + pthread_rwlock_unlock(&s_db_rwlock); + return 0; +} + +/** + * Execute SQL query to database that does not return data + * + * return 0 if Ok, else error code >0 + */ +static int dap_db_driver_sqlite_exec(sqlite3 *l_db, const char *l_query, char **l_error_message) +{ + char *l_zErrMsg = NULL; + int l_rc = sqlite3_exec(l_db, l_query, NULL, 0, &l_zErrMsg); + //printf("%s\n",l_query); + if(l_rc != SQLITE_OK) + { + if(l_error_message && l_zErrMsg) + *l_error_message = sqlite3_mprintf("SQL error: %s", l_zErrMsg); + if(l_zErrMsg) + sqlite3_free(l_zErrMsg); + return l_rc; + } + if(l_zErrMsg) + sqlite3_free(l_zErrMsg); + return l_rc; +} + +/** + * Create table + * + * return 0 if Ok, else error code + */ +static int dap_db_driver_sqlite_create_group_table(const char *a_table_name) +{ + char *l_error_message = NULL; + if(!s_db || !a_table_name) + return -1; + char *l_query = + dap_strdup_printf( + "create table if not exists '%s'(id INTEGER NOT NULL PRIMARY KEY, key TEXT KEY, hash BLOB, ts INTEGER KEY, value BLOB)", + a_table_name); + if(dap_db_driver_sqlite_exec(s_db, (const char*) l_query, &l_error_message) != SQLITE_OK) + { + log_it(L_ERROR, "Creatу_table : %s\n", l_error_message); + dap_db_driver_sqlite_free(l_error_message); + DAP_DELETE(l_query); + return -1; + } + DAP_DELETE(l_query); + // create unique index - key + l_query = dap_strdup_printf("create unique index if not exists 'idx_key_%s' ON '%s' (key)", a_table_name, + a_table_name); + if(dap_db_driver_sqlite_exec(s_db, (const char*) l_query, &l_error_message) != SQLITE_OK) { + log_it(L_ERROR, "Create unique index : %s\n", l_error_message); + dap_db_driver_sqlite_free(l_error_message); + DAP_DELETE(l_query); + return -1; + } + DAP_DELETE(l_query); + return 0; +} + +/** + * Prepare SQL query for database + * l_query [in] SQL-string with a query to database, example: + * SELECT * FROM data + * SELECT id, sd FROM data LIMIT 300 + * SELECT id, sd FROM data ORDER BY id ASC/DESC + * SELECT * FROM data WHERE time>449464766900000 and time<449464766910000" + * SELECT * FROM data WHERE hex(sd) LIKE '%370%' + * hex(x'0806') -> '08f6' или quote(sd) -> X'08f6' + * substr(x'031407301210361320690000',3,2) -> x'0730' + * + * CAST(substr(sd,5,2) as TEXT) + * additional function of line to number _uint8 + * byte_to_bin(x'ff') -> 255 + */ +static int dap_db_driver_sqlite_query(sqlite3 *db, char *query, sqlite3_stmt **l_res, char **l_error_message) +{ + const char *pzTail; // OUT: Pointer to unused portion of zSql + int l_rc = sqlite3_prepare_v2(db, query, -1, l_res, &pzTail); + if(l_rc != SQLITE_OK) + { + if(l_error_message) + { + const char *zErrMsg = sqlite3_errmsg(db); + if(zErrMsg) + *l_error_message = sqlite3_mprintf("SQL Query error: %s\n", zErrMsg); + } + return l_rc; + } + return l_rc; +} + +/** + * Clear memory after fetching a string + * + * return 0 if Ok, else -1 + */ +static void dap_db_driver_sqlite_row_free(SQLITE_ROW_VALUE *row) +{ + if(row) { + // delete the whole string + sqlite3_free(row->val); + // delete structure + sqlite3_free(row); + } +} + +/** + * Selects the next entry from the result of the query and returns an array + * + * l_res: identifier received in sqlite_query () + * l_row_out [out]: pointer to a column or NULL + * + * return: + * SQLITE_ROW(100) has another row ready + * SQLITE_DONE(101) finished executing, + * SQLITE_CONSTRAINT(19) data is not unique and will not be added + */ +static int dap_db_driver_sqlite_fetch_array(sqlite3_stmt *l_res, SQLITE_ROW_VALUE **l_row_out) +{ + SQLITE_ROW_VALUE *l_row = NULL; + // go to next the string + int l_rc = sqlite3_step(l_res); + if(l_rc == SQLITE_ROW) // SQLITE_ROW(100) or SQLITE_DONE(101) or SQLITE_BUSY(5) + { + int l_iCol; // number of the column in the row + // allocate memory for a row with data + l_row = (SQLITE_ROW_VALUE*) sqlite3_malloc(sizeof(SQLITE_ROW_VALUE)); + int l_count = sqlite3_column_count(l_res); // get the number of columns + // allocate memory for all columns + l_row->val = (SQLITE_VALUE*) sqlite3_malloc(l_count * (int)sizeof(SQLITE_VALUE)); + if(l_row->val) + { + l_row->count = l_count; // number of columns + for(l_iCol = 0; l_iCol < l_row->count; l_iCol++) + { + SQLITE_VALUE *cur_val = l_row->val + l_iCol; + cur_val->len = sqlite3_column_bytes(l_res, l_iCol); // how many bytes will be needed + cur_val->type = (signed char)sqlite3_column_type(l_res, l_iCol); // field type + if(cur_val->type == SQLITE_INTEGER) + { + cur_val->val.val_int64 = sqlite3_column_int64(l_res, l_iCol); + } + else if(cur_val->type == SQLITE_FLOAT) + cur_val->val.val_float = sqlite3_column_double(l_res, l_iCol); + else if(cur_val->type == SQLITE_BLOB) + cur_val->val.val_blob = (const unsigned char*) sqlite3_column_blob(l_res, l_iCol); + else if(cur_val->type == SQLITE_TEXT) + cur_val->val.val_str = (const char*) sqlite3_column_text(l_res, l_iCol); //sqlite3_mprintf("%s",sqlite3_column_text(l_res,iCol)); + else + cur_val->val.val_str = NULL; + } + } + else + l_row->count = 0; // number of columns + } + if(l_row_out) + *l_row_out = l_row; + else + dap_db_driver_sqlite_row_free(l_row); + return l_rc; +} + +/** + * Clear memory when request processing is complete + */ +static bool dap_db_driver_sqlite_query_free(sqlite3_stmt *l_res) +{ + if(!l_res) + return false; + int rc = sqlite3_finalize(l_res); + if(rc != SQLITE_OK) + return false; + return true; +} + +/** + * Convert the array into a string to save to blob + */ +static char* dap_db_driver_get_string_from_blob(uint8_t *blob, int len) +{ + char *str_out; + int ret; + if(!blob) + return NULL; + str_out = (char*) sqlite3_malloc(len * 2 + 1); + ret = (int)dap_bin2hex(str_out, (const void*)blob, (size_t)len); + str_out[len * 2] = 0; + return str_out; + +} + +/** + * Cleaning the database from the deleted data + * + * return 0 if Ok, else error code >0 + */ +int dap_db_driver_sqlite_vacuum(sqlite3 *l_db) +{ + if(!s_db) + return -1; + int l_rc = dap_db_driver_sqlite_exec(l_db, "VACUUM", NULL); + return l_rc; +} + +/** + * Start a transaction + */ +int dap_db_driver_sqlite_start_transaction(void) +{ + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return -666; + } + + if(SQLITE_OK == dap_db_driver_sqlite_exec(s_db, "BEGIN", NULL)){ + pthread_rwlock_unlock(&s_db_rwlock); + return 0; + }else{ + pthread_rwlock_unlock(&s_db_rwlock); + return -1; + } +} + +/** + * End of transaction + */ +int dap_db_driver_sqlite_end_transaction(void) +{ + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return -666; + } + if(SQLITE_OK == dap_db_driver_sqlite_exec(s_db, "COMMIT", NULL)){ + pthread_rwlock_unlock(&s_db_rwlock); + return 0; + }else{ + pthread_rwlock_unlock(&s_db_rwlock); + return -1; + } +} + +char *dap_db_driver_sqlite_make_group_name(const char *a_table_name) +{ + char *l_table_name = dap_strdup(a_table_name); + ssize_t l_table_name_len = (ssize_t)dap_strlen(l_table_name); + const char *l_needle = "_"; + // replace '_' to '.' + while(1){ + char *l_str = dap_strstr_len(l_table_name, l_table_name_len, l_needle); + if(l_str) + *l_str = '.'; + else + break; + } + return l_table_name; +} + +char *dap_db_driver_sqlite_make_table_name(const char *a_group_name) +{ + char *l_group_name = dap_strdup(a_group_name); + ssize_t l_group_name_len = (ssize_t)dap_strlen(l_group_name); + const char *l_needle = "."; + // replace '.' to '_' + while(1){ + char *l_str = dap_strstr_len(l_group_name, l_group_name_len, l_needle); + if(l_str) + *l_str = '_'; + else + break; + } + return l_group_name; +} + +/** + * Apply data (write or delete) + * + */ +int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj) +{ + if(!a_store_obj || !a_store_obj->group ) + return -1; + char *l_query = NULL; + char *l_error_message = NULL; + char *l_table_name = dap_db_driver_sqlite_make_table_name(a_store_obj->group); + if(a_store_obj->type == 'a') { + if(!a_store_obj->key || !a_store_obj->value || !a_store_obj->value_len) + return -1; + //dap_chain_hash_fast_t l_hash; + //dap_hash_fast(a_store_obj->value, a_store_obj->value_len, &l_hash); + + char *l_blob_hash = "";//dap_db_driver_get_string_from_blob((uint8_t*) &l_hash, sizeof(dap_chain_hash_fast_t)); + char *l_blob_value = dap_db_driver_get_string_from_blob(a_store_obj->value, (int)a_store_obj->value_len); + //add one record + l_query = sqlite3_mprintf("insert into '%s' values(NULL, '%s', x'%s', '%lld', x'%s')", + l_table_name, a_store_obj->key, l_blob_hash, a_store_obj->timestamp, l_blob_value); + //dap_db_driver_sqlite_free(l_blob_hash); + dap_db_driver_sqlite_free(l_blob_value); + } + else if(a_store_obj->type == 'd') { + //delete one record + if(a_store_obj->key) + l_query = sqlite3_mprintf("delete from '%s' where key = '%s'", + l_table_name, a_store_obj->key); + // remove all group + else { + l_query = sqlite3_mprintf("drop table if exists '%s'", l_table_name); + } + } + else { + log_it(L_ERROR, "Unknown store_obj type '0x%x'", a_store_obj->type); + return -1; + } + // execute request + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return -666; + } + + int l_ret = dap_db_driver_sqlite_exec(s_db, l_query, &l_error_message); + if(l_ret == SQLITE_ERROR) { + dap_db_driver_sqlite_free(l_error_message); + l_error_message = NULL; + // create table + dap_db_driver_sqlite_create_group_table(l_table_name); + // repeat request + l_ret = dap_db_driver_sqlite_exec(s_db, l_query, &l_error_message); + + } + // entry with the same hash is already present + if(l_ret == SQLITE_CONSTRAINT) { + dap_db_driver_sqlite_free(l_error_message); + l_error_message = NULL; + //delete exist record + char *l_query_del = sqlite3_mprintf("delete from '%s' where key = '%s'", l_table_name, a_store_obj->key); + l_ret = dap_db_driver_sqlite_exec(s_db, l_query_del, &l_error_message); + dap_db_driver_sqlite_free(l_query_del); + if(l_ret != SQLITE_OK) { + log_it(L_INFO, "Entry with the same key is already present and can't delete, %s", l_error_message); + dap_db_driver_sqlite_free(l_error_message); + l_error_message = NULL; + } + // repeat request + l_ret = dap_db_driver_sqlite_exec(s_db, l_query, &l_error_message); + } + pthread_rwlock_unlock(&s_db_rwlock); + // missing database + if(l_ret != SQLITE_OK) { + log_it(L_ERROR, "sqlite apply error: %s", l_error_message); + dap_db_driver_sqlite_free(l_error_message); + l_ret = -1; + } + dap_db_driver_sqlite_free(l_query); + DAP_DELETE(l_table_name); + return l_ret; +} + +static void fill_one_item(const char *a_group, dap_store_obj_t *a_obj, SQLITE_ROW_VALUE *a_row) +{ + a_obj->group = dap_strdup(a_group); + + for(int l_iCol = 0; l_iCol < a_row->count; l_iCol++) { + SQLITE_VALUE *l_cur_val = a_row->val + l_iCol; + switch (l_iCol) { + case 0: + if(l_cur_val->type == SQLITE_INTEGER) + a_obj->id = (uint64_t)l_cur_val->val.val_int64; + break; // id + case 1: + if(l_cur_val->type == SQLITE_INTEGER) + a_obj->timestamp = l_cur_val->val.val_int64; + break; // ts + case 2: + if(l_cur_val->type == SQLITE_TEXT) + a_obj->key = dap_strdup(l_cur_val->val.val_str); + break; // key + case 3: + if(l_cur_val->type == SQLITE_BLOB) + { + a_obj->value_len = (size_t) l_cur_val->len; + a_obj->value = DAP_NEW_SIZE(uint8_t, a_obj->value_len); + memcpy(a_obj->value, l_cur_val->val.val_blob, a_obj->value_len); + } + break; // value + } + } + +} + +/** + * Read last items + * + * a_group - group name + */ +dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group) +{ + + dap_store_obj_t *l_obj = NULL; + char *l_error_message = NULL; + sqlite3_stmt *l_res; + if(!a_group) + return NULL; + char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group); + char *l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id DESC LIMIT 1", l_table_name); + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return NULL; + } + + int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, &l_error_message); + pthread_rwlock_unlock(&s_db_rwlock); + sqlite3_free(l_str_query); + DAP_DEL_Z(l_table_name); + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "read last l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + dap_db_driver_sqlite_free(l_error_message); + return NULL; + } + + SQLITE_ROW_VALUE *l_row = NULL; + l_ret = dap_db_driver_sqlite_fetch_array(l_res, &l_row); + if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE) + { + //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + } + if(l_ret == SQLITE_ROW && l_row) { + l_obj = DAP_NEW_Z(dap_store_obj_t); + fill_one_item(a_group, l_obj, l_row); + } + dap_db_driver_sqlite_row_free(l_row); + dap_db_driver_sqlite_query_free(l_res); + + return l_obj; +} + +/** + * Read several items with conditoin + * + * a_group - group name + * a_id - read from this id + * a_count_out[in], how many items to read, 0 - no limits + * a_count_out[out], how many items was read + */ +dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out) +{ + dap_store_obj_t *l_obj = NULL; + char *l_error_message = NULL; + sqlite3_stmt *l_res; + if(!a_group) + return NULL; + + char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group); + // no limit + int l_count_out = 0; + if(a_count_out) + l_count_out = (int)*a_count_out; + char *l_str_query; + if(l_count_out) + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC LIMIT %d", + l_table_name, a_id, l_count_out); + else + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC", + l_table_name, a_id); + pthread_rwlock_wrlock(&s_db_rwlock); + if(!s_db){ + pthread_rwlock_unlock(&s_db_rwlock); + return NULL; + } + + int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, &l_error_message); + pthread_rwlock_unlock(&s_db_rwlock); + sqlite3_free(l_str_query); + DAP_DEL_Z(l_table_name); + + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + dap_db_driver_sqlite_free(l_error_message); + return NULL; + } + + //int b = qlite3_column_count(s_db); + SQLITE_ROW_VALUE *l_row = NULL; + l_count_out = 0; + int l_count_sized = 0; + do { + l_ret = dap_db_driver_sqlite_fetch_array(l_res, &l_row); + if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE) + { + // log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + } + if(l_ret == SQLITE_ROW && l_row) { + // realloc memory + if(l_count_out >= l_count_sized) { + l_count_sized += 10; + l_obj = DAP_REALLOC(l_obj, sizeof(dap_store_obj_t) * (uint64_t)l_count_sized); + memset(l_obj + l_count_out, 0, sizeof(dap_store_obj_t) * (uint64_t)(l_count_sized - l_count_out)); + } + // fill current item + dap_store_obj_t *l_obj_cur = l_obj + l_count_out; + fill_one_item(a_group, l_obj_cur, l_row); + l_count_out++; + } + dap_db_driver_sqlite_row_free(l_row); + } while(l_row); + + dap_db_driver_sqlite_query_free(l_res); + + if(a_count_out) + *a_count_out = (size_t)l_count_out; + return l_obj; +} + +/** + * Read several items + * + * a_group - group name + * a_key - key name, may by NULL, it means reading the whole group + * a_count_out[in], how many items to read, 0 - no limits + * a_count_out[out], how many items was read + */ +dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out) +{ + if(!a_group || !s_db) + return NULL; + dap_store_obj_t *l_obj = NULL; + sqlite3_stmt *l_res; + char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group); + // no limit + uint64_t l_count_out = 0; + if(a_count_out) + l_count_out = *a_count_out; + char *l_str_query; + if(a_key) { + if(l_count_out) + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE key='%s' ORDER BY id ASC LIMIT %d", + l_table_name, a_key, l_count_out); + else + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE key='%s' ORDER BY id ASC", + l_table_name, a_key); + } + else { + if(l_count_out) + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id ASC LIMIT %d", + l_table_name, l_count_out); + else + l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id ASC", l_table_name); + } + pthread_rwlock_wrlock(&s_db_rwlock); + int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL); + pthread_rwlock_unlock(&s_db_rwlock); + + sqlite3_free(l_str_query); + DAP_DEL_Z(l_table_name); + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + return NULL; + } + + //int b = qlite3_column_count(s_db); + SQLITE_ROW_VALUE *l_row = NULL; + l_count_out = 0; + uint64_t l_count_sized = 0; + do { + l_ret = dap_db_driver_sqlite_fetch_array(l_res, &l_row); + if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE) + { + // log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + } + if(l_ret == SQLITE_ROW && l_row) { + // realloc memory + if(l_count_out >= l_count_sized) { + l_count_sized += 10; + l_obj = DAP_REALLOC(l_obj, sizeof(dap_store_obj_t) * l_count_sized); + memset(l_obj + l_count_out, 0, sizeof(dap_store_obj_t) * (l_count_sized - l_count_out)); + } + // fill currrent item + dap_store_obj_t *l_obj_cur = l_obj + l_count_out; + fill_one_item(a_group, l_obj_cur, l_row); + l_count_out++; + } + dap_db_driver_sqlite_row_free(l_row); + } while(l_row); + + dap_db_driver_sqlite_query_free(l_res); + + if(a_count_out) + *a_count_out = l_count_out; + return l_obj; +} + +dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask) +{ + if(!a_group_mask || !s_db) + return NULL; + sqlite3_stmt *l_res; + const char *l_str_query = "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%'"; + dap_list_t *l_ret_list = NULL; + pthread_rwlock_wrlock(&s_db_rwlock); + int l_ret = dap_db_driver_sqlite_query(s_db, (char *)l_str_query, &l_res, NULL); + pthread_rwlock_unlock(&s_db_rwlock); + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "Get tables l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + return NULL; + } + char * l_mask = dap_db_driver_sqlite_make_table_name(a_group_mask); + SQLITE_ROW_VALUE *l_row = NULL; + while (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) { + char *l_table_name = (char *)l_row->val->val.val_str; + if(!dap_fnmatch(l_mask, l_table_name, 0)) + l_ret_list = dap_list_prepend(l_ret_list, dap_db_driver_sqlite_make_group_name(l_table_name)); + dap_db_driver_sqlite_row_free(l_row); + } + dap_db_driver_sqlite_query_free(l_res); + return l_ret_list; +} + +size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id) +{ + sqlite3_stmt *l_res; + if(!a_group || ! s_db) + return 0; + + char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group); + char *l_str_query = sqlite3_mprintf("SELECT COUNT(*) FROM '%s' WHERE id>='%lld'", l_table_name, a_id); + pthread_rwlock_wrlock(&s_db_rwlock); + int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL); + pthread_rwlock_unlock(&s_db_rwlock); + sqlite3_free(l_str_query); + DAP_DEL_Z(l_table_name); + + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "Count l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + return 0; + } + size_t l_ret_val; + SQLITE_ROW_VALUE *l_row = NULL; + if (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) { + l_ret_val = (size_t)l_row->val->val.val_int64; + dap_db_driver_sqlite_row_free(l_row); + } + dap_db_driver_sqlite_query_free(l_res); + return l_ret_val; +} + +bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key) +{ + sqlite3_stmt *l_res; + if(!a_group || ! s_db) + return false; + + char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group); + char *l_str_query = sqlite3_mprintf("SELECT EXISTS(SELECT * FROM '%s' WHERE key='%s')", l_table_name, a_key); + pthread_rwlock_wrlock(&s_db_rwlock); + int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL); + pthread_rwlock_unlock(&s_db_rwlock); + sqlite3_free(l_str_query); + DAP_DEL_Z(l_table_name); + + if(l_ret != SQLITE_OK) { + //log_it(L_ERROR, "Exists l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db)); + return false; + } + bool l_ret_val; + SQLITE_ROW_VALUE *l_row = NULL; + if (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) { + l_ret_val = (size_t)l_row->val->val.val_int64; + dap_db_driver_sqlite_row_free(l_row); + } + dap_db_driver_sqlite_query_free(l_res); + return l_ret_val; +} +#endif diff --git a/modules/global-db/include/dap_chain_global_db_driver_pgsql.h b/modules/global-db/include/dap_chain_global_db_driver_pgsql.h new file mode 100644 index 0000000000..72fc70db64 --- /dev/null +++ b/modules/global-db/include/dap_chain_global_db_driver_pgsql.h @@ -0,0 +1,8 @@ +#pragma once + +#include "dap_chain_global_db_driver.h" +#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL +#include "/usr/include/postgresql/libpq-fe.h" +#endif + +int dap_db_driver_pgsql_init(const char *a_filename_dir, dap_db_driver_callbacks_t *a_drv_callback); diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index e065f87730..5259aa5715 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -988,7 +988,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "mempool_list -net <net name> -chain <chain name>\n"); dap_chain_node_cli_cmd_item_create ("mempool_proc", com_mempool_proc, NULL, "Proc mempool entries for selected chain network and chain id", - "mempool_proc -net <net name> -chain <chain name>\n"); + "mempool_proc -net <net name> -chain <chain name> -datum <datum hash>\n"); dap_chain_node_cli_cmd_item_create ("mempool_delete", com_mempool_delete, NULL, "Delete datum with hash <datum hash>", "mempool_delete -net <net name> -chain <chain name> -datum <datum hash>\n"); diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 3f7b307e1b..1633f6fe57 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -256,7 +256,7 @@ void _dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum, dap_chain_tx_out_cond_subtype_to_str(((dap_chain_tx_out_cond_t*)item)->header.subtype)); switch (((dap_chain_tx_out_cond_t*)item)->header.subtype) { case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: - l_hash_str_tmp = dap_hash_fast_to_str_new(&((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.pkey_hash); + l_hash_str_tmp = dap_chain_hash_fast_to_str_new(&((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.pkey_hash); dap_string_append_printf(a_str_out, "\t\t\t unit: 0x%08x\n" "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n" "\t\t\t pkey: %s\n" diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c index 015eb3fe86..c6a8b7dc73 100644 --- a/modules/type/dag/dap_chain_cs_dag.c +++ b/modules/type/dag/dap_chain_cs_dag.c @@ -1522,9 +1522,10 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply) pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock); HASH_FIND(hh,PVT(l_dag)->events,&l_event_hash,sizeof(l_event_hash),l_event_item); pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock); - if ( l_event_item ) + if ( l_event_item ) { l_event = l_event_item->event; - else { + l_event_size = l_event_item->event_size; + } else { ret = -24; dap_chain_node_cli_set_reply_text(a_str_reply, "Can't find event %s in events table\n", l_event_hash_str); @@ -1594,7 +1595,7 @@ static int s_cli_dag(int argc, char ** argv, void *arg_func, char **a_str_reply) dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, l_net->pub.id); char * l_addr_str = dap_chain_addr_to_str(&l_addr); dap_string_append_printf(l_str_tmp,"\t\t\t\t\t\ttype: %s\taddr: %s" - "n", dap_sign_type_to_str( l_sign->header.type ), + "\n", dap_sign_type_to_str( l_sign->header.type ), l_addr_str ); l_offset += l_sign_size; DAP_DELETE( l_addr_str); -- GitLab