You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

传递SQLite3数据库指针到含sqlite3_close的函数时出现21错误

SQLite3数据库关闭失败(错误码21)问题排查

我的目标是让自行编写的函数在打开SQLite3数据库后能成功关闭,期望close操作返回码为0。我将成功打开后的sqlite3 *db指针传递到自行实现的、包含rc = sqlite3_close(db)的函数中,似乎在传递指针的过程中丢失了某些信息,导致close操作报错。我计划围绕SQLite的数据库调用函数构建多个功能函数,因此先实现简单的打开和关闭功能对后续开发很重要,这可能是我对指针传递方式存在误解。

运行错误信息

Return code: 0 |Error code: 0 |Error message: not an error |Message: Database open success
New message -->Return code: 0 |Message: Database close success
Old message -->Return code: 21 |Error code: 21 |Error message: bad parameter or other API misuse |Message: Database close failed 

我的代码

#include <iostream>
#include <string>
#include <sqlite3.h>
using namespace std;

// Function prototypes
int openDB(sqlite3**, string); // Mod - Added additional *
int closeDB(sqlite3**); // Mod - Added additional *


int main()
{    
    // Open database
    sqlite3 *db;
    string errmsg;
    int rc;
    string dbStr = "/home/steven/sparks-robotics/data/myDB.db";
    const char* database = dbStr.c_str();
    rc = openDB(&db,database); // Mod - Added &
    if (rc != EXIT_SUCCESS) {return EXIT_FAILURE;}

    // Close database
    rc = closeDB(&db); // Mod - Added &
    if (rc != EXIT_SUCCESS) {return EXIT_FAILURE;}

return 0;
};

int openDB(sqlite3 **db, string dbStr) { // Mod - Added *
    int rc;         // SQLite return code
    const char* em; // SQLite error message 
    int ec;         // SQLite error code
    
    string errmsg;
    const char* database = dbStr.c_str();
    rc = sqlite3_open_v2(database, &*db, SQLITE_OPEN_READONLY, NULL); // Mod - Added *
    errmsg = "Database open success";
    ec = sqlite3_errcode(*db); // Mod - Added *
    em = sqlite3_errmsg(*db);  // Mod - Added *
    if(rc != SQLITE_OK) {errmsg = "Database open failed";}
    cout << "Return code: " << rc <<" |Error code: " << ec << " |Error message: " << em << " |Message: " + errmsg << endl;
    return rc;
};

int closeDB(sqlite3 **db) { // Mod - Added *
    int rc;         // SQLite return code
    //const char* em; // SQLite error message // Mod - Deleted
    //int ec;         // SQLite error code // Mod - Deleted

    string errmsg;
    rc = sqlite3_close(*db); // Mod - Added *
    errmsg = "Database close success";
    //ec = sqlite3_errcode(*db); // Mod - deleted, db already closed
    //em = sqlite3_errmsg(*db);  // Mod - deleted, db already closed
    if(rc != SQLITE_OK) {errmsg = "Database close failed";}
    //cout << "Return code: " << rc <<" |Error code: " << ec << " |Error message: " << em << " |Message: " + errmsg << endl; 
    cout << "Return code: " << rc << " |Message: " + errmsg << endl;  
    return rc;
};

问题原因分析

错误码21(SQLITE_MISUSE)核心原因是对已失效的数据库句柄执行操作:

  1. 输出中出现两次关闭提示,说明存在重复调用closeDB的旧代码残留,导致对已关闭的句柄再次执行关闭操作。
  2. openDB中sqlite3_open_v2的参数写法&*db虽语法合法,但逻辑冗余,且若初始*db为野指针会增加风险。

修复方案

  1. 清理冗余输出/调用逻辑:删除旧的调试代码,确保closeDB只被调用一次。
  2. 修正数据库打开的参数传递:sqlite3_open_v2的第二个参数直接传db(本身就是sqlite3**类型),无需&*db。
  3. 关闭后清空句柄:成功关闭数据库后将*db设为nullptr,避免后续误操作无效指针。
  4. 初始化指针:将main中的sqlite3 *db初始化为nullptr,避免野指针问题。

修正后的代码

#include <iostream>
#include <string>
#include <sqlite3.h>
using namespace std;

// Function prototypes
int openDB(sqlite3**, const string&);
int closeDB(sqlite3**);


int main()
{    
    // Open database
    sqlite3 *db = nullptr; // 初始化指针为nullptr,避免野指针
    int rc;
    const string dbStr = "/home/steven/sparks-robotics/data/myDB.db";
    rc = openDB(&db, dbStr);
    if (rc != SQLITE_OK) {return EXIT_FAILURE;}

    // Close database
    rc = closeDB(&db);
    if (rc != SQLITE_OK) {return EXIT_FAILURE;}

    return 0;
};

int openDB(sqlite3 **db, const string& dbStr) {
    int rc;
    const char* em;
    int ec;
    
    string errmsg;
    const char* database = dbStr.c_str();
    // 直接传递db,符合sqlite3_open_v2的参数要求
    rc = sqlite3_open_v2(database, db, SQLITE_OPEN_READONLY, NULL);
    errmsg = "Database open success";
    ec = sqlite3_errcode(*db);
    em = sqlite3_errmsg(*db);
    if(rc != SQLITE_OK) {
        errmsg = "Database open failed";
    }
    cout << "Return code: " << rc <<" |Error code: " << ec << " |Error message: " << em << " |Message: " << errmsg << endl;
    return rc;
};

int closeDB(sqlite3 **db) {
    int rc;
    string errmsg;

    // 提前检查指针有效性
    if (*db == nullptr) {
        errmsg = "Database handle is null";
        cout << "Return code: -1 |Message: " << errmsg << endl;
        return -1;
    }

    rc = sqlite3_close(*db);
    errmsg = "Database close success";
    if(rc != SQLITE_OK) {
        errmsg = "Database close failed";
    }
    cout << "Return code: " << rc << " |Message: " << errmsg << endl;  

    // 关闭后清空指针,防止重复调用
    *db = nullptr;
    return rc;
};

额外建议

  • 使用const string&作为函数参数,避免不必要的字符串拷贝。
  • 在closeDB中增加指针有效性检查,提前拦截无效调用。

内容的提问来源于stack exchange,提问作者Steven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:45:30