/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program 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 Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #ifndef ZABBIX_ZBXDB_H #define ZABBIX_ZBXDB_H #include "zbxcommon.h" #include "zbxjson.h" #include "zbxdbschema.h" #define ZBX_DB_OK 0 #define ZBX_DB_FAIL -1 #define ZBX_DB_DOWN -2 #define ZBX_DB_TLS_CONNECT_REQUIRED_TXT "required" #define ZBX_DB_TLS_CONNECT_VERIFY_CA_TXT "verify_ca" #define ZBX_DB_TLS_CONNECT_VERIFY_FULL_TXT "verify_full" typedef char **zbx_db_row_t; typedef struct zbx_db_result *zbx_db_result_t; typedef struct zbx_dbconn zbx_dbconn_t; /* database field value */ typedef union { int i32; zbx_uint64_t ui64; double dbl; char *str; } zbx_db_value_t; typedef struct { char *dbhost; char *dbname; char *dbschema; char *dbuser; char *dbpassword; char *dbsocket; char *db_tls_connect; char *db_tls_cert_file; char *db_tls_key_file; char *db_tls_ca_file; char *db_tls_cipher; char *db_tls_cipher_13; unsigned int dbport; int log_slow_queries; int read_only_recoverable; } zbx_db_config_t; #ifdef HAVE_SQLITE3 /* we have to put double % here for sprintf */ # define ZBX_SQL_MOD(x, y) #x "%%" #y #else # define ZBX_SQL_MOD(x, y) "mod(" #x "," #y ")" #endif #ifdef HAVE_SQLITE3 # define ZBX_FOR_UPDATE "" /* SQLite3 does not support "select ... for update" */ #else # define ZBX_FOR_UPDATE " for update" #endif #ifdef HAVE_MYSQL # define ZBX_SQL_STRCMP "%s binary '%s'" #else # define ZBX_SQL_STRCMP "%s'%s'" #endif #define ZBX_SQL_STRVAL_EQ(str) "=", str #define ZBX_SQL_STRVAL_NE(str) "<>", str #ifdef HAVE_MYSQL # define ZBX_SQL_CONCAT() "concat(%s,%s)" #else # define ZBX_SQL_CONCAT() "%s||%s" #endif #define ZBX_SQL_NULLCMP(f1, f2) "((" f1 " is null and " f2 " is null) or " f1 "=" f2 ")" #define ZBX_DBROW2UINT64(uint, row) \ do { \ if (SUCCEED == zbx_db_is_null(row)) \ uint = 0; \ else \ zbx_is_uint64(row, &uint); \ } \ while (0) #ifdef HAVE_MYSQL # define ZBX_SQL_SORT_ASC(field) field " asc" # define ZBX_SQL_SORT_DESC(field) field " desc" #else # define ZBX_SQL_SORT_ASC(field) field " asc nulls first" # define ZBX_SQL_SORT_DESC(field) field " desc nulls last" #endif #define ZBX_DB_MAX_ID (zbx_uint64_t)__UINT64_C(0x7fffffffffffffff) int zbx_db_init(char **error); void zbx_db_deinit(void); typedef enum { ERR_Z3001 = 3001, ERR_Z3002, ERR_Z3003, ERR_Z3004, ERR_Z3005, ERR_Z3006, ERR_Z3007, ERR_Z3008, ERR_Z3009 } zbx_err_codes_t; #ifdef HAVE_POSTGRESQL int zbx_tsdb_get_version(void); #endif #if defined (HAVE_MYSQL) void zbx_mysql_escape_bin(const char *src, char *dst, size_t size); #elif defined(HAVE_POSTGRESQL) void zbx_postgresql_escape_bin(const char *src, char **dst, size_t size); #endif typedef enum { ESCAPE_SEQUENCE_OFF, ESCAPE_SEQUENCE_ON } zbx_escape_sequence_t; #define ZBX_SQL_LIKE_ESCAPE_CHAR '!' char *zbx_db_dyn_escape_like_pattern(const char *src); size_t zbx_db_strlen_n(const char *text_loc, size_t maxlen); #define ZBX_DB_EXTENSION_TIMESCALEDB "timescaledb" #if defined(HAVE_POSTGRESQL) # define ZBX_SUPPORTED_DB_CHARACTER_SET "utf8" #elif defined(HAVE_MYSQL) # define ZBX_DB_STRLIST_DELIM ',' # define ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8 "utf8" # define ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8MB3 "utf8mb3" # define ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8MB4 "utf8mb4" # define ZBX_SUPPORTED_DB_CHARACTER_SET ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8 ","\ ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8MB3 ","\ ZBX_SUPPORTED_DB_CHARACTER_SET_UTF8MB4 # define ZBX_SUPPORTED_DB_COLLATION "utf8_bin,utf8mb3_bin,utf8mb4_bin" #endif typedef enum { /* db version status flags shared with FRONTEND */ DB_VERSION_SUPPORTED, DB_VERSION_LOWER_THAN_MINIMUM, DB_VERSION_HIGHER_THAN_MAXIMUM, DB_VERSION_FAILED_TO_RETRIEVE, DB_VERSION_NOT_SUPPORTED_ERROR, DB_VERSION_NOT_SUPPORTED_WARNING, DB_VERSION_HIGHER_THAN_MAXIMUM_ERROR, DB_VERSION_HIGHER_THAN_MAXIMUM_WARNING } zbx_db_version_status_t; typedef enum { /* db extension error codes shared with FRONTEND */ ZBX_EXT_ERR_UNDEFINED = 0, ZBX_EXT_SUCCEED = 1, /* ZBX_TIMESCALEDB_POSTGRES_TOO_OLD, obsoleted since Zabbix 7.0 */ ZBX_TIMESCALEDB_VERSION_FAILED_TO_RETRIEVE = 3, ZBX_TIMESCALEDB_VERSION_LOWER_THAN_MINIMUM, ZBX_TIMESCALEDB_VERSION_NOT_SUPPORTED, ZBX_TIMESCALEDB_VERSION_HIGHER_THAN_MAXIMUM, ZBX_TIMESCALEDB_LICENSE_NOT_COMMUNITY } zbx_db_ext_err_code_t; struct zbx_db_version_info_t { /* information about database server */ const char *database; zbx_uint32_t current_version; zbx_uint32_t min_version; zbx_uint32_t max_version; zbx_uint32_t min_supported_version; char *friendly_current_version; const char *friendly_min_version; const char *friendly_max_version; const char *friendly_min_supported_version; zbx_db_version_status_t flag; int history_pk; /* information about database server extension */ char *extension; zbx_uint32_t ext_current_version; zbx_uint32_t ext_min_version; zbx_uint32_t ext_max_version; zbx_uint32_t ext_min_supported_version; char *ext_friendly_current_version; const char *ext_friendly_min_version; const char *ext_friendly_max_version; const char *ext_friendly_min_supported_version; zbx_db_version_status_t ext_flag; zbx_db_ext_err_code_t ext_err_code; int history_compressed_chunks; int trends_compressed_chunks; }; #ifdef HAVE_POSTGRESQL void zbx_tsdb_info_extract(struct zbx_db_version_info_t *version_info); void zbx_tsdb_set_compression_availability(int compression_availabile); int zbx_tsdb_get_compression_availability(void); void zbx_tsdb_extract_compressed_chunk_flags(struct zbx_db_version_info_t *version_info); #endif int zbx_db_version_check(const char *database, zbx_uint32_t current_version, zbx_uint32_t min_version, zbx_uint32_t max_version, zbx_uint32_t min_supported_version); void zbx_db_version_json_create(struct zbx_json *json, struct zbx_db_version_info_t *info); #if defined(HAVE_MYSQL) # define ZBX_DB_TIMESTAMP() "unix_timestamp()" # define ZBX_DB_CHAR_LENGTH(str) "char_length(" #str ")" #elif defined(HAVE_POSTGRESQL) # define ZBX_DB_TIMESTAMP() "cast(extract(epoch from now()) as int)" # define ZBX_DB_CHAR_LENGTH(str) "char_length(" #str ")" #else # define ZBX_DB_TIMESTAMP() "cast(strftime('%s', 'now') as integer)" # define ZBX_DB_CHAR_LENGTH(str) "length(" #str ")" #endif #define ZBX_DB_CONNECT_NORMAL 0 #define ZBX_DB_CONNECT_EXIT 1 #define ZBX_DB_CONNECT_ONCE 2 ZBX_CONST_PTR_VECTOR_DECL(const_db_field_ptr, const zbx_db_field_t *) ZBX_PTR_VECTOR_DECL(db_value_ptr, zbx_db_value_t *) typedef struct { /* database connection */ zbx_dbconn_t *db; /* the target table */ const zbx_db_table_t *table; /* the fields to insert (pointers to the zbx_db_field_t structures from database schema) */ zbx_vector_const_db_field_ptr_t fields; /* the values rows to insert (pointers to arrays of zbx_db_value_t structures) */ zbx_vector_db_value_ptr_t rows; /* index of autoincrement field */ int autoincrement; /* number of rows to cache before flushing (inserting), 0 - no limit */ int batch_size; /* the last id assigned by autoincrement */ zbx_uint64_t lastid; } zbx_db_insert_t; void zbx_init_library_db(zbx_db_config_t *config); void zbx_deinit_library_db(zbx_db_config_t *config); zbx_dbconn_t *zbx_dbconn_create(void); void zbx_dbconn_free(zbx_dbconn_t *db); int zbx_dbconn_set_connect_options(zbx_dbconn_t *db, int options); void zbx_dbconn_set_autoincrement(zbx_dbconn_t *db, int options); int zbx_dbconn_open(zbx_dbconn_t *db); void zbx_dbconn_close(zbx_dbconn_t *db); int zbx_dbconn_execute(zbx_dbconn_t *db, const char *fmt, ...); int zbx_dbconn_vexecute(zbx_dbconn_t *db, const char *fmt, va_list args); zbx_db_result_t zbx_dbconn_vselect(zbx_dbconn_t *db, const char *fmt, va_list args); zbx_db_result_t zbx_dbconn_select(zbx_dbconn_t *db, const char *fmt, ...); zbx_db_result_t zbx_dbconn_select_n(zbx_dbconn_t *db, const char *query, int n); zbx_db_row_t zbx_db_fetch(zbx_db_result_t result); void zbx_db_free_result(zbx_db_result_t result); int zbx_dbconn_begin(zbx_dbconn_t *db); int zbx_dbconn_commit(zbx_dbconn_t *db); int zbx_dbconn_rollback(zbx_dbconn_t *db); int zbx_dbconn_end(zbx_dbconn_t *db, int ret); zbx_uint64_t zbx_dbconn_get_maxid_num(zbx_dbconn_t *db, const char *tablename, int num); /* bulk insert support */ void zbx_dbconn_prepare_insert_dyn(zbx_dbconn_t *db, zbx_db_insert_t *db_insert, const zbx_db_table_t *table, const zbx_db_field_t * const *fields, int fields_num); void zbx_dbconn_prepare_vinsert(zbx_dbconn_t *db, zbx_db_insert_t *db_insert, const char *table, va_list args); void zbx_dbconn_prepare_insert(zbx_dbconn_t *db, zbx_db_insert_t *db_insert, const char *table, ...); void zbx_db_insert_add_values(zbx_db_insert_t *db_insert, ...); void zbx_db_insert_add_values_dyn(zbx_db_insert_t *db_insert, zbx_db_value_t **values, int values_num); int zbx_db_insert_execute(zbx_db_insert_t *db_insert); void zbx_db_insert_autoincrement(zbx_db_insert_t *db_insert, const char *field_name); zbx_uint64_t zbx_db_insert_get_lastid(zbx_db_insert_t *self); void zbx_db_insert_clean(zbx_db_insert_t *db_insert); void zbx_db_insert_set_batch_size(zbx_db_insert_t *self, int batch_size); void zbx_dbconn_extract_version_info(zbx_dbconn_t *db, struct zbx_db_version_info_t *version_info); const char *zbx_dbconn_last_strerr(zbx_dbconn_t *db); zbx_err_codes_t zbx_dbconn_last_errcode(zbx_dbconn_t *db); zbx_db_config_t *zbx_db_config_create(void); void zbx_db_config_free(zbx_db_config_t *config); int zbx_dbconn_lock_record(zbx_dbconn_t *db, const char *table, zbx_uint64_t id, const char *add_field, zbx_uint64_t add_id); int zbx_dbconn_lock_records(zbx_dbconn_t *db, const char *table, const zbx_vector_uint64_t *ids); int zbx_dbconn_lock_ids(zbx_dbconn_t *db, const char *table_name, const char *field_name, zbx_vector_uint64_t *ids); int zbx_db_config_validate_features(zbx_db_config_t *config, unsigned char program_type); void zbx_db_config_validate(zbx_db_config_t *config); int zbx_dbconn_check_extension(zbx_dbconn_t *db, struct zbx_db_version_info_t *info, int allow_unsupported); #if defined(HAVE_POSTGRESQL) void zbx_dbconn_tsdb_extract_compressed_chunk_flags(zbx_dbconn_t *db, struct zbx_db_version_info_t *version_info); void zbx_dbconn_tsdb_info_extract(zbx_dbconn_t *db, struct zbx_db_version_info_t *version_info); int zbx_dbconn_tsdb_get_version(zbx_dbconn_t *db); #endif int zbx_dbconn_table_exists(zbx_dbconn_t *db, const char *table_name); int zbx_dbconn_field_exists(zbx_dbconn_t *db, const char *table_name, const char *field_name); #if !defined(HAVE_SQLITE3) int zbx_dbconn_trigger_exists(zbx_dbconn_t *db, const char *table_name, const char *trigger_name); int zbx_dbconn_index_exists(zbx_dbconn_t *db, const char *table_name, const char *index_name); int zbx_dbconn_pk_exists(zbx_dbconn_t *db, const char *table_name); #endif void zbx_dbconn_select_uint64(zbx_dbconn_t *db, const char *sql, zbx_vector_uint64_t *ids); int zbx_dbconn_prepare_multiple_query(zbx_dbconn_t *db, const char *query, const char *field_name, zbx_vector_uint64_t *ids, char **sql, size_t *sql_alloc, size_t *sql_offset); int zbx_dbconn_execute_multiple_query(zbx_dbconn_t *db, const char *query, const char *field_name, zbx_vector_uint64_t *ids); char *zbx_db_dyn_escape_field(const char *table_name, const char *field_name, const char *src); char *zbx_db_dyn_escape_string(const char *src); char *zbx_db_dyn_escape_string_len(const char *src, size_t length); void zbx_db_add_condition_alloc(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *fieldname, const zbx_uint64_t *values, const int num); void zbx_db_add_str_condition_alloc(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *fieldname, const char * const *values, const int num); const zbx_db_table_t *zbx_db_get_table(const char *tablename); const zbx_db_field_t *zbx_db_get_field(const zbx_db_table_t *table, const char *fieldname); int zbx_db_validate_field_size(const char *tablename, const char *fieldname, const char *str); #define zbx_db_get_maxid(table) zbx_db_get_maxid_num(table, 1) zbx_uint64_t zbx_db_get_maxid_num(const char *tablename, int num); int zbx_db_get_row_num(zbx_db_result_t result); int zbx_db_is_null(const char *field); #if defined(HAVE_POSTGRESQL) char *zbx_db_get_schema_esc(void); #endif int zbx_dbconn_execute_overflowed_sql(zbx_dbconn_t *db, char **sql, size_t *sql_alloc, size_t *sql_offset); int zbx_dbconn_flush_overflowed_sql(zbx_dbconn_t *db, char *sql, size_t sql_offset); const char *zbx_db_sql_id_ins(zbx_uint64_t id); const char *zbx_db_sql_id_cmp(zbx_uint64_t id); void zbx_db_check_character_set(void); /* large query support */ #define ZBX_DB_LARGE_QUERY_BATCH_SIZE 1000 #define ZBX_DB_LARGE_INSERT_BATCH_SIZE 10000 typedef enum { ZBX_DB_LARGE_QUERY_UI64, ZBX_DB_LARGE_QUERY_STR } zbx_db_large_query_type_t; typedef struct { zbx_db_large_query_type_t type; char **sql; size_t *sql_alloc; size_t *sql_offset; size_t sql_reset; const char *field; int offset; char *suffix; union { const zbx_vector_uint64_t *ui64; const zbx_vector_str_t *str; } ids; zbx_db_result_t result; zbx_dbconn_t *db; } zbx_db_large_query_t; void zbx_dbconn_large_query_prepare_uint(zbx_db_large_query_t *query, zbx_dbconn_t *db, char **sql, size_t *sql_alloc, size_t *sql_offset, const char *field, const zbx_vector_uint64_t *ids); void zbx_dbconn_large_query_prepare_str(zbx_db_large_query_t *query, zbx_dbconn_t *db, char **sql, size_t *sql_alloc, size_t *sql_offset, const char *field, const zbx_vector_str_t *ids); zbx_db_row_t zbx_db_large_query_fetch(zbx_db_large_query_t *query); void zbx_db_large_query_clear(zbx_db_large_query_t *query); void zbx_dbconn_large_query_append_sql(zbx_db_large_query_t *query, const char *sql); /* compatibility wrappers */ void zbx_db_init_autoincrement_options(void); int zbx_db_connect(int flag); void zbx_db_close(void); void zbx_db_begin(void); int zbx_db_commit(void); void zbx_db_rollback(void); int zbx_db_end(int ret); int zbx_db_execute(const char *fmt, ...); int zbx_db_execute_once(const char *fmt, ...); zbx_db_result_t zbx_db_select(const char *fmt, ...); zbx_db_result_t zbx_db_vselect(const char *fmt, va_list args); zbx_db_result_t zbx_db_select_n(const char *query, int n); void zbx_db_insert_prepare_dyn(zbx_db_insert_t *db_insert, const zbx_db_table_t *table, const zbx_db_field_t **fields, int fields_num); void zbx_db_insert_prepare(zbx_db_insert_t *self, const char *table, ...); void zbx_db_extract_version_info(struct zbx_db_version_info_t *version_info); const char *zbx_db_last_strerr(void); zbx_err_codes_t zbx_db_last_errcode(void); int zbx_db_lock_record(const char *table, zbx_uint64_t id, const char *add_field, zbx_uint64_t add_id); int zbx_db_lock_records(const char *table, const zbx_vector_uint64_t *ids); int zbx_db_lock_ids(const char *table_name, const char *field_name, zbx_vector_uint64_t *ids); int zbx_db_check_extension(struct zbx_db_version_info_t *info, int allow_unsupported); int zbx_db_flush_overflowed_sql(char *sql, size_t sql_offset); int zbx_db_execute_overflowed_sql(char **sql, size_t *sql_alloc, size_t *sql_offset); int zbx_db_table_exists(const char *table_name); int zbx_db_field_exists(const char *table_name, const char *field_name); #if !defined(HAVE_SQLITE3) int zbx_db_trigger_exists(const char *table_name, const char *trigger_name); int zbx_db_index_exists(const char *table_name, const char *index_name); int zbx_db_pk_exists(const char *table_name); #endif void zbx_db_select_uint64(const char *sql, zbx_vector_uint64_t *ids); int zbx_db_prepare_multiple_query(const char *query, const char *field_name, zbx_vector_uint64_t *ids, char **sql, size_t *sql_alloc, size_t *sql_offset); int zbx_db_execute_multiple_query(const char *query, const char *field_name, zbx_vector_uint64_t *ids); void zbx_db_large_query_prepare_uint(zbx_db_large_query_t *query, char **sql, size_t *sql_alloc, size_t *sql_offset, const char *field, const zbx_vector_uint64_t *ids); void zbx_db_large_query_prepare_str(zbx_db_large_query_t *query, char **sql, size_t *sql_alloc, size_t *sql_offset, const char *field, const zbx_vector_str_t *ids); void zbx_db_large_query_append_sql(zbx_db_large_query_t *query, const char *sql); #endif