我使用soci库访问sqlite3数据库:
rowset<row> rs = (sql.prepare << "select * from my_table");
for (auto it = rs.begin(); it != rs.end(); ++it) {
int some_value = it->get<int>(1);
// ...
}
(这不是我的实际代码;它被严重简化来描述问题。)
现在,大多数时候,这是有效的。但是,有时,行中索引1处的值是字符串,而不是int(导致std::bad_cast
异常)。相应列的SQL类型为NUMERIC(8) NOT NULL
。我做了一些调试,看起来行中的条目数量及其值总是正确的。唯一的问题是,这一行的值有时是一个字符串。
这可能是soci中的错误,也可能是我的错误假设。我的假设是,一列返回的数据类型总是相同的。类型切换可能发生在我的应用程序的一次运行中——在一个查询结果中,值可能是int,在下一个结果中可能是字符串。
由于我不知道sqlite3 API的底层,我甚至不确定这个问题是源于sqlite3还是源于soci。解决方法似乎很简单:检查行值的类型,如果是字符串,则将其转换为int。但重要的是要知道这是预期行为还是错误。有人能对此发表评论吗?
编辑:
新行插入如下:
soci::session sql(Connetion::pool);
sql << "INSERT INTO " << NAME << " (REP_TIMESTAMP, REP_EVENT, REP_LTU_ID, REP_SEC_ID) VALUES (:timestamp, :event, :ltuId, :secId)",
use (bo.timestamp),
use (bo.event),
use (bo.ltuId),
use (bo.secId);
其中bo.timestamp
是具有以下映射的boost::posix_time::ptime
:
template<> struct type_conversion<boost::posix_time::ptime> {
typedef long long base_type;
static void from_base(const long long& t, indicator& i, boost::posix_time::ptime& target) {
target = Helper::Time::timeFrom(t);
}
static void to_base(const boost::posix_time::ptime& d, long long& target, indicator& i) {
target = Helper::Time::secondsSinceEpoch(d);
i = i_ok;
}
};
Helper::Time
将ptime
转换为自1970年1月1日起的秒数并返回。我不知道如何用这段代码将字符串放入列REP_TIMESTAMP
中。
SQLite使用动态类型;为列声明的类型几乎没有任何效果。
您从数据库中获得字符串值,因为您的程序将字符串值写入数据库。如果要强制执行列类型,则必须添加一个单独的检查约束:
CREATE TABLE MyTable(
MyColumn INTEGER NOT NULL CHECK(typeof(MyColumn) = 'integer'),
...
)