[glom/sqlbuilder2: 23/23] Merged from master.



commit f7a37729f260e6d32e588c779ee4fe1eea7a45db
Merge: 8612976 ccafe3a
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu May 6 17:53:14 2010 +0200

    Merged from master.

 ChangeLog                                          |  135 ++
 Makefile_glom.am                                   |    4 -
 Makefile_libglom.am                                |   11 +-
 Makefile_tests.am                                  |   35 +-
 NEWS                                               |   14 +-
 configure.ac                                       |    2 +-
 docs/user-guide/C/glom.xml                         |    4 +-
 docs/user-guide/ChangeLog                          |    7 +
 docs/user-guide/de/de.po                           |  642 +++++--
 glom/application.cc                                |  219 +--
 glom/application.h                                 |    5 +-
 glom/base_db.cc                                    | 1287 +--------------
 glom/base_db.h                                     |   63 +-
 glom/base_db_table_data.cc                         |    7 +-
 glom/dialog_existing_or_new.cc                     |    1 -
 glom/filechooser_export.cc                         |    3 -
 glom/frame_glom.cc                                 |  100 +-
 glom/glade_utils.h                                 |    7 -
 glom/import_csv/dialog_import_csv_progress.cc      |    3 +-
 glom/libglom/connectionpool.cc                     |   12 +-
 glom/libglom/connectionpool.h                      |    5 +
 glom/libglom/data_structure/glomconversions.cc     |   76 +-
 glom/libglom/db_utils.cc                           | 1808 ++++++++++++++++++++
 glom/libglom/db_utils.h                            |  110 ++
 glom/libglom/document/bakery/document.cc           |    9 +-
 glom/{ => libglom}/glom_postgres.cc                |    1 +
 glom/{ => libglom}/glom_postgres.h                 |    7 +-
 glom/{glom_privs.cc => libglom/privs.cc}           |   74 +-
 glom/{glom_privs.h => libglom/privs.h}             |    4 +-
 glom/libglom/utils.cc                              |   43 +-
 glom/libglom/utils.h                               |    6 +-
 glom/main.cc                                       |    1 +
 glom/mode_data/box_data.cc                         |    6 +-
 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_data/datawidget/combo.cc                 |    8 +-
 .../datawidget/combochoiceswithtreemodel.cc        |    2 +-
 glom/mode_data/datawidget/dialog_choose_id.cc      |    6 +-
 glom/mode_data/datawidget/dialog_choose_id.h       |    2 +-
 glom/mode_design/dialog_add_related_table.cc       |    5 +-
 glom/mode_design/dialog_database_preferences.cc    |   25 +-
 glom/mode_design/fields/box_db_table_definition.cc |    7 +-
 glom/mode_design/fields/dialog_fieldcalculation.cc |   11 +-
 .../layout/layout_item_dialogs/box_formatting.h    |    2 +-
 .../layout_item_dialogs/dialog_buttonscript.cc     |   10 +-
 .../layout_item_dialogs/dialog_buttonscript.h      |    2 +-
 .../script_library/dialog_script_library.cc        |    1 -
 .../mode_design/translation/window_translations.cc |    2 -
 glom/mode_design/users/dialog_groups_list.cc       |    6 +-
 glom/mode_design/users/dialog_users_list.cc        |    2 +-
 glom/navigation/box_tables.cc                      |    7 +-
 glom/python_embed/glom_python.cc                   |   46 +-
 glom/python_embed/glom_python.h                    |    6 +-
 glom/python_embed/python_module/py_glom_module.cc  |   56 +-
 glom/utility_widgets/db_adddel/db_adddel.cc        |    3 +-
 .../filechooserdialog_saveextras.cc                |    2 -
 glom/utils_ui.cc                                   |   21 +-
 glom/utils_ui.h                                    |    5 +
 glom/window_boxholder.cc                           |    3 -
 po/POTFILES.in                                     |    2 +
 po/cs.po                                           |  528 +++---
 po/de.po                                           |  510 +++---
 tests/test_document_autosave.cc                    |  111 ++
 .../{test_document_load => }/test_document_load.cc |    0
 tests/test_python_execute_func.cc                  |    9 +-
 tests/test_python_execute_func_bad_syntax.cc       |   56 +
 .../test_python_execute_func_change_result_type.cc |   56 +
 tests/test_python_execute_func_date.cc             |   14 +-
 tests/test_python_execute_script.cc                |    6 +-
 .../test_selfhosting_new_empty.cc                  |   45 +-
 ...pty.cc => test_selfhosting_new_from_example.cc} |   42 +-
 73 files changed, 3817 insertions(+), 2530 deletions(-)
---
diff --cc ChangeLog
index 01a01a0,591d033..dddf193
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,18 -1,138 +1,153 @@@
+ 2010-05-03  Daniel Borgmann  <danielb openismus com>
+ 
+ 	Set default icon instead of individual window icons.
+ 
+ 	* glom/application.cc: Set default window icon.
+ 
+ 	* glom/dialog_existing_or_new.cc:
+ 	* glom/filechooser_export.cc:
+ 	* glom/frame_glom.cc:
+ 	* glom/glade_utils.h:
+ 	* glom/mode_design/script_library/dialog_script_library.cc:
+ 	* glom/mode_design/translation/window_translations.cc:
+ 	* glom/mode_design/users/dialog_groups_list.cc:
+ 	* glom/utility_widgets/filechooserdialog_saveextras.cc:
+ 	* glom/utils_ui.cc:
+ 	* glom/window_boxholder.cc:
+ 
+ 	Don't call set_icon_name() on individual windows.
+ 
+ 1.14.2:
+ 
+ 2010-05-02  Murray Cumming  <murrayc murrayc-x61>
+ 
+ 	Python calculations: Really convert to expected types.
+ 	
+ 	* glom/libglom/data_structure/glomconversions.cc: 
+ 	get_double_for_gda_value_numeric(): Handle all numeric GTypes - not just 
+ 	G_TYPE_INT..
+ 	convert_value(): Remove the special case for G_TYPE_INT (now handled in 
+ 	get_double_for_gda_value_numeric instead). Make sure that all numeric GTypes 
+ 	are converted to GDA_TYPE_NUMERIC, making it easier for callers to check.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Add test of type conversion after python calculations.
+ 	
+ 	* Makefile_tests.am:
+ 	* tests/test_python_execute_func_change_result_type.cc: Add a test that 
+ 	calls a python function that returns a number, for a text field, to 
+ 	check that the conversion is done.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Python scripts and calculations: Test buttons now show python errors.
+ 	
+ 	* glom/python_embed/glom_python.[h|cc]: 
+ 	glom_execute_python_function_implementation(), 
+ 	glom_evaluate_python_function_implementation(): Add an error_message output 
+ 	parameter, to report syntax errors, for instance.
+ 	* glom/mode_design/fields/dialog_fieldcalculation.cc:
+   * glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc:
+   Show the python error, if any, when pressing the Test button.
+   * Other files: Adapt, ignoring the error message for now.
+   * Makefile_tests.am:
+ 	* tests/test_python_execute_func_bad_syntax.cc: Added a test of the new 
+ 	error_message parameter. 
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Fix a possible crash when showing choices.
+ 
+ 	* glom/mode_data/datawidget/combo.cc: set_text(): Don't show a warning if 
+ 	"" is not found because it's OK to use that to clear the combo.
+ 	* glom/mode_data/datawidget/combochoiceswithtreemodel.cc: 
+ 	set_choices_with_second(): Don't dereference a null smartpointer, avoiding 
+ 	a crash with one .glom file that I tried.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Python Glom API documentation improvement.
+ 	
+ 	* glom/python_embed/python_module/py_glom_module.cc: Turn off auto-writing 
+ 	of the Python signatures in the docstrings, because that is a) crappy and 
+ 	b) confuses the sphinx autodoc module, which adds an invisible ..function 
+ 	reStrucuredText line.
+ 	Add :param:, :type, and :returns: lines with the necessary indenting and 
+ 	empty lines needed by that invisible ..function line. 
+ 	
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Move some more methods from Base_DB.
+ 	
+ 	* glom/base_db.[h|cc]: Move show_warning_no_records_found() to utils_ui.[h|cc].
+ 	get_find_where_clause_quick(): Move to utils.[h|cc].
+ 	* glom/frame_glom.cc: Adapted.
+ 	* glom/mode_design/layout/layout_item_dialogs/box_formatting.h:
+ 	* glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.[h|cc]:
+ 		* glom/mode_data/datawidget/dialog_choose_id.[h|cc]: Don't derive from Base_DB 
+ 	because that is no longer necessary after adapting.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	* glom/libglom/db_utils.cc: create_database(): Actually use the progress slot.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Move some Base_DB methods to DbUtils and test database recreation.
+ 	
+ 	* glom/base_db.[h|cc]: Move many db-related methods to 
+ 	glom/libglom/db_utils.[h|cpp], taking a Document* paramater where necessary.
+ 	This makes Base_DB slightly less of a mess, makes it clearer when we are 
+ 	doing Database IO, and makes it possible to do more testing of non-UI code.
+ 	* Makefile_tests.am:
+ 	* tests/test_selfhost_new_from_example.cc: Use DbUtils to recreate the 
+ 	database structure and data from the example file.
+ 	* Many files: Adapted.
+ 
+ This is the master branch. See also the glom-1-14 branch.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Fix document saving (recently broken by me) and add a test for it.
+ 
+ 	* glom/libglom/document/bakery/document.cc: write_to_disk():
+ 	Do not fail if the parent directory already exists.
+ 	* Makefile_tests.am:
+ 	* tests/test_document_autosave.cc: Added a test of document saving and 
+ 	autosaving.
+ 
+ 2010-05-01  Murray Cumming  <murrayc murrayc com>
+ 
+ 	Move tests out of sub-directories, simplifying the build file.
+ 
+ 	* tests/Makefile_test.am:
+ 	* tests/test_document_load.cc:
+ 	* tests/test_selfhosting_new_empty.cc: Move out of the sub-directories,
+ 	because they do not need extra files.
+ 
+ 2010-04-27  Murray Cumming  <murrayc murrayc-x61>
+ 
+ 	PyGlom: Don't use deprecated boost::python::args.
+ 	
+ 	* glom/python_embed/python_module/py_glom_module.cc: Use boost::python::arg() 
+ 	instead of boost::python::args(), because I noticed that args is deprecated.
+ 
 +2010-04-27  Murray Cumming  <murrayc murrayc com>
 +
 +    More use of SqlBuilder.
 +
 +	* glom/base_db.[h|cc]: Move sqlbuilder_get_full_query() to Utils so that
 +    other code can use it.
 +	* glom/libglom/utils.[h|cc]: get_choice_values(): Use SqlBuilder.
 +
 +2010-04-27  Murray Cumming  <murrayc murrayc com>
 +
 +    More use of SqlBuilder.
 +
 +	* glom/report_builder.cc: report_build_groupby(): Use the new
 +    SqlBuilder::select_group_by() method to replace another SQL string.
 +
  1.14.1:
  
  2010-04-27  Murray Cumming  <murrayc murrayc com>
diff --cc glom/base_db.cc
index 9f98932,cccfeeb..f169ef5
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@@ -212,79 -212,26 +212,80 @@@ Glib::RefPtr<Gnome::Gda::DataModel> Bas
    const Application* app = Application::get_application();
    if(stmt && app && app->get_show_sql_debug())
    {
 +    const std::string full_query = Utils::sqlbuilder_get_full_query(gda_connection, strQuery, params);
 +    std::cout << "Debug: Base_DB::query_execute_select():  " << full_query << std::endl;
 +  }
 +
  #ifdef GLIBMM_EXCEPTIONS_ENABLED
 -    try
 -    {
 -      const Glib::ustring full_query = stmt->to_sql(params);
 -      std::cout << "Debug: Base_DB::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;
 -    }
 +  try
 +  {
 +    result = gda_connection->statement_execute_select(stmt, params);
 +  }
 +  catch(const Gnome::Gda::ConnectionError& ex)
 +  {
 +    std::cout << "debug: Base_DB::query_execute_select(): ConnectionError: exception from statement_execute_select(): " << ex.what() << std::endl;
 +  }
 +  catch(const Gnome::Gda::ServerProviderError& ex)
 +  {
 +    std::cout << "debug: Base_DB::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: Base_DB::query_execute_select(): Error exception from statement_execute_select(): " << ex.what() << std::endl;
 +  }
  #else
 -      const Glib::ustring full_query = stmt->to_sql(params, ex);
 -      std::cout << "Debug: Base_DB::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;
 +  result = gda_connection->statement_execute_select(stmt, params, ex);
 +  if(ex.get())
 +    std::cout << "debug: Base_DB::query_execute_select(): Glib::Error from statement_execute_select(): " << ex->what() << std::endl;
 +#endif //GLIBMM_EXCEPTIONS_ENABLED
 +
 +  if(!result)
 +  {
 +    const std::string full_query = Utils::sqlbuilder_get_full_query(gda_connection, strQuery, params);
 +    std::cerr << "Glom  Base_DB::query_execute_select(): Error while executing SQL" << std::endl <<
 +      "  " <<  full_query << std::endl;
 +    handle_error();
 +  }
  
 +  return result;
 +}
 +
 +//static:
 +Glib::RefPtr<Gnome::Gda::DataModel> Base_DB::query_execute_select(const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
 +                                                                  const Glib::RefPtr<const Gnome::Gda::Set>& params)
 +{
 +  Glib::RefPtr<Gnome::Gda::DataModel> result;
 +
 +  //TODO: BusyCursor busy_cursor(get_app_window());
 +
 +#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::query_execute_select() failed (query was: %s): %s", strQuery.c_str(), error->what());
 +    // TODO: Rethrow?
 +  }
  #endif
 +  if(!sharedconnection)
 +  {
 +    std::cerr << "Base_DB::query_execute_select(): No connection yet." << std::endl;
 +    return result;
 +  }
 +
 +  Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
 +
 +  //Debug output:
 +  const Application* app = Application::get_application();
 +  if(app && app->get_show_sql_debug())
 +  {
 +    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, params);
 +    std::cout << "Debug: Base_DB::query_execute_select():  " << full_query << std::endl;
    }
  
+   //TODO: Use DbUtils::query_execute().
  #ifdef GLIBMM_EXCEPTIONS_ENABLED
    try
    {
@@@ -646,7 -424,7 +522,6 @@@ void Base_DB::set_document(Document* pD
  
  }
  
--
  //static:
  Base_DB::type_vec_strings Base_DB::util_vecStrings_from_Fields(const type_vec_fields& fields)
  {
@@@ -661,260 -439,7 +536,6 @@@
    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:
@@@ -1789,124 -609,7 +705,44 @@@ bool Base_DB::change_columns(const Glib
  
    return true;
  }
- #endif
+ 
++#endif //GLOM_ENABLE_CLIENT_ONLY
 +
 +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;
- 
-     ParameterNameGenerator generator;
-     Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_INSERT);
-     builder->set_table(table_name);
- 
-     for(unsigned int i = 0; i < row_data.size(); ++i) //TODO_Performance: Avoid calling size() so much.
-     {
-       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;
-       }
- 
-       const Gnome::Gda::Value& value = row_data[i];
-       if(!value.is_null()) //TODO: Remove this check when libgda allows this.
-       {
-         /*
-         std::cout << "debug: field=" << field->get_name() << ", value=" << value.to_string() << std::endl;
-         if(value.get_value_type() == GDA_TYPE_NULL)
-           std::cout << "  (GDA_TYPE_NULL)" << std::endl;
-         else
-           std::cout << "  value.get_value_type()=" << value.get_value_type() << std::endl;
-         */
-         builder->add_field_value_as_value(field->get_name(), value);
-       }
-     }
- 
-     insert_succeeded = query_execute(builder);
-     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;
- }
 +
++#ifndef GLOM_ENABLE_CLIENT_ONLY
  sharedptr<LayoutItem_Field> Base_DB::offer_field_list_select_one_field(const Glib::ustring& table_name, Gtk::Window* transient_for)
  {
    return offer_field_list_select_one_field(sharedptr<LayoutItem_Field>(), table_name, transient_for);
diff --cc glom/base_db.h
index b330846,33295f3..571522c
--- a/glom/base_db.h
+++ b/glom/base_db.h
@@@ -103,26 -87,12 +96,12 @@@ 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;
  
-   bool change_columns(const Glib::ustring& table_name, const type_vec_const_fields& old_fields, type_vec_fields& fields, Gtk::Window* parent_window) const;
+   typedef std::vector< sharedptr<Field> > type_vec_fields;
+   typedef std::vector< sharedptr<const Field> > type_vec_const_fields;
 -  
 +
-   bool insert_example_data(const Glib::ustring& table_name) const;
+   bool change_columns(const Glib::ustring& table_name, const type_vec_const_fields& old_fields, type_vec_fields& fields, Gtk::Window* parent_window) const;
  
  #endif //GLOM_ENABLE_CLIENT_ONLY
  
@@@ -397,13 -339,7 +348,6 @@@ 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);
diff --cc glom/libglom/db_utils.cc
index 0000000,f3b104d..8a9ac08
mode 000000,100644..100644
--- a/glom/libglom/db_utils.cc
+++ b/glom/libglom/db_utils.cc
@@@ -1,0 -1,1680 +1,1808 @@@
+ /* 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 
++/** 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
+ 
+   progress();
 -  
++
+   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;
+   }
+ 
+   progress();
 -  
++
+   //Connect to the actual database:
+   ConnectionPool* connection_pool = ConnectionPool::get_instance();
+   connection_pool->set_database(database_name);
+ 
+   progress();
 -  
++
+   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)
+   {
+     progress();
 -    
++
+     bool test = add_standard_tables(document); //Add internal, hidden, tables.
+     if(!test)
+       return false;
+ 
+     progress();
 -    
++
+     //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;
+ 
+     progress();
+ 
+     //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;
+     }
+ 
+     progress();
+ 
+     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 "\"";
++  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
++    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_NAME, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_NAME, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE, GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++
++  if(optional_org_logo)
++  {
++    builder->select_add_field(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO, 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);
++      //const std::string full_query = Utils::sqlbuilder_get_full_query(builder);
++      Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(builder);
+       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.
++   //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;
++
++  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
++  builder->set_table(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_NAME, prefs.m_name);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET, prefs.m_org_address_street);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_STREET2, prefs.m_org_address_street2);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_TOWN, prefs.m_org_address_town);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTY, prefs.m_org_address_county);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_COUNTRY, prefs.m_org_address_country);
++  builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_ADDRESS_POSTCODE, prefs.m_org_address_postcode);
+   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, ";
++    builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO, prefs.m_org_logo);
+   }
 -  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);
++  builder->set_where(builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                       builder->add_id(GLOM_STANDARD_TABLE_PREFS_FIELD_ID),
++                                       builder->add_expr(1)));
++  const bool test = query_execute(builder);
+ 
+   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)");
++        Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_INSERT);
++        builder->set_table(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++        builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_ID, 1);
++        const bool test = query_execute(builder);
+         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");
++          Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
++          builder->set_table(GLOM_STANDARD_TABLE_PREFS_TABLE_NAME);
++          builder->add_field_value(GLOM_STANDARD_TABLE_PREFS_FIELD_NAME, system_name);
++          builder->set_where(builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                               builder->add_id(GLOM_STANDARD_TABLE_PREFS_FIELD_ID),
++                                               builder->add_expr(1)));
++          const bool test = query_execute(builder);
+           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.");
++    g_warning("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);
++
++  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
++  builder->set_table(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
++  builder->add_field_value_as_value(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE, next_value);
++  builder->set_where(builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND,
++                                       builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                                         builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME),
++                                                         builder->add_expr(table_name)),
++                                       builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                                         builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME),
++                                                         builder->add_expr(field_name))));
++  const bool test = query_execute(builder);
+   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);
++  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
++    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
++  builder->select_add_field("next_value", GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
++  builder->select_add_target(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
++  builder->set_where(
++    builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND,
++      builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++        builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME),
++        builder->add_expr(table_name)),
++      builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++        builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME),
++        builder->add_expr(field_name))));
++
++  const Glib::RefPtr<const Gnome::Gda::DataModel> datamodel = query_execute_select(builder);
+   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)";
++    builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_INSERT);
++    builder->set_table(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
++    builder->add_field_value(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME, table_name);
++    builder->add_field_value(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME, field_name);
++    builder->add_field_value(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE, 0);
+ 
 -    const bool test = query_execute(sql_query, params);
++    const bool test = query_execute(builder);
+     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);
++  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
++  std::list<guint> args;
++  args.push_back(builder->add_id(table_name + "." + field_name));
++  builder->add_field_id(builder->add_function("MAX", args));
++  builder->select_add_target(table_name);
++
++  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(builder);
+   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);
++    builder.reset();
++    builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
++    builder->set_table(GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME);
++    builder->add_field_value_as_value(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE, next_value);
++    builder->set_where(builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND,
++                                         builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                                           builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME),
++                                                           builder->add_expr(table_name)),
++                                         builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
++                                                           builder->add_id(GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME),
++                                                           builder->add_expr(field_name))));
++
++    const bool test = query_execute(builder);
+     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:
++Glib::RefPtr<Gnome::Gda::DataModel> query_execute_select(const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
++  const Glib::RefPtr<const 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;
++  }
++
++  //Debug output:
++  if(builder && ConnectionPool::get_instance()->get_show_debug_output())
++  {
++    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, params);
++    std::cout << "Debug: query_execute_select():  " << full_query << std::endl;
++  }
++
++  //TODO: Use DbUtils::query_execute().
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
++  try
++  {
++    result = gda_connection->statement_execute_select_builder(builder, params);
++  }
++  catch(const Gnome::Gda::ConnectionError& ex)
++  {
++    std::cerr << "debug: query_execute_select(): ConnectionError: exception from statement_execute_select_builder(): " << ex.what() << std::endl;
++  }
++  catch(const Gnome::Gda::ServerProviderError& ex)
++  {
++    std::cerr << "debug: query_execute_select(): ServerProviderError: exception from statement_execute_select_builder(): code=" << ex.code() << "message=" << ex.what() << std::endl;
++  }
++  catch(const Glib::Error& ex)
++  {
++    std::cerr << "debug: query_execute_select(): Error: exception from statement_execute_select_builder(): " << ex.what() << std::endl;
++  }
++
++#else
++  result = gda_connection->statement_execute_select_builder(builder, params, ex);
++  if(ex.get())
++    std::cerr << "debug: query_execute_select(): Glib::Error from statement_execute_select_builder(): " << ex->what() << std::endl;
++#endif //GLIBMM_EXCEPTIONS_ENABLED
++
++  if(!result)
++  {
++    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, params);
++    std::cerr << "Glom  query_execute_select(): Error while executing SQL: "
++      << std::endl << "  " << full_query << std::endl << std::endl;
++    handle_error();
++  }
++
++  return result;
++}
++
+ 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);
+ }
+ 
++bool query_execute(const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
++                            const Glib::RefPtr<const 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;
++  }
++
++  //Debug output:
++  if(builder && ConnectionPool::get_instance()->get_show_debug_output())
++  {
++    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, params);
++    std::cerr << "Debug: query_execute(): " << full_query << std::endl;
++  }
++
++
++  int exec_retval = -1;
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
++  try
++  {
++    exec_retval = gda_connection->statement_execute_non_select_builder(builder, params);
++  }
++  catch(const Glib::Error& error)
++  {
++    std::cerr << "BaseDB::query_execute: ConnectionError: " << error.what() << std::endl;
++    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, 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_builder(builder, params, exec_error);
++  if(exec_error.get())
++  {
++    std::cerr << "BaseDB::query_execute: ConnectionError: " << exec_error->what() << std::endl;
++    const std::string full_query = Utils::sqlbuilder_get_full_query(builder, params);
++    std::cerr << "  full_query: " << full_query << std::endl;
++    return false;
++  }
++#endif
++  return (exec_retval >= 0);
++}
++
+ } //namespace DbUtils
+ 
+ } //namespace Glom
 -
diff --cc glom/libglom/db_utils.h
index 0000000,042b1ae..205f41f
mode 000000,100644..100644
--- a/glom/libglom/db_utils.h
+++ b/glom/libglom/db_utils.h
@@@ -1,0 -1,99 +1,110 @@@
+ /* 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, 
++/** 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, 
++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 Select command, returning the result.
++  */
++Glib::RefPtr<Gnome::Gda::DataModel> query_execute_select(
++  const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
++  const Glib::RefPtr<const Gnome::Gda::Set>& params = Glib::RefPtr<const 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));
+ 
++/** Execute a SQL non-select command, returning true if it succeeded.
++  */
++bool query_execute(const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
++  const Glib::RefPtr<const Gnome::Gda::Set>& params = Glib::RefPtr<const 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 --cc glom/libglom/privs.cc
index 74764c5,128b055..97fdf20
--- a/glom/libglom/privs.cc
+++ b/glom/libglom/privs.cc
@@@ -33,23 -35,19 +35,23 @@@ Privs::type_vec_strings Privs::get_data
  {
    type_vec_strings result;
  
 -  const Glib::ustring strQuery = "SELECT \"pg_group\".\"groname\" FROM \"pg_group\"";
 -  Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(strQuery);
 +  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
 +      Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
 +  builder->select_add_field("groname", "pg_group");
 +  builder->select_add_target("pg_group");
-   
-   Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
++
++  Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
    if(data_model)
    {
      const int rows_count = data_model->get_n_rows();
      for(int row = 0; row < rows_count; ++row)
      {
--#ifdef GLIBMM_EXCEPTIONS_ENABLED    
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
        const Gnome::Gda::Value value = data_model->get_value_at(0, row);
  #else
        std::auto_ptr<Glib::Error> value_error;
--      const Gnome::Gda::Value value = data_model->get_value_at(0, row, value_error); 
--#endif           
++      const Gnome::Gda::Value value = data_model->get_value_at(0, row, value_error);
++#endif
        const Glib::ustring name = value.get_string();
        result.push_back(name);
      }
@@@ -105,51 -103,39 +107,51 @@@ Privs::type_vec_strings Privs::get_data
    if(group_name.empty())
    {
      //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 = DbUtils::query_execute_select(strQuery);
 +    Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
 +      Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
 +    builder->select_add_field("usename", "pg_shadow");
 +    builder->select_add_target("pg_shadow");
-   
-     Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
++
++    Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
      if(data_model)
      {
        const int rows_count = data_model->get_n_rows();
        for(int row = 0; row < rows_count; ++row)
        {
--#ifdef GLIBMM_EXCEPTIONS_ENABLED      
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
          const Gnome::Gda::Value value = data_model->get_value_at(0, row);
  #else
--        std::auto_ptr<Glib::Error> value_error;       
++        std::auto_ptr<Glib::Error> value_error;
          const Gnome::Gda::Value value = data_model->get_value_at(0, row, value_error);
--#endif         
--        const Glib::ustring name = value.get_string();        
++#endif
++        const Glib::ustring name = value.get_string();
          result.push_back(name);
        }
      }
    }
    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 = DbUtils::query_execute_select(strQuery);
 +    Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
 +      Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
 +    builder->select_add_field("groname", "pg_group");
 +    builder->select_add_field("grolist", "pg_group");
 +    builder->select_add_target("pg_group");
 +    builder->set_where(
 +      builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
 +        builder->add_id("groname"), //TODO: It would be nice to specify the table here too.
 +        builder->add_expr(group_name)));
-     Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
++    Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
      if(data_model && data_model->get_n_rows())
      {
        const int rows_count = data_model->get_n_rows();
        for(int row = 0; row < rows_count; ++row)
        {
--#ifdef GLIBMM_EXCEPTIONS_ENABLED      
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
          const Gnome::Gda::Value value = data_model->get_value_at(1, row); //Column 1 is the /* the user list.
  #else
          std::auto_ptr<Glib::Error> value_error;
          const Gnome::Gda::Value value = data_model->get_value_at(1, row, value_error); //Column 1 is the /* the user list.
--#endif        
++#endif
          //pg_group is a string, formatted, bizarrely, like so: "{100, 101}".
  
          Glib::ustring group_list;
@@@ -160,23 -146,16 +162,23 @@@
          for(type_vec_strings::const_iterator iter = vecUserIds.begin(); iter != vecUserIds.end(); ++iter)
          {
            //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 = DbUtils::query_execute_select(strQuery);
 +          Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
 +            Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
 +          builder->select_add_field("usename", "pg_user");
 +          builder->select_add_target("pg_user");
 +          builder->set_where(
 +            builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
 +              builder->add_id("usesysid"), //TODO: It would be nice to specify the table here too.
 +              builder->add_expr(*iter)));
-           Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
++          Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
            if(data_model)
            {
--#ifdef GLIBMM_EXCEPTIONS_ENABLED          
++#ifdef GLIBMM_EXCEPTIONS_ENABLED
              const Gnome::Gda::Value value = data_model->get_value_at(0, 0);
  #else
              std::auto_ptr<Glib::Error> value_error;
--            const Gnome::Gda::Value value = data_model->get_value_at(0, 0, value_error);            
--#endif            
++            const Gnome::Gda::Value value = data_model->get_value_at(0, 0, value_error);
++#endif
              result.push_back(value.get_string());
            }
          }
@@@ -222,7 -201,7 +224,7 @@@ void Privs::set_table_privileges(const 
      if(privs.m_create)
      {
        if(!strPrivilege.empty())
--      
++
          strPrivilege += ", ";
  
        strPrivilege += "INSERT";
@@@ -276,15 -255,8 +278,15 @@@ Privileges Privs::get_table_privileges(
    }
  
    //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 = DbUtils::query_execute_select(strQuery);
 +  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
 +    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
 +  builder->select_add_field("relacl", "pg_class");
 +  builder->select_add_target("pg_class");
 +  builder->set_where(
 +    builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
 +      builder->add_id("relname"), //TODO: It would be nice to specify the table here too.
 +      builder->add_expr(table_name)));
-   Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
++  Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
    if(data_model && data_model->get_n_rows())
    {
  #ifdef GLIBMM_EXCEPTIONS_ENABLED
@@@ -293,7 -265,7 +295,7 @@@
      std::auto_ptr<Glib::Error> value_error;
      const Gnome::Gda::Value value = data_model->get_value_at(0, 0, value_error);
  #endif
--    
++
      Glib::ustring access_details;
      if(!value.is_null())
        access_details = value.get_string();
@@@ -315,7 -287,7 +317,7 @@@
  
        //Find group permissions, ignoring user permissions:
        //We need to find the role by name.
--      // Previous versions of Postgres (8.1, or maybe 7.4) prefixed group names by "group ", 
++      // Previous versions of Postgres (8.1, or maybe 7.4) prefixed group names by "group ",
        // but that doesn't work for recent versions of Postgres,
        // probably because the user and group concepts have been combined into "roles".
        //
@@@ -418,8 -390,8 +420,8 @@@ bool Privs::get_user_is_in_group(const 
  
  bool Privs::on_privs_privileges_cache_timeout(const Glib::ustring& table_name)
  {
--  //std::cout << "DEBUG: Privs::on_privs_privileges_cache_timeou(): table=" << table_name << std::endl;  
--      
++  //std::cout << "DEBUG: Privs::on_privs_privileges_cache_timeou(): table=" << table_name << std::endl;
++
    //Forget the cached privileges after a few seconds:
    type_map_privileges::iterator iter = m_privileges_cache.find(table_name);
    if(iter != m_privileges_cache.end())
@@@ -447,11 -419,11 +449,11 @@@ Privileges Privs::get_current_privs(con
      return iter->second;
    }
  
--   
++
    //Get the up-to-date privileges from the database:
    Privileges result;
  
--  //std::cout << "DEBUG: Privs::get_current_privs(): Getting non-cached." << std::endl;  
++  //std::cout << "DEBUG: Privs::get_current_privs(): Getting non-cached." << std::endl;
  
    ConnectionPool* connection_pool = ConnectionPool::get_instance();
    const Glib::ustring current_user = connection_pool->get_user();
@@@ -468,9 -440,9 +470,9 @@@
  #ifdef GLIBMM_EXCEPTIONS_ENABLED
    sharedptr<SharedConnection> sharedconnection = connection_pool->connect();
  #else
--  std::auto_ptr<ExceptionConnection> ex;  
++  std::auto_ptr<ExceptionConnection> ex;
    sharedptr<SharedConnection> sharedconnection = connection_pool->connect(ex);
--#endif  
++#endif
    if(sharedconnection && sharedconnection->get_gda_connection()->supports_feature(Gnome::Gda::CONNECTION_FEATURE_USERS))
    {
      //Get the "true" rights for any groups that the user is in:
@@@ -514,9 -486,9 +516,9 @@@
    if(iter_connection != m_map_cache_timeouts.end())
      iter_connection->second.disconnect();
  
--  m_map_cache_timeouts[table_name] = 
++  m_map_cache_timeouts[table_name] =
      Glib::signal_timeout().connect_seconds(
--      sigc::bind( sigc::ptr_fun(&Privs::on_privs_privileges_cache_timeout), table_name ), 
++      sigc::bind( sigc::ptr_fun(&Privs::on_privs_privileges_cache_timeout), table_name ),
        30 /* seconds */);
  
    return result;
diff --cc glom/libglom/utils.cc
index 49cb268,5fe1625..d3be830
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@@ -853,100 -841,48 +853,141 @@@ bool Utils::file_exists(const Glib::ust
    }
  }
  
- 
 +std::string Utils::sqlbuilder_get_full_query(
 +    const Glib::RefPtr<Gnome::Gda::Connection>& connection,
 +    const Glib::ustring& query,
 +    const Glib::RefPtr<const Gnome::Gda::Set>& params)
 +{
 +  Glib::ustring result = "glom_query_not_parsed";
 +
 +  try
 +  {
 +    Glib::RefPtr<Gnome::Gda::SqlParser> parser = connection->create_parser();
 +    if(parser)
 +    {
 +      Glib::RefPtr<Gnome::Gda::Statement> stmt = parser->parse_string(query);
 +      if(stmt)
 +        result = stmt->to_sql(params);
 +    }
 +  }
 +  catch(const Glib::Exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while parsing query: " << ex.what() << std::endl;
 +  }
 +  catch(const std::exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while parsing query: " << ex.what() << std::endl;
 +  }
 +
 +  //Convert to something that std::cout should be able to handle.
 +  const Glib::ScopedPtr<char> buf(g_convert_with_fallback(
 +    result.raw().data(), result.raw().size(),
 +    "ISO-8859-1", "UTF-8",
 +    (char*)"?",
 +    0, 0, 0));
 +  return std::string(buf.get());
 +}
 +
 +
 +std::string Utils::sqlbuilder_get_full_query(
 +  const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
 +  const Glib::RefPtr<const Gnome::Gda::Set>& params)
 +{
 +  Glib::ustring result = "glom_query_not_parsed";
 +
 +  try
 +  {
 +    Glib::RefPtr<Gnome::Gda::Statement> stmt = builder->get_statement();
 +    if(stmt)
 +      result = stmt->to_sql(params);
 +  }
 +  catch(const Glib::Exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while getting query: " << ex.what() << std::endl;
 +  }
 +  catch(const std::exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while getting query: " << ex.what() << std::endl;
 +  }
 +
 +  //Convert to something that std::cout should be able to handle.
 +  const Glib::ScopedPtr<char> buf(g_convert_with_fallback(
 +    result.raw().data(), result.raw().size(),
 +    "ISO-8859-1", "UTF-8",
 +    (char*)"?",
 +    0, 0, 0));
 +  return std::string(buf.get());
 +}
 +
 +std::string Utils::sqlbuilder_get_full_query(
 +  const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder)
 +{
 +  Glib::ustring result = "glom_query_not_parsed";
 +
 +  try
 +  {
 +    Glib::RefPtr<Gnome::Gda::Statement> stmt = builder->get_statement();
 +    if(stmt)
 +      result = stmt->to_sql();
 +  }
 +  catch(const Glib::Exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while getting query: " << ex.what() << std::endl;
 +  }
 +  catch(const std::exception& ex)
 +  {
 +    std::cerr << "sqlbuilder_get_full_query(): exception while getting query: " << ex.what() << std::endl;
 +  }
 +
 +  //Convert to something that std::cout should be able to handle.
 +  const Glib::ScopedPtr<char> buf(g_convert_with_fallback(
 +    result.raw().data(), result.raw().size(),
 +    "ISO-8859-1", "UTF-8",
 +    (char*)"?",
 +    0, 0, 0));
 +  return std::string(buf.get());
 +}
  
 -Glib::ustring Utils::get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search) 
++Glib::ustring Utils::get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search)
+ {
+   Glib::ustring strClause;
+ 
+   if(document)
+   {
+     //TODO: Cache the list of all fields, as well as caching (m_Fields) the list of all visible fields:
+     const Document::type_vec_fields fields = document->get_table_fields(table_name);
+ 
+     typedef std::vector< sharedptr<LayoutItem_Field> > type_vecLayoutFields;
+     type_vecLayoutFields fieldsToGet;
+     for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+     {
+       Glib::ustring strClausePart;
+ 
+       sharedptr<const Field> field = *iter;
+ 
+       bool use_this_field = true;
+       if(field->get_glom_type() != Field::TYPE_TEXT)
+       {
+           use_this_field = false;
+       }
+ 
+       if(use_this_field)
+       {
+         //TODO: Use a SQL parameter instead of using sql().
+         strClausePart = "\"" + table_name + "\".\"" + field->get_name() + "\" " + field->sql_find_operator() + " " +  field->sql_find(quick_search);
+       }
+ 
+       if(!strClausePart.empty())
+       {
+         if(!strClause.empty())
+           strClause += " OR ";
+ 
+         strClause += strClausePart;
+       }
+     }
+   }
+ 
+   return strClause;
+ }
+ 
 -
  } //namespace Glom
diff --cc glom/libglom/utils.h
index af7fd6b,f4f33b6..a792647
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@@ -93,9 -91,11 +94,12 @@@ Glib::ustring build_sql_select_with_key
    const Glib::ustring& table_name,
    const type_vecConstLayoutFields& fieldsToGet,
    const sharedptr<const Field>& key_field,
 -  const Gnome::Gda::Value& key_value);
 +  const Gnome::Gda::Value& key_value,
 +  guint limit = 0);
  
+ Glib::ustring get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search);
+ 
+ 
  typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
  type_list_values_with_second get_choice_values(const sharedptr<const LayoutItem_Field>& field);
  



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