Comparison

plugins/mod_storage_sql.lua @ 13143:3ec48555b773

mod_storage_sql: Add UPSERT support Currently limited to SQLite3 for lack of testing on other databases. Adds a migration to replace the non-UNIQUE prosody_index, renaming it prosody_unique_index since ALTER INDEX does not seem to be portable.
author Kim Alvefur <zash@zash.se>
date Sat, 10 Jun 2023 15:44:09 +0200
parent 12977:74b9e05af71e
child 13144:033ea8b46d6a
comparison
equal deleted inserted replaced
13142:879a6a33c21b 13143:3ec48555b773
201 local insert_sql = [[ 201 local insert_sql = [[
202 INSERT INTO "prosody" 202 INSERT INTO "prosody"
203 ("host","user","store","key","type","value") 203 ("host","user","store","key","type","value")
204 VALUES (?,?,?,?,?,?); 204 VALUES (?,?,?,?,?,?);
205 ]]; 205 ]];
206 local upsert_sql = [[
207 INSERT INTO "prosody"
208 ("host","user","store","key","type","value")
209 VALUES (?,?,?,?,?,?)
210 ON CONFLICT ("host", "user","store", "key")
211 DO UPDATE SET "type"=?, "value"=?;
212 ]];
206 local select_extradata_sql = [[ 213 local select_extradata_sql = [[
207 SELECT "type", "value" 214 SELECT "type", "value"
208 FROM "prosody" 215 FROM "prosody"
209 WHERE "host"=? AND "user"=? AND "store"=? AND "key"=? 216 WHERE "host"=? AND "user"=? AND "store"=? AND "key"=?
210 LIMIT 1; 217 LIMIT 1;
211 ]]; 218 ]];
212 for key, data in pairs(keydatas) do 219 for key, data in pairs(keydatas) do
213 if type(key) == "string" and key ~= "" then 220 if type(key) == "string" and key ~= "" and engine.params.driver == "SQLite3" and data ~= self.remove then
221 local t, value = assert(serialize(data));
222 engine:insert(upsert_sql, host, username or "", self.store, key, t, value, t, value);
223 elseif type(key) == "string" and key ~= "" then
214 engine:delete(delete_sql, 224 engine:delete(delete_sql,
215 host, username or "", self.store, key); 225 host, username or "", self.store, key);
216 if data ~= self.remove then 226 if data ~= self.remove then
217 local t, value = assert(serialize(data)); 227 local t, value = assert(serialize(data));
218 engine:insert(insert_sql, host, username or "", self.store, key, t, value); 228 engine:insert(insert_sql, host, username or "", self.store, key, t, value);
703 Column { name="user", type="TEXT", nullable=false }; 713 Column { name="user", type="TEXT", nullable=false };
704 Column { name="store", type="TEXT", nullable=false }; 714 Column { name="store", type="TEXT", nullable=false };
705 Column { name="key", type="TEXT", nullable=false }; 715 Column { name="key", type="TEXT", nullable=false };
706 Column { name="type", type="TEXT", nullable=false }; 716 Column { name="type", type="TEXT", nullable=false };
707 Column { name="value", type="MEDIUMTEXT", nullable=false }; 717 Column { name="value", type="MEDIUMTEXT", nullable=false };
708 Index { name="prosody_index", "host", "user", "store", "key" }; 718 Index { name = "prosody_unique_index"; unique = engine.params.driver ~= "MySQL"; "host"; "user"; "store"; "key" };
709 }; 719 };
710 engine:transaction(function() 720 engine:transaction(function()
711 ProsodyTable:create(engine); 721 ProsodyTable:create(engine);
712 end); 722 end);
713 723
801 end 811 end
802 end); 812 end);
803 success,err = engine:transaction(function() 813 success,err = engine:transaction(function()
804 return engine:execute(check_encoding_query, params.database, 814 return engine:execute(check_encoding_query, params.database,
805 engine.charset, engine.charset.."_bin"); 815 engine.charset, engine.charset.."_bin");
806 end); 816 end);
807 if not success then 817 if not success then
808 module:log("error", "Failed to check/upgrade database encoding: %s", err or "unknown error"); 818 module:log("error", "Failed to check/upgrade database encoding: %s", err or "unknown error");
809 return false; 819 return false;
810 end 820 end
811 end 821 else
822 local indices = {};
823 engine:transaction(function ()
824 if params.driver == "SQLite3" then
825 for row in engine:select [[SELECT "name" from "sqlite_schema" WHERE "name"='prosody_index';]] do
826 indices[row[1]] = true;
827 end
828 elseif params.driver == "PostgreSQL" then
829 for row in engine:select [[SELECT "relname" FROM "pg_class" WHERE "relname"='prosody_index';]] do
830 indices[row[1]] = true;
831 end
832 end
833 end)
834 if apply_changes then
835 local success = engine:transaction(function ()
836 return assert(engine:execute([[DROP INDEX "prosody_index";]]));
837 end);
838 if not success then
839 module:log("error", "Failed to delete obsolete index \"prosody_index\"");
840 return false;
841 end
842 else
843 changes = changes or indices["prosody_index"];
844 end
845 end
812 return changes; 846 return changes;
813 end 847 end
814 848
815 local function normalize_database(driver, database) -- luacheck: ignore 431/driver 849 local function normalize_database(driver, database) -- luacheck: ignore 431/driver
816 if driver == "SQLite3" and database ~= ":memory:" then 850 if driver == "SQLite3" and database ~= ":memory:" then