summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/data/database.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/data/database.lua')
-rw-r--r--plugins/data/database.lua170
1 files changed, 144 insertions, 26 deletions
diff --git a/plugins/data/database.lua b/plugins/data/database.lua
index be52f23ee63..e0249182409 100644
--- a/plugins/data/database.lua
+++ b/plugins/data/database.lua
@@ -1,41 +1,159 @@
-local sql = require("lsqlite3")
-local datfile = {}
+local sql = require('lsqlite3')
local db
-local function check_db(msg)
+local function check_db_result(msg)
if db:errcode() > sql.OK then
- emu.print_error(string.format("Error: %s (%s - %s)", msg, db:errcode(), db:errmsg()))
+ emu.print_error(string.format('Error: %s (%s - %s)', msg, db:errcode(), db:errmsg()))
+ return false
end
+ return true
end
-do
- local dbpath = emu.subst_env(mame_manager.ui.options.entries.historypath:value():match("([^;]+)"))
- db = sql.open(dbpath .. "/history.db")
- if not db then
- lfs.mkdir(dbpath)
- db = sql.open(dbpath .. "/history.db")
+local function settings_path()
+ return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/data'
+end
+
+local function check_version_table()
+ local found = false
+ db:exec(
+ [[SELECT COUNT(*) FROM sqlite_master WHERE name = 'version' AND type = 'table';]],
+ function (udata, cols, values, names)
+ found = tonumber(values[1]) > 0
+ return 0
+ end)
+ if check_db_result('checking for "version" table') and (not found) then
+ db:exec(
+ [[CREATE TABLE version (
+ datfile VARCHAR NOT NULL,
+ version VARCHAR NOT NULL,
+ PRIMARY KEY (datfile));]])
+ found = check_db_result('creating "version" table')
+ end
+ if not found then
+ db:close()
+ db = nil
+ end
+end
+
+local function open_existing()
+ db = sql.open(settings_path() .. '/history.db', sql.OPEN_READWRITE)
+ if db then
+ check_version_table()
+ end
+ return db
+end
+
+local function open_create()
+ -- first try to create settings directory
+ local dir = settings_path()
+ local attr = lfs.attributes(dir)
+ if (not attr) and (not lfs.mkdir(dir)) then
+ emu.print_error(string.format('Error creating data plugin settings directory "%s"', dir))
+ elseif attr and (attr.mode ~= 'directory') then
+ emu.print_error(string.format('Error opening data plugin database: "%s" is not a directory', dir))
+ else
+ -- now try to open the database
+ local dbpath = dir .. '/history.db'
+ db = sql.open(dbpath, sql.OPEN_READWRITE | sql.OPEN_CREATE)
if not db then
- emu.print_error("Unable to create history.db")
- return false
+ emu.print_error(string.format('Error opening data plugin database "%s"', dbpath))
+ else
+ check_version_table()
end
- check_db("opening database")
end
+ return db
end
-if db then
- local found = false
- db:exec("select * from sqlite_master where name = 'version'", function() found = true return 0 end)
- check_db("checking for 'version' table")
- if not found then
- db:exec([[
- CREATE TABLE version (
- version VARCHAR NOT NULL,
- datfile VARCHAR UNIQUE NOT NULL)]])
- check_db("creating 'version' table")
+
+local dbtable = {
+ ROW = sql.ROW,
+ BUSY = sql.BUSY,
+ DONE = sql.DONE,
+ check = check_db_result }
+
+function dbtable.sanitize_name(name)
+ return name:gsub('[^%w%."]', '_')
+end
+
+function dbtable.get_version(filename)
+ -- don't try to create the database here, just return nil if it doesn't exist
+ if (not db) and (not open_existing()) then
+ return nil
+ end
+ local query = db:prepare([[SELECT version FROM version WHERE datfile = ?;]])
+ query:bind_values(filename)
+ local result
+ while result == nil do
+ local status = query:step()
+ if status == sql.ROW then
+ result = query:get_value(0)
+ elseif status ~= sql.BUSY then
+ break
+ end
+ end
+ query:finalize()
+ return result
+end
+
+function dbtable.set_version(filename, version)
+ if (not db) and (not open_create()) then
+ return nil
+ end
+ local query
+ if version ~= nil then
+ query = db:prepare(
+ [[INSERT INTO version (datfile, version) VALUES (?1, ?2)
+ ON CONFLICT(datfile) DO UPDATE set version = ?2;]])
+ query:bind_values(filename, version)
+ else
+ query = db:prepare([[DELETE FROM version WHERE datfile = ?1;]])
+ query:bind_values(filename)
+ end
+ local result
+ while result == nil do
+ local status = query:step()
+ if status == sqlite3.DONE then
+ result = true
+ elseif result ~= sqlite3.ROW then
+ result = false
+ end
+ end
+ query:finalize()
+ return result
+end
+
+function dbtable.prepare(...)
+ if (not db) and open_create() then
+ dbtable.prepare = function (...) return db:prepare(...) end
+ end
+ if db then
+ return db:prepare(...)
+ else
+ return nil
end
end
-local dbtable = { prepare = function(...) return db:prepare(...) end,
- exec = function(...) return db:exec(...) end, ROW = sql.ROW, check = check_db }
+function dbtable.exec(...)
+ if (not db) and open_create() then
+ dbtable.exec = function (...) return db:exec(...) end
+ end
+ if db then
+ return db:exec(...)
+ else
+ return nil
+ end
+end
+
+function dbtable.open_data_file(file)
+ local fh, filepath
+ for path in mame_manager.ui.options.entries.historypath:value():gmatch('([^;]+)') do
+ filepath = emu.subst_env(path) .. '/' .. file
+ fh = io.open(filepath, 'r')
+ if fh then
+ break
+ end
+ end
+ return fh, filepath, dbtable.sanitize_name(file), dbtable.get_version(file)
+end
-return db and dbtable or false
+return dbtable