+-- luacheck: ignore 212/self
+
local json = require "util.json";
local sql = require "util.sql";
local xml_parse = require "util.xml".parse;
local extradata = {};
for key, value in pairs(data) do
if type(key) == "string" and key ~= "" then
- local t, value = serialize(value);
- assert(t, value);
+ local t, value = assert(serialize(value));
engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user or "", store, key, t, value);
else
extradata[key] = value;
end
end
if next(extradata) ~= nil then
- local t, extradata = serialize(extradata);
- assert(t, extradata);
+ local t, extradata = assert(serialize(extradata));
engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user or "", store, "", t, extradata);
end
end
--- Archive store API
+-- luacheck: ignore 512 431/user 431/store
local map_store = {};
map_store.__index = map_store;
+map_store.remove = {};
function map_store:get(username, key)
local ok, result = engine:transaction(function()
+ local data;
if type(key) == "string" and key ~= "" then
- for row in engine:select("SELECT `type`, `value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", host, username or "", self.store, key) do
- return deserialize(row[1], row[2]);
+ for row in engine:select("SELECT `type`, `value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=? LIMIT 1", host, username or "", self.store, key) do
+ data = deserialize(row[1], row[2]);
end
+ return data;
else
- error("TODO: non-string keys");
+ for row in engine:select("SELECT `type`, `value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=? LIMIT 1", host, username or "", self.store, "") do
+ data = deserialize(row[1], row[2]);
+ end
+ return data and data[key] or nil;
end
end);
if not ok then return nil, result; end
return result;
end
function map_store:set(username, key, data)
+ if data == nil then data = self.remove; end
+ return self:set_keys(username, { [key] = data });
+end
+function map_store:set_keys(username, keydatas)
local ok, result = engine:transaction(function()
- if type(key) == "string" and key ~= "" then
- engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?",
- host, username or "", self.store, key);
- if data ~= nil then
- local t, value = assert(serialize(data));
- engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, username or "", self.store, key, t, value);
+ for key, data in pairs(keydatas) do
+ if type(key) == "string" and key ~= "" then
+ engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?",
+ host, username or "", self.store, key);
+ if data ~= self.remove then
+ local t, value = assert(serialize(data));
+ engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, username or "", self.store, key, t, value);
+ end
+ else
+ local extradata = {};
+ for row in engine:select("SELECT `type`, `value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=? LIMIT 1", host, username or "", self.store, "") do
+ extradata = deserialize(row[1], row[2]);
+ end
+ engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?",
+ host, username or "", self.store, "");
+ extradata[key] = data;
+ local t, value = assert(serialize(extradata));
+ engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, username or "", self.store, "", t, value);
end
- else
- error("TODO: non-string keys");
end
return true;
end);
else
key = uuid.generate();
end
- local t, value = serialize(value);
+ local t, value = assert(serialize(value));
engine:insert("INSERT INTO `prosodyarchive` (`host`, `user`, `store`, `when`, `with`, `key`, `type`, `value`) VALUES (?,?,?,?,?,?,?,?)", host, user or "", store, when, with, key, t, value);
return key;
end);
local args_len = #args
-- Before or after specific item, exclusive
if query.after then -- keys better be unique!
- where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)"
+ where[#where+1] = "`sort_id` > COALESCE((SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1), 0)"
args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.after, args[1], args[2], args[3];
args_len = args_len + 4
end
if query.before then
- where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)"
+ where[#where+1] = "`sort_id` < COALESCE((SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1), (SELECT MAX(`sort_id`)+1 FROM `prosodyarchive`))"
args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.before, args[1], args[2], args[3];
end
end
if query.total then
local stats = engine:select("SELECT COUNT(*) FROM `prosodyarchive` WHERE " .. t_concat(where, " AND "), unpack(args));
if stats then
- local _total = stats()
- total = _total and _total[1];
+ for row in stats do
+ total = row[1];
+ end
end
if query.limit == 0 then -- Skip the real query
return noop, total;
end
sql_query = sql_query:format(t_concat(where, " AND "), query.reverse and "DESC" or "ASC", query.limit and " LIMIT ?" or "");
- module:log("debug", sql_query);
return engine:select(sql_query, unpack(args));
end);
if not ok then return ok, result end
archive_where(query, args, where);
archive_where_id_range(query, args, where);
sql_query = sql_query:format(t_concat(where, " AND "));
- module:log("debug", sql_query);
return engine:delete(sql_query, unpack(args));
end);
end
function module.load()
if prosody.prosodyctl then return; end
+ local engines = module:shared("/*/sql/connections");
local params = normalize_params(module:get_option("sql", default_params));
- engine = sql:create_engine(params, function (engine)
- if module:get_option("sql_manage_tables", true) then
- -- Automatically create table, ignore failure (table probably already exists)
- -- FIXME: we should check in information_schema, etc.
- create_table();
- -- Check whether the table needs upgrading
- if upgrade_table(params, false) then
- module:log("error", "Old database format detected. Please run: prosodyctl mod_%s upgrade", module.name);
- return false, "database upgrade needed";
+ engine = engines[sql.db2uri(params)];
+ if not engine then
+ module:log("debug", "Creating new engine");
+ engine = sql:create_engine(params, function (engine)
+ if module:get_option("sql_manage_tables", true) then
+ -- Automatically create table, ignore failure (table probably already exists)
+ -- FIXME: we should check in information_schema, etc.
+ create_table();
+ -- Check whether the table needs upgrading
+ if upgrade_table(params, false) then
+ module:log("error", "Old database format detected. Please run: prosodyctl mod_%s upgrade", module.name);
+ return false, "database upgrade needed";
+ end
end
- end
- end);
+ end);
+ engines[sql.db2uri(params)] = engine;
+ end
module:provides("storage", driver);
end