【问题标题】:soci does not always return the same type for a NUMERIC columnsoci 并不总是为 NUMERIC 列返回相同的类型
【发布时间】:2013-07-30 19:24:38
【问题描述】:

我使用 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。我做了一些调试,看起来行中的条目数和它们的值总是正确的。唯一的问题是这一行的值有时是一个字符串。

这可能是社会中的一个错误,也可能是我的错误假设。我的假设是列的返回数据类型总是相同的。类型切换可能发生在我的应用程序的一次运行中 - 值可能是一个查询结果中的 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.timestampboost::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::Timeptime 转换为自 1.1.1970 以来的秒数并返回。我不知道如何使用此代码将字符串放入 REP_TIMESTAMP 列中。

【问题讨论】:

    标签: sqlite soci


    【解决方案1】:

    SQLite 使用dynamic typing;您为列声明的类型几乎没有影响。

    您从数据库中获得了一个字符串值,因为您的程序将一个字符串值写入了数据库。 如果要强制执行列类型,则必须添加单独的检查约束:

    CREATE TABLE MyTable(
        MyColumn INTEGER NOT NULL CHECK(typeof(MyColumn) = 'integer'),
        ...
    )
    

    【讨论】:

    • 有趣。但是,我在 soci 调用之上有一个 ORM 层,它是类型安全的,不能将字符串写入此列。我提供的 int 值是否有可能在 soci 或 sqlite3 API 中转换为字符串?我想我会尝试添加检查,看看会发生什么。
    • 可以使用type affinity 转换类型,但NUMERIC 列不能以这种方式获取字符串。您确实需要检查字符串的来源。
    • 我尝试将支票添加到我的数据库布局中。现在每个提交都被“约束失败”拒绝。 SQLite 似乎只有一个integer 类型,所以即使我在C++ 端插入了long long,SQLite 也应该是integer,对吧?确实没有其他地方可以将某些东西提交到数据库中,因此值 必须 在 soci 或 sqlite 中的某处转换为字符串。
    • 根据documentation,soci 不支持long long 用于 SQLite(或任何其他 64 位类型)。尝试改用int,或将日期存储为字符串。
    猜你喜欢
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 2012-07-13
    • 1970-01-01
    • 2016-06-07
    相关资源
    最近更新 更多