mirror of https://github.com/status-im/nim-eth.git
Add support for array[N, byte] in SQLite queries
This commit is contained in:
parent
49c40c9b95
commit
482ea988c0
|
@ -3,7 +3,7 @@
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import
|
import
|
||||||
os, strformat,
|
std/[os, strformat],
|
||||||
sqlite3_abi,
|
sqlite3_abi,
|
||||||
./kvstore
|
./kvstore
|
||||||
|
|
||||||
|
@ -74,12 +74,22 @@ proc bindParam(s: RawStmtPtr, n: int, val: auto): cint =
|
||||||
sqlite3_bind_blob(s, n.cint, unsafeAddr val[0], val.len.cint, nil)
|
sqlite3_bind_blob(s, n.cint, unsafeAddr val[0], val.len.cint, nil)
|
||||||
else:
|
else:
|
||||||
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
||||||
|
elif val is array:
|
||||||
|
when val.items.typeof is byte:
|
||||||
|
# Prior to Nim 1.4 and view types array[N, byte] in tuples
|
||||||
|
# don't match with openarray[byte]
|
||||||
|
if val.len > 0:
|
||||||
|
sqlite3_bind_blob(s, n.cint, unsafeAddr val[0], val.len.cint, nil)
|
||||||
|
else:
|
||||||
|
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
||||||
|
else:
|
||||||
|
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||||
elif val is int32:
|
elif val is int32:
|
||||||
sqlite3_bind_int(s, n.cint, val)
|
sqlite3_bind_int(s, n.cint, val)
|
||||||
elif val is int64:
|
elif val is int64:
|
||||||
sqlite3_bind_int64(s, n.cint, val)
|
sqlite3_bind_int64(s, n.cint, val)
|
||||||
else:
|
else:
|
||||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||||
|
|
||||||
template bindParams(s: RawStmtPtr, params: auto) =
|
template bindParams(s: RawStmtPtr, params: auto) =
|
||||||
when params is tuple:
|
when params is tuple:
|
||||||
|
@ -125,6 +135,20 @@ template readResult(s: RawStmtPtr, column: cint, T: type): auto =
|
||||||
res.setLen(len)
|
res.setLen(len)
|
||||||
copyMem(addr res[0], sqlite3_column_blob(s, column), len)
|
copyMem(addr res[0], sqlite3_column_blob(s, column), len)
|
||||||
res
|
res
|
||||||
|
elif T is array:
|
||||||
|
# array[N, byte]. "genericParams(T)[1]" requires 1.4 to handle nnkTypeOfExpr
|
||||||
|
when typeof(block: (var a: T; a[0])) is byte:
|
||||||
|
var res: T
|
||||||
|
let colLen = sqlite3_column_bytes(s, column)
|
||||||
|
|
||||||
|
# truncate if the type is too small
|
||||||
|
# TODO: warning/error? We assume that users always properly dimension buffers
|
||||||
|
let copyLen = min(colLen, res.len)
|
||||||
|
if copyLen > 0:
|
||||||
|
copyMem(addr res[0], sqlite3_column_blob(s, column), copyLen)
|
||||||
|
res
|
||||||
|
else:
|
||||||
|
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||||
else:
|
else:
|
||||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||||
|
|
||||||
|
@ -445,4 +469,3 @@ when defined(metrics):
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -95,3 +95,84 @@ procSuite "SqStoreRef":
|
||||||
@[byte 5]
|
@[byte 5]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
test "Tuple with byte arrays support":
|
||||||
|
# openarray[byte] requires either Nim 1.4
|
||||||
|
# or hardcoding the seq[byte] and array[N, byte] paths
|
||||||
|
let db = SqStoreRef.init("", "test", inMemory = true)[]
|
||||||
|
defer: db.close()
|
||||||
|
|
||||||
|
let createTableRes = db.exec """
|
||||||
|
CREATE TABLE IF NOT EXISTS attestations(
|
||||||
|
validator_id INTEGER NOT NULL,
|
||||||
|
source_epoch INTEGER NOT NULL,
|
||||||
|
target_epoch INTEGER NOT NULL,
|
||||||
|
attestation_root BLOB NOT NULL UNIQUE,
|
||||||
|
UNIQUE (validator_id, target_epoch)
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
check createTableRes.isOk
|
||||||
|
|
||||||
|
let insertStmt = db.prepareStmt("""
|
||||||
|
INSERT INTO attestations(
|
||||||
|
validator_id,
|
||||||
|
source_epoch,
|
||||||
|
target_epoch,
|
||||||
|
attestation_root)
|
||||||
|
VALUES
|
||||||
|
(?,?,?,?);
|
||||||
|
""", (int32, int64, int64, array[32, byte]), void).get()
|
||||||
|
|
||||||
|
var hash: array[32, byte]
|
||||||
|
hash[1] = byte 1
|
||||||
|
hash[2] = byte 2
|
||||||
|
let insertRes = insertStmt.exec(
|
||||||
|
(123'i32, 2'i64, 4'i64, hash)
|
||||||
|
)
|
||||||
|
|
||||||
|
check: insertRes.isOk
|
||||||
|
|
||||||
|
let countStmt = db.prepareStmt(
|
||||||
|
"SELECT COUNT(*) FROM attestations;",
|
||||||
|
NoParams, int64).get
|
||||||
|
|
||||||
|
var totalRecords = 0
|
||||||
|
echo "About to call total attestations"
|
||||||
|
let countRes = countStmt.exec do (res: int64):
|
||||||
|
totalRecords = int res
|
||||||
|
|
||||||
|
check:
|
||||||
|
countRes.isOk and countRes.get == true
|
||||||
|
totalRecords == 1
|
||||||
|
|
||||||
|
let selectRangeStmt = db.prepareStmt("""
|
||||||
|
SELECT
|
||||||
|
source_epoch,
|
||||||
|
target_epoch,
|
||||||
|
attestation_root
|
||||||
|
FROM
|
||||||
|
attestations
|
||||||
|
WHERE
|
||||||
|
validator_id = ?
|
||||||
|
AND
|
||||||
|
? < source_epoch AND target_epoch < ?
|
||||||
|
LIMIT 1
|
||||||
|
""", (int32, int64, int64), (int64, int64, array[32, byte])).get()
|
||||||
|
|
||||||
|
block:
|
||||||
|
var digest: array[32, byte]
|
||||||
|
var source, target: int64
|
||||||
|
let selectRangeRes = selectRangeStmt.exec(
|
||||||
|
(123'i32, 1'i64, 5'i64)
|
||||||
|
) do (res: tuple[source, target: int64, hash: array[32, byte]]) {.gcsafe.}:
|
||||||
|
source = res.source
|
||||||
|
target = res.target
|
||||||
|
digest = res.hash
|
||||||
|
|
||||||
|
if selectRangeRes.isErr:
|
||||||
|
echo selectRangeRes.error
|
||||||
|
|
||||||
|
check:
|
||||||
|
selectRangeRes.isOk and selectRangeRes.get == true
|
||||||
|
source == 2
|
||||||
|
target == 4
|
||||||
|
digest == hash
|
||||||
|
|
Loading…
Reference in New Issue