nim-eth/tests/db/test_kvstore_sqlite3_custom_func.nim
Kim De Mey e5c2b1784e
Replace registerCustomScalarFunction with createCustomFunction (#649)
* Replace registerCustomScalarFunction with createCustomFunction

The nice thing about `registerCustomScalarFunction` and
`registerCustomScalarFunction` was that it kept the sqlite calls
of type sqlite3_value_xxx inside kvstore_sqlite.

The big downside however is that the "custom" call is awfully
specific due to the specific function signature it demands.
It is likely that for each different use case, a new version
needs to be added.

In this PR the code gets altered to `createCustomFunction` which
allows to just create a custom function with directly xFunc
signature of sqlite. The downside of this is that you still need
to import sqlite_abi in your local code to have access to each of
the sqlite3_value_xxx and sqlite3_result_xxx calls. These could of
course also be wrapped.

* Fix custom sql func test
2023-11-21 14:39:24 +01:00

66 lines
1.6 KiB
Nim

{.used.}
import
std/sequtils,
testutils/unittests,
stew/endians2,
stew/ptrops,
sqlite3_abi,
../../eth/db/kvstore_sqlite3
procSuite "SqStoreRef custom function":
proc customSum(
ctx: SqliteContext, n: cint, v: SqliteValue)
{.cdecl, gcsafe, raises: [].} =
doAssert(n == 2)
let
ptrs = makeUncheckedArray(v)
blob1Len = sqlite3_value_bytes(ptrs[][0])
blob2Len = sqlite3_value_bytes(ptrs[][1])
num1 = uint32.fromBytesBE(makeOpenArray(
sqlite3_value_blob(ptrs[][0]), byte, blob1Len))
num2 = uint32.fromBytesBE(makeOpenArray(
sqlite3_value_blob(ptrs[][1]), byte, blob2Len))
sum = num1 + num2
bytes = sum.toBytesBE().toSeq()
sqlite3_result_blob(ctx, baseAddr bytes, cint bytes.len, SQLITE_TRANSIENT)
test "Create custom function":
let db = SqStoreRef.init("", "test", inMemory = true)[]
defer: db.close()
db.createCustomFunction("sum32", 2, customSum).expect(
"Custom function creation OK")
let kv = db.openKvStore().expect("Working database")
defer: kv.close()
# Use the custom function, which interprets blobs as uint32 numbers and
# sums them together
let sumStmt = db.prepareStmt(
"SELECT sum32(key, value) FROM kvstore;",
NoParams, seq[byte]).get()
let
key = uint32(39)
val = uint32(38)
kv.put(key.toBytesBE(), val.toBytesBE()).expect("Working database")
var sums: seq[seq[byte]] = @[]
discard sumStmt.exec do (res: seq[byte]):
sums.add(res)
check:
len(sums) == 1
let sum = uint32.fromBytesBE(sums[0])
check:
sum == key + val