Skip to content

Commit 3f69614

Browse files
committed
DatabaseFunction with raw xFunc
No use right now, but I was really bugged that we could not use raw sqlite3_result_xxx methods from custom functions.
1 parent b4f3a83 commit 3f69614

File tree

1 file changed

+44
-16
lines changed

1 file changed

+44
-16
lines changed

GRDB/Core/DatabaseFunction.swift

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,45 @@ public final class DatabaseFunction: Identifiable, Sendable {
8282
/// such as `Int`, `String`, `Date`, etc. The array is guaranteed to
8383
/// have exactly `argumentCount` elements, provided `argumentCount` is
8484
/// not nil.
85-
public init(
85+
public convenience init(
8686
_ name: String,
8787
argumentCount: Int? = nil,
8888
pure: Bool = false,
8989
function: @escaping @Sendable ([DatabaseValue]) throws -> (any DatabaseValueConvertible)?)
9090
{
91-
self.id = ID(name: name, nArg: argumentCount.map(CInt.init) ?? -1)
92-
self.isPure = pure
93-
self.kind = .function { (argc, argv) in
91+
self.init(name, argumentCount: argumentCount, pure: pure) { (argc, argv, context) in
9492
let arguments = (0..<Int(argc)).map { index in
95-
DatabaseValue(sqliteValue: argv.unsafelyUnwrapped[index]!)
93+
DatabaseValue(sqliteValue: argv[index]!)
94+
}
95+
let result = try function(arguments)
96+
switch result?.databaseValue.storage ?? .null {
97+
case .null:
98+
sqlite3_result_null(context)
99+
case .int64(let int64):
100+
sqlite3_result_int64(context, int64)
101+
case .double(let double):
102+
sqlite3_result_double(context, double)
103+
case .string(let string):
104+
sqlite3_result_text(context, string, -1, SQLITE_TRANSIENT)
105+
case .blob(let data):
106+
data.withUnsafeBytes {
107+
sqlite3_result_blob(context, $0.baseAddress, CInt($0.count), SQLITE_TRANSIENT)
108+
}
96109
}
97-
return try function(arguments)
98110
}
99111
}
100112

113+
init(
114+
_ name: String,
115+
argumentCount: Int? = nil,
116+
pure: Bool = false,
117+
xFunc: @escaping XFunc)
118+
{
119+
self.id = ID(name: name, nArg: argumentCount.map(CInt.init) ?? -1)
120+
self.isPure = pure
121+
self.kind = .function(xFunc)
122+
}
123+
101124
/// Creates an SQL aggregate function.
102125
///
103126
/// For example:
@@ -256,11 +279,10 @@ public final class DatabaseFunction: Identifiable, Sendable {
256279
/// Feeds the `pApp` parameter of sqlite3_create_function_v2
257280
/// <http://sqlite.org/capi3ref.html#sqlite3_create_function>
258281
private class FunctionDefinition {
259-
let compute: (CInt, UnsafeMutablePointer<OpaquePointer?>?) throws -> (any DatabaseValueConvertible)?
260-
init(compute: @escaping (CInt, UnsafeMutablePointer<OpaquePointer?>?)
261-
throws -> (any DatabaseValueConvertible)?)
282+
let xFunc: XFunc
283+
init(xFunc: @escaping XFunc)
262284
{
263-
self.compute = compute
285+
self.xFunc = xFunc
264286
}
265287
}
266288

@@ -283,11 +305,19 @@ public final class DatabaseFunction: Identifiable, Sendable {
283305
}
284306
}
285307

308+
/// Feeds the `xFunc` parameter of sqlite3_create_function_v2
309+
/// <http://sqlite.org/capi3ref.html#sqlite3_create_function>
310+
typealias XFunc = @Sendable (
311+
_ argc: CInt,
312+
_ argv: UnsafeMutablePointer<OpaquePointer?>,
313+
_ context: OpaquePointer?
314+
) throws -> Void
315+
286316
/// A function kind: an "SQL function" or an "aggregate".
287317
/// See <http://sqlite.org/capi3ref.html#sqlite3_create_function>
288318
private enum Kind: Sendable {
289319
/// A regular function: SELECT f(1)
290-
case function(@Sendable (CInt, UnsafeMutablePointer<OpaquePointer?>?) throws -> (any DatabaseValueConvertible)?)
320+
case function(XFunc)
291321

292322
/// An aggregate: SELECT f(foo) FROM bar GROUP BY baz
293323
case aggregate(@Sendable () -> any DatabaseAggregate)
@@ -296,8 +326,8 @@ public final class DatabaseFunction: Identifiable, Sendable {
296326
/// <http://sqlite.org/capi3ref.html#sqlite3_create_function>
297327
var definition: AnyObject {
298328
switch self {
299-
case .function(let compute):
300-
return FunctionDefinition(compute: compute)
329+
case .function(let xFunc):
330+
return FunctionDefinition(xFunc: xFunc)
301331
case .aggregate(let makeAggregate):
302332
return AggregateDefinition(makeAggregate: makeAggregate)
303333
}
@@ -312,9 +342,7 @@ public final class DatabaseFunction: Identifiable, Sendable {
312342
.fromOpaque(sqlite3_user_data(sqliteContext))
313343
.takeUnretainedValue()
314344
do {
315-
try DatabaseFunction.report(
316-
result: definition.compute(argc, argv),
317-
in: sqliteContext)
345+
try definition.xFunc(argc, argv.unsafelyUnwrapped, sqliteContext)
318346
} catch {
319347
DatabaseFunction.report(error: error, in: sqliteContext)
320348
}

0 commit comments

Comments
 (0)