Skip to content

Commit dfd73af

Browse files
committed
feat: implement MSSQL cancelQuery and applyQueryTimeout
1 parent d30fba6 commit dfd73af

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Copy as INSERT/UPDATE SQL statements from data grid context menu
1313
- Plugin download count display in Browse Plugins — fetched from GitHub Releases API and cached for 1 hour
14+
- MSSQL query cancellation (`cancelQuery`) and lock timeout (`applyQueryTimeout`) support
1415

1516
### Fixed
1617

Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ private final class FreeTDSConnection: @unchecked Sendable {
9292
private let database: String
9393
private let lock = NSLock()
9494
private var _isConnected = false
95+
private var _isCancelled = false
9596

9697
var isConnected: Bool {
9798
lock.lock()
@@ -172,6 +173,16 @@ private final class FreeTDSConnection: @unchecked Sendable {
172173
}
173174
}
174175

176+
func cancelCurrentQuery() {
177+
lock.lock()
178+
_isCancelled = true
179+
let proc = dbproc
180+
lock.unlock()
181+
182+
guard let proc else { return }
183+
dbcancel(proc)
184+
}
185+
175186
func executeQuery(_ query: String) async throws -> FreeTDSQueryResult {
176187
let queryToRun = String(query)
177188
return try await pluginDispatchAsync(on: queue) { [self] in
@@ -186,6 +197,10 @@ private final class FreeTDSConnection: @unchecked Sendable {
186197

187198
_ = dbcanquery(proc)
188199

200+
lock.lock()
201+
_isCancelled = false
202+
lock.unlock()
203+
189204
freetdsLastError = ""
190205
if dbcmd(proc, query) == FAIL {
191206
throw MSSQLPluginError.queryFailed("Failed to prepare query")
@@ -232,6 +247,14 @@ private final class FreeTDSConnection: @unchecked Sendable {
232247
if rowCode == Int32(NO_MORE_ROWS) { break }
233248
if rowCode == FAIL { break }
234249

250+
lock.lock()
251+
let cancelled = _isCancelled
252+
if cancelled { _isCancelled = false }
253+
lock.unlock()
254+
if cancelled {
255+
throw MSSQLPluginError.queryFailed("Query cancelled")
256+
}
257+
235258
var row: [String?] = []
236259
for i in 1...numCols {
237260
let len = dbdatlen(proc, Int32(i))
@@ -386,6 +409,16 @@ final class MSSQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
386409
)
387410
}
388411

412+
func cancelQuery() throws {
413+
freeTDSConn?.cancelCurrentQuery()
414+
}
415+
416+
func applyQueryTimeout(_ seconds: Int) async throws {
417+
guard seconds > 0 else { return }
418+
let ms = seconds * 1_000
419+
_ = try await execute(query: "SET LOCK_TIMEOUT \(ms)")
420+
}
421+
389422
func executeParameterized(query: String, parameters: [String?]) async throws -> PluginQueryResult {
390423
guard !parameters.isEmpty else {
391424
return try await execute(query: query)

0 commit comments

Comments
 (0)