luasql官方还没有duckdb驱动,有人提了一个PR,DuckDB,但还没被合并,它是基于libduckdb 1.1.1版本的。
1.克隆分支
因为他的duckdb驱动在分支上,直接克隆分支地址行不通
git clone --depth=1 https://bgithub.xyz/rousbound/luasql/tree/duckdb
Cloning into 'duckdb'...
fatal: repository 'https://bgithub.xyz/rousbound/luasql/tree/duckdb/' not found
询问DeepSeek后,他给出了如下步骤,确实可以。
mkdir luaduckdb
cd luaduckdb
root@66d4e20ec1d7:/par/luaduckdb# git clone https://bgithub.xyz/rousbound/luasql
Cloning into 'luasql'...
remote: Enumerating objects: 3036, done.
remote: Counting objects: 100% (57/57), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 3036 (delta 26), reused 16 (delta 16), pack-reused 2979 (from 3)
Receiving objects: 100% (3036/3036), 846.22 KiB | 1.24 MiB/s, done.
Resolving deltas: 100% (1861/1861), done.
cd luasql
git checkout duckdb
branch 'duckdb' set up to track 'origin/duckdb'.
Switched to a new branch 'duckdb'
上面方法拉取了所有分支,如果只要DuckDB分支,还有更简单的办法吗,张泽鹏先生提供了如下步骤,也可以,而且拉取的内容更少,一个命令也更省事。
mkdir treeduckdb
cd treeduckdb
git clone --depth=1 --single-branch -b duckdb https://bgithub.xyz/rousbound/luasql
Cloning into 'luasql'...
remote: Enumerating objects: 169, done.
remote: Counting objects: 100% (169/169), done.
remote: Compressing objects: 100% (106/106), done.
remote: Total 169 (delta 85), reused 100 (delta 47), pack-reused 0 (from 0)
Receiving objects: 100% (169/169), 115.58 KiB | 281.00 KiB/s, done.
Resolving deltas: 100% (85/85), done.
2.编译
在luasql目录下make,会提示编译选项,按它提示操作,报找不到头文件duckdb.h错误
root@66d4e20ec1d7:/par/luaduckdb/luasql# make
usage: make { duckdb | firebird | mysql | oci8 | odbc | postgres | sqlite | sqlite3 }
root@66d4e20ec1d7:/par/luaduckdb/luasql# make duckdb
gcc -fPIC -Wmissing-prototypes -Wmissing-declarations -ansi -pedantic -I/usr/include/lua5.2 -DLUASQL_VERSION_NUMBER='"2.6.0"' -std=gnu99 -fPIC -c src/luasql.c -o src/luasql.o
gcc -fPIC -Wmissing-prototypes -Wmissing-declarations -ansi -pedantic -I/usr/include/lua5.2 -DLUASQL_VERSION_NUMBER='"2.6.0"' -std=gnu99 -fPIC src/ls_duckdb.c -o src/duckdb.so -shared src/luasql.o
src/ls_duckdb.c:7:10: fatal error: duckdb.h: No such file or directory
7 | #include "duckdb.h"
| ^~~~~~~~~~
compilation terminated.
make: *** [Makefile:24: src/duckdb.so] Error 1
我选的1.41版本的libduckdb,设置相应环境变量,重新make,这次是编译错误
root@66d4e20ec1d7:/par/luaduckdb/luasql# export C_INCLUDE_PATH=$C_INCLUDE_PATH:/par/141
root@66d4e20ec1d7:/par/luaduckdb/luasql# export LIBRARY_PATH=$LIBRARY_PATH:/par/141
root@66d4e20ec1d7:/par/luaduckdb/luasql# make duckdb
gcc -fPIC -Wmissing-prototypes -Wmissing-declarations -ansi -pedantic -I/usr/include/lua5.2 -DLUASQL_VERSION_NUMBER='"2.6.0"' -std=gnu99 -fPIC src/ls_duckdb.c -o src/duckdb.so -shared src/luasql.o -I /par/141
src/ls_duckdb.c: In function 'create_connection':
src/ls_duckdb.c:401:15: error: assignment to 'duckdb_connection' {aka 'struct _duckdb_connection *'} from incompatible pointer type 'struct _duckdb_connection **' [-Wincompatible-pointer-types]
401 | conn->con = con;
| ^
src/ls_duckdb.c: In function 'env_connect':
src/ls_duckdb.c:448:36: error: passing argument 3 of 'create_connection' from incompatible pointer type [-Wincompatible-pointer-types]
448 | return create_connection(L, 1, con);
| ^~~
| |
| duckdb_connection {aka struct _duckdb_connection *}
src/ls_duckdb.c:393:78: note: expected 'struct _duckdb_connection ** const' but argument is of type 'duckdb_connection' {aka 'struct _duckdb_connection *'}
393 | static int create_connection(lua_State *L, int env, duckdb_connection *const con) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~^~~
src/ls_duckdb.c: At top level:
src/ls_duckdb.c:533:16: warning: no previous prototype for 'luaopen_luasql_duckdb' [-Wmissing-prototypes]
533 | LUASQL_API int luaopen_luasql_duckdb(lua_State *L) {
| ^~~~~~~~~~~~~~~~~~~~~
按错误提示信息修改源代码,把con变量改成取地址和解引用,
c
/*
** Create a new Connection object and push it on top of the stack.
*/
static int create_connection(lua_State *L, int env, duckdb_connection *const con) {
conn_data *conn = (conn_data *)LUASQL_NEWUD(L, sizeof(conn_data));
luasql_setmeta(L, LUASQL_CONNECTION_DUCKDB);
/* fill in structure */
conn->closed = 0;
conn->env = LUA_NOREF;
conn->auto_commit = 1;
conn->con = *con; /* 原代码 conn->con = con */
lua_pushvalue(L, env);
conn->env = luaL_ref(L, LUA_REGISTRYINDEX);
return 1;
}
/*
** Connects to a DuckDB database.
*/
static int env_connect(lua_State *L) {
const char *sourcename = luaL_checkstring(L, 2);
duckdb_database db;
duckdb_connection con;
duckdb_config conf;
duckdb_create_config(&conf);
// Changes luasql API so the 7th argument is a config table
// Ex: dado.connect("db", nil, nil, "duckdb", nil, nil, {access_mode = "READ_ONLY", memory_limit = '69GB'})
// Used 7th argument because as far as I know ls_postgres.c uses 5th and 6th:
// const char *pghost = luaL_optstring(L, 5, NULL);
// const char *pgport = luaL_optstring(L, 6, NULL);
if (lua_gettop(L) >= 7 && !lua_isnil(L, 7)) {
luaL_checktype(L, 7, LUA_TTABLE);
lua_pushnil(L); // First key
while (lua_next(L, 7) != 0) {
// Get the key and value from the table
const char *key = lua_tostring(L, -2);
const char *val = lua_tostring(L, -1);
// Set the configuration option
duckdb_set_config(conf, key, val);
lua_pop(L, 1); // Remove value, keep key for the next iteration
}
}
char * error = NULL;
getenvironment(L); /* validate environment */
// Needs to pass in db config in third parameter here
if (duckdb_open_ext(sourcename, &db, conf, &error) != DuckDBSuccess) {
return luasql_failmsg(L, "error connecting to database. DuckDB: ", error);
}
if (duckdb_connect(db, &con) != DuckDBSuccess) {
duckdb_close(&db);
return luasql_failmsg(L, "error connecting to database. DuckDB: ", "Unspecified driver error");
}
return create_connection(L, 1, &con); /* 原代码 return create_connection(L, 1, con) */
}
编译通过,make duckdb完成。
gcc -fPIC -Wmissing-prototypes -Wmissing-declarations -ansi -pedantic -I/usr/include/lua5.2 -DLUASQL_VERSION_NUMBER='"2.6.0"' -std=gnu99 -fPIC src/ls_duckdb.c -o src/duckdb.so -shared src/luasql.o
src/ls_duckdb.c:533:16: warning: no previous prototype for 'luaopen_luasql_duckdb' [-Wmissing-prototypes]
533 | LUASQL_API int luaopen_luasql_duckdb(lua_State *L) {
| ^~~~~~~~~~~~~~~~~~~~~
root@66d4e20ec1d7:/par/luaduckdb/luasql# make
usage: make { duckdb | firebird | mysql | oci8 | odbc | postgres | sqlite | sqlite3 }
root@66d4e20ec1d7:/par/luaduckdb/luasql# make duckdb
make: Nothing to be done for 'duckdb'.
有了模块,还要安装到合适的位置,否则lua无法找到它,执行lua脚本就会报错,比如,执行项目自带的tests目录下的test.lua文件。
root@66d4e20ec1d7:/par/luaduckdb/luasql/rockspec# cd ../tests
root@66d4e20ec1d7:/par/luaduckdb/luasql/tests# lua test.lua
Usage test.lua <driver> [<data source> [, <user> [, <password>]]]
root@66d4e20ec1d7:/par/luaduckdb/luasql/tests# lua test.lua DuckDB
LuaSQL test: couldn't find driver-specific test file (DuckDB.lua).
Proceeding with general test
lua: test.lua:693: module 'luasql.DuckDB' not found:
no field package.preload['luasql.DuckDB']
no file '/usr/local/share/lua/5.4/luasql/DuckDB.lua'
no file '/usr/local/share/lua/5.4/luasql/DuckDB/init.lua'
no file '/usr/local/lib/lua/5.4/luasql/DuckDB.lua'
no file '/usr/local/lib/lua/5.4/luasql/DuckDB/init.lua'
no file './luasql/DuckDB.lua'
no file './luasql/DuckDB/init.lua'
no file '/usr/local/lib/lua/5.4/luasql/DuckDB.so'
no file '/usr/local/lib/lua/5.4/loadall.so'
no file './luasql/DuckDB.so'
no file '/usr/local/lib/lua/5.4/luasql.so'
no file '/usr/local/lib/lua/5.4/loadall.so'
no file './luasql.so'
stack traceback:
[C]: in function 'require'
test.lua:693: in main chunk
[C]: in ?
按照 https://www.runoob.com/lua/lua-modules-packages.html 介绍的方法,设置LUA_PATH变量也没有解决,所以要用打包成rock文件的方法来安装。
询问DeepSeek, 他给出的命令是luarocks pack,试验了一下,报错,这个错误在网上也挺多人提问的。
root@66d4e20ec1d7:/par/treeduckdb# cd ../luaduckdb
root@66d4e20ec1d7:/par/luaduckdb# cd luasql
root@66d4e20ec1d7:/par/luaduckdb/luasql# luarocks pack rockspec/luasql-duckdb-2.6.0-3.rockspec
Error: Couldn't extract archive /tmp/luarocks_pack-luasql-duckdb-2.6.0-3-4088158: unrecognized filename extension
查看luarocks在线帮助luarocks make也可以打包,
luarocks make --help
Usage: luarocks make [-h] [--no-install] [--no-doc]
[--pack-binary-rock] [--keep] [--force] [--force-fast]
[--verify] [--sign] [--check-lua-versions] [--pin]
[--no-manifest] [--only-deps] [--deps-mode <mode>] [<rockspec>]
将luasql-duckdb-2.6.0-3.rockspec文件从rockspec子目录复制到luasql目录下,用luarocks make打包, 比 pack好很多,至少每步的错误都是明确的,可以解决。比如设置选项参数,比如缺少zip文件
cp rockspec/luasql-duckdb-2.6.0-3.rockspec .
root@66d4e20ec1d7:/par/luaduckdb/luasql# luarocks make luasql-duckdb-2.6.0-3.rockspec --pack-binary-rock
Error: Could not find header file for DUCKDB
No file duckdb.h in /usr/local/include
No file duckdb.h in /usr/include
No file duckdb.h in /include
You may have to install DUCKDB in your system and/or pass DUCKDB_DIR or DUCKDB_INCDIR to the luarocks command.
Example: luarocks install luasql-duckdb DUCKDB_DIR=/usr/local
root@66d4e20ec1d7:/par/luaduckdb/luasql# luarocks make luasql-duckdb-2.6.0-3.rockspec --pack-binary-rock DUCKDB_DIR=/par/141 DUCKDB_INCDIR=/par/141
luasql-duckdb 2.6.0-3 depends on lua >= 5.1 (5.4-1 provided by VM: success)
gcc -O2 -fPIC -I/usr/local/include -c src/luasql.c -o src/luasql.o -I/par/141
gcc -O2 -fPIC -I/usr/local/include -c src/ls_duckdb.c -o src/ls_duckdb.o -I/par/141
gcc -shared -o /tmp/luarocks_build-LuaSQL-DuckDB-2.6.0-3-1792292/luasql/duckdb.so src/luasql.o src/ls_duckdb.o -L/par/141/lib/aarch64-linux-gnu -Wl,-rpath,/par/141/lib/aarch64-linux-gnu -lduckdb
No existing manifest. Attempting to rebuild...
luasql-duckdb 2.6.0-3 is now installed in /tmp/luarocks_luarocks-build-pack-luasql-duckdb-795982 (license: MIT/X11)
Error: Failed packing /par/luaduckdb/luasql/luasql-duckdb-2.6.0-3.linux-aarch64.rock - 'zip' program not found. Make sure zip is installed and is available in your PATH (or you may want to edit the 'variables.ZIP' value in file '/usr/local/etc/luarocks/config-5.4.lua')
在网站 https://debian.pkgs.org/12/debian-main-arm64/zip_3.0-13_arm64.deb.html找到了zip的deb安装包,下载并安装后,上述命令就能正确执行完成打包了。这个包能用luarocks install命令成功安装。
root@66d4e20ec1d7:/par/luaduckdb/luasql# wget http://ftp.de.debian.org/debian/pool/main/z/zip/zip_3.0-13_arm64.deb
2025-10-30 16:19:05 (43.9 KB/s) - 'zip_3.0-13_arm64.deb' saved [222732/222732]
root@66d4e20ec1d7:/par/luaduckdb/luasql# dpkg --install zip_3.0-13_arm64.deb
Selecting previously unselected package zip.
(Reading database ... 25180 files and directories currently installed.)
Preparing to unpack zip_3.0-13_arm64.deb ...
Unpacking zip (3.0-13) ...
Setting up zip (3.0-13) ...
root@66d4e20ec1d7:/par/luaduckdb/luasql# luarocks make luasql-duckdb-2.6.0-3.rockspec --pack-binary-rock DUCKDB_DIR=/par/141 DUCKDB_INCDIR=/par/141
luasql-duckdb 2.6.0-3 depends on lua >= 5.1 (5.4-1 provided by VM: success)
gcc -O2 -fPIC -I/usr/local/include -c src/luasql.c -o src/luasql.o -I/par/141
gcc -O2 -fPIC -I/usr/local/include -c src/ls_duckdb.c -o src/ls_duckdb.o -I/par/141
gcc -shared -o /tmp/luarocks_build-LuaSQL-DuckDB-2.6.0-3-2518578/luasql/duckdb.so src/luasql.o src/ls_duckdb.o -L/par/141/lib/aarch64-linux-gnu -Wl,-rpath,/par/141/lib/aarch64-linux-gnu -lduckdb
No existing manifest. Attempting to rebuild...
luasql-duckdb 2.6.0-3 is now installed in /tmp/luarocks_luarocks-build-pack-luasql-duckdb-4271313 (license: MIT/X11)
Packed: /par/luaduckdb/luasql/luasql-duckdb-2.6.0-3.linux-aarch64.rock
root@66d4e20ec1d7:/par/luaduckdb/luasql# luarocks install luasql-duckdb-2.6.0-3.linux-aarch64.rock
luasql-duckdb 2.6.0-3 depends on lua >= 5.1 (5.4-1 provided by VM: success)
luasql-duckdb 2.6.0-3 is now installed in /usr/local (license: MIT/X11)
把tests目录下的example.lua文件修改为如下,让它引用刚才安装的luasql.duckdb包
lua
-- See Copyright Notice in license.html
-- load driver
local driver = require"luasql.duckdb"
-- create environment object
env = assert (driver.duckdb())
-- connect to data source
con = assert (env:connect("luasql-test"))
-- reset our table
res = con:execute"DROP TABLE people"
res = assert (con:execute[[
CREATE TABLE people(
name varchar(50),
email varchar(50)
)
]])
-- add a few elements
list = {
{ name="Jose das Couves", email="jose@couves.com", },
{ name="Manoel Joaquim", email="manoel.joaquim@cafundo.com", },
{ name="Maria das Dores", email="maria@dores.com", },
}
for i, p in pairs (list) do
res = assert (con:execute(string.format([[
INSERT INTO people
VALUES ('%s', '%s')]], p.name, p.email)
))
end
-- retrieve a cursor
cur = assert (con:execute"SELECT name, email from people")
-- print all rows
row = cur:fetch ({}, "a") -- the rows will be indexed by field names
while row do
print(string.format("Name: %s, E-mail: %s", row.name, row.email))
row = cur:fetch (row, "a") -- reusing the table of results
end
-- close everything
cur:close()
con:close()
env:close()
执行就成功了。如果提示找不到libduckdb.so文件,把它所在的目录用export LD_LIBRARY_PATH=命令加入即可。
root@66d4e20ec1d7:/par/luaduckdb/luasql/tests# lua example.lua
Name: Jose das Couves, E-mail: jose@couves.com
Name: Manoel Joaquim, E-mail: manoel.joaquim@cafundo.com
Name: Maria das Dores, E-mail: maria@dores.com
Bus error (core dumped)
将刚才打包的rock文件在其他机器上安装,也可以执行,证明没有缺少依赖。