glom r1932 - in trunk: . glom glom/libglom glom/libglom/connectionpool_backends



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]