2017-04-19 43 views
0

我正尝试创建注入查询SQLite的斯威夫特卡伦特3,但I'm功能具有逃逸字符的问题SQLite的SQLITE_MISUSE错误3

class SQLiteQueryManager { 

    static func insertNewStore(StoreId: Int64, Name: String, Address: String) -> Bool { 

     let vCommand = "INSERT INTO Store (Id, StoreId, Name, Address) VALUES (\(SQLiteConnectionManager.nextID("Store")),\(StoreId),'\(Name)','\(Address)')" 

     return SQLiteConnectionManager.insertDatabase(vCommand) 
    } 

} 

问题INS当I'm试图执行SQLiteConnectionManager.insertDatabase功能I'm发送到SQLite的字符串看起来是这样的:

INSERT INTO商店(ID,STOREID,姓名,地址)VALUES(1,1,\'蒂达 1 \ ','Dirección1')

SQLite拒绝查询。

我试过.replacingOccurrences(的:“\”,与:“”),但它不工作。

我在DB浏览器中的查询已经测试和工程

INSERT INTO商店(ID,STOREID,姓名,地址)VALUES(1,1, '蒂达 1', 'Dirección1')

如何删除\ ??

我SQLite的功能是这样的:

static func insertDatabase(_ pCommand: String) -> Bool 
{ 
    var vInsertStatement: OpaquePointer? = nil 

    let vDB: OpaquePointer = SQLiteConnectionManager.openDatabase() 

    var vReturn: Bool 

    if sqlite3_prepare_v2(vDB, pCommand.replacingOccurrences(of: "\\", with: ""), -1, &vInsertStatement, nil) == SQLITE_OK { 
     if sqlite3_step(vInsertStatement) == SQLITE_DONE { 
      print("insertDatabase() correct with statement \(pCommand)") 
      vReturn = true 
     } else { 
      print("insertDatabase() fail with statement \(pCommand)") 
      vReturn = false 
     } 
    } else { 
     print("insertDatabase() pCommand could not be prepared") 
     vReturn = false 
    } 

    sqlite3_finalize(vInsertStatement) 

    sqlite3_close(vDB) 

    return vReturn 
} 

Open函数返回OK,所以我的猜测是逃避char或类似的东西。

这是函数的打印输出:

insertDatabase()失败,并声明INSERT INTO商店(ID,STOREID, 姓名,地址)VALUES(1,1, '蒂达1',” Dirección1' )

更新1:

sqlite3_step(vInsertStatement)将返回SQLITE_MISUSE,但我找不到错误,DB是在包和执行open()表演工作和选择我正在做的工作,有什么可能是错的?

更新2:

我这是怎么开德DB返回OK:

private static func openDatabase() -> OpaquePointer { 
    var vDB: OpaquePointer? = nil 
    mDBURL = Bundle.main.url(forResource: "ARDB", withExtension: "db") 
    if let vDBURL = mDBURL{ 
     if sqlite3_open(vDBURL.absoluteString, &vDB) == SQLITE_OK { 
      print("The database is open.") 
     } else { 
      print("Unable to open database in method openDatabase().") 
     } 
     return vDB! 
    } else { 
     return vDB! 
    } 
} 

然后我跑这来获取最后一个ID和工作原理:

static func nextID(_ pTableName: String!) -> Int 
{ 
    var vGetIdStatement: OpaquePointer? = nil 

    let vDB: OpaquePointer = SQLiteConnectionManager.openDatabase() 

    let vCommand = String(format: "SELECT Id FROM %@ ORDER BY Id DESC LIMIT 1", pTableName) 

    var vResult: Int32? = 0 

    if sqlite3_prepare_v2(vDB, vCommand, -1, &vGetIdStatement, nil) == SQLITE_OK { 
     if sqlite3_step(vGetIdStatement) == SQLITE_ROW { 
      vResult = sqlite3_column_int(vGetIdStatement, 0) 
      print("nextID() correct with statement \(vCommand)") 
     } else { 
      print("nextID() fail with statement \(vCommand)") 
     } 

    } else { 
     print("nextID() statement could not be prepared") 
    } 

    sqlite3_finalize(vGetIdStatement) 

    sqlite3_close(vDB) 

    var id: Int = 1 
    if (vResult != nil) 
    { 
     id = Int(vResult!) + 1 
    } 

    return id 
} 

我已经改变了我的插入功能,使用或不使用cString语句:

static func insertDatabase(_ pCommand: String) -> Bool 
{ 
    var vInsertStatement: OpaquePointer? = nil 

    let vDB: OpaquePointer = SQLiteConnectionManager.openDatabase() 

    var vReturn: Bool 

    if sqlite3_prepare_v2(vDB, pCommand.cString(using: .utf8), -1, &vInsertStatement, nil) == SQLITE_OK { 
     if sqlite3_step(vInsertStatement) == SQLITE_DONE { 
      print("insertDatabase() correct with statement \(pCommand)") 
      vReturn = true 
     } else { 
      print("insertDatabase() fail with statement \(pCommand) with error: \(sqlite3_step(vInsertStatement)) : \(sqlite3_errmsg(vDB))") 
      vReturn = false 
     } 
    } else { 
     print("insertDatabase() \(pCommand) could not be prepared with error: \(sqlite3_prepare_v2(vDB, pCommand.cString(using: .utf8), -1, &vInsertStatement, nil))") 
     vReturn = false 
    } 

    sqlite3_finalize(vInsertStatement) 

    sqlite3_close(vDB) 

    return vReturn 
} 

如果我在控制台打印sqlite3_errmsg(VDB)我得到这个没有帮助:

▿可选>▿一些:0x0000000105347e80 - pointerValue:4382293632

如果我打印sqlite3_step(vInsertStatement)返回21 SQLITE_MISUSE

任何帮助将不胜感激。

在此先感谢。

+2

尝试使用[binding](https://sqlite.org/c3ref/bind_blob.html),而不是直接插入字符串。无论如何,出于安全原因,这是很好的做法。 –

+0

我同意约翰蒙哥马利:你不应该逃避任何事情。 SQLite语句可以被赋值而不需要任何转义:这就是“语句绑定”。现在你也可以使用像https://github.com/groue/GRDB.swift这样的强大的Swift库:'try db.execute(“INSERT ... VALUES(?,...)”,arguments:[value, ...])# –

+0

@GwendalRoué嗨sqlite3_step(vInsertStatement)正在返回SQLITE_MISUSE,但我找不到错误,数据库在捆绑和open()语句的工作和选择我在做的工作,什么可以是错的? –

回答

1

我刚刚发现问题,我们没有在主包中写入的权限。

所以,你必须先复制DB,这里是代码:

private static func copyFromBundle() { 
    let vBundlePath = Bundle.main.path(forResource: "ARDB", ofType: ".db") 
    let vDestPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! 
    let vFileManager = FileManager.default 
    let vFullDestPath = URL(fileURLWithPath: vDestPath).appendingPathComponent("ARDB.db") 
    mDocumentsPath = "" 
    if vFileManager.fileExists(atPath: vFullDestPath.path){ 
     print("Database file exist don´t copy.") 
     mDocumentsPath = vFullDestPath.path 
    } else { 
     if vFileManager.fileExists(atPath: vBundlePath!) { 
      do { 
       try vFileManager.copyItem(atPath: vBundlePath!, toPath: vFullDestPath.path) 
       print("Database file does´t exist copy it.") 
       mDocumentsPath = vFullDestPath.path 
      } catch { 
       print("copyFromBundle() fail with error: ",error) 
      } 
     } 
    } 
} 

感谢您的帮助。

快乐编码。