LMAssembly // Correctly handle statement pointers.

This commit is contained in:
ShikiSuen 2023-11-30 20:39:56 +08:00
parent a66879f7bf
commit 161aa100cc
3 changed files with 47 additions and 29 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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)
}