我只用了几天 C++ 的 sqlite3 库,但它给我带来了很大的挫败感。
我想定义一个参数化的 CREATE TABLE,然后将参数绑定(bind)到它。它看起来像这样:
const char[] CREATE_SQL =
"CRAETE TABLE t1 ("
" name VARCHAR(:NAME_LEN)"
" other VARCHAR(:OTHER_LEN)"
");";
我的想法是,在不同的文件(这个头文件的 .cpp)中,我可以将这些参数绑定(bind)到:
int index = sqlite3_bind_parameter_index(stmt, ":NAME_LEN");
sqlite3_bind_int(stmt, index, _DB_FIELD_SIZE_NAME);
其中 _DB_FIELD_SIZE_NAME 也在别处定义。
我不想将 sprintf()
与包含 %d
而不是 :NAME_LEN
的 CREATE_SQL
一起使用和 :OTHER_LEN
,因为我可能会更改参数的顺序或添加新的参数,并且我希望保持显式绑定(bind)。
现在,对于这个问题:我的准备不返回 SQLITE_OK
,而是导致 sqlite3_stmt
的空指针。这是我拥有的:
sqlite3_stmt *stmt;
const char *pStmt = 0;
if( SQLITE_OK != sqlite3_prepare_v2(*db, CREATE_SQL, -1, &stmt, &pStmt) )
// throws exception with the sqlite3_errmsg(*db) text
所以,我得到的错误是这样的:
near ":NAME_LEN": syntax error
我做错了什么?我确定数据库连接打开正常。
最佳答案
为了不回答您的问题,sqlite 没有严格的文本列大小调整。出于兼容性考虑,它接受 VARCHAR 类型,但其行为没有差异。
你总是会得到与此等价的东西:
const char *sql =
"CREATE TABLE t1 ("
" name TEXT"
" ,other TEXT"
");";
为了回答您的问题,我认为您不被允许这样做。 Sqlite 的替换机制仅适用于通常被视为值参数的内容。
例如,您通常会在 INSERT
或 UPDATE
语句中看到的内容。
const char *sql = "INSERT INTO foo (a,b) VALUES (?1,?);";
我完全不记得您是否可以在 CREATE
语句中执行它们,也许对于默认参数?好久不见了。
我发现 boost::format
比我在必须更改非值参数时尝试过的任何其他解决方案更不可能破坏和创建更清晰的代码。
#include <boost/format.hpp>
// ...
int instance_id = 42;
const char *sql = "CREATE TABLE type_%1% (a,b);";
boost::str( boost::format(sql) % instance_id );
我肯定会鼓励您避免进行非值参数替换,除非您绝对必须这样做。这是一个维护麻烦且容易出错的过程。
关于C++ sqlite3 绑定(bind)参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8993229/