[glom] Make auto-increment fields work even if they are not primary keys.



commit 63e6fd4912475c7211013149dea4813d7e4a1de2
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu Mar 1 11:41:55 2012 +0100

    Make auto-increment fields work even if they are not primary keys.
    
    * glom/libglom/db_utils.h: get_next_auto_increment_value(): Document that
    this also increments the value ready for the next call.
    * glom/base_db_table_data.cc: record_new(): Decide auto-increment values
    as well as just default values and calculated values. And do this while
    building the SQL, instead of first setting it in the widget, because we
    do not always want to use the entered data, so we would then ignore those
    automatic values accidentally.
    Bug #661702

 ChangeLog                  |   13 ++++
 glom/base_db_table_data.cc |  137 +++++++++++++++++++++-----------------------
 glom/libglom/db_utils.h    |    1 +
 3 files changed, 80 insertions(+), 71 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 09950e9..44d0283 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2012-03-01  Murray Cumming  <murrayc murrayc com>
 
+	Make auto-increment fields work even if they are not primary keys.
+
+	* glom/libglom/db_utils.h: get_next_auto_increment_value(): Document that
+	this also increments the value ready for the next call.
+	* glom/base_db_table_data.cc: record_new(): Decide auto-increment values
+	as well as just default values and calculated values. And do this while
+	building the SQL, instead of first setting it in the widget, because we
+	do not always want to use the entered data, so we would then ignore those
+	automatic values accidentally.
+	Bug #661702
+
+2012-03-01  Murray Cumming  <murrayc murrayc com>
+
 	Make the --debug_sql option work again.
 
 	* glom/appwindow.cc: set_show_sql_debug(): Set it in the ConnectionPool
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index 9e7b74c..c7c8512 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -67,6 +67,8 @@ Gtk::TreeModel::iterator Base_DB_Table_Data::get_row_selected()
 
 bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Value& primary_key_value)
 {
+  //std::cout << G_STRFUNC << ": debug: use_entered_data=" << use_entered_data << std::endl;
+
   Document* document = get_document();
 
   sharedptr<const Field> fieldPrimaryKey = get_field_primary_key();
@@ -78,7 +80,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
     m_TableFields = DbUtils::get_fields_for_table(document, m_table_name);
 
   //Add values for all fields, not just the shown ones:
-  //For instance, we must always add the primary key, and fields with default/calculated/lookup values:
+  //For instance, we must always add the primary key, and fields with default/calculated/lookup/auto-incremented values:
   for(type_vec_fields::const_iterator iter = m_TableFields.begin(); iter != m_TableFields.end(); ++iter)
   {
     //TODO: Search for the non-related field with the name, not just the field with the name:
@@ -92,31 +94,55 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
     }
   }
 
-  //Calculate any necessary field values and enter them:
+  //Get all entered field name/value pairs:
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_INSERT);
+  builder->set_table(m_table_name);
+
+  //Avoid specifying the same field twice:
+  typedef std::map<Glib::ustring, bool> type_map_added;
+  type_map_added map_added;
+  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+
   for(type_vecConstLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
   {
     sharedptr<const LayoutItem_Field> layout_item = *iter;
-
-    //If the user did not enter something in this field:
-    Gnome::Gda::Value value = get_entered_field_data(layout_item);
-
-    if(Conversions::value_is_empty(value)) //This deals with empty strings too.
+    const Glib::ustring field_name = layout_item->get_name();
+    if(!layout_item->get_has_relationship_name()) //TODO: Allow people to add a related record also by entering new data in a related field of the related record.
     {
-      const sharedptr<const Field>& field = layout_item->get_full_field_details();
-      if(field)
+      type_map_added::const_iterator iterFind = map_added.find(field_name);
+      if(iterFind == map_added.end()) //If it was not added already
       {
-        //If the default value should be calculated, then calculate it:
-        if(field->get_has_calculation())
+        Gnome::Gda::Value value;
+
+        const sharedptr<const Field>& field = layout_item->get_full_field_details();
+        if(!field)
+          continue;
+        
+        //Use the specified (generated) primary key value, if there is one:
+        if(primary_key_name == field_name && !Conversions::value_is_empty(primary_key_value))
         {
-          const Glib::ustring calculation = field->get_calculation();
-          const type_map_fields field_values = get_record_field_values_for_calculation(m_table_name, fieldPrimaryKey, primary_key_value);
+          value = primary_key_value;
+        }
+        else
+        {
+          if(use_entered_data)
+            value = get_entered_field_data(layout_item);
+        }
 
-          //We need the connection when we run the script, so that the script may use it.
-          // TODO: Is this function supposed to throw an exception?
-          sharedptr<SharedConnection> sharedconnection = connect_to_server(AppWindow::get_appwindow());
+        if(Conversions::value_is_empty(value)) //This deals with empty strings too.
+        {
+          //If the default value should be calculated, then calculate it:
+          if(field->get_has_calculation())
+          {
+            const Glib::ustring calculation = field->get_calculation();
+            const type_map_fields field_values = get_record_field_values_for_calculation(m_table_name, fieldPrimaryKey, primary_key_value);
+
+            //We need the connection when we run the script, so that the script may use it.
+            // TODO: Is this function supposed to throw an exception?
+            sharedptr<SharedConnection> sharedconnection = connect_to_server(AppWindow::get_appwindow());
 
             Glib::ustring error_message; //TODO: Check this.
-            const Gnome::Gda::Value value =
+            value =
               glom_evaluate_python_function_implementation(
                 field->get_glom_type(),
                 calculation,
@@ -126,7 +152,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
                 fieldPrimaryKey, primary_key_value,
                 sharedconnection->get_gda_connection(),
                 error_message);
-            set_entered_field_data(layout_item, value);
+          }
         }
 
         //Use default values (These are also specified in postgres as part of the field definition,
@@ -134,66 +160,35 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
         //TODO_Performance: Add has_default_value()?
         if(Conversions::value_is_empty(value))
         {
-          const Gnome::Gda::Value default_value = field->get_default_value();
-          if(!Conversions::value_is_empty(default_value))
-          {
-            set_entered_field_data(layout_item, default_value);
-          }
+          value = field->get_default_value();
         }
-      }
-    }
-  }
 
-  //Get all entered field name/value pairs:
-  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_INSERT);
-  builder->set_table(m_table_name);
-
-  //Avoid specifying the same field twice:
-  typedef std::map<Glib::ustring, bool> type_map_added;
-  type_map_added map_added;
-  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
-
-  for(type_vecConstLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
-  {
-    sharedptr<const LayoutItem_Field> layout_item = *iter;
-    const Glib::ustring field_name = layout_item->get_name();
-    if(!layout_item->get_has_relationship_name()) //TODO: Allow people to add a related record also by entering new data in a related field of the related record.
-    {
-      type_map_added::const_iterator iterFind = map_added.find(field_name);
-      if(iterFind == map_added.end()) //If it was not added already
-      {
-        Gnome::Gda::Value value;
-
-        const sharedptr<const Field>& field = layout_item->get_full_field_details();
-        if(field)
+        //Use auto-increment values:
+        if(field->get_auto_increment() && Conversions::value_is_empty(value))
         {
-          //Use the specified (generated) primary key value, if there is one:
-          if(primary_key_name == field_name && !Conversions::value_is_empty(primary_key_value))
-          {
-            value = primary_key_value;
-          }
-          else
-          {
-            if(use_entered_data)
-              value = get_entered_field_data(layout_item);
-          }
+          value = 
+            DbUtils::get_next_auto_increment_value(m_table_name, field->get_name());
+        }
 
-          /* //TODO: This would be too many small queries when adding one record.
-          //Check whether the value meets uniqueness constraints:
-          if(field->get_primary_key() || field->get_unique_key())
-          {
-            if(!get_field_value_is_unique(m_table_name, layout_item, value))
-            {
-              //Ignore this field value. TODO: Warn the user about it.
-            }
-          }
-          */
-          if(!value.is_null())
+        /* //TODO: This would be too many small queries when adding one record.
+        //Check whether the value meets uniqueness constraints:
+        if(field->get_primary_key() || field->get_unique_key())
+        {
+          if(!get_field_value_is_unique(m_table_name, layout_item, value))
           {
-            builder->add_field_value(field_name, value);
-            map_added[field_name] = true;
+            //Ignore this field value. TODO: Warn the user about it.
           }
         }
+        */
+        if(!value.is_null())
+        {
+          builder->add_field_value(field_name, value);
+          map_added[field_name] = true;
+        }
+        else
+        {
+          std::cerr << G_STRFUNC << ": value is null for field: " << field_name << std::endl;
+        }
       }
     }
   }
diff --git a/glom/libglom/db_utils.h b/glom/libglom/db_utils.h
index eed305a..1633782 100644
--- a/glom/libglom/db_utils.h
+++ b/glom/libglom/db_utils.h
@@ -119,6 +119,7 @@ Gnome::Gda::Value auto_increment_insert_first_if_necessary(const Glib::ustring&
 
 /** Get the next auto-increment value for this primary key, from the glom system table.
   * Add a row for this field in the system table if it does not exist already.
+  * This increments the next value after obtaining the current next value.
   */
 Gnome::Gda::Value get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name);
 



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