SQLite3:在C++中插入包含NULL字符的BLOB

8

我正在开发一个使用自定义插件与不同的数据库引擎进行接口,使用它们的API和特定的SQL语法的C++ API。

目前,我正在尝试找到一种插入BLOB的方法,但由于在C/C++中NULL是终止字符,所以当构建INSERT INTO查询字符串时,BLOB会被截断。到目前为止,我已经使用了

//...
char* sql;
void* blob;
int len;
//...
blob = some_blob_already_in_memory;
len = length_of_blob_already_known;
sql = sqlite3_malloc(2*len+1);
sql = sqlite3_mprintf("INSERT INTO table VALUES (%Q)", (char*)blob);
//...

我认为,如果在SQLite3交互式控制台中有可能做到的话,应该可以构造具有正确转义的NULL字符的查询字符串。也许有一种标准SQL的方法,它也被SQLite SQL语法所支持?

肯定有人之前遇到过同样的情况。我已经通过谷歌搜索找到了一些答案,但是它们是其他编程语言(Python)的。

提前感谢您的反馈。


这个页面似乎列出了你需要的所有函数。 - zvrba
3个回答

10

再次感谢大家的反馈。这一次,我将报告如何在此处提供的指示下解决问题。希望这能帮助未来的其他人。

正如前三位回答者建议的那样,我确实使用了预处理语句 - 另外,因为我也对获取列的数据类型感兴趣,简单的sqlite3_get_table()是不行的。

在准备好以下常量字符串形式的SQL语句后:

INSERT INTO table VALUES(?,?,?,?);

通过发出与列相同数量的sqlite3_bind_blob()调用,可以保持相应值的绑定。 (对于其他“简单”数据类型,我还使用了sqlite3_bind_text(),因为我正在使用的API可以将整数/双精度等翻译成字符串。) 所以:

#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
/* ... */
void* blobvalue[4] = { NULL, NULL, NULL, NULL };
int blobsize[4] = { 0, 0, 0, 0 };
const char* tail = NULL;
const char* sql = "INSERT INTO tabl VALUES(?,?,?,?)";
sqlite3_stmt* stmt = NULL;
sqlite3* db = NULL;
/* ... */
sqlite3_open("sqlite.db", &db);
sqlite3_prepare_v2(db,
                   sql, strlen(sql) + 1,
                   &stmt, &tail);
for(unsigned int i = 0; i < 4; i++) {
    sqlite3_bind_blob(stmt, 
                      i + 1, blobvalue[i], blobsize[i], 
                      SQLITE_TRANSIENT);
}
if(sqlite3_step(stmt) != SQLITE_DONE) {
    printf("Error message: %s\n", sqlite3_errmsg(db));
}
sqlite3_finalize(stmt);
sqlite3_close(db);

需要注意的是,一些函数(sqlite3_open_v2()sqlite3_prepare_v2())仅适用于 SQLite 的较新版本(我猜测是 3.5.x 及以上版本)。

在文件 sqlite.db 中可以用以下方式创建 SQLite 表格 tabl(例如):

CREATE TABLE tabl(a TEXT PRIMARY KEY, b TEXT, c TEXT, d TEXT);

@kibab 谢谢,已经修复了。(顺便说一句,如果你想自己改进它的话,也是非常欢迎的。) - jbatista
我不知道我可以编辑别人的帖子 :) 谢谢,好知道。 - Krystian Bigaj

9

您需要使用此功能与准备好的语句一起使用。

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));

C/C++中处理字符串中的NULL的标准方法是将字符串的开头和长度存储起来,或者将指向字符串开头和结尾的指针存储起来。


1

您想预编译语句sqlite_prepare_v2(),然后使用sqlite3_bind_blob()绑定Blob。请注意,您要绑定的语句将是INSERT INTO table VALUES (?)


我不确定这个,但是只有一个“?”占位符是否有效?还是必须与表字段数量一样多? - jbatista
1
是的,如果您这样做,您需要匹配字段计数。 - Louis Gerbarg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接