From 161aa100cc292d5a90bc897f4b99d1a27a91eced Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 30 Nov 2023 20:39:56 +0800 Subject: [PATCH] LMAssembly // Correctly handle statement pointers. --- .../LangModelAssembly/LMInstantiator.swift | 7 --- .../LMInstantiator_SQLExtension.swift | 43 ++++++++++--------- .../LangModelAssembly/vChewingLM.swift | 26 ++++++++++- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift index aad0d738..70c3b474 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift @@ -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 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift index 9f6f6334..12e9a151 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift @@ -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 } diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift index ec8d4c07..801e3104 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift @@ -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) +}