Add. Support multiple database backends.
```Lua
local Database = require 'resources.functions.database'
-- Default backend configured via xml_handler.db_backend = 'native'
dbh = Database.new("system")
-- To use other backends you can use
dbh = Database.backend.luasql("system")
```
This commit is contained in:
parent
80758e8826
commit
5afec68fb1
|
|
@ -0,0 +1,67 @@
|
||||||
|
-- Start background service to support Lua-ODBC-Pool database backend
|
||||||
|
|
||||||
|
require "resources.functions.config"
|
||||||
|
require "resources.functions.file_exists"
|
||||||
|
|
||||||
|
local log = require "resources.functions.log".dbpool
|
||||||
|
local odbc = require "odbc"
|
||||||
|
local odbcpool = require "odbc.pool"
|
||||||
|
|
||||||
|
-- Configuration
|
||||||
|
local POLL_TIMEOUT = 5
|
||||||
|
local run_file = scripts_dir .. "/run/dbpool.tmp";
|
||||||
|
|
||||||
|
-- Pool ctor
|
||||||
|
local function run_odbc_pool(name, n)
|
||||||
|
local connection_string = assert(database[name])
|
||||||
|
|
||||||
|
local typ, dsn, user, password = connection_string:match("^(.-)://(.-):(.-):(.-)$")
|
||||||
|
assert(typ == 'odbc', "unsupported connection string:" .. connection_string)
|
||||||
|
|
||||||
|
local cli = odbcpool.client(name)
|
||||||
|
|
||||||
|
log.noticef("Starting reconnect thread[%s] ...", name)
|
||||||
|
local rthread = odbcpool.reconnect_thread(cli, dsn, user, password)
|
||||||
|
rthread:start()
|
||||||
|
log.noticef("Reconnect thread[%s] started", name)
|
||||||
|
|
||||||
|
local env = odbc.environment()
|
||||||
|
|
||||||
|
local connections = {}
|
||||||
|
for i = 1, (n or 10) do
|
||||||
|
local cnn = odbc.assert(env:connection())
|
||||||
|
connections[#connections+1] = cnn
|
||||||
|
cli:reconnect(cnn)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
name = name;
|
||||||
|
cli = cli;
|
||||||
|
cnn = connections;
|
||||||
|
thr = rthread;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stop_odbc_pool(ctx)
|
||||||
|
log.noticef("Stopping reconnect thread[%s] ...", ctx.name)
|
||||||
|
ctx.thr:stop()
|
||||||
|
log.noticef("Reconnect thread[%s] stopped", ctx.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function main()
|
||||||
|
local system_pool = run_odbc_pool("system", 10)
|
||||||
|
local switch_pool = run_odbc_pool("switch", 10)
|
||||||
|
|
||||||
|
local file = assert(io.open(run_file, "w"));
|
||||||
|
file:write("remove this file to stop the script");
|
||||||
|
file:close()
|
||||||
|
|
||||||
|
while file_exists(run_file) do
|
||||||
|
freeswitch.msleep(POLL_TIMEOUT*1000)
|
||||||
|
end
|
||||||
|
|
||||||
|
stop_odbc_pool(system_pool)
|
||||||
|
stop_odbc_pool(switch_pool)
|
||||||
|
end
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
@ -1,120 +1,30 @@
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- -- Use default backend
|
||||||
|
-- dbh = Database.new("system")
|
||||||
|
-- .....
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- -- Use LuaSQL backend
|
||||||
|
-- dbh = Database.backend.luasql("system")
|
||||||
|
-- .....
|
||||||
|
|
||||||
require 'resources.functions.config'
|
require 'resources.functions.config'
|
||||||
|
|
||||||
-----------------------------------------------------------
|
local log = require "resources.functions.log".database
|
||||||
local OdbcDatabase = {} if not freeswitch then
|
|
||||||
OdbcDatabase.__index = OdbcDatabase
|
|
||||||
|
|
||||||
local odbc = require "odbc.dba"
|
local BACKEND = xml_handler and xml_handler.db_backend or 'native'
|
||||||
|
|
||||||
function OdbcDatabase.new(name)
|
|
||||||
local self = setmetatable({}, OdbcDatabase)
|
|
||||||
|
|
||||||
local connection_string = assert(database[name])
|
|
||||||
|
|
||||||
local typ, dsn, user, password = connection_string:match("^(.-)://(.-):(.-):(.-)$")
|
|
||||||
assert(typ == 'odbc', "unsupported connection string:" .. connection_string)
|
|
||||||
|
|
||||||
self._dbh = odbc.Connect(dsn, user, password)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function OdbcDatabase:query(sql, fn)
|
|
||||||
self._rows_affected = nil
|
|
||||||
if fn then
|
|
||||||
return self._dbh:neach(sql, function(row)
|
|
||||||
local o = {}
|
|
||||||
for k, v in pairs(row) do
|
|
||||||
if v == odbc.NULL then
|
|
||||||
o[k] = nil
|
|
||||||
else
|
|
||||||
o[k] = tostring(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return fn(o)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
local ok, err = self._dbh:exec(sql)
|
|
||||||
if not ok then return nil, err end
|
|
||||||
self._rows_affected = ok
|
|
||||||
return self._rows_affected
|
|
||||||
end
|
|
||||||
|
|
||||||
function OdbcDatabase:affected_rows()
|
|
||||||
return self._rows_affected;
|
|
||||||
end
|
|
||||||
|
|
||||||
function OdbcDatabase:release()
|
|
||||||
if self._dbh then
|
|
||||||
self._dbh:destroy()
|
|
||||||
self._dbh = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function OdbcDatabase:connected()
|
|
||||||
return self._dbh and self._dbh:connected()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
-----------------------------------------------------------
|
||||||
local FsDatabase = {} if freeswitch then
|
local installed_classes = {}
|
||||||
|
local default_backend = FsDatabase
|
||||||
|
local function new_database(backend)
|
||||||
|
local class = installed_classes[backend]
|
||||||
|
if class then return class end
|
||||||
|
|
||||||
require "resources.functions.file_exists"
|
|
||||||
require "resources.functions.database_handle"
|
|
||||||
|
|
||||||
FsDatabase.__index = FsDatabase
|
|
||||||
|
|
||||||
function FsDatabase.new(name)
|
|
||||||
local dbh = assert(name)
|
|
||||||
if type(name) == 'string' then
|
|
||||||
if name == 'switch' and file_exists(database_dir.."/core.db") then
|
|
||||||
dbh = freeswitch.Dbh("sqlite://"..database_dir.."/core.db")
|
|
||||||
else
|
|
||||||
dbh = database_handle(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert(dbh:connected())
|
|
||||||
|
|
||||||
local self = setmetatable({
|
|
||||||
_dbh = dbh;
|
|
||||||
}, FsDatabase)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function FsDatabase:query(sql, fn)
|
|
||||||
if fn then
|
|
||||||
return self._dbh:query(sql, fn)
|
|
||||||
end
|
|
||||||
return self._dbh:query(sql)
|
|
||||||
end
|
|
||||||
|
|
||||||
function FsDatabase:affected_rows()
|
|
||||||
if self._dbh then
|
|
||||||
return self._dbh:affected_rows()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function FsDatabase:release()
|
|
||||||
if self._dbh then
|
|
||||||
self._dbh:release()
|
|
||||||
self._dbh = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function FsDatabase:connected()
|
|
||||||
return self._dbh and self._dbh:connected()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
local Database = {} do
|
local Database = {} do
|
||||||
Database.__index = Database
|
Database.__index = Database
|
||||||
Database.__base = freeswitch and FsDatabase or OdbcDatabase
|
Database.__base = backend or default_backend
|
||||||
Database = setmetatable(Database, Database.__base)
|
Database = setmetatable(Database, Database.__base)
|
||||||
|
|
||||||
function Database.new(...)
|
function Database.new(...)
|
||||||
|
|
@ -160,7 +70,9 @@ function Database:fetch_all(sql)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Database.__self_test__(...)
|
function Database.__self_test__(...)
|
||||||
|
log.info('self_test Database - ' .. Database._backend_name)
|
||||||
local db = Database.new(...)
|
local db = Database.new(...)
|
||||||
|
|
||||||
assert(db:connected())
|
assert(db:connected())
|
||||||
|
|
||||||
assert("1" == db:first_value("select 1 as v union all select 2 as v"))
|
assert("1" == db:first_value("select 1 as v union all select 2 as v"))
|
||||||
|
|
@ -179,11 +91,45 @@ function Database.__self_test__(...)
|
||||||
|
|
||||||
-- assert(nil == db:first_value("some non sql query"))
|
-- assert(nil == db:first_value("some non sql query"))
|
||||||
|
|
||||||
|
-- select NULL
|
||||||
|
local a = assert(db:first_value("select NULL as a"))
|
||||||
|
assert(a == "")
|
||||||
|
|
||||||
db:release()
|
db:release()
|
||||||
assert(not db:connected())
|
assert(not db:connected())
|
||||||
print(" * databse - OK!")
|
log.info('self_test Database - pass')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
installed_classes[backend] = Database
|
||||||
|
return Database
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
local Database = {} do
|
||||||
|
|
||||||
|
local backend_loader = setmetatable({}, {__index = function(self, backend)
|
||||||
|
local class = require("resources.functions.database." .. backend)
|
||||||
|
local database = new_database(class)
|
||||||
|
self[backend] = function(...)
|
||||||
|
return database.new(...)
|
||||||
|
end
|
||||||
|
return self[backend]
|
||||||
|
end})
|
||||||
|
|
||||||
|
Database.backend = backend_loader
|
||||||
|
|
||||||
|
Database.new = Database.backend[BACKEND]
|
||||||
|
|
||||||
|
Database.__self_test__ = function(backends, ...)
|
||||||
|
for _, backend in ipairs(backends) do
|
||||||
|
local t = Database.backend[backend]
|
||||||
|
t(...).__self_test__(...)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
end
|
end
|
||||||
-----------------------------------------------------------
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
--
|
||||||
|
-- LuaSQL backend to FusionPBX database class
|
||||||
|
--
|
||||||
|
|
||||||
|
require "resources.functions.split"
|
||||||
|
local log = require "resources.functions.log".database
|
||||||
|
|
||||||
|
local LuaSQLDatabase = {} do
|
||||||
|
LuaSQLDatabase.__index = LuaSQLDatabase
|
||||||
|
LuaSQLDatabase._backend_name = 'LuaSQL'
|
||||||
|
|
||||||
|
local map = {
|
||||||
|
pgsql = 'postgres';
|
||||||
|
}
|
||||||
|
|
||||||
|
local function apply_names(row, colnames, null_value)
|
||||||
|
for _, name in pairs(colnames) do
|
||||||
|
if row[name] == nil then
|
||||||
|
row[name] = null_value
|
||||||
|
else
|
||||||
|
row[name] = tostring(row[name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return row
|
||||||
|
end
|
||||||
|
|
||||||
|
function LuaSQLDatabase.new(name)
|
||||||
|
local self = setmetatable({}, OdbcDatabase)
|
||||||
|
|
||||||
|
local connection_string = assert(database[name])
|
||||||
|
|
||||||
|
local typ, args = split_first(database[name], "://", true);
|
||||||
|
typ = map[typ] or typ
|
||||||
|
|
||||||
|
local luasql = require ("luasql." .. typ)
|
||||||
|
local env = assert (luasql[typ]())
|
||||||
|
local dbh = assert (env:connect( usplit(args, ':', true) ))
|
||||||
|
|
||||||
|
self._env, self._dbh = env, dbh
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function LuaSQLDatabase:query(sql, fn)
|
||||||
|
self._rows_affected = nil
|
||||||
|
|
||||||
|
if fn then
|
||||||
|
local cur, err = self._dbh:execute(sql)
|
||||||
|
if err and not cur then
|
||||||
|
log.errf("Can not execute sql: %s\n%s", tostring(err), sql)
|
||||||
|
end
|
||||||
|
|
||||||
|
local colnames = cur:getcolnames()
|
||||||
|
while true do
|
||||||
|
local row, err = cur:fetch({}, "a")
|
||||||
|
if not row then break end
|
||||||
|
local ok, ret = pcall(fn, apply_names(row, colnames, ""))
|
||||||
|
if (not ok) or (type(ret) == 'number' and ret > 0) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cur:close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = self._dbh:execute(sql)
|
||||||
|
if err and not ok then
|
||||||
|
log.errf("Can not execute sql: %s\n%s", tostring(err), sql)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not ok then return nil, err end
|
||||||
|
|
||||||
|
if type(ok) ~= 'number' then
|
||||||
|
ok:close()
|
||||||
|
log.warning('SQL return recordset')
|
||||||
|
else
|
||||||
|
self._rows_affected = ok
|
||||||
|
end
|
||||||
|
|
||||||
|
self._rows_affected = ok
|
||||||
|
return self._rows_affected
|
||||||
|
end
|
||||||
|
|
||||||
|
function LuaSQLDatabase:affected_rows()
|
||||||
|
return self._rows_affected;
|
||||||
|
end
|
||||||
|
|
||||||
|
function LuaSQLDatabase:release()
|
||||||
|
if self._dbh then
|
||||||
|
self._dbh:close()
|
||||||
|
self._env:close()
|
||||||
|
self._env, self._dbh = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function LuaSQLDatabase:connected()
|
||||||
|
return self._dbh and self._dbh:connected()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return LuaSQLDatabase
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
--
|
||||||
|
-- Native backend to FusionPBX database class
|
||||||
|
--
|
||||||
|
|
||||||
|
local log = require "resources.functions.log".database
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
local FsDatabase = {} if freeswitch then
|
||||||
|
|
||||||
|
require "resources.functions.file_exists"
|
||||||
|
require "resources.functions.database_handle"
|
||||||
|
|
||||||
|
FsDatabase.__index = FsDatabase
|
||||||
|
FsDatabase._backend_name = 'native'
|
||||||
|
|
||||||
|
function FsDatabase.new(name)
|
||||||
|
local dbh = assert(name)
|
||||||
|
if type(name) == 'string' then
|
||||||
|
if name == 'switch' and file_exists(database_dir.."/core.db") then
|
||||||
|
dbh = freeswitch.Dbh("sqlite://"..database_dir.."/core.db")
|
||||||
|
else
|
||||||
|
dbh = database_handle(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(dbh:connected())
|
||||||
|
|
||||||
|
local self = setmetatable({
|
||||||
|
_dbh = dbh;
|
||||||
|
}, FsDatabase)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function FsDatabase:query(sql, fn)
|
||||||
|
if fn then
|
||||||
|
return self._dbh:query(sql, fn)
|
||||||
|
end
|
||||||
|
return self._dbh:query(sql)
|
||||||
|
end
|
||||||
|
|
||||||
|
function FsDatabase:affected_rows()
|
||||||
|
if self._dbh then
|
||||||
|
return self._dbh:affected_rows()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FsDatabase:release()
|
||||||
|
if self._dbh then
|
||||||
|
self._dbh:release()
|
||||||
|
self._dbh = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FsDatabase:connected()
|
||||||
|
return self._dbh and self._dbh:connected()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
return FsDatabase
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
--
|
||||||
|
-- Lua-ODBC backend to FusionPBX database class
|
||||||
|
--
|
||||||
|
|
||||||
|
local log = require "resources.functions.log".database
|
||||||
|
local odbc = require "odbc.dba"
|
||||||
|
|
||||||
|
local function remove_null(row, null, null_value)
|
||||||
|
local o = {}
|
||||||
|
for k, v in pairs(row) do
|
||||||
|
if v == null then
|
||||||
|
o[k] = null_value
|
||||||
|
else
|
||||||
|
o[k] = tostring(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
local OdbcDatabase = {} do
|
||||||
|
OdbcDatabase.__index = OdbcDatabase
|
||||||
|
OdbcDatabase._backend_name = 'ODBC'
|
||||||
|
|
||||||
|
function OdbcDatabase.new(name)
|
||||||
|
local self = setmetatable({}, OdbcDatabase)
|
||||||
|
|
||||||
|
local connection_string = assert(database[name])
|
||||||
|
|
||||||
|
local typ, dsn, user, password = connection_string:match("^(.-)://(.-):(.-):(.-)$")
|
||||||
|
assert(typ == 'odbc', "unsupported connection string:" .. connection_string)
|
||||||
|
|
||||||
|
self._dbh = odbc.Connect(dsn, user, password)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcDatabase:query(sql, fn)
|
||||||
|
self._rows_affected = nil
|
||||||
|
if fn then
|
||||||
|
return self._dbh:neach(sql, function(row)
|
||||||
|
return fn(remove_null(row, odbc.NULL, ""))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
local ok, err = self._dbh:exec(sql)
|
||||||
|
if not ok then return nil, err end
|
||||||
|
self._rows_affected = ok
|
||||||
|
return self._rows_affected
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcDatabase:affected_rows()
|
||||||
|
return self._rows_affected;
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcDatabase:release()
|
||||||
|
if self._dbh then
|
||||||
|
self._dbh:destroy()
|
||||||
|
self._dbh = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcDatabase:connected()
|
||||||
|
return self._dbh and self._dbh:connected()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return OdbcDatabase
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
--
|
||||||
|
-- Lua-ODBC-Pool backend to FusionPBX database class
|
||||||
|
--
|
||||||
|
|
||||||
|
local log = require "resources.functions.log".database
|
||||||
|
local odbc = require "odbc.dba"
|
||||||
|
local odbcpool = require "odbc.dba.pool"
|
||||||
|
|
||||||
|
local function remove_null(row, null, null_value)
|
||||||
|
local o = {}
|
||||||
|
for k, v in pairs(row) do
|
||||||
|
if v == null then
|
||||||
|
o[k] = null_value
|
||||||
|
else
|
||||||
|
o[k] = tostring(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
local OdbcPoolDatabase = {} do
|
||||||
|
OdbcPoolDatabase.__index = OdbcPoolDatabase
|
||||||
|
OdbcPoolDatabase._backend_name = 'ODBC Pool'
|
||||||
|
|
||||||
|
function OdbcPoolDatabase.new(name)
|
||||||
|
local self = setmetatable({}, OdbcPoolDatabase)
|
||||||
|
self._cli = odbcpool.client(name)
|
||||||
|
self._timeout = 1000
|
||||||
|
self._rows_affected = nil
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcPoolDatabase:query(sql, fn)
|
||||||
|
self._rows_affected = nil
|
||||||
|
local cli = self._cli
|
||||||
|
|
||||||
|
local ok, err
|
||||||
|
if fn then
|
||||||
|
ok, err = cli:acquire(self._timeout, function(dbh)
|
||||||
|
local ok, err = dbh:neach(sql, function(row)
|
||||||
|
return fn(remove_null(row, odbc.NULL, ""))
|
||||||
|
end)
|
||||||
|
if err and not ok then
|
||||||
|
log.errf("Can not execute sql: %s\n%s", tostring(err), sql)
|
||||||
|
end
|
||||||
|
return not not dbh:connected(), true
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
ok, err = cli:acquire(self._timeout, function(dbh)
|
||||||
|
local ok, err = dbh:exec(sql)
|
||||||
|
if err and not ok then
|
||||||
|
log.errf("Can not execute sql: %s\n%s", tostring(err), sql)
|
||||||
|
end
|
||||||
|
self._rows_affected = ok
|
||||||
|
return not not dbh:connected(), ok
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if err and not ok then
|
||||||
|
log.errf("Can not get database handle: %s", tostring(err))
|
||||||
|
end
|
||||||
|
|
||||||
|
return ok
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcPoolDatabase:affected_rows()
|
||||||
|
return self._rows_affected;
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcPoolDatabase:release()
|
||||||
|
self._cli = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function OdbcPoolDatabase:connected()
|
||||||
|
return not not self._cli
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
return OdbcPoolDatabase
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
local Cache = require 'resources.functions.cache'
|
||||||
|
local Database = require 'resources.functions.database'
|
||||||
|
|
||||||
|
Database.__self_test__({
|
||||||
|
"native",
|
||||||
|
"luasql",
|
||||||
|
"odbc",
|
||||||
|
"odbcpool",
|
||||||
|
},
|
||||||
|
"system")
|
||||||
|
|
||||||
|
Cache._self_test()
|
||||||
Loading…
Reference in New Issue