[glom/mysql: 2/21] Some more MySQL support.



commit 4bc56ab17f3abc180512a99f4df2d73ed6d2b762
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed Jan 2 22:37:19 2013 +0100

    Some more MySQL support.

 configure.ac                                       |   14 +-
 glom/libglom/connectionpool.cc                     |   20 ++
 glom/libglom/connectionpool_backends/mysql.cc      |  111 +-------
 glom/libglom/connectionpool_backends/mysql.h       |    7 -
 .../connectionpool_backends/mysql_central.cc       |  170 ++++++++++
 .../connectionpool_backends/mysql_central.h        |   66 ++++
 glom/libglom/connectionpool_backends/mysql_self.cc |  325 +++++++-------------
 glom/libglom/connectionpool_backends/mysql_self.h  |    6 +
 glom/libglom/document/document.cc                  |   34 ++-
 glom/libglom/document/document.h                   |    6 +-
 glom/libglom/filelist.am                           |    2 +
 tests/test_selfhosting_new_empty.cc                |    7 +
 tests/test_selfhosting_utils.cc                    |    2 +
 13 files changed, 429 insertions(+), 341 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ca1ed24..38e19f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,8 +258,8 @@ AS_IF([test "x$glom_host_win32" != xyes && test "x$glom_enable_client_only" != x
   POSTGRES_UTILS_PATH=`pg_config --bindir 2>&AS_MESSAGE_LOG_FD`
   AS_IF(["$POSTGRES_UTILS_PATH/pg_ctl" --version >/dev/null 2>&AS_MESSAGE_LOG_FD],,
         [AC_MSG_ERROR([[
-The Postgres utilities could not be found. They are needed for
-self-hosting of Glom databases. Please make sure that Postgres
+The PostgreSQL utilities could not be found. They are needed for
+self-hosting of Glom databases. Please make sure that PostgreSQL
 is installed, and if necessary specify the correct directory
 explicitly with the --with-postgres-utils option.
 ]])])])])
@@ -275,8 +275,16 @@ AC_ARG_WITH([mysql-utils],
             [AS_HELP_STRING([--with-mysql-utils=DIR],
                             [path to MySQL utilities.])],
             [MYSQL_UTILS_PATH=$withval])
+# Path not needed on Windows
+AS_IF([test "x$glom_host_win32" != xyes && test "x$glom_enable_client_only" != xyes],
+      [AS_CASE([$MYSQL_UTILS_PATH], [""|no|yes],
+[
+  # TODO: Check properly instead of hard-coding /usr/bin
+  MYSQL_UTILS_PATH="/usr/bin"
+])])
+
 AC_DEFINE_UNQUOTED([MYSQL_UTILS_PATH], ["$MYSQL_UTILS_PATH"],
-                   [Define to the location of the PostgreSQL utilities.])
+                   [Define to the location of the MySQL utilities.])
 
 
 GNOME_DOC_INIT([0.9.0],,
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index f06c3cf..9224433 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -29,6 +29,8 @@
 #include <libglom/connectionpool_backends/postgres_central.h>
 #include <libglom/connectionpool_backends/postgres_self.h>
 #include <libglom/connectionpool_backends/sqlite.h>
+#include <libglom/connectionpool_backends/mysql_central.h>
+#include <libglom/connectionpool_backends/mysql_self.h>
 
 #include <glibmm/main.h>
 
@@ -164,6 +166,22 @@ void ConnectionPool::setup_from_document(const Document* document)
       set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
     }
     break;
+  case Document::HOSTING_MODE_MYSQL_SELF:
+    {
+      ConnectionPoolBackends::MySQLSelfHosted* backend = new ConnectionPoolBackends::MySQLSelfHosted;
+      backend->set_database_directory_uri(document->get_connection_self_hosted_directory_uri());
+      set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
+    }
+    break;
+  case Document::HOSTING_MODE_MYSQL_CENTRAL:
+    {
+      ConnectionPoolBackends::MySQLCentralHosted* backend = new ConnectionPoolBackends::MySQLCentralHosted;
+      backend->set_host(document->get_connection_server());
+      backend->set_port(document->get_connection_port());
+      backend->set_try_other_ports(document->get_connection_try_other_ports());
+      set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
+    }
+    break;
 
   default:
     //on_document_load() should have checked for this already, informing the user.
@@ -420,6 +438,7 @@ bool ConnectionPool::save_backup(const SlotProgress& slot_progress, const std::s
   std::string uri;
   try
   {
+    //TODO_MySQL:
     //TODO: Avoid the copy/paste of glom_postgres_data and make it work for sqlite too.
     const std::string subdir = Glib::build_filename(path_dir, "glom_postgres_data");
     uri = Glib::filename_to_uri(subdir);
@@ -440,6 +459,7 @@ bool ConnectionPool::convert_backup(const SlotProgress& slot_progress, const std
 {
   g_assert(m_backend.get());
 
+  //TODO_MySQL:
   //TODO: Avoid this copy/paste of the directory name:
   std::string path_dir_to_use = path_dir;
   if(!path_dir_to_use.empty())
diff --git a/glom/libglom/connectionpool_backends/mysql.cc b/glom/libglom/connectionpool_backends/mysql.cc
index f738711..724b824 100644
--- a/glom/libglom/connectionpool_backends/mysql.cc
+++ b/glom/libglom/connectionpool_backends/mysql.cc
@@ -523,63 +523,7 @@ Glib::ustring MySQL::port_as_string(unsigned int port_num)
   return result;
 }
 
-//Because ~/.pgpass is not an absolute path.
-static std::string get_absolute_pgpass_filepath()
-{
-  return Glib::build_filename(
-    Glib::get_home_dir(), ".pgpass");
-}
-
-bool MySQL::save_password_to_pgpass(const Glib::ustring username, const Glib::ustring& password, std::string& filepath_previous, std::string& filepath_original)
-{
-  //Initialize output variables:
-  filepath_previous.clear();
-  filepath_original.clear();
-
-  const std::string filepath_pgpass = get_absolute_pgpass_filepath();
-  filepath_original = filepath_pgpass;
-
-  //Move any existing file out of the way:
-  if(file_exists_filepath(filepath_pgpass))
-  {
-    //std::cout << "DEBUG: File exists: " << filepath_pgpass << std::endl;
-    filepath_previous = filepath_pgpass + ".glombackup";
-    if(g_rename(filepath_pgpass.c_str(), filepath_previous.c_str()) != 0)
-    {
-      std::cerr << G_STRFUNC << "Could not rename file: from=" << filepath_pgpass << ", to=" << filepath_previous << std::endl;
-      return false;
-    }
-  }
-
-  //See http://www.mysqlql.org/docs/8.4/static/libpq-pgpass.html
-  //TODO: Escape \ and : characters.
-  const Glib::ustring contents =
-    m_host + ":" + port_as_string(m_port) + ":*:" + username + ":" + password;
-
-  std::string uri;
-  try
-  {
-    uri = Glib::filename_to_uri(filepath_pgpass);
-  }
-  catch(const Glib::Error& ex)
-  {
-    std::cerr << G_STRFUNC << ": exception from Glib::filename_from_uri(): " << ex.what() << std::endl;
-    g_rename(filepath_previous.c_str(), filepath_pgpass.c_str());
-    return false;
-  }
-
-  const bool result = create_text_file(uri, contents, true /* current user only */);
-  if(!result)
-  {
-    std::cerr << G_STRFUNC << ": create_text_file() failed." << std::endl;
-    g_rename(filepath_previous.c_str(), filepath_pgpass.c_str());
-    return false;
-  }
-
-  return result;
-}
-
-bool MySQL::save_backup(const SlotProgress& slot_progress, const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name)
+bool MySQL::save_backup(const SlotProgress& slot_progress, const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& /* database_name */)
 {
 /* TODO:
   if(m_network_shared && !running)
@@ -614,43 +558,19 @@ bool MySQL::save_backup(const SlotProgress& slot_progress, const Glib::ustring&
     return false;
   }
 
-  // Save the password to ~/.pgpass, because this is the only way to use
-  // pg_dump without it asking for the password:
-  std::string pgpass_backup, pgpass_original;
-  const bool pgpass_created = save_password_to_pgpass(username, password, pgpass_backup, pgpass_original);
-  if(!pgpass_created)
-  {
-    std::cerr << G_STRFUNC << ": save_password_to_pgpass() failed." << std::endl;
-    return false;
-  }
-
   const std::string path_backup = get_self_hosting_backup_path(std::string(), true /* create parent directory if necessary */);
   if(path_backup.empty())
     return false;
 
   // Make sure to use double quotes for the executable path, because the
   // CreateProcess() API used on Windows does not support single quotes.
-  const std::string command_dump = get_path_to_mysql_executable("pg_dump") +
-    " --format=c " + // The default (plain) format cannot be used with pg_restore.
-    " --create --file=" + Glib::shell_quote(path_backup) +
-    " --host=" + Glib::shell_quote(m_host) +
-    " --port=" + port_as_string(m_port) +
-    " --username=" + Glib::shell_quote(username) +
-    " " + database_name; //TODO: Quote database_name?
+  const std::string command_dump; //TODO_MySQL
 
 
   //std::cout << "DEBUG: command_dump=" << command_dump << std::endl;
 
   const bool result = Glom::Spawn::execute_command_line_and_wait(command_dump, slot_progress);
 
-  //Move the previously-existing .pgpass file back:
-  //TODO: Really, we should just edit the file instead of completely replacing it,
-  //      because another application might try to edit it in the meantime.
-  if(!pgpass_backup.empty())
-  {
-    g_rename(pgpass_backup.c_str(), pgpass_original.c_str());
-  }
-
   if(!result)
   {
     std::cerr << "Error while attempting to call pg_dump." << std::endl;
@@ -659,7 +579,7 @@ bool MySQL::save_backup(const SlotProgress& slot_progress, const Glib::ustring&
   return result;
 }
 
-bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name)
+bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& /* database_name */)
 {
 /* TODO:
   if(m_network_shared && !running)
@@ -702,24 +622,9 @@ bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string&
     return false;
   }
 
-  // Save the password to ~/.pgpass, because this is the only way to use
-  // pg_dump without it asking for the password:
-  std::string pgpass_backup, pgpass_original;
-  const bool pgpass_created = save_password_to_pgpass(username, password, pgpass_backup, pgpass_original);
-  if(!pgpass_created)
-  {
-    std::cerr << G_STRFUNC << ": save_password_to_pgpass() failed." << std::endl;
-    return false;
-  }
-
   // Make sure to use double quotes for the executable path, because the
   // CreateProcess() API used on Windows does not support single quotes.
-  const std::string command_restore = get_path_to_mysql_executable("pg_restore") +
-    " -d " + database_name + //TODO: Quote database name?
-    " --host=" + Glib::shell_quote(m_host) +
-    " --port=" + port_as_string(m_port) +
-    " --username=" + Glib::shell_quote(username) +
-    " " + path_backup;
+  const std::string command_restore; //TODO_MySQL
 
   std::cout << "DEBUG: command_restore=" << command_restore << std::endl;
 
@@ -727,14 +632,6 @@ bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string&
 
   const bool result = Glom::Spawn::execute_command_line_and_wait(command_restore, slot_progress);
 
-  //Move the previously-existing .pgpass file back:
-  //TODO: Really, we should just edit the file instead of completely replacing it,
-  //      because another application might try to edit it in the meantime.
-  if(!pgpass_backup.empty())
-  {
-    g_rename(pgpass_backup.c_str(), pgpass_original.c_str());
-  }
-
   if(!result)
   {
     std::cerr << "Error while attempting to call pg_restore." << std::endl;
diff --git a/glom/libglom/connectionpool_backends/mysql.h b/glom/libglom/connectionpool_backends/mysql.h
index d711a38..218cccc 100644
--- a/glom/libglom/connectionpool_backends/mysql.h
+++ b/glom/libglom/connectionpool_backends/mysql.h
@@ -97,13 +97,6 @@ protected:
    */
   static bool create_text_file(const std::string& file_uri, const std::string& contents, bool current_user_only = false);
 
-  /**
-   * @param filepath_previous The path to which the previous .pgpass, if any was moved.
-   * @param filepath_original The path to which filepath_previous should be moved back after the caller has finished.
-   * @param result whether it succeeded.
-   */
-  bool save_password_to_pgpass(const Glib::ustring username, const Glib::ustring& password, std::string& filepath_previous, std::string& filepath_original);
-
 protected:
   static Glib::ustring port_as_string(unsigned int port_num);
 
diff --git a/glom/libglom/connectionpool_backends/mysql_central.cc b/glom/libglom/connectionpool_backends/mysql_central.cc
new file mode 100644
index 0000000..5bbbda6
--- /dev/null
+++ b/glom/libglom/connectionpool_backends/mysql_central.cc
@@ -0,0 +1,170 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include <libglom/libglom_config.h>
+
+#include <libglom/connectionpool_backends/mysql_central.h>
+#include <glibmm/i18n.h>
+
+// Uncomment to see debug messages
+//#define GLOM_CONNECTION_DEBUG
+
+namespace Glom
+{
+
+namespace ConnectionPoolBackends
+{
+
+MySQLCentralHosted::MySQLCentralHosted()
+: m_try_other_ports(true)
+{
+  //TODO_MySQL:
+  m_list_ports.push_back("5432"); //Ubuntu Breezy seems to default to this for MySQL 7.4, and this is probably the default for most mysql installations, including Fedora.
+
+  m_list_ports.push_back("5433"); //Ubuntu Dapper seems to default to this for MySQL 8.1, probably to avoid a clash with MySQL 7.4
+
+  m_list_ports.push_back("5434"); //Earlier versions of Ubuntu Feisty defaulted to this for MySQL 8.2.
+  m_list_ports.push_back("5435"); //In case Ubuntu increases the port number again in future.
+  m_list_ports.push_back("5436"); //In case Ubuntu increases the port number again in future.
+}
+
+void MySQLCentralHosted::set_host(const Glib::ustring& value)
+{
+  if(value != m_host)
+  {
+    m_host = value;
+
+    // Force us to try all ports again when connecting for the first time, then remember the working port again. Except when a specific port was set to be used.
+    if(m_try_other_ports)
+      m_port = 0;
+  }
+}
+
+void MySQLCentralHosted::set_port(unsigned int port)
+{
+  m_port = port;
+}
+
+void MySQLCentralHosted::set_try_other_ports(bool val)
+{
+  m_try_other_ports = val;
+}
+
+Glib::ustring MySQLCentralHosted::get_host() const
+{
+  return m_host;
+}
+
+unsigned int MySQLCentralHosted::get_port() const
+{
+  return m_port;
+}
+
+bool MySQLCentralHosted::get_try_other_ports() const
+{
+  return m_try_other_ports;
+}
+
+Glib::RefPtr<Gnome::Gda::Connection> MySQLCentralHosted::connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password, bool fake_connection)
+{
+  Glib::RefPtr<Gnome::Gda::Connection> connection;
+
+  //Try each possible network port:
+  type_list_ports::const_iterator iter_port = m_list_ports.begin();
+
+  //Start with the remembered-as-working port:
+  Glib::ustring port = port_as_string(m_port);
+  if(m_port == 0)
+    port = *iter_port ++;
+
+  bool connection_possible = false;
+  try
+  {
+    connection = attempt_connect(port, database, username, password, fake_connection);
+    connection_possible = true;
+    m_port = atoi(port.c_str());
+  }
+  catch(const ExceptionConnection& ex)
+  {
+    // Remember port if only the database was missing
+    connection_possible = false;
+    if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_DATABASE)
+    {
+      connection_possible = true;
+      m_port = atoi(port.c_str());
+    }
+  }
+
+  // Try more ports if so desired, and we don't have a connection yet
+  if(m_try_other_ports && !connection)
+  {
+    while(!connection && iter_port != m_list_ports.end())
+    {
+      port = *iter_port;
+
+      try
+      {
+        connection = attempt_connect(port, database, username, password, fake_connection);
+        connection_possible = true;
+        m_port = atoi(port.c_str());
+      }
+      catch(const ExceptionConnection& ex)
+      {
+        //Don't set this, because we might have previously set it to true to 
+        //show that a connection was possible with a previously-tried port: connection_possible = false;
+
+        // Remember port if only the database was missing
+        if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_DATABASE)
+        {
+          connection_possible = true;
+          m_port = atoi(port.c_str());
+        }
+      }
+
+      // Skip if we already tried this port
+      if(iter_port != m_list_ports.end() && *iter_port == port)
+        ++ iter_port;
+    }
+  }
+
+  if(connection)
+  {
+    //Remember working port:
+    m_port = atoi(port.c_str());
+  }
+  else
+  {
+    if(connection_possible)
+      throw ExceptionConnection(ExceptionConnection::FAILURE_NO_DATABASE);
+    else
+      throw ExceptionConnection(ExceptionConnection::FAILURE_NO_SERVER);
+  }
+
+  return connection;
+}
+
+bool MySQLCentralHosted::create_database(const SlotProgress& slot_progress, const Glib::ustring& database_name, const Glib::ustring& username, const Glib::ustring& password)
+{
+  return attempt_create_database(slot_progress, database_name, get_host(), port_as_string(m_port), username, password);
+}
+
+}
+
+}
diff --git a/glom/libglom/connectionpool_backends/mysql_central.h b/glom/libglom/connectionpool_backends/mysql_central.h
new file mode 100644
index 0000000..8bdbbfb
--- /dev/null
+++ b/glom/libglom/connectionpool_backends/mysql_central.h
@@ -0,0 +1,66 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GLOM_BACKEND_MYSQL_CENTRAL_H
+#define GLOM_BACKEND_MYSQL_CENTRAL_H
+
+#include <libglom/connectionpool_backends/mysql.h>
+
+#include <libglom/libglom_config.h>
+
+namespace Glom
+{
+
+namespace ConnectionPoolBackends
+{
+
+class MySQLCentralHosted : public MySQL
+{
+public:
+  MySQLCentralHosted();
+
+  /** 0 means any port
+   * Other ports will be tried if the specified port fails.
+   */
+  void set_host(const Glib::ustring& value);
+  void set_port(unsigned int port);
+  void set_try_other_ports(bool val);
+
+  Glib::ustring get_host() const;
+  unsigned int get_port() const;
+  bool get_try_other_ports() const;
+
+private:
+  virtual Glib::RefPtr<Gnome::Gda::Connection> connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password, bool fake_connection = false);
+
+  virtual bool create_database(const SlotProgress& slot_progress, const Glib::ustring& database_name, const Glib::ustring& username, const Glib::ustring& password);
+
+private:
+  typedef std::vector<Glib::ustring> type_list_ports;
+  type_list_ports m_list_ports;
+
+  bool m_try_other_ports;
+};
+
+} //namespace ConnectionPoolBackends
+
+} //namespace Glom
+
+#endif //GLOM_BACKEND_MYSQL_CENTRAL_H
diff --git a/glom/libglom/connectionpool_backends/mysql_self.cc b/glom/libglom/connectionpool_backends/mysql_self.cc
index aa64130..3d910b1 100644
--- a/glom/libglom/connectionpool_backends/mysql_self.cc
+++ b/glom/libglom/connectionpool_backends/mysql_self.cc
@@ -27,6 +27,7 @@
 #include <glib/gstdio.h> // For g_remove
 
 #include <glibmm/convert.h>
+#include <glibmm/fileutils.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/stringutils.h>
 #include <glibmm/regex.h>
@@ -59,39 +60,15 @@ namespace Glom
 namespace ConnectionPoolBackends
 {
 
-
-#define DEFAULT_CONFIG_PG_HBA_LOCAL \
-"# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD\n" \
-"\n" \
-"# local is for Unix domain socket connections only\n" \
-"# trust allows connection from the current PC without a password:\n" \
-"local   all         all                               trust\n" \
-"local   all         all                               md5\n" \
-"\n" \
-"# TCP connections from the same computer, with a password:\n" \
-"host    all         all         127.0.0.1    255.255.255.255    md5\n" \
-"# IPv6 local connections:\n" \
-"host    all         all         ::1/128               md5\n"
-
-#define DEFAULT_CONFIG_PG_HBA_REMOTE_EXTRA \
-"\n" \
-"# IPv4 local connections:\n" \
-"host    all         all         0.0.0.0/0          md5\n" \
-"# IPv6 local connections:\n" \
-"host    all         all         ::1/128               md5\n"
-
-#define DEFAULT_CONFIG_PG_HBA_REMOTE \
-DEFAULT_CONFIG_PG_HBA_LOCAL \
-DEFAULT_CONFIG_PG_HBA_REMOTE_EXTRA
-
-static const int PORT_MYSQL_SELF_HOSTED_START = 5433;
-static const int PORT_MYSQL_SELF_HOSTED_END = 5500;
+static const int PORT_MYSQL_SELF_HOSTED_START = 3306;
+static const int PORT_MYSQL_SELF_HOSTED_END = 3350;
 
 static const char FILENAME_DATA[] = "data";
 static const char FILENAME_BACKUP[] = "backup";
 
 MySQLSelfHosted::MySQLSelfHosted()
-: m_network_shared(false)
+: m_network_shared(false),
+  m_temporary_password_active(false)
 {
   m_host = "localhost";
 }
@@ -179,17 +156,8 @@ Backend::InitErrors MySQLSelfHosted::initialize(const SlotProgress& slot_progres
     return INITERROR_COULD_NOT_CREATE_DIRECTORY;
   }
 
-  //Create the config directory:
-  const std::string dbdir_config = get_self_hosting_config_path(true /* create */);
-  if(dbdir_config.empty())
-  {
-    std::cerr << "Couldn't create the config directory: " << dbdir << std::endl;
-
-    return INITERROR_COULD_NOT_CREATE_DIRECTORY;
-  }
-
-  //Create these files: environment, pg_hba.conf, start.conf
-  set_network_shared(slot_progress, m_network_shared); //Creates pg_hba.conf
+  //Create these files: environment
+  set_network_shared(slot_progress, m_network_shared);
 
   //Check that there is not an existing data directory:
   const std::string dbdir_data = get_self_hosting_data_path(true /* create */);
@@ -202,139 +170,65 @@ Backend::InitErrors MySQLSelfHosted::initialize(const SlotProgress& slot_progres
 
   // initdb creates a new mysql database cluster:
 
-  //Get file:// URI for the tmp/ directory:
-  const std::string temp_pwfile = Utils::get_temp_file_path("glom_initdb_pwfile");
-  const Glib::ustring temp_pwfile_uri = Glib::filename_to_uri(temp_pwfile);
-  const bool pwfile_creation_succeeded = create_text_file(temp_pwfile_uri, password);
-  g_assert(pwfile_creation_succeeded);
-
   // Make sure to use double quotes for the executable path, because the
   // CreateProcess() API used on Windows does not support single quotes.
-  const std::string command_initdb = get_path_to_mysql_executable("initdb") + " -D " + Glib::shell_quote(dbdir_data) +
-                                        " -U " + initial_username + " --pwfile=" + Glib::shell_quote(temp_pwfile);
-
-  //Note that --pwfile takes the password from the first line of a file. It's an alternative to supplying it when prompted on stdin.
-  const bool result = Glom::Spawn::execute_command_line_and_wait(command_initdb, slot_progress);
+  // We don't use mysql_secure_installation because it only takes the details via prompts.
+  // TODO: With MySQL 5.6, use the new --random-passwords option, because otherwise the root password will be blank,
+  // and, at least on Ubuntu, we will then not be able to connect with mysqladmin.
+  const std::string command_initdb = get_path_to_mysql_executable("mysql_install_db")
+    + " --no-defaults" //Otherwise Ubuntu specifies --user=mysql
+    + " --datadir=" + Glib::shell_quote(dbdir_data);
+    //TODO: + " --random-passwords";
+  std::cout << "debug: command_initdb=" << command_initdb << std::endl;
+  bool result = Glom::Spawn::execute_command_line_and_wait(command_initdb, slot_progress);
   if(!result)
   {
-    std::cerr << "Error while attempting to create self-hosting database." << std::endl;
+    std::cerr << "Error while attempting to create self-hosting MySQL database." << std::endl;
   }
+  else
+  {
+    //This is used during the first start:
+    m_initial_password_to_set = password;
+
+    //TODO: With MySQL 5.6, use the new --random-passwords option (see above)
+    m_temporary_password = "";
+    m_temporary_password_active = true;
+    //Get the temporary random password,
+    //which will be used when first starting the server.
+    /*
+    const std::string temporary_password_file = Glib::build_filename(
+      Glib::get_home_dir(), ".mysql.secret");
+    try
+    {
+      m_temporary_password = Glib::file_get_contents(temporary_password_file);
+      m_temporary_password_active = true;
+    }
+    catch(const Glib::Error& ex)
+    {
+      std::cerr << G_STRFUNC << "file_get_contents() failed: " << ex.what() << std::endl;
+    }
 
-  const int temp_pwfile_removed = g_remove(temp_pwfile.c_str()); //Of course, we don't want this to stay around. It would be a security risk.
-  g_assert(temp_pwfile_removed == 0);
+    if(m_temporary_password.empty())
+    {
+       std::cerr << G_STRFUNC << " Unable to discover the initial MySQL password." << std::endl;
+       result = false;
+    }
+    */
+  }
 
   return result ? INITERROR_NONE : INITERROR_COULD_NOT_START_SERVER;
 }
 
-Glib::ustring MySQLSelfHosted::get_mysqlql_utils_version(const SlotProgress& slot_progress)
+Glib::ustring MySQLSelfHosted::get_mysqlql_utils_version(const SlotProgress& /* slot_progress */)
 {
-  Glib::ustring result;
-
-  const std::string command = get_path_to_mysql_executable("pg_ctl") + " --version";
-
-  //The first command does not return, but the second command can check whether it succeeded:
-  std::string output;
-  const bool spawn_result = Glom::Spawn::execute_command_line_and_wait(command, slot_progress, output);
-  if(!spawn_result)
-  {
-    std::cerr << "Error while attempting to discover the pg_ctl version." << std::endl;
-    return result;
-  }
-
-  //Use a regex to get the version number:
-  Glib::RefPtr<Glib::Regex> regex;
-
-  //We want the characters at the end:
-  const gchar VERSION_REGEX[] = "pg_ctl \\(MySQL\\) (.*)";
-
-  try
-  {
-    regex = Glib::Regex::create(VERSION_REGEX);
-  }
-  catch(const Glib::Error& ex)
-  {
-    std::cerr << "Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
-    return result;
-  }
-
-  if(!regex)
-    return result;
-
-  typedef std::vector<Glib::ustring> type_vec_strings;
-  const type_vec_strings vec = regex->split(output, Glib::REGEX_MATCH_NOTEMPTY);
-  //std::cout << "DEBUG: output == " << output << std::endl;
-  //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
-
-  // We get, for instance, "\n" and 8.4.1" and "\n".
-  for(type_vec_strings::const_iterator iter = vec.begin();
-       iter != vec.end();
-       ++iter)
-  {
-    const Glib::ustring str = *iter;
-    if(!str.empty())
-      return str; //Found.
-  }
-
-  return result;
+  return Glib::ustring(); //TODO
 }
 
-float MySQLSelfHosted::get_mysqlql_utils_version_as_number(const SlotProgress& slot_progress)
+float MySQLSelfHosted::get_mysqlql_utils_version_as_number(const SlotProgress& /* slot_progress */)
 {
-  float result = 0;
-
-  const Glib::ustring version_str = get_mysqlql_utils_version(slot_progress);
-
-  Glib::RefPtr<Glib::Regex> regex;
-
-  //We want the characters at the end:
-  const gchar VERSION_REGEX[] = "^(\\d*)\\.(\\d*)";
-
-  try
-  {
-    regex = Glib::Regex::create(VERSION_REGEX);
-  }
-  catch(const Glib::Error& ex)
-  {
-    std::cerr << "Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
-    return result;
-  }
-
-  if(!regex)
-    return result;
-
-  typedef std::vector<Glib::ustring> type_vec_strings;
-  const type_vec_strings vec = regex->split(version_str, Glib::REGEX_MATCH_NOTEMPTY);
-  //std::cout << "DEBUG: str == " << version_str << std::endl;
-  //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
-
-  //We need to loop over the numbers because we get some "" items that we want to ignore:
-  guint count = 0; //We want 2 numbers.
-  for(type_vec_strings::const_iterator iter = vec.begin();
-       iter != vec.end();
-       ++iter)
-  {
-    //std::cout << "regex item: START" << *iter << "END" << std::endl;
-
-    const Glib::ustring str = *iter;
-    if(str.empty())
-      continue;
-
-    const float num = atoi(str.c_str());
-    if(count == 0)
-      result = num;
-    else if(count == 1)
-    {
-      result += (0.1 * num);
-      break;
-    }
-
-    ++count;
-  }
-
-  return result;
+  return 0; //TODO
 }
 
-
 Backend::StartupErrors MySQLSelfHosted::startup(const SlotProgress& slot_progress, bool network_shared)
 {
   m_network_shared = network_shared;
@@ -381,7 +275,7 @@ Backend::StartupErrors MySQLSelfHosted::startup(const SlotProgress& slot_progres
   }
 
   //Attempt to ensure that the config files are correct:
-  set_network_shared(slot_progress, m_network_shared); //Creates pg_hba.conf
+  set_network_shared(slot_progress, m_network_shared);
 
   const unsigned int available_port = discover_first_free_port(PORT_MYSQL_SELF_HOSTED_START, PORT_MYSQL_SELF_HOSTED_END);
   //std::cout << "debug: " << G_STRFUNC << ":() : debug: Available port for self-hosting: " << available_port << std::endl;
@@ -395,46 +289,57 @@ Backend::StartupErrors MySQLSelfHosted::startup(const SlotProgress& slot_progres
   //TODO: Performance:
   const std::string port_as_text = Glib::Ascii::dtostr(available_port);
 
-  // -D specifies the data directory.
-  // -c config_file= specifies the configuration file
-  // -k specifies a directory to use for the socket. This must be writable by us.
   // Make sure to use double quotes for the executable path, because the
   // CreateProcess() API used on Windows does not support single quotes.
-  const std::string dbdir_config = Glib::build_filename(dbdir, "config");
-  const std::string dbdir_hba = Glib::build_filename(dbdir_config, "pg_hba.conf");
   const std::string dbdir_pid = Glib::build_filename(dbdir, "pid");
-  const std::string listen_address = (m_network_shared ? "*" : "localhost");
-  const std::string command_mysql_start = get_path_to_mysql_executable("mysql") + " -D " + Glib::shell_quote(dbdir_data)
-                                  + " -p " + port_as_text
-                                  + " -h " + listen_address
-                                  + " -c hba_file=" + Glib::shell_quote(dbdir_hba)
-                                  + " -k " + Glib::shell_quote(dbdir)
-                                  + " --external_pid_file=" + Glib::shell_quote(dbdir_pid);
-  //std::cout << G_STRFUNC << ": debug: " << command_mysql_start << std::endl;
+  const std::string dbdir_socket = Glib::build_filename(dbdir, "mysqld.sock");
+  const std::string command_mysql_start = get_path_to_mysql_executable("mysqld_safe")
+                                  + " --no-defaults"
+                                  + " --port=" + port_as_text
+                                  + " --datadir=" + Glib::shell_quote(dbdir_data)
+                                  + " --socket=" + Glib::shell_quote(dbdir_socket)
+                                  + " --pid-file=" + Glib::shell_quote(dbdir_pid);
+  std::cout << G_STRFUNC << ": debug: command_mysql_start=" << command_mysql_start << std::endl;
+
+  m_port = available_port; //Needed by get_mysqladmin_command().
+  const std::string command_check_mysql_has_started = get_mysqladmin_command(m_temporary_password) //TODO: Get the temporary password in a callback.
+    + " ping";
+  const std::string second_command_success_text = "mysqld is alive"; //TODO: This is not a stable API. Also, watch out for localisation.
+  std::cout << G_STRFUNC << ": debug: command_check_mysql_has_started=" << command_check_mysql_has_started << std::endl;
 
-  // Make sure to use double quotes for the executable path, because the
-  // CreateProcess() API used on Windows does not support single quotes.
-  const std::string command_check_mysql_has_started = get_path_to_mysql_executable("pg_ctl") + " status -D " + Glib::shell_quote(dbdir_data);
-
-  //For mysql 8.1, this is "postmaster is running".
-  //For mysql 8.2, this is "server is running".
-  //This is a big hack that we should avoid. murrayc.
-  //
-  //pg_ctl actually seems to return a 0 result code for "is running" and a 1 for not running, at least with MySQL 8.2,
-  //so maybe we can avoid this in future.
-  //Please do test it with your mysql version, using "echo $?" to see the result code of the last command.
-  const std::string second_command_success_text = "is running"; //TODO: This is not a stable API. Also, watch out for localisation.
-
-  //The first command does not return, but the second command can check whether it succeeded:
   const bool result = Glom::Spawn::execute_command_line_and_wait_until_second_command_returns_success(command_mysql_start, command_check_mysql_has_started, slot_progress, second_command_success_text);
+
   if(!result)
   {
-    std::cerr << "Error while attempting to self-host a database." << std::endl;
+    m_port = 0;
+
+    std::cerr << "Error while attempting to self-host a MySQL database." << std::endl;
     return STARTUPERROR_FAILED_UNKNOWN_REASON;
   }
 
   m_port = available_port; //Remember it for later.
 
+  //If necessary, set the initial password:
+  if(m_temporary_password_active)
+  {
+    const std::string command_initdb_initial_password = get_mysqladmin_command(m_temporary_password)
+      + " password" + Glib::shell_quote(m_initial_password_to_set);
+    std::cout << "debug: command_initdb_initial_password=" << command_initdb_initial_password << std::endl;
+
+    const bool result = Glom::Spawn::execute_command_line_and_wait(command_initdb_initial_password, slot_progress);
+
+    if(!result)
+    {
+      std::cerr << "Error while attempting to start self-hosting MySQL database, when setting the initial password." << std::endl;
+      return STARTUPERROR_FAILED_UNKNOWN_REASON;
+    }
+
+    m_temporary_password_active = false;
+    m_temporary_password.clear();
+
+    //TODO_MySQL: " -U " + initial_username
+  }
+
   return STARTUPERROR_NONE;
 }
 
@@ -476,6 +381,17 @@ void MySQLSelfHosted::show_active_connections()
   gda_connection->close();
 }
 
+std::string MySQLSelfHosted::get_mysqladmin_command(const Glib::ustring& password)
+{
+  const std::string port_as_text = Glib::Ascii::dtostr(m_port);
+
+  return get_path_to_mysql_executable("mysqladmin")
+    + " --no-defaults"
+    + " --port=" + port_as_text
+    + " --user=root"
+    + " --password=" + Glib::shell_quote(password);
+}
+
 bool MySQLSelfHosted::cleanup(const SlotProgress& slot_progress)
 {
   // This seems to be called twice sometimes, so we don't assert here until
@@ -485,15 +401,7 @@ bool MySQLSelfHosted::cleanup(const SlotProgress& slot_progress)
   if(!get_self_hosting_active())
     return true; //Don't try to stop it if we have not started it.
 
-  const std::string dbdir_uri = m_database_directory_uri;
-  const std::string dbdir = Glib::filename_from_uri(dbdir_uri);
-  g_assert(!dbdir.empty());
-
-  const std::string dbdir_data = Glib::build_filename(dbdir, FILENAME_DATA);
-
-
-  // TODO: Detect other instances on the same computer, and use a different port number,
-  // or refuse to continue, showing an error dialog.
+  const std::string port_as_text = Glib::Ascii::dtostr(m_port);
 
   // -D specifies the data directory.
   // -c config_file= specifies the configuration file
@@ -502,11 +410,12 @@ bool MySQLSelfHosted::cleanup(const SlotProgress& slot_progress)
   // TODO: Warn about connected clients on other computers? Warn those other users?
   // Make sure to use double quotes for the executable path, because the
   // CreateProcess() API used on Windows does not support single quotes.
-  const std::string command_mysql_stop = get_path_to_mysql_executable("pg_ctl") + " -D " + Glib::shell_quote(dbdir_data) + " stop -m fast";
+  const std::string command_mysql_stop = get_mysqladmin_command("" /* m_password */)
+    + " shutdown";
   const bool result = Glom::Spawn::execute_command_line_and_wait(command_mysql_stop, slot_progress);
   if(!result)
   {
-    std::cerr << "Error while attempting to stop self-hosting of the database. Trying again."  << std::endl;
+    std::cerr << "Error while attempting to stop self-hosting of the MySQL database. Trying again."  << std::endl;
     
     //Show open connections for debugging:
     try
@@ -515,7 +424,7 @@ bool MySQLSelfHosted::cleanup(const SlotProgress& slot_progress)
     }
     catch(const Glib::Error& ex)
     {
-      std::cerr << G_STRFUNC << ": exception while trying to show active connections: " << ex.what() << std::endl;
+      std::cerr << G_STRFUNC << ": exception while trying to show active MySQL connections: " << ex.what() << std::endl;
     }
     
     //I've seen it fail when running under valgrind, and there are reports of failures in bug #420962.
@@ -541,27 +450,7 @@ bool MySQLSelfHosted::set_network_shared(const SlotProgress& /* slot_progress */
 
   m_network_shared = network_shared;
 
-  const std::string dbdir_uri = m_database_directory_uri;
-  const std::string dbdir = Glib::filename_from_uri(dbdir_uri);
-
-  const std::string dbdir_uri_config = dbdir_uri + "/config";
-  const char* default_conf_contents = 0;
-
-  // Choose the configuration contents based on 
-  // whether we want to be network-shared:
-  //const float mysqlql_version = get_mysqlql_utils_version_as_number(slot_progress);
-  //std::cout << "DEBUG: mysqlql_version=" << mysqlql_version << std::endl;
-
-  default_conf_contents = m_network_shared ? DEFAULT_CONFIG_PG_HBA_REMOTE : DEFAULT_CONFIG_PG_HBA_LOCAL;
-
-  //std::cout << "DEBUG: default_conf_contents=" << default_conf_contents << std::endl;
-
-  const bool hba_conf_creation_succeeded = create_text_file(dbdir_uri_config + "/pg_hba.conf", default_conf_contents);
-  g_assert(hba_conf_creation_succeeded);
-  if(!hba_conf_creation_succeeded)
-    return false;
-
-  return hba_conf_creation_succeeded;
+  return true;
 }
 
 static bool on_timeout_delay(const Glib::RefPtr<Glib::MainLoop>& mainloop)
diff --git a/glom/libglom/connectionpool_backends/mysql_self.h b/glom/libglom/connectionpool_backends/mysql_self.h
index 538a9b2..4216154 100644
--- a/glom/libglom/connectionpool_backends/mysql_self.h
+++ b/glom/libglom/connectionpool_backends/mysql_self.h
@@ -55,6 +55,8 @@ public:
   static bool install_mysql(const SlotProgress& slot_progress);
 
 private:
+  std::string get_mysqladmin_command(const Glib::ustring& password);
+
   virtual InitErrors initialize(const SlotProgress& slot_progress, const Glib::ustring& initial_username, const Glib::ustring& password, bool network_shared = false);
 
   virtual StartupErrors startup(const SlotProgress& slot_progress, bool network_shared = false);
@@ -86,6 +88,10 @@ private:
   //These are only remembered in order to use them to provide debug
   //information when the MySQL shutdown fails:
   Glib::ustring m_saved_database_name, m_saved_username, m_saved_password;
+
+  bool m_temporary_password_active; //Whether the password is an initial temporary one.
+  Glib::ustring m_initial_password_to_set;
+  Glib::ustring m_temporary_password;
 };
 
 } // namespace ConnectionPoolBackends
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 2718d26..9b394b4 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -58,6 +58,8 @@ static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE[] = "hosting_mode";
 static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_CENTRAL[] = "postgres_central";
 static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_SELF[] = "postgres_self";
 static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_SQLITE[] = "sqlite";
+static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_CENTRAL[] = "mysql_central";
+static const char GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_SELF[] = "mysql_self";
 static const char GLOM_ATTRIBUTE_CONNECTION_NETWORK_SHARED[] = "network_shared";
 static const char GLOM_ATTRIBUTE_CONNECTION_SERVER[] = "server";
 static const char GLOM_ATTRIBUTE_CONNECTION_PORT[] = "port";
@@ -341,8 +343,11 @@ bool Document::get_network_shared() const
 
   //Enforce constraints:
   const HostingMode hosting_mode = get_hosting_mode();
-  if(hosting_mode == HOSTING_MODE_POSTGRES_CENTRAL)
+  if( (hosting_mode == HOSTING_MODE_POSTGRES_CENTRAL) ||
+    (hosting_mode == HOSTING_MODE_MYSQL_CENTRAL) )
+  {
     shared = true; //Central hosting means that it must be shared on the network.
+  }
   else if(hosting_mode == HOSTING_MODE_SQLITE)
     shared = false; //sqlite does not allow network sharing.
 
@@ -378,6 +383,12 @@ std::string Document::get_connection_self_hosted_directory_uri() const
       case HOSTING_MODE_SQLITE:
         datadir = parent;
         break;
+      case HOSTING_MODE_MYSQL_SELF:
+        datadir = parent->get_child("glom_mysql_data");
+        break;
+      case HOSTING_MODE_MYSQL_CENTRAL:
+        datadir = parent;
+        break;
       default:
         g_assert_not_reached();
         break;
@@ -2547,6 +2558,10 @@ bool Document::load_after(int& failure_code)
             mode = HOSTING_MODE_POSTGRES_SELF;
           else if(attr_mode == GLOM_ATTRIBUTE_CONNECTION_HOSTING_SQLITE)
             mode = HOSTING_MODE_SQLITE;
+          else if(attr_mode == GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_CENTRAL)
+            mode = HOSTING_MODE_MYSQL_CENTRAL;
+          else if(attr_mode == GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_SELF)
+            mode = HOSTING_MODE_MYSQL_SELF;
           else
 	  {
             std::cerr << G_STRFUNC << ": Hosting mode " << attr_mode << " is not supported" << std::endl;
@@ -3570,13 +3585,24 @@ bool Document::save_before()
     switch(m_hosting_mode)
     {
     case HOSTING_MODE_POSTGRES_CENTRAL:
-      XmlUtils::set_node_attribute_value(nodeConnection, GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_CENTRAL);
+      XmlUtils::set_node_attribute_value(nodeConnection, 
+        GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_CENTRAL);
       break;
     case HOSTING_MODE_POSTGRES_SELF:
-      XmlUtils::set_node_attribute_value(nodeConnection, GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_SELF);
+      XmlUtils::set_node_attribute_value(nodeConnection,
+        GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_POSTGRES_SELF);
       break;
     case HOSTING_MODE_SQLITE:
-      XmlUtils::set_node_attribute_value(nodeConnection, GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_SQLITE);
+      XmlUtils::set_node_attribute_value(nodeConnection,
+        GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_SQLITE);
+      break;
+    case HOSTING_MODE_MYSQL_CENTRAL:
+      XmlUtils::set_node_attribute_value(nodeConnection, 
+        GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_CENTRAL);
+      break;
+    case HOSTING_MODE_MYSQL_SELF:
+      XmlUtils::set_node_attribute_value(nodeConnection,
+        GLOM_ATTRIBUTE_CONNECTION_HOSTING_MODE, GLOM_ATTRIBUTE_CONNECTION_HOSTING_MYSQL_SELF);
       break;
     default:
       g_assert_not_reached();
diff --git a/glom/libglom/document/document.h b/glom/libglom/document/document.h
index 58d5dfd..fd12fd6 100644
--- a/glom/libglom/document/document.h
+++ b/glom/libglom/document/document.h
@@ -106,9 +106,11 @@ public:
   /// How the database is hosted.
   enum HostingMode
   {
-    HOSTING_MODE_POSTGRES_CENTRAL, /*!< The database is hosted on an external postgresql server. */
-    HOSTING_MODE_POSTGRES_SELF, /*!< A new postgres database process is spawned that hosts the data. */
+    HOSTING_MODE_POSTGRES_CENTRAL, /*!< The database is hosted on an external PostgreSQL server. */
+    HOSTING_MODE_POSTGRES_SELF, /*!< A new PostgreSQL database process is spawned that hosts the data. */
     HOSTING_MODE_SQLITE, /*!< A sqlite database file is used. */
+    HOSTING_MODE_MYSQL_CENTRAL, /*!< The database is hosted on an external MySQL server. */
+    HOSTING_MODE_MYSQL_SELF,  /*!< A new MySQL database process is spawned that hosts the data. */
     HOSTING_MODE_DEFAULT = HOSTING_MODE_POSTGRES_SELF /*!- Arbitrary default. */
   };
 
diff --git a/glom/libglom/filelist.am b/glom/libglom/filelist.am
index 7488026..d4feee5 100644
--- a/glom/libglom/filelist.am
+++ b/glom/libglom/filelist.am
@@ -182,6 +182,8 @@ libglom_sources =							\
 	glom/libglom/python_embed/pygdavalue_conversions.h		\
 	glom/libglom/connectionpool_backends/mysql.cc			\
 	glom/libglom/connectionpool_backends/mysql.h			\
+	glom/libglom/connectionpool_backends/mysql_central.cc \
+	glom/libglom/connectionpool_backends/mysql_central.h \
 	glom/libglom/connectionpool_backends/sqlite.cc			\
 	glom/libglom/connectionpool_backends/sqlite.h			\
 	glom/libglom/connectionpool_backends/postgres.cc		\
diff --git a/tests/test_selfhosting_new_empty.cc b/tests/test_selfhosting_new_empty.cc
index 7c8c656..4f47086 100644
--- a/tests/test_selfhosting_new_empty.cc
+++ b/tests/test_selfhosting_new_empty.cc
@@ -71,6 +71,13 @@ int main()
     return EXIT_FAILURE;
   }
 
+  if(!test(Glom::Document::HOSTING_MODE_MYSQL_SELF))
+  {
+    std::cerr << "Failed with MySQL" << std::endl;
+    test_selfhosting_cleanup();
+    return EXIT_FAILURE;
+  }
+
   Glom::libglom_deinit();
 
   return EXIT_SUCCESS;
diff --git a/tests/test_selfhosting_utils.cc b/tests/test_selfhosting_utils.cc
index f40d338..b7fa45f 100644
--- a/tests/test_selfhosting_utils.cc
+++ b/tests/test_selfhosting_utils.cc
@@ -173,6 +173,7 @@ bool test_selfhost(Glom::Document& document, const Glib::ustring& user, const Gl
 bool test_create_and_selfhost_new_empty(Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path)
 {
   if( (hosting_mode != Glom::Document::HOSTING_MODE_POSTGRES_SELF) &&
+    (hosting_mode != Glom::Document::HOSTING_MODE_MYSQL_SELF) &&
     (hosting_mode != Glom::Document::HOSTING_MODE_SQLITE) )
   {
     std::cerr << G_STRFUNC << ": This test function does not support the specified hosting_mode: " << hosting_mode << std::endl;
@@ -323,6 +324,7 @@ bool test_create_and_selfhost_from_test_example(const std::string& example_filen
 bool test_create_and_selfhost_from_uri(const Glib::ustring& example_file_uri, Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path)
 {
   if( (hosting_mode != Glom::Document::HOSTING_MODE_POSTGRES_SELF) &&
+    (hosting_mode != Glom::Document::HOSTING_MODE_MYSQL_SELF) &&
     (hosting_mode != Glom::Document::HOSTING_MODE_SQLITE) )
   {
     std::cerr << G_STRFUNC << ": This test function does not support the specified hosting_mode: " << hosting_mode << std::endl;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]