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



Author: arminb
Date: Mon Feb  9 12:33:01 2009
New Revision: 1887
URL: http://svn.gnome.org/viewvc/glom?rev=1887&view=rev

Log:
2009-02-09  Armin Burgmeier  <armin openismus com>

	* glom/libglom/connectionpool.h:
	* glom/libglom/connectionpool.cc: Added set_server_operation_value(),
	create_server_operation() and perform_server_operation() convenience
	methods to connectionpool backend base class.

	* glom/libglom/connectionpool_backends/sqlite.h:
	* glom libglom/connectionpool_backends/sqlite.cc: Implemented table
	recreation, required for changing or dropping columns, or adding
	primary key columns. The glom type of newly added columns doesn't yet
	seem to be recognized correctly, though.


Modified:
   trunk/ChangeLog
   trunk/glom/libglom/connectionpool.cc
   trunk/glom/libglom/connectionpool.h
   trunk/glom/libglom/connectionpool_backends/sqlite.cc
   trunk/glom/libglom/connectionpool_backends/sqlite.h

Modified: trunk/glom/libglom/connectionpool.cc
==============================================================================
--- trunk/glom/libglom/connectionpool.cc	(original)
+++ trunk/glom/libglom/connectionpool.cc	Mon Feb  9 12:33:01 2009
@@ -234,64 +234,61 @@
 void ConnectionPoolBackend::cleanup(Gtk::Window* /* parent_window */)
 {}
 
-namespace
+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)
 {
-  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)
-  {
 #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;
+  try
+  {
+    operation->set_value_at(path, value);
     return true;
-#endif
   }
-
-  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)
+  catch(const Glib::Error& ex)
   {
-#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>();
-    }
+    error.reset(new Glib::Error(ex));
+    return false;
+  }
 #else
-    return provider->create_operation(connection, type, error);
+  operation->set_value_at(path, value, error);
+  if(error.get()) return false;
+  return true;
 #endif
-  }
+}
 
-  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)
-  {
+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
-    {
-      provider->perform_operation(connection, operation);
-      return true;
-    }
-    catch(const Glib::Error& ex)
-    {
-      error.reset(new Glib::Error(ex));
-      return false;
-    }
+  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
-    provider->perform_operation(connection, operation, error);
-    if(error.get()) return false;
-    return true;
+  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)

Modified: trunk/glom/libglom/connectionpool.h
==============================================================================
--- trunk/glom/libglom/connectionpool.h	(original)
+++ trunk/glom/libglom/connectionpool.h	Mon Feb  9 12:33:01 2009
@@ -116,6 +116,9 @@
    * 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);

Modified: trunk/glom/libglom/connectionpool_backends/sqlite.cc
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/sqlite.cc	(original)
+++ trunk/glom/libglom/connectionpool_backends/sqlite.cc	Mon Feb  9 12:33:01 2009
@@ -120,6 +120,250 @@
 }
 #endif
 
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+namespace
+{
+#if 0
+  enum
+  {
+    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 = 7 // ?
+  };
+
+  Glib::RefPtr<Gnome::Gda::DataModel> get_meta_store_fields(const Glib::RefPtr<Gnome::Gda::Connection>& connection, Glib::ustring& table_name, std::auto_ptr<Glib::Error>& error)
+  {
+    Glib::RefPtr<Gnome::Gda::Holder> holder_table_name = Gnome::Gda::Holder::create(G_TYPE_STRING, "name");
+    Gnome::Gda::Value table_name_value(table_name);
+    holder_table_name->set_value(table_name_value);
+    std::vector<Glib::RefPtr<Gnome::Gda::Holder> > holder_list;
+    holder_list.push_back(holder_table_name);
+
+    Glib::RefPtr<Gnome::Gda::DataModel> model;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      model = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list);
+    }
+    catch(const Glib::Error& ex)
+    {
+      error.reset(new Glib::Error(ex));
+      return model;
+    }
+#else
+    model = connection->get_meta_store_data(Gnome::Gda::CONNECTION_META_FIELDS, holder_list, error);
+#endif
+
+    return model;
+  }
+
+  bool set_data_model_value(const Glib::RefPtr<Gnome::Gda::DataModel>& model, int col, int row, const Gnome::Gda::Value& value, std::auto_ptr<Glib::Error>& error)
+  {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try
+    {
+      model->set_value_at(col, row, value);
+      return true;
+    }
+    catch(const Glib::Error& ex)
+    {
+      error.reset(new Glib::Error(ex));
+      return false;
+    }
+#else
+    return model->set_value_at(col, row, value, error);
+#endif
+  }
+#endif
+}
+
+bool Sqlite::add_column_to_server_operation(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, GdaMetaTableColumn* column, unsigned int i, std::auto_ptr<Glib::Error>& error)
+{
+  Glib::ustring name_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_NAME/%1", i);
+  Glib::ustring type_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_TYPE/%1", i);
+  Glib::ustring pkey_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_PKEY/%1", i);
+  // TODO: Find out whether the column is unique.
+  Glib::ustring default_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_DEFAULT/%1", i);
+
+  if(!set_server_operation_value(operation, name_path, column->column_name, error)) return false;
+  if(!set_server_operation_value(operation, type_path, column->column_type, error)) return false;
+  if(!set_server_operation_value(operation, pkey_path, column->pkey ? "TRUE" : "FALSE", error)) return false;
+
+  if(column->default_value)
+    if(!set_server_operation_value(operation, default_path, column->default_value, error))
+      return false;
+
+  return true;
+}
+
+bool Sqlite::add_column_to_server_operation(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const sharedptr<const Field>& column, unsigned int i, std::auto_ptr<Glib::Error>& error)
+{
+  Glib::ustring name_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_NAME/%1", i);
+  Glib::ustring type_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_TYPE/%1", i);
+  Glib::ustring pkey_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_PKEY/%1", i);
+  Glib::ustring unique_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_UNIQUE/%1", i);
+  Glib::ustring default_path = Glib::ustring::compose("/FIELDS_A/@COLUMN_DEFAULT/%1", i);
+
+  if(!set_server_operation_value(operation, name_path, column->get_name(), error)) return false;
+  if(!set_server_operation_value(operation, type_path, column->get_sql_type(), error)) return false;
+  if(!set_server_operation_value(operation, pkey_path, column->get_primary_key() ? "TRUE" : "FALSE", error)) return false;
+  if(!set_server_operation_value(operation, unique_path, column->get_unique_key() ? "TRUE" : "FALSE", error)) return false;
+
+  Gnome::Gda::Value value = column->get_default_value();
+  if(value.get_value_type() != G_TYPE_NONE && !value.is_null())
+    if(!set_server_operation_value(operation, default_path, value.to_string(), error))
+      return false;
+  return true;
+}
+
+bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecStrings& fields_removed, const type_vecFields& fields_added, std::auto_ptr<Glib::Error>& error)
+{
+  static const gchar* TEMPORARY_TABLE_NAME = "GLOM_TEMP_TABLE"; // TODO: Make sure this is unique.
+  static const gchar* TRANSACTION_NAME = "GLOM_RECREATE_TABLE_TRANSACTION";
+
+  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* object = metastruct->complement(Gnome::Gda::META_DB_TABLE, Gnome::Gda::Value(), Gnome::Gda::Value(), Gnome::Gda::Value(table_name));
+  if(!object) return false;
+
+  Glib::RefPtr<Gnome::Gda::ServerOperation> operation = create_server_operation(connection->get_provider(), connection, Gnome::Gda::SERVER_OPERATION_CREATE_TABLE, error);
+  if(!operation) return false;
+
+  if(!set_server_operation_value(operation, "/TABLE_DEF_P/TABLE_NAME", TEMPORARY_TABLE_NAME, error)) return false;
+
+  GdaMetaTable* table = GDA_META_TABLE(object);
+  unsigned int i = 0;
+
+  Glib::ustring trans_fields;
+
+  for(GSList* item = table->columns; item != NULL; item = item->next)
+  {
+    GdaMetaTableColumn* column = GDA_META_TABLE_COLUMN(item->data);
+
+    // Don't add if field was removed
+    sharedptr<const Field> added;
+    if(std::find(fields_removed.begin(), fields_removed.end(), column->column_name) != fields_removed.end())
+    {
+      // If it was removed, and added again, then it has changed, so use the
+      // definition from the added_fields vector.
+      type_vecFields::const_iterator iter = std::find_if(fields_added.begin(), fields_added.end(), predicate_FieldHasName<Field>(column->column_name));
+      if(iter == fields_added.end())
+        continue;
+      else
+        added = *iter;
+    }
+
+    if(!trans_fields.empty())
+      trans_fields += ",";
+    trans_fields += column->column_name;
+
+    if(added)
+    {
+      if(!add_column_to_server_operation(operation, added, i++, error))
+        return false;
+    }
+    else
+    {
+      if(!add_column_to_server_operation(operation, column, i++, error))
+        return false;
+    }
+  }
+
+  for(type_vecFields::const_iterator iter = fields_added.begin(); iter != fields_added.end(); ++ iter)
+  {
+    // Add new fields to the table. Fields that have changed have already
+    // been handled above.
+    const sharedptr<const Field>& field = *iter;
+    type_vecStrings::const_iterator removed_iter = std::find(fields_removed.begin(), fields_removed.end(), field->get_name());
+    if(removed_iter == fields_removed.end())
+    {
+      if(!add_column_to_server_operation(operation, field, i++, error))
+        return false;
+      if(!trans_fields.empty())
+        trans_fields += ",";
+      Gnome::Gda::Value default_value = field->get_default_value();
+      if(default_value.get_g_type() != G_TYPE_NONE && !default_value.is_null())
+        trans_fields += field->sql(default_value, Field::SQL_FORMAT_SQLITE);
+      else
+      {
+        switch(field->get_glom_type())
+        {
+        case Field::TYPE_NUMERIC:
+          trans_fields += "0";
+          break;
+        case Field::TYPE_BOOLEAN:
+          trans_fields += "'false'";
+          break;
+        case Field::TYPE_TEXT:
+          trans_fields += "''";
+          break;
+        default:
+          trans_fields += "NULL";
+          break;
+        }
+      }
+    }
+  }
+
+  if(!begin_transaction(connection, TRANSACTION_NAME, Gnome::Gda::TRANSACTION_ISOLATION_UNKNOWN, error)) return false;
+
+  if(perform_server_operation(connection->get_provider(), connection, operation, error))
+  {
+    if(trans_fields.empty() || query_execute(connection, Glib::ustring("INSERT INTO ") + TEMPORARY_TABLE_NAME + " SELECT " + trans_fields + " FROM " + table_name, error))
+    {
+      if(query_execute(connection, "DROP TABLE " + table_name, error))
+      {
+        if(query_execute(connection, Glib::ustring("ALTER TABLE ") + TEMPORARY_TABLE_NAME + " RENAME TO " + table_name, error))
+        {
+          if(commit_transaction(connection, TRANSACTION_NAME, error))
+          {
+            return true;
+          }
+        }
+      }
+    }
+  }
+
+  std::auto_ptr<Glib::Error> rollback_error;
+  if(!rollback_transaction(connection, TRANSACTION_NAME, rollback_error))
+  {
+    std::cerr << "Sqlite::recreate_table: Failed to rollback failed transaction: " << rollback_error->what() << std::endl;
+  }
+
+  return false;
+}
+
+bool Sqlite::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)
+{
+  // Sqlite does not support adding primary key columns. So recreate the table
+  // in that case.
+/*  if(!field->get_primary_key())
+  {
+    return ConnectionPoolBackend::add_column(connection, table, field, error);
+  }
+  else*/
+  {
+#if 0
+    Glib::RefPtr<Gnome::Gda::DataModel> model = get_meta_store_fields(connection, table_name, error);
+    if(!model) return false;
+
+/*    guint new_row = model->append_row();
+    if(!set_data_model_value(model, DATAMODEL_FIELDS_COL_NAME, new_row, Gnome::Gda::Value(field->get_name()), error)) return false;
+    if(!set_data_model_value(model, DATAMODEL_FIELDS_COL_TYPE, new_row, Gnome::Gda::Value(field->get_sql_type()), error)) return false;
+    if(!set_data_model_value(model, DATAMODEL_FIELDS_COL_GTYPE, new_row, Gnome::Gda::Value(g_type_name(field->get_field_info()->get_g_type())), error)) return false;*/
+
+#endif
+    if(!recreate_table(connection, table_name, type_vecStrings(), type_vecFields(1, field), error)) return false;
+    return true;
+  }
+}
+#endif
+
 } // namespace ConnectionPoolBackends
 
 } // namespace Glom

Modified: trunk/glom/libglom/connectionpool_backends/sqlite.h
==============================================================================
--- trunk/glom/libglom/connectionpool_backends/sqlite.h	(original)
+++ trunk/glom/libglom/connectionpool_backends/sqlite.h	Mon Feb  9 12:33:01 2009
@@ -44,6 +44,18 @@
   virtual Field::sql_format get_sql_format() const { return Field::SQL_FORMAT_SQLITE; }
   virtual bool supports_remote_access() const { return false; }
 
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+  bool add_column_to_server_operation(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, GdaMetaTableColumn* column, unsigned int i, std::auto_ptr<Glib::Error>& error);
+  bool add_column_to_server_operation(const Glib::RefPtr<Gnome::Gda::ServerOperation>& operation, const sharedptr<const Field>& column, unsigned int i, std::auto_ptr<Glib::Error>& error);
+
+  typedef std::vector<Glib::ustring> type_vecStrings;
+  typedef std::vector<sharedptr<const Field> > type_vecFields;
+
+  bool recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vecStrings& fields_removed, const type_vecFields& fields_added, std::auto_ptr<Glib::Error>& error);
+
+  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);
+#endif
+
   virtual Glib::RefPtr<Gnome::Gda::Connection> connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password, std::auto_ptr<ExceptionConnection>& error);
 
   /** Creates a new database.



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