我在iOS项目中使用sqlite。但是sqlite3_column_count总是返回0,即使我确定查询确实返回了一些列(我甚至认为SQL中的SELECT查询不可能有零输出列)。奇怪的是,这种行为会发生变化,具体取决于我链接的库的版本,特别是该库使用的编译时选项。
这些是用于库版本的编译时选项:
COMPILER=clang-8.0.0 (clang-800.2.34)
ENABLE_API_ARMOR
ENABLE_FTS3
ENABLE_FTS3_PARENTHESIS
ENABLE_JSON1
ENABLE_LOCKING_STYLE=1
ENABLE_RTREE
ENABLE_UPDATE_DELETE_LIMIT
HAS_CODEC
HAVE_ISNAN
MAX_MMAP_SIZE=20971520
OMIT_AUTORESET
OMIT_BUILTIN_TEST
OMIT_LOAD_EXTENSION
SYSTEM_MALLOC
THREADSAFE=2
以下是适用版本的标志:
COMPILER=clang-8.0.0
SYSTEM_MALLOC
THREADSAFE=1
可能导致此行为的原因是什么?
更新2016/12/01
这是一个可用于重新创建问题的项目:https://github.com/iannewson/Stackoverflow40895740.git
ViewController.swift包含以下代码:
Test.doDbStuff()
此功能包含以下内容:
public static func doDbStuff() {
do {
var db :OpaquePointer?
let dbPath = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("\(Date.init().timeIntervalSince1970)".replacingOccurrences(of: ".", with: "") + ".db")
.path
var returnCode :Int32 = sqlite3_open(dbPath, &db)
if SQLITE_OK != returnCode {
preconditionFailure("Failed to open db")
}
var stmt :OpaquePointer?
returnCode = sqlite3_prepare_v2(db, "CREATE TABLE Things (name TEXT)", -1, &stmt, nil)
if SQLITE_OK != returnCode {
preconditionFailure("Failed to prepare table creation SQL")
}
returnCode = sqlite3_step(stmt)
if SQLITE_DONE != returnCode {
preconditionFailure("Failed to execute tbl creation SQL")
}
returnCode = sqlite3_prepare_v2(db, "SELECT name FROM sqlite_master WHERE type ='table'", -1, &stmt, nil)
if SQLITE_OK != returnCode {
preconditionFailure("Failed to prepare count SQL")
}
returnCode = sqlite3_step(stmt)
if SQLITE_ROW != returnCode {
preconditionFailure("Failed to execute count SQL")
} else {
let columnCount = sqlite3_column_count(stmt)
print("columnCount: \(columnCount)")
let name = String(cString: sqlite3_column_text(stmt, 0))
//print("Num tables: \(count)")
print("Table name: \(name)")
}
} catch let error {
preconditionFailure(error.localizedDescription)
}
}
此函数在所有情况下都能正常工作,并始终创建表并从sqlite_master中检索其名称而不会出错。
ViewController.swift还包含以下代码:
Database.instance().executeSql("CREATE TABLE IF NOT EXISTS Things (name TEXT)")
Database.instance().printTableNames()
Database.instance().withStatementFromSql("SELECT name FROM sqlite_master WHERE type ='table'", callback: {statement in
while SQLITE_ROW == sqlite3_step(statement) {
print("Column index: \(sqlite3_column_count(statement))")
let name = SqlHelper.toString(statement, columnName: "name")
print("Table: \(name)")
}
})
此代码创建一个表,然后尝试从sqlite_master检索其名称。这适用于当前在repo中设置的项目,因此要重现安装Google Analytics pod所需的错误。您可以通过在Podfile中取消注释pod 'Google/Analytics'
并运行pod install
来执行此操作。现在,当您尝试运行此项目时,第一组代码(Test.doDbStuff()
)仍然可以正常工作,但使用Database
的第二组代码将使用EXC_BAD_ACCESS错误或返回{{ 1}}来自SQLITE_MISUSE
。