From 1b766af3f3eba6e5b7a7f5c45e6591e43629dc92 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 27 May 2023 22:53:25 +0100 Subject: [PATCH] Return values in types other than string --- .envrc | 2 +- README.md | 4 ++ sqlite.prs => sql.prs | 0 src/{sqlite.nim => sql.nim} | 0 src/sqlite_actor.nim | 109 ++++++++++++++++++++++++++++++++---- 5 files changed, 102 insertions(+), 13 deletions(-) rename sqlite.prs => sql.prs (100%) rename src/{sqlite.nim => sql.nim} (100%) diff --git a/.envrc b/.envrc index 294916a..e82085e 100644 --- a/.envrc +++ b/.envrc @@ -1,2 +1,2 @@ -use flake "git+https://gitea.c3d2.de/ehmry/meta?ref=flake#simplex_history_actor" source_env .. +use flake syndicate#sqlite_actor diff --git a/README.md b/README.md index e542bcd..d694ae6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ Syndicate actor for accessing SQLite databases. +## Build + +Depends on the [SQLcipher](https://www.zetetic.net/sqlcipher/) library and pkg-config. + ## Example configuration ``` ? [ diff --git a/sqlite.prs b/sql.prs similarity index 100% rename from sqlite.prs rename to sql.prs diff --git a/src/sqlite.nim b/src/sql.nim similarity index 100% rename from src/sqlite.nim rename to src/sql.nim diff --git a/src/sqlite_actor.nim b/src/sqlite_actor.nim index 9790835..3c9ae22 100644 --- a/src/sqlite_actor.nim +++ b/src/sqlite_actor.nim @@ -1,27 +1,112 @@ # SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense +# Avoid Sqlite3 from the standard library because it is +# only held together by wishful thinking and dlload. + {.passC: staticExec("pkg-config --cflags sqlcipher").} {.passL: staticExec("pkg-config --libs sqlcipher").} -import std/db_sqlite +{.pragma: sqlite3h, header: "sqlite3.h".} + +var + SQLITE_VERSION_NUMBER {.importc, sqlite3h.}: cint + SQLITE_OK {.importc, sqlite3h.}: cint + SQLITE_ROW {.importc, sqlite3h.}: cint + SQLITE_DONE {.importc, sqlite3h.}: cint + SQLITE_OPEN_READONLY {.importc, sqlite3h.}: cint + +const + SQLITE_INTEGER = 1 + SQLITE_FLOAT = 2 + SQLITE_TEXT = 3 + SQLITE_BLOB = 4 + # SQLITE_NULL = 5 + +type + Sqlite3 {.importc: "sqlite3", sqlite3h.} = distinct pointer + Stmt {.importc: "sqlite3_stmt", sqlite3h.} = distinct pointer + +{.pragma: importSqlite3, importc: "sqlite3_$1", sqlite3h.} + +proc libversion_number: cint {.importSqlite3.} + +proc open_v2(filename: cstring; ppDb: ptr Sqlite3; flags: cint; zVfs: cstring): cint {.importSqlite3.} +proc close(ds: Sqlite3): int32 {.discardable, importSqlite3.} + +proc errmsg(db: Sqlite3): cstring {.importSqlite3.} + +proc prepare_v2(db: Sqlite3; zSql: cstring, nByte: cint; ppStmt: ptr Stmt; pzTail: ptr cstring): cint {.importSqlite3.} + +proc step(para1: Stmt): cint {.importSqlite3.} + +proc column_count(stmt: Stmt): int32 {.importSqlite3.} +proc column_blob(stmt: Stmt; col: cint): pointer {.importSqlite3.} +proc column_bytes(stmt: Stmt; col: cint): cint {.importSqlite3.} +proc column_double(stmt: Stmt; col: cint): float64 {.importSqlite3.} +proc column_int64(stmt: Stmt; col: cint): int64 {.importSqlite3.} +proc column_text(stmt: Stmt; col: cint): cstring {.importSqlite3.} +proc column_type(stmt: Stmt; col: cint): cint {.importSqlite3.} +proc finalize(stmt: Stmt): cint {.importSqlite3.} + +doAssert libversion_number() == SQLITE_VERSION_NUMBER + import preserves, syndicate -import ./sqlite +import ./sql -type Value = Preserve[void] +proc logError(db: Sqlite3; context: string) = + writeLine(stderr, errmsg(db), ": ", context) -type Args {.preservesDictionary.}= object - database: string - dataspace: Ref +type + Value = Preserve[void] + Args {.preservesDictionary.} = object + database: string + dataspace: Ref + +proc extractValue(stmt: Stmt; col: cint): Value = + case column_type(stmt, col) + of SQLITE_INTEGER: + result = toPreserve(column_int64(stmt, col)) + of SQLITE_FLOAT: + result = toPreserve(column_double(stmt, col)) + of SQLITE_TEXT: + result = Value(kind: pkString, string: newString(column_bytes(stmt, col))) + if result.string.len > 0: + copyMem(addr result.string[0], column_text(stmt, col), result.string.len) + of SQLITE_BLOB: + result = Value(kind: pkByteString, bytes: newSeq[byte](column_bytes(stmt, col))) + if result.bytes.len > 0: + copyMem(addr result.bytes[0], column_blob(stmt, col), result.bytes.len) + else: + result = initRecord[void]("null") + +proc extractRecord(stmt: Stmt; label: Value, arity: cint): Value = + result = initRecord(label, arity) + for col in 0..