LMAssembly // Correctly handle statement pointers.
This commit is contained in:
parent
a66879f7bf
commit
161aa100cc
|
@ -36,9 +36,6 @@ public extension vChewingLM {
|
|||
// SQLite 連線是否已經建立。
|
||||
public private(set) static var isSQLDBConnected: Bool = false
|
||||
|
||||
// SQLite Statement 專用的記憶體位置。
|
||||
static var ptrStatement: OpaquePointer?
|
||||
|
||||
// 在函式內部用以記錄狀態的開關。
|
||||
public var isCassetteEnabled = false
|
||||
public var isPhraseReplacementEnabled = false
|
||||
|
@ -63,10 +60,6 @@ public extension vChewingLM {
|
|||
}
|
||||
|
||||
public static func disconnectSQLDB() {
|
||||
if Self.ptrStatement != nil {
|
||||
sqlite3_finalize(Self.ptrStatement)
|
||||
Self.ptrStatement = nil
|
||||
}
|
||||
if Self.ptrSQL != nil {
|
||||
sqlite3_close_v2(Self.ptrSQL)
|
||||
Self.ptrSQL = nil
|
||||
|
|
|
@ -57,23 +57,25 @@ enum CoreColumn: Int32 {
|
|||
extension vChewingLM.LMInstantiator {
|
||||
fileprivate static func querySQL(strStmt sqlQuery: String, coreColumn column: CoreColumn, handler: (String) -> Void) {
|
||||
guard Self.ptrSQL != nil else { return }
|
||||
defer { sqlite3_finalize(Self.ptrStatement) }
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &Self.ptrStatement, nil)
|
||||
while sqlite3_step(Self.ptrStatement) == SQLITE_ROW {
|
||||
guard let rawValue = sqlite3_column_text(Self.ptrStatement, column.id) else { continue }
|
||||
handler(String(cString: rawValue))
|
||||
performStatementSansResult { ptrStatement in
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &ptrStatement, nil)
|
||||
while sqlite3_step(ptrStatement) == SQLITE_ROW {
|
||||
guard let rawValue = sqlite3_column_text(ptrStatement, column.id) else { continue }
|
||||
handler(String(cString: rawValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate static func hasSQLResult(strStmt sqlQuery: String, coreColumn column: CoreColumn) -> Bool {
|
||||
guard Self.ptrSQL != nil else { return false }
|
||||
defer { sqlite3_finalize(Self.ptrStatement) }
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &Self.ptrStatement, nil)
|
||||
while sqlite3_step(Self.ptrStatement) == SQLITE_ROW {
|
||||
guard sqlite3_column_text(Self.ptrStatement, column.id) != nil else { continue }
|
||||
return true
|
||||
return performStatement { ptrStatement in
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &ptrStatement, nil)
|
||||
while sqlite3_step(ptrStatement) == SQLITE_ROW {
|
||||
guard sqlite3_column_text(ptrStatement, column.id) != nil else { continue }
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// 获取字根反查资料。
|
||||
|
@ -81,15 +83,16 @@ extension vChewingLM.LMInstantiator {
|
|||
var results: [String] = []
|
||||
let sqlQuery = "SELECT * FROM DATA_REV WHERE theChar='\(kanji)';"
|
||||
guard Self.ptrSQL != nil else { return nil }
|
||||
defer { sqlite3_finalize(Self.ptrStatement) }
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &Self.ptrStatement, nil)
|
||||
while sqlite3_step(Self.ptrStatement) == SQLITE_ROW {
|
||||
guard let rawValue = sqlite3_column_text(Self.ptrStatement, 1) else { continue }
|
||||
results.append(
|
||||
contentsOf: String(cString: rawValue).split(separator: "\t").map { reading in
|
||||
Self.restorePhonabetFromASCII(reading.description)
|
||||
}
|
||||
)
|
||||
performStatementSansResult { ptrStatement in
|
||||
sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &ptrStatement, nil)
|
||||
while sqlite3_step(ptrStatement) == SQLITE_ROW {
|
||||
guard let rawValue = sqlite3_column_text(ptrStatement, 1) else { continue }
|
||||
results.append(
|
||||
contentsOf: String(cString: rawValue).split(separator: "\t").map { reading in
|
||||
Self.restorePhonabetFromASCII(reading.description)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
return results.isEmpty ? nil : results
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ extension String {
|
|||
ptrDB != nil && sqlite3_exec(ptrDB, self, nil, nil, nil) == SQLITE_OK
|
||||
}
|
||||
|
||||
@discardableResult func runAsSQLPreparedStep(dbPointer ptrDB: inout OpaquePointer?, stmtPtr ptrStmt: inout OpaquePointer?) -> Bool {
|
||||
@discardableResult func runAsSQLPreparedStep(dbPointer ptrDB: inout OpaquePointer?) -> Bool {
|
||||
guard ptrDB != nil else { return false }
|
||||
return sqlite3_prepare_v2(ptrDB, self, -1, &ptrStmt, nil) == SQLITE_OK && sqlite3_step(ptrStmt) == SQLITE_DONE
|
||||
return performStatement { ptrStmt in
|
||||
sqlite3_prepare_v2(ptrDB, self, -1, &ptrStmt, nil) == SQLITE_OK && sqlite3_step(ptrStmt) == SQLITE_DONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,3 +62,23 @@ extension Array where Element == String {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Safe APIs for using SQLite Statements.
|
||||
|
||||
func performStatement(_ handler: (inout OpaquePointer?) -> Bool) -> Bool {
|
||||
var ptrStmt: OpaquePointer?
|
||||
defer {
|
||||
sqlite3_finalize(ptrStmt)
|
||||
ptrStmt = nil
|
||||
}
|
||||
return handler(&ptrStmt)
|
||||
}
|
||||
|
||||
func performStatementSansResult(_ handler: (inout OpaquePointer?) -> Void) {
|
||||
var ptrStmt: OpaquePointer?
|
||||
defer {
|
||||
sqlite3_finalize(ptrStmt)
|
||||
ptrStmt = nil
|
||||
}
|
||||
handler(&ptrStmt)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue