Reputation: 387
I am using the "raw" C functions to access my SQLite database and getting 2 problems with date and text fields, my code, considere that all is already working:
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)
}
Issue #1 is how to populate the Date field as a valid SQLite timestamp? Issue #2 and more important, the values that are updated into the table with the string fields (field3/field4) are wrong. Only the last value is used to fill both (strVar1/strVar2), so if strVar1 = "A" and strVar2 = "B", both field3 and field4 are saved as "B", value of strVar2. This is very weird because all examples I found have no difference here.
Upvotes: 0
Views: 2721
Reputation: 47876
#1 is how to populate the Date field as a valid SQLite timestamp?
SQLite3 has no DATETIME type nor TIMESTAMP type. So, you need to store a timestamp as a TEXT or NUMERIC.
When you choose NUMERIC, you should better use UNIX epoch time.
sqlite3_bind_double(insertStatement, 2, Date().timeIntervalSince1970)
#2
Swift allocates a temporary region to store UTF-8 representation when passing a String to a parameter of type UnsafePointer<Int8>
. And the region is released immediately after the call to the function, and may be reused.
Try this:
sqlite3_bind_text(insertStatement, 3, strdup(strVar1), -1, free)
sqlite3_bind_text(insertStatement, 4, strdup(strVar2), -1, free)
strdup
allocates a stable region which is available until free
d.
Or (thanks to rmaddy and Martin R "SQLITE_TRANSIENT undefined in Swift"), you can use SQLITE_TRANSIENT
.
Define somewhere in your code:
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
And use it:
sqlite3_bind_text(insertStatement, 3, strVar1, -1, SQLITE_TRANSIENT)
sqlite3_bind_text(insertStatement, 4, strVar2, -1, SQLITE_TRANSIENT)
Upvotes: 2