Skip to content
This repository was archived by the owner on Aug 20, 2020. It is now read-only.

Commit fc093ab

Browse files
committed
Add SQL abstraction layer
1 parent b47400e commit fc093ab

File tree

2 files changed

+168
-20
lines changed

2 files changed

+168
-20
lines changed

abstraction.lua

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
local modname = minetest.get_current_modname()
2+
3+
local thismod = _G[modname]
4+
5+
---- Table creation & deletion
6+
7+
function thismod.create_table_sql(name, params)
8+
local lines = {}
9+
for _, coldata in ipairs(params.columns) do
10+
local line = (coldata.name or coldata[1]) .. ' ' .. (coldata.type or coldata[2])
11+
if coldata.notnull then
12+
line = line .. ' NOT NULL'
13+
end
14+
if coldata.autoincrement then
15+
line = line .. ' AUTO_INCREMENT'
16+
end
17+
table.insert(lines, line)
18+
end
19+
table.insert(lines, 'PRIMARY KEY (' .. table.concat(params.pkey, ',') .. ')')
20+
for fkeyname, fkeydata in pairs(params.fkeys or {}) do
21+
table.insert(lines, 'FOREIGN KEY (' .. fkeyname .. ') REFERENCES ' .. fkeydata.table ..
22+
'(' .. fkeydata.column .. ')')
23+
end
24+
for _, ucol in pairs(params.unique or {}) do
25+
if type(ucol) == 'table' then
26+
table.insert(lines, 'UNIQUE (' .. table.concat(ucol, ',') .. ')')
27+
else
28+
table.insert(lines, 'UNIQUE (' .. ucol .. ')')
29+
end
30+
end
31+
return 'CREATE TABLE ' .. name .. ' (' .. table.concat(lines, ',') .. ')'
32+
end
33+
function thismod.create_table(name, params)
34+
thismod.conn:query(thismod.create_table_sql(name, params))
35+
end
36+
37+
function thismod.drop_table_sql(name)
38+
return 'DROP TABLE ' .. name
39+
end
40+
function thismod.drop_table(name)
41+
thismod.conn:query(thismod.drop_table_sql(name))
42+
end
43+
44+
---- INSERT prepare
45+
46+
function thismod.prepare_insert_sql(tablename, colnames)
47+
local qmarks = {}
48+
for i = 1, #colnames do
49+
qmarks[i] = '?'
50+
end
51+
return 'INSERT INTO ' .. tablename .. '(' .. table.concat(colnames, ',') .. ') VALUES (' ..
52+
table.concat(qmarks, ',') .. ')'
53+
end
54+
function thismod.prepare_insert(tablename, cols)
55+
local colnames, coltypes = {}, {}
56+
for _, col in ipairs(cols) do
57+
table.insert(colnames, col.name or col[1])
58+
table.insert(coltypes, col.type or col[2])
59+
end
60+
local stmt = thismod.conn:prepare(thismod.prepare_insert_sql(tablename, colnames))
61+
return stmt, stmt:bind_params(coltypes)
62+
end
63+
64+
---- UPDATE prepare
65+
66+
function thismod.prepare_update_sql(tablename, colnames, where)
67+
return 'UPDATE ' .. tablename .. ' SET ' .. table.concat(colnames, ',') .. ' WHERE ' .. where
68+
end
69+
function thismod.prepare_update(tablename, cols, where, wheretypes)
70+
local colnames, paramtypes = {}, {}
71+
for _, col in ipairs(cols) do
72+
table.insert(colnames, (col.name or col[1]) .. '=?')
73+
table.insert(paramtypes, col.type or col[2])
74+
end
75+
for _, wheretype in ipairs(wheretypes) do
76+
table.insert(paramtypes, wheretype)
77+
end
78+
local stmt = thismod.conn:prepare(thismod.prepare_update_sql(tablename, colnames, where))
79+
return stmt, stmt:bind_params(paramtypes)
80+
end
81+
82+
---- DELETE prepare
83+
84+
function thismod.prepare_delete(tablename, where, wheretypes)
85+
local stmt = thismod.conn:prepare('DELETE FROM ' .. tablename .. ' WHERE ' .. where)
86+
return stmt, stmt:bind_params(wheretypes)
87+
end
88+
89+
---- SELECT prepare
90+
91+
function thismod.prepare_select_sql(tablename, colnames, where)
92+
return 'SELECT ' .. table.concat(colnames, ',') .. ' FROM ' .. tablename .. ' WHERE ' .. where
93+
end
94+
function thismod.prepare_select(tablename, cols, where, wheretypes)
95+
local colnames, coltypes = {}, {}
96+
for _, col in ipairs(cols) do
97+
table.insert(colnames, col.name or col[1])
98+
table.insert(coltypes, col.type or col[2])
99+
end
100+
local stmt = thismod.conn:prepare(thismod.prepare_select_sql(tablename, colnames, where))
101+
return stmt, stmt:bind_params(wheretypes), stmt:bind_result(coltypes)
102+
end

init.lua

+66-20
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ local thismod = {
66
}
77
_G[modname] = thismod
88

9+
function thismod.mklog(level, modname)
10+
return function(str)
11+
minetest.log(level, "[" .. modname .. "] " .. str)
12+
end
13+
end
14+
local LogI = thismod.mklog('action', modname)
15+
local LogE = thismod.mklog('error', modname)
16+
917
local singleplayer = minetest.is_singleplayer() -- Caching is OK since you can't open a game to
1018
-- multiplayer unless you restart it.
11-
if not minetest.setting_get(modname .. '.enable_singleplayer') and singleplayer then
12-
minetest.log('action', modname .. ": Not enabling because of singleplayer game")
19+
if minetest.setting_get(modname .. '.enable_singleplayer') ~= 'true' and singleplayer then
20+
LogI("Not enabling because of singleplayer game")
1321
return
1422
end
1523

@@ -27,6 +35,27 @@ local function setoverlay(tab, orig)
2735
setmetatable(tab, mt)
2836
end
2937

38+
local insecrequire = _G.require
39+
local ffi, bit
40+
do
41+
if minetest.request_insecure_environment then
42+
insecrequire = minetest.request_insecure_environment().require
43+
LogI("Fetched require() from insecure env")
44+
end
45+
local test_fn = function()
46+
return { require('ffi'), require('bit') }
47+
end
48+
local env = { require = insecrequire }
49+
setoverlay(env, _G)
50+
setfenv(test_fn, env)
51+
local ffi_ok, ret = pcall(test_fn)
52+
if not ffi_ok then
53+
error("Cannot access LuaJIT FFI. Either you are not using LuaJIT, or mod security is enabled" ..
54+
" and mysql_base is not an exception.")
55+
end
56+
ffi, bit = unpack(ret)
57+
end
58+
3059
local function string_splitdots(s)
3160
local temp = {}
3261
local index = 0
@@ -52,29 +81,45 @@ end
5281

5382
local mysql
5483
do -- MySQL module loading
55-
local env = {
56-
require = function (module)
57-
if module == 'mysql_h' then
58-
return dofile(modpath .. '/mysql/mysql_h.lua')
59-
else
60-
return require(module)
61-
end
62-
end
63-
}
84+
local env = {}
6485
setoverlay(env, _G)
65-
local fn, msg = loadfile(modpath .. '/mysql/mysql.lua')
66-
if not fn then error(msg) end
67-
setfenv(fn, env)
86+
local function secexec(path)
87+
local fn, msg = loadfile(path)
88+
if not fn then error(msg) end
89+
setfenv(fn, env)
90+
local status, ret = pcall(fn, {})
91+
if not status then
92+
error(ret)
93+
end
94+
return ret
95+
end
96+
local function secrequire(module)
97+
if module == 'mysql_h' then
98+
return secexec(modpath .. '/mysql/mysql_h.lua')
99+
elseif module == 'ffi' then
100+
return ffi
101+
elseif module == 'bit' then
102+
return bit
103+
else
104+
error("mysql.lua tried to require('" .. module .. "')")
105+
end
106+
end
107+
env.require = secrequire
68108
local status
69-
status, mysql = pcall(fn, {})
109+
status, mysql = pcall(secexec, modpath .. '/mysql/mysql.lua')
70110
if not status then
71111
error(modname .. ' failed to load MySQL FFI interface: ' .. tostring(mysql))
72112
end
73113
thismod.mysql = mysql
74114
end
75115

76116
function thismod.mkget(modname)
77-
local get = function (name) return minetest.setting_get(modname .. '.' .. name) end
117+
local get
118+
if minetest.settings then
119+
get = function (name) return minetest.settings:get(modname .. '.' .. name) end
120+
else
121+
get = function (name) return minetest.setting_get(modname .. '.' .. name) end
122+
end
78123
local cfgfile = get('cfgfile')
79124
if type(cfgfile) == 'string' and cfgfile ~= '' then
80125
local file = io.open(cfgfile, 'rb')
@@ -128,7 +173,7 @@ do
128173
connopts.options.MYSQL_OPT_RECONNECT = true
129174
conn = mysql.connect(connopts)
130175
dbname = connopts.db
131-
minetest.log('action', modname .. ": Connected to MySQL database " .. dbname)
176+
LogI("Connected to MySQL database " .. dbname)
132177
thismod.conn = conn
133178
thismod.dbname = dbname
134179

@@ -152,7 +197,7 @@ end
152197
local function ping()
153198
if thismod.conn then
154199
if not thismod.conn:ping() then
155-
minetest.log('error', modname .. ": failed to ping database")
200+
LogE('error', modname .. ": failed to ping database")
156201
end
157202
end
158203
minetest.after(1800, ping)
@@ -166,13 +211,13 @@ end
166211

167212
minetest.register_on_shutdown(function()
168213
if thismod.conn then
169-
minetest.log('action', modname .. ": Shutting down, running callbacks")
214+
LogI("Shutting down, running callbacks")
170215
for _, func in ipairs(shutdown_callbacks) do
171216
func()
172217
end
173218
thismod.conn:close()
174219
thismod.conn = nil
175-
minetest.log('action', modname .. ": Cosed database connection")
220+
LogI("Closed database connection")
176221
end
177222
end)
178223

@@ -184,3 +229,4 @@ function thismod.table_exists(name)
184229
return exists
185230
end
186231

232+
dofile(modpath .. '/abstraction.lua')

0 commit comments

Comments
 (0)