summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/data/data_history.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/data/data_history.lua')
-rw-r--r--plugins/data/data_history.lua208
1 files changed, 200 insertions, 8 deletions
diff --git a/plugins/data/data_history.lua b/plugins/data/data_history.lua
index 331243b57bf..b233405e984 100644
--- a/plugins/data/data_history.lua
+++ b/plugins/data/data_history.lua
@@ -1,18 +1,210 @@
local dat = {}
+
+local db = require('data/database')
local ver, info
-local datread = require("data/load_dat")
-datread, ver = datread.open("history.dat", "## REVISION:")
+local file = 'history.xml'
+local tablename
+
+local function init()
+ -- check for old history table
+ if db.get_version('history.dat') then
+ db.exec([[DROP TABLE "history.dat";]])
+ db.exec([[DROP TABLE "history.dat_idx";]])
+ db.set_version('history.dat', nil)
+ end
+
+ local fh, filepath, dbver
+ fh, filepath, tablename, dbver = db.open_data_file(file)
+ if not fh then
+ if dbver then
+ -- data in database but missing file, just use what we have
+ ver = dbver
+ end
+ return
+ end
+
+ -- scan file for version
+ for line in fh:lines() do
+ local match = line:match('<history([^>]*)>')
+ if match then
+ match = match:match('version="([^"]*)"')
+ if match then
+ ver = match
+ break
+ end
+ end
+ end
+ if (not ver) or (ver == dbver) then
+ fh:close()
+ ver = dbver
+ return
+ end
+
+ if not dbver then
+ db.exec(
+ string.format(
+ [[CREATE TABLE "%s_idx" (
+ name VARCHAR NOT NULL,
+ list VARCHAR NOT NULL,
+ data INTEGER NOT NULL);]],
+ tablename))
+ db.check(string.format('creating %s index table', file))
+ db.exec(string.format([[CREATE TABLE "%s" (data CLOB NOT NULL);]], tablename))
+ db.check(string.format('creating %s data table', file))
+ db.exec(
+ string.format(
+ [[CREATE INDEX "namelist_%s" ON "%s_idx" (name, list);]],
+ tablename, tablename))
+ db.check(string.format('creating %s name/list index', file))
+ end
+
+ local slaxml = require('xml')
+
+ db.exec([[BEGIN TRANSACTION;]])
+ if not db.check(string.format('starting %s transaction', file)) then
+ fh:close()
+ ver = dbver
+ return
+ end
+
+ -- clean out previous data and update the version
+ if dbver then
+ db.exec(string.format([[DELETE FROM "%s";]], tablename))
+ if not db.check(string.format('deleting previous %s data', file)) then
+ db.exec([[ROLLBACK TRANSACTION;]])
+ fh:close()
+ ver = dbver
+ return
+ end
+ db.exec(string.format([[DELETE FROM "%s_idx";]], tablename))
+ if not db.check(string.format('deleting previous %s data', file)) then
+ db.exec([[ROLLBACK TRANSACTION;]])
+ fh:close()
+ ver = dbver
+ return
+ end
+ end
+ db.set_version(file, ver)
+ if not db.check(string.format('updating %s version', file)) then
+ db.exec([[ROLLBACK TRANSACTION;]])
+ fh:close()
+ ver = dbver
+ return
+ end
+
+ fh:seek('set')
+ local buffer = fh:read('a')
+
+ local lasttag
+ local entry = {}
+ local rowid
+
+ local dataquery = db.prepare(
+ string.format([[INSERT INTO "%s" (data) VALUES (?);]], tablename))
+ local indexquery = db.prepare(
+ string.format([[INSERT INTO "%s_idx" (name, list, data) VALUES (?, ?, ?);]], tablename))
+
+ local parser = slaxml:parser{
+ startElement = function(name)
+ lasttag = name
+ if name == 'entry' then
+ entry = {}
+ rowid = nil
+ elseif (name == 'system') or (name == 'item') then
+ table.insert(entry, {})
+ end
+ end,
+ attribute = function(name, value)
+ if (name == 'name') or (name == 'list') then
+ entry[#entry][name] = value
+ end
+ end,
+ text = function(text, cdata)
+ if lasttag == 'text' then
+ text = text:gsub('\r', '') -- strip carriage returns
+ dataquery:bind_values(text)
+ while true do
+ local status = dataquery:step()
+ if status == db.DONE then
+ rowid = dataquery:last_insert_rowid();
+ break
+ elseif result == db.BUSY then
+ emu.print_error(string.format('Database busy: inserting %s data', file))
+ -- FIXME: how to abort parse and roll back?
+ break
+ elseif result ~= db.ROW then
+ db.check(string.format('inserting %s data', file))
+ break
+ end
+ end
+ dataquery:reset()
+ end
+ end,
+ closeElement = function(name)
+ if (name == 'entry') and rowid then
+ for num, entry in pairs(entry) do
+ indexquery:bind_values(entry.name, entry.list or '', rowid)
+ while true do
+ local status = indexquery:step()
+ if status == db.DONE then
+ break
+ elseif status == db.BUSY then
+ emu.print_error(string.format('Database busy: inserting %s data', file))
+ -- FIXME: how to abort parse and roll back?
+ break
+ elseif result ~= db.ROW then
+ db.check(string.format('inserting %s data', file))
+ break
+ end
+ end
+ indexquery:reset()
+ end
+ end
+ end
+ }
+
+ parser:parse(buffer, { stripWhitespace = true })
+ dataquery:finalize()
+ indexquery:finalize()
+ fh:close()
+
+ db.exec([[COMMIT TRANSACTION;]])
+ if not db.check(string.format('committing %s transaction', file)) then
+ db.exec([[ROLLBACK TRANSACTION;]])
+ ver = dbver
+ end
+end
+
+if db then
+ init()
+end
function dat.check(set, softlist)
- if not datread then
+ if not ver then
return nil
end
- local status
- status, info = pcall(datread, "bio", softlist or "info", set)
- if not status or not info then
- return nil
+
+ info = nil
+ local query = db.prepare(
+ string.format(
+ [[SELECT f.data
+ FROM "%s_idx" AS fi LEFT JOIN "%s" AS f ON fi.data = f.rowid
+ WHERE fi.name = ? AND fi.list = ?;]],
+ tablename, tablename))
+ query:bind_values(set, softlist or '')
+ while not info do
+ local status = query:step()
+ if status == db.ROW then
+ info = query:get_value(0)
+ elseif status == db.DONE then
+ break
+ elseif status ~= db.BUSY then
+ db.check(string.format('reading %s data', file))
+ break
+ end
end
- return _("History")
+ query:finalize()
+ return info and _p('plugin-data', 'History') or nil
end
function dat.get()