I was playing around with making a SQLite extension in Nim the other day.
Here's a simple example of how to do this. This example defines a _hello_
function in SQL that takes one parameter and returns "Hello <value>". With a
bit more effort you can do things like create virtual tables, etc.
## Nim version of Hello World SQLite plugin
##
## compile as DLL/.so
## nim c --app:lib helloworld.nim
##
## Test with something like the following:
##
## sqlite3
## sqlite> .load libhelloworld
## sqlite> CREATE TABLE testing(id INTEGER PRIMARY KEY, name STRING);
## sqlite> INSERT INTO testing VALUES (1, 'Alice'), (2, 'Bob');
## sqlite> SELECT id, hello(name) FROM testing;
## 1|Hello Alice
## 2|Hello Bob
## sqlite>
import sqlite3
{.emit:"""
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
"""
.}
# This is the logic for our 'hello()' function that will be available in
SQLite
proc helloFunc(context : Pcontext, argcount: int32, argv: PValueArg)
{.cdecl.} =
assert argcount == 1
var
output = "Hello " & $value_text(argv[0])
length = output.len + 1
result_text(context, output, length.int32, SQLITE_TRANSIENT)
proc sqlite3_helloworld_init(sqlite3 : PSqlite3, pzErrMsg: ptr string,
pApi: ptr int32) : cint {.exportc, dynlib.} =
result = SQLITE_OK
{.emit:"""
SQLITE_EXTENSION_INIT2(pApi);
"""
.}
var
# Can be pointer to any extra data you want available in your function
# but it has to be scoped to survive the length of your
# database connection and not just this proc
userData = cast[pointer](0)
let
funcName = "hello" # name that will be available in SQL.
numOfArgs = 1.int32
encoding = SQLITE_UTF8.int32
# These must be null pointers for just a basic SQL function
stepFunc = cast[Create_function_step_func](0)
finalFunc = cast[Create_function_final_func](0)
discard create_function(sqlite3, funcName, numOfArgs, encoding,
userData, helloFunc, stepFunc, finalFunc)
Run