[glom/sqlbuilder2: 23/23] Merged from master.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom/sqlbuilder2: 23/23] Merged from master.
- Date: Thu, 6 May 2010 15:54:40 +0000 (UTC)
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]