sqlite返回结果以csv方式编码

This commit is contained in:
sc committed 2026-02-11 11:21:41 +08:00
1 parent 20c890d6b3
commit 79a90c67e9
11 files changed
+157 -28

No files matched your search

+126 -22
View File
@@ -14,6 +14,7 @@
#include "DB_SQLite.h"
#include "sqlite3.h"
#include <stdbool.h>
#include "libcsv.h"
#define DB_NAME "/sddisk/SC828.db"
int db_HelperInit;
@@ -96,34 +97,136 @@ static void return_disabled(struct db_command *cmd) {
/**
* @brief SELECT 查询回调函数
*/
// 辅助函数:将单个字段转义为 CSV 字符串(原地写入 out,需足够大)
static int csv_escape_field(const char *field, char *out, int out_size)
{
if (!field) {
field = "";
}
// 检查是否需要引号:包含 delimiter(,)、quote(")、换行(\n\r) 或首尾空格
int need_quote = 0;
const char *p = field;
while (*p) {
if (*p == ',' || *p == '"' || *p == '\n' || *p == '\r') {
need_quote = 1;
break;
}
p++;
}
// 首尾空格也建议加引号(可选)
if (!need_quote && (field[0] == ' ' || field[rt_strlen(field)-1] == ' ')) {
need_quote = 1;
}
if (!need_quote) {
// 直接复制
int len = rt_strlen(field);
if (len >= out_size) return -1;
rt_memcpy(out, field, len + 1);
return len;
}
// 需要加引号:先写开头引号
if (out_size < 2) return -1;
*out++ = '"';
out_size--;
// 复制内容,双写引号
p = field;
int written = 1; // 已写入开头 "
while (*p && out_size > 1) {
if (*p == '"') {
if (out_size < 3) return -1; // 需要 ""\0
*out++ = '"';
*out++ = '"';
out_size -= 2;
written += 2;
} else {
*out++ = *p;
out_size--;
written++;
}
p++;
}
if (*p != '\0') return -1; // 缓冲区不足
// 写结尾引号
if (out_size < 2) return -1;
*out++ = '"';
*out = '\0';
return written + 1; // +1 for closing "
}
// 第一次调用:写入列名 header
static int first_call = 1;
static int callback(void *result_str, int argc, char **argv, char **azColName) {
//char *buf = (char *)result_str;
int written = rt_strlen(result_str); // 当前已写入长度(假设 buf 是 \0 结尾的)
int remaining = MAX_RESULT_LEN - written - 1; // -1 留给最终 \0
char *buf = (char *)result_str;
int written = rt_strlen(buf); // 当前长度(\0 结尾)
int remaining = MAX_RESULT_LEN - written - 1; // 留 \0
if (remaining <= 0) {
return 0; // 缓冲区已满,不再写入
}
for (int i = 0; i < argc && remaining > 0; i++) {
const char *val = argv[i] ? argv[i] : "NULL";
// 预估所需长度(保守估计)
int needed = rt_strlen(azColName[i]) + rt_strlen(val) + 2; // + "=...\0" 至少 2 字节(= 和 |)
if (needed > remaining) {
break; // 空间不足,停止
if (remaining <= 0) {
return 1; // 停止查询(缓冲区满)
}
int n = rt_snprintf(result_str + written, remaining + 1, "%s=%s|", azColName[i], val);
if (n < 0 || n > remaining) {
break; // 写入失败或超限
if (first_call) {
first_call = 0;
for (int i = 0; i < argc; i++) {
char temp[128];
int esc_len = csv_escape_field(azColName[i], temp, sizeof(temp));
if (esc_len < 0) continue; // 跳过超长列名
int needed = esc_len + (i < argc - 1 ? 1 : 0); // + 逗号
if (needed > remaining) break;
int n = rt_snprintf(buf + written, remaining + 1, "%s%s", temp, (i < argc - 1) ? "," : "");
if (n <= 0 || n > remaining) break;
written += n;
remaining -= n;
}
// 添加换行
if (remaining >= 2) {
buf[written++] = '\n';
buf[written] = '\0';
remaining--;
}
}
written += n;
remaining -= n;
}
//buf[MAX_RESULT_LEN - 1] = '\0'; // 强制终止,防止意外
return 0;
// 写入数据行
for (int i = 0; i < argc; i++) {
const char *val = argv[i] ? argv[i] : ""; // NULL 视为空字符串(CSV 标准)
char temp[256]; // 足够大以容纳转义后字段
int esc_len = csv_escape_field(val, temp, sizeof(temp));
if (esc_len < 0) {
// 字段太长,截断或跳过
rt_strncpy(temp, val, sizeof(temp) - 1);
temp[sizeof(temp)-1] = '\0';
esc_len = rt_strlen(temp);
}
int needed = esc_len + (i < argc - 1 ? 1 : 0); // + 逗号
if (needed > remaining) break;
int n = rt_snprintf(buf + written, remaining + 1, "%s%s", temp, (i < argc - 1) ? "," : "");
if (n <= 0 || n > remaining) break;
written += n;
remaining -= n;
}
// 行尾加换行
if (remaining >= 2) {
buf[written++] = '\n';
buf[written] = '\0';
remaining--;
}
return 0; //
}
/**
@@ -152,6 +255,7 @@ static void handle_db_command(struct db_command *cmd_dat) {
case DB_CMD_SELECT:
cmd_dat->result[0] = '\0';
first_call=1;
rc = sqlite3_exec(g_db, cmd_dat->sql, callback, cmd_dat->result, &err_msg);
if (rc != SQLITE_OK) {
cmd_dat->result_code = rc;
+1 -1
View File
@@ -25,7 +25,7 @@ extern "C" {
#endif
#ifndef MAX_RESULT_LEN
#define MAX_RESULT_LEN (1024) /**< 结果字符串最大长度 */
#define MAX_RESULT_LEN (4096) /**< 结果字符串最大长度 */
#endif
#ifndef DB_MAX_WAITING_MS