Merge 0.10->trunk
[prosody.git] / plugins / mod_storage_sql2.lua
index e03b1fd61fbf2cddf16e66dbf912a413ff338fb6..e5357416913f6137525780eb4fe734095ea57e7c 100644 (file)
@@ -2,7 +2,7 @@
 local json = require "util.json";
 local xml_parse = require "util.xml".parse;
 local uuid = require "util.uuid";
-local resolve_relative_path = require "core.configmanager".resolve_relative_path;
+local resolve_relative_path = require "util.paths".resolve_relative_path;
 
 local stanza_mt = require"util.stanza".stanza_mt;
 local getmetatable = getmetatable;
@@ -198,7 +198,9 @@ local keyval_store = {};
 keyval_store.__index = keyval_store;
 function keyval_store:get(username)
        user,store = username,self.store;
-       return select(2, engine:transaction(keyval_store_get));
+       local ok, result = engine:transaction(keyval_store_get);
+       if not ok then return ok, result; end
+       return result;
 end
 function keyval_store:set(username, data)
        user,store = username,self.store;
@@ -214,12 +216,52 @@ function keyval_store:users()
        return iterator(result);
 end
 
+local map_store = {};
+map_store.__index = map_store;
+function map_store:get(username, key)
+       local ok, result = engine:transaction(function()
+               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]);
+                       end
+               else
+                       error("TODO: non-string keys");
+               end
+       end);
+       if not ok then return nil, result; end
+       return result;
+end
+function map_store:set(username, key, data)
+       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);
+                       end
+               else
+                       error("TODO: non-string keys");
+               end
+               return true;
+       end);
+       if not ok then return nil, result; end
+       return result;
+end
+
 local archive_store = {}
 archive_store.__index = archive_store
-function archive_store:append(username, when, with, value)
+function archive_store:append(username, key, when, with, value)
+       if value == nil then -- COMPAT early versions
+               when, with, value, key = key, when, with, value
+       end
        local user,store = username,self.store;
        return engine:transaction(function()
-               local key = uuid.generate();
+               if key then
+                       engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", host, user or "", store, key);
+               else
+                       key = uuid.generate();
+               end
                local t, value = 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;
@@ -256,14 +298,16 @@ local function archive_where(query, args, where)
        end
 end
 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` = ? LIMIT 1)"
-               args[#args+1] = query.after
+               where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)"
+               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` = ? LIMIT 1)"
-               args[#args+1] = query.before
+               where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)"
+               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
 
@@ -280,7 +324,7 @@ function archive_store:find(username, query)
 
                -- Total matching
                if query.total then
-                       local stats = engine:select(sql_query:gsub("^(SELECT).-(FROM)", "%1 COUNT(*) %2"):format(t_concat(where, " AND "), "DESC", ""), unpack(args));
+                       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];
@@ -316,6 +360,10 @@ function archive_store:delete(username, query)
                local sql_query = "DELETE FROM `prosodyarchive` WHERE %s;";
                local args = { host, user or "", store, };
                local where = { "`host` = ?", "`user` = ?", "`store` = ?", };
+               if user == true then
+                       table.remove(args, 2);
+                       table.remove(where, 2);
+               end
                archive_where(query, args, where);
                archive_where_id_range(query, args, where);
                sql_query = sql_query:format(t_concat(where, " AND "));
@@ -326,6 +374,7 @@ end
 
 local stores = {
        keyval = keyval_store;
+       map = map_store;
        archive = archive_store;
 };