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