I've been working on to insert a record into the database and I get an API misuse error from Sqlite. Though it throws an error, all the records are inserted properly whenever an insert operation is performed. The issue started happening after I added Sqlitebusytimeout to handle concurrency in multi threaded environment when opening a database connection.
//OpenDatabase connection func openDatabase(path:String) -> OpaquePointer? { var db: OpaquePointer? = nil //Sqlite random crash handle sqlite3_busy_timeout(db, 500) if sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX|SQLITE_OPEN_CREATE, nil) == SQLITE_OK { // print("sql Successfully opened connection to database at \(path)") } else { print("sql Unable to open database. Verify that you created the directory described " +"in the Getting Started section.") } return db }
All the sqlite operations are performed inside a queue to avoid concurrency.
//Insert Sale caller SQLite.shared.databaseQueue.sync(execute: {() -> Void in // do your database activity here SQLite.shared.insert(sale: check) })
Sqlite misuse error in console
2021-05-03 19:55:18.757183-0400 Linga POS[17756:14991901] [logging] API call with NULL database connection pointer2021-05-03 19:55:18.757317-0400 Linga POS[17756:14991901] [logging] misuse at line 163599 of [378230ae7f]
I want to know how this error could be resolved or is it a warning to ignore as all records are being inserted as required.
//Database queue to avoid concurrency var databaseQueue = DispatchQueue(label: "com.app.database", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)//Insert sale method func insert(sale model: SocketSale) { if model.checkId.isEmpty { return } if model.status == TableServiceViewController.onHoldStr { UserDefaults.standard.set(true, forKey: "StartHoldTimer") } var isServiceTypeChanged = 0 isServiceTypeChanged = getServiceTypeChanged(checkId: model.checkId) var insertStatement: OpaquePointer? = nil let insertStatementString = "REPLACE INTO myTable (driver, customerPhoneNumber, sale, isServiceTypeChanged) VALUES (?, ?, ?, ?);" let db = openDatabase(path:dbPath) //Sqlite random crash handle sqlite3_busy_timeout(db, 500) // 1 if sqlite3_prepare_v2(db, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK { // 2 sqlite3_bind_text(insertStatement, 1, (model.customerName as NSString).utf8String, -1, nil) sqlite3_bind_text(insertStatement, 2, (model.ticketNo as NSString).utf8String, -1, nil) sqlite3_bind_text(insertStatement, 3, (model.checkId as NSString).utf8String, -1, nil) sqlite3_bind_text(insertStatement, 4, (model.outEmployeeName as NSString).utf8String, -1, nil) let result = sqlite3_step(insertStatement); if result == SQLITE_DONE { print("sql Successfully inserted row.") insertCounter = 0 } else { print("sql Could not insert row.") if result == SQLITE_BUSY { if db != nil { sqlite3_close(db!) self.insertCounter = self.insertCounter + 1 ShareDataController.ShareDataInstance.shareInstanceQueue.async(execute: { ShareDataController.ShareDataInstance.postEventLog(model.sale, eventType: "recreateSqliteFile Sale", saleUniqueId: model.checkId) }) // if self.insertCounter == 1 && self.db != nil { if self.insertCounter == 1 {// SQLite.shared.databaseQueue.sync(execute: {() -> Void in // do your database activity here self.insert(sale: model)// }) } } } if result == SQLITE_CORRUPT { print("sql Recreate SQLite") if db != nil { sqlite3_close(db!) } recreateSqliteFile(sqlFile: databaseFileName, completion: { (result) in ShareDataController.ShareDataInstance.shareInstanceQueue.async(execute: { ShareDataController.ShareDataInstance.postEventLog(model.sale, eventType: "recreateSqliteFile Sale", saleUniqueId: model.checkId) }) if result { self.insertCounter = 0// SQLite.shared.databaseQueue.sync(execute: {() -> Void in // do your database activity here self.insert(sale: model)// }) } }) } } sqlite3_reset(insertStatement) } else { print("sql INSERT statement could not be prepared.") if db != nil { sqlite3_close(db!) } reInitiateSaleDatabase(checkId: "SQLITE Error", logStr: "INSERT statement could not be prepared.") insertCounter = 0 } // 5 sqlite3_finalize(insertStatement) if db != nil { sqlite3_close(db) } }//Method to reinit database when it is corrupted func reInitiateSaleDatabase(checkId:String,logStr:String) { //closeDB(databaseName: databaseFileName) { (result) in // self.db = nil self.dbPath = "" self.initDBPath() self.createSaleTable() UserDefaults.standard.setValue("0", forKey: "dataVersion") self.syncData { (posted) in } }