这个插件比名字类似的lua插件功能强大太多,不要装错。
存储库地址:https://github.com/alitrack/duckdb-luajit
1.安装插件
memory D force install luajit from community;
memory D load luajit;
2.拉取远程duckdb-luajit现成库(https://github.com/alitrack/duckdb-luajit-libs)
--列举可用模块
memory D SELECT * FROM luajit_module(mode := 'list_remote');
┌─────────┬─────────────┬─────────────┬────────────────────┬────────────────────────────────────────────────┬──────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────────┼─────────────┼────────────────────┼────────────────────────────────────────────────┼──────────┤
│ true │ list_remote │ list_remote │ duckdb-luajit-libs │ available libs:\n dicom --- libs/datasource/dic │ │
│ │ │ │ │ om.lua\n dirscan --- libs/datasource/dirscan.lu │ │
│ │ │ │ │ a\n export --- libs/export/export.lua\n json --- │ │
│ │ │ │ │ libs/parser/json.lua\n base64 --- libs/udf/bas │ │
│ │ │ │ │ e64.lua\n crc32 --- libs/udf/crc32.lua\n uuid │ │
│ │ │ │ │ --- libs/udf/uuid.lua\n html_escape --- libs/udf/ │ │
│ │ │ │ │ html_escape.lua\n mcp_demo --- libs/mcp/mcp-ser │ │
│ │ │ │ │ ver.sql\n │ │
└─────────┴─────────────┴─────────────┴────────────────────┴────────────────────────────────────────────────┴──────────┘
--拉取base64 udf
memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'base64');
┌─────────┬─────────┬─────────┬──────────────────────────────────────┬──────────────────────────────────────┬──────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼──────────────────────────────────────┼──────────────────────────────────────┼──────────┤
│ true │ install │ install │ installed 'base64' (UDF) --- cached at │ luajit_table('base64') or luajit_s(' │ base64 │
│ │ │ │ ~/.duckdb/luajit-libs/base64.lua │ base64', ...) │ │
└─────────┴─────────┴─────────┴──────────────────────────────────────┴──────────────────────────────────────┴──────────┘
--使用base64 udf成功
memory D SELECT luajit_s('base64', 'hello');
┌─────────────────────────────┐
│ luajit_s('base64', 'hello') │
│ varchar │
├─────────────────────────────┤
│ aGVsbG8= │
└─────────────────────────────┘
错误的用法尝试
--希望安装mcp_demo,报错
memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'mcp_demo');
┌─────────┬─────────┬─────────┬───────────────────────────────────────────────────────────────────┬─────────┬──────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼───────────────────────────────────────────────────────────────────┼─────────┼──────────┤
│ false │ install │ │ install 'mcp_demo': [string "-- @lib: mcp_demo..."]:28: '=' expec │ │ mcp_demo │
│ │ │ │ ted near '*' │ │ │
└─────────┴─────────┴─────────┴───────────────────────────────────────────────────────────────────┴─────────┴──────────┘
--拉取sudoku失败,第一次是网络问题,第二次网络正常后,说不在索引中
memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'sudoku');
┌─────────┬─────────┬─────────┬───────────────────────────────────────────────────────────────────┬─────────┬──────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼───────────────────────────────────────────────────────────────────┼─────────┼──────────┤
│ false │ install │ │ install 'sudoku' failed: IO Error: Timeout was reached error for │ │ sudoku │
│ │ │ │ HTTP HEAD to 'https://raw.githubusercontent.com/alitrack/duckdb-l │ │ │
│ │ │ │ uajit-libs/main/INDEX' │ │ │
└─────────┴─────────┴─────────┴───────────────────────────────────────────────────────────────────┴─────────┴──────────┘
memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'sudoku');
┌─────────┬─────────┬─────────┬──────────────────────────────────────────────────────────┬─────────┬──────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼──────────────────────────────────────────────────────────┼─────────┼──────────┤
│ false │ install │ │ install 'sudoku' failed: lib 'sudoku' not found in INDEX │ │ sudoku │
└─────────┴─────────┴─────────┴──────────────────────────────────────────────────────────┴─────────┴──────────┘
实地查看索引内容,确实不存在一个sudoku udf
ls ~/.duckdb/luajit-libs/
INDEX base64.lua mcp_demo.lua
root@DESKTOP-59T6U68:/mnt/c/d# cat ~/.duckdb/luajit-libs/INDEX
dicom|libs/datasource/dicom.lua
dirscan|libs/datasource/dirscan.lua
export|libs/export/export.lua
json|libs/parser/json.lua
base64|libs/udf/base64.lua
crc32|libs/udf/crc32.lua
uuid|libs/udf/uuid.lua
html_escape|libs/udf/html_escape.lua
mcp_demo|libs/mcp/mcp-server.sql
考虑到国内上github.com经常网络出错,趁早把存储库整个下载到本地duckdb-luajit-libs-main目录下。
然后复制mcp-server.sql中的语句
-- 2. 注册 Lua UDF: 数独求解 (模块文件 sudoku.lua 需同目录, 或改用 install 协议从本仓库拉)
memory D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve',
source := 'local s = dofile(''duckdb-luajit-libs-main/libs/mcp/sudoku.lua'') return function(x) return s.solve(x) end');
┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────┤
│ true │ compile │ compile │ OK │ │ sudoku_solve │
└─────────┴─────────┴─────────┴─────────┴─────────┴──────────────┘
memory D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ r │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │
└───────────────────────────────────────────────────────────────────────────────────┘
memory D .timer on
memory D select count(*) from read_csv('sudoku17.txt');
┌──────────────┐
│ count_star() │
│ int64 │
├──────────────┤
│ 49150 │
└──────────────┘
Run Time (s): real 0.075 user 0.007009 sys 0.014781
memory D with a(i) as(select * from read_csv('sudoku17.txt') limit 3)select luajit_s('sudoku_solve',i)from a;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ luajit_s('sudoku_solve', i) │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │
│ 673894512912735486845612973798261354526473891134589267469128735287356149351947628 │
│ 679835412123694758548217936416723895892561374735489621287956143961342587354178269 │
└───────────────────────────────────────────────────────────────────────────────────┘
Run Time (s): real 10.209 user 9.331371 sys 0.000000
计算成功,速度不算太快,可能是算法过于简单原因。
李艳红先生将上述测试文档输入AI,AI自动找到了问题,并且修复了,顺便还升级了数独算法,用新的sudoku.lua重新编译一版sudoku_solve_opt函数,速度是上一版本的100倍。
testluaudf D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve_opt',
source := 'local s = dofile(''./sudoku.lua'') return function(x) return s.solve(x) end');
┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────────┤
│ true │ compile │ compile │ OK │ │ sudoku_solve_opt │
└─────────┴─────────┴─────────┴─────────┴─────────┴──────────────────┘
testluaudf D with a(i) as(select * from read_csv('sudoku17.txt') limit 3)select luajit_s('sudoku_solve_opt',i)from a;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ luajit_s('sudoku_solve_opt', i) │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │
│ 673894512912735486845612973798261354526473891134589267469128735287356149351947628 │
│ 679835412123694758548217936416723895892561374735489621287956143961342587354178269 │
└───────────────────────────────────────────────────────────────────────────────────┘
testluaudf D .timer on
testluaudf D with a(i) as(from read_csv('sudoku17.txt') limit 3)select max(luajit_s('sudoku_solve_opt',i))from a;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ max(luajit_s('sudoku_solve_opt', i)) │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │
└───────────────────────────────────────────────────────────────────────────────────┘
Run Time (s): real 0.071 user 0.015625 sys 0.000000
testluaudf D with a(i) as(from read_csv('sudoku17.txt') limit 300)select max(luajit_s('sudoku_solve_opt',i))from a;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ max(luajit_s('sudoku_solve_opt', i)) │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 986735124143298576275614893459183762821467359637529481592371648364852917718946235 │
└───────────────────────────────────────────────────────────────────────────────────┘
Run Time (s): real 5.289 user 5.234375 sys 0.031250
又及,上个版本还存在lua自定义函数不能持久化的问题,现在也解决了。
到https://github.com/alitrack/duckdb-luajit/releases/tag/v0.32 下载离线版插件。强制安装并装载。
将内存数据库保存到物理数据库文件,再次打开此文件,load luajit;后,原来编译的lua自定义函数直接能用。
C:\d>duckdb155 -unsigned
DuckDB v1.5.5 (Variegata)
Enter ".help" for usage hints.
memory D force install 'C:\Users\lt\Downloads\luajit.duckdb_extension';
memory D from duckdb_extensions();
┌──────────────────┬─────────┬───────────┬───┬───────────────────┬───────────────────┬─────────────────────────────────┐
│ extension_name │ loaded │ installed │ ... │ extension_version │ install_mode │ installed_from │
│ varchar │ boolean │ boolean │ ... │ varchar │ varchar │ varchar │
├──────────────────┼─────────┼───────────┼───┼───────────────────┼───────────────────┼─────────────────────────────────┤
│ luajit │ false │ true │ ... │ v0.32 │ CUSTOM_PATH │ C:\Users\lt\Downloads\luajit.d... │
memory D load luajit;
memory D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve',
source := 'local s = dofile(''duckdb-luajit-libs-main/libs/mcp/sudoku.lua'') return function(x) return s.solve(x) end');
┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────┐
│ ok │ mode │ phase │ message │ detail │ sql_name │
│ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │
├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────┤
│ true │ compile │ compile │ OK │ │ sudoku_solve │
└─────────┴─────────┴─────────┴─────────┴─────────┴──────────────┘
memory D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ r │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │
└───────────────────────────────────────────────────────────────────────────────────┘
memory D ATTACH 'lua032.db';
memory D COPY FROM DATABASE memory to lua032;
memory D .exit
C:\d>duckdb155 lua032.db -unsigned
DuckDB v1.5.5 (Variegata)
Enter ".help" for usage hints.
lua032 D load luajit;
lua032 D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r;
┌───────────────────────────────────────────────────────────────────────────────────┐
│ r │
│ varchar │
├───────────────────────────────────────────────────────────────────────────────────┤
│ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │
└───────────────────────────────────────────────────────────────────────────────────┘