对luasql-duckdb PR的测试

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文件在其他机器上安装,也可以执行,证明没有缺少依赖。

相关推荐
初见无风8 小时前
3.3 Lua代码中的协程
开发语言·lua·lua5.4
l1t8 小时前
利用DeepSeek辅助改写luadbi-duckdb支持日期和时间戳数据类型
c语言·数据库·人工智能·junit·lua·duckdb·deepseek
緣木求魚8 小时前
redis事务与Lua脚本
数据库·redis·lua
小龙报8 小时前
《算法通关指南算法千题篇(5)--- 1.最长递增,2.交换瓶子,3.翻硬币》
c语言·开发语言·数据结构·c++·算法·学习方法·visual studio
不剪发的Tony老师8 小时前
SQL Studio:一个基于浏览器的数据库查询工具
数据库·sql
yugi9878389 小时前
C语言多进程创建和回收
linux·c语言·算法
王道长服务器 | 亚马逊云9 小时前
AWS + SeyouCMS:海外资源站的高性能部署实战
服务器·网络·数据库·云计算·软件构建·aws
紫金桥软件10 小时前
组态软件和实时数据库区别大吗?
数据库·物联网·软件工程·scada·监控组态软件
小龙报10 小时前
《算法通关指南:数据结构和算法篇 --- 顺序表相关算法题》--- 1.移动零,2.颜色分类
c语言·开发语言·数据结构·c++·算法·学习方法·visual studio