2016-11-30 142 views
1

我试图在Swift中创建一个简单的sqlite数据库,但我在尝试创建表时收到错误(特别是SQLITE_ERROR)。Swift Sqlite SQL错误

这里是我的代码:

 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") 
      .absoluteString 

     var returnCode :Int32 = sqlite3_open(dbPath.cString(using: .utf8), &db) 
     if SQLITE_OK != returnCode { 
      preconditionFailure("Failed to open db") 
     } 

     var stmt :OpaquePointer? 
     returnCode = sqlite3_prepare_v2(db, "CREATE TABLE Things (name TEXT)".cString(using: .utf8), -1, &stmt, nil) 
     if SQLITE_OK != returnCode { 
      preconditionFailure("Failed to prepare table creation SQL") 
     } 

SQLite是通过Cocoapod包括在内。我试过在转换为C字符串时使用不同的字符串编码,特别是我尝试过使用ASCII编码,而且我也尝试了对数据库名称进行硬编码。

该错误发生在sqlite3_prepare_v2

的错误消息是“近\” \∪{01} \“:语法错误”

+1

使用'sqlite3_errmsg()'打印错误原因。 - 请注意,您可以将Swift字符串直接传递给C函数,例如'sqlite3_open(dbPath,&db)' –

+0

@MartinR错误信息是“near \”\ u {01} \“:语法错误” –

+0

http://stackoverflow.com/questions/34135305/nsfilemanager-defaultmanager-fileexistsatpath的副本-returns-false-instead-of-true? - 不要使用'absoluteString'来获取文件路径。 –

回答

1

我不是100%肯定为什么.cString(using: .utf8)方法 到斯威夫特字符串转换为C字符串原因问题。 这可能与 Why does Swift return an unexpected pointer when converting an optional String into an UnsafePointer?(这是 报告为Swift错误)中的问题相同。展开的cString() 明确的结果似乎帮助:

let sql = "CREATE TABLE Things (name TEXT)".cString(using: .utf8)! 
returnCode = sqlite3_prepare_v2(db, sql, -1, &stmt, nil) 

但是你可以直接传递一个斯威夫特String C函数期待 一个const char *(比较String value to UnsafePointer<UInt8> function parameter behavior):

var returnCode = sqlite3_open(dbPath, &db) 
// ... 
returnCode = sqlite3_prepare_v2(db, "CREATE TABLE Things (name TEXT)", -1, &stmt, nil) 

,这按预期工作。

补充说明:

  • 使用.pathURL转换为文件路径字符串, 不.absoluteString
  • 如果出现问题,使用sqlite3_errmsg()可以获取错误消息。
  • 删除不必要的类型注释,如var returnCode :Int32

全部放在一起:

var db: OpaquePointer? 
let dbPath = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) 
    .appendingPathComponent("xxx.db") 
    .path 

var returnCode = sqlite3_open(dbPath, &db) 
if SQLITE_OK != returnCode { 
    let errmsg = String(cString: sqlite3_errmsg(db)) 
    fatalError("Failed to open db: \(errmsg)") 
} 

var stmt: OpaquePointer? 
returnCode = sqlite3_prepare_v2(db, "CREATE TABLE Things (name TEXT)", -1, &stmt, nil) 
if SQLITE_OK != returnCode { 
    let errmsg = String(cString: sqlite3_errmsg(db)) 
    fatalError("Failed to prepare table creation SQL: \(errmsg)") 
}