iOS 16升级后Swift SQLite带参数查询无数据问题求助
问题:iOS 16升级后SQLite带TrackingNumber参数的查询返回空数组
2019年用Swift开发的APP,升级iOS 16后出现异常:SQLite无参数全表查询正常返回数据,但传入TrackingNumber参数(调用示例:requestSource: "All", cTrackingNumber: "0705632085943")时查询返回空数组,尽管全表查询能看到对应记录,表中所有字段均为VARCHAR类型。
相关代码
func queryAllReceiptTransaction(requestSource: String = "All", cTrackingNumber: String = "All") -> [[String: String]] { var queryAllReceiptStatement: OpaquePointer? = nil var queryAllReceiptStatementString: String = "" var vTrackingNumber: String = "" var vEmpID: String = "" var vCarrier: String = "" var vRecdLocation: String = "" var vRecdDate: String = "" var vRecdBy: String = "" var vDeliveryStatus: String = "" var vSite: String = "" var vUploadDate: String = "" var vUploadFlag: String = "" var vDownloadTrackingNumber: String = "" var vDownloadDate: String = "" var vDownloadFlag: String = "" var vAttribute1: String = "" var vAttribute2: String = "" var vAttribute3: String = "" var vAttribute4: String = "" var vAttribute5: String = "" var transHdrDictAll: [String: String] = [:] var transHdrArrayAll = Array<Dictionary<String, String>>() print(" Dec 2 - From queryAllReceiptTransaction method. cTrackingNumber = \(cTrackingNumber)") if cTrackingNumber == "All" { queryAllReceiptStatementString = "SELECT TRACKING_NUMBER,EMPLOYEE_ID, CARRIER, RECEIVED_LOCATION, RECEIVED_DATE, RECEIVED_BY, DELIVERY_STATUS, SITE, UPLOAD_DATE, UPLOAD_FLAG, DOWNLOAD_TRACKING_NUMBER, DOWNLOAD_DATE, DOWNLOAD_FLAG, ATTRIBUTE1, ATTRIBUTE2, ATTRIBUTE3, ATTRIBUTE4, ATTRIBUTE5 FROM BAE_MT_HEADER" } else if cTrackingNumber != "All" { queryAllReceiptStatementString = "SELECT TRACKING_NUMBER,EMPLOYEE_ID, CARRIER, RECEIVED_LOCATION, RECEIVED_DATE, RECEIVED_BY, DELIVERY_STATUS, SITE, UPLOAD_DATE, UPLOAD_FLAG, DOWNLOAD_TRACKING_NUMBER, DOWNLOAD_DATE, DOWNLOAD_FLAG, ATTRIBUTE1, ATTRIBUTE2, ATTRIBUTE3, ATTRIBUTE4, ATTRIBUTE5 FROM BAE_MT_HEADER WHERE TRACKING_NUMBER = ?" } if sqlite3_prepare_v2(db, queryAllReceiptStatementString, -1, &queryAllReceiptStatement, nil) == SQLITE_OK { if cTrackingNumber != "All" { if sqlite3_bind_text(queryAllReceiptStatement, 1, cTrackingNumber, -1, nil) != SQLITE_OK{ let errorBind = String(cString: sqlite3_errmsg(db)!) print("Error while binding: \(errorBind)") } } while sqlite3_step(queryAllReceiptStatement) == SQLITE_ROW { let queryResultCol1 = sqlite3_column_text(queryAllReceiptStatement, 0) vTrackingNumber = String(cString: queryResultCol1!) let queryResultCol2 = sqlite3_column_text(queryAllReceiptStatement, 1) vEmpID = String(cString: queryResultCol2!) let queryResultCol3 = sqlite3_column_text(queryAllReceiptStatement, 2) vCarrier = String(cString: queryResultCol3!) let queryResultCol4 = sqlite3_column_text(queryAllReceiptStatement, 3) vRecdLocation = String(cString: queryResultCol4!) let queryResultCol5 = sqlite3_column_text(queryAllReceiptStatement, 4) vRecdDate = String(cString: queryResultCol5!) let queryResultCol6 = sqlite3_column_text(queryAllReceiptStatement, 5) vRecdBy = String(cString: queryResultCol6!) let queryResultCol7 = sqlite3_column_text(queryAllReceiptStatement, 6) vDeliveryStatus = String(cString: queryResultCol7!) let queryResultCol8 = sqlite3_column_text(queryAllReceiptStatement, 7) vSite = String(cString: queryResultCol8!) if let queryResultCol9 = sqlite3_column_text(queryAllReceiptStatement, 8) { vUploadDate = String(cString: queryResultCol9) } if let queryResultCol10 = sqlite3_column_text(queryAllReceiptStatement, 9) { vUploadFlag = String(cString: queryResultCol10) } if let queryResultCol11 = sqlite3_column_text(queryAllReceiptStatement, 10) { vDownloadTrackingNumber = String(cString: queryResultCol11) } if let queryResultCol12 = sqlite3_column_text(queryAllReceiptStatement, 11) { vDownloadDate = String(cString: queryResultCol12) } if let queryResultCol13 = sqlite3_column_text(queryAllReceiptStatement, 12) { vDownloadFlag = String(cString: queryResultCol13) } if let queryResultCol14 = sqlite3_column_text(queryAllReceiptStatement, 13) { vAttribute1 = String(cString: queryResultCol14) } if let queryResultCol15 = sqlite3_column_text(queryAllReceiptStatement, 14) { vAttribute2 = String(cString: queryResultCol15) } if let queryResultCol16 = sqlite3_column_text(queryAllReceiptStatement, 15) { vAttribute3 = String(cString: queryResultCol16) } if let queryResultCol17 = sqlite3_column_text(queryAllReceiptStatement, 16) { vAttribute4 = String(cString: queryResultCol17) } if let queryResultCol18 = sqlite3_column_text(queryAllReceiptStatement, 17) { vAttribute5 = String(cString: queryResultCol18) } transHdrDictAll["trackingNumber"] = vTrackingNumber transHdrDictAll["employeeId"] = vEmpID transHdrDictAll["carrier"] = vCarrier transHdrDictAll["receivedLocation"] = vRecdLocation transHdrDictAll["receivedDate"] = vRecdDate transHdrDictAll["receivedBy"] = vRecdBy transHdrDictAll["deliveryStatus"] = vDeliveryStatus transHdrArrayAll.append(transHdrDictAll) } } else { print ("Query All Receipt Transactions: Error Preparing Query Statement BAE_MT_HEADER") let errorMessage = String.init(cString: sqlite3_errmsg(db)) print("Error Message = \(errorMessage)") } sqlite3_finalize(queryAllReceiptStatement) return transHdrArrayAll }
MAC端输出
Successfully opened existing database at /var/mobile/Containers/Data/Application/FC1DB26B-AEDF-48F6-9F03-4A8797A227B2/Documents/MailTrackingDatabase2.sqlite Prtinting from app delegate.... Dec 2 - From queryAllReceiptTransaction method. cTrackingNumber = 0705632085943 []
解决思路及方案
修复参数绑定的内存管理:iOS 16中SQLite对字符串绑定的内存处理要求更严格,原代码中
sqlite3_bind_text最后一个参数传nil可能导致字符串提前释放,替换为SQLITE_TRANSIENT(或等价的unsafeBitCast(-1, to: sqlite3_destructor_type.self)),确保SQLite复制字符串内容,同时对参数做trim处理避免隐藏字符干扰:if cTrackingNumber != "All" { let trimmedTrackingNumber = cTrackingNumber.trimmingCharacters(in: .whitespacesAndNewlines) if sqlite3_bind_text(queryAllReceiptStatement, 1, trimmedTrackingNumber, -1, SQLITE_TRANSIENT) != SQLITE_OK { let errorBind = String(cString: sqlite3_errmsg(db)!) print("Error while binding: \(errorBind)") } }排查字段值的隐藏字符:在全表查询循环内和查询前分别打印数据库字段值与参数的原始内容及长度,确认是否存在空格、换行等不可见字符:
// 全表查询循环内添加 print("DB TrackingNumber: '\(vTrackingNumber)',长度:\(vTrackingNumber.count)") // 查询前添加 print("Param TrackingNumber: '\(cTrackingNumber)',长度:\(cTrackingNumber.count)")验证SQL匹配逻辑:临时改用
LIKE匹配排查是否是严格相等的兼容性问题:queryAllReceiptStatementString = "SELECT TRACKING_NUMBER,EMPLOYEE_ID, CARRIER, RECEIVED_LOCATION, RECEIVED_DATE, RECEIVED_BY, DELIVERY_STATUS, SITE, UPLOAD_DATE, UPLOAD_FLAG, DOWNLOAD_TRACKING_NUMBER, DOWNLOAD_DATE, DOWNLOAD_FLAG, ATTRIBUTE1, ATTRIBUTE2, ATTRIBUTE3, ATTRIBUTE4, ATTRIBUTE5 FROM BAE_MT_HEADER WHERE TRACKING_NUMBER LIKE ?" let likeParam = cTrackingNumber.trimmingCharacters(in: .whitespacesAndNewlines) sqlite3_bind_text(queryAllReceiptStatement, 1, likeParam, -1, SQLITE_TRANSIENT)
内容的提问来源于stack exchange,提问作者Dharma
相关产品推荐
相关产品推荐

