sqlite 使用: 03-问题记录:在使用 sqlite3_bind_text 中设置 SQLITE_STATIC 参数时,处理不当造成的字符乱码

用通义千问生成了一个测试代码,发现存入的文本为乱码,记录下问题与解决方式。

1.问题背景:

以下为问题代码片段,主要看 sqlite3_bind_text 调用文本传参的这一句即可:

cpp 复制代码
//saveTimer 的实现
bool DatabaseManager::saveTimer(const Timer& timer) {
    const char* insertSQL = R"(
        INSERT INTO timers (name, description, expire_time, status)
        VALUES (?, ?, ?, ?);
    )";
    
    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(db_, insertSQL, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db_) << std::endl;
        return false;
    }
    /* 问题代码部分,SQLITE_STATIC ,timer.getName() 返回的是一个临时变量,语句执行完成就销毁了,就会出问题 */
    sqlite3_bind_text(stmt, 1, timer.getName().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, timer.getDescription().c_str(), -1, SQLITE_STATIC);
    std::string timeStr = timePointToString(timer.getExpireTime());
    sqlite3_bind_text(stmt, 3, timeStr.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 4, static_cast<int>(timer.getStatus()));
    
    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    
    return rc == SQLITE_DONE;
}

2.问题原因与解决

timer.getName()等方法返回的都是临时变量,语句执行完成就销毁了。sqlite3_bind_text传入的指针

变成了野指针,这会导致数据库文件中的名称和描述为以乱码的形式存在。

需要修改将 SQLITE_STATIC 改为 SQLITE_TRANSIENT。

这两个参数的区别是:

  • SQLITE_STATIC:告诉 SQLite 字符串指针在 SQLite 使用期间不会改变,SQLite 不会复制数据
  • SQLITE_TRANSIENT:告诉 SQLite 需要复制数据,因为原始数据可能在 SQLite 使用完之前被释放或修改。
cpp 复制代码
bool DatabaseManager::saveTimer(const Timer& timer) {
    const char* insertSQL = R"(
        INSERT INTO timers (name, description, expire_time, status)
        VALUES (?, ?, ?, ?);
    )";
    
    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(db_, insertSQL, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db_) << std::endl;
        return false;
    }
    /*
	修改传入的参数为 SQLITE_TRANSIENT
    */
    sqlite3_bind_text(stmt, 1, timer.getName().c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, timer.getDescription().c_str(), -1, SQLITE_TRANSIENT);
    std::string timeStr = timePointToString(timer.getExpireTime());
    sqlite3_bind_text(stmt, 3, timeStr.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 4, static_cast<int>(timer.getStatus()));
    
    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    
    return rc == SQLITE_DONE;
}
相关推荐
无足鸟ICT1 小时前
【RHCA+】ipcrm命令(删除IPC资源)
linux
csdn_aspnet2 小时前
C++ 3个有序点的方向(Orientation of 3 ordered points)
c++·算法
星恒随风2 小时前
MySQL 从零入门(四):表的增删改查与基础查询详解
linux·服务器·数据库·笔记·mysql
小七在进步3 小时前
string的使用(2)
c++
青少儿编程课堂3 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
陈希1235 小时前
Linux 网络诊断工具实战:ping、curl、tcpdump、mtr、dig 用法详解
linux·网络·tcpdump
wo_jack5 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
进击的荆棘5 小时前
Linux系统——线程同步与互斥之线程池和安全
linux·运维·服务器·安全·单例模式·线程
刘大望5 小时前
不用买开发板:用 QEMU 走通嵌入式 Linux 全流程(三)存储与网络实地验证
linux·qemu·嵌入式linux·alpine
青少儿编程课堂6 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛