Comparison

plugins/mod_storage_sql.lua @ 13837:0b63c2c3b563

Merge 13.0->trunk
author Kim Alvefur <zash@zash.se>
date Wed, 09 Apr 2025 20:28:28 +0200
parent 13836:c600794cafb6
child 13838:a93e7310bfcd
comparison
equal deleted inserted replaced
13831:bf4cd327966f 13837:0b63c2c3b563
11 local is_stanza = require"prosody.util.stanza".is_stanza; 11 local is_stanza = require"prosody.util.stanza".is_stanza;
12 local t_concat = table.concat; 12 local t_concat = table.concat;
13 13
14 local have_dbisql, dbisql = pcall(require, "prosody.util.sql"); 14 local have_dbisql, dbisql = pcall(require, "prosody.util.sql");
15 local have_sqlite, sqlite = pcall(require, "prosody.util.sqlite3"); 15 local have_sqlite, sqlite = pcall(require, "prosody.util.sqlite3");
16 if not have_dbisql then
17 module:log("debug", "Could not load LuaDBI: %s", dbisql)
18 dbisql = nil;
19 end
20 if not have_sqlite then
21 module:log("debug", "Could not load LuaSQLite3: %s", sqlite)
22 sqlite = nil;
23 end
24 if not (have_dbisql or have_sqlite) then 16 if not (have_dbisql or have_sqlite) then
25 module:log("error", "LuaDBI or LuaSQLite3 are required for using SQL databases but neither are installed"); 17 module:log("error", "LuaDBI or LuaSQLite3 are required for using SQL databases but neither are installed");
26 module:log("error", "Please install at least one of LuaDBI and LuaSQLite3. See https://prosody.im/doc/depends"); 18 module:log("error", "Please install at least one of LuaDBI and LuaSQLite3. See https://prosody.im/doc/depends");
19 module:log("debug", "Could not load LuaDBI: %s", dbisql);
20 module:log("debug", "Could not load LuaSQLite3: %s", sqlite);
27 error("No SQL library available") 21 error("No SQL library available")
22 end
23
24 local function get_sql_lib(driver)
25 if driver == "SQLite3" and have_sqlite then
26 return sqlite;
27 elseif have_dbisql then
28 return dbisql;
29 else
30 error(dbisql);
31 end
28 end 32 end
29 33
30 local noop = function() end 34 local noop = function() end
31 local unpack = table.unpack; 35 local unpack = table.unpack;
32 local function iterator(result) 36 local function iterator(result)
40 44
41 -- COMPAT Support for UPSERT is not in all versions of all compatible databases. 45 -- COMPAT Support for UPSERT is not in all versions of all compatible databases.
42 local function has_upsert(engine) 46 local function has_upsert(engine)
43 if engine.params.driver == "SQLite3" then 47 if engine.params.driver == "SQLite3" then
44 -- SQLite3 >= 3.24.0 48 -- SQLite3 >= 3.24.0
45 return engine.sqlite_version and (engine.sqlite_version[2] or 0) >= 24; 49 return engine.sqlite_version and (engine.sqlite_version[2] or 0) >= 24 and engine.has_upsert_index;
46 elseif engine.params.driver == "PostgreSQL" then 50 elseif engine.params.driver == "PostgreSQL" then
47 -- PostgreSQL >= 9.5 51 -- PostgreSQL >= 9.5
48 -- Versions without support have long since reached end of life. 52 -- Versions without support have long since reached end of life.
49 return true; 53 return engine.has_upsert_index;
50 end 54 end
51 -- We don't support UPSERT on MySQL/MariaDB, they seem to have a completely different syntax, uncertaint from which versions. 55 -- We don't support UPSERT on MySQL/MariaDB, they seem to have a completely different syntax, uncertaint from which versions.
52 return false 56 return false
53 end 57 end
54 58
755 759
756 --- Initialization 760 --- Initialization
757 761
758 762
759 local function create_table(engine) -- luacheck: ignore 431/engine 763 local function create_table(engine) -- luacheck: ignore 431/engine
760 local sql = engine.params.driver == "SQLite3" and sqlite or dbisql; 764 local sql = get_sql_lib(engine.params.driver);
761 local Table, Column, Index = sql.Table, sql.Column, sql.Index; 765 local Table, Column, Index = sql.Table, sql.Column, sql.Index;
762 766
763 local ProsodyTable = Table { 767 local ProsodyTable = Table {
764 name = "prosody"; 768 name = "prosody";
765 Column { name="host", type="TEXT", nullable=false }; 769 Column { name="host", type="TEXT", nullable=false };
796 end 800 end
797 801
798 local function upgrade_table(engine, params, apply_changes) -- luacheck: ignore 431/engine 802 local function upgrade_table(engine, params, apply_changes) -- luacheck: ignore 431/engine
799 local changes = false; 803 local changes = false;
800 if params.driver == "MySQL" then 804 if params.driver == "MySQL" then
801 local sql = dbisql; 805 local sql = get_sql_lib("MySQL");
802 local success,err = engine:transaction(function() 806 local success,err = engine:transaction(function()
803 do 807 do
804 local result = assert(engine:execute("SHOW COLUMNS FROM \"prosody\" WHERE \"Field\"='value' and \"Type\"='text'")); 808 local result = assert(engine:execute("SHOW COLUMNS FROM \"prosody\" WHERE \"Field\"='value' and \"Type\"='text'"));
805 if result:rowcount() > 0 then 809 if result:rowcount() > 0 then
806 changes = true; 810 changes = true;
891 if not success then 895 if not success then
892 module:log("error", "Failed to delete obsolete index \"prosody_index\""); 896 module:log("error", "Failed to delete obsolete index \"prosody_index\"");
893 return false; 897 return false;
894 end 898 end
895 end 899 end
900 if not indices["prosody_unique_index"] then
901 module:log("warn", "Index \"prosody_unique_index\" does not exist, performance may be worse than normal!");
902 engine.has_upsert_index = false;
903 else
904 engine.has_upsert_index = true;
905 end
896 end 906 end
897 return changes; 907 return changes;
898 end 908 end
899 909
900 local function normalize_database(driver, database) -- luacheck: ignore 431/driver 910 local function normalize_database(driver, database) -- luacheck: ignore 431/driver
918 end 928 end
919 929
920 function module.load() 930 function module.load()
921 local engines = module:shared("/*/sql/connections"); 931 local engines = module:shared("/*/sql/connections");
922 local params = normalize_params(module:get_option("sql", default_params)); 932 local params = normalize_params(module:get_option("sql", default_params));
923 local sql = params.driver == "SQLite3" and sqlite or dbisql; 933 local sql = get_sql_lib(params.driver);
924 local db_uri = sql.db2uri(params); 934 local db_uri = sql.db2uri(params);
925 engine = engines[db_uri]; 935 engine = engines[db_uri];
926 if not engine then 936 if not engine then
927 module:log("debug", "Creating new engine %s", db_uri); 937 module:log("debug", "Creating new engine %s", db_uri);
928 engine = sql:create_engine(params, function (engine) -- luacheck: ignore 431/engine 938 engine = sql:create_engine(params, function (engine) -- luacheck: ignore 431/engine
1010 if command == "upgrade" then 1020 if command == "upgrade" then
1011 -- We need to find every unique dburi in the config 1021 -- We need to find every unique dburi in the config
1012 local uris = {}; 1022 local uris = {};
1013 for host in pairs(prosody.hosts) do -- luacheck: ignore 431/host 1023 for host in pairs(prosody.hosts) do -- luacheck: ignore 431/host
1014 local params = normalize_params(config.get(host, "sql") or default_params); 1024 local params = normalize_params(config.get(host, "sql") or default_params);
1015 local sql = engine.params.driver == "SQLite3" and sqlite or dbisql; 1025 local sql = get_sql_lib(engine.params.driver);
1016 uris[sql.db2uri(params)] = params; 1026 uris[sql.db2uri(params)] = params;
1017 end 1027 end
1018 print("We will check and upgrade the following databases:\n"); 1028 print("We will check and upgrade the following databases:\n");
1019 for _, params in pairs(uris) do 1029 for _, params in pairs(uris) do
1020 print("", "["..params.driver.."] "..params.database..(params.host and " on "..params.host or "")); 1030 print("", "["..params.driver.."] "..params.database..(params.host and " on "..params.host or ""));
1026 return; 1036 return;
1027 end 1037 end
1028 -- Upgrade each one 1038 -- Upgrade each one
1029 for _, params in pairs(uris) do 1039 for _, params in pairs(uris) do
1030 print("Checking "..params.database.."..."); 1040 print("Checking "..params.database.."...");
1031 local sql = params.driver == "SQLite3" and sqlite or dbisql; 1041 local sql = get_sql_lib(params.driver);
1032 engine = sql:create_engine(params); 1042 engine = sql:create_engine(params);
1033 upgrade_table(engine, params, true); 1043 upgrade_table(engine, params, true);
1034 end 1044 end
1035 print("All done!"); 1045 print("All done!");
1036 elseif command then 1046 elseif command then
1038 else 1048 else
1039 print("Available commands:"); 1049 print("Available commands:");
1040 print("","upgrade - Perform database upgrade"); 1050 print("","upgrade - Perform database upgrade");
1041 end 1051 end
1042 end 1052 end
1053
1054 module:add_item("shell-command", {
1055 section = "sql";
1056 section_desc = "SQL management commands";
1057 name = "create";
1058 desc = "Create the tables and indices used by Prosody (again)";
1059 args = { { name = "host"; type = "string" } };
1060 host_selector = "host";
1061 handler = function(shell, _host)
1062 local logger = require "prosody.util.logger";
1063 local writing = false;
1064 local sink = logger.add_simple_sink(function (source, level, message)
1065 local print = shell.session.print;
1066 if writing or source ~= "sql" then return; end
1067 writing = true;
1068 print(message);
1069 writing = false;
1070 end);
1071
1072 local debug_enabled = engine._debug;
1073 engine:debug(true);
1074 create_table(engine);
1075 engine:debug(debug_enabled);
1076
1077 if not logger.remove_sink(sink) then
1078 module:log("warn", "Unable to remove log sink");
1079 end
1080 end;
1081 })