[glom] In progress



commit 15f8a65e5ee7df019fcf1d4c48a369c3f77677ca
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Apr 30 23:16:17 2010 +0200

    In progress

 Makefile_glom.am                                   |    4 -
 Makefile_libglom.am                                |   11 +-
 Makefile_tests.am                                  |    8 +-
 glom/application.cc                                |  213 +--
 glom/application.h                                 |    5 +-
 glom/base_db.cc                                    | 1246 +---------------
 glom/base_db.h                                     |   58 +-
 glom/base_db_table_data.cc                         |    3 +-
 glom/frame_glom.cc                                 |   88 +-
 glom/import_csv/dialog_import_csv_progress.cc      |    3 +-
 glom/libglom/connectionpool.cc                     |   12 +-
 glom/libglom/connectionpool.h                      |    5 +
 glom/libglom/db_utils.cc                           | 1666 ++++++++++++++++++++
 glom/libglom/db_utils.h                            |   99 ++
 glom/{ => libglom}/glom_postgres.cc                |    1 +
 glom/{ => libglom}/glom_postgres.h                 |    7 +-
 glom/{glom_privs.cc => libglom/privs.cc}           |   24 +-
 glom/{glom_privs.h => libglom/privs.h}             |    4 +-
 glom/libglom/utils.cc                              |    1 -
 glom/main.cc                                       |    1 +
 glom/mode_data/box_data.cc                         |    2 +-
 glom/mode_data/box_data_details.cc                 |    7 +-
 glom/mode_data/box_data_list.cc                    |    5 +-
 glom/mode_data/box_data_list_related.cc            |    3 +-
 glom/mode_data/box_data_manyrecords.cc             |    2 +-
 glom/mode_design/dialog_add_related_table.cc       |    5 +-
 glom/mode_design/dialog_database_preferences.cc    |   19 +-
 glom/mode_design/fields/box_db_table_definition.cc |    7 +-
 glom/mode_design/users/dialog_groups_list.cc       |    5 +-
 glom/mode_design/users/dialog_users_list.cc        |    2 +-
 glom/navigation/box_tables.cc                      |    7 +-
 glom/utility_widgets/db_adddel/db_adddel.cc        |    3 +-
 po/POTFILES.in                                     |    1 +
 .../test_selfhosting_new_empty.cc                  |   45 +-
 .../test_selfhosting_new_from_example.cc           |  208 +++
 35 files changed, 2145 insertions(+), 1635 deletions(-)
---
diff --git a/Makefile_glom.am b/Makefile_glom.am
index cb2ab37..bc5c1da 100644
--- a/Makefile_glom.am
+++ b/Makefile_glom.am
@@ -44,10 +44,6 @@ glom_source_files = \
 	glom/frame_glom.h						\
 	glom/glade_utils.cc						\
 	glom/glade_utils.h						\
-	glom/glom_postgres.cc						\
-	glom/glom_postgres.h						\
-	glom/glom_privs.cc						\
-	glom/glom_privs.h						\
 	glom/notebook_glom.cc						\
 	glom/notebook_glom.h						\
 	glom/signal_reemitter.h						\
diff --git a/Makefile_libglom.am b/Makefile_libglom.am
index f00c65b..a1a4524 100644
--- a/Makefile_libglom.am
+++ b/Makefile_libglom.am
@@ -21,8 +21,9 @@ libglom_include_HEADERS =			\
 	glom/libglom/init.h			\
 	glom/libglom/libglom_config.h		\
 	glom/libglom/sharedptr.h		\
-	glom/libglom/standard_table_prefs_fields.h\
-	glom/libglom/utils.h
+	glom/libglom/standard_table_prefs_fields.h \
+	glom/libglom/utils.h \
+	glom/libglom/db_utils.h
 
 libglom_data_structure_includedir = $(libglom_includedir)/data_structure
 libglom_data_structure_include_HEADERS =			\
@@ -91,9 +92,15 @@ glom_libglom_libglom_1_14_la_SOURCES =					\
 	glom/libglom/calcinprogress.h					\
 	glom/libglom/connectionpool.cc					\
 	glom/libglom/connectionpool.h					\
+	glom/libglom/db_utils.cc						\
+	glom/libglom/db_utils.h					\
+	glom/libglom/glom_postgres.cc						\
+	glom/libglom/glom_postgres.h						\
 	glom/libglom/gst-package.c					\
 	glom/libglom/gst-package.h					\
 	glom/libglom/init.cc						\
+	glom/libglom/privs.cc						\
+	glom/libglom/privs.h						\
 	glom/libglom/spawn_with_feedback.cc				\
 	glom/libglom/spawn_with_feedback.h				\
 	glom/libglom/utils.cc						\
diff --git a/Makefile_tests.am b/Makefile_tests.am
index d393142..d4f2822 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -33,7 +33,8 @@ check_PROGRAMS =						\
 	tests/import/test_signals \
 	tests/test_glade_derived_instantiation \
 	tests/glade_toplevels_instantiation \
-	tests/test_selfhosting_new_empty/test_selfhosting_new_empty
+	tests/test_selfhosting_new_empty/test_selfhosting_new_empty \
+	tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example
 
 TESTS =	tests/test_document_load/test_document_load	\
 	tests/test_parsing_time	\
@@ -47,7 +48,8 @@ TESTS =	tests/test_document_load/test_document_load	\
 	tests/test_python_execute_func \
 	tests/test_python_execute_func_date \
 	tests/test_python_execute_script \
-	tests/test_selfhosting_new_empty/test_selfhosting_new_empty
+	tests/test_selfhosting_new_empty/test_selfhosting_new_empty \
+	tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example
 	
 # These hang most of the time, but not always:
 #	tests/import/test_parsing \
@@ -94,6 +96,7 @@ tests_import_test_signals_SOURCES =	\
 	tests/import/test_signals.cc
 tests_test_glade_derived_instantiation_SOURCES = tests/test_glade_derived_instantiation.cc $(glom_source_files)
 tests_test_selfhosting_new_empty_test_selfhosting_new_empty_SOURCES = tests/test_selfhosting_new_empty/test_selfhosting_new_empty.cc $(glom_source_files)
+tests_test_selfhosting_new_from_example_test_selfhosting_new_from_example_SOURCES = tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example.cc $(glom_source_files)
 
 glom_libglom_test_connectionpool_LDADD = $(tests_ldadd)
 glom_libglom_example_document_load_LDADD = $(tests_ldadd)
@@ -139,3 +142,4 @@ tests_import_test_parsing_LDADD = $(LIBGLOM_LIBS) $(GLOM_LIBS)
 tests_import_test_signals_LDADD = $(LIBGLOM_LIBS) $(GLOM_LIBS)
 tests_test_glade_derived_instantiation_LDADD = $(glom_all_libs)
 tests_test_selfhosting_new_empty_test_selfhosting_new_empty_LDADD = $(glom_all_libs)
+tests_test_selfhosting_new_from_example_test_selfhosting_new_from_example_LDADD = $(glom_all_libs)
diff --git a/glom/application.cc b/glom/application.cc
index e9b4e30..f75b5d9 100644
--- a/glom/application.cc
+++ b/glom/application.cc
@@ -29,11 +29,13 @@
 #include <glom/mode_design/translation/dialog_change_language.h>
 #include <glom/mode_design/translation/window_translations.h>
 #include <glom/utility_widgets/filechooserdialog_saveextras.h>
+#include <glom/glade_utils.h>
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
 #include <glom/utils_ui.h>
 #include <glom/glade_utils.h>
-#include <glom/glom_privs.h>
+#include <libglom/db_utils.h>
+#include <libglom/privs.h>
 #include <glom/python_embed/python_ui_callbacks.h>
 #include <glom/python_embed/glom_python.h>
 
@@ -89,6 +91,7 @@ Application::Application(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builde
   m_ui_save_extra_showextras(false),
   m_ui_save_extra_newdb_hosting_mode(Document::HOSTING_MODE_DEFAULT),
   m_avahi_progress_dialog(0),
+  m_dialog_progress_creating(0),
 #endif // !GLOM_ENABLE_CLIENT_ONLY
   m_show_sql_debug(false)
 {
@@ -130,6 +133,12 @@ Application::~Application()
     delete m_avahi_progress_dialog;
     m_avahi_progress_dialog = 0;
   }
+
+  if(m_dialog_progress_creating)
+  {
+    delete m_dialog_progress_creating;
+    m_dialog_progress_creating = 0;
+  }
   #endif // !GLOM_ENABLE_CLIENT_ONLY
 
   #ifdef GLOM_ENABLE_MAEMO
@@ -1179,24 +1188,14 @@ bool Application::on_document_load()
       {
         //Create the example database:
         //connection_request_password_and_choose_new_database_name() has already change the database name to a new unused one:
-        bool user_cancelled = false;
-        const bool test = recreate_database(user_cancelled);
+        const bool test = recreate_database();
         if(!test)
         {
           // TODO: Do we need to call connection_pool->cleanup() here, for
           // stopping self-hosted databases? armin.
           connection_pool->cleanup( sigc::mem_fun(*this, &Application::on_connection_close_progress) );
           //If the database was not successfully recreated:
-          if(!user_cancelled)
-          {
-            //Let the user try again.
-            //A warning has already been shown.
-            //TODO: No, I don't think there is a warning.
-            std::cerr << "Application::on_document_load(): recreate_database() failed." << std::endl;
-            return offer_new_or_existing();
-          }
-          else
-            return false;
+          return false;
         }
         else
         {
@@ -1583,181 +1582,49 @@ void Application::on_menu_help_contents()
 #endif //GLOM_ENABLE_MAEMO
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-bool Application::recreate_database(bool& user_cancelled)
+void Application::on_recreate_database_progress()
 {
-  //Create a database, based on the information in the current document:
-  Document* pDocument = static_cast<Document*>(get_document());
-  if(!pDocument)
-    return false;
-
-  ConnectionPool* connection_pool = ConnectionPool::get_instance();
-  if(!connection_pool)
-    return false; //Impossible anyway.
-
-  //Check whether the database exists already.
-  const Glib::ustring db_name = pDocument->get_connection_database();
-  if(db_name.empty())
-    return false;
-
-  connection_pool->set_database(db_name);
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-#else
-  std::auto_ptr<std::exception> error;
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-  {
-    connection_pool->set_ready_to_connect(); //This has succeeded already.
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    sharedptr<SharedConnection> sharedconnection = connection_pool->connect();
-#else
-    sharedptr<SharedConnection> sharedconnection = connection_pool->connect(error);
-    if(!error.get())
-    {
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-      g_warning("Application::recreate_database(): Failed because database exists already.");
-
-      return false; //Connection to the database succeeded, because no exception was thrown. so the database exists already.
-#ifndef GLIBMM_EXCEPTIONS_ENABLED
-    }
-#endif // !GLIBMM_EXCEPTIONS_ENABLED
-  }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  catch(const ExceptionConnection& ex)
-  {
-#else
-  if(error.get())
-  {
-    const ExceptionConnection* exptr = dynamic_cast<ExceptionConnection*>(error.get());
-    if(exptr)
-    {
-      const ExceptionConnection& ex = *exptr;
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-      if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
-      {
-        user_cancelled = true; //Eventually, the user will cancel after retrying.
-        g_warning("Application::recreate_database(): Failed because connection to server failed, without specifying a database.");
-        return false;
-      }
-#ifndef GLIBMM_EXCEPTIONS_ENABLED
-    }
-#endif // !GLIBMM_EXCEPTIONS_ENABLED
-
-    //Otherwise continue, because we _expected_ connect() to fail if the db does not exist yet.
-  }
-
   //Show the user that something is happening, because the INSERTS might take time.
   //TOOD: This doesn't actually show up until near the end, even with Gtk::Main::instance()->iteration().
-  Dialog_ProgressCreating* dialog_progress_temp = 0;
-  Utils::get_glade_widget_derived_with_warning(dialog_progress_temp);
-  dialog_progress_temp->set_message(_("Creating Glom Database"), _("Creating Glom database from example file."));
-  std::auto_ptr<Dialog_ProgressCreating> dialog_progress(dialog_progress_temp); //Put the dialog in an auto_ptr so that it will be deleted (and hidden) when the current function returns.
+  if(!m_dialog_progress_creating)
+  {
+    Utils::get_glade_widget_derived_with_warning(m_dialog_progress_creating);
 
-  dialog_progress->set_transient_for(*this);
-  dialog_progress->show();
+    m_dialog_progress_creating->set_message(_("Creating Glom Database"), _("Creating Glom database from example file."));
+  
+    m_dialog_progress_creating->set_transient_for(*this);
+    m_dialog_progress_creating->show();
+  
+  }
 
   //Ensure that the dialog is shown, instead of waiting for the application to be idle:
   while(Gtk::Main::instance()->events_pending())
     Gtk::Main::instance()->iteration();
 
-  dialog_progress->pulse();
-
-  //Create the database: (This will show a connection dialog)
-  connection_pool->set_database( Glib::ustring() );
-  const bool db_created = m_pFrame->create_database(db_name, pDocument->get_database_title());
-
-  if(!db_created)
-  {
-    return false;
-  }
-  else
-    connection_pool->set_database(db_name); //Specify the new database when connecting from now on.
-
-  dialog_progress->pulse();
-  BusyCursor busy_cursor(this);
+  m_dialog_progress_creating->pulse();
+}
 
-  sharedptr<SharedConnection> sharedconnection;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-  {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    sharedconnection = connection_pool->connect();
-#else
-    sharedconnection = connection_pool->connect(error);
-    if(!error.get())
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-      connection_pool->set_database(db_name); //The database was successfully created, so specify it when connecting from now on.
-  }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  catch(const ExceptionConnection& ex)
-  {
-#else
-  if(error.get())
-  {
-    const std::exception& ex = *error.get();
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-    g_warning("Application::recreate_database(): Failed to connect to the newly-created database.");
+bool Application::recreate_database()
+{
+  //Create a database, based on the information in the current document:
+  Document* pDocument = static_cast<Document*>(get_document());
+  if(!pDocument)
     return false;
-  }
 
-  dialog_progress->pulse();
+  Gtk::Window* pWindowApp = get_application();
+  g_assert(pWindowApp);
+  BusyCursor busycursor(*pWindowApp);
 
-  //Create each table:
-  Document::type_listTableInfo tables = pDocument->get_tables();
-  for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
+  const bool result = DbUtils::recreate_database_from_document(pDocument, 
+    sigc::mem_fun(*this, &Application::on_recreate_database_progress));
+  
+  if(m_dialog_progress_creating)
   {
-    sharedptr<const TableInfo> table_info = *iter;
-
-    //Create SQL to describe all fields in this table:
-    Glib::ustring sql_fields;
-    Document::type_vec_fields fields = pDocument->get_table_fields(table_info->get_name());
-
-    dialog_progress->pulse();
-    const bool table_creation_succeeded = m_pFrame->create_table(table_info, fields);
-    dialog_progress->pulse();
-    if(!table_creation_succeeded)
-    {
-      g_warning("Application::recreate_database(): CREATE TABLE failed with the newly-created database.");
-      return false;
-    }
+    delete m_dialog_progress_creating;
+    m_dialog_progress_creating = 0;
   }
-
-  dialog_progress->pulse();
-  m_pFrame->add_standard_tables(); //Add internal, hidden, tables.
-
-  //Create the developer group, and make this user a member of it:
-  //If we got this far then the user must really have developer privileges already:
-  dialog_progress->pulse();
-  const bool test = m_pFrame->add_standard_groups();
-  if(!test)
-    return false;
-
-  for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
-  {
-    sharedptr<const TableInfo> table_info = *iter;
-
-    //Add any example data to the table:
-    dialog_progress->pulse();
-
-    //try
-    //{
-      const bool table_insert_succeeded = m_pFrame->insert_example_data(table_info->get_name());
-
-      if(!table_insert_succeeded)
-      {
-        g_warning("Application::recreate_database(): INSERT of example data failed with the newly-created database.");
-        return false;
-      }
-    //}
-    //catch(const std::exception& ex)
-    //{
-    //  std::cerr << "Application::recreate_database(): exception: " << ex.what() << std::endl;
-      //HandleError(ex);
-    //}
-
-  } //for(tables)
-
-  return true; //All tables created successfully.
+ 
+  return result; //All tables created successfully.
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
diff --git a/glom/application.h b/glom/application.h
index 332f0b9..faaddaa 100644
--- a/glom/application.h
+++ b/glom/application.h
@@ -178,7 +178,8 @@ private:
 
   Document* on_connection_pool_get_document();
 
-  bool recreate_database(bool& user_cancelled); //return indicates success.
+  bool recreate_database(); //return indicates success.
+  void on_recreate_database_progress();
   void stop_self_hosting_of_document_database();
 
   void on_connection_avahi_begin();
@@ -256,6 +257,8 @@ private:
   Document::HostingMode m_ui_save_extra_newdb_hosting_mode;
 
   Gtk::MessageDialog* m_avahi_progress_dialog;
+
+  Dialog_ProgressCreating* m_dialog_progress_creating;
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
   // This is set to the URI of an example file that is loaded to be able to
diff --git a/glom/base_db.cc b/glom/base_db.cc
index 3aa2a32..8d93b4d 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -46,8 +46,8 @@
 #include <libglom/data_structure/layout/report_parts/layoutitem_header.h>
 #include <libglom/data_structure/layout/report_parts/layoutitem_footer.h>
 #include <glom/python_embed/glom_python.h>
-#include <glom/glom_postgres.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
+#include <libglom/db_utils.h>
 #include <glibmm/i18n.h>
 //#include <libgnomeui/gnome-app-helper.h>
 
@@ -231,7 +231,7 @@ Glib::RefPtr<Gnome::Gda::DataModel> Base_DB::query_execute_select(const Glib::us
 #endif
   }
 
-
+  //TODO: Use DbUtils::query_execute().
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
   try
   {
@@ -287,6 +287,7 @@ bool Base_DB::query_execute(const Glib::ustring& strQuery,
     return false;
   }
 
+  //TODO: Use DbUtils::query_execute().
   Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
   Glib::RefPtr<Gnome::Gda::SqlParser> parser = gda_connection->create_parser();
   Glib::RefPtr<Gnome::Gda::Statement> stmt;
@@ -376,132 +377,6 @@ void Base_DB::load_from_document()
   }
 }
 
-bool Base_DB::get_table_exists_in_database(const Glib::ustring& table_name) const
-{
-  //TODO_Performance
-
-  type_vec_strings tables = get_table_names_from_database();
-  type_vec_strings::const_iterator iterFind = std::find(tables.begin(), tables.end(), table_name);
-  return (iterFind != tables.end());
-}
-
-namespace { //anonymous
-
-//If the string has quotes around it, remove them
-static Glib::ustring remove_quotes(const Glib::ustring& str)
-{
-  const gchar* quote = "\"";
-  const Glib::ustring::size_type posQuoteStart = str.find(quote);
-  if(posQuoteStart != 0)
-    return str;
-
-  const Glib::ustring::size_type size = str.size();
-  const Glib::ustring::size_type posQuoteEnd = str.find(quote, 1);
-  if(posQuoteEnd != (size - 1))
-    return str;
-
-  return str.substr(1, size - 2);
-}
-
-} //anonymous namespace
-
-//TODO_Performance: Avoid calling this so often.
-//TODO: Put this in libgdamm.
-Base_DB::type_vec_strings Base_DB::get_table_names_from_database(bool ignore_system_tables) const
-{
-  type_vec_strings result;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection = connect_to_server();
-#else
-  std::auto_ptr<ExceptionConnection> error;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-  // TODO: Rethrow?
-#endif
-  if(sharedconnection)
-  {
-    Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
-
-    Glib::RefPtr<Gnome::Gda::DataModel> data_model_tables;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    try
-    {
-      data_model_tables = gda_connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_TABLES);
-    }
-    catch(const Gnome::Gda::MetaStoreError& ex)
-    {
-      std::cerr << "Base_DB::get_table_names_from_database(): MetaStoreError: " << ex.what() << std::endl;
-    }
-    catch(const Glib::Error& ex)
-    {
-      std::cerr << "Base_DB::get_table_names_from_database(): Error: " << ex.what() << std::endl;
-    }
-#else
-    std::auto_ptr<Glib::Error> error;
-    data_model_tables = gda_connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_TABLES, error);
-    // Ignore error, data_model_tables presence is checked below
-#endif
-
-    if(data_model_tables && (data_model_tables->get_n_columns() == 0))
-    {
-      std::cerr << "Base_DB::get_table_names_from_database(): libgda reported 0 tables for the database." << std::endl;
-    }
-    else if(data_model_tables)
-    {
-      //std::cout << "debug: data_model_tables refcount=" << G_OBJECT(data_model_tables->gobj())->ref_count << std::endl;
-      const int rows = data_model_tables->get_n_rows();
-      for(int i = 0; i < rows; ++i)
-      {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-        const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i);
-#else
-        const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i, error);
-#endif
-        //Get the table name:
-        Glib::ustring table_name;
-        if(G_VALUE_TYPE(value.gobj()) ==  G_TYPE_STRING)
-        {
-          table_name = value.get_string();
-
-          //The table names have quotes sometimes. See http://bugzilla.gnome.org/show_bug.cgi?id=593154
-          table_name = remove_quotes(table_name);
-
-          //TODO: Unescape the string with gda_server_provider_unescape_string()?
-
-          //std::cout << "DEBUG: Found table: " << table_name << std::endl;
-
-          if(ignore_system_tables)
-          {
-            //Check whether it's a system table:
-            const Glib::ustring prefix = "glom_system_";
-            const Glib::ustring table_prefix = table_name.substr(0, prefix.size());
-            if(table_prefix == prefix)
-              continue;
-          }
-
-          //Ignore the pga_* tables that pgadmin adds when you use it:
-          if(table_name.substr(0, 4) == "pga_")
-            continue;
-
-          //Ignore the pg_* tables that something (Postgres? libgda?) adds:
-          //Not needed now that this was fixed again in libgda-4.0.
-          //if(table_name.substr(0, 14) == "pg_catalog.pg_")
-          //  continue;
-
-          //Ignore the information_schema tables that something (libgda?) adds:
-          //Not needed now that this was fixed again in libgda-4.0.
-          //if(table_name.substr(0, 23) == "information_schema.sql_")
-          //  continue;
-
-          result.push_back(table_name);
-        }
-      }
-    }
-  }
-
-  return result;
-}
-
-
 AppState::userlevels Base_DB::get_userlevel() const
 {
   const Document* document = dynamic_cast<const Document*>(get_document());
@@ -564,264 +439,11 @@ Base_DB::type_vec_strings Base_DB::util_vecStrings_from_Fields(const type_vec_fi
   return vecNames;
 }
 
-static bool meta_table_column_is_primary_key(GdaMetaTable* meta_table, const Glib::ustring column_name)
-{
-  if(!meta_table)
-    return false;
-
-  for(GSList* item = meta_table->columns; item != 0; item = item->next)
-  {
-    GdaMetaTableColumn* column = GDA_META_TABLE_COLUMN(item->data);
-    if(!column)
-      continue;
-
-    if(column->column_name && (column_name == remove_quotes(column->column_name)))
-      return column->pkey;
-  }
-
-  return false;
-}
-
-bool Base_DB::get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name)
-{
-  type_vec_fields vecFields = get_fields_for_table_from_database(table_name);
-  type_vec_fields::const_iterator iterFind = std::find_if(vecFields.begin(), vecFields.end(), predicate_FieldHasName<Field>(field_name));
-  return iterFind != vecFields.end();
-}
-
-Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib::ustring& table_name, bool /* including_system_fields */)
-{
-  type_vec_fields result;
-
-  if(table_name.empty())
-    return result;
-
-  // These are documented here:
-  // http://library.gnome.org/devel/libgda-4.0/3.99/connection.html#GdaConnectionMetaTypeHead
-  enum GlomGdaDataModelFieldColumns
-  {
-    DATAMODEL_FIELDS_COL_NAME = 0,
-    DATAMODEL_FIELDS_COL_TYPE = 1,
-    DATAMODEL_FIELDS_COL_GTYPE = 2,
-    DATAMODEL_FIELDS_COL_SIZE = 3,
-    DATAMODEL_FIELDS_COL_SCALE = 4,
-    DATAMODEL_FIELDS_COL_NOTNULL = 5,
-    DATAMODEL_FIELDS_COL_DEFAULTVALUE = 6,
-    DATAMODEL_FIELDS_COL_EXTRA = 6 // Could be auto-increment
-  };
-
-  //TODO: BusyCursor busy_cursor(get_application());
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection = connect_to_server();
-#else
-  std::auto_ptr<ExceptionConnection> error;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-  // TODO: Rethrow?
-#endif
-
-  if(!sharedconnection)
-  {
-    g_warning("Base_DB::get_fields_for_table_from_database(): connection failed.");
-  }
-  else
-  {
-    Glib::RefPtr<Gnome::Gda::Connection> connection = sharedconnection->get_gda_connection();
-
-    Glib::RefPtr<Gnome::Gda::Holder> holder_table_name = Gnome::Gda::Holder::create(G_TYPE_STRING, "name");
-    gchar* quoted_table_name_c = gda_meta_store_sql_identifier_quote(table_name.c_str(), connection->gobj());
-    g_assert(quoted_table_name_c);
-    Glib::ustring quoted_table_name(quoted_table_name_c);
-    g_free (quoted_table_name_c);
-    quoted_table_name_c = 0;
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    holder_table_name->set_value(quoted_table_name);
-#else
-    std::auto_ptr<Glib::Error> error;
-    holder_table_name->set_value(quoted_table_name, error);
-#endif
-
-    std::list< Glib::RefPtr<Gnome::Gda::Holder> > holder_list;
-    holder_list.push_back(holder_table_name);
-
-    Glib::RefPtr<Gnome::Gda::DataModel> data_model_fields;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    try
-    {
-      data_model_fields = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list);
-    }
-    catch(const Gnome::Gda::MetaStoreError& ex)
-    {
-      std::cerr << "Base_DB::get_fields_for_table_from_database(): MetaStoreError: " << ex.what() << std::endl;
-    }
-    catch(const Glib::Error& ex)
-    {
-      std::cerr << "Base_DB::get_fields_for_table_from_database(): Error: " << ex.what() << std::endl;
-    }
-#else
-    data_model_fields = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list, error);
-
-    // Ignore error, data_model_fields presence is checked below
-#endif
-
-
-    if(!data_model_fields)
-    {
-      std::cerr << "Base_DB::get_fields_for_table_from_database(): libgda reported empty fields schema data_model for the table." << std::endl;
-    }
-    else if(data_model_fields->get_n_columns() == 0)
-    {
-      std::cerr << "Base_DB::get_fields_for_table_from_database(): libgda reported 0 fields for the table." << std::endl;
-    }
-    else if(data_model_fields->get_n_rows() == 0)
-    {
-      g_warning("Base_DB::get_fields_for_table_from_database(): table_name=%s, data_model_fields->get_n_rows() == 0: The table probably does not exist in the specified database.", table_name.c_str());
-    }
-    else
-    {
-      //We also use the GdaMetaTable to discover primary keys.
-      //Both these libgda APIs are awful, and it's awful that we must use two APIs. murrayc.
-      Glib::RefPtr<Gnome::Gda::MetaStore> store = connection->get_meta_store();
-      Glib::RefPtr<Gnome::Gda::MetaStruct> metastruct =
-        Gnome::Gda::MetaStruct::create(store, Gnome::Gda::META_STRUCT_FEATURE_NONE);
-      GdaMetaDbObject* meta_dbobject = 0;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-      try
-      {
-        meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
-          Gnome::Gda::Value(), /* catalog */
-          Gnome::Gda::Value(), /* schema */
-          Gnome::Gda::Value(quoted_table_name)); //It's a static instance inside the MetaStore.
-      }
-      catch(const Glib::Error& ex)
-      {
-        handle_error(ex);
-        //TODO: Really fail.
-      }
-#else
-      std::auto_ptr<Glib::Error> ex;
-      meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
-        Gnome::Gda::Value(), /* catalog */
-        Gnome::Gda::Value(), /* schema */
-        Gnome::Gda::Value(quoted_table_name), ex); //It's a static instance inside the MetaStore.
-       if(error.get())
-       {
-         handle_error(*ex);
-       }
-#endif //GLIBMM_EXCEPTIONS_ENABLED
-      GdaMetaTable* meta_table = GDA_META_TABLE(meta_dbobject);
-
-      //Examine each field:
-      guint row = 0;
-      const guint rows_count = data_model_fields->get_n_rows();
-      while(row < rows_count)
-      {
-        Glib::RefPtr<Gnome::Gda::Column> field_info = Gnome::Gda::Column::create();
-
-        //Get the field name:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED //TODO: Actually catch exceptions.
-        Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row);
-#else
-        std::auto_ptr<Glib::Error> value_error;
-        Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row, value_error);
-#endif
-        if(value_name.get_value_type() ==  G_TYPE_STRING)
-        {
-          if(value_name.get_string().empty())
-            g_warning("Base_DB::get_fields_for_table_from_database(): value_name is empty.");
-
-          Glib::ustring field_name = value_name.get_string(); //TODO: get_string() is a dodgy choice. murrayc.
-          field_name = remove_quotes(field_name);
-          field_info->set_name(field_name);
-          //std::cout << "  debug: field_name=" << field_name << std::endl;
-        }
-
-        //Get the field type:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-        Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row);
-#else
-        Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row, value_error);
-#endif
-        if(value_fieldtype.get_value_type() ==  G_TYPE_STRING)
-        {
-          const Glib::ustring type_string = value_fieldtype.get_string();
-          const GType gdatype = gda_g_type_from_string(type_string.c_str());
-          field_info->set_g_type(gdatype);
-        }
-
-
-        //Get the default value:
-        /* libgda does not return this correctly yet. TODO: check bug http://bugzilla.gnome.org/show_bug.cgi?id=143576
-        Gnome::Gda::Value value_defaultvalue = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_DEFAULTVALUE, row);
-        if(value_defaultG_VALUE_TYPE(value.gobj()) ==  G_TYPE_STRING)
-          field_info->set_default_value(value_defaultvalue);
-        */
-
-        //Get whether it can be null:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-        Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row);
-#else
-        Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row, value_error);
-#endif
-        if(value_notnull.get_value_type() ==  G_TYPE_BOOLEAN)
-          field_info->set_allow_null(value_notnull.get_boolean());
-
-
-        sharedptr<Field> field = sharedptr<Field>::create(); //TODO: Get glom-specific information from the document?
-        field->set_field_info(field_info);
-
-
-        //Get whether it is a primary key:
-        field->set_primary_key(
-          meta_table_column_is_primary_key(meta_table, field_info->get_name()) );
-
-
-#if 0 // This was with libgda-3.0:
-        Gnome::Gda::Value value_primarykey = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_PRIMARYKEY, row);
-        if(value_primarykey.get_value_type() ==  G_TYPE_BOOLEAN)
-          field_info->set_primary_key( value_primarykey.get_boolean() );
-
-        //Get whether it is unique
-        Gnome::Gda::Value value_unique = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_UNIQUEINDEX, row);
-        if(value_unique.get_value_type() ==  G_TYPE_BOOLEAN)
-          ;//TODO_gda:field_info->set_unique_key( value_unique.get_boolean() );
-        //TODO_gda:else if(field_info->get_primary_key()) //All primaries keys are unique, so force this.
-          //TODO_gda:field_info->set_unique_key();
-
-        //Get whether it is autoincrements
-        /* libgda does not provide this yet.
-        Gnome::Gda::Value value_autoincrement = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_AUTOINCREMENT, row);
-        if(value_autoincrement.get_value_type() ==  G_TYPE_BOOLEAN)
-          field_info->set_auto_increment( value_autoincrement.get_bool() );
-        */
-#endif
-
-
-        result.push_back(field);
-
-        ++row;
-      }
-    }
-  }
-
-  if(result.empty())
-  {
-    //g_warning("Base_DB::get_fields_for_table_from_database(): returning empty result.");
-  }
-
-  //Hide system fields.
-  type_vec_fields::iterator iterFind = std::find_if(result.begin(), result.end(), predicate_FieldHasName<Field>(GLOM_STANDARD_FIELD_LOCK));
-  if(iterFind != result.end())
-    result.erase(iterFind);
-
-  return result;
-}
 
 Base_DB::type_vec_fields Base_DB::get_fields_for_table(const Glib::ustring& table_name, bool including_system_fields) const
 {
   //Get field definitions from the database:
-  type_vec_fields fieldsDatabase = get_fields_for_table_from_database(table_name, including_system_fields);
+  type_vec_fields fieldsDatabase = DbUtils::get_fields_for_table_from_database(table_name, including_system_fields);
 
   const Document* pDoc = dynamic_cast<const Document*>(get_document());
   if(!pDoc)
@@ -881,689 +503,8 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table(const Glib::ustring& tabl
   }
 }
 
-Gnome::Gda::Value Base_DB::auto_increment_insert_first_if_necessary(const Glib::ustring& table_name, const Glib::ustring& field_name) const
-{
-  Gnome::Gda::Value value;
-
-  //Check that the user is allowd to view and edit this table:
-  Privileges table_privs = Privs::get_current_privs(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
-  if(!table_privs.m_view || !table_privs.m_edit)
-  {
-    //This should not happen:
-    std::cerr << "Glom: Base_DB::auto_increment_insert_first_if_necessary(): The current user may not edit the autoincrements table. Any user who has create rights for a table should have edit rights to the autoincrements table." << std::endl;
-  }
-  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
-  params->add_holder("table_name", table_name);
-  params->add_holder("field_name", field_name);
-
-  const Glib::ustring sql_query = "SELECT \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\".\"next_value\" FROM \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\""
-   " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = ##table_name::gchararray AND "
-          "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = ##field_name::gchararray";
-
-  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query, params);
-  if(!datamodel || (datamodel->get_n_rows() == 0))
-  {
-    //Start with zero:
-
-    //Insert the row if it's not there.
-    const Glib::ustring sql_query = "INSERT INTO \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" ("
-      GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME ", " GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME ", " GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE
-      ") VALUES (##table_name::gchararray, ##field_name::gchararray, 0)";
-
-    const bool test = query_execute(sql_query, params);
-    if(!test)
-      std::cerr << "Base_DB::auto_increment_insert_first_if_necessary(): INSERT of new row failed." << std::endl;
-
-    //GdaNumeric is a pain, so we take a short-cut:
-    bool success = false;
-    value = Conversions::parse_value(Field::TYPE_NUMERIC, "0", success, true /* iso_format */);
-  }
-  else
-  {
-    //Return the value so that a calling function does not need to do a second SELECT.
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0);
-#else
-    std::auto_ptr<Glib::Error> value_error;
-    const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0, value_error);
-#endif
-    //But the caller wants a numeric value not a text value
-    //(our system_autoincrements table has it as text, for future flexibility):
-    const std::string actual_value_text = actual_value.get_string();
-    bool success = false;
-    value = Conversions::parse_value(Field::TYPE_NUMERIC, actual_value_text, success, true /* iso_format */);
-  }
-
-  //std::cout << "Base_DB::auto_increment_insert_first_if_necessary: returning value of type=" << value.get_value_type() << std::endl;
-  return value;
-}
-
-void Base_DB::recalculate_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name) const
-{
-  //Make sure that the row exists in the glom system table:
-  auto_increment_insert_first_if_necessary(table_name, field_name);
-
-  //Get the max key value in the database:
-  const Glib::ustring sql_query = "SELECT MAX(\"" + table_name + "\".\"" + field_name + "\") FROM \"" + table_name + "\"";
-  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
-  if(datamodel && datamodel->get_n_rows() && datamodel->get_n_columns())
-  {
-    //Increment it:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0); // A GdaNumeric.
-#else
-    std::auto_ptr<Glib::Error> error;
-    const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0, error); // A GdaNumeric.
-#endif
-    double num_max = Conversions::get_double_for_gda_value_numeric(value_max);
-    ++num_max;
-
-    //Set it in the glom system table:
-    const Gnome::Gda::Value next_value = Conversions::parse_value(num_max);
-    const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" SET "
-      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE "\" = " + next_value.to_string() + //TODO: Don't use to_string().
-      " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = '" + table_name + "' AND "
-      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = '" + field_name + "'";
-
-    const bool test = query_execute(sql_query);
-    if(!test)
-      std::cerr << "Base_DB::recalculate_next_auto_increment_value(): UPDATE failed." << std::endl;
-  }
-  else
-    std::cerr << "Base_DB::recalculate_next_auto_increment_value(): SELECT MAX() failed." << std::endl;
-}
-
-Gnome::Gda::Value Base_DB::get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name) const
-{
-  const Gnome::Gda::Value result = auto_increment_insert_first_if_necessary(table_name, field_name);
-  double num_result = Conversions::get_double_for_gda_value_numeric(result);
-
-
-  //Increment the next_value:
-  ++num_result;
-  const Gnome::Gda::Value next_value = Conversions::parse_value(num_result);
-  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
-  params->add_holder("table_name", table_name);
-  params->add_holder("field_name", field_name);
-  params->add_holder("next_value", next_value);
-  const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" SET "
-      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE "\" = ##next_value::gchararray"
-      " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = ##table_name::gchararray AND "
-            "\""  GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = ##field_name::gchararray";
-
-  const bool test = query_execute(sql_query, params);
-  if(!test)
-    std::cerr << "Base_DB::get_next_auto_increment_value(): Increment failed." << std::endl;
-
-  return result;
-}
-
-SystemPrefs Base_DB::get_database_preferences() const
-{
-  //if(get_userlevel() == AppState::USERLEVEL_DEVELOPER)
-  //  add_standard_tables();
-
-  SystemPrefs result;
-
-  //Check that the user is allowed to even view this table:
-  Privileges table_privs = Privs::get_current_privs(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
-  if(!table_privs.m_view)
-    return result;
-
-  const bool optional_org_logo = get_field_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME, GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO);
-
-  const Glib::ustring sql_query = "SELECT "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_NAME "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2 "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY "\", "
-      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE "\""
-      + Glib::ustring(optional_org_logo ? ", \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO "\"" : "") +
-      " FROM \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\"";
-
-  int attempts = 0;
-  while(attempts < 2)
-  {
-    bool succeeded = true;
-    #ifdef GLIBMM_EXCEPTIONS_ENABLED
-    try
-    {
-      Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
-      if(datamodel && (datamodel->get_n_rows() != 0))
-      {
-        result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0));
-        result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0));
-        result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0));
-        result.m_org_address_street2 = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(3, 0));
-        result.m_org_address_town = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(4, 0));
-        result.m_org_address_county = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(5, 0));
-        result.m_org_address_country = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(6, 0));
-        result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0));
-
-        //We need to be more clever about these column indexes if we add more new fields:
-        if(optional_org_logo)
-          result.m_org_logo = datamodel->get_value_at(8, 0);
-      }
-      else
-        succeeded = false;
-    }
-    catch(const Glib::Exception& ex)
-    {
-      std::cerr << "Base_DB::get_database_preferences(): exception: " << ex.what() << std::endl;
-      succeeded = false;
-    }
-    catch(const std::exception& ex)
-    {
-      std::cerr << "Base_DB::get_database_preferences(): exception: " << ex.what() << std::endl;
-      succeeded = false;
-    }
-    #else // GLIBMM_EXCEPTIONS_ENABLED
-    std::auto_ptr<Glib::Error> error;
-    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
-    if(datamodel && (datamodel->get_n_rows() != 0))
-    {
-      result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0, error));
-      result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0, error));
-      result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0, error));
-      result.m_org_address_street2 = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(3, 0, error));
-      result.m_org_address_town = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(4, 0, error));
-      result.m_org_address_county = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(5, 0, error));
-      result.m_org_address_country = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(6, 0, error));
-      result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0, error));
-
-      //We need to be more clever about these column indexes if we add more new fields:
-      if(optional_org_logo)
-        result.m_org_logo = datamodel->get_value_at(8, 0, error);
-    }
-    else
-      succeeded = false;
-
-    if (error.get())
-    {
-      std::cerr << "Error: " << error->what() << std::endl;
-      succeeded = false;
-    }
-    #endif
-    //Return the result, or try again:
-    if(succeeded)
-      return result;
-#ifndef GLOM_ENABLE_CLIENT_ONLY
-    else
-    {
-      add_standard_tables();
-      ++attempts; //Try again now that we have tried to create the table.
-    }
-#endif //GLOM_ENABLE_CLIENT_ONLY
-  }
-
-  return result;
-}
-
 #ifndef GLOM_ENABLE_CLIENT_ONLY
 
-bool Base_DB::add_standard_tables() const
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-  {
-    Document::type_vec_fields pref_fields;
-    sharedptr<TableInfo> prefs_table_info = Document::create_table_system_preferences(pref_fields);
-
-    //Name, address, etc:
-    if(!get_table_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME))
-    {
-      const bool test = create_table(prefs_table_info, pref_fields);
-
-      if(test)
-      {
-        //Add the single record:
-        const bool test = query_execute("INSERT INTO \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" (\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\") VALUES (1)");
-        if(!test)
-          std::cerr << "Base_DB::add_standard_tables(): INSERT failed." << std::endl;
-
-        //Use the database title from the document, if there is one:
-        const Glib::ustring system_name = get_document()->get_database_title();
-        if(!system_name.empty())
-        {
-          const bool test = query_execute("UPDATE \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" SET  " "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\" = '" + system_name + "' WHERE \"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\" = 1");
-          if(!test)
-            std::cerr << "Base_DB::add_standard_tables(): UPDATE failed." << std::endl;
-        }
-      }
-      else
-      {
-        g_warning("Base_DB::add_standard_tables(): create_table(prefs) failed.");
-        return false;
-      }
-    }
-    else
-    {
-      //Make sure that it has all the fields it should have,
-      //because we sometimes add some in new Glom versions:
-      create_table_add_missing_fields(prefs_table_info, pref_fields);
-    }
-
-    //Auto-increment next values:
-    if(!get_table_exists_in_database(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME))
-    {
-      sharedptr<TableInfo> table_info(new TableInfo());
-      table_info->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
-      table_info->set_title("System: Auto Increments"); //TODO: Provide standard translations.
-      table_info->m_hidden = true;
-
-      Document::type_vec_fields fields;
-
-      sharedptr<Field> primary_key(new Field()); //It's not used, because there's only one record, but we must have one.
-      primary_key->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_ID);
-      primary_key->set_glom_type(Field::TYPE_NUMERIC);
-      fields.push_back(primary_key);
-
-      sharedptr<Field> field_table_name(new Field());
-      field_table_name->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME);
-      field_table_name->set_glom_type(Field::TYPE_TEXT);
-      fields.push_back(field_table_name);
-
-      sharedptr<Field> field_field_name(new Field());
-      field_field_name->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME);
-      field_field_name->set_glom_type(Field::TYPE_TEXT);
-      fields.push_back(field_field_name);
-
-      sharedptr<Field> field_next_value(new Field());
-      field_next_value->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE);
-      field_next_value->set_glom_type(Field::TYPE_TEXT);
-      fields.push_back(field_next_value);
-
-      const bool test = create_table(table_info, fields);
-      if(!test)
-      {
-        g_warning("Base_DB::add_standard_tables(): create_table(autoincrements) failed.");
-        return false;
-      }
-
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  catch(const Glib::Exception& ex)
-  {
-    std::cerr << "Base_DB::add_standard_tables(): caught exception: " << ex.what() << std::endl;
-    return false;
-  }
-  catch(const std::exception& ex)
-  {
-    std::cerr << "Base_DB::add_standard_tables(): caught exception: " << ex.what() << std::endl;
-    return false;
-  }
-#endif // GLIBMM_EXCEPTIONS_ENABLED
-}
-
-bool Base_DB::add_standard_groups()
-{
-  //Add the glom_developer group if it does not exist:
-  const Glib::ustring devgroup = GLOM_STANDARD_GROUP_NAME_DEVELOPER;
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection = connect_to_server();
-#else
-  std::auto_ptr<ExceptionConnection> error;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-  if(error.get())
-  {
-    g_warning("Base_DB::add_standard_groups: Failed to connect: %s", error->what());
-    // TODO: Rethrow?
-  }
-#endif
-
-  // If the connection doesn't support users we can skip this step
-  if(sharedconnection->get_gda_connection()->supports_feature(Gnome::Gda::CONNECTION_FEATURE_USERS))
-  {
-    const type_vec_strings vecGroups = Privs::get_database_groups();
-    type_vec_strings::const_iterator iterFind = std::find(vecGroups.begin(), vecGroups.end(), devgroup);
-    if(iterFind == vecGroups.end())
-    {
-      //The "SUPERUSER" here has no effect because SUPERUSER is not "inherited" to member users.
-      //But let's keep it to make the purpose of this group obvious.
-      bool test = query_execute("CREATE GROUP \"" GLOM_STANDARD_GROUP_NAME_DEVELOPER "\" WITH SUPERUSER");
-      if(!test)
-      {
-        std::cerr << "Glom Base_DB::add_standard_groups(): CREATE GROUP failed when adding the developer group." << std::endl;
-        return false;
-      }
-
-      //Make sure the current user is in the developer group.
-      //(If he is capable of creating these groups then he is obviously a developer, and has developer rights on the postgres server.)
-      const Glib::ustring current_user = ConnectionPool::get_instance()->get_user();
-      Glib::ustring strQuery = "ALTER GROUP \"" GLOM_STANDARD_GROUP_NAME_DEVELOPER "\" ADD USER \"" + current_user + "\"";
-      test = query_execute(strQuery);
-      if(!test)
-      {
-        std::cerr << "Glom Base_DB::add_standard_groups(): ALTER GROUP failed when adding the user to the developer group." << std::endl;
-        return false;
-      }
-
-      std::cout << "DEBUG: Added user " << current_user << " to glom developer group on postgres server." << std::endl;
-
-      Privileges priv_devs;
-      priv_devs.m_view = true;
-      priv_devs.m_edit = true;
-      priv_devs.m_create = true;
-      priv_devs.m_delete = true;
-
-      Document::type_listTableInfo table_list = get_document()->get_tables(true /* including system prefs */);
-
-      for(Document::type_listTableInfo::const_iterator iter = table_list.begin(); iter != table_list.end(); ++iter)
-      {
-        sharedptr<const TableInfo> table_info = *iter;
-        if(table_info)
-        {
-          const Glib::ustring table_name = table_info->get_name();
-          if(get_table_exists_in_database(table_name)) //Maybe the table has not been created yet.
-            Privs::set_table_privileges(devgroup, table_name, priv_devs, true /* developer privileges */);
-        }
-      }
-
-      //Make sure that it is in the database too:
-      GroupInfo group_info;
-      group_info.set_name(GLOM_STANDARD_GROUP_NAME_DEVELOPER);
-      group_info.m_developer = true;
-      get_document()->set_group(group_info);
-    }
-  }
-  else
-  {
-    std::cout << "DEBUG: Connection does not support users" << std::endl;
-  }
-
-  return true;
-}
-
-void Base_DB::set_database_preferences(const SystemPrefs& prefs)
-{
-  if(get_userlevel() == AppState::USERLEVEL_DEVELOPER)
-    add_standard_tables();
-
-  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
-  params->add_holder("name", prefs.m_name);
-  params->add_holder("street", prefs.m_org_address_street);
-  params->add_holder("street2", prefs.m_org_address_street2);
-  params->add_holder("town", prefs.m_org_address_town);
-  params->add_holder("county", prefs.m_org_address_county);
-  params->add_holder("country", prefs.m_org_address_country);
-  params->add_holder("postcode", prefs.m_org_address_postcode);
-
-  //The logo field was introduced in a later version of Glom.
-  //If the user is not in developer mode then the new field has not yet been added:
-  Glib::ustring optional_part_logo;
-  if(get_field_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME, GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO))
-  {
-    params->add_holder("org_logo", prefs.m_org_logo);
-    optional_part_logo =  "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO "\" = ##org_logo::GDA_TYPE_BINARY, ";
-  }
-  const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" SET "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\" = ##name::gchararray, "
-      + optional_part_logo +
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET "\" = ##street::gchararray, "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2 "\" = ##street2::gchararray, "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN "\" = ##town::gchararray, "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY "\" = ##county::gchararray, "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY "\" = ##country::gchararray, "
-      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE "\" = ##postcode::gchararray"
-      " WHERE \"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\" = 1";
-
-  bool test = false;
-  test = query_execute(sql_query, params);
-
-  if(!test)
-    std::cerr << "Base_DB::set_database_preferences(): UPDATE failed." << std::endl;
-
-  //Set some information in the document too, so we can use it to recreate the database:
-  get_document()->set_database_title(prefs.m_name);
-}
-
-bool Base_DB::create_table_with_default_fields(const Glib::ustring& table_name)
-{
-  if(table_name.empty())
-    return false;
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-    sharedptr<SharedConnection> sharedconnection = connect_to_server();
-#else
-    std::auto_ptr<ExceptionConnection> error;
-    sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-    // TODO: Rethrow?
-#endif
-  if(!sharedconnection)
-  {
-    g_warning("Base_DB::create_table_with_default_fields: connection failed.");
-    return false;
-  }
-
-  bool created = false;
-
-  //Primary key:
-  sharedptr<Field> field_primary_key(new Field());
-  field_primary_key->set_name(table_name + "_id");
-  field_primary_key->set_title(table_name + " ID");
-  field_primary_key->set_primary_key();
-  field_primary_key->set_auto_increment();
-
-  Glib::RefPtr<Gnome::Gda::Column> field_info = field_primary_key->get_field_info();
-  field_info->set_allow_null(false);
-  field_primary_key->set_field_info(field_info);
-
-  field_primary_key->set_glom_type(Field::TYPE_NUMERIC);
-  //std::cout << "field_primary_key->get_auto_increment():" << field_primary_key->get_auto_increment() << std::endl;
-
-  type_vec_fields fields;
-  fields.push_back(field_primary_key);
-
-  //Description:
-  sharedptr<Field> field_description(new Field());
-  field_description->set_name("description");
-  field_description->set_title(_("Description")); //Use a translation, because the original locale will be marked as non-English if the current locale is non-English.
-  field_description->set_glom_type(Field::TYPE_TEXT);
-  fields.push_back(field_description);
-
-  //Comments:
-  sharedptr<Field> field_comments(new Field());
-  field_comments->set_name("comments");
-  field_comments->set_title(_("Comments"));
-  field_comments->set_glom_type(Field::TYPE_TEXT);
-  field_comments->m_default_formatting.set_text_format_multiline();
-  fields.push_back(field_comments);
-
-  sharedptr<TableInfo> table_info(new TableInfo());
-  table_info->set_name(table_name);
-  table_info->set_title( Utils::title_from_string( table_name ) ); //Start with a title that might be appropriate.
-
-  created = create_table(table_info, fields);
-
-    //Create a table with 1 "ID" field:
-   //MSYQL:
-    //query_execute( "CREATE TABLE \"" + table_name + "\" (" + primary_key_name + " INT NOT NULL AUTO_INCREMENT PRIMARY KEY)" );
-    //query_execute( "INSERT INTO \"" + table_name + "\" VALUES (0)" );
-
-    //PostgresSQL:
-    //query_execute( "CREATE TABLE \"" + table_name + "\" (\"" + primary_key_name + "\" serial NOT NULL  PRIMARY KEY)" );
-
-    //query_execute( "CREATE TABLE \"" + table_name + "\" (" +
-    //  field_primary_key->get_name() + " numeric NOT NULL  PRIMARY KEY," +
-    //  extra_field_description + "varchar, " +
-    //  extra_field_comments + "varchar" +
-    //  ")" );
-
-  if(created)
-  {
-    //Save the changes in the document:
-    Document* document = get_document();
-    if(document)
-    {
-      document->add_table(table_info);
-      document->set_table_fields(table_info->get_name(), fields);
-    }
-  }
-
-  return created;
-}
-
-bool Base_DB::create_table(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields_in) const
-{
-  //std::cout << "Base_DB::create_table(): " << table_info->get_name() << ", title=" << table_info->get_title() << std::endl;
-
-  bool table_creation_succeeded = false;
-
-
-  Document::type_vec_fields fields = fields_in;
-
-  //Create the standard field too:
-  //(We don't actually use this yet)
-  if(std::find_if(fields.begin(), fields.end(), predicate_FieldHasName<Field>(GLOM_STANDARD_FIELD_LOCK)) == fields.end())
-  {
-    sharedptr<Field> field = sharedptr<Field>::create();
-    field->set_name(GLOM_STANDARD_FIELD_LOCK);
-    field->set_glom_type(Field::TYPE_TEXT);
-    fields.push_back(field);
-  }
-
-  //Create SQL to describe all fields in this table:
-  Glib::ustring sql_fields;
-  for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
-  {
-    //Create SQL to describe this field:
-    sharedptr<Field> field = *iter;
-
-    //The field has no gda type, so we set that:
-    //This usually comes from the database, but that's a bit strange.
-    Glib::RefPtr<Gnome::Gda::Column> info = field->get_field_info();
-    info->set_g_type( Field::get_gda_type_for_glom_type(field->get_glom_type()) );
-    field->set_field_info(info); //TODO_Performance
-
-    Glib::ustring sql_field_description = "\"" + field->get_name() + "\" " + field->get_sql_type();
-
-    if(field->get_primary_key())
-      sql_field_description += " NOT NULL  PRIMARY KEY";
-
-    //Append it:
-    if(!sql_fields.empty())
-      sql_fields += ", ";
-
-    sql_fields += sql_field_description;
-  }
-
-  if(sql_fields.empty())
-  {
-    g_warning("Base_Db::create_table::create_table(): sql_fields is empty.");
-  }
-
-  //Actually create the table
-  try
-  {
-    //TODO: Escape the table name?
-    //TODO: Use GDA_SERVER_OPERATION_CREATE_TABLE instead?
-    table_creation_succeeded = query_execute( "CREATE TABLE \"" + table_info->get_name() + "\" (" + sql_fields + ");" );
-    if(!table_creation_succeeded)
-      std::cerr << "Base_DB::create_table(): CREATE TABLE failed." << std::endl;
-  }
-  catch(const ExceptionConnection& ex)
-  {
-    table_creation_succeeded = false;
-  }
-
-  if(table_creation_succeeded)
-  {
-    // Update the libgda meta store, so that get_fields_for_table_from_database()
-    // returns the fields correctly for the new table.
-    update_gda_metastore_for_table(table_info->get_name());
-
-    // TODO: Maybe we should create the table directly via libgda instead of
-    // executing an SQL query ourselves, so that libgda has the chance to
-    // do this meta store update automatically.
-    // (Yes, generally it would be nice to use libgda API instead of generating SQL. murrayc)
-  }
-
-  return table_creation_succeeded;
-}
-
-bool Base_DB::create_table_add_missing_fields(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields) const
-{
-  const Glib::ustring table_name = table_info->get_name();
-
-  for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
-  {
-    sharedptr<const Field> field = *iter;
-    if(!get_field_exists_in_database(table_name, field->get_name()))
-    {
-      const bool test = add_column(table_name, field, 0); /* TODO: parent_window */
-      if(!test)
-       return test;
-    }
-  }
-
-  return true;
-}
-
-bool Base_DB::add_column(const Glib::ustring& table_name, const sharedptr<const Field>& field, Gtk::Window* /* parent_window */) const
-{
-  ConnectionPool* connection_pool = ConnectionPool::get_instance();
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-  {
-    connection_pool->add_column(table_name, field);
-  }
-  catch(const Glib::Error& ex)
-  {
-#else
-  std::auto_ptr<Glib::Error> error;
-  connection_pool->add_column(table_name, field, error);
-  if(error.get())
-  {
-    const Glib::Error& ex = *error;
-#endif
-    handle_error(ex);
-//    Gtk::MessageDialog window(*parent_window, Utils::bold_message(ex.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
-//    window.run();
-    return false;
-  }
-
-  return true;
-}
-
-bool Base_DB::drop_column(const Glib::ustring& table_name, const Glib::ustring& field_name, Gtk::Window* /* parent_window */) const
-{
-  ConnectionPool* connection_pool = ConnectionPool::get_instance();
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-  {
-    return connection_pool->drop_column(table_name, field_name);
-  }
-  catch(const Glib::Error& ex)
-  {
-#else
-  std::auto_ptr<Glib::Error> error;
-  connection_pool->add_column(table_name, field_name, error);
-  if(error.get())
-  {
-    const Glib::Error& ex = *error;
-#endif
-    handle_error(ex);
-//    Gtk::MessageDialog window(*parent_window, Utils::bold_message(ex.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
-//    window.run();
-    return false;
-  }
-
-  return true;
-}
-
 namespace
 {
   // Check primary key and uniqueness constraints when changing a column
@@ -1668,143 +609,6 @@ bool Base_DB::change_columns(const Glib::ustring& table_name, const type_vec_con
 
   return true;
 }
-#endif
-
-Glib::RefPtr<Gnome::Gda::Connection> Base_DB::get_connection()
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection;
-  try
-  {
-     sharedconnection = connect_to_server();
-  }
-  catch (const Glib::Error& error)
-  {
-    std::cerr << "Base_DB::get_connection(): " << error.what() << std::endl;
-  }
-#else
-  std::auto_ptr<ExceptionConnection> error;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-  if(error.get())
-  {
-    std::cerr << "Base_DB::get_connection(): " << error->what() << std::endl;
-    // TODO: Rethrow?
-  }
-#endif
-
-  if(!sharedconnection)
-  {
-    std::cerr << "Base_DB::get_connection(): No connection yet." << std::endl;
-    return Glib::RefPtr<Gnome::Gda::Connection>(0);
-  }
-
-  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
-
-  return gda_connection;
-}
-
-#ifndef GLOM_ENABLE_CLIENT_ONLY
-
-bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
-{
-  //TODO_Performance: Avoid copying:
-  const Document::type_example_rows example_rows = get_document()->get_table_example_data(table_name);
-  if(example_rows.empty())
-  {
-    //std::cout << "debug: Base_DB::insert_example_data(): No example data available." << std::endl;
-    return true;
-  }
-
-  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
-  if(!gda_connection)
-    return false;
-
-
-  //std::cout << "debug: inserting example_rows for table: " << table_name << std::endl;
-
-  bool insert_succeeded = true;
-
-
-  //Get field names:
-  Document::type_vec_fields vec_fields = get_document()->get_table_fields(table_name);
-
-  //Actually insert the data:
-  //std::cout << "  debug: Base_DB::insert_example_data(): number of rows of data: " << vec_rows.size() << std::endl;
-
-  //std::cout << "DEBUG: example_row size = " << example_rows.size() << std::endl;
-
-  for(Document::type_example_rows::const_iterator iter = example_rows.begin(); iter != example_rows.end(); ++iter)
-  {
-    //Check that the row contains the correct number of columns.
-    //This check will slow this down, but it seems useful:
-    //TODO: This can only work if we can distinguish , inside "" and , outside "":
-    const Document::type_row_data& row_data = *iter;
-    Glib::ustring strNames;
-    Glib::ustring strVals;
-    if(row_data.empty())
-      break;
-
-    //std::cout << "DEBUG: row_data size = " << row_data.size() << ", (fields size= " << vec_fields.size() << " )" << std::endl;
-
-    Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
-    ParameterNameGenerator generator;
-    for(unsigned int i = 0; i < row_data.size(); ++i) //TODO_Performance: Avoid calling size() so much.
-    {
-      //std::cout << "  DEBUG: i=" << i << ", row_data.size()=" << row_data.size() << std::endl;
-
-      if(i > 0)
-      {
-        strVals += ", ";
-        strNames += ", ";
-      }
-
-      sharedptr<Field> field = vec_fields[i];
-      if(!field)
-      {
-        std::cerr << "Base_DB::insert_example_data(): field was null for field num=" << i << std::endl;
-        break;
-      }
-
-      strNames += field->get_name();
-
-      Gnome::Gda::Value value = row_data[i];
-      //std::cout << "  DEBUG: example: field=" << field->get_name() << ", value=" << value.to_string() << std::endl;
-
-      //Add a SQL parameter for the value:
-      guint id = 0;
-      const Field::glom_field_type glom_type = field->get_glom_type();
-      Glib::RefPtr<Gnome::Gda::Holder> holder =
-        Gnome::Gda::Holder::create( Field::get_gda_type_for_glom_type(glom_type),
-          generator.get_next_name(id));
-
-      holder->set_not_null(false);
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-      holder->set_value_as_value(value);
-#else
-      std::auto_ptr<Glib::Error> holder_error;
-      holder->set_value_as_value(value, holder_error);
-#endif
-      params->add_holder(holder);
-
-      strVals += "##" + generator.get_name_from_id(id) + "::" + vec_fields[i]->get_gda_type_name();
-    }
-
-    //Create and parse the SQL query:
-    //After this, the Parser will know how many SQL parameters there are in
-    //the query, and allow us to set their values.
-    const Glib::ustring strQuery = "INSERT INTO \"" + table_name + "\" (" + strNames + ") VALUES (" + strVals + ")";
-    insert_succeeded = query_execute(strQuery, params);
-    if(!insert_succeeded)
-      break;
-  }
-
-  for(Document::type_vec_fields::const_iterator iter = vec_fields.begin(); iter != vec_fields.end(); ++iter)
-  {
-    if((*iter)->get_auto_increment())
-      recalculate_next_auto_increment_value(table_name, (*iter)->get_name());
-  }
-  return insert_succeeded;
-}
 
 sharedptr<LayoutItem_Field> Base_DB::offer_field_list_select_one_field(const Glib::ustring& table_name, Gtk::Window* transient_for)
 {
@@ -3444,46 +2248,6 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
     found_set.m_where_clause = "\"" + where_clause_to_table_name + "\".\"" + relationship->get_to_field() + "\" = " + where_clause_to_key_field->sql(foreign_key_value);
 }
 
-void Base_DB::update_gda_metastore_for_table(const Glib::ustring& table_name) const
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(Application::get_application());
-#else
-  std::auto_ptr<Glom::ExceptionConnection> ex;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(Application::get_application(), ex);
-#endif
-  if(!sharedconnection)
-  {
-    std::cerr << "Base_DB::update_gda_metastore_for_table(): No connection." << std::endl;
-    return;
-  }
-
-  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
-  if(!gda_connection)
-  {
-    std::cerr << "Base_DB::update_gda_metastore_for_table(): No gda_connection." << std::endl;
-    return;
-  }
-
-  if(table_name.empty())
-  {
-    std::cerr << "Base_DB::update_gda_metastore_for_table(): table_name is empty." << std::endl;
-    return;
-  }
-
-  //std::cout << "DEBUG: Base_DB::update_gda_metastore_for_table(): Calling Gda::Connection::update_meta_store_table(" << table_name << ") ..." << std::endl;
-  //TODO: This doesn't seem to quite work yet:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  gda_connection->update_meta_store_table(table_name);
-#else
-  std::auto_ptr<Glib::Error> update_error;
-  gda_connection->update_meta_store_table(table_name, Glib::ustring(), update_error);
-#endif
-
-  //This does work, though it takes ages: gda_connection->update_meta_store();
-  //std::cout << "DEBUG: Base_DB::update_gda_metastore_for_table(): ... Finished calling Gda::Connection::update_meta_store_table()" << std::endl;
-}
-
 bool Base_DB::add_user(const Glib::ustring& user, const Glib::ustring& password, const Glib::ustring& group)
 {
   if(user.empty() || password.empty() || group.empty())
diff --git a/glom/base_db.h b/glom/base_db.h
index 6fce311..08f795b 100644
--- a/glom/base_db.h
+++ b/glom/base_db.h
@@ -71,13 +71,6 @@ public:
   virtual void set_document(Document* pDocument); //View override
   virtual void load_from_document(); //View override
 
-  typedef std::vector< sharedptr<Field> > type_vec_fields;
-  typedef std::vector< sharedptr<const Field> > type_vec_const_fields;
-
-  static type_vec_fields get_fields_for_table_from_database(const Glib::ustring& table_name, bool including_system_fields = false);
-  static bool get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name);
-
-
   /** Execute a SQL Select command, returning the result.
    * This method handles any Gda exceptions caused by executing the command.
    */
@@ -94,27 +87,13 @@ public:
   static int count_rows_returned_by(const Glib::ustring& sql_query);
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-  bool add_standard_groups();
-  bool add_standard_tables() const;
-
-  bool create_table(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields) const;
-  bool create_table_add_missing_fields(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields) const;
-
-  /// Also saves the table information in the document:
-  bool create_table_with_default_fields(const Glib::ustring& table_name);
-
-  // TODO: Should these functions update the document, so callers don't need
-  // to do it?
-  bool add_column(const Glib::ustring& table_name, const sharedptr<const Field>& field, Gtk::Window* parent_window) const;
-
-  bool drop_column(const Glib::ustring& table_name, const Glib::ustring& field_name, Gtk::Window* parent_window) const;
-
   sharedptr<Field> change_column(const Glib::ustring& table_name, const sharedptr<const Field>& field_old, const sharedptr<const Field>& field, Gtk::Window* parent_window) const;
 
+  typedef std::vector< sharedptr<Field> > type_vec_fields;
+  typedef std::vector< sharedptr<const Field> > type_vec_const_fields;
+  
   bool change_columns(const Glib::ustring& table_name, const type_vec_const_fields& old_fields, type_vec_fields& fields, Gtk::Window* parent_window) const;
 
-  bool insert_example_data(const Glib::ustring& table_name) const;
-
 #endif //GLOM_ENABLE_CLIENT_ONLY
 
   //TODO: This is not a very good place for this function.
@@ -162,10 +141,6 @@ protected:
 
   void fill_full_field_details(const Glib::ustring& parent_table_name, sharedptr<LayoutItem_Field>& layout_item);
 
-  typedef std::vector<Glib::ustring> type_vec_strings;
-  type_vec_strings get_table_names_from_database(bool ignore_system_tables = false) const;
-
-  bool get_table_exists_in_database(const Glib::ustring& table_name) const;
   bool get_relationship_exists(const Glib::ustring& table_name, const Glib::ustring& relationship_name);
 
   /** Get all the fields for a table, including any from the datasbase that are not yet known in the document.
@@ -336,24 +311,6 @@ protected:
   ///Get a single field value from the database.
   Gnome::Gda::Value get_field_value_in_database(const sharedptr<Field>& field, const FoundSet& found_set, Gtk::Window* parent_window);
 
-
-
-  SystemPrefs get_database_preferences() const;
-  void set_database_preferences(const SystemPrefs& prefs);
-
-  Gnome::Gda::Value auto_increment_insert_first_if_necessary(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
-
-  /** Get the next auto-increment value for this primary key, from the glom system table.
-   * Add a row for this field in the system table if it does not exist already.
-   */
-  Gnome::Gda::Value get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
-
-  /** Set the next auto-increment value in the glom system table, by examining all current values.
-   * Use this, for instance, after importing rows.
-   * Add a row for this field in the system table if it does not exist already.
-   */
-  void recalculate_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
-
   bool get_field_value_is_unique(const Glib::ustring& table_name, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
 
   bool check_entered_value_for_uniqueness(const Glib::ustring& table_name, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value, Gtk::Window* parent_window);
@@ -388,18 +345,13 @@ protected:
    */
   void set_found_set_where_clause_for_portal(FoundSet& found_set, const sharedptr<LayoutItem_Portal>& portal, const Gnome::Gda::Value& foreign_key_value);
 
-  /** Update GDA's information about the table structure, such as the 
-   * field list and their types.
-   * Call this whenever changing the table structure, for instance with an ALTER query.
-   * This may take a few seconds to return.
-   */
-  void update_gda_metastore_for_table(const Glib::ustring& table_name) const;
-  
+  //TODO: Not implemented. Is this used?
   static Glib::RefPtr<Gnome::Gda::Connection> get_connection();
 
   static bool get_field_primary_key_index_for_fields(const type_vec_fields& fields, guint& field_column);
   static bool get_field_primary_key_index_for_fields(const type_vecLayoutFields& fields, guint& field_column);
 
+  typedef std::vector<Glib::ustring> type_vec_strings;
   static type_vec_strings util_vecStrings_from_Fields(const type_vec_fields& fields);
 
   /** Add a @a user to the database, with the specified @a password, in the specified @a group.
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index 271799d..4247c01 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -24,6 +24,7 @@
 #include <glom/application.h>
 #include <glom/python_embed/glom_python.h>
 #include <glom/utils_ui.h>
+#include <libglom/db_utils.h>
 #include <sstream>
 #include <glibmm/i18n.h>
 
@@ -363,7 +364,7 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
       //Create the related record:
       if(key_is_auto_increment)
       {
-        primary_key_value = get_next_auto_increment_value(relationship->get_to_table(), primary_key_field->get_name());
+        primary_key_value = DbUtils::get_next_auto_increment_value(relationship->get_to_table(), primary_key_field->get_name());
 
         //Generate the new key value;
       }
diff --git a/glom/frame_glom.cc b/glom/frame_glom.cc
index 2a8e75b..76d08dc 100644
--- a/glom/frame_glom.cc
+++ b/glom/frame_glom.cc
@@ -43,6 +43,7 @@
 #include <glom/mode_design/script_library/dialog_script_library.h>
 #include <glom/mode_design/dialog_initial_password.h>
 #include <glom/mode_design/relationships_overview/dialog_relationships_overview.h>
+#include <glom/glade_utils.h>
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
 #include <glom/utils_ui.h>
@@ -66,7 +67,8 @@
 #endif
 
 #include <glom/filechooser_export.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
+#include <libglom/db_utils.h>
 #include <sstream> //For stringstream.
 #include <fstream>
 #include <glibmm/i18n.h>
@@ -1278,7 +1280,7 @@ void Frame_Glom::on_dialog_add_related_table_response(int response)
 
     //It would be nice to put this in the dialog's on_response() instead,
     //but I don't think we can stop the response from being returned. murrayc
-    if(get_table_exists_in_database(table_name))
+    if(DbUtils::get_table_exists_in_database(table_name))
     {
       Frame_Glom::show_ok_dialog(_("Table Exists Already"), _("A table with this name already exists in the database. Please choose a different table name."), *parent, Gtk::MESSAGE_ERROR);
     }
@@ -1304,7 +1306,7 @@ void Frame_Glom::on_dialog_add_related_table_response(int response)
     else
     {
       //Create the new table:
-      const bool result = create_table_with_default_fields(table_name);
+      const bool result = DbUtils::create_table_with_default_fields(get_document(), table_name);
       if(!result)
       {
         std::cerr << "Frame_Glom::on_menu_Tables_AddRelatedTable(): create_table_with_default_fields() failed." << std::endl;
@@ -1570,7 +1572,7 @@ void Frame_Glom::update_table_in_document_from_database()
   typedef Box_DB_Table::type_vec_fields type_vec_fields;
 
   //Get the fields information from the database:
-  Base_DB::type_vec_fields fieldsDatabase = Base_DB::get_fields_for_table_from_database(m_table_name);
+  DbUtils::type_vec_fields fieldsDatabase = DbUtils::get_fields_for_table_from_database(m_table_name);
 
   Document* pDoc = dynamic_cast<const Document*>(get_document());
   if(pDoc)
@@ -2457,27 +2459,20 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
 #ifndef GLOM_ENABLE_CLIENT_ONLY
 bool Frame_Glom::create_database(const Glib::ustring& database_name, const Glib::ustring& title)
 {
-#if 1
-  // This seems to increase the chance that the database creation does not
-  // fail due to the "source database is still in use" error. armin.
-  //std::cout << "Going to sleep" << std::endl;
-  Glib::usleep(500 * 1000);
-  //std::cout << "Awake" << std::endl;
-#endif
+  bool result = false;
 
   Gtk::Window* pWindowApp = get_app_window();
   g_assert(pWindowApp);
-
-  BusyCursor busycursor(*pWindowApp);
-
-  try
+      
   {
-    ConnectionPool::get_instance()->create_database(database_name);
+    BusyCursor busycursor(*pWindowApp);
+
+    sigc::slot<void> onProgress; //TODO: Show visual feedback.
+    result = DbUtils::create_database(get_document(), database_name, title, onProgress);
   }
-  catch(const Glib::Exception& ex) // libgda does not set error domain
+  
+  if(!result)
   {
-    std::cerr << "Frame_Glom::create_database():  Gnome::Gda::Connection::create_database(" << database_name << ") failed: " << ex.what() << std::endl;
-
     //Tell the user:
     Gtk::Dialog* dialog = 0;
     Utils::get_glade_widget_with_warning("glom_developer.glade", "dialog_error_create_database", dialog);
@@ -2488,60 +2483,7 @@ bool Frame_Glom::create_database(const Glib::ustring& database_name, const Glib:
     return false;
   }
 
-  //Connect to the actual database:
-  ConnectionPool* connection_pool = ConnectionPool::get_instance();
-  connection_pool->set_database(database_name);
-
-  sharedptr<SharedConnection> sharedconnection;
-  try
-  {
-    sharedconnection = connection_pool->connect();
-  }
-  catch(const Glib::Exception& ex)
-  {
-    std::cerr << "Frame_Glom::create_database(): Could not connect to just-created database. exception caught:" << ex.what() << std::endl;
-    return false;
-  }
-  catch(const std::exception& ex)
-  {
-    std::cerr << "Frame_Glom::create_database(): Could not connect to just-created database. exception caught:" << ex.what() << std::endl;
-    return false;
-  }
-
-  if(sharedconnection)
-  {
-    bool test = add_standard_tables(); //Add internal, hidden, tables.
-    if(!test)
-      return false;
-
-    //Create the developer group, and make this user a member of it:
-    //If we got this far then the user must really have developer privileges already:
-    test = add_standard_groups();
-    if(!test)
-      return false;
-
-    //std::cout << "Frame_Glom::create_database(): Creation of standard tables and groups finished." << std::endl;
-
-    //Set the title based on the title in the example document, or the user-supplied title when creating new documents:
-    SystemPrefs prefs = get_database_preferences();
-    if(prefs.m_name.empty())
-    {
-      //std::cout << "Frame_Glom::create_database(): Setting title in the database." << std::endl;
-      prefs.m_name = title;
-      set_database_preferences(prefs);
-    }
-    else
-    {
-      //std::cout << "Frame_Glom::create_database(): database has title: " << prefs.m_name << std::endl;
-    }
-
-    return true;
-  }
-  else
-  {
-    std::cerr << "Frame_Glom::create_database(): Could not connect to just-created database." << std::endl;
-    return false;
-  }
+  return result;
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
diff --git a/glom/import_csv/dialog_import_csv_progress.cc b/glom/import_csv/dialog_import_csv_progress.cc
index 85e1b70..3c0caff 100644
--- a/glom/import_csv/dialog_import_csv_progress.cc
+++ b/glom/import_csv/dialog_import_csv_progress.cc
@@ -20,6 +20,7 @@
 
 #include "dialog_import_csv_progress.h"
 #include <libglom/libglom_config.h>
+#include <libglom/db_utils.h>
 
 #include <libglom/data_structure/glomconversions.h>
 #include <glibmm/i18n.h>
@@ -210,7 +211,7 @@ bool Dialog_Import_CSV_Progress::on_idle_import()
   Gnome::Gda::Value primary_key_value;
   if(m_field_primary_key->get_auto_increment())
   {
-    primary_key_value = get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name());
+    primary_key_value = DbUtils::get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name());
   }
   else
   {
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index 9c572b7..dfb560b 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -103,7 +103,8 @@ ConnectionPool::ConnectionPool()
   m_backend(0),
   m_sharedconnection_refcount(0),
   m_ready_to_connect(false),
-  m_pFieldTypes(0)
+  m_pFieldTypes(0),
+  m_show_debug_output(false)
 {
 }
 
@@ -948,5 +949,14 @@ void ConnectionPool::set_get_document_func(const SlotGetDocument& slot)
   m_slot_get_document = slot;
 }
 
+void ConnectionPool::set_show_debug_output(bool val)
+{
+  m_show_debug_output = val;
+}
+ 
+bool ConnectionPool::get_show_debug_output() const
+{
+  return m_show_debug_output;
+}
 
 } //namespace Glom
diff --git a/glom/libglom/connectionpool.h b/glom/libglom/connectionpool.h
index a881229..b02fe35 100644
--- a/glom/libglom/connectionpool.h
+++ b/glom/libglom/connectionpool.h
@@ -255,6 +255,10 @@ public:
   static void on_epc_progress_end(gpointer user_data);
 #endif // !G_OS_WIN32
 
+  //TODO: Document
+  void set_show_debug_output(bool val);
+  bool get_show_debug_output() const;
+
   //Show the gda error in a dialog.
   static bool handle_error_cerr_only();
 
@@ -292,6 +296,7 @@ private:
   Glib::ustring m_host, m_user, m_password, m_database;
 
   FieldTypes* m_pFieldTypes;
+  bool m_show_debug_output;
 
 private:
 
diff --git a/glom/libglom/db_utils.cc b/glom/libglom/db_utils.cc
new file mode 100644
index 0000000..725dd73
--- /dev/null
+++ b/glom/libglom/db_utils.cc
@@ -0,0 +1,1666 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2010 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/db_utils.h>
+#include <libglom/connectionpool.h>
+#include <libglom/data_structure/glomconversions.h>
+#include <libglom/standard_table_prefs_fields.h>
+#include <libglom/privs.h>
+#include <libglom/data_structure/parameternamegenerator.h>
+#include <libglom/utils.h>
+#include <libgda/libgda.h> // For gda_g_type_from_string
+#include <glibmm/i18n.h>
+
+namespace Glom
+{
+
+namespace DbUtils
+{
+
+static Glib::RefPtr<Gnome::Gda::Connection> get_connection()
+{
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  sharedptr<SharedConnection> sharedconnection;
+  try
+  {
+     sharedconnection = ConnectionPool::get_and_connect();
+  }
+  catch (const Glib::Error& error)
+  {
+    std::cerr << "get_connection(): " << error.what() << std::endl;
+  }
+#else
+  std::auto_ptr<ExceptionConnection> error;
+  sharedptr<SharedConnection> sharedconnection = ConnectionPool::get_and_connect(error);
+  if(error.get())
+  {
+    std::cerr << "get_connection(): " << error->what() << std::endl;
+    // TODO: Rethrow?
+  }
+#endif
+
+  if(!sharedconnection)
+  {
+    std::cerr << "get_connection(): No connection yet." << std::endl;
+    return Glib::RefPtr<Gnome::Gda::Connection>(0);
+  }
+
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
+
+  return gda_connection;
+}
+
+/** Update GDA's information about the table structure, such as the 
+  * field list and their types.
+  * Call this whenever changing the table structure, for instance with an ALTER query.
+  * This may take a few seconds to return.
+  */
+static void update_gda_metastore_for_table(const Glib::ustring& table_name)
+{
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "update_gda_metastore_for_table(): No gda_connection." << std::endl;
+    return;
+  }
+
+  if(table_name.empty())
+  {
+    std::cerr << "update_gda_metastore_for_table(): table_name is empty." << std::endl;
+    return;
+  }
+
+  //std::cout << "DEBUG: update_gda_metastore_for_table(): Calling Gda::Connection::update_meta_store_table(" << table_name << ") ..." << std::endl;
+  //TODO: This doesn't seem to quite work yet:
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  gda_connection->update_meta_store_table(table_name);
+#else
+  std::auto_ptr<Glib::Error> update_error;
+  gda_connection->update_meta_store_table(table_name, Glib::ustring(), update_error);
+#endif
+
+  //This does work, though it takes ages: gda_connection->update_meta_store();
+  //std::cout << "DEBUG: update_gda_metastore_for_table(): ... Finished calling Gda::Connection::update_meta_store_table()" << std::endl;
+}
+
+bool create_database(Document* document, const Glib::ustring& database_name, const Glib::ustring& title, const sigc::slot<void>& progress)
+{
+#if 1
+  // This seems to increase the chance that the database creation does not
+  // fail due to the "source database is still in use" error. armin.
+  //std::cout << "Going to sleep" << std::endl;
+  Glib::usleep(500 * 1000);
+  //std::cout << "Awake" << std::endl;
+#endif
+
+  try
+  {
+    ConnectionPool::get_instance()->create_database(database_name);
+  }
+  catch(const Glib::Exception& ex) // libgda does not set error domain
+  {
+    std::cerr << "create_database():  Gnome::Gda::Connection::create_database(" << database_name << ") failed: " << ex.what() << std::endl;
+
+    return false;
+  }
+
+  //Connect to the actual database:
+  ConnectionPool* connection_pool = ConnectionPool::get_instance();
+  connection_pool->set_database(database_name);
+
+  sharedptr<SharedConnection> sharedconnection;
+  try
+  {
+    sharedconnection = connection_pool->connect();
+  }
+  catch(const Glib::Exception& ex)
+  {
+    std::cerr << "create_database(): Could not connect to just-created database. exception caught:" << ex.what() << std::endl;
+    return false;
+  }
+  catch(const std::exception& ex)
+  {
+    std::cerr << "create_database(): Could not connect to just-created database. exception caught:" << ex.what() << std::endl;
+    return false;
+  }
+
+  if(sharedconnection)
+  {
+    bool test = add_standard_tables(document); //Add internal, hidden, tables.
+    if(!test)
+      return false;
+
+    //Create the developer group, and make this user a member of it:
+    //If we got this far then the user must really have developer privileges already:
+    test = add_standard_groups(document);
+    if(!test)
+      return false;
+
+    //std::cout << "create_database(): Creation of standard tables and groups finished." << std::endl;
+
+    //Set the title based on the title in the example document, or the user-supplied title when creating new documents:
+    SystemPrefs prefs = get_database_preferences(document);
+    if(prefs.m_name.empty())
+    {
+      //std::cout << "create_database(): Setting title in the database." << std::endl;
+      prefs.m_name = title;
+      set_database_preferences(document, prefs);
+    }
+    else
+    {
+      //std::cout << "create_database(): database has title: " << prefs.m_name << std::endl;
+    }
+
+    return true;
+  }
+  else
+  {
+    std::cerr << "create_database(): Could not connect to just-created database." << std::endl;
+    return false;
+  }
+}
+
+bool recreate_database_from_document(Document* document, const sigc::slot<void>& progress)
+{
+ ConnectionPool* connection_pool = ConnectionPool::get_instance();
+  if(!connection_pool)
+    return false; //Impossible anyway.
+
+  //Check whether the database exists already.
+  const Glib::ustring db_name = document->get_connection_database();
+  if(db_name.empty())
+    return false;
+
+  connection_pool->set_database(db_name);
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+#else
+  std::auto_ptr<std::exception> error;
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+  {
+    connection_pool->set_ready_to_connect(); //This has succeeded already.
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    sharedptr<SharedConnection> sharedconnection = connection_pool->connect();
+#else
+    sharedptr<SharedConnection> sharedconnection = connection_pool->connect(error);
+    if(!error.get())
+    {
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+      g_warning("Application::recreate_database(): Failed because database exists already.");
+
+      return false; //Connection to the database succeeded, because no exception was thrown. so the database exists already.
+#ifndef GLIBMM_EXCEPTIONS_ENABLED
+    }
+#endif // !GLIBMM_EXCEPTIONS_ENABLED
+  }
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  catch(const ExceptionConnection& ex)
+  {
+#else
+  if(error.get())
+  {
+    const ExceptionConnection* exptr = dynamic_cast<ExceptionConnection*>(error.get());
+    if(exptr)
+    {
+      const ExceptionConnection& ex = *exptr;
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+      if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
+      {
+        g_warning("Application::recreate_database(): Failed because connection to server failed even without specifying a database.");
+        return false;
+      }
+#ifndef GLIBMM_EXCEPTIONS_ENABLED
+    }
+#endif // !GLIBMM_EXCEPTIONS_ENABLED
+
+    //Otherwise continue, because we _expected_ connect() to fail if the db does not exist yet.
+  }
+
+
+  //Create the database: (This will show a connection dialog)
+  progress();
+  connection_pool->set_database( Glib::ustring() );
+  const bool db_created = create_database(document, db_name, document->get_database_title(), progress);
+
+  if(!db_created)
+  {
+    return false;
+  }
+  else
+    connection_pool->set_database(db_name); //Specify the new database when connecting from now on.
+
+  progress();
+
+  sharedptr<SharedConnection> sharedconnection;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+  {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    sharedconnection = connection_pool->connect();
+#else
+    sharedconnection = connection_pool->connect(error);
+    if(!error.get())
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+      connection_pool->set_database(db_name); //The database was successfully created, so specify it when connecting from now on.
+  }
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  catch(const ExceptionConnection& ex)
+  {
+#else
+  if(error.get())
+  {
+    const std::exception& ex = *error.get();
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+    g_warning("Application::recreate_database(): Failed to connect to the newly-created database.");
+    return false;
+  }
+
+  progress();
+
+  //Create each table:
+  Document::type_listTableInfo tables = document->get_tables();
+  for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
+  {
+    sharedptr<const TableInfo> table_info = *iter;
+
+    //Create SQL to describe all fields in this table:
+    Glib::ustring sql_fields;
+    Document::type_vec_fields fields = document->get_table_fields(table_info->get_name());
+
+    progress();
+    const bool table_creation_succeeded = create_table(table_info, fields);
+    progress();
+    if(!table_creation_succeeded)
+    {
+      g_warning("Application::recreate_database(): CREATE TABLE failed with the newly-created database.");
+      return false;
+    }
+  }
+
+  progress();
+  add_standard_tables(document); //Add internal, hidden, tables.
+
+  //Create the developer group, and make this user a member of it:
+  //If we got this far then the user must really have developer privileges already:
+  progress();
+  const bool test = add_standard_groups(document);
+  if(!test)
+    return false;
+
+  for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
+  {
+    sharedptr<const TableInfo> table_info = *iter;
+
+    //Add any example data to the table:
+    progress();
+
+    //try
+    //{
+      const bool table_insert_succeeded = insert_example_data(document, table_info->get_name());
+
+      if(!table_insert_succeeded)
+      {
+        g_warning("Application::recreate_database(): INSERT of example data failed with the newly-created database.");
+        return false;
+      }
+    //}
+    //catch(const std::exception& ex)
+    //{
+    //  std::cerr << "Application::recreate_database(): exception: " << ex.what() << std::endl;
+      //HandleError(ex);
+    //}
+
+  } //for(tables)
+
+  return true; //All tables created successfully.
+}
+
+
+SystemPrefs get_database_preferences(Document* document)
+{
+  //if(get_userlevel() == AppState::USERLEVEL_DEVELOPER)
+  //  add_standard_tables(document);
+
+  SystemPrefs result;
+
+  //Check that the user is allowed to even view this table:
+  //TODO_moved:
+  //Privileges table_privs = Glom::Privs::get_current_privs(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
+  //if(!table_privs.m_view)
+  //  return result;
+
+  const bool optional_org_logo = get_field_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME, GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO);
+
+  const Glib::ustring sql_query = "SELECT "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_NAME "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2 "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY "\", "
+      "\"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE "\""
+      + Glib::ustring(optional_org_logo ? ", \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\".\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO "\"" : "") +
+      " FROM \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\"";
+
+  int attempts = 0;
+  while(attempts < 2)
+  {
+    bool succeeded = true;
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
+      if(datamodel && (datamodel->get_n_rows() != 0))
+      {
+        result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0));
+        result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0));
+        result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0));
+        result.m_org_address_street2 = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(3, 0));
+        result.m_org_address_town = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(4, 0));
+        result.m_org_address_county = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(5, 0));
+        result.m_org_address_country = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(6, 0));
+        result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0));
+
+        //We need to be more clever about these column indexes if we add more new fields:
+        if(optional_org_logo)
+          result.m_org_logo = datamodel->get_value_at(8, 0);
+      }
+      else
+        succeeded = false;
+    }
+    catch(const Glib::Exception& ex)
+    {
+      std::cerr << "get_database_preferences(): exception: " << ex.what() << std::endl;
+      succeeded = false;
+    }
+    catch(const std::exception& ex)
+    {
+      std::cerr << "get_database_preferences(): exception: " << ex.what() << std::endl;
+      succeeded = false;
+    }
+    #else // GLIBMM_EXCEPTIONS_ENABLED
+    std::auto_ptr<Glib::Error> error;
+    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
+    if(datamodel && (datamodel->get_n_rows() != 0))
+    {
+      result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0, error));
+      result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0, error));
+      result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0, error));
+      result.m_org_address_street2 = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(3, 0, error));
+      result.m_org_address_town = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(4, 0, error));
+      result.m_org_address_county = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(5, 0, error));
+      result.m_org_address_country = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(6, 0, error));
+      result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0, error));
+
+      //We need to be more clever about these column indexes if we add more new fields:
+      if(optional_org_logo)
+        result.m_org_logo = datamodel->get_value_at(8, 0, error);
+    }
+    else
+      succeeded = false;
+
+    if (error.get())
+    {
+      std::cerr << "Error: " << error->what() << std::endl;
+      succeeded = false;
+    }
+    #endif
+    //Return the result, or try again:
+    if(succeeded)
+      return result;
+    else
+    {
+      add_standard_tables(document);
+      ++attempts; //Try again now that we have tried to create the table.
+    }
+  }
+
+  return result;
+}
+
+
+void set_database_preferences(Document* document, const SystemPrefs& prefs)
+{
+  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+  params->add_holder("name", prefs.m_name);
+  params->add_holder("street", prefs.m_org_address_street);
+  params->add_holder("street2", prefs.m_org_address_street2);
+  params->add_holder("town", prefs.m_org_address_town);
+  params->add_holder("county", prefs.m_org_address_county);
+  params->add_holder("country", prefs.m_org_address_country);
+  params->add_holder("postcode", prefs.m_org_address_postcode);
+
+  //The logo field was introduced in a later version of Glom.
+  //If the user is not in developer mode then the new field has not yet been added:
+  Glib::ustring optional_part_logo;
+  if(get_field_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME, GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO))
+  {
+    params->add_holder("org_logo", prefs.m_org_logo);
+    optional_part_logo =  "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO "\" = ##org_logo::GDA_TYPE_BINARY, ";
+  }
+  const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" SET "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\" = ##name::gchararray, "
+      + optional_part_logo +
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET "\" = ##street::gchararray, "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2 "\" = ##street2::gchararray, "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN "\" = ##town::gchararray, "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY "\" = ##county::gchararray, "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY "\" = ##country::gchararray, "
+      "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE "\" = ##postcode::gchararray"
+      " WHERE \"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\" = 1";
+
+  bool test = false;
+  test = query_execute(sql_query, params);
+
+  if(!test)
+    std::cerr << "set_database_preferences(): UPDATE failed." << std::endl;
+
+  //Set some information in the document too, so we can use it to recreate the database:
+  document->set_database_title(prefs.m_name);
+}
+
+
+bool add_standard_tables(Document* document)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+  {
+    Document::type_vec_fields pref_fields;
+    sharedptr<TableInfo> prefs_table_info = Document::create_table_system_preferences(pref_fields);
+
+    //Name, address, etc:
+    if(!get_table_exists_in_database(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME))
+    {
+      const bool test = create_table(prefs_table_info, pref_fields);
+
+      if(test)
+      {
+        //Add the single record:
+        const bool test = query_execute("INSERT INTO \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" (\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\") VALUES (1)");
+        if(!test)
+          std::cerr << "add_standard_tables(): INSERT failed." << std::endl;
+
+        //Use the database title from the document, if there is one:
+        const Glib::ustring system_name = document->get_database_title();
+        if(!system_name.empty())
+        {
+          const bool test = query_execute("UPDATE \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" SET  " "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\" = '" + system_name + "' WHERE \"" GLOM_STANDARD_TABLE_PREFS_FIELD_ID "\" = 1");
+          if(!test)
+            std::cerr << "add_standard_tables(): UPDATE failed." << std::endl;
+        }
+      }
+      else
+      {
+        g_warning("add_standard_tables(): create_table(prefs) failed.");
+        return false;
+      }
+    }
+    else
+    {
+      //Make sure that it has all the fields it should have,
+      //because we sometimes add some in new Glom versions:
+      create_table_add_missing_fields(prefs_table_info, pref_fields);
+    }
+
+    //Auto-increment next values:
+    if(!get_table_exists_in_database(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME))
+    {
+      sharedptr<TableInfo> table_info(new TableInfo());
+      table_info->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
+      table_info->set_title("System: Auto Increments"); //TODO: Provide standard translations.
+      table_info->m_hidden = true;
+
+      Document::type_vec_fields fields;
+
+      sharedptr<Field> primary_key(new Field()); //It's not used, because there's only one record, but we must have one.
+      primary_key->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_ID);
+      primary_key->set_glom_type(Field::TYPE_NUMERIC);
+      fields.push_back(primary_key);
+
+      sharedptr<Field> field_table_name(new Field());
+      field_table_name->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME);
+      field_table_name->set_glom_type(Field::TYPE_TEXT);
+      fields.push_back(field_table_name);
+
+      sharedptr<Field> field_field_name(new Field());
+      field_field_name->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME);
+      field_field_name->set_glom_type(Field::TYPE_TEXT);
+      fields.push_back(field_field_name);
+
+      sharedptr<Field> field_next_value(new Field());
+      field_next_value->set_name(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE);
+      field_next_value->set_glom_type(Field::TYPE_TEXT);
+      fields.push_back(field_next_value);
+
+      const bool test = create_table(table_info, fields);
+      if(!test)
+      {
+        g_warning("add_standard_tables(): create_table(autoincrements) failed.");
+        return false;
+      }
+
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  catch(const Glib::Exception& ex)
+  {
+    std::cerr << "add_standard_tables(): caught exception: " << ex.what() << std::endl;
+    return false;
+  }
+  catch(const std::exception& ex)
+  {
+    std::cerr << "add_standard_tables(): caught exception: " << ex.what() << std::endl;
+    return false;
+  }
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+}
+
+bool add_standard_groups(Document* document)
+{
+  //Add the glom_developer group if it does not exist:
+  const Glib::ustring devgroup = GLOM_STANDARD_GROUP_NAME_DEVELOPER;
+
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "add_standard_groups(): No connection yet." << std::endl;
+  }
+
+  // If the connection doesn't support users we can skip this step
+  if(gda_connection->supports_feature(Gnome::Gda::CONNECTION_FEATURE_USERS))
+  {
+    const type_vec_strings vecGroups = Glom::Privs::get_database_groups();
+    type_vec_strings::const_iterator iterFind = std::find(vecGroups.begin(), vecGroups.end(), devgroup);
+    if(iterFind == vecGroups.end())
+    {
+      //The "SUPERUSER" here has no effect because SUPERUSER is not "inherited" to member users.
+      //But let's keep it to make the purpose of this group obvious.
+      bool test = query_execute("CREATE GROUP \"" GLOM_STANDARD_GROUP_NAME_DEVELOPER "\" WITH SUPERUSER");
+      if(!test)
+      {
+        std::cerr << "Glom add_standard_groups(): CREATE GROUP failed when adding the developer group." << std::endl;
+        return false;
+      }
+
+      //Make sure the current user is in the developer group.
+      //(If he is capable of creating these groups then he is obviously a developer, and has developer rights on the postgres server.)
+      const Glib::ustring current_user = ConnectionPool::get_instance()->get_user();
+      Glib::ustring strQuery = "ALTER GROUP \"" GLOM_STANDARD_GROUP_NAME_DEVELOPER "\" ADD USER \"" + current_user + "\"";
+      test = query_execute(strQuery);
+      if(!test)
+      {
+        std::cerr << "Glom add_standard_groups(): ALTER GROUP failed when adding the user to the developer group." << std::endl;
+        return false;
+      }
+
+      std::cout << "DEBUG: Added user " << current_user << " to glom developer group on postgres server." << std::endl;
+
+      Privileges priv_devs;
+      priv_devs.m_view = true;
+      priv_devs.m_edit = true;
+      priv_devs.m_create = true;
+      priv_devs.m_delete = true;
+
+      Document::type_listTableInfo table_list = document->get_tables(true /* including system prefs */);
+
+      for(Document::type_listTableInfo::const_iterator iter = table_list.begin(); iter != table_list.end(); ++iter)
+      {
+        sharedptr<const TableInfo> table_info = *iter;
+        if(table_info)
+        {
+          const Glib::ustring table_name = table_info->get_name();
+          if(get_table_exists_in_database(table_name)) //Maybe the table has not been created yet.
+            Glom::Privs::set_table_privileges(devgroup, table_name, priv_devs, true /* developer privileges */);
+        }
+      }
+
+      //Make sure that it is in the database too:
+      GroupInfo group_info;
+      group_info.set_name(GLOM_STANDARD_GROUP_NAME_DEVELOPER);
+      group_info.m_developer = true;
+      document->set_group(group_info);
+    }
+  }
+  else
+  {
+    std::cout << "DEBUG: Connection does not support users" << std::endl;
+  }
+
+  return true;
+}
+
+
+namespace { //anonymous
+
+//If the string has quotes around it, remove them
+static Glib::ustring remove_quotes(const Glib::ustring& str)
+{
+  const gchar* quote = "\"";
+  const Glib::ustring::size_type posQuoteStart = str.find(quote);
+  if(posQuoteStart != 0)
+    return str;
+
+  const Glib::ustring::size_type size = str.size();
+  const Glib::ustring::size_type posQuoteEnd = str.find(quote, 1);
+  if(posQuoteEnd != (size - 1))
+    return str;
+
+  return str.substr(1, size - 2);
+}
+
+} //anonymous namespace
+
+static bool meta_table_column_is_primary_key(GdaMetaTable* meta_table, const Glib::ustring column_name)
+{
+  if(!meta_table)
+    return false;
+
+  for(GSList* item = meta_table->columns; item != 0; item = item->next)
+  {
+    GdaMetaTableColumn* column = GDA_META_TABLE_COLUMN(item->data);
+    if(!column)
+      continue;
+
+    if(column->column_name && (column_name == remove_quotes(column->column_name)))
+      return column->pkey;
+  }
+
+  return false;
+}
+
+bool handle_error()
+{
+  return ConnectionPool::handle_error_cerr_only();
+}
+
+void handle_error(const Glib::Exception& ex)
+{
+  std::cerr << "Internal Error (handle_error()): exception type=" << typeid(ex).name() << ", ex.what()=" << ex.what() << std::endl;
+
+  //TODO_Moved:
+  //Gtk::MessageDialog dialog(Utils::bold_message(_("Internal error")), true, Gtk::MESSAGE_WARNING );
+  //dialog.set_secondary_text(ex.what());
+  //TODO: dialog.set_transient_for(*get_application());
+  //dialog.run();
+}
+
+void handle_error(const std::exception& ex)
+{
+  std::cerr << "Internal Error (handle_error()): exception type=" << typeid(ex).name() << ", ex.what()=" << ex.what() << std::endl;
+
+ //TODO_Moved:
+#ifdef GLOM_ENABLE_MAEMO
+  //Hildon::Note dialog(Hildon::NOTE_TYPE_INFORMATION, ex.what());
+#else
+  //Gtk::MessageDialog dialog(Utils::bold_message(_("Internal error")), true, Gtk::MESSAGE_WARNING );
+  //dialog.set_secondary_text(ex.what());
+  //TODO: dialog.set_transient_for(*get_application());
+#endif
+  //dialog.run();
+}
+
+
+bool get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+  type_vec_fields vecFields = get_fields_for_table_from_database(table_name);
+  type_vec_fields::const_iterator iterFind = std::find_if(vecFields.begin(), vecFields.end(), predicate_FieldHasName<Field>(field_name));
+  return iterFind != vecFields.end();
+}
+
+type_vec_fields get_fields_for_table_from_database(const Glib::ustring& table_name, bool /* including_system_fields */)
+{
+  type_vec_fields result;
+
+  if(table_name.empty())
+    return result;
+
+  // These are documented here:
+  // http://library.gnome.org/devel/libgda-4.0/3.99/connection.html#GdaConnectionMetaTypeHead
+  enum GlomGdaDataModelFieldColumns
+  {
+    DATAMODEL_FIELDS_COL_NAME = 0,
+    DATAMODEL_FIELDS_COL_TYPE = 1,
+    DATAMODEL_FIELDS_COL_GTYPE = 2,
+    DATAMODEL_FIELDS_COL_SIZE = 3,
+    DATAMODEL_FIELDS_COL_SCALE = 4,
+    DATAMODEL_FIELDS_COL_NOTNULL = 5,
+    DATAMODEL_FIELDS_COL_DEFAULTVALUE = 6,
+    DATAMODEL_FIELDS_COL_EXTRA = 6 // Could be auto-increment
+  };
+
+  //TODO: BusyCursor busy_cursor(get_application());
+
+  {
+    Glib::RefPtr<Gnome::Gda::Connection> connection = get_connection();
+    if(!connection)
+    {
+      std::cerr << "get_fields_for_table_from_database(): connection is null" << std::endl;
+      return result;
+    }
+    
+    Glib::RefPtr<Gnome::Gda::Holder> holder_table_name = Gnome::Gda::Holder::create(G_TYPE_STRING, "name");
+    gchar* quoted_table_name_c = gda_meta_store_sql_identifier_quote(table_name.c_str(), connection->gobj());
+    g_assert(quoted_table_name_c);
+    Glib::ustring quoted_table_name(quoted_table_name_c);
+    g_free (quoted_table_name_c);
+    quoted_table_name_c = 0;
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    holder_table_name->set_value(quoted_table_name);
+#else
+    std::auto_ptr<Glib::Error> error;
+    holder_table_name->set_value(quoted_table_name, error);
+#endif
+
+    std::list< Glib::RefPtr<Gnome::Gda::Holder> > holder_list;
+    holder_list.push_back(holder_table_name);
+
+    Glib::RefPtr<Gnome::Gda::DataModel> data_model_fields;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      data_model_fields = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list);
+    }
+    catch(const Gnome::Gda::MetaStoreError& ex)
+    {
+      std::cerr << "get_fields_for_table_from_database(): MetaStoreError: " << ex.what() << std::endl;
+    }
+    catch(const Glib::Error& ex)
+    {
+      std::cerr << "get_fields_for_table_from_database(): Error: " << ex.what() << std::endl;
+    }
+#else
+    data_model_fields = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list, error);
+
+    // Ignore error, data_model_fields presence is checked below
+#endif
+
+
+    if(!data_model_fields)
+    {
+      std::cerr << "get_fields_for_table_from_database(): libgda reported empty fields schema data_model for the table." << std::endl;
+    }
+    else if(data_model_fields->get_n_columns() == 0)
+    {
+      std::cerr << "get_fields_for_table_from_database(): libgda reported 0 fields for the table." << std::endl;
+    }
+    else if(data_model_fields->get_n_rows() == 0)
+    {
+      g_warning("get_fields_for_table_from_database(): table_name=%s, data_model_fields->get_n_rows() == 0: The table probably does not exist in the specified database.", table_name.c_str());
+    }
+    else
+    {
+      //We also use the GdaMetaTable to discover primary keys.
+      //Both these libgda APIs are awful, and it's awful that we must use two APIs. murrayc.
+      Glib::RefPtr<Gnome::Gda::MetaStore> store = connection->get_meta_store();
+      Glib::RefPtr<Gnome::Gda::MetaStruct> metastruct =
+        Gnome::Gda::MetaStruct::create(store, Gnome::Gda::META_STRUCT_FEATURE_NONE);
+      GdaMetaDbObject* meta_dbobject = 0;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+      try
+      {
+        meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
+          Gnome::Gda::Value(), /* catalog */
+          Gnome::Gda::Value(), /* schema */
+          Gnome::Gda::Value(quoted_table_name)); //It's a static instance inside the MetaStore.
+      }
+      catch(const Glib::Error& ex)
+      {
+        handle_error(ex);
+        //TODO: Really fail.
+      }
+#else
+      std::auto_ptr<Glib::Error> ex;
+      meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
+        Gnome::Gda::Value(), /* catalog */
+        Gnome::Gda::Value(), /* schema */
+        Gnome::Gda::Value(quoted_table_name), ex); //It's a static instance inside the MetaStore.
+       if(error.get())
+       {
+         handle_error(*ex);
+       }
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+      GdaMetaTable* meta_table = GDA_META_TABLE(meta_dbobject);
+
+      //Examine each field:
+      guint row = 0;
+      const guint rows_count = data_model_fields->get_n_rows();
+      while(row < rows_count)
+      {
+        Glib::RefPtr<Gnome::Gda::Column> field_info = Gnome::Gda::Column::create();
+
+        //Get the field name:
+#ifdef GLIBMM_EXCEPTIONS_ENABLED //TODO: Actually catch exceptions.
+        Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row);
+#else
+        std::auto_ptr<Glib::Error> value_error;
+        Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row, value_error);
+#endif
+        if(value_name.get_value_type() ==  G_TYPE_STRING)
+        {
+          if(value_name.get_string().empty())
+            g_warning("get_fields_for_table_from_database(): value_name is empty.");
+
+          Glib::ustring field_name = value_name.get_string(); //TODO: get_string() is a dodgy choice. murrayc.
+          field_name = remove_quotes(field_name);
+          field_info->set_name(field_name);
+          //std::cout << "  debug: field_name=" << field_name << std::endl;
+        }
+
+        //Get the field type:
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+        Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row);
+#else
+        Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row, value_error);
+#endif
+        if(value_fieldtype.get_value_type() ==  G_TYPE_STRING)
+        {
+          const Glib::ustring type_string = value_fieldtype.get_string();
+          const GType gdatype = gda_g_type_from_string(type_string.c_str());
+          field_info->set_g_type(gdatype);
+        }
+
+
+        //Get the default value:
+        /* libgda does not return this correctly yet. TODO: check bug http://bugzilla.gnome.org/show_bug.cgi?id=143576
+        Gnome::Gda::Value value_defaultvalue = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_DEFAULTVALUE, row);
+        if(value_defaultG_VALUE_TYPE(value.gobj()) ==  G_TYPE_STRING)
+          field_info->set_default_value(value_defaultvalue);
+        */
+
+        //Get whether it can be null:
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+        Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row);
+#else
+        Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row, value_error);
+#endif
+        if(value_notnull.get_value_type() ==  G_TYPE_BOOLEAN)
+          field_info->set_allow_null(value_notnull.get_boolean());
+
+
+        sharedptr<Field> field = sharedptr<Field>::create(); //TODO: Get glom-specific information from the document?
+        field->set_field_info(field_info);
+
+
+        //Get whether it is a primary key:
+        field->set_primary_key(
+          meta_table_column_is_primary_key(meta_table, field_info->get_name()) );
+
+        result.push_back(field);
+
+        ++row;
+      }
+    }
+  }
+
+  if(result.empty())
+  {
+    //g_warning("get_fields_for_table_from_database(): returning empty result.");
+  }
+
+  //Hide system fields.
+  type_vec_fields::iterator iterFind = std::find_if(result.begin(), result.end(), predicate_FieldHasName<Field>(GLOM_STANDARD_FIELD_LOCK));
+  if(iterFind != result.end())
+    result.erase(iterFind);
+
+  return result;
+}
+
+//TODO_Performance: Avoid calling this so often.
+//TODO: Put this in libgdamm.
+type_vec_strings get_table_names_from_database(bool ignore_system_tables)
+{
+  type_vec_strings result;
+
+  {
+    Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+
+    Glib::RefPtr<Gnome::Gda::DataModel> data_model_tables;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      data_model_tables = gda_connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_TABLES);
+    }
+    catch(const Gnome::Gda::MetaStoreError& ex)
+    {
+      std::cerr << "get_table_names_from_database(): MetaStoreError: " << ex.what() << std::endl;
+    }
+    catch(const Glib::Error& ex)
+    {
+      std::cerr << "get_table_names_from_database(): Error: " << ex.what() << std::endl;
+    }
+#else
+    std::auto_ptr<Glib::Error> error;
+    data_model_tables = gda_connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_TABLES, error);
+    // Ignore error, data_model_tables presence is checked below
+#endif
+
+    if(data_model_tables && (data_model_tables->get_n_columns() == 0))
+    {
+      std::cerr << "get_table_names_from_database(): libgda reported 0 tables for the database." << std::endl;
+    }
+    else if(data_model_tables)
+    {
+      //std::cout << "debug: data_model_tables refcount=" << G_OBJECT(data_model_tables->gobj())->ref_count << std::endl;
+      const int rows = data_model_tables->get_n_rows();
+      for(int i = 0; i < rows; ++i)
+      {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+        const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i);
+#else
+        const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i, error);
+#endif
+        //Get the table name:
+        Glib::ustring table_name;
+        if(G_VALUE_TYPE(value.gobj()) ==  G_TYPE_STRING)
+        {
+          table_name = value.get_string();
+
+          //The table names have quotes sometimes. See http://bugzilla.gnome.org/show_bug.cgi?id=593154
+          table_name = remove_quotes(table_name);
+
+          //TODO: Unescape the string with gda_server_provider_unescape_string()?
+
+          //std::cout << "DEBUG: Found table: " << table_name << std::endl;
+
+          if(ignore_system_tables)
+          {
+            //Check whether it's a system table:
+            const Glib::ustring prefix = "glom_system_";
+            const Glib::ustring table_prefix = table_name.substr(0, prefix.size());
+            if(table_prefix == prefix)
+              continue;
+          }
+
+          //Ignore the pga_* tables that pgadmin adds when you use it:
+          if(table_name.substr(0, 4) == "pga_")
+            continue;
+
+          //Ignore the pg_* tables that something (Postgres? libgda?) adds:
+          //Not needed now that this was fixed again in libgda-4.0.
+          //if(table_name.substr(0, 14) == "pg_catalog.pg_")
+          //  continue;
+
+          //Ignore the information_schema tables that something (libgda?) adds:
+          //Not needed now that this was fixed again in libgda-4.0.
+          //if(table_name.substr(0, 23) == "information_schema.sql_")
+          //  continue;
+
+          result.push_back(table_name);
+        }
+      }
+    }
+  }
+
+  return result;
+}
+
+bool get_table_exists_in_database(const Glib::ustring& table_name)
+{
+  //TODO_Performance
+
+  type_vec_strings tables = get_table_names_from_database();
+  type_vec_strings::const_iterator iterFind = std::find(tables.begin(), tables.end(), table_name);
+  return (iterFind != tables.end());
+}
+
+
+bool create_table_with_default_fields(Document* document, const Glib::ustring& table_name)
+{
+  if(table_name.empty())
+    return false;
+
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "create_table_with_default_fields(): No connection yet." << std::endl;
+    return false;
+  }
+
+  bool created = false;
+
+  //Primary key:
+  sharedptr<Field> field_primary_key(new Field());
+  field_primary_key->set_name(table_name + "_id");
+  field_primary_key->set_title(table_name + " ID");
+  field_primary_key->set_primary_key();
+  field_primary_key->set_auto_increment();
+
+  Glib::RefPtr<Gnome::Gda::Column> field_info = field_primary_key->get_field_info();
+  field_info->set_allow_null(false);
+  field_primary_key->set_field_info(field_info);
+
+  field_primary_key->set_glom_type(Field::TYPE_NUMERIC);
+  //std::cout << "field_primary_key->get_auto_increment():" << field_primary_key->get_auto_increment() << std::endl;
+
+  type_vec_fields fields;
+  fields.push_back(field_primary_key);
+
+  //Description:
+  sharedptr<Field> field_description(new Field());
+  field_description->set_name("description");
+  field_description->set_title(_("Description")); //Use a translation, because the original locale will be marked as non-English if the current locale is non-English.
+  field_description->set_glom_type(Field::TYPE_TEXT);
+  fields.push_back(field_description);
+
+  //Comments:
+  sharedptr<Field> field_comments(new Field());
+  field_comments->set_name("comments");
+  field_comments->set_title(_("Comments"));
+  field_comments->set_glom_type(Field::TYPE_TEXT);
+  field_comments->m_default_formatting.set_text_format_multiline();
+  fields.push_back(field_comments);
+
+  sharedptr<TableInfo> table_info(new TableInfo());
+  table_info->set_name(table_name);
+  table_info->set_title( Utils::title_from_string( table_name ) ); //Start with a title that might be appropriate.
+
+  created = create_table(table_info, fields);
+
+    //Create a table with 1 "ID" field:
+   //MSYQL:
+    //query_execute( "CREATE TABLE \"" + table_name + "\" (" + primary_key_name + " INT NOT NULL AUTO_INCREMENT PRIMARY KEY)" );
+    //query_execute( "INSERT INTO \"" + table_name + "\" VALUES (0)" );
+
+    //PostgresSQL:
+    //query_execute( "CREATE TABLE \"" + table_name + "\" (\"" + primary_key_name + "\" serial NOT NULL  PRIMARY KEY)" );
+
+    //query_execute( "CREATE TABLE \"" + table_name + "\" (" +
+    //  field_primary_key->get_name() + " numeric NOT NULL  PRIMARY KEY," +
+    //  extra_field_description + "varchar, " +
+    //  extra_field_comments + "varchar" +
+    //  ")" );
+
+  if(created)
+  {
+    //Save the changes in the document:
+    if(document)
+    {
+      document->add_table(table_info);
+      document->set_table_fields(table_info->get_name(), fields);
+    }
+  }
+
+  return created;
+}
+bool create_table(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields_in)
+{
+  //std::cout << "create_table(): " << table_info->get_name() << ", title=" << table_info->get_title() << std::endl;
+
+  bool table_creation_succeeded = false;
+
+
+  Document::type_vec_fields fields = fields_in;
+
+  //Create the standard field too:
+  //(We don't actually use this yet)
+  if(std::find_if(fields.begin(), fields.end(), predicate_FieldHasName<Field>(GLOM_STANDARD_FIELD_LOCK)) == fields.end())
+  {
+    sharedptr<Field> field = sharedptr<Field>::create();
+    field->set_name(GLOM_STANDARD_FIELD_LOCK);
+    field->set_glom_type(Field::TYPE_TEXT);
+    fields.push_back(field);
+  }
+
+  //Create SQL to describe all fields in this table:
+  Glib::ustring sql_fields;
+  for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+  {
+    //Create SQL to describe this field:
+    sharedptr<Field> field = *iter;
+
+    //The field has no gda type, so we set that:
+    //This usually comes from the database, but that's a bit strange.
+    Glib::RefPtr<Gnome::Gda::Column> info = field->get_field_info();
+    info->set_g_type( Field::get_gda_type_for_glom_type(field->get_glom_type()) );
+    field->set_field_info(info); //TODO_Performance
+
+    Glib::ustring sql_field_description = "\"" + field->get_name() + "\" " + field->get_sql_type();
+
+    if(field->get_primary_key())
+      sql_field_description += " NOT NULL  PRIMARY KEY";
+
+    //Append it:
+    if(!sql_fields.empty())
+      sql_fields += ", ";
+
+    sql_fields += sql_field_description;
+  }
+
+  if(sql_fields.empty())
+  {
+    g_warning("Base_Db::create_table::create_table(): sql_fields is empty.");
+  }
+
+  //Actually create the table
+  try
+  {
+    //TODO: Escape the table name?
+    //TODO: Use GDA_SERVER_OPERATION_CREATE_TABLE instead?
+    table_creation_succeeded = query_execute( "CREATE TABLE \"" + table_info->get_name() + "\" (" + sql_fields + ");" );
+    if(!table_creation_succeeded)
+      std::cerr << "create_table(): CREATE TABLE failed." << std::endl;
+  }
+  catch(const ExceptionConnection& ex)
+  {
+    table_creation_succeeded = false;
+  }
+
+  if(table_creation_succeeded)
+  {
+    // Update the libgda meta store, so that get_fields_for_table_from_database()
+    // returns the fields correctly for the new table.
+    update_gda_metastore_for_table(table_info->get_name());
+
+    // TODO: Maybe we should create the table directly via libgda instead of
+    // executing an SQL query ourselves, so that libgda has the chance to
+    // do this meta store update automatically.
+    // (Yes, generally it would be nice to use libgda API instead of generating SQL. murrayc)
+  }
+
+  return table_creation_succeeded;
+}
+
+bool create_table_add_missing_fields(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields)
+{
+  const Glib::ustring table_name = table_info->get_name();
+
+  for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+  {
+    sharedptr<const Field> field = *iter;
+    if(!get_field_exists_in_database(table_name, field->get_name()))
+    {
+      const bool test = add_column(table_name, field, 0); /* TODO: parent_window */
+      if(!test)
+       return test;
+    }
+  }
+
+  return true;
+}
+
+
+bool add_column(const Glib::ustring& table_name, const sharedptr<const Field>& field, Gtk::Window* /* parent_window */)
+{
+  ConnectionPool* connection_pool = ConnectionPool::get_instance();
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    connection_pool->add_column(table_name, field);
+  }
+  catch(const Glib::Error& ex)
+  {
+#else
+  std::auto_ptr<Glib::Error> error;
+  connection_pool->add_column(table_name, field, error);
+  if(error.get())
+  {
+    const Glib::Error& ex = *error;
+#endif
+    handle_error(ex);
+//    Gtk::MessageDialog window(*parent_window, Utils::bold_message(ex.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
+//    window.run();
+    return false;
+  }
+
+  return true;
+}
+
+bool drop_column(const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+  ConnectionPool* connection_pool = ConnectionPool::get_instance();
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    return connection_pool->drop_column(table_name, field_name);
+  }
+  catch(const Glib::Error& ex)
+  {
+#else
+  std::auto_ptr<Glib::Error> error;
+  connection_pool->add_column(table_name, field_name, error);
+  if(error.get())
+  {
+    const Glib::Error& ex = *error;
+#endif
+    handle_error(ex);
+//    Gtk::MessageDialog window(*parent_window, Utils::bold_message(ex.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
+//    window.run();
+    return false;
+  }
+
+  return true;
+}
+
+Gnome::Gda::Value get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+  const Gnome::Gda::Value result = DbUtils::auto_increment_insert_first_if_necessary(table_name, field_name);
+  double num_result = Conversions::get_double_for_gda_value_numeric(result);
+
+
+  //Increment the next_value:
+  ++num_result;
+  const Gnome::Gda::Value next_value = Conversions::parse_value(num_result);
+  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+  params->add_holder("table_name", table_name);
+  params->add_holder("field_name", field_name);
+  params->add_holder("next_value", next_value);
+  const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" SET "
+      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE "\" = ##next_value::gchararray"
+      " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = ##table_name::gchararray AND "
+            "\""  GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = ##field_name::gchararray";
+
+  const bool test = query_execute(sql_query, params);
+  if(!test)
+    std::cerr << "get_next_auto_increment_value(): Increment failed." << std::endl;
+
+  return result;
+}
+
+Gnome::Gda::Value auto_increment_insert_first_if_necessary(const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+  Gnome::Gda::Value value;
+
+  //Check that the user is allowd to view and edit this table:
+  Privileges table_privs = Privs::get_current_privs(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
+  if(!table_privs.m_view || !table_privs.m_edit)
+  {
+    //This should not happen:
+    std::cerr << "Glom: auto_increment_insert_first_if_necessary(): The current user may not edit the autoincrements table. Any user who has create rights for a table should have edit rights to the autoincrements table." << std::endl;
+  }
+  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+  params->add_holder("table_name", table_name);
+  params->add_holder("field_name", field_name);
+
+  const Glib::ustring sql_query = "SELECT \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\".\"next_value\" FROM \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\""
+   " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = ##table_name::gchararray AND "
+          "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = ##field_name::gchararray";
+
+  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query, params);
+  if(!datamodel || (datamodel->get_n_rows() == 0))
+  {
+    //Start with zero:
+
+    //Insert the row if it's not there.
+    const Glib::ustring sql_query = "INSERT INTO \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" ("
+      GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME ", " GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME ", " GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE
+      ") VALUES (##table_name::gchararray, ##field_name::gchararray, 0)";
+
+    const bool test = query_execute(sql_query, params);
+    if(!test)
+      std::cerr << "auto_increment_insert_first_if_necessary(): INSERT of new row failed." << std::endl;
+
+    //GdaNumeric is a pain, so we take a short-cut:
+    bool success = false;
+    value = Conversions::parse_value(Field::TYPE_NUMERIC, "0", success, true /* iso_format */);
+  }
+  else
+  {
+    //Return the value so that a calling function does not need to do a second SELECT.
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0);
+#else
+    std::auto_ptr<Glib::Error> value_error;
+    const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0, value_error);
+#endif
+    //But the caller wants a numeric value not a text value
+    //(our system_autoincrements table has it as text, for future flexibility):
+    const std::string actual_value_text = actual_value.get_string();
+    bool success = false;
+    value = Conversions::parse_value(Field::TYPE_NUMERIC, actual_value_text, success, true /* iso_format */);
+  }
+
+  //std::cout << "auto_increment_insert_first_if_necessary: returning value of type=" << value.get_value_type() << std::endl;
+  return value;
+}
+
+/** Set the next auto-increment value in the glom system table, by examining all current values.
+ * Use this, for instance, after importing rows.
+ * Add a row for this field in the system table if it does not exist already.
+ */
+static void recalculate_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+  //Make sure that the row exists in the glom system table:
+  auto_increment_insert_first_if_necessary(table_name, field_name);
+
+  //Get the max key value in the database:
+  const Glib::ustring sql_query = "SELECT MAX(\"" + table_name + "\".\"" + field_name + "\") FROM \"" + table_name + "\"";
+  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
+  if(datamodel && datamodel->get_n_rows() && datamodel->get_n_columns())
+  {
+    //Increment it:
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0); // A GdaNumeric.
+#else
+    std::auto_ptr<Glib::Error> error;
+    const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0, error); // A GdaNumeric.
+#endif
+    double num_max = Conversions::get_double_for_gda_value_numeric(value_max);
+    ++num_max;
+
+    //Set it in the glom system table:
+    const Gnome::Gda::Value next_value = Conversions::parse_value(num_max);
+    const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\" SET "
+      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE "\" = " + next_value.to_string() + //TODO: Don't use to_string().
+      " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = '" + table_name + "' AND "
+      "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = '" + field_name + "'";
+
+    const bool test = query_execute(sql_query);
+    if(!test)
+      std::cerr << "recalculate_next_auto_increment_value(): UPDATE failed." << std::endl;
+  }
+  else
+    std::cerr << "recalculate_next_auto_increment_value(): SELECT MAX() failed." << std::endl;
+}
+
+bool insert_example_data(Document* document, const Glib::ustring& table_name)
+{
+  //TODO_Performance: Avoid copying:
+  const Document::type_example_rows example_rows = document->get_table_example_data(table_name);
+  if(example_rows.empty())
+  {
+    //std::cout << "debug: insert_example_data(): No example data available." << std::endl;
+    return true;
+  }
+
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "insert_example_data(): connection is null" << std::endl;
+    return false;
+  }
+
+  //std::cout << "debug: inserting example_rows for table: " << table_name << std::endl;
+
+  bool insert_succeeded = true;
+
+
+  //Get field names:
+  Document::type_vec_fields vec_fields = document->get_table_fields(table_name);
+
+  //Actually insert the data:
+  //std::cout << "  debug: insert_example_data(): number of rows of data: " << vec_rows.size() << std::endl;
+
+  //std::cout << "DEBUG: example_row size = " << example_rows.size() << std::endl;
+
+  for(Document::type_example_rows::const_iterator iter = example_rows.begin(); iter != example_rows.end(); ++iter)
+  {
+    //Check that the row contains the correct number of columns.
+    //This check will slow this down, but it seems useful:
+    //TODO: This can only work if we can distinguish , inside "" and , outside "":
+    const Document::type_row_data& row_data = *iter;
+    Glib::ustring strNames;
+    Glib::ustring strVals;
+    if(row_data.empty())
+      break;
+
+    //std::cout << "DEBUG: row_data size = " << row_data.size() << ", (fields size= " << vec_fields.size() << " )" << std::endl;
+
+    Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+    Glom::ParameterNameGenerator generator;
+    for(unsigned int i = 0; i < row_data.size(); ++i) //TODO_Performance: Avoid calling size() so much.
+    {
+      //std::cout << "  DEBUG: i=" << i << ", row_data.size()=" << row_data.size() << std::endl;
+
+      if(i > 0)
+      {
+        strVals += ", ";
+        strNames += ", ";
+      }
+
+      sharedptr<Field> field = vec_fields[i];
+      if(!field)
+      {
+        std::cerr << "insert_example_data(): field was null for field num=" << i << std::endl;
+        break;
+      }
+
+      strNames += field->get_name();
+
+      Gnome::Gda::Value value = row_data[i];
+      //std::cout << "  DEBUG: example: field=" << field->get_name() << ", value=" << value.to_string() << std::endl;
+
+      //Add a SQL parameter for the value:
+      guint id = 0;
+      const Field::glom_field_type glom_type = field->get_glom_type();
+      Glib::RefPtr<Gnome::Gda::Holder> holder =
+        Gnome::Gda::Holder::create( Field::get_gda_type_for_glom_type(glom_type),
+          generator.get_next_name(id));
+
+      holder->set_not_null(false);
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+      holder->set_value_as_value(value);
+#else
+      std::auto_ptr<Glib::Error> holder_error;
+      holder->set_value_as_value(value, holder_error);
+#endif
+      params->add_holder(holder);
+
+      strVals += "##" + generator.get_name_from_id(id) + "::" + vec_fields[i]->get_gda_type_name();
+    }
+
+    //Create and parse the SQL query:
+    //After this, the Parser will know how many SQL parameters there are in
+    //the query, and allow us to set their values.
+    const Glib::ustring strQuery = "INSERT INTO \"" + table_name + "\" (" + strNames + ") VALUES (" + strVals + ")";
+    insert_succeeded = query_execute(strQuery, params);
+    if(!insert_succeeded)
+      break;
+  }
+
+  for(Document::type_vec_fields::const_iterator iter = vec_fields.begin(); iter != vec_fields.end(); ++iter)
+  {
+    if((*iter)->get_auto_increment())
+      recalculate_next_auto_increment_value(table_name, (*iter)->get_name());
+  }
+  return insert_succeeded;
+}
+
+//static:
+Glib::RefPtr<Gnome::Gda::DataModel> query_execute_select(const Glib::ustring& strQuery,
+                                                                  const Glib::RefPtr<Gnome::Gda::Set>& params)
+{
+  Glib::RefPtr<Gnome::Gda::DataModel> result;
+
+  //TODO: BusyCursor busy_cursor(get_app_window());
+
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "query_execute_select(): No connection yet." << std::endl;
+    return result;
+  }
+
+  Glib::RefPtr<Gnome::Gda::SqlParser> parser = gda_connection->create_parser();
+
+  Glib::RefPtr<Gnome::Gda::Statement> stmt;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    stmt = parser->parse_string(strQuery);
+  }
+  catch(const Gnome::Gda::SqlParserError& ex)
+  {
+    std::cout << "debug: query_execute_select(): SqlParserError: exception from parse_string(): " << ex.what() << std::endl;
+  }
+#else
+  std::auto_ptr<Glib::Error> ex;
+  stmt = parser->parse_string(strQuery, ex);
+  if(error.get())
+     std::cout << "debug: query_execute_select(): SqlParserError: exception from parse_string(): " << error->what() << std::endl;
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+
+
+  //Debug output:
+  if(stmt && ConnectionPool::get_instance()->get_show_debug_output())
+  {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      const Glib::ustring full_query = stmt->to_sql(params);
+      std::cout << "Debug: query_execute_select():  " << full_query << std::endl;
+    }
+    catch(const Glib::Exception& ex)
+    {
+      std::cout << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
+    }
+#else
+      const Glib::ustring full_query = stmt->to_sql(params, ex);
+      std::cout << "Debug: query_execute_select():  " << full_query << std::endl;
+      if (ex.get())
+        std::cout << "Debug: query string could not be converted to std::cout: " << ex->what() << std::endl;
+
+#endif
+  }
+
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    result = gda_connection->statement_execute_select(stmt, params);
+  }
+  catch(const Gnome::Gda::ConnectionError& ex)
+  {
+    std::cout << "debug: query_execute_select(): ConnectionError: exception from statement_execute_select(): " << ex.what() << std::endl;
+  }
+  catch(const Gnome::Gda::ServerProviderError& ex)
+  {
+    std::cout << "debug: query_execute_select(): ServerProviderError: exception from statement_execute_select(): code=" << ex.code() << "message=" << ex.what() << std::endl;
+  }
+  catch(const Glib::Error& ex)
+  {
+    std::cout << "debug: query_execute_select(): Error: exception from statement_execute_select(): " << ex.what() << std::endl;
+  }
+
+#else
+  result = gda_connection->statement_execute_select(stmt, params, ex);
+  if(ex.get())
+    std::cout << "debug: query_execute_select(): Glib::Error from statement_execute_select(): " << ex->what() << std::endl;
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+
+  if(!result)
+  {
+    std::cerr << "Glom  query_execute_select(): Error while executing SQL" << std::endl <<
+      "  " <<  strQuery << std::endl;
+    handle_error();
+  }
+
+  return result;
+}
+
+//static:
+bool query_execute(const Glib::ustring& strQuery, const Glib::RefPtr<Gnome::Gda::Set>& params)
+{
+  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = get_connection();
+  if(!gda_connection)
+  {
+    std::cerr << "query_execute(): No connection yet." << std::endl;
+    return false;
+  }
+
+  Glib::RefPtr<Gnome::Gda::SqlParser> parser = gda_connection->create_parser();
+  Glib::RefPtr<Gnome::Gda::Statement> stmt;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    stmt = parser->parse_string(strQuery);
+  }
+  catch(const Gnome::Gda::SqlParserError& error)
+  {
+    std::cerr << "DEBUG: BaseDB::query_execute: SqlParserError: " << error.what() << std::endl;
+    return false;
+  }
+#else
+  std::auto_ptr<Glib::Error> sql_error;
+  stmt = parser->parse_string(strQuery, sql_error);
+  if(sql_error.get())
+  {
+    std::cerr << "DEBUG: BaseDB::query_execute: SqlParserError:" << sql_error->what() << std::endl;
+    return false;
+  }
+#endif
+
+
+  //Debug output:
+  if(stmt && ConnectionPool::get_instance()->get_show_debug_output())
+  {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      //TODO: full_query still seems to contain ## parameter names,
+      //though it works for our SELECT queries in query_execute_select():
+      const Glib::ustring full_query = stmt->to_sql(params);
+      std::cerr << "Debug: query_execute(): " << full_query << std::endl;
+    }
+    catch(const Glib::Exception& ex)
+    {
+      std::cerr << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
+    }
+#else
+    const Glib::ustring full_query = stmt->to_sql(params, sql_error);
+    std::cerr << "Debug: query_execute(): " << full_query << std::endl;
+    if (sql_error.get())
+      std::cerr << "Debug: query string could not be converted to std::cout: " << sql_error->what() << std::endl;
+#endif
+  }
+
+
+  int exec_retval = -1;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    exec_retval = gda_connection->statement_execute_non_select(stmt, params);
+  }
+  catch(const Glib::Error& error)
+  {
+    std::cerr << "BaseDB::query_execute: ConnectionError: " << error.what() << std::endl;
+    const Glib::ustring full_query = stmt->to_sql(params);
+    std::cerr << "  full_query: " << full_query << std::endl;
+    return false;
+  }
+#else
+  std::auto_ptr<Glib::Error> exec_error;
+  exec_retval = gda_connection->statement_execute_non_select (stmt, params, exec_error);
+  if(exec_error.get())
+  {
+    std::cerr << "BaseDB::query_execute: ConnectionError: " << exec_error->what() << std::endl;
+    const Glib::ustring full_query = stmt->to_sql(params, exec_error);
+    std::cerr << "  full_query: " << full_query << std::endl;
+    return false;
+  }
+#endif
+  return (exec_retval >= 0);
+}
+
+} //namespace DbUtils
+
+} //namespace Glom
+
diff --git a/glom/libglom/db_utils.h b/glom/libglom/db_utils.h
new file mode 100644
index 0000000..042b1ae
--- /dev/null
+++ b/glom/libglom/db_utils.h
@@ -0,0 +1,99 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2010 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOM_DB_UTILS_H
+#define GLOM_DB_UTILS_H
+
+#include <libglom/document/document.h>
+#include <libglom/data_structure/system_prefs.h>
+
+namespace Glom
+{
+
+namespace DbUtils
+{
+
+bool create_database(Document* document, const Glib::ustring& database_name, const Glib::ustring& title, const sigc::slot<void>& progress);
+
+bool recreate_database_from_document(Document* document, const sigc::slot<void>& progress);
+
+/** This creates the standard tables if necessary, 
+ * filling them with some information from the document.
+ */
+SystemPrefs get_database_preferences(Document* document);
+
+void set_database_preferences(Document* document, const SystemPrefs& prefs);
+
+bool add_standard_tables(Document* document);
+
+bool add_standard_groups(Document* document);
+
+typedef std::vector< sharedptr<Field> > type_vec_fields;
+type_vec_fields get_fields_for_table_from_database(const Glib::ustring& table_name, bool including_system_fields = false);
+bool get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name);
+
+//TODO: Is this used directly?
+typedef std::vector<Glib::ustring> type_vec_strings;
+type_vec_strings get_table_names_from_database(bool ignore_system_tables = false);
+
+bool get_table_exists_in_database(const Glib::ustring& table_name);
+
+bool create_table(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields);
+
+/// Also saves the table information in the document:
+bool create_table_with_default_fields(Document* document, const Glib::ustring& table_name);
+
+bool create_table_add_missing_fields(const sharedptr<const TableInfo>& table_info, const Document::type_vec_fields& fields);
+
+// TODO: Should these functions update the document, so callers don't need
+// to do it?
+bool add_column(const Glib::ustring& table_name, const sharedptr<const Field>& field, Gtk::Window* parent_window);
+
+bool drop_column(const Glib::ustring& table_name, const Glib::ustring& field_name);
+
+
+//TODO: Is this used directly?
+bool insert_example_data(Document* document, const Glib::ustring& table_name);
+
+/** Execute a SQL Select command, returning the result.
+  */
+Glib::RefPtr<Gnome::Gda::DataModel> query_execute_select(const Glib::ustring& strQuery, 
+  const Glib::RefPtr<Gnome::Gda::Set>& params = Glib::RefPtr<Gnome::Gda::Set>(0));
+
+
+/** Execute a SQL non-select command, returning true if it succeeded.
+  */
+bool query_execute(const Glib::ustring& strQuery,
+  const Glib::RefPtr<Gnome::Gda::Set>& params = Glib::RefPtr<Gnome::Gda::Set>(0));
+
+//TODO: Is this used directly?
+Gnome::Gda::Value auto_increment_insert_first_if_necessary(const Glib::ustring& table_name, const Glib::ustring& field_name);
+
+/** Get the next auto-increment value for this primary key, from the glom system table.
+  * Add a row for this field in the system table if it does not exist already.
+  */
+Gnome::Gda::Value get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name);
+
+  
+} //namespace DbUtils
+
+} //namespace Glom
+
+#endif //GLOM_DB_UTILS_H
diff --git a/glom/glom_postgres.cc b/glom/libglom/glom_postgres.cc
similarity index 97%
rename from glom/glom_postgres.cc
rename to glom/libglom/glom_postgres.cc
index f9ffb98..42f7d9e 100644
--- a/glom/glom_postgres.cc
+++ b/glom/libglom/glom_postgres.cc
@@ -19,6 +19,7 @@
  */
 
 #include "glom_postgres.h"
+#include <libglom/utils.h>
 
 namespace Glom
 {
diff --git a/glom/glom_postgres.h b/glom/libglom/glom_postgres.h
similarity index 90%
rename from glom/glom_postgres.h
rename to glom/libglom/glom_postgres.h
index 47896ea..64609d6 100644
--- a/glom/glom_postgres.h
+++ b/glom/libglom/glom_postgres.h
@@ -21,21 +21,22 @@
 #ifndef DB_POSTGRES_H
 #define DB_POSTGRES_H
 
-#include <gtkmm.h>
+//#include <gtkmm.h>
 
-#include <glom/base_db.h>
+//#include <glom/base_db.h>
 #include <libglom/document/document.h>
 #include <libglom/connectionpool.h>
 
 namespace Glom
 {
 
-class GlomPostgres : public Base_DB
+class GlomPostgres
 {
 public:
 
 protected:
   //Utility functions to help with the odd formats of postgres internal catalog fields:
+  typedef std::vector<Glib::ustring> type_vec_strings;
   static type_vec_strings pg_list_separate(const Glib::ustring& str);
 
 };
diff --git a/glom/glom_privs.cc b/glom/libglom/privs.cc
similarity index 94%
rename from glom/glom_privs.cc
rename to glom/libglom/privs.cc
index 2b025f5..128b055 100644
--- a/glom/glom_privs.cc
+++ b/glom/libglom/privs.cc
@@ -18,9 +18,11 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include "glom_privs.h"
+#include "privs.h"
 #include <libglom/standard_table_prefs_fields.h>
-#include <glom/application.h>
+#include <libglom/db_utils.h>
+#include <libglom/utils.h>
+//#include <glom/application.h>
 
 namespace Glom
 {
@@ -34,7 +36,7 @@ Privs::type_vec_strings Privs::get_database_groups()
   type_vec_strings result;
 
   const Glib::ustring strQuery = "SELECT \"pg_group\".\"groname\" FROM \"pg_group\"";
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(strQuery);
+  Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
   if(data_model)
   {
     const int rows_count = data_model->get_n_rows();
@@ -94,7 +96,7 @@ Glib::ustring Privs::get_default_developer_user_name(Glib::ustring& password)
 
 Privs::type_vec_strings Privs::get_database_users(const Glib::ustring& group_name)
 {
-  BusyCursor cursor(Application::get_application());
+  //TODO_Moved: BusyCursor cursor(Application::get_application());
 
   type_vec_strings result;
 
@@ -102,7 +104,7 @@ Privs::type_vec_strings Privs::get_database_users(const Glib::ustring& group_nam
   {
     //pg_shadow contains the users. pg_users is a view of pg_shadow without the password.
     const Glib::ustring strQuery = "SELECT \"pg_shadow\".\"usename\" FROM \"pg_shadow\"";
-    Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(strQuery);
+    Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
     if(data_model)
     {
       const int rows_count = data_model->get_n_rows();
@@ -122,7 +124,7 @@ Privs::type_vec_strings Privs::get_database_users(const Glib::ustring& group_nam
   else
   {
     const Glib::ustring strQuery = "SELECT \"pg_group\".\"groname\", \"pg_group\".\"grolist\" FROM \"pg_group\" WHERE \"pg_group\".\"groname\" = '" + group_name + "'";
-    Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(strQuery);
+    Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
     if(data_model && data_model->get_n_rows())
     {
       const int rows_count = data_model->get_n_rows();
@@ -145,7 +147,7 @@ Privs::type_vec_strings Privs::get_database_users(const Glib::ustring& group_nam
         {
           //TODO_Performance: Can we do this in one SQL SELECT?
           const Glib::ustring strQuery = "SELECT \"pg_user\".\"usename\" FROM \"pg_user\" WHERE \"pg_user\".\"usesysid\" = '" + *iter + "'";
-          Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(strQuery);
+          Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
           if(data_model)
           {
 #ifdef GLIBMM_EXCEPTIONS_ENABLED          
@@ -221,7 +223,7 @@ void Privs::set_table_privileges(const Glib::ustring& group_name, const Glib::us
 
   strQuery += " GROUP \"" + group_name + "\"";
 
-  const bool test = query_execute(strQuery);
+  const bool test = DbUtils::query_execute(strQuery);
   if(!test)
     std::cerr << "Privs::set_table_privileges(): GRANT failed." << std::endl;
   else
@@ -254,7 +256,7 @@ Privileges Privs::get_table_privileges(const Glib::ustring& group_name, const Gl
 
   //Get the permissions:
   Glib::ustring strQuery = "SELECT \"pg_class\".\"relacl\" FROM \"pg_class\" WHERE \"pg_class\".\"relname\" = '" + table_name + "'";
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(strQuery);
+  Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
   if(data_model && data_model->get_n_rows())
   {
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
@@ -358,7 +360,7 @@ Glib::ustring Privs::get_user_visible_group_name(const Glib::ustring& group_name
   return result;
 }
 
-Base_DB::type_vec_strings Privs::get_groups_of_user(const Glib::ustring& user)
+Privs::type_vec_strings Privs::get_groups_of_user(const Glib::ustring& user)
 {
   //TODO_Performance
 
@@ -406,7 +408,7 @@ Privileges Privs::get_current_privs(const Glib::ustring& table_name)
   //TODO_Performance: There's lots of database access here.
   //We could maybe replace some with the postgres has_table_* function().
 
-  BusyCursor cursor(Application::get_application());
+  //TODO_Moved: BusyCursor cursor(Application::get_application());
 
   //Return a cached value if possible.
   //(If it is in the cache then it's fairly recent)
diff --git a/glom/glom_privs.h b/glom/libglom/privs.h
similarity index 98%
rename from glom/glom_privs.h
rename to glom/libglom/privs.h
index d7915c0..afc1d01 100644
--- a/glom/glom_privs.h
+++ b/glom/libglom/privs.h
@@ -21,9 +21,9 @@
 #ifndef GLOM_PRIVS_H
 #define GLOM_PRIVS_H
 
-#include <gtkmm.h>
+//#include <gtkmm.h>
 
-#include <glom/glom_postgres.h>
+#include <libglom/glom_postgres.h>
 
 namespace Glom
 {
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index 0eb629b..f4f1e94 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -841,5 +841,4 @@ bool Utils::file_exists(const Glib::ustring& uri)
   }
 }
 
-
 } //namespace Glom
diff --git a/glom/main.cc b/glom/main.cc
index 45e983e..ad2333e 100644
--- a/glom/main.cc
+++ b/glom/main.cc
@@ -627,6 +627,7 @@ main(int argc, char* argv[])
 
     pApplication->set_command_line_args(argc, argv);
     pApplication->set_show_sql_debug(group.m_arg_debug_sql);
+    Glom::ConnectionPool::get_instance()->set_show_debug_output(group.m_arg_debug_sql);
 
     const bool test = pApplication->init(input_uri); //Sets it up and shows it.
 
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index dc611c3..4ec1994 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -24,7 +24,7 @@
 #include <libglom/data_structure/glomconversions.h>
 #include <glom/utils_ui.h>
 #include <libglom/data_structure/layout/layoutitem_field.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 #include <glom/python_embed/glom_python.h>
 #include <glom/python_embed/python_ui_callbacks.h>
 #include <glom/application.h>
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index fba041f..3f56902 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -24,10 +24,11 @@
 #include <libglom/data_structure/field.h>
 #include <libglom/data_structure/relationship.h>
 #include <libglom/data_structure/glomconversions.h>
+#include <libglom/db_utils.h>
 #include <glom/mode_design/layout/dialog_layout_details.h>
 #include <glom/glade_utils.h>
 #include <glom/utils_ui.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 #include <glom/xsl_utils.h>
 #include <glom/python_embed/glom_python.h>
 #include <sstream> //For stringstream
@@ -458,7 +459,7 @@ void Box_Data_Details::on_button_new()
   if(m_field_primary_key && m_field_primary_key->get_auto_increment()) //If the primary key is an auto-increment:
   {
     //Just make a new record, and show it:
-    Gnome::Gda::Value primary_key_value = get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name()); //TODO: This should return a Gda::Value
+    const Gnome::Gda::Value primary_key_value = DbUtils::get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name()); //TODO: This should return a Gda::Value
 
     record_new(false /* use entered field data */, primary_key_value);
     refresh_data_from_database_with_primary_key(primary_key_value);
@@ -899,7 +900,7 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
       else
       {
         //Make a new record, and show it:
-        Gnome::Gda::Value primary_key_value = get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name());
+        const Gnome::Gda::Value primary_key_value = DbUtils::get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name());
 
         record_new(true /* use entered field data */, primary_key_value);
         refresh_data_from_database_with_primary_key(primary_key_value);
diff --git a/glom/mode_data/box_data_list.cc b/glom/mode_data/box_data_list.cc
index 5c70e3c..2922961 100644
--- a/glom/mode_data/box_data_list.cc
+++ b/glom/mode_data/box_data_list.cc
@@ -23,7 +23,8 @@
 #include <glom/glade_utils.h>
 #include <glom/report_builder.h>
 #include <glom/mode_design/layout/dialog_layout_list.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
+#include <libglom/db_utils.h>
 #include <libglom/utils.h> //For bold_message()).
 //#include <../utility_widgets/db_adddel/glom_db_treemodel.h> //For DbTreeModel.
 #include <sstream> //For stringstream
@@ -432,7 +433,7 @@ void Box_Data_List::create_layout_add_group(const sharedptr<LayoutGroup>& layout
       {
         //Check that the field really exists, to avoid SQL errors.
         //This could probably only happen if we have failed to rename something everywhere, when the user has renamed something.
-        if(!get_field_exists_in_database(child_field->get_table_used(m_table_name), child_field->get_name()))
+        if(!DbUtils::get_field_exists_in_database(child_field->get_table_used(m_table_name), child_field->get_name()))
         {
           std::cerr << "debug: Box_Data_List::create_layout_add_group(): Field does not exist in database: table_name=" << child_field->get_table_used(m_table_name) << ", field_name=" << child_field->get_name() << std::endl;
           continue;
diff --git a/glom/mode_data/box_data_list_related.cc b/glom/mode_data/box_data_list_related.cc
index c4b8646..62b810e 100644
--- a/glom/mode_data/box_data_list_related.cc
+++ b/glom/mode_data/box_data_list_related.cc
@@ -21,6 +21,7 @@
 #include <glom/mode_data/box_data_list_related.h>
 #include <glom/mode_design/layout/dialog_layout_list_related.h>
 #include <libglom/data_structure/glomconversions.h>
+#include <libglom/db_utils.h>
 #include <glom/glade_utils.h>
 #include <glom/frame_glom.h> //For show_ok_dialog()
 #include <glom/utils_ui.h> //For bold_message()).
@@ -465,7 +466,7 @@ void Box_Data_List_Related::create_layout_add_group(const sharedptr<LayoutGroup>
       {
         //Check that the field really exists, to avoid SQL errors.
         //This could probably only happen if we have failed to rename something everywhere, when the user has renamed something.
-        if(!get_field_exists_in_database(child_field->get_table_used(Base_DB_Table::m_table_name), child_field->get_name()))
+        if(!DbUtils::get_field_exists_in_database(child_field->get_table_used(Base_DB_Table::m_table_name), child_field->get_name()))
         {
           std::cerr << "debug: Box_Data_List_Related::create_layout_add_group(): Field does not exist in database: table_name=" << child_field->get_table_used(Base_DB_Table::m_table_name) << ", field_name=" << child_field->get_name() << std::endl;
           continue;
diff --git a/glom/mode_data/box_data_manyrecords.cc b/glom/mode_data/box_data_manyrecords.cc
index 6693a31..9d8ded6 100644
--- a/glom/mode_data/box_data_manyrecords.cc
+++ b/glom/mode_data/box_data_manyrecords.cc
@@ -23,7 +23,7 @@
 #include <glom/glade_utils.h>
 #include <glom/report_builder.h>
 #include <glom/mode_design/layout/dialog_layout_list.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 #include <libglom/utils.h> //For bold_message()).
 #include <sstream> //For stringstream
 #include <glibmm/i18n.h>
diff --git a/glom/mode_design/dialog_add_related_table.cc b/glom/mode_design/dialog_add_related_table.cc
index ec52f4d..218be5c 100644
--- a/glom/mode_design/dialog_add_related_table.cc
+++ b/glom/mode_design/dialog_add_related_table.cc
@@ -20,6 +20,7 @@
  
 #include "dialog_add_related_table.h"
 #include <glom/frame_glom.h> //For show_ok_dialog.h
+#include <libglom/db_utils.h>
 #include <glibmm/i18n.h>
 
 namespace Glom
@@ -68,7 +69,7 @@ void Dialog_AddRelatedTable::set_fields(const Glib::ustring& table_name)
 {
   m_table_name = table_name;
 
-  type_vec_fields fields = get_fields_for_table_from_database(table_name);
+  const type_vec_fields fields = DbUtils::get_fields_for_table_from_database(table_name);
 
   //Show the fields:
   m_combo_from_field->clear_items();
@@ -135,7 +136,7 @@ void Dialog_AddRelatedTable::on_combo_field_name()
   int suffix_number = 1;
   while(exists_already)
   {
-    if(!get_table_exists_in_database(name_to_try))
+    if(!DbUtils::get_table_exists_in_database(name_to_try))
        exists_already = false; //Stop the while loop.
     else
     {
diff --git a/glom/mode_design/dialog_database_preferences.cc b/glom/mode_design/dialog_database_preferences.cc
index 257d220..d43b41a 100644
--- a/glom/mode_design/dialog_database_preferences.cc
+++ b/glom/mode_design/dialog_database_preferences.cc
@@ -22,6 +22,7 @@
 #include <glom/python_embed/glom_python.h>
 #include <libglom/standard_table_prefs_fields.h>
 #include <libglom/data_structure/glomconversions.h>
+#include <libglom/db_utils.h>
 #include <glom/bakery/busy_cursor.h>
 #include <gtksourceviewmm/sourcelanguagemanager.h>
 #include <glibmm/i18n.h>
@@ -139,7 +140,8 @@ void Dialog_Database_Preferences::on_treeview_cell_edited_next_value(const Glib:
 
 void Dialog_Database_Preferences::load_from_document()
 {
-  m_system_prefs = get_database_preferences();
+  Document* document = get_document();
+  m_system_prefs = DbUtils::get_database_preferences(document);
 
   //Show the data in the UI:
   m_glade_variables_map.transfer_variables_to_widgets();
@@ -147,7 +149,7 @@ void Dialog_Database_Preferences::load_from_document()
 
 
   //Make sure that all auto-increment values are setup:
-  const Document* document = get_document();
+
   const Document::type_listTableInfo tables = document->get_tables();
   for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
   {
@@ -156,7 +158,7 @@ void Dialog_Database_Preferences::load_from_document()
     {
       sharedptr<Field> field = *iterFields;
       if(field->get_primary_key())
-        auto_increment_insert_first_if_necessary((*iter)->get_name(), field->get_name());
+        DbUtils::auto_increment_insert_first_if_necessary((*iter)->get_name(), field->get_name());
     }
   }
 
@@ -216,11 +218,16 @@ void Dialog_Database_Preferences::save_to_document()
   m_glade_variables_map.transfer_widgets_to_variables();
   m_system_prefs.m_org_logo = m_image->get_value();
 
-  set_database_preferences(m_system_prefs);
+  Document* document = get_document();
+
+  //Make sure that set_database_preferences() can work.
+  if(get_userlevel() == AppState::USERLEVEL_DEVELOPER)
+    DbUtils::add_standard_tables(document);
+
+  DbUtils::set_database_preferences(document, m_system_prefs);
 
-  //The script is not part of "database preferencs" in the database data,
+  //The script is not part of "database preferences" in the database data,
   //because it does not seem to be part of simple personalisation.
-  Document* document = get_document();
   if(!document)
      return;
   const Glib::ustring script = m_text_view_script->get_buffer()->get_text();
diff --git a/glom/mode_design/fields/box_db_table_definition.cc b/glom/mode_design/fields/box_db_table_definition.cc
index b913f10..ab46d1a 100644
--- a/glom/mode_design/fields/box_db_table_definition.cc
+++ b/glom/mode_design/fields/box_db_table_definition.cc
@@ -23,6 +23,7 @@
 #include <glom/glade_utils.h>
 #include <glom/utils_ui.h> //For bold_message()).
 #include <libglom/libglom_config.h>
+#include <libglom/db_utils.h>
 #include <glibmm/i18n.h>
 
 namespace Glom
@@ -177,7 +178,7 @@ void Box_DB_Table_Definition::on_adddel_add(const Gtk::TreeModel::iterator& row)
 
     //TODO: Warn about a delay before actually doing this when the backend
     //needs to recreate the whole table.
-    const bool bTest = add_column(m_table_name, field, get_app_window()); //TODO: Get schema type for Field::TYPE_NUMERIC
+    const bool bTest = DbUtils::add_column(m_table_name, field, get_app_window()); //TODO: Get schema type for Field::TYPE_NUMERIC
     if(bTest)
     {
       //Store the generated title in the document:
@@ -229,7 +230,7 @@ void Box_DB_Table_Definition::on_adddel_delete(const Gtk::TreeModel::iterator& r
     {
       //TODO: Warn about a delay before actually doing this when the backend
       //needs to recreate the whole table.
-      const bool test = drop_column(m_table_name, name, get_app_window());
+      const bool test = DbUtils::drop_column(m_table_name, name);
       if(test)
       {
         //update_gda_metastore_for_table(m_table_name); // already done in drop_column().
@@ -322,7 +323,7 @@ bool Box_DB_Table_Definition::check_field_change(const sharedptr<const Field>& f
 
   //Refuse to change a field name to the same as an existing one:
   if( (field_new->get_name() != field_old->get_name()) &&
-      (get_field_exists_in_database(m_table_name, field_new->get_name())) )
+      (DbUtils::get_field_exists_in_database(m_table_name, field_new->get_name())) )
   {
     std::cout << "get_field_exists_in_database(" << m_table_name << ", " << field_new->get_name() << ") returned true" << std::endl;
 
diff --git a/glom/mode_design/users/dialog_groups_list.cc b/glom/mode_design/users/dialog_groups_list.cc
index a4f1a38..f843e77 100644
--- a/glom/mode_design/users/dialog_groups_list.cc
+++ b/glom/mode_design/users/dialog_groups_list.cc
@@ -24,9 +24,10 @@
 #include "dialog_new_group.h"
 #include <libglom/standard_table_prefs_fields.h>
 #include <glom/glade_utils.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 //#include <libgnome/gnome-i18n.h>
 #include <glom/utils_ui.h> //For bold_message()).
+#include <libglom/db_utils.h>
 #include <glibmm/i18n.h>
 
 namespace Glom
@@ -419,7 +420,7 @@ void Dialog_GroupsList::fill_table_list(const Glib::ustring& group_name)
 void Dialog_GroupsList::load_from_document()
 {
   //Ensure that the glom_developer group exists.
-  add_standard_groups();
+  DbUtils::add_standard_groups(get_document());
 
   fill_group_list();
   //fill_table_list();
diff --git a/glom/mode_design/users/dialog_users_list.cc b/glom/mode_design/users/dialog_users_list.cc
index 76fd1b4..fd8577d 100644
--- a/glom/mode_design/users/dialog_users_list.cc
+++ b/glom/mode_design/users/dialog_users_list.cc
@@ -21,7 +21,7 @@
 #include "dialog_users_list.h"
 #include "dialog_user.h"
 #include "dialog_choose_user.h"
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 #include <glom/glade_utils.h>
 #include <glom/utils_ui.h> //For bold_message()).
 //#include <libgnome/gnome-i18n.h>
diff --git a/glom/navigation/box_tables.cc b/glom/navigation/box_tables.cc
index 2ed20f6..c513528 100644
--- a/glom/navigation/box_tables.cc
+++ b/glom/navigation/box_tables.cc
@@ -20,6 +20,7 @@
 
 #include <glom/navigation/box_tables.h>
 #include <glom/utils_ui.h> //For bold_message()).
+#include <libglom/db_utils.h>
 #include <glom/application.h>
 #include <glibmm/i18n.h>
 
@@ -163,7 +164,7 @@ bool Box_Tables::fill_from_database()
     m_AddDel.remove_all();
     Glib::RefPtr<Gnome::Gda::Connection> connection = sharedconnection->get_gda_connection();
 
-    const type_vec_strings vecTables = get_table_names_from_database();
+    const type_vec_strings vecTables = DbUtils::get_table_names_from_database();
 
     for(type_vec_strings::const_iterator iter = vecTables.begin(); iter != vecTables.end(); ++iter)
     {
@@ -231,7 +232,7 @@ void Box_Tables::on_adddel_Add(const Gtk::TreeModel::iterator& row)
   bool created = false; 
 
   //Check whether it exists already. (Maybe it is somehow in the database but not in the document. That shouldn't happen.)
-  const bool exists_in_db = get_table_exists_in_database(table_name);
+  const bool exists_in_db = DbUtils::get_table_exists_in_database(table_name);
   if(exists_in_db)
   {
     //Ask the user if they want us to try to cope with this:
@@ -250,7 +251,7 @@ void Box_Tables::on_adddel_Add(const Gtk::TreeModel::iterator& row)
   }
   else
   {
-    created = create_table_with_default_fields(table_name);
+    created = DbUtils::create_table_with_default_fields(get_document(), table_name);
   }
   
   if(created)
diff --git a/glom/utility_widgets/db_adddel/db_adddel.cc b/glom/utility_widgets/db_adddel/db_adddel.cc
index 6eabf8a..0b0cfd1 100644
--- a/glom/utility_widgets/db_adddel/db_adddel.cc
+++ b/glom/utility_widgets/db_adddel/db_adddel.cc
@@ -30,6 +30,7 @@
 #include "cellrenderer_buttonimage.h"
 #include "cellrenderer_buttontext.h"
 #include <glom/utils_ui.h> //For Utils::image_scale_keeping_ratio().
+#include <libglom/db_utils.h>
 
 #include <iostream> //For debug output.
 #include <gtk/gtktreeview.h>
@@ -2646,7 +2647,7 @@ void DbAddDel::user_added(const Gtk::TreeModel::iterator& row)
   {
     //Auto-increment is awkward (we can't get the last-generated ID) with postgres, so we auto-generate it ourselves;
     const Glib::ustring strPrimaryKeyName = primary_key_field->get_name();
-    primary_key_value = get_next_auto_increment_value(m_found_set.m_table_name, strPrimaryKeyName);  //TODO: return a Gnome::Gda::Value of an appropriate type.
+    primary_key_value = DbUtils::get_next_auto_increment_value(m_found_set.m_table_name, strPrimaryKeyName);  //TODO: return a Gnome::Gda::Value of an appropriate type.
   }
   else
   {
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3e45f27..caec1da 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -53,6 +53,7 @@ glom/libglom/document/bakery/view/view_composite.cc
 glom/libglom/gst-package.c
 glom/libglom/spawn_with_feedback.cc
 glom/libglom/utils.cc
+glom/libglom/db_utils.cc
 glom/main.cc
 glom/mode_data/box_data_calendar_related.cc
 glom/mode_data/box_data.cc
diff --git a/tests/test_selfhosting_new_empty/test_selfhosting_new_empty.cc b/tests/test_selfhosting_new_empty/test_selfhosting_new_empty.cc
index 562c630..d67ce6a 100644
--- a/tests/test_selfhosting_new_empty/test_selfhosting_new_empty.cc
+++ b/tests/test_selfhosting_new_empty/test_selfhosting_new_empty.cc
@@ -22,7 +22,7 @@
 #include <libglom/connectionpool.h>
 #include <libglom/connectionpool_backends/postgres_self.h>
 #include <libglom/init.h>
-#include <glom/glom_privs.h>
+#include <libglom/privs.h>
 #include <giomm/file.h>
 
 static void on_initialize_progress()
@@ -88,47 +88,11 @@ int main()
 {
   Glom::libglom_init();
 
-  // Get a URI for a test file:
-  Glib::ustring uri;
-
-  #ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-  {
-    const std::string path = 
-       Glib::build_filename(GLOM_DOCDIR_EXAMPLES_NOTINSTALLED, 
-         "example_music_collection.glom");
-    uri = Glib::filename_to_uri(path);
-  }
-  catch(const Glib::ConvertError& ex)
-  {
-    std::cerr << "Exception from Glib::filename_to_uri(): " << ex.what();
-    return EXIT_FAILURE;
-  }
-  #else
-  std::auto_ptr<Glib::Error> ex;
-  uri = Glib::filename_to_uri("/usr/share/glom/doc/examples/example_music_collection.glom", ex);
-  #endif
-
-  //std::cout << "URI=" << uri << std::endl;
-
-
-  // Load the document:
+  // Create the document:
   Glom::Document document;
-  document.set_file_uri(uri);
-  int failure_code = 0;
-  const bool test = document.load(failure_code);
-  //std::cout << "Document load result=" << test << std::endl;
 
-  if(!test)
-  {
-    std::cerr << "Document::load() failed with failure_code=" << failure_code << std::endl;
-    return EXIT_FAILURE;
-  }
-  
-  g_assert(document.get_is_example_file());;
 
-  Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
-  
+
   //Save a copy, specifying the path to file in a directory:
   //For instance, /tmp/testfileglom/testfile.glom");
   const std::string temp_filename = "testglom";
@@ -142,7 +106,7 @@ int main()
     delete_directory(uri);
   }
 
-  //Save the example as a real file:
+  //Save the file. TODO: Do we need to do this for the test?
   const Glib::ustring file_uri = Glib::filename_to_uri(temp_filepath);
   document.set_file_uri(file_uri);
   
@@ -153,6 +117,7 @@ int main()
   g_assert(saved);
 
   //Specify the backend and backend-specific details to be used by the connectionpool.
+  Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
   connection_pool->setup_from_document(&document);
 
   //We must specify a default username and password:
diff --git a/tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example.cc b/tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example.cc
new file mode 100644
index 0000000..81cb508
--- /dev/null
+++ b/tests/test_selfhosting_new_from_example/test_selfhosting_new_from_example.cc
@@ -0,0 +1,208 @@
+/* Glom
+ *
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * 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
+71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/document/document.h>
+#include <libglom/connectionpool.h>
+#include <libglom/connectionpool_backends/postgres_self.h>
+#include <libglom/init.h>
+#include <libglom/privs.h>
+#include <libglom/db_utils.h>
+#include <giomm/file.h>
+
+static void on_initialize_progress()
+{
+  std::cout << "Database initialization progress" << std::endl;
+}
+
+static void on_startup_progress()
+{
+  std::cout << "Database startup progress" << std::endl;
+}
+
+static void on_recreate_progress()
+{
+  std::cout << "Database re-creation progress" << std::endl;
+}
+
+static void on_cleanup_progress()
+{
+  std::cout << "Database cleanup progress" << std::endl;
+}
+
+/** Delete a directory, if it exists, and its contents.
+ * Unlike g_file_delete(), this does not fail if the directory is not empty.
+ */
+static bool delete_directory(const Glib::RefPtr<Gio::File>& directory)
+{
+  if(!(directory->query_exists()))
+    return true;
+
+  //(Recursively) Delete any child files and directories,
+  //so we can delete this directory.
+  Glib::RefPtr<Gio::FileEnumerator> enumerator = directory->enumerate_children();
+  
+  Glib::RefPtr<Gio::FileInfo> info = enumerator->next_file();
+  while(info)
+  {
+    Glib::RefPtr<Gio::File> child = directory->get_child(info->get_name());
+    bool removed_child = false;
+    if(child->query_file_type() == Gio::FILE_TYPE_DIRECTORY)
+      removed_child = delete_directory(child);
+    else
+      removed_child = child->remove();
+
+    if(!removed_child)
+       return false;
+    
+    info = enumerator->next_file();
+  }
+
+  //Delete the actual directory:
+  if(!directory->remove())
+    return false;
+  
+  return true;
+}
+
+/** Delete a directory, if it exists, and its contents.
+ * Unlike g_file_delete(), this does not fail if the directory is not empty.
+ */
+static bool delete_directory(const std::string& uri)
+{
+  Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(uri);
+  return delete_directory(file);
+}
+
+std::string temp_filepath_dir;
+
+void cleanup()
+{
+  Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
+ 
+  const bool stopped = connection_pool->cleanup( sigc::ptr_fun(&on_cleanup_progress) );  
+  g_assert(stopped);
+
+  //Make sure the directory is removed at the end,
+  {
+    const Glib::ustring uri = Glib::filename_to_uri(temp_filepath_dir);
+    delete_directory(uri);
+  }
+}
+
+int main()
+{
+  Glom::libglom_init();
+
+  // Get a URI for a test file:
+  Glib::ustring uri;
+
+  #ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+    const std::string path = 
+       Glib::build_filename(GLOM_DOCDIR_EXAMPLES_NOTINSTALLED, 
+         "example_music_collection.glom");
+    uri = Glib::filename_to_uri(path);
+  }
+  catch(const Glib::ConvertError& ex)
+  {
+    std::cerr << "Exception from Glib::filename_to_uri(): " << ex.what();
+    return EXIT_FAILURE;
+  }
+  #else
+  std::auto_ptr<Glib::Error> ex;
+  uri = Glib::filename_to_uri("/usr/share/glom/doc/examples/example_music_collection.glom", ex);
+  #endif
+
+  //std::cout << "URI=" << uri << std::endl;
+
+
+  // Load the document:
+  Glom::Document document;
+  document.set_file_uri(uri);
+  int failure_code = 0;
+  const bool test = document.load(failure_code);
+  //std::cout << "Document load result=" << test << std::endl;
+
+  if(!test)
+  {
+    std::cerr << "Document::load() failed with failure_code=" << failure_code << std::endl;
+    return EXIT_FAILURE;
+  }
+  
+  g_assert(document.get_is_example_file());;
+
+  Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
+  
+  //Save a copy, specifying the path to file in a directory:
+  //For instance, /tmp/testfileglom/testfile.glom");
+  const std::string temp_filename = "testglom";
+  temp_filepath_dir = Glib::build_filename(Glib::get_tmp_dir(), 
+    temp_filename);
+  const std::string temp_filepath = Glib::build_filename(temp_filepath_dir, temp_filename);
+  
+  //Make sure that the file does not exist yet:
+  {
+    const Glib::ustring uri = Glib::filename_to_uri(temp_filepath_dir);
+    delete_directory(uri);
+  }
+
+  //Save the example as a real file:
+  const Glib::ustring file_uri = Glib::filename_to_uri(temp_filepath);
+  document.set_file_uri(file_uri);
+  
+  document.set_hosting_mode(Glom::Document::HOSTING_MODE_POSTGRES_SELF);
+  document.set_is_example_file(false);
+  document.set_network_shared(false);
+  const bool saved = document.save();
+  g_assert(saved);
+
+  //Specify the backend and backend-specific details to be used by the connectionpool.
+  connection_pool->setup_from_document(&document);
+
+  //We must specify a default username and password:
+  Glib::ustring password;
+  const Glib::ustring user = Glom::Privs::get_default_developer_user_name(password);
+  connection_pool->set_user(user);
+  connection_pool->set_password(password);
+
+  //Create the self-hosting files:
+  const Glom::ConnectionPool::InitErrors initialized_errors = 
+    connection_pool->initialize( sigc::ptr_fun(&on_initialize_progress) );
+  g_assert(initialized_errors == Glom::ConnectionPool::Backend::INITERROR_NONE);
+
+  //Start self-hosting:
+  //TODO: Let this happen automatically on first connection?
+  const bool started = connection_pool->startup( sigc::ptr_fun(&on_startup_progress) );
+  if(!started)
+    cleanup();
+  g_assert(started);
+
+  const bool recreated = Glom::DbUtils::recreate_database_from_document(&document, sigc::ptr_fun(&on_recreate_progress) );
+  if(!recreated)
+    cleanup();
+  g_assert(recreated);
+
+  cleanup();
+  
+  Glom::libglom_deinit();
+
+  return EXIT_SUCCESS;
+}



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