传递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)核心原因是对已失效的数据库句柄执行操作:
- 输出中出现两次关闭提示,说明存在重复调用
closeDB的旧代码残留,导致对已关闭的句柄再次执行关闭操作。 openDB中sqlite3_open_v2的参数写法&*db虽语法合法,但逻辑冗余,且若初始*db为野指针会增加风险。
修复方案
- 清理冗余输出/调用逻辑:删除旧的调试代码,确保
closeDB只被调用一次。 - 修正数据库打开的参数传递:
sqlite3_open_v2的第二个参数直接传db(本身就是sqlite3**类型),无需&*db。 - 关闭后清空句柄:成功关闭数据库后将
*db设为nullptr,避免后续误操作无效指针。 - 初始化指针:将
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
相关产品推荐
相关产品推荐

