Changeset

6767:d01c29b62b16

Merge 0.10->trunk
author Matthew Wild <mwild1@gmail.com>
date Thu, 09 Jul 2015 00:14:27 +0100
parents 6749:9dc05d3efdc9 (current diff) 6766:b38db4b634d3 (diff)
children 6768:7816923fd5bf 6769:4caef6d53304
files plugins/mod_storage_sql2.lua
diffstat 5 files changed, 82 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/.luacheckrc	Sun Jul 05 18:00:05 2015 +0200
+++ b/.luacheckrc	Thu Jul 09 00:14:27 2015 +0100
@@ -6,3 +6,7 @@
 unused_secondaries = false
 codes = true
 ignore = { "411/err", "421/err", "411/ok", "421/ok" }
+
+files["plugins/"] = {
+	ignore = { "122/module" };
+}
--- a/net/dns.lua	Sun Jul 05 18:00:05 2015 +0200
+++ b/net/dns.lua	Thu Jul 09 00:14:27 2015 +0100
@@ -213,15 +213,6 @@
 end
 
 
-function resolver:new()    -- - - - - - - - - - - - - - - - - - - - - resolver
-	local r = { active = {}, cache = {}, unsorted = {} };
-	setmetatable(r, resolver);
-	setmetatable(r.cache, cache_metatable);
-	setmetatable(r.unsorted, { __mode = 'kv' });
-	return r;
-end
-
-
 -- packet layer -------------------------------------------------- packet layer
 
 
@@ -1054,8 +1045,6 @@
 
 
 function dns.resolver ()    -- - - - - - - - - - - - - - - - - - - - - resolver
-	-- this function seems to be redundant with resolver.new ()
-
 	local r = { active = {}, cache = {}, unsorted = {}, wanted = {}, best_server = 1 };
 	setmetatable (r, resolver);
 	setmetatable (r.cache, cache_metatable);
--- a/plugins/mod_storage_sql2.lua	Sun Jul 05 18:00:05 2015 +0200
+++ b/plugins/mod_storage_sql2.lua	Thu Jul 09 00:14:27 2015 +0100
@@ -13,8 +13,8 @@
 local noop = function() end
 local unpack = unpack
 local function iterator(result)
-	return function(result)
-		local row = result();
+	return function(result_)
+		local row = result_();
 		if row ~= nil then
 			return unpack(row);
 		end
@@ -385,7 +385,8 @@
 		end
 
 		-- COMPAT w/pre-0.10: Upgrade table to UTF-8 if not already
-		local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE` FROM `information_schema`.`columns` WHERE `TABLE_NAME`='prosody' AND ( `CHARACTER_SET_NAME`!='utf8' OR `COLLATION_NAME`!='utf8_bin' );";
+		local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE`,`TABLE_NAME` FROM `information_schema`.`columns` WHERE `TABLE_NAME` LIKE 'prosody%%' AND ( `CHARACTER_SET_NAME`!='%s' OR `COLLATION_NAME`!='%s_bin' );";
+		check_encoding_query = check_encoding_query:format(engine.charset, engine.charset);
 		success,err = engine:transaction(function()
 			local result = engine:execute(check_encoding_query);
 			local n_bad_columns = result:rowcount();
@@ -393,12 +394,13 @@
 				changes = true;
 				if apply_changes then
 					module:log("warn", "Found %d columns in prosody table requiring encoding change, updating now...", n_bad_columns);
-					local fix_column_query1 = "ALTER TABLE `prosody` CHANGE `%s` `%s` BLOB;";
-					local fix_column_query2 = "ALTER TABLE `prosody` CHANGE `%s` `%s` %s CHARACTER SET 'utf8' COLLATE 'utf8_bin';";
+					local fix_column_query1 = "ALTER TABLE `%s` CHANGE `%s` `%s` BLOB;";
+					local fix_column_query2 = "ALTER TABLE `%s` CHANGE `%s` `%s` %s CHARACTER SET '%s' COLLATE '%s_bin';";
 					for row in result:rows() do
-						local column_name, column_type = unpack(row);
-						engine:execute(fix_column_query1:format(column_name, column_name));
-						engine:execute(fix_column_query2:format(column_name, column_name, column_type));
+						local column_name, column_type, table_name  = unpack(row);
+						module:log("debug", "Fixing column %s in table %s", column_name, table_name);
+						engine:execute(fix_column_query1:format(table_name, column_name, column_name));
+						engine:execute(fix_column_query2:format(table_name, column_name, column_name, column_type, engine.charset, engine.charset));
 					end
 					module:log("info", "Database encoding upgrade complete!");
 				end
@@ -410,6 +412,7 @@
 			return false;
 		end
 	end
+	return changes;
 end
 
 local function normalize_params(params)
@@ -429,8 +432,8 @@
 			-- FIXME: we should check in information_schema, etc.
 			create_table();
 			-- Check whether the table needs upgrading
-			if not upgrade_table(params, true) then
-				module:log("error", "Old database format detected, and upgrade failed");
+			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
@@ -438,3 +441,36 @@
 
 	module:provides("storage", driver);
 end
+
+function module.command(arg)
+	local config = require "core.configmanager";
+	local prosodyctl = require "util.prosodyctl";
+	local command = table.remove(arg, 1);
+	if command == "upgrade" then
+		-- We need to find every unique dburi in the config
+		local uris = {};
+		for host in pairs(prosody.hosts) do
+			local params = config.get(host, "sql") or default_params;
+			uris[sql.db2uri(params)] = params;
+		end
+		print("We will check and upgrade the following databases:\n");
+		for _, params in pairs(uris) do
+			print("", "["..params.driver.."] "..params.database..(params.host and " on "..params.host or ""));
+		end
+		print("");
+		print("Ensure you have working backups of the above databases before continuing! ");
+		if not prosodyctl.show_yesno("Continue with the database upgrade? [yN]") then
+			print("Ok, no upgrade. But you do have backups, don't you? ...don't you?? :-)");
+			return;
+		end
+		-- Upgrade each one
+		for _, params in pairs(uris) do
+			print("Checking "..params.database.."...");
+			engine = sql:create_engine(params);
+			upgrade_table(params, true);
+		end
+		print("All done!");
+	else
+		print("Unknown command: "..command);
+	end
+end
--- a/prosodyctl	Sun Jul 05 18:00:05 2015 +0200
+++ b/prosodyctl	Thu Jul 09 00:14:27 2015 +0100
@@ -841,7 +841,8 @@
 		});
 		local known_global_options = set.new({
 			"pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize",
-			"umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings"
+			"umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings",
+			"network_backend", "http_default_host",
 		});
 		local config = config.getconfig();
 		-- Check that we have any global options (caused by putting a host at the top)
--- a/util/sql.lua	Sun Jul 05 18:00:05 2015 +0200
+++ b/util/sql.lua	Thu Jul 09 00:14:27 2015 +0100
@@ -101,6 +101,7 @@
 
 	local params = self.params;
 	assert(params.driver, "no driver")
+	log("debug", "Connecting to [%s] %s...", params.driver, params.database);
 	local dbh, err = DBI.Connect(
 		params.driver, params.database,
 		params.username, params.password,
@@ -110,8 +111,14 @@
 	dbh:autocommit(false); -- don't commit automatically
 	self.conn = dbh;
 	self.prepared = {};
-	self:set_encoding();
-	self:onconnect();
+	local ok, err = self:set_encoding();
+	if not ok then
+		return ok, err;
+	end
+	local ok, err = self:onconnect();
+	if ok == false then
+		return ok, err;
+	end
 	return true;
 end
 function engine:onconnect()
@@ -242,7 +249,7 @@
 	if self.params.driver == "PostgreSQL" then
 		sql = sql:gsub("`", "\"");
 	elseif self.params.driver == "MySQL" then
-		sql = sql:gsub(";$", " CHARACTER SET 'utf8' COLLATE 'utf8_bin';");
+		sql = sql:gsub(";$", (" CHARACTER SET '%s' COLLATE '%s_bin';"):format(self.charset, self.charset));
 	end
 	local success,err = self:execute(sql);
 	if not success then return success,err; end
@@ -265,15 +272,33 @@
 	local set_names_query = "SET NAMES '%s';"
 	local charset = "utf8";
 	if driver == "MySQL" then
-		set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';");
 		local ok, charsets = self:transaction(function()
 			return self:select"SELECT `CHARACTER_SET_NAME` FROM `information_schema`.`CHARACTER_SETS` WHERE `CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;";
 		end);
 		local row = ok and charsets();
 		charset = row and row[1] or charset;
+		set_names_query = set_names_query:gsub(";$", (" COLLATE '%s';"):format(charset.."_bin"));
 	end
 	self.charset = charset;
-	return self:transaction(function() return self:execute(set_names_query:format(charset)); end);
+	log("debug", "Using encoding '%s' for database connection", charset);
+	local ok, err = self:transaction(function() return self:execute(set_names_query:format(charset)); end);
+	if not ok then
+		return ok, err;
+	end
+	
+	if driver == "MySQL" then
+		local ok, actual_charset = self:transaction(function ()
+			return self:select"SHOW SESSION VARIABLES LIKE 'character_set_client'";
+		end);
+		for row in actual_charset do
+			if row[2] ~= charset then
+				log("error", "MySQL %s is actually %q (expected %q)", row[1], row[2], charset);
+				return false, "Failed to set connection encoding";
+			end
+		end
+	end
+	
+	return true;
 end
 local engine_mt = { __index = engine };