3815 lines
148 KiB
C
3815 lines
148 KiB
C
/*****************************************************************************
|
||
* @copyright 2024-2024, . POWER SUPPLY CO., LTD.
|
||
* @file kit_db.c
|
||
* @brief sqlite3数据库操作方法
|
||
* @author Gary
|
||
* @date 2024/09/10
|
||
* @remark 去掉sqlite3_get_table即将过期的方法,补充了设备、协议和点位表的查询方法
|
||
*****************************************************************************/
|
||
#include <string.h>
|
||
#include <dirent.h>
|
||
#include <sys/stat.h>
|
||
#include <pthread.h>
|
||
#include "utextend.h"
|
||
#include "kit_log.h"
|
||
#include "kit_string.h"
|
||
#include "kit_db.h"
|
||
|
||
#define CONFIG_SQLITE_PATH "/opt/company_ems/db/sqlite3.db" // 配置数据库
|
||
#define BUSINESS_SQLITE_PATH "/opt/company_ems/db/business.db" // 业务数据库
|
||
|
||
static sqlite3 *config_db; // 全局变量,数据库句柄
|
||
static sqlite3 *business_db; // 全局变量,业务数据库句柄
|
||
|
||
pthread_mutex_t config_db_mutex = PTHREAD_MUTEX_INITIALIZER; // 全局变量,配置数据库线程锁
|
||
pthread_mutex_t business_db_mutex = PTHREAD_MUTEX_INITIALIZER; // 全局变量,业务数据库线程锁
|
||
|
||
// 设备配置信息icd
|
||
static UT_icd ems_dev_config_icd =
|
||
{
|
||
sizeof(ems_dev_config_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 设备信息的icd
|
||
static UT_icd dev_icd =
|
||
{
|
||
sizeof(dev_info_t), // 设备结构体大小
|
||
NULL, // 初始化函数
|
||
NULL, // 复制函数
|
||
NULL, // 销毁函数
|
||
};
|
||
|
||
// 点位信息icd
|
||
static UT_icd point_icd =
|
||
{
|
||
sizeof(point_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 时序数据的icd
|
||
static UT_icd timed_data_config_icd =
|
||
{
|
||
sizeof(timed_data_config_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 故障数据的icd
|
||
static UT_icd faults_data_config_icd =
|
||
{
|
||
sizeof(faults_data_config_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 北向配置信息icd
|
||
static UT_icd north_config_icd =
|
||
{
|
||
sizeof(north_config_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 削峰填谷日期配置信息icd
|
||
static UT_icd pv_date_config_icd =
|
||
{
|
||
sizeof(pv_date_config_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 设备拓扑结构信息icd
|
||
static UT_icd topology_icd =
|
||
{
|
||
sizeof(topology_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
static UT_icd advanced_setting_icd =
|
||
{
|
||
sizeof(advanced_setting_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// MQTT断点记录信息icd
|
||
static UT_icd break_record_icd =
|
||
{
|
||
sizeof(break_record_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// DIDO逻辑设置信息的icd
|
||
static UT_icd di_do_logic_set_icd =
|
||
{
|
||
sizeof(di_do_logic_set_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
/*****************************************************************************
|
||
* @brief 检查文件夹是否存在
|
||
* @param[in] path:文件夹路径
|
||
* @return 存在-true,不存在-false
|
||
*****************************************************************************/
|
||
static bool file_exists(const char *const path)
|
||
{
|
||
struct stat buf = {0};
|
||
if (-1 != stat(path, &buf) && S_ISDIR(buf.st_mode))
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 拼接路径,将源路径拼接到目标路径的指定位置
|
||
* @param[in] dst: 目标路径字符串
|
||
* @param[in] offset: 拼接的起始位置(即从目标路径的何处开始拼接)
|
||
* @param[in] max_size: 目标路径的最大长度(缓冲区大小)
|
||
* @param[in] src: 源路径字符串
|
||
* @return 返回拼接后的路径长度;如果拼接失败,则返回 -1
|
||
*****************************************************************************/
|
||
static int path_cat(char *dst, int offset, int max_size, const char *src)
|
||
{
|
||
int len = strlen(src);
|
||
// 检查目标缓冲区是否足够容纳新拼接的路径
|
||
if (offset + len >= max_size)
|
||
{
|
||
return -1;
|
||
}
|
||
// 将源路径复制到目标路径的指定位置
|
||
strcpy(dst + offset, src);
|
||
return offset + len;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 读取文件内容并存储为字符串
|
||
* @param[in] path: 文件路径
|
||
* @param[out] sql: 指向读取的字符串的指针,内存由该函数分配,调用者需负责释放
|
||
* @return 0 表示成功,非 0 表示失败
|
||
*****************************************************************************/
|
||
static int read_file_string(const char *path, char **sql)
|
||
{
|
||
FILE *fp = fopen(path, "r");
|
||
if (fp == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "打开文件'%s'失败", path);
|
||
return 1; // 打开文件失败
|
||
}
|
||
|
||
// 获取文件大小
|
||
fseek(fp, 0, SEEK_END);
|
||
long size = ftell(fp);
|
||
rewind(fp);
|
||
|
||
// 分配足够的内存来存储文件内容
|
||
*sql = malloc(size + 1);
|
||
if (*sql == NULL)
|
||
{
|
||
fclose(fp);
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1; // 内存分配失败
|
||
}
|
||
|
||
// 读取文件内容到内存中并检查读取结果
|
||
size_t read_size = fread(*sql, 1, size, fp);
|
||
if (read_size != size)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "读取文件内容失败");
|
||
free(*sql);
|
||
fclose(fp);
|
||
return 1; // 读取文件内容失败
|
||
}
|
||
|
||
(*sql)[size] = '\0'; // 添加字符串终止符
|
||
|
||
fclose(fp);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 判断字符串是否以指定后缀结尾
|
||
* @param[in] str: 要检查的字符串
|
||
* @param[in] suffix: 指定的后缀
|
||
* @return 如果字符串以指定后缀结尾则返回 true,否则返回 false
|
||
*****************************************************************************/
|
||
static bool ends_with(const char *str, const char *suffix)
|
||
{
|
||
// 如果字符串的长度小于后缀的长度,直接返回 false
|
||
if (strlen(str) < strlen(suffix))
|
||
{
|
||
return false;
|
||
}
|
||
// 比较字符串的结尾部分与后缀是否相等
|
||
return strcmp(str + strlen(str) - strlen(suffix), suffix) == 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 比较两个 schema 文件名,用于排序
|
||
* @param[in] a: 第一个文件名
|
||
* @param[in] b: 第二个文件名
|
||
* @return 比较结果,用于排序函数
|
||
*****************************************************************************/
|
||
static int schema_sort_cmp(const void *a, const void *b)
|
||
{
|
||
return strcmp(*(char **)a, *(char **)b);
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 收集目录中的所有 SQL 文件
|
||
* @param[in] dir: 目录路径
|
||
* @return 包含所有 SQL 文件名的 UT_array 指针;如果失败,则返回 NULL
|
||
*****************************************************************************/
|
||
static UT_array *collect_schemas(const char *dir)
|
||
{
|
||
DIR *dirp = NULL;
|
||
struct dirent *dent = NULL;
|
||
UT_array *files = NULL;
|
||
|
||
// 打开目录
|
||
if ((dirp = opendir(dir)) == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "文件夹打开失败: %s", dir);
|
||
return NULL;
|
||
}
|
||
|
||
// 初始化 UT_array 用于存储文件名
|
||
utarray_new(files, &ut_str_icd);
|
||
|
||
// 遍历目录中的所有文件,筛选出以 ".sql" 结尾的文件
|
||
while (NULL != (dent = readdir(dirp)))
|
||
{
|
||
if (ends_with(dent->d_name, ".sql"))
|
||
{
|
||
char *file = strdup(dent->d_name); // strdup 自动分配并拷贝字符串
|
||
if (file == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "strdup 失败");
|
||
continue;
|
||
}
|
||
// 将副本指针推入 UT_array
|
||
utarray_push_back(files, &file);
|
||
}
|
||
}
|
||
|
||
// 关闭目录
|
||
closedir(dirp);
|
||
return files;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 执行目录中的所有 SQL 文件
|
||
* @param[in] dir: 存储 SQL 文件的目录路径
|
||
* @param[in] db: 数据库句柄
|
||
* @return 0 表示成功,非 0 表示失败
|
||
*****************************************************************************/
|
||
static int execute_sql_files(const char *dir, sqlite3 *db)
|
||
{
|
||
char *sql = NULL;
|
||
int ret = 0;
|
||
|
||
if (!file_exists(dir))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "sql 文件 `%s` 不存在", dir);
|
||
return 1;
|
||
}
|
||
|
||
// 获取目录下的所有 SQL 文件
|
||
UT_array *files = collect_schemas(dir);
|
||
if (NULL == files)
|
||
{
|
||
return 1; // 目录读取失败
|
||
}
|
||
|
||
// 对文件名进行排序
|
||
utarray_sort(files, schema_sort_cmp);
|
||
|
||
// 遍历每个 SQL 文件
|
||
utarray_foreach(files, char **, file)
|
||
{
|
||
char *path = NULL;
|
||
path = calloc(PATH_MAX_SIZE, sizeof(char));
|
||
if (NULL == path)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1;
|
||
}
|
||
|
||
// 拼接文件路径
|
||
if (PATH_MAX_SIZE <= path_cat(path, 0, PATH_MAX_SIZE, dir) ||
|
||
PATH_MAX_SIZE <= path_cat(path, strlen(dir), PATH_MAX_SIZE, *file))
|
||
{ // 修正了路径拼接问题
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "路径过长: %s", path);
|
||
free(path);
|
||
return 1;
|
||
}
|
||
|
||
// 读取 SQL 文件内容
|
||
ret = read_file_string(path, &sql);
|
||
if (0 != ret)
|
||
{
|
||
free(path);
|
||
continue; // 读取失败,跳过该文件
|
||
}
|
||
|
||
// 执行 SQL 语句
|
||
char *err_msg = NULL;
|
||
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
|
||
if (SQLITE_OK != ret)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "执行 %s 失败: (%d)%s", path, ret, err_msg);
|
||
sqlite3_free(err_msg);
|
||
ret = 1;
|
||
free(path);
|
||
free(sql);
|
||
continue;
|
||
}
|
||
|
||
free(path);
|
||
free(sql);
|
||
}
|
||
|
||
// 释放文件列表内存
|
||
utarray_free(files);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 初始化 SQLite 数据库
|
||
* @param[in] schema_dir: 存储 SQL 文件的目录路径
|
||
* @param[in] db: 待初始化数据库
|
||
* @return 0 表示成功,1 表示失败
|
||
*****************************************************************************/
|
||
static int init_db_handle(const char *schema_dir, sqlite3 *db)
|
||
{
|
||
int ret = 0;
|
||
|
||
// 设置忙时超时时间
|
||
ret = sqlite3_busy_timeout(db, 120 * 1000);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "设置忙时超时失败: %s", sqlite3_errmsg(db));
|
||
sqlite3_close(db);
|
||
return 1;
|
||
}
|
||
|
||
// 启用外键支持
|
||
ret = sqlite3_exec(db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "数据库外键启动失败: %s", sqlite3_errmsg(db));
|
||
sqlite3_close(db);
|
||
return 1;
|
||
}
|
||
|
||
// 设置 WAL 模式
|
||
ret = sqlite3_exec(db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "数据库 journal_mode WAL 启动失败: %s", sqlite3_errmsg(db));
|
||
sqlite3_close(db);
|
||
return 1;
|
||
}
|
||
|
||
#ifdef INIT_DB
|
||
// 执行目录中的所有 SQL 文件
|
||
ret = execute_sql_files(schema_dir, db);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "执行 SQL 文件失败");
|
||
sqlite3_close(db);
|
||
return 1;
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据北向上报下发设备Id获取点位信息
|
||
* @param[in] upDisDevDbId: 上报下发设备Id
|
||
* @param[out] p_upDisDev: 用于存储北向配置信息的指针, 包含上报点位和下发设备信息
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
static int kit_get_updis_dev_point(int upDisDevDbId, up_dis_dev_t *p_upDisDev)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = "SELECT udd.dev_type, d.code, udp.cloud_code, "
|
||
"udp.cloud_name, udp.point_code "
|
||
"FROM up_dis_dev udd "
|
||
"LEFT JOIN device d ON udd.dev_id = d.id "
|
||
"LEFT JOIN up_dis_point udp ON udd.id = udp.up_dis_id "
|
||
"WHERE udd.id = ?";
|
||
|
||
if (sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL) != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询失败: %s", sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
if (sqlite3_bind_int(stmt, 1, upDisDevDbId) != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定upDisDevDbId失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
int step;
|
||
while ((step = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
up_dis_point_t *temp = realloc(p_upDisDev->upDisPointArr, (p_upDisDev->upDisPointNum + 1) * sizeof(up_dis_point_t));
|
||
if (temp == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
ret = 1;
|
||
break;
|
||
}
|
||
p_upDisDev->upDisPointArr = temp;
|
||
up_dis_point_t *point = &p_upDisDev->upDisPointArr[p_upDisDev->upDisPointNum++];
|
||
point->devType = (dev_type_e)sqlite3_column_int(stmt, 0);
|
||
point->devId = sqlite3_column_int(stmt, 1);
|
||
snprintf((char *)point->cloudCode, MAX_CODE_BUF_LEN, "%s", sqlite3_column_text(stmt, 2));
|
||
snprintf((char *)point->cloudName, MAX_NAME_BUF_LEN, "%s", sqlite3_column_text(stmt, 3));
|
||
point->pointId = sqlite3_column_int(stmt, 4);
|
||
}
|
||
|
||
if (step != SQLITE_DONE && ret == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询上报下发点位信息失败: %s", sqlite3_errmsg(config_db));
|
||
ret = 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据北向配置ID获取上报下发配置信息
|
||
* @param[in] northConfigDbId: 北向配置表数据库ID
|
||
* @param[out] northConfig: 用于存储北向配置信息的指针, 包含上报点位和下发点位信息
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
static int kit_get_north_config_by_id(int northConfigDbId, north_config_t *northConfig)
|
||
{
|
||
int ret = 0;
|
||
int upDisDevId;
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = "SELECT udd.up_dis_config_type, udd.dev_type, d.code, "
|
||
"udd.id "
|
||
"FROM up_dis_dev udd "
|
||
"LEFT JOIN device d ON udd.dev_id = d.id "
|
||
"WHERE udd.north_config_id = ?";
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL)) // config_db: 全局数据库连接
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
// 绑定参数到预编译语句
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt, 1, northConfigDbId))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 northConfigId 失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step)
|
||
{
|
||
// 获取上报下发配置类型
|
||
up_dis_config_type_e upDisConfigType = sqlite3_column_int(stmt, 0);
|
||
|
||
// 根据配置类型分配内存并存储点位信息
|
||
switch (upDisConfigType)
|
||
{
|
||
case kUp_Dis_Cfg_Type_Up: // 上报点位
|
||
northConfig->upDevNum++;
|
||
// 分配内存以存储新的上报设备信息
|
||
up_dis_dev_t *tempUp = (up_dis_dev_t *)realloc(northConfig->upDevArr, northConfig->upDevNum * sizeof(up_dis_dev_t));
|
||
if (tempUp == NULL)
|
||
{
|
||
// 内存分配失败,记录错误信息并返回
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
ret = 1;
|
||
goto error;
|
||
}
|
||
northConfig->upDevArr = tempUp;
|
||
// 获取上报配置信息
|
||
northConfig->upDevArr[northConfig->upDevNum - 1].devType = (dev_type_e)sqlite3_column_int(stmt, 1); // 设备类型
|
||
northConfig->upDevArr[northConfig->upDevNum - 1].devId = sqlite3_column_int(stmt, 2); // 设备编号
|
||
upDisDevId = sqlite3_column_int(stmt, 3); // 上报下发设备Id
|
||
kit_get_updis_dev_point(upDisDevId, &northConfig->upDevArr[northConfig->upDevNum - 1]);
|
||
break;
|
||
case kUp_Dis_Cfg_Type_Dis_Point: // 下发控制点位
|
||
northConfig->disDevNum++;
|
||
// 分配内存以存储新的下发设备信息
|
||
up_dis_dev_t *tempDis = (up_dis_dev_t *)realloc(northConfig->disDevArr, northConfig->disDevNum * sizeof(up_dis_dev_t));
|
||
if (tempDis == NULL)
|
||
{
|
||
// 内存分配失败,记录错误信息并返回
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
ret = 1;
|
||
goto error;
|
||
}
|
||
northConfig->disDevArr = tempDis;
|
||
// 获取下发配置信息
|
||
northConfig->disDevArr[northConfig->disDevNum - 1].devType = (dev_type_e)sqlite3_column_int(stmt, 1); // 设备类型
|
||
northConfig->disDevArr[northConfig->disDevNum - 1].devId = sqlite3_column_int(stmt, 2); // 设备编号
|
||
upDisDevId = sqlite3_column_int(stmt, 3); // 上报下发设备Id
|
||
kit_get_updis_dev_point(upDisDevId, &northConfig->disDevArr[northConfig->upDevNum - 1]);
|
||
break;
|
||
default:
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "未知的上报下发配置类型: %d", upDisConfigType);
|
||
ret = 1;
|
||
break;
|
||
}
|
||
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "填充上报下发信息失败");
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询上报下发配置信息失败: %s", sqlite3_errmsg(config_db));
|
||
ret = 1;
|
||
}
|
||
|
||
error:
|
||
// 清理资源
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/* ############################################################################### 配置数据库操作 ############################################################################### */
|
||
|
||
/*****************************************************************************
|
||
* @brief 初始化 SQLite 数据库
|
||
* @param[in] schema_dir: 存储 SQL 文件的目录路径
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_init_db(const char *schema_dir)
|
||
{
|
||
int ret = 0;
|
||
|
||
// 打开配置数据库,如果不存在则创建
|
||
// ret = sqlite3_open(CONFIG_SQLITE_PATH, &config_db);
|
||
ret = sqlite3_open_v2(CONFIG_SQLITE_PATH, &config_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_WAL, NULL);
|
||
if (SQLITE_OK != ret)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "打开数据库 `%s` 失败: %s", CONFIG_SQLITE_PATH, sqlite3_errstr(ret));
|
||
return 1;
|
||
}
|
||
char config_schema_dir[PATH_MAX_SIZE]; // 假设路径不会超过 PATH_MAX_SIZE 字符
|
||
snprintf(config_schema_dir, PATH_MAX_SIZE, "%s/config/", schema_dir);
|
||
ret = init_db_handle(config_schema_dir, config_db);
|
||
if (0 != ret)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "初始化数据库 `%s` 失败", CONFIG_SQLITE_PATH);
|
||
return 1;
|
||
}
|
||
|
||
// 打开业务数据库,如果不存在则创建
|
||
// ret = sqlite3_open(BUSINESS_SQLITE_PATH, &business_db);
|
||
ret = sqlite3_open_v2(BUSINESS_SQLITE_PATH, &business_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_WAL, NULL);
|
||
if (SQLITE_OK != ret)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "打开数据库 `%s` 失败: %s", BUSINESS_SQLITE_PATH, sqlite3_errstr(ret));
|
||
return 1;
|
||
}
|
||
char business_schema_dir[PATH_MAX_SIZE]; // 假设路径不会超过 PATH_MAX_SIZE 字符
|
||
snprintf(business_schema_dir, PATH_MAX_SIZE, "%s/business/", schema_dir);
|
||
ret = init_db_handle(business_schema_dir, business_db);
|
||
if (0 != ret)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "初始化数据库 `%s` 失败", BUSINESS_SQLITE_PATH);
|
||
return 1;
|
||
}
|
||
|
||
#ifdef INIT_DB
|
||
kit_sync_dev_data(); // 同步设备信息
|
||
kit_sync_point_data(); // 同步点位信息
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 释放 SQLite 数据库连接
|
||
* @return 0 表示成功,1 表示失败
|
||
*****************************************************************************/
|
||
int kit_uninit_db()
|
||
{
|
||
if (config_db != NULL)
|
||
{
|
||
sqlite3_close(config_db);
|
||
config_db = NULL;
|
||
return 0;
|
||
}
|
||
if (business_db != NULL)
|
||
{
|
||
sqlite3_close(business_db);
|
||
business_db = NULL;
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从 SQLite 数据库中获取数据表数据。使用准备好的语句(Prepared Statement)从 SQLite数据库中
|
||
* 获取数据表数据,避免使用 `sqlite3_get_table`,因为它是一个过时的接口,存在安全和性能问题。
|
||
* @param[out] outData: 用于存储查询结果的结构体指针。
|
||
* @param[in] tableName: 数据表名称。
|
||
* @param[in] columnsName: 要查询的列名数组,可以为 NULL 或空数组,表示查询所有列。
|
||
* @param[in] columnNum: 要查询的列名数量。
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_db_data(db_table_data_t *outData, const char *tableName, const char *columnsName[], int columnNum)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
int ret = 0;
|
||
char *sql = NULL;
|
||
char *sql_columns = NULL;
|
||
|
||
// 构建 SQL 查询语句
|
||
if (columnsName == NULL || columnNum == 0)
|
||
{
|
||
sql = sqlite3_mprintf("SELECT * FROM %s", tableName);
|
||
}
|
||
else
|
||
{
|
||
sql_columns = kit_join_text(columnNum, columnsName, ",");
|
||
if (sql_columns == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "构建列名失败");
|
||
return 1;
|
||
}
|
||
sql = sqlite3_mprintf("SELECT %s FROM %s", sql_columns, tableName);
|
||
free(sql_columns); // 释放拼接好的列名字符串
|
||
}
|
||
|
||
if (sql == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "构建 SQL 语句失败: sqlite3_mprintf 失败");
|
||
return 1;
|
||
}
|
||
|
||
// 准备 SQL 语句
|
||
sqlite3_free(sql); // 释放 SQL 字符串
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备语句失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt); // 结束语句
|
||
return 1;
|
||
}
|
||
|
||
// 获取查询结果
|
||
outData->nrow = 0;
|
||
outData->ncolumn = sqlite3_column_count(stmt); // 获取列数
|
||
|
||
// 如果有列,继续处理
|
||
if (outData->ncolumn > 0)
|
||
{
|
||
// 先检查有多少行
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
outData->nrow++;
|
||
}
|
||
|
||
// 如果没有找到行
|
||
if (outData->nrow == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, INFO_EN, "没有找到匹配的行");
|
||
sqlite3_finalize(stmt);
|
||
return 0;
|
||
}
|
||
|
||
// 为结果表分配内存
|
||
outData->dbresult = (char **)sqlite3_malloc(outData->nrow * outData->ncolumn * sizeof(char *));
|
||
if (outData->dbresult == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "分配结果表内存失败");
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 重置语句,重新开始读取
|
||
sqlite3_reset(stmt);
|
||
|
||
// 读取数据行并存储结果
|
||
int row = 0;
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
for (int i = 0; i < outData->ncolumn; i++)
|
||
{
|
||
const char *text = (const char *)sqlite3_column_text(stmt, i);
|
||
outData->dbresult[row * outData->ncolumn + i] = text ? sqlite3_mprintf("%s", text) : NULL;
|
||
}
|
||
row++;
|
||
}
|
||
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "执行语句失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// 结束语句
|
||
sqlite3_finalize(stmt);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 释放 `db_table_data_t` 结构体中分配的内存。
|
||
* 该函数用于释放 `kitGetDbData` 函数获取的查询结果数据所占用的内存。
|
||
* 它会依次释放 `dbresult`、`errmsg` 和 `db` 指针指向的内存。
|
||
* @param data 指向 `db_table_data_t` 结构体的指针。
|
||
*****************************************************************************/
|
||
void kit_free_table_data(db_table_data_t *data)
|
||
{
|
||
if (data == NULL)
|
||
{
|
||
// 如果 `data` 指针为空,则直接返回。
|
||
return;
|
||
}
|
||
|
||
// 释放 `dbresult` 指向的内存,如果 `dbresult` 不为空。
|
||
if (data->dbresult != NULL)
|
||
{
|
||
sqlite3_free_table(data->dbresult);
|
||
data->dbresult = NULL;
|
||
}
|
||
|
||
// 释放 `errmsg` 指向的内存,如果 `errmsg` 不为空。
|
||
if (data->errmsg != NULL)
|
||
{
|
||
sqlite3_free(data->errmsg);
|
||
data->errmsg = NULL;
|
||
}
|
||
|
||
// 函数执行完毕,返回。
|
||
return;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief: 执行多条 SQL 语句,函数内关闭连接。
|
||
* 该函数用于执行多个 SQL 语句,并处理执行过程中的错误。
|
||
* 它会依次执行传入的 SQL 语句数组,并在执行失败时记录错误信息。
|
||
* 函数执行完毕后会关闭数据库连接。
|
||
* @param[in] tableName: 数据表名称(未使用,可以忽略)。
|
||
* @param[in] sql: 包含多个 SQL 语句的字符串数组。
|
||
* @param[in] sql_num: SQL 语句的数量。
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_exec_db_data(char *tableName, char *sql[], int sql_num)
|
||
{
|
||
sqlite3 *db = NULL; // 数据库连接指针
|
||
int ret = 0; // sqlite3_exec 函数返回值
|
||
char *zErrMsg = 0; // 错误信息指针
|
||
|
||
// 循环执行每个 SQL 语句
|
||
for (int i = 0; i < sql_num; i++)
|
||
{
|
||
// printf("%s\n",sql[i]); // 可选:打印每个 SQL 语句
|
||
ret = sqlite3_exec(db, sql[i], NULL, 0, &zErrMsg);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "执行 SQL 语句[%d] 失败: %s.", i, zErrMsg);
|
||
sqlite3_free(zErrMsg); // 释放错误信息内存
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
sqlite3_free(zErrMsg); // 释放错误信息内存
|
||
return 0; // 返回执行结果标志
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库查询电站数据
|
||
* @param[in] p_station:电站信息的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_station_db_data(station_t *p_station)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT name, address, lng, lat, time_zone FROM station DESC LIMIT 1");
|
||
|
||
if (query == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1;
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (step == SQLITE_ROW)
|
||
{
|
||
snprintf((char *)p_station->name, MAX_NAME_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 0)); // 电站名称
|
||
snprintf((char *)p_station->address, MAX_ADDR_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 1)); // 电站地址
|
||
p_station->lng = sqlite3_column_double(stmt, 2); // 经度
|
||
p_station->lat = sqlite3_column_double(stmt, 3); // 纬度
|
||
snprintf((char *)p_station->timeZone, MAX_CODE_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 4)); // 时区
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return (step == SQLITE_ROW) ? 0 : 1; // 返回成功或失败代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取设备信息
|
||
* @param[out] devPointInfo: 用于存储设备信息的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_dev_db_data(UT_array **devPointInfo)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
utarray_new(*devPointInfo, &dev_icd); // 创建新的 UT_array 用于存储设备点位信息
|
||
|
||
// 构建查询语句
|
||
query = "SELECT id, type, code, protocol_type, name, "
|
||
"sort_order, template_id "
|
||
"FROM device WHERE 1=1 "; // 基础查询语句
|
||
// 添加结果排序
|
||
query = sqlite3_mprintf("%s ORDER BY type, protocol_type, id ASC", query); // 按 id 升序排序
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
dev_info_t dev_info = {0}; // 初始化设备点位结构体
|
||
dev_info.devDbId = sqlite3_column_int(stmt, 0);
|
||
dev_info.devType = sqlite3_column_int(stmt, 1);
|
||
dev_info.devId = sqlite3_column_int(stmt, 2);
|
||
dev_info.protocolType = sqlite3_column_int(stmt, 3);
|
||
snprintf((char *)dev_info.devName, MAX_NAME_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 4));
|
||
dev_info.sortOrder = sqlite3_column_int(stmt, 5);
|
||
dev_info.templateId = sqlite3_column_int(stmt, 6);
|
||
|
||
// 将设备点位信息添加到 UT_array 中
|
||
utarray_push_back(*devPointInfo, &dev_info);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*devPointInfo); // 释放 UT_array
|
||
devPointInfo = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 将 config_db 中的 device 表数据复制到 business_db 中的 device 表
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_sync_dev_data()
|
||
{
|
||
sqlite3_stmt *stmt_select = NULL; // 用于 SELECT 语句
|
||
sqlite3_stmt *stmt_insert = NULL; // 用于 INSERT 语句
|
||
const char *sql_delete;
|
||
const char *sql_select;
|
||
const char *sql_insert;
|
||
int ret;
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 给配置库操作上锁
|
||
pthread_mutex_lock(&business_db_mutex); // 给业务库操作上锁
|
||
|
||
// 清空 business_db 中的 device 表
|
||
sql_delete = "DELETE FROM device";
|
||
ret = sqlite3_exec(business_db, sql_delete, NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "清空 business_db 中的 device 表失败: %s", sqlite3_errmsg(business_db));
|
||
goto error;
|
||
}
|
||
|
||
// 从 config_db 中选择数据
|
||
sql_select = "SELECT id, sn, type, code, name, protocol_type, template_id, sort_order, remark, status FROM device";
|
||
ret = sqlite3_prepare_v2(config_db, sql_select, -1, &stmt_select, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", sql_select, sqlite3_errmsg(config_db));
|
||
goto error;
|
||
}
|
||
|
||
// 准备插入语句
|
||
sql_insert = "INSERT INTO device (id, sn, type, code, name, protocol_type, template_id, sort_order, remark, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||
ret = sqlite3_prepare_v2(business_db, sql_insert, -1, &stmt_insert, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备插入语句 `%s` 失败: %s", sql_insert, sqlite3_errmsg(business_db));
|
||
goto error;
|
||
}
|
||
|
||
// 循环插入数据
|
||
while ((ret = sqlite3_step(stmt_select)) == SQLITE_ROW)
|
||
{
|
||
// 绑定参数
|
||
sqlite3_bind_int(stmt_insert, 1, sqlite3_column_int(stmt_select, 0));
|
||
sqlite3_bind_text(stmt_insert, 2, (const char *)sqlite3_column_text(stmt_select, 1), -1, SQLITE_STATIC);
|
||
sqlite3_bind_int(stmt_insert, 3, sqlite3_column_int(stmt_select, 2));
|
||
sqlite3_bind_int(stmt_insert, 4, sqlite3_column_int(stmt_select, 3));
|
||
sqlite3_bind_text(stmt_insert, 5, (const char *)sqlite3_column_text(stmt_select, 4), -1, SQLITE_STATIC);
|
||
sqlite3_bind_int(stmt_insert, 6, sqlite3_column_int(stmt_select, 5));
|
||
sqlite3_bind_int(stmt_insert, 7, sqlite3_column_int(stmt_select, 6));
|
||
sqlite3_bind_int(stmt_insert, 8, sqlite3_column_int(stmt_select, 7));
|
||
sqlite3_bind_text(stmt_insert, 9, (const char *)sqlite3_column_text(stmt_select, 8), -1, SQLITE_STATIC);
|
||
sqlite3_bind_int(stmt_insert, 10, sqlite3_column_int(stmt_select, 9));
|
||
|
||
// 执行插入
|
||
ret = sqlite3_step(stmt_insert);
|
||
sqlite3_reset(stmt_insert); // 重置语句以进行下一次插入
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
// 检查是否有错误发生在sqlite3_step(stmt_select)中
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询数据失败: %s", sqlite3_errmsg(config_db));
|
||
goto error;
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt_select);
|
||
sqlite3_finalize(stmt_insert);
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 0;
|
||
|
||
error:
|
||
sqlite3_finalize(stmt_select);
|
||
sqlite3_finalize(stmt_insert);
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 1;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取协议信息。
|
||
* 该函数从数据库中获取与指定设备 ID 关联的协议信息。
|
||
* 它使用准备好的语句(Prepared Statement)来执行查询,并绑定设备 ID 参数。
|
||
* 函数会返回获取到的协议信息,并处理查询过程中的错误。
|
||
* @param[in] templateType: 模板类别(0设备配置, 1北向配置)。
|
||
* @param[in] relatedId: 关联数据库 ID。
|
||
* @param[out] protoContent: 用于存储协议信息的字符数组。
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_protocol_db_data(const template_type_e templateType, const uint64_t relatedId, char protoContent[MAX_CONFIG_CONTENT_LEN])
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
char *query = sqlite3_mprintf("SELECT content FROM protocol WHERE 1=1 AND template_type=? AND related_id=? LIMIT 1");
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query); // 释放查询字符串
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 绑定参数到预编译语句
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt, 1, templateType))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 template_type 失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query); // 释放查询字符串
|
||
return 1; // 返回错误代码
|
||
}
|
||
if (SQLITE_OK != sqlite3_bind_int64(stmt, 2, relatedId))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 related_id 失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query); // 释放查询字符串
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
if (step == SQLITE_ROW || step == SQLITE_DONE)
|
||
{
|
||
snprintf(protoContent, MAX_CONFIG_CONTENT_LEN, "%s", sqlite3_column_text(stmt, 0));
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query); // 释放查询字符串
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
sqlite3_free(query); // 释放查询字符串
|
||
return 0; // 成功返回
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取点位信息
|
||
* @param[in] templateId: 模板Id
|
||
* @param[out] points: 用于存储点位信息的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_point_db_data(const uint64_t templateId, UT_array **points)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
utarray_new(*points, &point_icd); // 创建新的 UT_array 用于存储设备点位信息
|
||
|
||
// 构建查询语句
|
||
query = "SELECT group_type, code, name, data_type, "
|
||
"attribute, func, reg_addr, bit_pos, bit_num, endian, "
|
||
"precision, ratio, offset, is_persisted, storage_interval, "
|
||
"mutate_bound, default_value, min_value, max_value, dev_type,id "
|
||
"FROM point WHERE 1=1 "; // 基础查询语句
|
||
|
||
// 检查并添加设备Id条件
|
||
query = sqlite3_mprintf("%s AND template_id=?", query); // 动态添加设备Id条件
|
||
|
||
// 添加结果排序
|
||
query = sqlite3_mprintf("%s ORDER BY func, reg_addr ASC", query); // 按 id 升序排序
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 绑定参数到预编译语句
|
||
int param_index = 1; // 参数索引
|
||
if (SQLITE_OK != sqlite3_bind_int64(stmt, param_index++, templateId))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 `%s` 的参数 dev_id 失败: %s", query, sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// printf("%s\n",query);
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
point_t point_info = {0}; // 初始化设备点位结构体
|
||
point_info.groupType = (point_group_type_e)sqlite3_column_int(stmt, 0);
|
||
point_info.pointId = (uint16_t)sqlite3_column_int(stmt, 1);
|
||
snprintf((char *)point_info.pointName, MAX_POINT_NAME_LEN, "%s", (const char *)sqlite3_column_text(stmt, 2));
|
||
point_info.dataType = (data_type_e)sqlite3_column_int(stmt, 3);
|
||
point_info.attribute = (point_attribute_e)sqlite3_column_int(stmt, 4);
|
||
point_info.func = (uint32_t)sqlite3_column_int(stmt, 5);
|
||
point_info.regAddr = (uint16_t)sqlite3_column_int(stmt, 6);
|
||
point_info.bitPos = (uint8_t)sqlite3_column_int(stmt, 7);
|
||
point_info.bitNum = (uint8_t)sqlite3_column_int(stmt, 8);
|
||
point_info.endian = (data_endian_e)sqlite3_column_int(stmt, 9);
|
||
point_info.precision = sqlite3_column_double(stmt, 10);
|
||
point_info.ratio = sqlite3_column_double(stmt, 11);
|
||
point_info.offset = sqlite3_column_double(stmt, 12);
|
||
point_info.isPersisted = (uint8_t)sqlite3_column_int(stmt, 13);
|
||
point_info.storageInterval = (storage_interval_type_e)sqlite3_column_int(stmt, 14);
|
||
point_info.mutateBound = sqlite3_column_double(stmt, 15);
|
||
point_info.defaultValue = sqlite3_column_double(stmt, 16);
|
||
point_info.minValue = sqlite3_column_double(stmt, 17);
|
||
point_info.maxValue = sqlite3_column_double(stmt, 18);
|
||
point_info.devType = sqlite3_column_int(stmt, 19);
|
||
point_info.pointDbId = sqlite3_column_int(stmt, 20);
|
||
// point_info.devDbId = sqlite3_column_int(stmt, 20);
|
||
|
||
// 将设备点位信息添加到 UT_array 中
|
||
utarray_push_back(*points, &point_info);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*points); // 释放 UT_array
|
||
points = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从 config_db 获取点位信息并同步到 business_db
|
||
* @param[out] 无
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_sync_point_data()
|
||
{
|
||
sqlite3_stmt *stmt_config = NULL; // config_db 中的预编译语句句柄
|
||
sqlite3_stmt *stmt_business = NULL; // business_db 中的预编译语句句柄
|
||
const char *query_config; // 从 config_db 查询点位信息的 SQL 语句
|
||
const char *query_clear = "DELETE FROM point"; // 清空 business_db 中的 point 表的 SQL 语句
|
||
int step; // 查询结果步骤
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 给配置库操作上锁
|
||
pthread_mutex_lock(&business_db_mutex); // 给业务库操作上锁
|
||
|
||
// 清空 business_db 中的 point 表
|
||
if (SQLITE_OK != sqlite3_exec(business_db, query_clear, NULL, NULL, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "清空 business_db 中的 point 表失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 1; // 处理错误
|
||
}
|
||
|
||
// 构建查询语句从 config_db 获取所有点位信息
|
||
query_config = "SELECT template_id, protocol_type, dev_type, group_type, code, name, "
|
||
"data_type, attribute, func, reg_addr, bit_pos, bit_num, endian, precision, "
|
||
"ratio, offset, is_persisted, storage_interval, mutate_bound, default_value, "
|
||
"min_value, max_value, unit, is_show FROM point ORDER BY id ASC";
|
||
|
||
// 准备从 config_db 执行查询语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query_config, -1, &stmt_config, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query_config, sqlite3_errmsg(config_db));
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 1; // 处理错误
|
||
}
|
||
|
||
// 准备向 business_db 插入数据的 SQL 语句
|
||
const char *insert_query = "INSERT INTO point (template_id, protocol_type, dev_type, group_type, "
|
||
"code, name, data_type, attribute, func, reg_addr, bit_pos, bit_num, endian, "
|
||
"precision, ratio, offset, is_persisted, storage_interval, mutate_bound, "
|
||
"default_value, min_value, max_value, unit, is_show) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||
|
||
// 准备向 business_db 插入数据
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, insert_query, -1, &stmt_business, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备插入 `%s` 失败: %s", insert_query, sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt_config); // 确保释放预编译语句
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 1; // 处理错误
|
||
}
|
||
|
||
// 执行查询并插入数据
|
||
step = sqlite3_step(stmt_config);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从 config_db 中获取每一列的值
|
||
int param_index = 1; // 参数索引
|
||
|
||
// 绑定参数到插入语句
|
||
if (SQLITE_OK != sqlite3_bind_int64(stmt_business, param_index++, sqlite3_column_int64(stmt_config, 0))) // template_id
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 1))) // protocol_type
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 2))) // dev_type
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 3))) // group_type
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 4))) // code
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_text(stmt_business, param_index++, sqlite3_column_text(stmt_config, 5), -1, SQLITE_STATIC)) // name
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 6))) // data_type
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 7))) // attribute
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 8))) // func
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 9))) // reg_addr
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 10))) // bit_pos
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 11))) // bit_num
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 12))) // endian
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 13))) // precision
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 14))) // ratio
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 15))) // offset
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 16))) // is_persisted
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 17))) // storage_interval
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 18))) // mutate_bound
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 19))) // default_value
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 20))) // min_value
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_double(stmt_business, param_index++, sqlite3_column_double(stmt_config, 21))) // max_value
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_text(stmt_business, param_index++, sqlite3_column_text(stmt_config, 22), -1, SQLITE_STATIC)) // unit
|
||
goto error;
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt_business, param_index++, sqlite3_column_int(stmt_config, 23))) // is_show
|
||
goto error;
|
||
|
||
// 执行插入操作
|
||
if (SQLITE_DONE != sqlite3_step(stmt_business))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
goto error;
|
||
}
|
||
|
||
// 重置插入语句以便于重新绑定参数
|
||
sqlite3_reset(stmt_business);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt_config);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt_config); // 释放 config_db 预编译语句
|
||
sqlite3_finalize(stmt_business); // 释放 business_db 预编译语句
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt_config); // 确保释放预编译语句
|
||
sqlite3_finalize(stmt_business); // 确保释放预编译语句
|
||
pthread_mutex_unlock(&config_db_mutex); // 给配置库操作释放锁
|
||
pthread_mutex_unlock(&business_db_mutex); // 给业务库操作释放锁
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取读取时序数据配置
|
||
* @param[out] timedDataConfigs: 用于指定存储间隔类型的的时序数据配置的数据
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_tdata_config(UT_array **timedDataConfigs)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT p.id, p.code, p.name, p.storage_interval, d.name, d.type, d.id, d.code FROM point p LEFT JOIN device d ON p.template_id = d.template_id ORDER BY p.storage_interval ASC");
|
||
int ret;
|
||
|
||
ret = sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1;
|
||
}
|
||
|
||
utarray_new(*timedDataConfigs, &timed_data_config_icd);
|
||
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
timed_data_config_t data_info = {0};
|
||
data_info.pointDbId = sqlite3_column_int(stmt, 0);
|
||
data_info.pointId = sqlite3_column_int(stmt, 1);
|
||
snprintf((char *)data_info.pointName, MAX_POINT_NAME_LEN, "%s", (const char *)sqlite3_column_text(stmt, 2));
|
||
data_info.storageInterval = (storage_interval_type_e)sqlite3_column_int(stmt, 3);
|
||
snprintf((char *)data_info.devName, MAX_NAME_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 4));
|
||
data_info.devType = sqlite3_column_int(stmt, 5);
|
||
data_info.devDbId = sqlite3_column_int(stmt, 6);
|
||
data_info.devId = sqlite3_column_int(stmt, 7);
|
||
|
||
utarray_push_back(*timedDataConfigs, &data_info);
|
||
}
|
||
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
utarray_free(*timedDataConfigs);
|
||
*timedDataConfigs = NULL;
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取故障点位配置
|
||
* @param[out] faultsDataConfigs: 用于存储故障配置点位的数据
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_faults_config(UT_array **faultsDataConfigs)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT p.id, p.code, p.name, d.name, d.type, d.id, d.code FROM point p LEFT JOIN device d ON p.template_id = d.template_id WHERE p.group_type = ? ORDER BY p.storage_interval ASC");
|
||
int ret;
|
||
|
||
ret = sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1;
|
||
}
|
||
|
||
// 绑定参数
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt, 1, kPoint_SOE))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 group_type 失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
utarray_new(*faultsDataConfigs, &faults_data_config_icd);
|
||
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
timed_data_config_t data_info = {0};
|
||
data_info.pointDbId = sqlite3_column_int(stmt, 0);
|
||
data_info.pointId = sqlite3_column_int(stmt, 1);
|
||
snprintf((char *)data_info.pointName, MAX_POINT_NAME_LEN, "%s", (const char *)sqlite3_column_text(stmt, 2));
|
||
snprintf((char *)data_info.devName, MAX_NAME_BUF_LEN, "%s", (const char *)sqlite3_column_text(stmt, 3));
|
||
data_info.devType = sqlite3_column_int(stmt, 4);
|
||
data_info.devDbId = sqlite3_column_int(stmt, 5);
|
||
data_info.devId = sqlite3_column_int(stmt, 6);
|
||
|
||
utarray_push_back(*faultsDataConfigs, &data_info);
|
||
}
|
||
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
utarray_free(*faultsDataConfigs);
|
||
*faultsDataConfigs = NULL;
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取EMS设备配置信息
|
||
* @param[out] emsDevConfigs: 用于设备配置信息的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_config_db_data(UT_array **emsDevConfigs)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
|
||
utarray_new(*emsDevConfigs, &ems_dev_config_icd); // 创建新的 UT_array 用于存储设备点位信息
|
||
|
||
// 构建查询语句
|
||
query = "SELECT id, type, content "
|
||
"FROM ems_device_config WHERE 1=1 "; // 基础查询语句
|
||
|
||
// 添加结果排序
|
||
query = sqlite3_mprintf("%s ORDER BY type ASC", query); // 按 type 升序排序
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
ems_dev_config_t dev_config = {0}; // 初始化设备配置结构体
|
||
dev_config.dbId = (uint16_t)sqlite3_column_int(stmt, 0);
|
||
dev_config.type = (ems_dev_config_type_e)sqlite3_column_int(stmt, 1);
|
||
snprintf((char *)dev_config.content, MAX_CONFIG_CONTENT_LEN, "%s", (const char *)sqlite3_column_text(stmt, 2));
|
||
|
||
// 将设备配置信息添加到 UT_array 中
|
||
utarray_push_back(*emsDevConfigs, &dev_config);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*emsDevConfigs); // 释放 UT_array
|
||
emsDevConfigs = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据指定配置类型Type从数据库获取 EMS 设备配置信息
|
||
* @param[in] type: 配置类型
|
||
* @param[out] emsDevConfig: 用于存储设备配置信息的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_config_by_type(ems_dev_config_type_e type, ems_dev_config_t *emsDevConfig)
|
||
{
|
||
int ret = 0; // 返回代码
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
|
||
// 构建查询语句
|
||
query = "SELECT content "
|
||
"FROM ems_device_config WHERE type = ? LIMIT 1"; // 根据 TYPE 查询
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt, 1, (int)type)) // 使用 sqlite3_bind_int
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 `%s` 的参数 type 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
if (SQLITE_ROW == step) // 如果找到结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
snprintf((char *)emsDevConfig->content, MAX_CONFIG_CONTENT_LEN, "%s", (const char *)sqlite3_column_text(stmt, 0));
|
||
}
|
||
else if (SQLITE_DONE == step) // 如果没有找到结果
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "未找到配置类型 Type 为 %d 的设备配置", type);
|
||
ret = 1; // 设置返回代码为失败
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
ret = 1; // 设置返回代码为失败
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return ret; // 返回结果
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据协议类型获取北向配置信息
|
||
* @param[out] northConfigs: 用于存储北向配置信息的数组, 使用 UT_array 存储
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_north_config_arr(UT_array **northConfigs)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *query = "SELECT nc.id, nc.protocol_type, nc.config_type "
|
||
"FROM north_config nc ";
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL)) // config_db: 全局数据库连接
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
KITPTF(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
utarray_new(*northConfigs, &north_config_icd); // 创建新的 UT_array 用于北向信息
|
||
|
||
// 执行查询
|
||
int step = sqlite3_step(stmt);
|
||
|
||
while (SQLITE_ROW == step)
|
||
{
|
||
north_config_t northConfig = {0};
|
||
// 获取北向配置信息
|
||
northConfig.dbId = sqlite3_column_int(stmt, 0);
|
||
northConfig.protocolType = (protocol_type_slave_e)sqlite3_column_int(stmt, 1);
|
||
northConfig.configType = (north_config_type_e)sqlite3_column_int(stmt, 2);
|
||
|
||
// 获取上报下发配置信息
|
||
ret = kit_get_north_config_by_id(sqlite3_column_int(stmt, 0), &northConfig);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "获取上报下发配置信息失败");
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 将北向配置信息添加到 UT_array 中
|
||
utarray_push_back(*northConfigs, &northConfig);
|
||
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询北向配置信息失败: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
|
||
error:
|
||
// 清理资源
|
||
sqlite3_finalize(stmt);
|
||
utarray_free(*northConfigs); // 释放 UT_array
|
||
northConfigs = NULL;
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 获取所有削峰填谷的日期配置
|
||
* @param[out] pvDateConfigs: 削峰填谷的日期配置数组, 使用 UT_array 存储
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_pv_date_cfg_db_data(UT_array **pvDateConfigs)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
// SQL 查询语句,获取 pv_date_config 表中的数据
|
||
const char *query = "SELECT pdc.pv_time_config_id, pdc.start_date, pdc.end_date "
|
||
"FROM pv_date_config pdc "
|
||
"ORDER BY pdc.start_date";
|
||
|
||
// 创建新的 UT_array 用于存储削峰填谷的日期配置, 使用 pv_date_config_icd 初始化
|
||
utarray_new(*pvDateConfigs, &pv_date_config_icd);
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL)) // global_db: 全局数据库连接
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt); // 执行查询
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
pv_date_config_t pv_date_config_info = {0}; // 削峰填谷的日期配置结构体
|
||
// 获取开始日期和结束日期
|
||
int snprintf_ret1 = snprintf((char *)pv_date_config_info.startDate, sizeof(pv_date_config_info.startDate), "%s", (const char *)sqlite3_column_text(stmt, 1));
|
||
int snprintf_ret2 = snprintf((char *)pv_date_config_info.endDate, sizeof(pv_date_config_info.endDate), "%s", (const char *)sqlite3_column_text(stmt, 2));
|
||
// 检查 snprintf 是否成功
|
||
if (snprintf_ret1 < 0 || snprintf_ret2 < 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "格式化日期失败");
|
||
goto error;
|
||
}
|
||
// 根据 pv_time_config_id 获取时间配置信息
|
||
if (kit_get_pv_time_cfg_db_data(sqlite3_column_int(stmt, 0), &pv_date_config_info) != 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "获取时间配置信息失败");
|
||
goto error;
|
||
}
|
||
// 将设备点位信息添加到 UT_array 中
|
||
utarray_push_back(*pvDateConfigs, &pv_date_config_info);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
|
||
return ret;
|
||
error:
|
||
// 处理查询过程中出现的错误
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*pvDateConfigs); // 释放 UT_array
|
||
pvDateConfigs = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据削峰填谷时间配置的数据库Id获取削峰填谷时间执行配置
|
||
* @param[in] pvTimeCfgDbId: 削峰填谷时间配置的数据库Id
|
||
* @param[out] pvDateConfig: 用于存储削峰填谷的日期配置, 包含一个 pv_time_config_t 类型的数组
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_pv_time_cfg_db_data(int pvDateCfgDbId, pv_date_config_t *pvDateConfig)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
// SQL 查询语句,根据 time_section_config_id 获取 pv_time_exe 表中的数据
|
||
char *query = "SELECT pte.start_time, pte.end_time, pte.power "
|
||
"FROM pv_time_exe pte "
|
||
"WHERE pte.time_section_config_id = ? "
|
||
"ORDER BY pte.start_time";
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL)) // config_db: 全局数据库连接
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
// 绑定参数
|
||
if (SQLITE_OK != sqlite3_bind_int(stmt, 1, pvDateCfgDbId))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定 pvDateCfgDbId 失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt); // 执行查询
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
pvDateConfig->timeCfgLen++;
|
||
// 重新分配内存以存储新的时间配置信息
|
||
pv_time_config_t *temp = (pv_time_config_t *)realloc(pvDateConfig->timeCfgTab, pvDateConfig->timeCfgLen * sizeof(pv_time_config_t));
|
||
if (temp == NULL)
|
||
{
|
||
// 内存分配失败,记录错误信息并返回
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
ret = 1;
|
||
goto error;
|
||
}
|
||
pvDateConfig->timeCfgTab = temp;
|
||
|
||
// 获取时间配置信息
|
||
pvDateConfig->timeCfgTab[pvDateConfig->timeCfgLen - 1].startTime = sqlite3_column_int(stmt, 0);
|
||
pvDateConfig->timeCfgTab[pvDateConfig->timeCfgLen - 1].endTime = sqlite3_column_int(stmt, 1);
|
||
// pvDateConfig->timeCfgTab[pvDateConfig->timeCfgLen - 1].workMode = sqlite3_column_int(stmt, 2);
|
||
pvDateConfig->timeCfgTab[pvDateConfig->timeCfgLen - 1].power = sqlite3_column_double(stmt, 2);
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查查询是否完成
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询削峰填谷时间配置执行信息失败: %s", sqlite3_errmsg(config_db));
|
||
ret = 1;
|
||
}
|
||
|
||
error:
|
||
// 清理资源
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 设置所有削峰填谷的日期配置
|
||
* @param[out] pvDateTimeConfigs: 削峰填谷的日期配置、时间配置数组, 使用 UT_array 存储
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_pv_date_time_cfg(UT_array **pvDateTimeConfigs)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt* stmt_date = NULL, * stmt_time = NULL, * stmt_exe = NULL;
|
||
// SQL 删除语句,删除 pv_date_config 表中的数据
|
||
const char* sql_delete_date = "DELETE FROM pv_date_config";
|
||
// SQL 查询语句,删除 pv_time_config 表中的数据
|
||
const char* sql_delete_time = "DELETE FROM pv_time_config";
|
||
// SQL 查询语句,删除 pv_time_exe 表中的数据
|
||
const char* sql_delete_exe = "DELETE FROM pv_time_exe";
|
||
// SQL 插入语句,插入 pv_date_config 表中的数据
|
||
const char* sql_insert_date = "INSERT INTO pv_date_config(pv_time_config_id, start_date, end_date, remark) VALUES (?, ?, ?, ?)";
|
||
// SQL 插入语句,插入 pv_time_config 表中的数据
|
||
const char* sql_insert_time = "INSERT INTO pv_time_config(name, remark) VALUES (?, ?)";
|
||
// SQL 插入语句,插入 pv_time_exe 表中的数据
|
||
const char* sql_insert_exe = "INSERT INTO pv_time_exe(time_section_config_id, start_time, end_time, power, remark) VALUES (?, ?, ?, ?,?)";
|
||
|
||
pthread_mutex_lock(&config_db_mutex);
|
||
|
||
// 开始事务
|
||
ret = sqlite3_exec(config_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "开启事务失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
|
||
// 清空表数据
|
||
if (sqlite3_exec(config_db, sql_delete_date, NULL, NULL, NULL) != SQLITE_OK ||
|
||
sqlite3_exec(config_db, sql_delete_time, NULL, NULL, NULL) != SQLITE_OK ||
|
||
sqlite3_exec(config_db, sql_delete_exe, NULL, NULL, NULL) != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "清空表失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
|
||
// 准备插入语句
|
||
if (sqlite3_prepare_v2(config_db, sql_insert_date, -1, &stmt_date, NULL) != SQLITE_OK ||
|
||
sqlite3_prepare_v2(config_db, sql_insert_time, -1, &stmt_time, NULL) != SQLITE_OK ||
|
||
sqlite3_prepare_v2(config_db, sql_insert_exe, -1, &stmt_exe, NULL) != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "预编译插入语句失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
|
||
// 遍历需要插入的数据
|
||
utarray_foreach(*pvDateTimeConfigs, pv_date_config_t *, p_pvDateConfig)
|
||
{
|
||
char timeConfigName[50]; // 存储时间配置名称
|
||
snprintf(timeConfigName, sizeof(timeConfigName), "%s-%s", p_pvDateConfig->startDate, p_pvDateConfig->endDate);
|
||
|
||
// 插入 pv_time_config
|
||
sqlite3_bind_text(stmt_time, 1, timeConfigName, -1, SQLITE_STATIC);
|
||
if (sqlite3_step(stmt_time) != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入 pv_time_config 表失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
long long timeConfigId = sqlite3_last_insert_rowid(config_db); // 获取最后插入行的 ID
|
||
sqlite3_reset(stmt_time);
|
||
|
||
// 插入 pv_time_exe
|
||
for (int i = 0; i < p_pvDateConfig->timeCfgLen; i++)
|
||
{
|
||
sqlite3_bind_int64(stmt_exe, 1, timeConfigId);
|
||
sqlite3_bind_int(stmt_exe, 2, p_pvDateConfig->timeCfgTab[i].startTime);
|
||
sqlite3_bind_int(stmt_exe, 3, p_pvDateConfig->timeCfgTab[i].endTime);
|
||
sqlite3_bind_double(stmt_exe, 4, p_pvDateConfig->timeCfgTab[i].power);
|
||
|
||
if (sqlite3_step(stmt_exe) != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入 pv_time_exe 表失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
sqlite3_reset(stmt_exe);
|
||
}
|
||
|
||
// 插入 pv_date_config
|
||
sqlite3_bind_int64(stmt_date, 1, timeConfigId);
|
||
sqlite3_bind_text(stmt_date, 2, (const char *)p_pvDateConfig->startDate, -1, SQLITE_STATIC);
|
||
sqlite3_bind_text(stmt_date, 3, (const char *)p_pvDateConfig->endDate, -1, SQLITE_STATIC);
|
||
|
||
if (sqlite3_step(stmt_date) != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入 pv_date_config 表失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
sqlite3_reset(stmt_date);
|
||
}
|
||
|
||
// 提交事务
|
||
if (sqlite3_exec(config_db, "COMMIT TRANSACTION", NULL, NULL, NULL) != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(config_db));
|
||
goto cleanup;
|
||
}
|
||
|
||
ret = 0; // 成功
|
||
|
||
cleanup:
|
||
if (ret != 0)
|
||
{
|
||
// 回滚事务
|
||
sqlite3_exec(config_db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
|
||
}
|
||
|
||
// 释放资源
|
||
sqlite3_finalize(stmt_date);
|
||
sqlite3_finalize(stmt_time);
|
||
sqlite3_finalize(stmt_exe);
|
||
pthread_mutex_unlock(&config_db_mutex);
|
||
|
||
// 释放 UT_array 资源
|
||
if (ret != 0)
|
||
{
|
||
utarray_free(*pvDateTimeConfigs);
|
||
*pvDateTimeConfigs = NULL;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取EMS拓扑结构信息
|
||
* @param[out] topologys: 用于存储ems拓扑信息结构体的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_topology_db_data(UT_array **topologies)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
|
||
query = "SELECT tpy.id, tpy.parent_id, tpy.menu_tree, tpy.sort_order, "
|
||
"CASE "
|
||
" WHEN tpy.menu_tree = 0 THEN tpy.name "
|
||
" WHEN tpy.menu_tree = 1 THEN dev.name ELSE NULL "
|
||
"END AS name, "
|
||
"CASE "
|
||
" WHEN tpy.menu_tree = 0 THEN NULL "
|
||
" WHEN tpy.menu_tree = 1 THEN dev.sn ELSE NULL "
|
||
"END AS sn, "
|
||
"CASE "
|
||
" WHEN tpy.menu_tree = 0 THEN NULL "
|
||
" WHEN tpy.menu_tree = 1 THEN dev.type ELSE NULL "
|
||
"END AS dev_type "
|
||
"FROM "
|
||
"topology tpy "
|
||
"LEFT JOIN device dev ON tpy.dev_id = dev.id";
|
||
|
||
utarray_new(*topologies, &topology_icd); // 创建新的 UT_array 用于存储ems拓扑信息
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
topology_t topology_info = {0}; // 初始化拓扑结构的结构体
|
||
topology_info.dbId = sqlite3_column_int(stmt, 0);
|
||
if (sqlite3_column_type(stmt, 1) == SQLITE_NULL)
|
||
{
|
||
topology_info.parentId = -999;
|
||
}
|
||
else
|
||
{
|
||
topology_info.parentId = sqlite3_column_int(stmt, 1);
|
||
}
|
||
topology_info.menuTree = (menu_tree_e)sqlite3_column_int(stmt, 2);
|
||
topology_info.sortOrder = sqlite3_column_int(stmt, 3);
|
||
const char *name = (const char *)sqlite3_column_text(stmt, 4);
|
||
snprintf((char *)topology_info.name, MAX_NAME_BUF_LEN, "%s", name ? name : "");
|
||
const char *sn = (const char *)sqlite3_column_text(stmt, 5);
|
||
snprintf((char *)topology_info.sn, MAX_CODE_BUF_LEN, "%s", sn ? sn : "");
|
||
topology_info.devType = (dev_type_e)sqlite3_column_int(stmt, 6);
|
||
|
||
// 将设备点位信息添加到 UT_array 中
|
||
utarray_push_back(*topologies, &topology_info);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*topologies); // 释放 UT_array
|
||
topologies = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库里获取保护算法的控制参数
|
||
* @param[in] p_protectAlgo:保护算法结构体指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_protect_algorithm(protect_algorithm_t *p_protectAlgo)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = "SELECT transformer_capacity, ol_warn_limit_value, ol_shutdown_value, "
|
||
"max_power, demand_switch, target_demand, de_warn_limit_value, "
|
||
"de_shutdown_value, backflow_switch, bf_warn_limit_value, "
|
||
"bf_shutdown_value, soc_forbid_chg, soc_forbid_dischg, "
|
||
"id "
|
||
"FROM protect_algorithm "
|
||
"ORDER BY id DESC "
|
||
"LIMIT 1";
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (SQLITE_ROW == step)
|
||
{
|
||
p_protectAlgo->transCapacity = sqlite3_column_double(stmt, 0); // 变压器总容量(KW)
|
||
p_protectAlgo->olWarnLimitVal = sqlite3_column_double(stmt, 1); // 过载预警限流值(KW)
|
||
p_protectAlgo->olShutdownVal = sqlite3_column_double(stmt, 2); // 过载关机值(KW)
|
||
p_protectAlgo->maxPower = sqlite3_column_double(stmt, 3); // 充放电功率上限(KW)
|
||
p_protectAlgo->demandSwitch = sqlite3_column_int(stmt, 4); // 防需量开关
|
||
p_protectAlgo->targetDemand = sqlite3_column_double(stmt, 5); // 目标需量
|
||
p_protectAlgo->deWarnLimitVal = sqlite3_column_double(stmt, 6); // 需量预警限流值(KW)
|
||
p_protectAlgo->deShutdownVal = sqlite3_column_double(stmt, 7); // 需量关机值(KW)
|
||
p_protectAlgo->backflowSwitch = sqlite3_column_int(stmt, 8); // 防逆流开关
|
||
p_protectAlgo->bfWarnLimitVal = sqlite3_column_double(stmt, 9); // 防逆流预警限流值(KW)
|
||
p_protectAlgo->bfShutdownVal = sqlite3_column_double(stmt, 10); // 防逆流关机值(KW)
|
||
p_protectAlgo->socForbidChg = sqlite3_column_int(stmt, 11); // 禁充SOC [55%-100%]
|
||
p_protectAlgo->socForbidDischg = sqlite3_column_int(stmt, 12); // 禁放SOC [0%-45%]
|
||
p_protectAlgo->dbId = sqlite3_column_int(stmt, 13); // 数据库Id
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败或者无数据,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
return 0; // 返回成功代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的保护算法数据
|
||
* @param[in] p_protectAlgo:保护算法结构体指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_protect_algorithm(protect_algorithm_t *p_protectAlgo)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *sql = sqlite3_mprintf(
|
||
"UPDATE protect_algorithm SET transformer_capacity = ?, ol_warn_limit_value = ?, ol_shutdown_value = ?, "
|
||
"max_power = ?, demand_switch = ?, target_demand = ?, de_warn_limit_value = ?, "
|
||
"de_shutdown_value = ?, backflow_switch = ?, bf_warn_limit_value = ?, "
|
||
"bf_shutdown_value = ?, soc_forbid_chg = ?, soc_forbid_dischg = ? WHERE id = ?");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, sql, -1, &stmt, NULL))
|
||
{
|
||
fprintf(stderr, "SQL语句预编译失败: %s\n", sqlite3_errmsg(config_db));
|
||
sqlite3_free(sql);
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_double(stmt, 1, p_protectAlgo->transCapacity);
|
||
sqlite3_bind_double(stmt, 2, p_protectAlgo->olWarnLimitVal);
|
||
sqlite3_bind_double(stmt, 3, p_protectAlgo->olShutdownVal);
|
||
sqlite3_bind_double(stmt, 4, p_protectAlgo->maxPower);
|
||
sqlite3_bind_int(stmt, 5, p_protectAlgo->demandSwitch);
|
||
sqlite3_bind_double(stmt, 6, p_protectAlgo->targetDemand);
|
||
sqlite3_bind_double(stmt, 7, p_protectAlgo->deWarnLimitVal);
|
||
sqlite3_bind_double(stmt, 8, p_protectAlgo->deShutdownVal);
|
||
sqlite3_bind_int(stmt, 9, p_protectAlgo->backflowSwitch);
|
||
sqlite3_bind_double(stmt, 10, p_protectAlgo->bfWarnLimitVal);
|
||
sqlite3_bind_double(stmt, 11, p_protectAlgo->bfShutdownVal);
|
||
sqlite3_bind_int(stmt, 12, p_protectAlgo->socForbidChg);
|
||
sqlite3_bind_int(stmt, 13, p_protectAlgo->socForbidDischg);
|
||
sqlite3_bind_int(stmt, 14, p_protectAlgo->dbId);
|
||
|
||
pthread_mutex_lock(&config_db_mutex);
|
||
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败");
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "%s", sqlite3_errmsg(config_db));
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "错误代码: %d", step);
|
||
}
|
||
ret = 1;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确");
|
||
ret = 1;
|
||
goto cleanup;
|
||
}
|
||
|
||
cleanup:
|
||
pthread_mutex_unlock(&config_db_mutex);
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(sql);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库里获取调试模式算法的控制参数
|
||
* @param[in] p_debugAlgo:调试模式算法结构体指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_debug_algorithm(debug_algorithm_t *p_debugAlgo)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = "SELECT active_power, reactive_power, pcs_switch, id, protect_switch "
|
||
"FROM debug_algorithm "
|
||
"ORDER BY id DESC "
|
||
"LIMIT 1";
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (SQLITE_ROW == step)
|
||
{
|
||
p_debugAlgo->activePower = sqlite3_column_double(stmt, 0); // 目标有功功率(KW)
|
||
p_debugAlgo->reactivePower = sqlite3_column_double(stmt, 1); // 目标无功功率(KW)
|
||
p_debugAlgo->pcsSwitch = sqlite3_column_int(stmt, 2); // 充放电开关
|
||
p_debugAlgo->dbId = sqlite3_column_int(stmt, 3); // 数据库Id
|
||
p_debugAlgo->protectSwitch = sqlite3_column_int(stmt, 4); // 保护算法开关
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
return 0; // 返回成功代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的调试模式算法数据
|
||
* @param[in] p_debugAlgo:调试模式算法结构体指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_debug_algorithm(debug_algorithm_t *p_debugAlgo)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = sqlite3_mprintf("UPDATE debug_algorithm SET active_power = ?, reactive_power = ?, pcs_switch = ?, protect_switch = ? WHERE id = ? ");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_double(stmt, 1, p_debugAlgo->activePower);
|
||
sqlite3_bind_double(stmt, 2, p_debugAlgo->reactivePower);
|
||
sqlite3_bind_int(stmt, 3, p_debugAlgo->pcsSwitch);
|
||
sqlite3_bind_int(stmt, 4, p_debugAlgo->protectSwitch);
|
||
sqlite3_bind_int(stmt, 5, p_debugAlgo->dbId);
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s", sqlite3_errmsg(config_db));
|
||
}
|
||
else if (step == SQLITE_ROW)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "UPDATE操作中出现意外的SQLITE_ROW返回值");
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL更新失败,错误代码: %d", step);
|
||
}
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行。SQLITE_DONE 并不保证这一点。
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确。");
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库查询功率分配数据
|
||
* @param[in] p_allocatePower:功率分配的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_allocate_power(allocate_power_t *p_allocatePower)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT pcs_num, chg_direction, id, allocate_mode FROM allocate_power ORDER BY id DESC LIMIT 1");
|
||
|
||
if (query == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1;
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (step == SQLITE_ROW)
|
||
{
|
||
p_allocatePower->pcsNum = sqlite3_column_int(stmt, 0); // pcs数量
|
||
p_allocatePower->chgDirection = sqlite3_column_int(stmt, 1); // 充放电方向:1(正放 负充) -1(正充 负放)
|
||
p_allocatePower->dbId = sqlite3_column_int(stmt, 2); // 数据库Id
|
||
p_allocatePower->allocateMode = sqlite3_column_int(stmt, 3); // 下发功率开关:总功率(0),分相功率(1)
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败或者无数据,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return (step == SQLITE_ROW) ? 0 : 1; // 返回成功或失败代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的功率分配数据
|
||
* @param[in] p_allocatePower:功率分配的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_allocate_power(allocate_power_t *p_allocatePower)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = sqlite3_mprintf("UPDATE allocate_power SET pcs_num = ?, chg_direction = ?, allocate_mode = ? WHERE id = ? ");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_int(stmt, 1, p_allocatePower->pcsNum);
|
||
sqlite3_bind_int(stmt, 2, p_allocatePower->chgDirection);
|
||
sqlite3_bind_int(stmt, 3, p_allocatePower->allocateMode);
|
||
sqlite3_bind_int(stmt, 4, p_allocatePower->dbId);
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s", sqlite3_errmsg(config_db));
|
||
}
|
||
else if (step == SQLITE_ROW)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "UPDATE操作中出现意外的SQLITE_ROW返回值");
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL更新失败,错误代码: %d", step);
|
||
}
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行。SQLITE_DONE 并不保证这一点。
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确。");
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库查询工作模式数据
|
||
* @param[in] p_workModeSet:工作模式的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_work_mode_set(work_mode_set_t *p_workModeSet)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT work_mode, id FROM work_mode_set DESC LIMIT 1");
|
||
|
||
if (query == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1;
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (step == SQLITE_ROW)
|
||
{
|
||
p_workModeSet->workMode = (work_mode_e)sqlite3_column_int(stmt, 0); // 工作模式
|
||
p_workModeSet->dbId = sqlite3_column_int(stmt, 1); // 数据库Id
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return (step == SQLITE_ROW) ? 0 : 1; // 返回成功或失败代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的工作模式数据
|
||
* @param[in] p_workModeSet:工作模式的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_work_mode(work_mode_set_t *p_workModeSet)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = sqlite3_mprintf("UPDATE work_mode_set SET work_mode = ? WHERE id = ? ");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_int(stmt, 1, (uint8_t)p_workModeSet->workMode);
|
||
sqlite3_bind_int(stmt, 2, p_workModeSet->dbId);
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s", sqlite3_errmsg(config_db));
|
||
}
|
||
else if (step == SQLITE_ROW)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "UPDATE操作中出现意外的SQLITE_ROW返回值");
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL更新失败,错误代码: %d", step);
|
||
}
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行。SQLITE_DONE 并不保证这一点。
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确。");
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库查询DIDO逻辑设置数据
|
||
* @param[in] diDoSets:DIDO逻辑设置结构体的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_di_do_set_arr(UT_array **diDoSets)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *query; // 查询语句
|
||
|
||
query = "SELECT seq, type, cabinet_code, strategy_seq "
|
||
"FROM di_do_set ";
|
||
|
||
// 准备 SQL 语句
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
utarray_new(*diDoSets, &di_do_logic_set_icd); // 创建新的 UT_array 用于存储DIDO逻辑设置信息
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step) // 遍历每一行结果
|
||
{
|
||
// 从数据库中获取每一列的值
|
||
di_do_logic_set_t di_do_set_logic_info = {0}; // 初始化DIDO逻辑设置的结构体
|
||
di_do_set_logic_info.dIDOseq = sqlite3_column_int(stmt, 0);
|
||
di_do_set_logic_info.dIDOType = (di_do_type_e)sqlite3_column_int(stmt, 1);
|
||
di_do_set_logic_info.cabinetCode = sqlite3_column_int(stmt, 2);
|
||
if (di_do_set_logic_info.dIDOType == kDi)
|
||
{
|
||
di_do_set_logic_info.strategySeqDi = (diFuc_e)sqlite3_column_int(stmt, 3);
|
||
}
|
||
else
|
||
{
|
||
di_do_set_logic_info.strategySeqDo = (doFuc_e)sqlite3_column_int(stmt, 3);
|
||
}
|
||
|
||
// 将DIDO逻辑设置添加到 UT_array 中
|
||
utarray_push_back(*diDoSets, &di_do_set_logic_info);
|
||
|
||
// 继续处理下一行
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
// 检查是否完成所有行的处理
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询未完成,错误信息: %s", sqlite3_errmsg(config_db));
|
||
goto error; // 处理错误
|
||
}
|
||
|
||
// 清理资源
|
||
sqlite3_finalize(stmt); // 释放预编译语句
|
||
return 0; // 成功返回
|
||
|
||
error:
|
||
sqlite3_finalize(stmt); // 确保释放预编译语句
|
||
utarray_free(*diDoSets); // 释放 UT_array
|
||
diDoSets = NULL; // 设置为 NULL
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库里获取温控算法的控制参数
|
||
* @param[in] p_tempCtrlAlgo:温控算法结构体指针
|
||
* @return 0-成功,非0-失败(具体错误码可通过日志或其他机制获取)
|
||
*****************************************************************************/
|
||
int kit_get_temp_ctrl_algorithm(temp_ctrl_algorithm_t *p_tempCtrlAlgo)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
|
||
if (p_tempCtrlAlgo == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "传入的结构体指针为空");
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
char *query = "SELECT mod, work_cool_trig_temp, work_cool_hys, "
|
||
"work_heat_trig_temp, work_heat_hys, standby_cool_trig_temp, "
|
||
"standby_cool_hys, standby_heat_trig_temp, standby_heat_hys, "
|
||
"standby_max_limit, standby_min_limit, standby_maxback_limit, "
|
||
"standby_minback_limit, temp_cmd_normal, temp_cmd_heat, temp_cmd_cold, "
|
||
"temp_cmd_open, temp_cmd_close, id "
|
||
"FROM temp_ctrl_algorithm "
|
||
"ORDER BY id DESC "
|
||
"LIMIT 1";
|
||
|
||
int rc = sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL);
|
||
if (rc != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
ret = rc; // 记录sqlite3的错误码
|
||
goto cleanup;
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (step == SQLITE_ROW)
|
||
{
|
||
p_tempCtrlAlgo->mod = (temperature_ctrl_mod_e)sqlite3_column_int(stmt, 0);
|
||
p_tempCtrlAlgo->workCoolTrigTemp = (float)sqlite3_column_double(stmt, 1);
|
||
p_tempCtrlAlgo->workCoolHys = (float)sqlite3_column_double(stmt, 2);
|
||
p_tempCtrlAlgo->workHeatTrigTemp = (float)sqlite3_column_double(stmt, 3);
|
||
p_tempCtrlAlgo->workHeatHys = (float)sqlite3_column_double(stmt, 4);
|
||
p_tempCtrlAlgo->standbyCoolTrigTemp = (float)sqlite3_column_double(stmt, 5);
|
||
p_tempCtrlAlgo->standbyCoolHys = (float)sqlite3_column_double(stmt, 6);
|
||
p_tempCtrlAlgo->standbyHeatTrigTemp = (float)sqlite3_column_double(stmt, 7);
|
||
p_tempCtrlAlgo->standbyHeatHys = (float)sqlite3_column_double(stmt, 8);
|
||
p_tempCtrlAlgo->standbyMaxLimit = (float)sqlite3_column_double(stmt, 9);
|
||
p_tempCtrlAlgo->standbyMinLimit = (float)sqlite3_column_double(stmt, 10);
|
||
p_tempCtrlAlgo->standbyMaxbackLimit = (float)sqlite3_column_double(stmt, 11);
|
||
p_tempCtrlAlgo->standbyMinbackLimit = (float)sqlite3_column_double(stmt, 12);
|
||
p_tempCtrlAlgo->tempCmdNormal = sqlite3_column_int(stmt, 13);
|
||
p_tempCtrlAlgo->tempCmdHeat = sqlite3_column_int(stmt, 14);
|
||
p_tempCtrlAlgo->tempCmdCold = sqlite3_column_int(stmt, 15);
|
||
p_tempCtrlAlgo->tempCmdOpen = sqlite3_column_int(stmt, 16);
|
||
p_tempCtrlAlgo->tempCmdClose = sqlite3_column_int(stmt, 17);
|
||
p_tempCtrlAlgo->dbId = sqlite3_column_int64(stmt, 18);
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
ret = step; // 记录sqlite3的错误码
|
||
}
|
||
|
||
cleanup:
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的温控算法数据
|
||
* @param[in] p_tempCtrlAlgo:温控算法结构体指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_set_temp_ctrl_algorithm(temp_ctrl_algorithm_t *p_tempCtrlAlgo)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
// 使用互斥锁保护数据库访问,防止多线程竞争
|
||
pthread_mutex_lock(&config_db_mutex);
|
||
|
||
// SQL语句,使用占位符防止SQL注入,并根据实际情况选择合适的更新策略 (UPDATE or INSERT)
|
||
char *query = "UPDATE temp_ctrl_algorithm SET mod = ?, work_cool_trig_temp = ?, work_cool_hys = ?, "
|
||
"work_heat_trig_temp = ?, work_heat_hys = ?, standby_cool_trig_temp = ?, "
|
||
"standby_cool_hys = ?, standby_heat_trig_temp = ?, standby_heat_hys = ?, "
|
||
"standby_max_limit = ?, standby_min_limit = ?, standby_maxback_limit = ?, "
|
||
"standby_minback_limit = ?, temp_cmd_normal = ?, temp_cmd_heat = ?, temp_cmd_cold = ?, "
|
||
"temp_cmd_open = ?, temp_cmd_close = ? "
|
||
"WHERE id = ?;"; // 更新最新的记录
|
||
|
||
// 准备SQL语句
|
||
int rc = sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL);
|
||
if (rc != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备SQL语句失败: %s", sqlite3_errmsg(config_db));
|
||
ret = 1;
|
||
goto unlock_and_return;
|
||
}
|
||
|
||
// 绑定参数
|
||
ret = sqlite3_bind_int(stmt, 1, p_tempCtrlAlgo->mod); // 温度控制模式
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 2, p_tempCtrlAlgo->workCoolTrigTemp); // 制冷触发温度
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 3, p_tempCtrlAlgo->workCoolHys); // 制冷回差
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 4, p_tempCtrlAlgo->workHeatTrigTemp); // 制热触发温度
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 5, p_tempCtrlAlgo->workHeatHys); // 制热回差
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 6, p_tempCtrlAlgo->standbyCoolTrigTemp); // 制冷触发温度
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 7, p_tempCtrlAlgo->standbyCoolHys); // 制冷回差
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 8, p_tempCtrlAlgo->standbyHeatTrigTemp); // 制热触发温度
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 9, p_tempCtrlAlgo->standbyHeatHys); // 制热回差
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 10, p_tempCtrlAlgo->standbyMaxLimit); // 开启自循环高温
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 11, p_tempCtrlAlgo->standbyMinLimit); // 开启自循环低温
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 12, p_tempCtrlAlgo->standbyMaxbackLimit); // 自循环高温回温
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_double(stmt, 13, p_tempCtrlAlgo->standbyMinbackLimit); // 自循环低温回温
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int(stmt, 14, p_tempCtrlAlgo->tempCmdNormal); // 循环控制字
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int(stmt, 15, p_tempCtrlAlgo->tempCmdHeat); // 制热控制字
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int(stmt, 16, p_tempCtrlAlgo->tempCmdCold); // 制冷控制字
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int(stmt, 17, p_tempCtrlAlgo->tempCmdOpen); // 开控制字
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int(stmt, 18, p_tempCtrlAlgo->tempCmdClose); // 关控制字
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
ret = sqlite3_bind_int64(stmt, 19, p_tempCtrlAlgo->dbId); // 数据库Id
|
||
if (ret != SQLITE_OK)
|
||
goto error;
|
||
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "执行SQL语句失败: %s", sqlite3_errmsg(config_db));
|
||
goto error;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, WARN_EN, "没有更新任何行。请检查数据是否存在。");
|
||
ret = 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
goto unlock_and_return;
|
||
|
||
error:
|
||
sqlite3_finalize(stmt);
|
||
ret = 1;
|
||
|
||
unlock_and_return:
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库获取高级设置
|
||
* @param[out] advancedSettings: 用于存储高级设置的数据
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_advanced_setting(UT_array **advancedSettings)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT key, value FROM advanced_setting ORDER BY key ASC");
|
||
int ret;
|
||
|
||
ret = sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1;
|
||
}
|
||
|
||
utarray_new(*advancedSettings, &advanced_setting_icd);
|
||
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
advanced_setting_t setting_info = {0};
|
||
snprintf((char *)setting_info.key, MAX_KEY_LEN, "%s", (const char *)sqlite3_column_text(stmt, 0));
|
||
snprintf((char *)setting_info.value, MAX_VALUE_LEN, "%s", (const char *)sqlite3_column_text(stmt, 1));
|
||
utarray_push_back(*advancedSettings, &setting_info);
|
||
}
|
||
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败: %s", sqlite3_errmsg(config_db));
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
utarray_free(*advancedSettings);
|
||
*advancedSettings = NULL;
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 从数据库查询升级记录数据
|
||
* @param[in] p_upgradeRecord:升级记录的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_get_upgrade_record(upgrade_record_t *p_upgradeRecord)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *query = sqlite3_mprintf("SELECT id, path FROM upgrade_record Where status = 0 LIMIT 1");
|
||
|
||
if (query == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
return 1;
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, query, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "准备查询 `%s` 失败: %s", query, sqlite3_errmsg(config_db));
|
||
sqlite3_free(query);
|
||
return 1; // 返回错误代码
|
||
}
|
||
|
||
int step = sqlite3_step(stmt);
|
||
|
||
if (step == SQLITE_ROW)
|
||
{
|
||
p_upgradeRecord->dbId = sqlite3_column_int(stmt, 0); // 数据库Id
|
||
snprintf((char *)p_upgradeRecord->path, MAX_UPGRADE_PATH_LEN, "%s", sqlite3_column_text(stmt, 1)); // 升级包文件路径
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "查询失败,错误码: %d, 错误信息: %s", step, sqlite3_errmsg(config_db));
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(query);
|
||
return (step == SQLITE_ROW) ? 0 : 1; // 返回成功或失败代码
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新数据库的升级记录数据
|
||
* @param[in] p_upgradeRecord:升级记录的指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_update_upgrade_record(upgrade_record_t *p_upgradeRecord)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = sqlite3_mprintf("UPDATE upgrade_record SET status = ?, err_msg = ? WHERE id = ? ");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(config_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(config_db));
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_int(stmt, 1, (uint8_t)p_upgradeRecord->status);
|
||
sqlite3_bind_text(stmt, 2, (const char *)p_upgradeRecord->errMsg, -1, SQLITE_STATIC);
|
||
sqlite3_bind_int(stmt, 3, p_upgradeRecord->dbId);
|
||
|
||
pthread_mutex_lock(&config_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s", sqlite3_errmsg(config_db));
|
||
}
|
||
else if (step == SQLITE_ROW)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "UPDATE操作中出现意外的SQLITE_ROW返回值");
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL更新失败,错误代码: %d", step);
|
||
}
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行。SQLITE_DONE 并不保证这一点。
|
||
if (sqlite3_changes(config_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确。");
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&config_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/* ############################################################################### 业务数据库操作 ############################################################################### */
|
||
|
||
/*****************************************************************************
|
||
* @brief 批量插入时序数据存储
|
||
* @param[in] timedDatas: 用于存储备份数据的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_insert_timed_data(UT_array *timedDatas)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *sql = "INSERT INTO timed_data_storage (dev_type, dev_id, point_id, timed_value, storage_interval, created_time) VALUES (?, ?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%S', 'now'))";
|
||
int ret = 0;
|
||
int total_count = utarray_len(timedDatas); // 总记录数
|
||
int batch_size = 100; // 每批插入的条数
|
||
int i;
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 预编译SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 批量插入
|
||
for (i = 0; i < total_count; i++)
|
||
{
|
||
timed_data_storage_t *timedData = (timed_data_storage_t *)utarray_eltptr(timedDatas, i);
|
||
|
||
// 绑定参数
|
||
sqlite3_bind_int(stmt, 1, timedData->devType);
|
||
sqlite3_bind_int(stmt, 2, timedData->devDbId);
|
||
sqlite3_bind_int(stmt, 3, timedData->pointDbId);
|
||
// sqlite3_bind_text(stmt, 4, (const char *)timedData->devName, -1, SQLITE_STATIC);
|
||
// sqlite3_bind_text(stmt, 5, (const char *)timedData->pointName, -1, SQLITE_STATIC);
|
||
sqlite3_bind_double(stmt, 4, timedData->timedValue);
|
||
sqlite3_bind_int(stmt, 5, timedData->storageInterval);
|
||
|
||
// 执行插入
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 重置语句,以便下次使用
|
||
sqlite3_reset(stmt);
|
||
|
||
// 每 batch_size 条记录提交一次事务
|
||
if ((i + 1) % batch_size == 0)
|
||
{
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
// 重新开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法重新开始事务: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 提交剩余数据
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 释放预编译语句
|
||
sqlite3_finalize(stmt);
|
||
utarray_free(timedDatas);
|
||
|
||
return 0; // 成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据日期时间条件,删除该日期时间之前timed_data_storage的数据
|
||
* @param[in] storage_interval:存储周期
|
||
* @param[in] date_time_string:日期时间
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_del_timed_data_by_date(int storage_interval, const char *date_time_string)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // SQLite语句句柄
|
||
int ret = 0; // 返回值
|
||
char sql[256]; // SQL语句缓冲区
|
||
|
||
// 参数校验,确保日期字符串不为NULL
|
||
if (date_time_string == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "日期时间字符串为NULL");
|
||
return 1;
|
||
}
|
||
|
||
// 使用sqlite3_snprintf构建SQL语句,防止SQL注入
|
||
sqlite3_snprintf(sizeof(sql), sql,
|
||
"DELETE FROM timed_data_storage WHERE storage_interval = %d AND created_time < '%q';",
|
||
storage_interval, date_time_string);
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务,确保数据一致性
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1; // 直接返回,不继续执行
|
||
}
|
||
|
||
// 准备SQL语句,避免直接使用sqlite3_exec
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句准备失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE) // SQLITE_DONE表示成功执行完语句
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "删除数据失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
|
||
// 提交事务,确保操作生效
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
|
||
// 释放SQLite语句句柄,避免内存泄漏
|
||
sqlite3_finalize(stmt);
|
||
|
||
return 0; // 返回0表示成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 批量插入故障数据存储
|
||
* @param[in] faultsDatas: 用于存储故障数据的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_insert_faults_data(UT_array *faultsDatas)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *sql = "INSERT INTO faults_record (dev_type, dev_id, point_id, faults_value, created_time) VALUES (?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%S', 'now'))";
|
||
int ret = 0;
|
||
int total_count = utarray_len(faultsDatas); // 总记录数
|
||
int batch_size = 100; // 每批插入的条数
|
||
int i;
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 预编译SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 批量插入
|
||
for (i = 0; i < total_count; i++)
|
||
{
|
||
faults_data_storage_t *faultsData = (faults_data_storage_t *)utarray_eltptr(faultsDatas, i);
|
||
|
||
// 绑定参数
|
||
sqlite3_bind_int(stmt, 1, faultsData->devType);
|
||
sqlite3_bind_int(stmt, 2, faultsData->devDbId);
|
||
sqlite3_bind_int(stmt, 3, faultsData->pointDbId);
|
||
sqlite3_bind_double(stmt, 4, faultsData->faultsValue);
|
||
|
||
// 执行插入
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 重置语句,以便下次使用
|
||
sqlite3_reset(stmt);
|
||
|
||
// 每 batch_size 条记录提交一次事务
|
||
if ((i + 1) % batch_size == 0)
|
||
{
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
// 重新开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法重新开始事务: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 提交剩余数据
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 释放预编译语句
|
||
sqlite3_finalize(stmt);
|
||
utarray_free(faultsDatas);
|
||
|
||
return 0; // 成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据日期时间条件,删除该日期时间之前faults_data_storage的数据
|
||
* @param[in] date_time_string:日期时间
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_del_faults_data_by_date(const char *date_time_string)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // SQLite语句句柄
|
||
int ret = 0; // 返回值
|
||
char sql[256]; // SQL语句缓冲区
|
||
|
||
// 参数校验,确保日期字符串不为NULL
|
||
if (date_time_string == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "日期时间字符串为NULL");
|
||
return 1;
|
||
}
|
||
|
||
// 使用sqlite3_snprintf构建SQL语句,防止SQL注入
|
||
sqlite3_snprintf(sizeof(sql), sql, "DELETE FROM faults_record WHERE created_time < '%q';", date_time_string);
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务,确保数据一致性
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1; // 直接返回,不继续执行
|
||
}
|
||
|
||
// 准备SQL语句,避免直接使用sqlite3_exec
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句准备失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE) // SQLITE_DONE表示成功执行完语句
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "删除数据失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
|
||
// 提交事务,确保操作生效
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
|
||
// 释放SQLite语句句柄,避免内存泄漏
|
||
sqlite3_finalize(stmt);
|
||
|
||
return 0; // 返回0表示成功
|
||
}
|
||
|
||
/*******************************************************************************
|
||
* @brief 删除指定时间字符串之前的断点保存数据
|
||
* @param[in] date_time_string 日期时间字符串,格式为"YYYY-MM-DD HH:MM:SS"
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_del_break_data_by_date(const char *date_time_string)
|
||
{
|
||
char sql1[256], sql2[256]; // SQL语句缓冲区
|
||
sqlite3_stmt *stmt1 = NULL, *stmt2 = NULL; // SQLite语句句柄
|
||
int ret = 0; // 返回值
|
||
|
||
// 参数校验,确保日期时间字符串不为NULL
|
||
if (date_time_string == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "日期时间字符串为NULL");
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务,确保数据一致性
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1; // 直接返回,不继续执行
|
||
}
|
||
|
||
// 使用sqlite3_snprintf构建SQL语句,防止SQL注入
|
||
sqlite3_snprintf(sizeof(sql1), sql1, "DELETE FROM break_record WHERE created_time < ?;");
|
||
sqlite3_snprintf(sizeof(sql2), sql2, "DELETE FROM break_data_storage WHERE created_time < ?;");
|
||
|
||
// 准备并执行第一个 DELETE 语句
|
||
// 准备SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql1, -1, &stmt1, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句准备失败: %s SQL: %s", sqlite3_errmsg(business_db), sql1);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
// 绑定参数
|
||
ret = sqlite3_bind_text(stmt1, 1, date_time_string, -1, SQLITE_STATIC);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定参数失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt1);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt1);
|
||
if (ret != SQLITE_DONE) // SQLITE_DONE表示成功执行完语句
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "删除数据失败: %s SQL: %s", sqlite3_errmsg(business_db), sql1);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt1); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
|
||
// 准备并执行第二个 DELETE 语句
|
||
// 准备SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql2, -1, &stmt2, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句准备失败: %s SQL: %s", sqlite3_errmsg(business_db), sql2);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
// 绑定参数
|
||
ret = sqlite3_bind_text(stmt2, 1, date_time_string, -1, SQLITE_STATIC);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "绑定参数失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt2);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt2);
|
||
if (ret != SQLITE_DONE) // SQLITE_DONE表示成功执行完语句
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "删除数据失败: %s SQL: %s", sqlite3_errmsg(business_db), sql2);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt2); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
|
||
// 提交事务,确保操作生效
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
|
||
// 释放SQLite语句句柄,避免内存泄漏
|
||
sqlite3_finalize(stmt1);
|
||
|
||
return 0; // 返回0表示成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 查询MQTT断开记录,根据isUploaded字段筛选。
|
||
* @param[in] isUploaded: 要查询的is_uploaded字段值。如果为255,则查询所有记录。
|
||
* @param[out] breakRecord: 用于存储查询结果的UT_array指针。
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_query_break_records(uint8_t isUploaded, UT_array **breakRecord)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *sql;
|
||
|
||
if (isUploaded == 255)
|
||
{
|
||
sql = sqlite3_mprintf("SELECT id, reason, is_uploaded FROM break_record ORDER BY created_time ASC;");
|
||
}
|
||
else
|
||
{
|
||
sql = sqlite3_mprintf("SELECT id, reason, is_uploaded FROM break_record WHERE is_uploaded = %d ORDER BY created_time ASC;", isUploaded);
|
||
}
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_free(sql);
|
||
return 1;
|
||
}
|
||
sqlite3_free(sql);
|
||
|
||
utarray_new(*breakRecord, &break_record_icd); // 初始化UT_array
|
||
|
||
// 执行查询并处理结果
|
||
int step = sqlite3_step(stmt);
|
||
while (SQLITE_ROW == step)
|
||
{
|
||
break_record_t record = {0};
|
||
/*
|
||
//永远不可能为空
|
||
if (&record == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "内存分配失败");
|
||
utarray_free(*breakRecord);
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
*/
|
||
record.dbId = sqlite3_column_int64(stmt, 0);
|
||
strncpy((char *)record.reason, (const char *)sqlite3_column_text(stmt, 1), MAX_NAME_BUF_LEN - 1);
|
||
record.reason[MAX_NAME_BUF_LEN - 1] = '\0'; // 确保字符串结尾为\0
|
||
record.isUploaded = sqlite3_column_int(stmt, 2);
|
||
utarray_push_back(*breakRecord, &record);
|
||
|
||
step = sqlite3_step(stmt);
|
||
}
|
||
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL执行失败: %s", sqlite3_errmsg(business_db));
|
||
utarray_free(*breakRecord);
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 插入MQTT断开记录,包括中断原因、是否已上传以及断开开始和结束时间。返回插入记录的ID。
|
||
* @param[in] breakRecord: 包含MQTT断开信息的结构体指针:该结构体必须包含中断原因(reason)
|
||
* @return 插入记录的ID;-1-插入记录失败(包括SQL预编译失败和SQL执行失败)。
|
||
*****************************************************************************/
|
||
long long kit_insert_break_record(break_record_t *breakRecord)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = "INSERT INTO break_record(reason, is_uploaded, start_time) VALUES(?, 0, strftime('%Y-%m-%d %H:%M:%S', 'now'));"; // 注意分号
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return -1; // 返回-1表示失败
|
||
}
|
||
|
||
sqlite3_bind_text(stmt, 1, (const char *)breakRecord->reason, -1, SQLITE_STATIC);
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return -1; // 返回-1表示失败
|
||
}
|
||
|
||
long long last_insert_rowid = sqlite3_last_insert_rowid(business_db); // 获取最后插入行的rowid
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return last_insert_rowid; // 返回插入记录的ID
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 更新MQTT断开记录的上传状态。此函数更新数据库中MQTT断开记录的`is_uploaded`字段。
|
||
* @param[in] breakRecord: 指向包含MQTT断开信息的结构体指针。该结构体必须包含断开记录在数据库中的ID (`dbId`) 和新的上传状态 (`isUploaded`)。
|
||
* @return 0-成功更新记录;1-更新记录失败(包括SQL语句预编译失败、SQL语句执行失败或未找到匹配的记录)。如果SQL语句执行成功,但没有更新任何行(例如,`dbId`不存在),则返回1,并记录警告日志。
|
||
*****************************************************************************/
|
||
int kit_update_break_record(break_record_t *breakRecord)
|
||
{
|
||
int ret = 0;
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = sqlite3_mprintf("UPDATE break_record SET is_uploaded = ? WHERE id = ?");
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_bind_int(stmt, 1, breakRecord->isUploaded);
|
||
sqlite3_bind_int64(stmt, 2, breakRecord->dbId);
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (step != SQLITE_DONE)
|
||
{
|
||
if (step == SQLITE_ERROR)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s", sqlite3_errmsg(business_db));
|
||
}
|
||
else if (step == SQLITE_ROW)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "UPDATE操作中出现意外的SQLITE_ROW返回值");
|
||
}
|
||
else
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL更新失败,错误代码: %d", step);
|
||
}
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 检查是否实际更新了任何行。SQLITE_DONE 并不保证这一点。
|
||
if (sqlite3_changes(business_db) == 0)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "没有更新任何行。请检查 dbId 是否正确。");
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 批量插入MQTT断联时的历史数据存储
|
||
* @param[in] breakDbId:MQTT断联的数据库Id
|
||
* @param[in] timedDatas: 用于历史数据存储的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_insert_break_data_storage(uint64_t breakDbId, UT_array **timedDatas)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *sql = "INSERT INTO break_data_storage(break_id, content, is_uploaded, created_time) VALUES (?, ?, 0, strftime('%Y-%m-%d %H:%M:%S', 'now'))";
|
||
int ret = 0;
|
||
int total_count = utarray_len(*timedDatas); // 总记录数
|
||
int batch_size = 100; // 每批插入的条数
|
||
int i;
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 预编译SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return 1;
|
||
}
|
||
|
||
// 批量插入
|
||
for (i = 0; i < total_count; i++)
|
||
{
|
||
break_data_storage_t *timedData = (break_data_storage_t *)utarray_eltptr(*timedDatas, i);
|
||
|
||
// 绑定参数
|
||
sqlite3_bind_int64(stmt, 1, breakDbId);
|
||
sqlite3_bind_text(stmt, 2, (const char *)timedData->content, -1, SQLITE_STATIC);
|
||
|
||
// 执行插入
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 重置语句,以便下次使用
|
||
sqlite3_reset(stmt);
|
||
|
||
// 每 batch_size 条记录提交一次事务
|
||
if ((i + 1) % batch_size == 0)
|
||
{
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
// 重新开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法重新开始事务: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 提交剩余数据
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 释放预编译语句
|
||
sqlite3_finalize(stmt);
|
||
|
||
return 0; // 成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据断开记录ID和行号范围查询断开数据。
|
||
* @param[in] breakDbId: MQTT断开记录的数据库ID。
|
||
* @param[out] timedDatas: 用于存储查询数据的UT_array指针。必须在调用之前初始化。
|
||
* @return 0-成功;1-失败(数据库错误或其他问题)。
|
||
*****************************************************************************/
|
||
int kit_query_break_data(uint64_t breakDbId, UT_array **timedDatas)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
char *sql = NULL;
|
||
int ret = 0;
|
||
|
||
// 构造SQL查询语句,使用LIMIT子句进行分页
|
||
// 将 SELECT 子句改为选择 id 和 content 两个字段
|
||
sql = sqlite3_mprintf("SELECT id, content FROM break_data_storage WHERE break_id = %d AND is_uploaded = 0 ORDER BY created_time LIMIT 100", breakDbId);
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_free(sql);
|
||
return 1;
|
||
}
|
||
|
||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
break_data_storage_t timedData = {0};
|
||
snprintf((char *)timedData.content, MAX_JSON_STR_LEN, "%s", (uint8_t *)sqlite3_column_text(stmt, 1));
|
||
uint64_t id = sqlite3_column_int(stmt, 0);
|
||
timedData.breakDbId = id;
|
||
utarray_push_back(*timedDatas, &timedData);
|
||
}
|
||
|
||
if (ret != SQLITE_DONE && ret != SQLITE_ROW)
|
||
{ // 添加对非SQLITE_DONE和SQLITE_ROW情况的检查
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s, 错误码: %d", sqlite3_errmsg(business_db), ret);
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(sql);
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_free(sql);
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 批量更新断开数据的上传状态,使用事务保证数据一致性。
|
||
* @param[in] break_id: MQTT断开记录的break_id。
|
||
* @param[in] ids: storage的id数组。
|
||
* @param[in] length: storage的id数组长度。
|
||
* @return 0-成功;1-失败
|
||
*****************************************************************************/
|
||
int kit_update_break_data(uint16_t break_id, uint64_t ids[], int length)
|
||
{
|
||
if (length <= 0 || ids == NULL)
|
||
{
|
||
// 如果传入的id数组为空或长度为0, 无需执行更新。
|
||
return 0;
|
||
}
|
||
|
||
sqlite3_stmt *stmt = NULL;
|
||
int ret = 0;
|
||
int i = 0;
|
||
char *sql = NULL;
|
||
char *in_clause = NULL;
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
|
||
// 开始事务
|
||
if (SQLITE_OK != sqlite3_exec(business_db, "BEGIN TRANSACTION", NULL, NULL, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "开始事务失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex);
|
||
return 1;
|
||
}
|
||
|
||
// 构建 IN 子句字符串
|
||
in_clause = sqlite3_mprintf("(");
|
||
for (i = 0; i < length; i++)
|
||
{
|
||
in_clause = sqlite3_mprintf("%s%s?", in_clause, (i > 0) ? "," : "");
|
||
}
|
||
in_clause = sqlite3_mprintf("%s)", in_clause);
|
||
|
||
// 创建 SQL 语句
|
||
sql = sqlite3_mprintf("UPDATE break_data_storage SET is_uploaded = 1 WHERE break_id = ? AND id IN %s", in_clause);
|
||
sqlite3_free(in_clause);
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句预编译失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_free(sql);
|
||
sqlite3_exec(business_db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex);
|
||
return 1;
|
||
}
|
||
sqlite3_free(sql);
|
||
|
||
// 绑定 break_id 参数
|
||
sqlite3_bind_int(stmt, 1, break_id);
|
||
|
||
// 绑定 ID 参数
|
||
for (i = 0; i < length; i++)
|
||
{
|
||
sqlite3_bind_int64(stmt, i + 2, ids[i]); // IDs 从第二个参数开始
|
||
}
|
||
|
||
// 执行 SQL 语句
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句执行失败: %s, 错误码: %d", sqlite3_errmsg(business_db), ret);
|
||
sqlite3_finalize(stmt);
|
||
sqlite3_exec(business_db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex);
|
||
return 1;
|
||
}
|
||
|
||
sqlite3_finalize(stmt);
|
||
|
||
// 提交事务
|
||
if (SQLITE_OK != sqlite3_exec(business_db, "COMMIT TRANSACTION", NULL, NULL, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex);
|
||
return 1;
|
||
}
|
||
|
||
pthread_mutex_unlock(&business_db_mutex);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 批量插入插入功率数据
|
||
* @param[in] powerDatas: 用于存储备份数据的 UT_array 指针
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_insert_power_data(UT_array *powerDatas)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // 预编译语句句柄
|
||
const char *sql = "INSERT INTO power_data_storage(dev_type, dev_code, point_code, value, created_time) VALUES(?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%S', 'now'));";
|
||
int ret = 0;
|
||
int total_count = utarray_len(powerDatas); // 总记录数
|
||
int batch_size = 100; // 每批插入的条数
|
||
int i;
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
// 预编译SQL语句
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
// 批量插入
|
||
for (i = 0; i < total_count; i++)
|
||
{
|
||
power_data_storage_t *powerData = (power_data_storage_t *)utarray_eltptr(powerDatas, i);
|
||
|
||
// 绑定参数
|
||
sqlite3_bind_int(stmt, 1, powerData->devType);
|
||
sqlite3_bind_int(stmt, 2, powerData->devId);
|
||
sqlite3_bind_int(stmt, 3, powerData->pointId);
|
||
sqlite3_bind_double(stmt, 4, powerData->value);
|
||
|
||
// 执行插入
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 重置语句,以便下次使用
|
||
sqlite3_reset(stmt);
|
||
|
||
// 每 batch_size 条记录提交一次事务
|
||
if ((i + 1) % batch_size == 0)
|
||
{
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
// 重新开始事务
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法重新开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 提交剩余数据
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1;
|
||
}
|
||
|
||
// 释放预编译语句
|
||
sqlite3_finalize(stmt);
|
||
utarray_free(powerDatas);
|
||
|
||
return 0; // 成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 根据日期时间条件,删除该日期时间之前power_data_storage的数据
|
||
* @param[in] date_time_string:日期时间
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
int kit_del_power_data_by_date(const char *date_time_string)
|
||
{
|
||
sqlite3_stmt *stmt = NULL; // SQLite语句句柄
|
||
int ret = 0; // 返回值
|
||
char sql[256]; // SQL语句缓冲区
|
||
|
||
// 参数校验,确保日期字符串不为NULL
|
||
if (date_time_string == NULL)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "日期时间字符串为NULL");
|
||
return 1;
|
||
}
|
||
|
||
// 使用sqlite3_snprintf构建SQL语句,防止SQL注入
|
||
sqlite3_snprintf(sizeof(sql), sql, "DELETE FROM power_data_storage WHERE created_time < '%q';", date_time_string);
|
||
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
// 开始事务,确保数据一致性
|
||
ret = sqlite3_exec(business_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "无法开始事务: %s", sqlite3_errmsg(business_db));
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1; // 直接返回,不继续执行
|
||
}
|
||
|
||
// 准备SQL语句,避免直接使用sqlite3_exec
|
||
ret = sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL语句准备失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
return 1;
|
||
}
|
||
|
||
// 执行SQL语句
|
||
ret = sqlite3_step(stmt);
|
||
if (ret != SQLITE_DONE) // SQLITE_DONE表示成功执行完语句
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "删除数据失败: %s SQL: %s", sqlite3_errmsg(business_db), sql);
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
|
||
// 提交事务,确保操作生效
|
||
ret = sqlite3_exec(business_db, "COMMIT;", NULL, NULL, NULL);
|
||
if (ret != SQLITE_OK)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "提交事务失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_exec(business_db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt); // 释放SQLite语句句柄
|
||
return 1;
|
||
}
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
|
||
// 释放SQLite语句句柄,避免内存泄漏
|
||
sqlite3_finalize(stmt);
|
||
|
||
return 0; // 返回0表示成功
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 获取指定表中特定dbId的记录数量
|
||
* @param[in] db: SQLite3 数据库连接对象
|
||
* @param[in] tabName: 查询表的名称
|
||
* @param[in] dbid: 用于查询记录的dbId值
|
||
* @return 记录数量(成功返回记录数量;失败返回-1)
|
||
*****************************************************************************/
|
||
int kit_get_record_count_by_dbid(sqlite3 *db, const char *tabName, uint64_t dbid)
|
||
{
|
||
sqlite3_stmt *stmt;
|
||
char sql[256];
|
||
int result = 0;
|
||
int rc;
|
||
|
||
// 使用 snprintf 合成 SQL 查询字符串
|
||
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE db_id = ?", tabName);
|
||
|
||
// 预编译SQL语句
|
||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||
if (rc != SQLITE_OK)
|
||
{
|
||
printf("Failed to prepare statement: %s\n", sqlite3_errmsg(db));
|
||
return -1;
|
||
}
|
||
|
||
// 绑定参数
|
||
sqlite3_bind_int64(stmt, 1, dbid);
|
||
|
||
// 执行SQL查询
|
||
if ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
|
||
{
|
||
result = sqlite3_column_int(stmt, 0);
|
||
}
|
||
else
|
||
{
|
||
printf("Failed to execute query: %s\n", sqlite3_errmsg(db));
|
||
}
|
||
|
||
// 清理和释放资源
|
||
sqlite3_finalize(stmt);
|
||
|
||
return result;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 插入北向断开记录,记录最新连接状态。
|
||
* @param[in] connectStatus: 连接状态
|
||
* @return 0-成功 1-失败。
|
||
*****************************************************************************/
|
||
int kit_insert_lost_contact_record(const char* connectStatus)
|
||
{
|
||
sqlite3_stmt *stmt = NULL;
|
||
const char *sql = "INSERT INTO lost_contact_record(connect_status, created_time) VALUES(?, strftime('%Y-%m-%d %H:%M:%S', 'now'));";
|
||
|
||
if (SQLITE_OK != sqlite3_prepare_v2(business_db, sql, -1, &stmt, NULL))
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "SQL预编译失败: %s", sqlite3_errmsg(business_db));
|
||
return 1; // 返回1表示失败
|
||
}
|
||
|
||
sqlite3_bind_text(stmt, 1, connectStatus, -1, SQLITE_STATIC);
|
||
pthread_mutex_lock(&business_db_mutex); // 加锁,确保单线程访问
|
||
int step = sqlite3_step(stmt);
|
||
if (SQLITE_DONE != step)
|
||
{
|
||
KITLOG(LOG_KIT_EN, ERROR_EN, "插入数据失败: %s", sqlite3_errmsg(business_db));
|
||
sqlite3_finalize(stmt);
|
||
return 1; // 返回1表示失败
|
||
}
|
||
|
||
pthread_mutex_unlock(&business_db_mutex); // 解锁
|
||
sqlite3_finalize(stmt);
|
||
return 0;
|
||
} |