X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmod_storage_sql.lua;h=4f46b3f662a5ef2a199ea4cad07240c454ac60da;hb=db2ebc9585c3d52cd30f913728fedb54d76298f2;hp=57d964e277b2a160411c8c5b882b5bfeb4f357dd;hpb=9d596e90c68b187dfa803b9806ced7a5db91c6ef;p=prosody.git diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index 57d964e2..4f46b3f6 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -1,4 +1,6 @@ +-- luacheck: ignore 212/self + local json = require "util.json"; local sql = require "util.sql"; local xml_parse = require "util.xml".parse; @@ -80,16 +82,14 @@ local function keyval_store_set(data) 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 @@ -125,32 +125,53 @@ 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); @@ -174,7 +195,7 @@ function archive_store:append(username, key, value, when, with) 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); @@ -213,12 +234,12 @@ local function archive_where_id_range(query, args, where) 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 @@ -238,8 +259,9 @@ function archive_store:find(username, query) 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; @@ -253,7 +275,6 @@ function archive_store:find(username, query) 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 @@ -279,7 +300,6 @@ function archive_store:delete(username, query) 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 @@ -427,19 +447,25 @@ 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