How to pass a callback function in sqlite3_exec to swift?

How to pass a callback function in sqlite3_exec to swift?

sqlite_str = sqlite_str + "\(sqlite_property_str))"; var str:NSString = sqlite_str; var sqlite:COpaquePointer = share().sqlite3_db; var errmsg:UnsafePointer<Int8> = nil let rc = sqlite3_exec(sqlite, str.cStringUsingEncoding(NSUTF8StringEncoding), <#callback: CFunctionPointer<((UnsafePointer<()>, Int32, UnsafePointer<UnsafePointer<Int8>>, UnsafePointer<UnsafePointer<Int8>>) -> Int32)>#>, <#UnsafePointer<()>#>, <#errmsg: UnsafePointer<UnsafePointer<Int8>>#>) 
+6
source share
3 answers

Swift 2.2 provides two options for implementing the sqlite3_exec callback function: (1) a global procedure without a func instance, or (2) closing without capturing the literal {} .

sqlite.org "SQLite in 5 minutes or less" is implemented in the Swift Xcode7 project here .

typealias

 typealias sqlite3 = COpaquePointer typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>> typealias CCharPointer = UnsafeMutablePointer<CChar> typealias CVoidPointer = UnsafeMutablePointer<Void> 

Callback approach

 func callback( resultVoidPointer: CVoidPointer, // void *NotUsed columnCount: CInt, // int argc values: CCharHandle, // char **argv columns: CCharHandle // char **azColName ) -> CInt { for i in 0 ..< Int(columnCount) { guard let value = String.fromCString(values[i]) else { continue } guard let column = String.fromCString(columns[i]) else { continue } print("\(column) = \(value)") } return 0 // status ok } func sqlQueryCallbackBasic(argc: Int, argv: [String]) -> Int { var db: sqlite3 = nil var zErrMsg:CCharPointer = nil var rc: Int32 = 0 // result code if argc != 3 { print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0])) return 1 } rc = sqlite3_open(argv[1], &db) if rc != 0 { print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "" ) sqlite3_close(db) return 1 } rc = sqlite3_exec(db, argv[2], callback, nil, &zErrMsg) if rc != SQLITE_OK { print("ERROR: sqlite3_exec " + String.fromCString(zErrMsg)! ?? "") sqlite3_free(zErrMsg) } sqlite3_close(db) return 0 } 

Closure Approach

 func sqlQueryClosureBasic(argc argc: Int, argv: [String]) -> Int { var db: sqlite3 = nil var zErrMsg:CCharPointer = nil var rc: Int32 = 0 if argc != 3 { print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0])) return 1 } rc = sqlite3_open(argv[1], &db) if rc != 0 { print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "" ) sqlite3_close(db) return 1 } rc = sqlite3_exec( db, // database argv[2], // statement { // callback: non-capturing closure resultVoidPointer, columnCount, values, columns in for i in 0 ..< Int(columnCount) { guard let value = String.fromCString(values[i]) else { continue } guard let column = String.fromCString(columns[i]) else { continue } print("\(column) = \(value)") } return 0 }, nil, &zErrMsg ) if rc != SQLITE_OK { let errorMsg = String.fromCString(zErrMsg)! ?? "" print("ERROR: sqlite3_exec \(errorMsg)") sqlite3_free(zErrMsg) } sqlite3_close(db) return 0 } 
+2
source

It's impossible now. The Xcode 6 beta 4 release notes say:

However, you cannot call a function pointer C or convert a closure to C.

As a workaround, you can put sqlite3_exec along with your callback in C and call it from Swift.

0
source

I wanted to provide an update for @l --marc l's answer for Swift 3 and Linux, which helped me get up and running. Thanks @l --marc l!

Callback approach

 func callback( resultVoidPointer: UnsafeMutablePointer<Void>?, // void *NotUsed columnCount: Int32, // int argc values:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, // char **argv columns:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? // char **azColName ) -> CInt { var dic: [String:String] = [:] for i in 0 ..< Int(columnCount) { guard let value = values?[i] else { continue } guard let column = columns?[i] else { continue } let strCol = String(cString:column) let strVal = String(cString:value) dic[strCol] = strVal //print("\(strCol) = \(strVal)") } resultSet.append(dic) return 0 // status ok } func sqlQueryCallbackBasic(dbStr:String, query:String) -> Int { var db: OpaquePointer? var zErrMsg:UnsafeMutablePointer<Int8>? var rc: Int32 = 0 // result code rc = sqlite3_open(dbStr, &db) if rc != 0 { print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "" ) sqlite3_close(db) return 1 } rc = sqlite3_exec(db, query, callback, nil, &zErrMsg) if rc != SQLITE_OK { let errorMsg = zErrMsg print("ERROR: sqlite3_exec \(errorMsg)") sqlite3_free(zErrMsg) } sqlite3_close(db) return 0 } 

Closure Approach

 func sqlQueryClosureBasic(dbStr:String, query:String) -> Int { var db: OpaquePointer? var zErrMsg:UnsafeMutablePointer<Int8>? var rc: Int32 = 0 rc = sqlite3_open(dbStr, &db) if rc != 0 { print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "" ) sqlite3_close(db) return 1 } rc = sqlite3_exec( db, // database query, // statement { // callback: non-capturing closure resultVoidPointer, columnCount, values, columns in var dic: [String:String] = [:] for i in 0 ..< Int(columnCount) { guard let value = values?[i] else { continue } guard let column = columns?[i] else { continue } let strCol = String(cString:column) let strVal = String(cString:value) dic[strCol] = strVal //print("\(strCol) = \(strVal)") } resultSet.append(dic) return 0 }, nil, &zErrMsg ) if rc != SQLITE_OK { let errorMsg = zErrMsg print("ERROR: sqlite3_exec \(errorMsg)") sqlite3_free(zErrMsg) } sqlite3_close(db) return 0 } 

Test

 import Glibc var resultSet: [[String: String]] = [[:]] //sqlQueryClosureBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee") sqlQueryCallbackBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee") for row in resultSet { for (col, val) in row { print("\(col): \(val)") } } 
0
source

Source: https://habr.com/ru/post/972317/


All Articles