glom r1932 - in trunk: . glom glom/libglom glom/libglom/connectionpool_backends
- From: arminb svn gnome org
- To: svn-commits-list gnome org
- Subject: glom r1932 - in trunk: . glom glom/libglom glom/libglom/connectionpool_backends
- Date: Tue, 24 Feb 2009 12:36:55 +0000 (UTC)
Author: arminb
Date: Tue Feb 24 12:36:55 2009
New Revision: 1932
URL: http://svn.gnome.org/viewvc/glom?rev=1932&view=rev
Log:
2009-02-24 Armin Burgmeier <armin openismus com>
* glom/libglom/connectionpool_backends/backend.h:
* glom/libglom/connectionpool_backends/backend.cc: Moved the
ConnectionPool backend base class into a new file in the
connectionpool_backends subdirectory.
* glom/libglom/connectionpool_backends/Makefile.am: Add it to the
build.
* glom/libglom/connectionpool_backends/postgres.h:
* glom/libglom/connectionpool_backends/sqlite.h:
* glom/libglom/connectionpool_backends/sqlite.cc:
* glom/libglom/connectionpool.h:
* glom/libglom/connectionpool.cc:
* glom/libglom/test_connectionpool.cc:
* glom/dialog_connection.cc:
* glom/frame_glom.cc: Adapt.
Added:
trunk/glom/libglom/connectionpool_backends/backend.cc
trunk/glom/libglom/connectionpool_backends/backend.h
Modified:
trunk/ChangeLog
trunk/glom/dialog_connection.cc
trunk/glom/frame_glom.cc
trunk/glom/libglom/connectionpool.cc
trunk/glom/libglom/connectionpool.h
trunk/glom/libglom/connectionpool_backends/Makefile.am
trunk/glom/libglom/connectionpool_backends/postgres.h
trunk/glom/libglom/connectionpool_backends/sqlite.cc
trunk/glom/libglom/connectionpool_backends/sqlite.h
trunk/glom/libglom/test_connectionpool.cc
Modified: trunk/glom/dialog_connection.cc
==============================================================================
--- trunk/glom/dialog_connection.cc (original)
+++ trunk/glom/dialog_connection.cc Tue Feb 24 12:36:55 2009
@@ -92,7 +92,7 @@
if(document->get_hosting_mode() == Document_Glom::POSTGRES_CENTRAL_HOSTED)
{
- ConnectionPoolBackend* backend = connection_pool->get_backend();
+ ConnectionPool::Backend* backend = connection_pool->get_backend();
ConnectionPoolBackends::PostgresCentralHosted* central = dynamic_cast<ConnectionPoolBackends::PostgresCentralHosted*>(backend);
g_assert(central != NULL);
@@ -123,7 +123,7 @@
Document_Glom* unconst = const_cast<Document_Glom*>(document);
if(document->get_hosting_mode() == Document_Glom::POSTGRES_CENTRAL_HOSTED)
{
- ConnectionPoolBackend* backend = connection_pool->get_backend();
+ ConnectionPool::Backend* backend = connection_pool->get_backend();
ConnectionPoolBackends::PostgresCentralHosted* central = dynamic_cast<ConnectionPoolBackends::PostgresCentralHosted*>(backend);
g_assert(central != NULL);
@@ -132,7 +132,7 @@
#ifndef GLOM_ENABLE_CLIENT_ONLY
else if(document->get_hosting_mode() == Document_Glom::POSTGRES_SELF_HOSTED)
{
- ConnectionPoolBackend* backend = connection_pool->get_backend();
+ ConnectionPool::Backend* backend = connection_pool->get_backend();
ConnectionPoolBackends::PostgresSelfHosted* self = dynamic_cast<ConnectionPoolBackends::PostgresSelfHosted*>(backend);
g_assert(self != NULL);
Modified: trunk/glom/frame_glom.cc
==============================================================================
--- trunk/glom/frame_glom.cc (original)
+++ trunk/glom/frame_glom.cc Tue Feb 24 12:36:55 2009
@@ -1648,7 +1648,7 @@
{
ConnectionPoolBackends::PostgresSelfHosted* backend = new ConnectionPoolBackends::PostgresSelfHosted;
backend->set_self_hosting_data_uri(document->get_connection_self_hosted_directory_uri());
- connection_pool->set_backend(std::auto_ptr<ConnectionPoolBackend>(backend));
+ connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
}
break;
#endif //GLOM_ENABLE_CLIENT_ONLY
@@ -1658,7 +1658,7 @@
backend->set_host(document->get_connection_server());
backend->set_port(document->get_connection_port());
backend->set_try_other_ports(document->get_connection_try_other_ports());
- connection_pool->set_backend(std::auto_ptr<ConnectionPoolBackend>(backend));
+ connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
}
break;
@@ -1667,7 +1667,7 @@
{
ConnectionPoolBackends::Sqlite* backend = new ConnectionPoolBackends::Sqlite;
backend->set_database_directory_uri(document->get_connection_self_hosted_directory_uri());
- connection_pool->set_backend(std::auto_ptr<ConnectionPoolBackend>(backend));
+ connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
}
break;
#endif // GLOM_ENABLE_SQLITE
@@ -1874,7 +1874,7 @@
// Remember host if the document is not self hosted
if(document->get_hosting_mode() == Document_Glom::POSTGRES_CENTRAL_HOSTED)
{
- ConnectionPoolBackend* backend = connection_pool->get_backend();
+ ConnectionPool::Backend* backend = connection_pool->get_backend();
ConnectionPoolBackends::PostgresCentralHosted* central = dynamic_cast<ConnectionPoolBackends::PostgresCentralHosted*>(backend);
g_assert(central != NULL);
Modified: trunk/glom/libglom/connectionpool.cc
==============================================================================
--- trunk/glom/libglom/connectionpool.cc (original)
+++ trunk/glom/libglom/connectionpool.cc Tue Feb 24 12:36:55 2009
@@ -158,25 +158,6 @@
namespace Glom
{
-ExceptionConnection::ExceptionConnection(failure_type failure)
-: m_failure_type(failure)
-{
-}
-
-ExceptionConnection::~ExceptionConnection() throw()
-{
-}
-
-const char* ExceptionConnection::what() const throw()
-{
- return "Glom database connection failed.";
-}
-
-ExceptionConnection::failure_type ExceptionConnection::get_failure_type() const
-{
- return m_failure_type;
-}
-
SharedConnection::SharedConnection()
{
}
@@ -219,229 +200,6 @@
m_signal_finished.emit();
}
-
-
-bool ConnectionPoolBackend::initialize(Gtk::Window* /* parent_window */, const Glib::ustring& /* initial_username */, const Glib::ustring& /* password */)
-{
- return true;
-}
-
-bool ConnectionPoolBackend::startup(Gtk::Window* /* parent_window */)
-{
- return true;
-}
-
-void ConnectionPoolBackend::cleanup(Gtk::Window* /* parent_window */)
-{}
-
-bool ConnectionPoolBackend::set_server_operation_value(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const Glib::ustring& path, const Glib::ustring& value, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- operation->set_value_at(path, value);
- return true;
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- operation->set_value_at(path, value, error);
- if(error.get()) return false;
- return true;
-#endif
-}
-
-Glib::RefPtr<Gnome::Gda::ServerOperation> ConnectionPoolBackend::create_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, Gnome::Gda::ServerOperationType type, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- return provider->create_operation(connection, type);
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return Glib::RefPtr<Gnome::Gda::ServerOperation>();
- }
-#else
- return provider->create_operation(connection, type, error);
-#endif
-}
-
-bool ConnectionPoolBackend::perform_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- provider->perform_operation(connection, operation);
- return true;
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- provider->perform_operation(connection, operation, error);
- if(error.get()) return false;
- return true;
-#endif
-}
-
-bool ConnectionPoolBackend::begin_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, Gnome::Gda::TransactionIsolation level, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- return connection->begin_transaction(name, level);
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- return connection->begin_transaction(name, level, error);
-#endif
-}
-
-bool ConnectionPoolBackend::commit_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- return connection->commit_transaction(name);
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- return connection->commit_transaction(name, error);
-#endif
-}
-
-bool ConnectionPoolBackend::rollback_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- return connection->rollback_transaction(name);
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- return connection->rollback_transaction(name, error);
-#endif
-}
-
-bool ConnectionPoolBackend::query_execute(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& sql_query, std::auto_ptr<Glib::Error>& error)
-{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- return connection->statement_execute_non_select(sql_query) != -1;
- }
- catch(const Glib::Error& ex)
- {
- error.reset(new Glib::Error(ex));
- return false;
- }
-#else
- return connection->statement_execute_non_select(sql_query, error) != -1;
-#endif
-}
-
-#ifndef GLOM_ENABLE_CLIENT_ONLY
-bool ConnectionPoolBackend::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field, std::auto_ptr<Glib::Error>& error)
-{
- Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
- Glib::RefPtr<Gnome::Gda::ServerOperation> operation = create_server_operation(provider, connection, Gnome::Gda::SERVER_OPERATION_ADD_COLUMN, error);
- if(!operation) return false;
-
- if(!set_server_operation_value(operation, "/COLUMN_DEF_P/TABLE_NAME", table_name, error)) return false;
- if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_NAME", field->get_name(), error)) return false;
- if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_TYPE", field->get_sql_type(), error)) return false;
- if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_PKEY", field->get_primary_key() ? "TRUE" : "FALSE", error)) return false;
- if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_UNIQUE", field->get_unique_key() ? "TRUE" : "FALSE", error)) return false;
-
- if(!perform_server_operation(provider, connection, operation, error)) return false;
- return true;
-}
-
-bool ConnectionPoolBackend::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name, std::auto_ptr<Glib::Error>& error)
-{
- Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
- Glib::RefPtr<Gnome::Gda::ServerOperation> operation = create_server_operation(provider, connection, Gnome::Gda::SERVER_OPERATION_DROP_COLUMN, error);
- if(!operation) return false;
-
- if(!set_server_operation_value(operation, "/COLUMN_DESC_P/TABLE_NAME", table_name, error)) return false;
- if(!set_server_operation_value(operation, "/COLUMN_DESC_P/COLUMN_NAME", field_name, error)) return false;
-
- if(!perform_server_operation(provider, connection, operation, error)) return false;
- return true;
-}
-
-//TODO: Why/When do we need to change multiple columns instead of a single one? murrayc.
-//When changing a table's primary key, we unset the primary key for the old
-//column and set it for the new column. Using a single call to the
-//ConnectionPoolBackend for this, the backend can do all the required
-//operations at once, maybe optimizing them. For example, for SQLite we need
-//to recreate the whole table when changing columns, so we only need to do
-//this once instead of twice when changing the primary key. armin.
-bool ConnectionPoolBackend::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecConstFields& old_fields, const type_vecConstFields& new_fields, std::auto_ptr<Glib::Error>& error)
-{
- static const char* TRANSACTION_NAME = "glom_change_columns_transaction";
- static const gchar* TEMP_COLUMN_NAME = "glom_temp_column"; // TODO: Find a unique name.
-
- if(!begin_transaction(connection, TRANSACTION_NAME, Gnome::Gda::TRANSACTION_ISOLATION_UNKNOWN, error)) return false; // TODO: What does the transaction isolation do?
-
- for(unsigned int i = 0; i < old_fields.size(); ++ i)
- {
- // TODO: Don't create an intermediate column if the name of the column
- // changes anyway.
- sharedptr<Field> temp_field = glom_sharedptr_clone(new_fields[i]);
- temp_field->set_name(TEMP_COLUMN_NAME);
- // The temporary column must not be a primary key, otherwise
- // we might end up with two primary key columns temporarily, which most
- // database systems do not allow.
- temp_field->set_primary_key(false);
-
- if(!add_column(connection, table_name, temp_field, error)) break;
-
- const Glib::ustring temp_move_query = "UPDATE " + table_name + " SET " + TEMP_COLUMN_NAME + " = CAST(" + old_fields[i]->get_name() + " AS " + new_fields[i]->get_sql_type() + ")";
- if(!query_execute(connection, temp_move_query, error)) break;
- // TODO: If this CAST was not successful, then just go on,
- // dropping the data in the column?
-
- if(!drop_column(connection, table_name, old_fields[i]->get_name(), error)) return false;
-
- if(!add_column(connection, table_name, new_fields[i], error)) break;
-
- const Glib::ustring final_move_query = "UPDATE " + table_name + " SET " + new_fields[i]->get_name() + " = " + TEMP_COLUMN_NAME; // TODO: Do we need a cast here, even though the type matches?
- if(!query_execute(connection, final_move_query, error)) break;
-
- if(!drop_column(connection, table_name, TEMP_COLUMN_NAME, error)) break;
- }
-
- if(error.get() || !commit_transaction(connection, TRANSACTION_NAME, error))
- {
- std::auto_ptr<Glib::Error> rollback_error;
- rollback_transaction(connection, TRANSACTION_NAME, rollback_error);
- return false;
- }
-
- return true;
-}
-#endif // !GLOM_ENABLE_CLIENT_ONLY
-
//init_db_details static data:
ConnectionPool* ConnectionPool::m_instance = 0;
@@ -499,17 +257,17 @@
m_ready_to_connect = val;
}
-void ConnectionPool::set_backend(std::auto_ptr<ConnectionPoolBackend> backend)
+void ConnectionPool::set_backend(std::auto_ptr<Backend> backend)
{
m_backend = backend;
}
-ConnectionPoolBackend* ConnectionPool::get_backend()
+ConnectionPool::Backend* ConnectionPool::get_backend()
{
return m_backend.get();
}
-const ConnectionPoolBackend* ConnectionPool::get_backend() const
+const ConnectionPool::Backend* ConnectionPool::get_backend() const
{
return m_backend.get();
}
Modified: trunk/glom/libglom/connectionpool.h
==============================================================================
--- trunk/glom/libglom/connectionpool.h (original)
+++ trunk/glom/libglom/connectionpool.h Tue Feb 24 12:36:55 2009
@@ -21,15 +21,16 @@
#ifndef GLOM_CONNECTIONPOOL_H
#define GLOM_CONNECTIONPOOL_H
+#include "config.h" // For GLOM_ENABLE_CLIENT_ONLY
+
#include <libgdamm.h>
#include <glom/libglom/sharedptr.h>
#include <glom/libglom/data_structure/fieldtypes.h>
#include <glom/libglom/data_structure/field.h>
+#include <glom/libglom/connectionpool_backends/backend.h>
#include <memory> // For std::auto_ptr
-#include "config.h" // For GLOM_ENABLE_CLIENT_ONLY
-
//Avoid including the header here:
extern "C"
{
@@ -49,26 +50,6 @@
class AvahiPublisher;
-class ExceptionConnection : public std::exception
-{
-public:
- enum failure_type
- {
- FAILURE_NO_SERVER, //Either there was no attempt to connect to a specific database, or the connection failed both with and without specifying the database.
- FAILURE_NO_DATABASE //Connection without specifying the database was possible.
- };
-
- ExceptionConnection(failure_type failure);
- virtual ~ExceptionConnection() throw();
-
- virtual const char* what() const throw();
-
- virtual failure_type get_failure_type() const;
-
-protected:
- failure_type m_failure_type;
-};
-
/** When the SharedConnection is destroyed, it will inform the connection pool,
* so that the connection pool can keep track of who is using the connection,
* so that it can close it when nobody is using it.
@@ -98,90 +79,6 @@
class Document_Glom;
-//TODO: Put this in the sub-directory:
-
-/** This hides database specific functionality from the ConnectionPool, so
- * the ConnectionPool can be used without worrying about the actual database
- * backend in use. Use ConnectionPool::set_backend() to set the backend for
- * the connectionpool to use. */
-class ConnectionPoolBackend
-{
- friend class ConnectionPool;
-public:
- virtual ~ConnectionPoolBackend() {}
- typedef std::vector<sharedptr<const Field> > type_vecConstFields;
-
-protected:
- /** Helper functions for backend implementations to use, so that these don't
- * need to worry whether glibmm was compiled with exceptions or not.
- */
- bool query_execute(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& sql_query, std::auto_ptr<Glib::Error>& error);
- bool set_server_operation_value(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const Glib::ustring& path, const Glib::ustring& value, std::auto_ptr<Glib::Error>& error);
- Glib::RefPtr<Gnome::Gda::ServerOperation> create_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, Gnome::Gda::ServerOperationType type, std::auto_ptr<Glib::Error>& error);
- bool perform_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, std::auto_ptr<Glib::Error>& error);
- bool begin_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, Gnome::Gda::TransactionIsolation level, std::auto_ptr<Glib::Error>& error);
- bool commit_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error);
- bool rollback_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error);
-
- /* TODO: Merge create_database() and initialize() into a single function?
- */
-
- /** This method specifies the format of values in SQL expressions.
- */
- virtual Field::sql_format get_sql_format() const = 0;
-
- /** Whether the database can be accessed from remote machines, once startup()
- * was called.
- */
- virtual bool supports_remote_access() const = 0;
-
- /** The operator to use to compare strings in a case-independant way. This
- * is backend-depandent. For example, postgres uses ILIKE but SQLite uses
- * LIKE.
- * TODO: Maybe we can use libgda to construct the expression, so we don't
- * need this function.
- */
- virtual Glib::ustring get_string_find_operator() const = 0;
-
- /** This method is called for one-time initialization of the database
- * storage. No need to implement this function if the data is centrally
- * hosted, not managed by Glom.
- */
- virtual bool initialize(Gtk::Window* parent_window, const Glib::ustring& initial_username, const Glib::ustring& password);
-
- /** This method is called before the backend is used otherwise. This can
- * be used to start a self-hosted database server. There is no need to implement
- * this function if there is no need for extra startup code.
- */
- virtual bool startup(Gtk::Window* parent_window);
-
- /** This method is called when the backend is no longer used. This can be
- * used to shut down a self-hosted database server. There is no need to
- * implement this function if there is no need for extra cleanup code.
- */
- virtual void cleanup(Gtk::Window* parent_window);
-
- /** This method is called to create a connection to the database server.
- * There exists only the variant with an error variable as last parameter
- * so we don't need #ifdefs all over the code. This part of the API is only
- * used by the ConnectionPool which will translate the error back into
- * an exception in case exceptions are enabled.
- */
- virtual Glib::RefPtr<Gnome::Gda::Connection> connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password, std::auto_ptr<ExceptionConnection>& error) = 0;
-
-#ifndef GLOM_ENABLE_CLIENT_ONLY
- virtual bool add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field, std::auto_ptr<Glib::Error>& error);
-
- virtual bool drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name, std::auto_ptr<Glib::Error>& error);
-
- virtual bool change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecConstFields& old_fields, const type_vecConstFields& new_fields, std::auto_ptr<Glib::Error>& error);
-
- /** This method is called to create a new database on the
- * database server. */
- virtual bool create_database(const Glib::ustring& database_name, const Glib::ustring& username, const Glib::ustring& password, std::auto_ptr<Glib::Error>& error) = 0;
-#endif
-};
-
/** This is a singleton.
* Use get_instance().
*/
@@ -194,7 +91,8 @@
//ConnectionPool& operator=(const ConnectionPool& src);
public:
- typedef ConnectionPoolBackend::type_vecConstFields type_vecConstFields;
+ typedef ConnectionPoolBackends::Backend Backend;
+ typedef Backend::type_vecConstFields type_vecConstFields;
/** Get the singleton instance.
* Use delete_instance() when the program quits.
@@ -207,10 +105,10 @@
bool get_ready_to_connect() const;
void set_ready_to_connect(bool val = true);
- void set_backend(std::auto_ptr<ConnectionPoolBackend> backend);
+ void set_backend(std::auto_ptr<Backend> backend);
- ConnectionPoolBackend* get_backend();
- const ConnectionPoolBackend* get_backend() const;
+ Backend* get_backend();
+ const Backend* get_backend() const;
/** This method will return a SharedConnection, either by opening a new connection or returning an already-open connection.
* When that SharedConnection is destroyed, or when SharedConnection::close() is called, then the ConnectionPool will be informed.
@@ -345,7 +243,7 @@
Gtk::Dialog* m_dialog_epc_progress; //For progress while generating certificates.
#endif // !GLOM_ENABLE_CLIENT_ONLY
- std::auto_ptr<ConnectionPoolBackend> m_backend;
+ std::auto_ptr<Backend> m_backend;
Glib::RefPtr<Gnome::Gda::Connection> m_refGdaConnection;
guint m_sharedconnection_refcount;
bool m_ready_to_connect;
Modified: trunk/glom/libglom/connectionpool_backends/Makefile.am
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/Makefile.am (original)
+++ trunk/glom/libglom/connectionpool_backends/Makefile.am Tue Feb 24 12:36:55 2009
@@ -4,6 +4,7 @@
noinst_LTLIBRARIES = libconnectionpool_backends.la
libconnectionpool_backends_la_SOURCES = \
+ backend.h backend.cc \
postgres.h postgres.cc \
postgres_central.h postgres_central.cc
Added: trunk/glom/libglom/connectionpool_backends/backend.cc
==============================================================================
--- (empty file)
+++ trunk/glom/libglom/connectionpool_backends/backend.cc Tue Feb 24 12:36:55 2009
@@ -0,0 +1,271 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glom/libglom/connectionpool_backends/backend.h>
+
+namespace Glom
+{
+
+ExceptionConnection::ExceptionConnection(failure_type failure)
+: m_failure_type(failure)
+{
+}
+
+ExceptionConnection::~ExceptionConnection() throw()
+{
+}
+
+const char* ExceptionConnection::what() const throw()
+{
+ return "Glom database connection failed.";
+}
+
+ExceptionConnection::failure_type ExceptionConnection::get_failure_type() const
+{
+ return m_failure_type;
+}
+
+namespace ConnectionPoolBackends
+{
+
+bool Backend::initialize(Gtk::Window* /* parent_window */, const Glib::ustring& /* initial_username */, const Glib::ustring& /* password */)
+{
+ return true;
+}
+
+bool Backend::startup(Gtk::Window* /* parent_window */)
+{
+ return true;
+}
+
+void Backend::cleanup(Gtk::Window* /* parent_window */)
+{}
+
+bool Backend::set_server_operation_value(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const Glib::ustring& path, const Glib::ustring& value, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ operation->set_value_at(path, value);
+ return true;
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ operation->set_value_at(path, value, error);
+ if(error.get()) return false;
+ return true;
+#endif
+}
+
+Glib::RefPtr<Gnome::Gda::ServerOperation> Backend::create_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, Gnome::Gda::ServerOperationType type, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ return provider->create_operation(connection, type);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return Glib::RefPtr<Gnome::Gda::ServerOperation>();
+ }
+#else
+ return provider->create_operation(connection, type, error);
+#endif
+}
+
+bool Backend::perform_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ provider->perform_operation(connection, operation);
+ return true;
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ provider->perform_operation(connection, operation, error);
+ if(error.get()) return false;
+ return true;
+#endif
+}
+
+bool Backend::begin_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, Gnome::Gda::TransactionIsolation level, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ return connection->begin_transaction(name, level);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ return connection->begin_transaction(name, level, error);
+#endif
+}
+
+bool Backend::commit_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ return connection->commit_transaction(name);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ return connection->commit_transaction(name, error);
+#endif
+}
+
+bool Backend::rollback_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ return connection->rollback_transaction(name);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ return connection->rollback_transaction(name, error);
+#endif
+}
+
+bool Backend::query_execute(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& sql_query, std::auto_ptr<Glib::Error>& error)
+{
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ return connection->statement_execute_non_select(sql_query) != -1;
+ }
+ catch(const Glib::Error& ex)
+ {
+ error.reset(new Glib::Error(ex));
+ return false;
+ }
+#else
+ return connection->statement_execute_non_select(sql_query, error) != -1;
+#endif
+}
+
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+bool Backend::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field, std::auto_ptr<Glib::Error>& error)
+{
+ Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
+ Glib::RefPtr<Gnome::Gda::ServerOperation> operation = create_server_operation(provider, connection, Gnome::Gda::SERVER_OPERATION_ADD_COLUMN, error);
+ if(!operation) return false;
+
+ if(!set_server_operation_value(operation, "/COLUMN_DEF_P/TABLE_NAME", table_name, error)) return false;
+ if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_NAME", field->get_name(), error)) return false;
+ if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_TYPE", field->get_sql_type(), error)) return false;
+ if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_PKEY", field->get_primary_key() ? "TRUE" : "FALSE", error)) return false;
+ if(!set_server_operation_value(operation, "/COLUMN_DEF_P/COLUMN_UNIQUE", field->get_unique_key() ? "TRUE" : "FALSE", error)) return false;
+
+ if(!perform_server_operation(provider, connection, operation, error)) return false;
+ return true;
+}
+
+bool Backend::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name, std::auto_ptr<Glib::Error>& error)
+{
+ Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
+ Glib::RefPtr<Gnome::Gda::ServerOperation> operation = create_server_operation(provider, connection, Gnome::Gda::SERVER_OPERATION_DROP_COLUMN, error);
+ if(!operation) return false;
+
+ if(!set_server_operation_value(operation, "/COLUMN_DESC_P/TABLE_NAME", table_name, error)) return false;
+ if(!set_server_operation_value(operation, "/COLUMN_DESC_P/COLUMN_NAME", field_name, error)) return false;
+
+ if(!perform_server_operation(provider, connection, operation, error)) return false;
+ return true;
+}
+
+//TODO: Why/When do we need to change multiple columns instead of a single one? murrayc.
+//When changing a table's primary key, we unset the primary key for the old
+//column and set it for the new column. Using a single call to the
+//ConnectionPoolBackend for this, the backend can do all the required
+//operations at once, maybe optimizing them. For example, for SQLite we need
+//to recreate the whole table when changing columns, so we only need to do
+//this once instead of twice when changing the primary key. armin.
+bool Backend::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecConstFields& old_fields, const type_vecConstFields& new_fields, std::auto_ptr<Glib::Error>& error)
+{
+ static const char* TRANSACTION_NAME = "glom_change_columns_transaction";
+ static const gchar* TEMP_COLUMN_NAME = "glom_temp_column"; // TODO: Find a unique name.
+
+ if(!begin_transaction(connection, TRANSACTION_NAME, Gnome::Gda::TRANSACTION_ISOLATION_UNKNOWN, error)) return false; // TODO: What does the transaction isolation do?
+
+ for(unsigned int i = 0; i < old_fields.size(); ++ i)
+ {
+ // TODO: Don't create an intermediate column if the name of the column
+ // changes anyway.
+ sharedptr<Field> temp_field = glom_sharedptr_clone(new_fields[i]);
+ temp_field->set_name(TEMP_COLUMN_NAME);
+ // The temporary column must not be a primary key, otherwise
+ // we might end up with two primary key columns temporarily, which most
+ // database systems do not allow.
+ temp_field->set_primary_key(false);
+
+ if(!add_column(connection, table_name, temp_field, error)) break;
+
+ const Glib::ustring temp_move_query = "UPDATE " + table_name + " SET " + TEMP_COLUMN_NAME + " = CAST(" + old_fields[i]->get_name() + " AS " + new_fields[i]->get_sql_type() + ")";
+ if(!query_execute(connection, temp_move_query, error)) break;
+ // TODO: If this CAST was not successful, then just go on,
+ // dropping the data in the column?
+
+ if(!drop_column(connection, table_name, old_fields[i]->get_name(), error)) return false;
+
+ if(!add_column(connection, table_name, new_fields[i], error)) break;
+
+ const Glib::ustring final_move_query = "UPDATE " + table_name + " SET " + new_fields[i]->get_name() + " = " + TEMP_COLUMN_NAME; // TODO: Do we need a cast here, even though the type matches?
+ if(!query_execute(connection, final_move_query, error)) break;
+
+ if(!drop_column(connection, table_name, TEMP_COLUMN_NAME, error)) break;
+ }
+
+ if(error.get() || !commit_transaction(connection, TRANSACTION_NAME, error))
+ {
+ std::auto_ptr<Glib::Error> rollback_error;
+ rollback_transaction(connection, TRANSACTION_NAME, rollback_error);
+ return false;
+ }
+
+ return true;
+}
+#endif // !GLOM_ENABLE_CLIENT_ONLY
+
+} // namespace ConnectionPoolBackends
+
+} // namespace Glom
Added: trunk/glom/libglom/connectionpool_backends/backend.h
==============================================================================
--- (empty file)
+++ trunk/glom/libglom/connectionpool_backends/backend.h Tue Feb 24 12:36:55 2009
@@ -0,0 +1,148 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOM_BACKEND_BACKEND_H
+#define GLOM_BACKEND_BACKEND_H
+
+#include <config.h> // For GLOM_ENABLE_CLIENT_ONLY
+
+#include <glom/libglom/sharedptr.h>
+#include <glom/libglom/data_structure/field.h>
+
+#include <gtkmm/window.h>
+
+#include <memory>
+
+namespace Glom
+{
+
+class ConnectionPool;
+
+class ExceptionConnection : public std::exception
+{
+public:
+ enum failure_type
+ {
+ FAILURE_NO_SERVER, //Either there was no attempt to connect to a specific database, or the connection failed both with and without specifying the database.
+ FAILURE_NO_DATABASE //Connection without specifying the database was possible.
+ };
+
+ ExceptionConnection(failure_type failure);
+ virtual ~ExceptionConnection() throw();
+
+ virtual const char* what() const throw();
+
+ virtual failure_type get_failure_type() const;
+
+protected:
+ failure_type m_failure_type;
+};
+
+namespace ConnectionPoolBackends
+{
+
+/** This hides database specific functionality from the ConnectionPool, so
+ * the ConnectionPool can be used without worrying about the actual database
+ * backend in use. Use ConnectionPool::set_backend() to set the backend for
+ * the connectionpool to use. */
+class Backend
+{
+ friend class Glom::ConnectionPool;
+public:
+ virtual ~Backend() {}
+ typedef std::vector<sharedptr<const Field> > type_vecConstFields;
+
+protected:
+ /** Helper functions for backend implementations to use, so that these don't
+ * need to worry whether glibmm was compiled with exceptions or not.
+ */
+ bool query_execute(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& sql_query, std::auto_ptr<Glib::Error>& error);
+ bool set_server_operation_value(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const Glib::ustring& path, const Glib::ustring& value, std::auto_ptr<Glib::Error>& error);
+ Glib::RefPtr<Gnome::Gda::ServerOperation> create_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, Gnome::Gda::ServerOperationType type, std::auto_ptr<Glib::Error>& error);
+ bool perform_server_operation(const Glib::RefPtr<Gnome::Gda::ServerProvider>& provider, const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, std::auto_ptr<Glib::Error>& error);
+ bool begin_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, Gnome::Gda::TransactionIsolation level, std::auto_ptr<Glib::Error>& error);
+ bool commit_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error);
+ bool rollback_transaction(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& name, std::auto_ptr<Glib::Error>& error);
+
+ /* TODO: Merge create_database() and initialize() into a single function?
+ */
+
+ /** This method specifies the format of values in SQL expressions.
+ */
+ virtual Field::sql_format get_sql_format() const = 0;
+
+ /** Whether the database can be accessed from remote machines, once startup()
+ * was called.
+ */
+ virtual bool supports_remote_access() const = 0;
+
+ /** The operator to use to compare strings in a case-independant way. This
+ * is backend-depandent. For example, postgres uses ILIKE but SQLite uses
+ * LIKE.
+ * TODO: Maybe we can use libgda to construct the expression, so we don't
+ * need this function.
+ */
+ virtual Glib::ustring get_string_find_operator() const = 0;
+
+ /** This method is called for one-time initialization of the database
+ * storage. No need to implement this function if the data is centrally
+ * hosted, not managed by Glom.
+ */
+ virtual bool initialize(Gtk::Window* parent_window, const Glib::ustring& initial_username, const Glib::ustring& password);
+
+ /** This method is called before the backend is used otherwise. This can
+ * be used to start a self-hosted database server. There is no need to implement
+ * this function if there is no need for extra startup code.
+ */
+ virtual bool startup(Gtk::Window* parent_window);
+
+ /** This method is called when the backend is no longer used. This can be
+ * used to shut down a self-hosted database server. There is no need to
+ * implement this function if there is no need for extra cleanup code.
+ */
+ virtual void cleanup(Gtk::Window* parent_window);
+
+ /** This method is called to create a connection to the database server.
+ * There exists only the variant with an error variable as last parameter
+ * so we don't need #ifdefs all over the code. This part of the API is only
+ * used by the ConnectionPool which will translate the error back into
+ * an exception in case exceptions are enabled.
+ */
+ virtual Glib::RefPtr<Gnome::Gda::Connection> connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password, std::auto_ptr<ExceptionConnection>& error) = 0;
+
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+ virtual bool add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field, std::auto_ptr<Glib::Error>& error);
+
+ virtual bool drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name, std::auto_ptr<Glib::Error>& error);
+
+ virtual bool change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecConstFields& old_fields, const type_vecConstFields& new_fields, std::auto_ptr<Glib::Error>& error);
+
+ /** This method is called to create a new database on the
+ * database server. */
+ virtual bool create_database(const Glib::ustring& database_name, const Glib::ustring& username, const Glib::ustring& password, std::auto_ptr<Glib::Error>& error) = 0;
+#endif
+};
+
+} // namespace ConnectionPoolBackends
+
+} //namespace Glom
+
+#endif // GLOM_BACKEND_BACKEND_H
+
Modified: trunk/glom/libglom/connectionpool_backends/postgres.h
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/postgres.h (original)
+++ trunk/glom/libglom/connectionpool_backends/postgres.h Tue Feb 24 12:36:55 2009
@@ -22,7 +22,7 @@
#define GLOM_BACKEND_POSTGRES_H
#include <libgdamm.h>
-#include <glom/libglom/connectionpool.h>
+#include <glom/libglom/connectionpool_backends/backend.h>
#include "config.h" // For GLOM_ENABLE_CLIENT_ONLY
@@ -32,7 +32,7 @@
namespace ConnectionPoolBackends
{
-class Postgres : public ConnectionPoolBackend
+class Postgres : public Backend
{
public:
Postgres();
Modified: trunk/glom/libglom/connectionpool_backends/sqlite.cc
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/sqlite.cc (original)
+++ trunk/glom/libglom/connectionpool_backends/sqlite.cc Tue Feb 24 12:36:55 2009
@@ -350,7 +350,7 @@
// in that case.
if(!field->get_primary_key())
{
- return ConnectionPoolBackend::add_column(connection, table_name, field, error);
+ return Backend::add_column(connection, table_name, field, error);
}
else
{
Modified: trunk/glom/libglom/connectionpool_backends/sqlite.h
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/sqlite.h (original)
+++ trunk/glom/libglom/connectionpool_backends/sqlite.h Tue Feb 24 12:36:55 2009
@@ -22,7 +22,7 @@
#define GLOM_BACKEND_SQLITE_H
#include <libgdamm.h>
-#include <glom/libglom/connectionpool.h>
+#include <glom/libglom/connectionpool_backends/backend.h>
#include "config.h" // For GLOM_ENABLE_CLIENT_ONLY, GLOM_ENABLE_SQLITE
@@ -36,7 +36,7 @@
namespace ConnectionPoolBackends
{
-class Sqlite : public ConnectionPoolBackend
+class Sqlite : public Backend
{
public:
Sqlite();
Modified: trunk/glom/libglom/test_connectionpool.cc
==============================================================================
--- trunk/glom/libglom/test_connectionpool.cc (original)
+++ trunk/glom/libglom/test_connectionpool.cc Tue Feb 24 12:36:55 2009
@@ -47,7 +47,7 @@
backend->set_port(5433);
backend->set_try_other_ports(false);
- connection_pool->set_backend(std::auto_ptr<Glom::ConnectionPoolBackend>(backend));
+ connection_pool->set_backend(std::auto_ptr<Glom::ConnectionPool::Backend>(backend));
connection_pool->set_ready_to_connect(); //Box_WithButtons::connect_to_server() will now attempt the connection-> Shared instances of m_Connection will also be usable.
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]