首页 > 解决方案 > 插入时 Swift 4 + SQLite

问题描述

我正在使用“原始”C 函数来访问我的 SQLite 数据库并遇到日期和文本字段的 2 个问题,我的代码,考虑到一切都已经正常工作:

let queryString = "INSERT INTO LOG (field1, field2, field3, field4) VALUES (?, ?, ?, ?);" 
if sqlitePrepare(database: &db, query: queryString, statement: &insertStatement) == SQLITE_OK {
    sqlite3_bind_int(insertStatement, 1, intVar)
    sqlite3_bind_double(insertStatement, 2, Date().timeIntervalSinceReferenceDate)
    sqlite3_bind_text(insertStatement, 3, strVar1, -1, nil)
    sqlite3_bind_text(insertStatement, 4, strVar2, -1, nil)
    if sqlite3_step(insertStatement) != SQLITE_DONE {
          let errmsg = String(cString: sqlite3_errmsg(db)!)
         print("failure insert: \(errmsg)")
     }
    sqlite3_finalize(insertStatement)
}

问题 #1 是如何将日期字段填充为有效的 SQLite 时间戳?问题 #2 更重要的是,使用字符串字段 (field3/field4) 更新到表中的值是错误的。只有最后一个值用于填充(strVar1/strVar2),所以如果strVar1 = "A" and strVar2 = "B",那么field3和field4都保存为"B",即strVar2的值。这很奇怪,因为我发现的所有示例在这里都没有区别。

标签: swiftsqlite

解决方案


#1 是如何将 Date 字段填充为有效的 SQLite 时间戳?

SQLite3 没有 DATETIME 类型也没有 TIMESTAMP 类型。因此,您需要将时间戳存储为 TEXT 或 NUMERIC。

选择 NUMERIC 时,最好使用 UNIX 纪元时间。

sqlite3_bind_double(insertStatement, 2, Date().timeIntervalSince1970)

#2

将 String 传递给 type 的参数时,Swift 会分配一个临时区域来存储 UTF-8 表示UnsafePointer<Int8>。并且该区域在调用该函数后立即释放,并且可以重复使用。

试试这个:

sqlite3_bind_text(insertStatement, 3, strdup(strVar1), -1, free)
sqlite3_bind_text(insertStatement, 4, strdup(strVar2), -1, free)

strdupfree分配一个在d之前可用的稳定区域。

或者(感谢 rmaddy 和Martin R "SQLITE_TRANSIENT undefined in Swift"),您可以使用SQLITE_TRANSIENT.

在代码中的某处定义:

let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)

并使用它:

sqlite3_bind_text(insertStatement, 3, strVar1, -1, SQLITE_TRANSIENT)
sqlite3_bind_text(insertStatement, 4, strVar2, -1, SQLITE_TRANSIENT)

推荐阅读