[glom] Python functions: Allow setting of values in the record via [].



commit b759195349ef396e275e2ff419b44483638efbe9
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu Feb 25 19:52:08 2010 +0100

    Python functions: Allow setting of values in the record via [].
    
    * glom/python_embed/python_module/py_glom_module.cc: Specify a setitem(),
    so python code can use [] syntax to set the record's field values as
    well as getting them.
    * glom/libglom/python_embed/py_glom_record.[h|cc]:
    PyGlomRecord_SetFields(): Take and store the primary key details and value,
    and use it in setitem() to UPDATE the value in the database.
    * glom/python_embed/glom_python.[h|cc]:
    glom_execute_python_function_implementation(),
    glom_evaluate_python_function_implementation():
    Take the primary key field and value.
    * glom/base_db.cc:
    * glom/base_db_table_data.cc:
    * glom/mode_data/box_data.cc:
    * glom/mode_design/fields/dialog_fieldcalculation.cc:
    * glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc:
    Adapted.

 ChangeLog                                          |   31 ++-
 glom/base_db.cc                                    |  253 ++++++++++----------
 glom/base_db_table_data.cc                         |   48 ++--
 glom/libglom/python_embed/py_glom_record.cc        |  139 ++++++++++-
 glom/libglom/python_embed/py_glom_record.h         |   13 +-
 glom/libglom/python_embed/py_glom_relatedrecord.cc |   22 +-
 glom/libglom/python_embed/pygdavalue_conversions.h |    4 +-
 glom/libglom/utils.h                               |   56 ++++-
 glom/mode_data/box_data.cc                         |   12 +-
 glom/mode_design/fields/dialog_fieldcalculation.cc |   15 +-
 .../layout_item_dialogs/dialog_buttonscript.cc     |   12 +-
 glom/python_embed/glom_python.cc                   |   25 ++-
 glom/python_embed/glom_python.h                    |   24 ++-
 glom/python_embed/python_module/py_glom_module.cc  |    1 +
 14 files changed, 443 insertions(+), 212 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index be49dda..20592b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,31 @@
+2010-02-25  Murray Cumming  <murrayc murrayc com>
+
+	Python functions: Allow setting of values in the record via [].
+
+	* glom/python_embed/python_module/py_glom_module.cc: Specify a setitem(),
+	so python code can use [] syntax to set the record's field values as
+	well as getting them.
+	* glom/libglom/python_embed/py_glom_record.[h|cc]:
+	PyGlomRecord_SetFields(): Take and store the primary key details and value,
+	and use it in setitem() to UPDATE the value in the database.
+	* glom/python_embed/glom_python.[h|cc]:
+	glom_execute_python_function_implementation(),
+	glom_evaluate_python_function_implementation():
+	Take the primary key field and value.
+	* glom/base_db.cc:
+	* glom/base_db_table_data.cc:
+	* glom/mode_data/box_data.cc:
+	* glom/mode_design/fields/dialog_fieldcalculation.cc:
+	* glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc:
+	Adapted.
+
 2010-02-22  Murray Cumming  <murrayc murrayc com>
 
-  Avoid showing %20 in the window title.
-  
-  * glom/libglom/document/bakery/document.cc: get_name():
-  Use Gio::FileInfo::get_display_name() instead of 
-	Glib::filename_display_basename() or Glib::filename_display_name(), to avoid 
+	Avoid showing %20 in the window title.
+
+	* glom/libglom/document/bakery/document.cc: get_name():
+	Use Gio::FileInfo::get_display_name() instead of
+	Glib::filename_display_basename() or Glib::filename_display_name(), to avoid
 	showing %20 in the window title bar when there are spaces in the file name.
 	Noticed by Daniel Borgmann.
 
diff --git a/glom/base_db.cc b/glom/base_db.cc
index 317076b..eafcaf2 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -84,7 +84,7 @@ public:
     if(layout_item && m_layout_item)
     {
       return m_layout_item->is_same_field(layout_item);
-      //std::cout << "          debug: name1=" << m_layout_item->get_name() << ", name2=" << layout_item->get_name() << ", result=" << result << std::endl; 
+      //std::cout << "          debug: name1=" << m_layout_item->get_name() << ", name2=" << layout_item->get_name() << ", result=" << result << std::endl;
       //return result;
     }
     else
@@ -178,7 +178,7 @@ Glib::RefPtr<Gnome::Gda::DataModel> Base_DB::query_execute_select(const Glib::us
   if(error.get())
   {
     g_warning("Base_DB::query_execute_select() failed (query was: %s): %s", strQuery.c_str(), error->what());
-    // TODO: Rethrow? 
+    // TODO: Rethrow?
   }
 #endif
   if(!sharedconnection)
@@ -227,11 +227,11 @@ Glib::RefPtr<Gnome::Gda::DataModel> Base_DB::query_execute_select(const Glib::us
       std::cout << "Debug: Base_DB::query_execute_select():  " << full_query << std::endl;
       if (ex.get())
         std::cout << "Debug: query string could not be converted to std::cout: " << ex->what() << std::endl;
-      
+
 #endif
   }
 
-  
+
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
   try
   {
@@ -278,7 +278,7 @@ bool Base_DB::query_execute(const Glib::ustring& strQuery,
   if(error.get())
   {
     g_warning("Base_DB::query_execute() failed (query was: %s): %s", strQuery.c_str(), error->what());
-    // TODO: Rethrow? 
+    // TODO: Rethrow?
   }
 #endif
   if(!sharedconnection)
@@ -286,7 +286,7 @@ bool Base_DB::query_execute(const Glib::ustring& strQuery,
     std::cerr << "Base_DB::query_execute(): No connection yet." << std::endl;
     return false;
   }
-  
+
   Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
   Glib::RefPtr<Gnome::Gda::SqlParser> parser = gda_connection->create_parser();
   Glib::RefPtr<Gnome::Gda::Statement> stmt;
@@ -318,8 +318,8 @@ bool Base_DB::query_execute(const Glib::ustring& strQuery,
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
     try
     {
-      //TODO: full_query still seems to contain ## parameter names, 
-      //though it works for our SELECT queries in query_execute_select(): 
+      //TODO: full_query still seems to contain ## parameter names,
+      //though it works for our SELECT queries in query_execute_select():
       const Glib::ustring full_query = stmt->to_sql(params);
       std::cerr << "Debug: Base_DB::query_execute(): " << full_query << std::endl;
     }
@@ -395,11 +395,11 @@ static Glib::ustring remove_quotes(const Glib::ustring& str)
   if(posQuoteStart != 0)
     return str;
 
-  const Glib::ustring::size_type size = str.size();    
+  const Glib::ustring::size_type size = str.size();
   const Glib::ustring::size_type posQuoteEnd = str.find(quote, 1);
   if(posQuoteEnd != (size - 1))
     return str;
-  
+
   return str.substr(1, size - 2);
 }
 
@@ -451,22 +451,22 @@ Base_DB::type_vec_strings Base_DB::get_table_names_from_database(bool ignore_sys
       const int rows = data_model_tables->get_n_rows();
       for(int i = 0; i < rows; ++i)
       {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
         const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i);
 #else
         const Gnome::Gda::Value value = data_model_tables->get_value_at(0, i, error);
-#endif        
+#endif
         //Get the table name:
         Glib::ustring table_name;
         if(G_VALUE_TYPE(value.gobj()) ==  G_TYPE_STRING)
         {
           table_name = value.get_string();
-          
+
           //The table names have quotes sometimes. See http://bugzilla.gnome.org/show_bug.cgi?id=593154
           table_name = remove_quotes(table_name);
-          
+
           //TODO: Unescape the string with gda_server_provider_unescape_string()?
-            
+
           //std::cout << "DEBUG: Found table: " << table_name << std::endl;
 
           if(ignore_system_tables)
@@ -568,20 +568,20 @@ static bool meta_table_column_is_primary_key(GdaMetaTable* meta_table, const Gli
 {
   if(!meta_table)
     return false;
-    
+
   for(GSList* item = meta_table->columns; item != 0; item = item->next)
   {
     GdaMetaTableColumn* column = GDA_META_TABLE_COLUMN(item->data);
     if(!column)
       continue;
-      
+
     if(column->column_name && (column_name == remove_quotes(column->column_name)))
       return column->pkey;
   }
-  
+
   return false;
-}    
-    
+}
+
 bool Base_DB::get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name)
 {
   type_vec_fields vecFields = get_fields_for_table_from_database(table_name);
@@ -629,19 +629,19 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
     Glib::RefPtr<Gnome::Gda::Connection> connection = sharedconnection->get_gda_connection();
 
     Glib::RefPtr<Gnome::Gda::Holder> holder_table_name = Gnome::Gda::Holder::create(G_TYPE_STRING, "name");
-    gchar* quoted_table_name_c = gda_meta_store_sql_identifier_quote(table_name.c_str(), connection->gobj());    
+    gchar* quoted_table_name_c = gda_meta_store_sql_identifier_quote(table_name.c_str(), connection->gobj());
     g_assert(quoted_table_name_c);
     Glib::ustring quoted_table_name(quoted_table_name_c);
     g_free (quoted_table_name_c);
     quoted_table_name_c = 0;
 
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     holder_table_name->set_value(quoted_table_name);
 #else
     std::auto_ptr<Glib::Error> error;
     holder_table_name->set_value(quoted_table_name, error);
 #endif
-    
+
     std::list< Glib::RefPtr<Gnome::Gda::Holder> > holder_list;
     holder_list.push_back(holder_table_name);
 
@@ -669,7 +669,7 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
     if(!data_model_fields)
     {
       std::cerr << "Base_DB::get_fields_for_table_from_database(): libgda reported empty fields schema data_model for the table." << std::endl;
-    } 
+    }
     else if(data_model_fields->get_n_columns() == 0)
     {
       std::cerr << "Base_DB::get_fields_for_table_from_database(): libgda reported 0 fields for the table." << std::endl;
@@ -683,13 +683,13 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
       //We also use the GdaMetaTable to discover primary keys.
       //Both these libgda APIs are awful, and it's awful that we must use two APIs. murrayc.
       Glib::RefPtr<Gnome::Gda::MetaStore> store = connection->get_meta_store();
-      Glib::RefPtr<Gnome::Gda::MetaStruct> metastruct = 
+      Glib::RefPtr<Gnome::Gda::MetaStruct> metastruct =
         Gnome::Gda::MetaStruct::create(store, Gnome::Gda::META_STRUCT_FEATURE_NONE);
       GdaMetaDbObject* meta_dbobject = 0;
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
       try
       {
-        meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE, 
+        meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
           Gnome::Gda::Value(), /* catalog */
           Gnome::Gda::Value(), /* schema */
           Gnome::Gda::Value(quoted_table_name)); //It's a static instance inside the MetaStore.
@@ -701,17 +701,17 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
       }
 #else
       std::auto_ptr<Glib::Error> ex;
-      meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE, 
+      meta_dbobject = metastruct->complement(Gnome::Gda::META_DB_TABLE,
         Gnome::Gda::Value(), /* catalog */
         Gnome::Gda::Value(), /* schema */
-        Gnome::Gda::Value(quoted_table_name), ex); //It's a static instance inside the MetaStore. 
+        Gnome::Gda::Value(quoted_table_name), ex); //It's a static instance inside the MetaStore.
        if(error.get())
        {
          handle_error(*ex);
        }
 #endif //GLIBMM_EXCEPTIONS_ENABLED
-      GdaMetaTable* meta_table = GDA_META_TABLE(meta_dbobject); 
-   
+      GdaMetaTable* meta_table = GDA_META_TABLE(meta_dbobject);
+
       //Examine each field:
       guint row = 0;
       const guint rows_count = data_model_fields->get_n_rows();
@@ -720,12 +720,12 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
         Glib::RefPtr<Gnome::Gda::Column> field_info = Gnome::Gda::Column::create();
 
         //Get the field name:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED //TODO: Actually catch exceptions.      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED //TODO: Actually catch exceptions.
         Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row);
 #else
         std::auto_ptr<Glib::Error> value_error;
         Gnome::Gda::Value value_name = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NAME, row, value_error);
-#endif        
+#endif
         if(value_name.get_value_type() ==  G_TYPE_STRING)
         {
           if(value_name.get_string().empty())
@@ -738,9 +738,9 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
         }
 
         //Get the field type:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED        
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
         Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row);
-#else        
+#else
         Gnome::Gda::Value value_fieldtype = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_GTYPE, row, value_error);
 #endif
         if(value_fieldtype.get_value_type() ==  G_TYPE_STRING)
@@ -750,7 +750,7 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
           field_info->set_g_type(gdatype);
         }
 
-        
+
         //Get the default value:
         /* libgda does not return this correctly yet. TODO: check bug http://bugzilla.gnome.org/show_bug.cgi?id=143576
         Gnome::Gda::Value value_defaultvalue = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_DEFAULTVALUE, row);
@@ -759,24 +759,24 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
         */
 
         //Get whether it can be null:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED         
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
         Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row);
-#else        
+#else
         Gnome::Gda::Value value_notnull = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_NOTNULL, row, value_error);
-#endif        
+#endif
         if(value_notnull.get_value_type() ==  G_TYPE_BOOLEAN)
           field_info->set_allow_null(value_notnull.get_boolean());
 
 
         sharedptr<Field> field = sharedptr<Field>::create(); //TODO: Get glom-specific information from the document?
         field->set_field_info(field_info);
-        
 
-        //Get whether it is a primary key:      
-        field->set_primary_key( 
-          meta_table_column_is_primary_key(meta_table, field_info->get_name()) );         
-  
-        
+
+        //Get whether it is a primary key:
+        field->set_primary_key(
+          meta_table_column_is_primary_key(meta_table, field_info->get_name()) );
+
+
 #if 0 // This was with libgda-3.0:
         Gnome::Gda::Value value_primarykey = data_model_fields->get_value_at(DATAMODEL_FIELDS_COL_PRIMARYKEY, row);
         if(value_primarykey.get_value_type() ==  G_TYPE_BOOLEAN)
@@ -797,7 +797,7 @@ Base_DB::type_vec_fields Base_DB::get_fields_for_table_from_database(const Glib:
         */
 #endif
 
-        
+
         result.push_back(field);
 
         ++row;
@@ -895,7 +895,7 @@ Gnome::Gda::Value Base_DB::auto_increment_insert_first_if_necessary(const Glib::
   Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
   params->add_holder("table_name", table_name);
   params->add_holder("field_name", field_name);
-  
+
   const Glib::ustring sql_query = "SELECT \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\".\"next_value\" FROM \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME "\""
    " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = ##table_name::gchararray AND "
           "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = ##field_name::gchararray";
@@ -921,12 +921,12 @@ Gnome::Gda::Value Base_DB::auto_increment_insert_first_if_necessary(const Glib::
   else
   {
     //Return the value so that a calling function does not need to do a second SELECT.
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0);
 #else
-    std::auto_ptr<Glib::Error> value_error;    
+    std::auto_ptr<Glib::Error> value_error;
     const Gnome::Gda::Value actual_value = datamodel->get_value_at(0, 0, value_error);
-#endif        
+#endif
     //But the caller wants a numeric value not a text value
     //(our system_autoincrements table has it as text, for future flexibility):
     const std::string actual_value_text = actual_value.get_string();
@@ -949,10 +949,10 @@ void Base_DB::recalculate_next_auto_increment_value(const Glib::ustring& table_n
   if(datamodel && datamodel->get_n_rows() && datamodel->get_n_columns())
   {
     //Increment it:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0); // A GdaNumeric.
 #else
-    std::auto_ptr<Glib::Error> error;        
+    std::auto_ptr<Glib::Error> error;
     const Gnome::Gda::Value value_max = datamodel->get_value_at(0, 0, error); // A GdaNumeric.
 #endif
     double num_max = Conversions::get_double_for_gda_value_numeric(value_max);
@@ -964,7 +964,7 @@ void Base_DB::recalculate_next_auto_increment_value(const Glib::ustring& table_n
       "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_NEXT_VALUE "\" = " + next_value.to_string() + //TODO: Don't use to_string().
       " WHERE \"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_TABLE_NAME "\" = '" + table_name + "' AND "
       "\"" GLOM_STANDARD_TABLE_AUTOINCREMENTS_FIELD_FIELD_NAME "\" = '" + field_name + "'";
-    
+
     const bool test = query_execute(sql_query);
     if(!test)
       std::cerr << "Base_DB::recalculate_next_auto_increment_value(): UPDATE failed." << std::endl;
@@ -976,7 +976,7 @@ void Base_DB::recalculate_next_auto_increment_value(const Glib::ustring& table_n
 Gnome::Gda::Value Base_DB::get_next_auto_increment_value(const Glib::ustring& table_name, const Glib::ustring& field_name) const
 {
   const Gnome::Gda::Value result = auto_increment_insert_first_if_necessary(table_name, field_name);
-  double num_result = Conversions::get_double_for_gda_value_numeric(result); 
+  double num_result = Conversions::get_double_for_gda_value_numeric(result);
 
 
   //Increment the next_value:
@@ -1033,7 +1033,7 @@ SystemPrefs Base_DB::get_database_preferences() const
     {
       Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
       if(datamodel && (datamodel->get_n_rows() != 0))
-      {            
+      {
         result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0));
         result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0));
         result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0));
@@ -1044,7 +1044,7 @@ SystemPrefs Base_DB::get_database_preferences() const
         result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0));
 
         //We need to be more clever about these column indexes if we add more new fields:
-        if(optional_org_logo)        
+        if(optional_org_logo)
           result.m_org_logo = datamodel->get_value_at(8, 0);
       }
       else
@@ -1064,7 +1064,7 @@ SystemPrefs Base_DB::get_database_preferences() const
     std::auto_ptr<Glib::Error> error;
     Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
     if(datamodel && (datamodel->get_n_rows() != 0))
-    {            
+    {
       result.m_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(0, 0, error));
       result.m_org_name = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(1, 0, error));
       result.m_org_address_street = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(2, 0, error));
@@ -1075,18 +1075,18 @@ SystemPrefs Base_DB::get_database_preferences() const
       result.m_org_address_postcode = Conversions::get_text_for_gda_value(Field::TYPE_TEXT, datamodel->get_value_at(7, 0, error));
 
       //We need to be more clever about these column indexes if we add more new fields:
-      if(optional_org_logo)        
+      if(optional_org_logo)
         result.m_org_logo = datamodel->get_value_at(8, 0, error);
     }
     else
       succeeded = false;
-      
+
     if (error.get())
     {
       std::cerr << "Error: " << error->what() << std::endl;
       succeeded = false;
     }
-    #endif    
+    #endif
     //Return the result, or try again:
     if(succeeded)
       return result;
@@ -1218,7 +1218,7 @@ bool Base_DB::add_standard_groups()
   if(error.get())
   {
     g_warning("Base_DB::add_standard_groups: Failed to connect: %s", error->what());
-    // TODO: Rethrow? 
+    // TODO: Rethrow?
   }
 #endif
 
@@ -1298,7 +1298,7 @@ void Base_DB::set_database_preferences(const SystemPrefs& prefs)
   params->add_holder("county", prefs.m_org_address_county);
   params->add_holder("country", prefs.m_org_address_country);
   params->add_holder("postcode", prefs.m_org_address_postcode);
-    
+
   //The logo field was introduced in a later version of Glom.
   //If the user is not in developer mode then the new field has not yet been added:
   Glib::ustring optional_part_logo;
@@ -1306,7 +1306,7 @@ void Base_DB::set_database_preferences(const SystemPrefs& prefs)
   {
     params->add_holder("org_logo", prefs.m_org_logo);
     optional_part_logo =  "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_ORG_LOGO "\" = ##org_logo::GDA_TYPE_BINARY, ";
-  }  
+  }
   const Glib::ustring sql_query = "UPDATE \"" GLOM_STANDARD_TABLE_PREFS_TABLE_NAME "\" SET "
       "\"" GLOM_STANDARD_TABLE_PREFS_FIELD_NAME "\" = ##name::gchararray, "
       + optional_part_logo +
@@ -1323,7 +1323,7 @@ void Base_DB::set_database_preferences(const SystemPrefs& prefs)
 
   if(!test)
     std::cerr << "Base_DB::set_database_preferences(): UPDATE failed." << std::endl;
-  
+
   //Set some information in the document too, so we can use it to recreate the database:
   get_document()->set_database_title(prefs.m_name);
 }
@@ -1332,7 +1332,7 @@ bool Base_DB::create_table_with_default_fields(const Glib::ustring& table_name)
 {
   if(table_name.empty())
     return false;
-  
+
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
     sharedptr<SharedConnection> sharedconnection = connect_to_server();
 #else
@@ -1395,7 +1395,7 @@ bool Base_DB::create_table_with_default_fields(const Glib::ustring& table_name)
     //query_execute( "CREATE TABLE \"" + table_name + "\" (\"" + primary_key_name + "\" serial NOT NULL  PRIMARY KEY)" );
 
     //query_execute( "CREATE TABLE \"" + table_name + "\" (" +
-    //  field_primary_key->get_name() + " numeric NOT NULL  PRIMARY KEY," + 
+    //  field_primary_key->get_name() + " numeric NOT NULL  PRIMARY KEY," +
     //  extra_field_description + "varchar, " +
     //  extra_field_comments + "varchar" +
     //  ")" );
@@ -1688,7 +1688,7 @@ Glib::RefPtr<Gnome::Gda::Connection> Base_DB::get_connection()
   if(error.get())
   {
     std::cerr << "Base_DB::get_connection(): " << error->what() << std::endl;
-    // TODO: Rethrow? 
+    // TODO: Rethrow?
   }
 #endif
 
@@ -1699,7 +1699,7 @@ Glib::RefPtr<Gnome::Gda::Connection> Base_DB::get_connection()
   }
 
   Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
-  
+
   return gda_connection;
 }
 
@@ -1719,7 +1719,7 @@ bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
   if(!gda_connection)
     return false;
 
-  
+
   //std::cout << "debug: inserting example_rows for table: " << table_name << std::endl;
 
   bool insert_succeeded = true;
@@ -1730,7 +1730,7 @@ bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
 
   //Actually insert the data:
   //std::cout << "  debug: Base_DB::insert_example_data(): number of rows of data: " << vec_rows.size() << std::endl;
-  
+
   //std::cout << "DEBUG: example_row size = " << example_rows.size() << std::endl;
 
   for(Document::type_example_rows::const_iterator iter = example_rows.begin(); iter != example_rows.end(); ++iter)
@@ -1773,24 +1773,24 @@ bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
       //Add a SQL parameter for the value:
       guint id = 0;
       const Field::glom_field_type glom_type = field->get_glom_type();
-      Glib::RefPtr<Gnome::Gda::Holder> holder = 
+      Glib::RefPtr<Gnome::Gda::Holder> holder =
         Gnome::Gda::Holder::create( Field::get_gda_type_for_glom_type(glom_type),
           generator.get_next_name(id));
 
       holder->set_not_null(false);
-#ifdef GLIBMM_EXCEPTIONS_ENABLED      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       holder->set_value_as_value(value);
 #else
       std::auto_ptr<Glib::Error> holder_error;
       holder->set_value_as_value(value, holder_error);
-#endif                  
+#endif
       params->add_holder(holder);
-          
+
       strVals += "##" + generator.get_name_from_id(id) + "::" + vec_fields[i]->get_gda_type_name();
     }
 
     //Create and parse the SQL query:
-    //After this, the Parser will know how many SQL parameters there are in 
+    //After this, the Parser will know how many SQL parameters there are in
     //the query, and allow us to set their values.
     const Glib::ustring strQuery = "INSERT INTO \"" + table_name + "\" (" + strNames + ") VALUES (" + strVals + ")";
     insert_succeeded = query_execute(strQuery, params);
@@ -1884,7 +1884,7 @@ Base_DB::type_list_field_items Base_DB::offer_field_list(const Glib::ustring& ta
   {
     std::cerr << error->what() << std::endl;
     return result;
-  }  
+  }
 #endif
 
   Dialog_ChooseField* dialog = 0;
@@ -1933,7 +1933,7 @@ bool Base_DB::offer_item_formatting(const sharedptr<LayoutItem_WithFormatting>&
        result = true;
     }
     //Cancel means use the old one:
-   
+
     remove_view(&dialog);
   }
   catch(const Gtk::BuilderError& ex)
@@ -2265,7 +2265,7 @@ sharedptr<Field> Base_DB::get_field_primary_key_for_table(const Glib::ustring& t
         continue;
 
       //std::cout << "  field=" << field->get_name() << std::endl;
-    
+
       if(field->get_primary_key())
         return *iter;
     }
@@ -2465,13 +2465,13 @@ void Base_DB::calculate_field_in_all_records(const Glib::ustring& table_name, co
   const int rows_count = data_model->get_n_rows();
   for(int row = 0; row < rows_count; ++row)
   {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED  
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     const Gnome::Gda::Value primary_key_value = data_model->get_value_at(0, row);
 #else
     std::auto_ptr<Glib::Error> error;
     const Gnome::Gda::Value primary_key_value = data_model->get_value_at(0, row, error);
-#endif    
-    
+#endif
+
     if(!Conversions::value_is_empty(primary_key_value))
     {
       field_in_record.m_key_value = primary_key_value;
@@ -2585,7 +2585,14 @@ void Base_DB::calculate_field(const LayoutFieldInRecord& field_in_record)
 
           g_assert(sharedconnection);
 
-          refCalcProgress.m_value = glom_evaluate_python_function_implementation(field->get_glom_type(), field->get_calculation(), field_values, get_document(), field_in_record.m_table_name, sharedconnection->get_gda_connection());
+          refCalcProgress.m_value =
+            glom_evaluate_python_function_implementation(field->get_glom_type(),
+              field->get_calculation(),
+              field_values,
+              get_document(),
+              field_in_record.m_table_name,
+              field_in_record.m_key, field_in_record.m_key_value,
+              sharedconnection->get_gda_connection());
 
           refCalcProgress.m_calc_finished = true;
           refCalcProgress.m_calc_in_progress = false;
@@ -2660,7 +2667,7 @@ Base_DB::type_map_fields Base_DB::get_record_field_values_for_calculation(const
         std::cerr << "Base_DB::get_record_field_values_for_calculation(): Exception while executing SQL: " << query << std::endl;
         return field_values;
       }
-#endif      
+#endif
       if(data_model && data_model->get_n_rows())
       {
         int col_index = 0;
@@ -2742,7 +2749,7 @@ bool Base_DB::set_field_value_in_database(const LayoutFieldInRecord& layoutfield
 
   const Glib::ustring field_name = field_in_record.m_field->get_name();
   if(!field_name.empty()) //This should not happen.
-  { 
+  {
     Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
     params->add_holder(field_in_record.m_field->get_holder(field_value));
     params->add_holder(field_in_record.m_key->get_holder(field_in_record.m_key_value));
@@ -2831,7 +2838,7 @@ Gnome::Gda::Value Base_DB::get_field_value_in_database(const LayoutFieldInRecord
 #else
       std::auto_ptr<Glib::Error> value_error;
       result = data_model->get_value_at(0, 0, value_error);
-#endif            
+#endif
     }
   }
   else
@@ -2875,7 +2882,7 @@ Gnome::Gda::Value Base_DB::get_field_value_in_database(const sharedptr<Field>& f
   {
     if(data_model->get_n_rows())
     {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       result = data_model->get_value_at(0, 0);
 #else
       std::auto_ptr<Glib::Error> value_error;
@@ -2895,7 +2902,7 @@ Gnome::Gda::Value Base_DB::get_field_value_in_database(const sharedptr<Field>& f
 void Base_DB::do_calculations(const LayoutFieldInRecord& field_changed, bool first_calc_field)
 {
   //std::cout << "debug: Base_DB::do_calcualtions(): field_changed=" << field_changed.m_field->get_name() << std::endl;
- 
+
   if(first_calc_field)
   {
     //g_warning("  clearing m_FieldsCalculationInProgress");
@@ -2903,7 +2910,7 @@ void Base_DB::do_calculations(const LayoutFieldInRecord& field_changed, bool fir
   }
 
   //Recalculate fields that are triggered by a change of this field's value, not including calculations that these calculations use.
-  
+
   type_list_const_field_items calculated_fields = get_calculated_fields(field_changed.m_table_name, field_changed.m_field);
   //std::cout << "  debug: calculated_field.size()=" << calculated_fields.size() << std::endl;
   for(type_list_const_field_items::const_iterator iter = calculated_fields.begin(); iter != calculated_fields.end(); ++iter)
@@ -2934,7 +2941,7 @@ Base_DB::type_list_const_field_items Base_DB::get_calculated_fields(const Glib::
   const Document* document = dynamic_cast<const Document*>(get_document());
   if(document)
   {
-    //Look at each field in the table, and get lists of what fields trigger their calculations, 
+    //Look at each field in the table, and get lists of what fields trigger their calculations,
     //so we can see if our field is in any of those lists:
 
     const type_vec_fields fields = document->get_table_fields(table_name); //TODO_Performance: Cache this?
@@ -2957,7 +2964,7 @@ Base_DB::type_list_const_field_items Base_DB::get_calculated_fields(const Glib::
         //std::cout << "      debug: FOUND: name=" << layoutitem_field_to_examine->get_name() << std::endl;
         //Tell the caller that this field is triggered by the specified field:
         //TODO: Test related fields too?
-        
+
         result.push_back(layoutitem_field_to_examine);
       }
     }
@@ -3150,12 +3157,12 @@ Gnome::Gda::Value Base_DB::get_lookup_value(const Glib::ustring& /* table_name *
     if(data_model && data_model->get_n_rows())
     {
       //There should be only 1 row. Well, there could be more but we will ignore them.
-#ifdef GLIBMM_EXCEPTIONS_ENABLED      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       result = data_model->get_value_at(0, 0);
 #else
       std::auto_ptr<Glib::Error> error;
       result = data_model->get_value_at(0, 0, error);
-#endif            
+#endif
     }
     else
     {
@@ -3170,7 +3177,7 @@ bool Base_DB::get_field_value_is_unique(const Glib::ustring& table_name, const s
 {
   bool result = true;  //Arbitrarily default to saying it's unique if we can't get any result.
 
-  const Glib::ustring table_name_used = field->get_table_used(table_name); 
+  const Glib::ustring table_name_used = field->get_table_used(table_name);
 
   Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
   sharedptr<const Field> glom_field = field->get_full_field_details();
@@ -3214,7 +3221,7 @@ bool Base_DB::check_entered_value_for_uniqueness(const Glib::ustring& table_name
       //Warn the user and revert the value:
       if(parent_window)
         Frame_Glom::show_ok_dialog(_("Value Is Not Unique"), _("The field's value must be unique, but a record with this value already exists."), *parent_window);
-         
+
       return false; //Failed.
     }
     else
@@ -3228,12 +3235,12 @@ bool Base_DB::get_relationship_exists(const Glib::ustring& table_name, const Gli
 {
   Document* document = get_document();
   if(document)
-  { 
+  {
     sharedptr<Relationship> relationship = document->get_relationship(table_name, relationship_name);
     if(relationship)
       return true;
   }
- 
+
   return false;
 }
 
@@ -3249,9 +3256,9 @@ sharedptr<const LayoutItem_Field> Base_DB::get_field_is_from_non_hidden_related_
   if(!document)
     return result;
 
-  const Glib::ustring parent_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */); 
+  const Glib::ustring parent_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
 
-  LayoutItem_Portal::type_list_const_items items = portal->get_items(); 
+  LayoutItem_Portal::type_list_const_items items = portal->get_items();
   for(LayoutItem_Portal::type_list_const_items::const_iterator iter = items.begin(); iter != items.end(); ++iter)
   {
     sharedptr<const LayoutItem_Field> field = sharedptr<const LayoutItem_Field>::cast_dynamic(*iter);
@@ -3281,7 +3288,7 @@ sharedptr<const LayoutItem_Field> Base_DB::get_field_identifies_non_hidden_relat
 
   const Glib::ustring parent_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
 
-  LayoutItem_Portal::type_list_const_items items = portal->get_items(); 
+  LayoutItem_Portal::type_list_const_items items = portal->get_items();
   for(LayoutItem_Portal::type_list_const_items::const_iterator iter = items.begin(); iter != items.end(); ++iter)
   {
     sharedptr<const LayoutItem_Field> field = sharedptr<const LayoutItem_Field>::cast_dynamic(*iter);
@@ -3312,18 +3319,18 @@ sharedptr<const UsesRelationship> Base_DB::get_portal_navigation_relationship_au
   navigation_main = false;
 
   const Document* document = get_document();
-  
+
   //If the related table is not hidden then we can just navigate to that:
   const Glib::ustring direct_related_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
   if(!(document->get_table_is_hidden(direct_related_table_name)))
   {
-    //Non-hidden tables can just be shown directly. Navigate to it: 
+    //Non-hidden tables can just be shown directly. Navigate to it:
     navigation_main = true;
     return sharedptr<UsesRelationship>();
   }
   else
   {
-    //If the related table is hidden, 
+    //If the related table is hidden,
     //then find a suitable related non-hidden table by finding the first layout field that mentions one:
     sharedptr<const LayoutItem_Field> field = get_field_is_from_non_hidden_related_record(portal);
     if(field)
@@ -3337,14 +3344,14 @@ sharedptr<const UsesRelationship> Base_DB::get_portal_navigation_relationship_au
     }
     else
     {
-      //Instead, find a key field that's used in a relationship, 
+      //Instead, find a key field that's used in a relationship,
       //and pretend that we are showing the to field as a related field:
       sharedptr<const Relationship> used_in_relationship;
       sharedptr<const LayoutItem_Field> field_identifies = get_field_identifies_non_hidden_related_record(portal, used_in_relationship);
       if(field_identifies)
       {
         sharedptr<UsesRelationship> result = sharedptr<UsesRelationship>::create();
-       
+
         sharedptr<Relationship> rel_nonconst = sharedptr<Relationship>::cast_const(used_in_relationship);
         result->set_relationship(rel_nonconst);
 
@@ -3354,7 +3361,7 @@ sharedptr<const UsesRelationship> Base_DB::get_portal_navigation_relationship_au
   }
 
   //There was no suitable related table to show:
-  return sharedptr<UsesRelationship>(); 
+  return sharedptr<UsesRelationship>();
 }
 
 bool Base_DB::get_primary_key_is_in_foundset(const FoundSet& found_set, const Gnome::Gda::Value& primary_key_value)
@@ -3366,16 +3373,16 @@ bool Base_DB::get_primary_key_is_in_foundset(const FoundSet& found_set, const Gn
     std::cerr << "Base_DB::get_primary_key_is_in_foundset(): No primary key found for table: " << found_set.m_table_name << std::endl;
     return false;
   }
-  
+
   type_vecLayoutFields fieldsToGet;
-    
+
   sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
   layout_item->set_full_field_details(primary_key);
   fieldsToGet.push_back(layout_item);
 
   Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
   params->add_holder("primary_key", primary_key_value);
-  
+
   Glib::ustring where_clause;
   if(!found_set.m_where_clause.empty())
     where_clause = "(" + found_set.m_where_clause + ") AND ";
@@ -3390,7 +3397,7 @@ bool Base_DB::get_primary_key_is_in_foundset(const FoundSet& found_set, const Gn
     //std::cout << "debug: Record found: " << query << std::endl;
     return true; //A record was found in the record set with this value.
   }
-  else  
+  else
     return false;
 }
 
@@ -3402,19 +3409,19 @@ int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
   //Note that the alias is just because the SQL syntax requires it - we get an error if we don't use it.
   //Be careful not to include ORDER BY clauses in this, because that would make it unnecessarily slow:
   const Glib::ustring query_count = "SELECT COUNT (*) FROM (" + sql_query + ") AS glomarbitraryalias";
-  
+
   const App_Glom* app = App_Glom::get_application();
   if(app && app->get_show_sql_debug())
-  {  
+  {
     try
     {
       std::cout << "Debug: count_rows_returned_by():  " << query_count << std::endl;
     }
     catch(const Glib::Exception& ex)
     {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       std::cout << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
-#endif      
+#endif
     }
   }
 
@@ -3431,7 +3438,7 @@ int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
     g_warning("Base_DB::count_rows_returned_by(): connection failed.");
     return 0;
   }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED  
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
   try
   {
     Glib::RefPtr<Gnome::Gda::DataModel> datamodel = sharedconnection->get_gda_connection()->statement_execute_select(query_count);
@@ -3446,7 +3453,7 @@ int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
 #endif
     if(datamodel && datamodel->get_n_rows() && datamodel->get_n_columns())
     {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
 #else
       std::auto_ptr<Glib::Error> value_error;
@@ -3487,7 +3494,7 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
   {
     return;
   }
- 
+
 
   sharedptr<Relationship> relationship = portal->get_relationship();
 
@@ -3499,7 +3506,7 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
   sharedptr<Field> where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), relationship->get_to_field());
 
   found_set.m_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
-      
+
   sharedptr<const Relationship> relationship_related = portal->get_related_relationship();
   if(relationship_related)
   {
@@ -3523,7 +3530,7 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
     Glib::ustring sql_part_from;
     Glib::ustring sql_part_leftouterjoin;
     const Glib::ustring sql_part_fields = Utils::build_sql_select_fields_to_get(
-      found_set.m_table_name, fields, found_set.m_sort_clause, 
+      found_set.m_table_name, fields, found_set.m_sort_clause,
       sql_part_from, sql_part_leftouterjoin);
     found_set.m_extra_group_by = "GROUP BY " + sql_part_fields;
 
@@ -3534,7 +3541,7 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
     const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
     where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
     //std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
- 
+
     //std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
   }
 
@@ -3550,7 +3557,7 @@ void Base_DB::update_gda_metastore_for_table(const Glib::ustring& table_name) co
 #else
   std::auto_ptr<Glom::ExceptionConnection> ex;
   sharedptr<SharedConnection> sharedconnection = connect_to_server(App_Glom::get_application(), ex);
-#endif  
+#endif
   if(!sharedconnection)
   {
     std::cerr << "Base_DB::update_gda_metastore_for_table(): No connection." << std::endl;
@@ -3572,13 +3579,13 @@ void Base_DB::update_gda_metastore_for_table(const Glib::ustring& table_name) co
 
   //std::cout << "DEBUG: Base_DB::update_gda_metastore_for_table(): Calling Gda::Connection::update_meta_store_table(" << table_name << ") ..." << std::endl;
   //TODO: This doesn't seem to quite work yet:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED  
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
   gda_connection->update_meta_store_table(table_name);
 #else
   std::auto_ptr<Glib::Error> update_error;
   gda_connection->update_meta_store_table(table_name, Glib::ustring(), update_error);
-#endif  
-  
+#endif
+
   //This does work, though it takes ages: gda_connection->update_meta_store();
   //std::cout << "DEBUG: Base_DB::update_gda_metastore_for_table(): ... Finished calling Gda::Connection::update_meta_store_table()" << std::endl;
 }
@@ -3593,7 +3600,7 @@ bool Base_DB::add_user(const Glib::ustring& user, const Glib::ustring& password,
   Glib::ustring strQuery = "CREATE USER \"" + user + "\" PASSWORD '" + password + "'" ; //TODO: Escape the password.
   if(group == GLOM_STANDARD_GROUP_NAME_DEVELOPER)
     strQuery += " SUPERUSER CREATEDB CREATEROLE"; //Because SUPERUSER is not "inherited" from groups to members.
-  
+
 
   //Glib::ustring strQuery = "CREATE USER \"" + user + "\"";
   //if(group == GLOM_STANDARD_GROUP_NAME_DEVELOPER)
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index cb989bc..be5ac82 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -49,7 +49,7 @@ bool Base_DB_Table_Data::refresh_data_from_database()
 Gnome::Gda::Value Base_DB_Table_Data::get_entered_field_data_field_only(const sharedptr<const Field>& field) const
 {
   sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
-  layout_item->set_full_field_details(field); 
+  layout_item->set_full_field_details(field);
 
   return get_entered_field_data(layout_item);
 }
@@ -63,7 +63,7 @@ Gnome::Gda::Value Base_DB_Table_Data::get_entered_field_data(const sharedptr<con
 
 Gtk::TreeModel::iterator Base_DB_Table_Data::get_row_selected()
 {
-  //This in meaningless for Details, 
+  //This in meaningless for Details,
   //but is overridden for list views.
   return Gtk::TreeModel::iterator();
 }
@@ -127,7 +127,15 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
             // Don't evaluate function on error
 #endif // GLIBMM_EXCEPTIONS_ENABLED
 
-            const Gnome::Gda::Value value = glom_evaluate_python_function_implementation(field->get_glom_type(), calculation, field_values, document, m_table_name, sharedconnection->get_gda_connection());
+            const Gnome::Gda::Value value =
+              glom_evaluate_python_function_implementation(
+                field->get_glom_type(),
+                calculation,
+                field_values,
+                document,
+                m_table_name,
+                fieldPrimaryKey, primary_key_value,
+                sharedconnection->get_gda_connection());
             set_entered_field_data(layout_item, value);
 #ifndef GLIBMM_EXCEPTIONS_ENABLED
           }
@@ -157,7 +165,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
   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_vecLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
   {
     sharedptr<LayoutItem_Field> layout_item = *iter;
@@ -169,7 +177,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
       {
         Gnome::Gda::Value value;
 
-        const sharedptr<const Field>& field = layout_item->get_full_field_details();        
+        const sharedptr<const Field>& field = layout_item->get_full_field_details();
         if(field)
         {
           //Use the specified (generated) primary key value, if there is one:
@@ -190,7 +198,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
             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())
@@ -200,12 +208,12 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
               strNames += ", ";
               strValues += ", ";
             }
-  
+
             strNames += "\"" + field_name + "\"";
             strValues += field->get_gda_holder_string();
             Glib::RefPtr<Gnome::Gda::Holder> holder = field->get_holder(value);
             params->add_holder(holder);
-  
+
             map_added[field_name] = true;
           }
         }
@@ -229,7 +237,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
       for(type_vecLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
       {
         sharedptr<const LayoutItem_Field> layout_item = *iter;
-         
+
         //TODO_Performance: We just set this with set_entered_field_data() above. Maybe we could just remember it.
         const Gnome::Gda::Value field_value = get_entered_field_data(layout_item);
 
@@ -284,9 +292,9 @@ bool Base_DB_Table_Data::get_related_record_exists(const sharedptr<const Relatio
   return result;
 }
 
-bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const LayoutItem_Field>& layout_item_parent, 
-  const sharedptr<const Relationship>& relationship, 
-  const sharedptr<const Field>& primary_key_field, 
+bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const LayoutItem_Field>& layout_item_parent,
+  const sharedptr<const Relationship>& relationship,
+  const sharedptr<const Field>& primary_key_field,
   const Gnome::Gda::Value& primary_key_value_provided,
   Gnome::Gda::Value& primary_key_value_used)
 {
@@ -299,7 +307,7 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
     primary_key_value_used = primary_key_value; //Let the caller know what related record was created.
     return true;
   }
-    
+
 
   //To store the entered data in the related field, we would first have to create a related record.
   if(!relationship->get_auto_create())
@@ -414,7 +422,7 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
           }
         }
       }
-        
+
       primary_key_value_used = primary_key_value; //Let the caller know what related record was created.
       return true;
     }
@@ -424,14 +432,14 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
 void Base_DB_Table_Data::on_record_added(const Gnome::Gda::Value& /* primary_key_value */, const Gtk::TreeModel::iterator& /* row */)
 {
    //Overridden by some derived classes.
-  
+
    signal_record_changed().emit();
 }
 
 void Base_DB_Table_Data::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
 {
   //Overridden by some derived classes.
-  
+
   signal_record_changed().emit();
 }
 
@@ -512,12 +520,12 @@ void Base_DB_Table_Data::refresh_related_fields(const LayoutFieldInRecord& field
 
         for(guint uiCol = 0; uiCol < cols_count; ++uiCol)
         {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED        
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
           const Gnome::Gda::Value value = result->get_value_at(uiCol, 0 /* row */);
-#else          
+#else
           std::auto_ptr<Glib::Error> value_error;
           const Gnome::Gda::Value value = result->get_value_at(uiCol, 0 /* row */, value_error);
-#endif          
+#endif
           sharedptr<LayoutItem_Field> layout_item = *iterFields;
           if(!layout_item)
             std::cerr << "Base_DB_Table_Data::refresh_related_fields(): The layout_item was null." << std::endl;
@@ -575,5 +583,3 @@ Base_DB_Table_Data::type_vecLayoutFields Base_DB_Table_Data::get_related_fields(
 }
 
 } //namespace Glom
-
-
diff --git a/glom/libglom/python_embed/py_glom_record.cc b/glom/libglom/python_embed/py_glom_record.cc
index 34f776c..a989659 100644
--- a/glom/libglom/python_embed/py_glom_record.cc
+++ b/glom/libglom/python_embed/py_glom_record.cc
@@ -27,6 +27,7 @@
 #include <libglom/python_embed/py_glom_record.h>
 #include <libglom/python_embed/py_glom_related.h>
 #include <libglom/python_embed/pygdavalue_conversions.h> //For pygda_value_as_pyobject().
+#include <libglom/data_structure/glomconversions.h>
 
 #include <libglom/data_structure/field.h>
 #include <glibmm/ustring.h>
@@ -52,15 +53,15 @@ std::string PyGlomRecord::get_table_name() const
 boost::python::object PyGlomRecord::get_connection()
 {
   boost::python::object result;
-  
+
   if(m_connection)
   {
-    //Ask pygobject to create a PyObject* that wraps our GObject, 
+    //Ask pygobject to create a PyObject* that wraps our GObject,
     //presumably using something from pygda:
     PyObject* cobject = pygobject_new( G_OBJECT(m_connection->gobj()) );
     result = boost::python::object( boost::python::borrowed(cobject) );
   }
-  
+
   return result;
 }
 
@@ -101,24 +102,144 @@ long PyGlomRecord::len() const
 boost::python::object PyGlomRecord::getitem(const boost::python::object& cppitem)
 {
   const std::string key = boost::python::extract<std::string>(cppitem);
-    
+
   PyGlomRecord::type_map_field_values::const_iterator iterFind = m_map_field_values.find(key);
   if(iterFind != m_map_field_values.end())
   {
     return glom_pygda_value_as_boost_pyobject(iterFind->second);
   }
 
-  return boost::python::object();   
+  return boost::python::object();
+}
+
+//TODO: Stop this from being used in field calculations, by making the record somehow read-only.
+void PyGlomRecord::setitem(const boost::python::object& key, const boost::python::object& value)
+{
+  //Get the specificd field name (and details) and value:
+
+  std::string field_name;
+  boost::python::extract<std::string> extractor(key);
+  if(extractor.check())
+    field_name = extractor;
+
+  sharedptr<const Field> field = m_document->get_field(m_table_name, field_name);
+  if(!field)
+  {
+     std::cerr << "PyGlomRecord::setitem(): field=" << field_name << " not found in table=" << m_table_name << std::endl;
+     //TODO: Throw python exception.
+     return;
+  }
+
+  const Field::glom_field_type field_type = field->get_glom_type(); //TODO
+
+  Gnome::Gda::Value field_value;
+  GValue value_c = {0, {{0}}};
+  bool test = glom_pygda_value_from_pyobject(&value_c, value);
+  if(test && G_IS_VALUE(&value))
+  {
+    field_value = Gnome::Gda::Value(&value_c);
+
+    //Make sure that the value is of the expected Gda type:
+    field_value = Conversions::convert_value(field_value, field_type);
+
+    g_value_unset(&value_c);
+  }
+  else
+    field_value = Conversions::get_empty_value(field_type);
+
+  //std::cout << "debug: PyGlomRecord::setitem(): field_name=" << field_name << ", field_type=" << field_type << ", field_value=" << field_value.to_string() << std::endl;
+
+
+  //Set the value in the database:
+  if(!m_key_field || Conversions::value_is_empty(m_key_field_value))
+  {
+    std::cerr << "PyGlomRecord::setitem(): The primary key name and value is not set. This would be a Glom bug." << std::endl;
+    return;
+  }
+
+  if(!m_connection)
+  {
+    std::cerr << "PyGlomRecord::setitem(): The connection is null. This would be a Glom bug." << std::endl;
+    return;
+  }
+
+  Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+  params->add_holder(field->get_holder(field_value));
+  params->add_holder(m_key_field->get_holder(m_key_field_value));
+
+  Glib::ustring strQuery = "UPDATE \"" + m_table_name + "\"";
+  strQuery += " SET \"" + field->get_name() + "\" = " + field->get_gda_holder_string();
+  strQuery += " WHERE \"" + m_key_field->get_name() + "\" = " + m_key_field->get_gda_holder_string();
+
+  bool updated = false;
+  Glib::RefPtr<Gnome::Gda::Statement> stmt;
+  try
+  {
+    Glib::RefPtr<Gnome::Gda::SqlParser> parser = m_connection->create_parser();
+    stmt = parser->parse_string(strQuery);
+
+  }
+  catch(const Glib::Exception& ex)
+  {
+    std::cerr << "PyGlomRecord::setitem(): exception while parsing query: " << ex.what() << std::endl;
+  }
+  catch(const std::exception& ex)
+  {
+    std::cerr << "PyGlomRecord::setitem(): exception while parsing query: " << ex.what() << std::endl;
+  }
+
+  if(stmt)
+  {
+    try
+    {
+      updated = m_connection->statement_execute_non_select(stmt, params);
+    }
+    catch(const Glib::Exception& ex)
+    {
+      std::cerr << "PyGlomRecord::setitem(): exception while executing query: " << ex.what() << std::endl;
+    }
+    catch(const std::exception& ex)
+    {
+      std::cerr << "PyGlomRecord::setitem(): exception while executing query: " << ex.what() << std::endl;
+    }
+  }
+
+  if(!updated)
+  {
+    Glib::ustring failed_query;
+
+    std::cerr << "PyGlomRecord::setitem(): UPDATE failed." << std::endl;
+    /*
+    if(stmt)
+      failed_query = stmt->to_sql(params); //this throws too.
+    else
+      failed_query = strQuery;
+
+    try
+    {
+      std::cerr << "  with SQL query: " << failed_query << std::endl;
+    }
+    catch(const Glib::Exception& ex)
+    {
+      std::cerr << "  query string could not be converted to std::cerr" << std::endl;
+    }
+    */
+
+  }
+
+  //TODO: Do dependent calculations and lookups. Or just do them for all fields for this record when finishing the script?
 }
 
-void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_field_values& field_values, Document* document, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
+void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_field_values& field_values, Document* document, const Glib::ustring& table_name, const sharedptr<const Field>& key_field, const Gnome::Gda::Value& key_field_value, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
 {
   g_assert(self);
-  
+
   self->m_map_field_values = field_values;
 
   self->m_table_name = table_name;
-  
+  self->m_key_field = key_field;
+  self->m_key_field_value = key_field_value;
+
   if(self->m_document == 0)
     self->m_document = document;
 
@@ -180,5 +301,3 @@ void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_fie
 }
 
 } //namespace Glom
-
-
diff --git a/glom/libglom/python_embed/py_glom_record.h b/glom/libglom/python_embed/py_glom_record.h
index 487dd76..c94188f 100644
--- a/glom/libglom/python_embed/py_glom_record.h
+++ b/glom/libglom/python_embed/py_glom_record.h
@@ -48,12 +48,13 @@ public:
   //[] notation:
   long len() const;
   boost::python::object getitem(const boost::python::object& item);
+  void setitem(const boost::python::object& /* key */, const boost::python::object& /* value */);
 
 public:
-  //PyObject* m_fields_dict; //Dictionary (map) of field names (string) to field values (Gnome::Gda::Value).
-  //PyGObject* m_py_gda_connection; //"derived" from PyObject.
   Document* m_document;
   Glib::ustring m_table_name;
+  sharedptr<const Field> m_key_field;
+  Gnome::Gda::Value m_key_field_value;
 
   boost::python::object m_related; //Actually a PyGlomRelated
 
@@ -64,7 +65,13 @@ public:
   Glib::RefPtr<Gnome::Gda::Connection> m_connection;
 };
 
-void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_field_values& field_values, Document* document, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
+void PyGlomRecord_SetFields(PyGlomRecord* self,
+  const PyGlomRecord::type_map_field_values& field_values,
+  Document* document,
+  const Glib::ustring& table_name,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_field_value,
+  const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
 
 } //namespace Glom
 
diff --git a/glom/libglom/python_embed/py_glom_relatedrecord.cc b/glom/libglom/python_embed/py_glom_relatedrecord.cc
index 51e7b81..59c5949 100644
--- a/glom/libglom/python_embed/py_glom_relatedrecord.cc
+++ b/glom/libglom/python_embed/py_glom_relatedrecord.cc
@@ -54,7 +54,7 @@ long PyGlomRelatedRecord::len() const
 boost::python::object PyGlomRelatedRecord::getitem(const boost::python::object& cppitem)
 {
   const std::string field_name = boost::python::extract<std::string>(cppitem);
- 
+
   PyGlomRelatedRecord::type_map_field_values::const_iterator iterFind = m_map_field_values.find(field_name);
   if(iterFind != m_map_field_values.end())
   {
@@ -67,7 +67,7 @@ boost::python::object PyGlomRelatedRecord::getitem(const boost::python::object&
 
     //Check whether the field exists in the table.
     //TODO_Performance: Do this without the useless Field information?
-    sharedptr<Field> field = m_document->get_field(m_relationship->get_to_table(), field_name);
+    sharedptr<const Field> field = m_document->get_field(m_relationship->get_to_table(), field_name);
     if(!field)
       g_warning("RelatedRecord_tp_as_mapping_getitem: field %s not found in table %s", field_name.c_str(), m_relationship->get_to_table().c_str());
     else
@@ -90,7 +90,7 @@ boost::python::object PyGlomRelatedRecord::getitem(const boost::python::object&
         //Do not try to get a value based on a null key value:
         if(m_from_key_value_sqlized.empty())
           return boost::python::object();
-       
+
         //Get the single value from the related records:
         const Glib::ustring sql_query = "SELECT \"" + related_table + "\".\"" + field_name + "\" FROM \"" + related_table + "\""
           + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + m_from_key_value_sqlized;
@@ -119,11 +119,11 @@ boost::python::object PyGlomRelatedRecord::getitem(const boost::python::object&
 #endif
         if(datamodel && datamodel->get_n_rows())
         {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED            
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
           Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
 #else
           Gnome::Gda::Value value = datamodel->get_value_at(0, 0, error);
-#endif                            
+#endif
           //g_warning("RelatedRecord_tp_as_mapping_getitem(): value from datamodel = %s", value.to_string().c_str());
 
           //Cache it, in case it's asked-for again.
@@ -176,7 +176,7 @@ boost::python::object PyGlomRelatedRecord::generic_aggregate(const std::string&
     g_warning("RelatedRecord_sum: no connection.");
     return boost::python::object();
   }
-  
+
   Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
 
   const Glib::ustring related_key_name = m_relationship->get_to_field();
@@ -186,11 +186,11 @@ boost::python::object PyGlomRelatedRecord::generic_aggregate(const std::string&
   {
     return boost::python::object();
   }
-       
+
   //Get the aggregate value from the related records:
   const Glib::ustring sql_query = "SELECT " + aggregate + "(\"" + related_table + "\".\"" + field_name + "\") FROM \"" + related_table + "\""
     + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + m_from_key_value_sqlized;
-        
+
   //std::cout << "PyGlomRelatedRecord: Executing:  " << sql_query << std::endl;
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
   Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query);
@@ -203,11 +203,11 @@ boost::python::object PyGlomRelatedRecord::generic_aggregate(const std::string&
 #endif
   if(datamodel && datamodel->get_n_rows())
   {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED        
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
 #else
     Gnome::Gda::Value value = datamodel->get_value_at(0, 0, error);
-#endif          
+#endif
     //g_warning("RelatedRecord_generic_aggregate(): value from datamodel = %s", value.to_string().c_str());
 
     //Cache it, in case it's asked-for again.
@@ -258,5 +258,3 @@ void PyGlomRelatedRecord_SetRelationship(PyGlomRelatedRecord* self, const shared
 }
 
 } //namespace Glom
-
-
diff --git a/glom/libglom/python_embed/pygdavalue_conversions.h b/glom/libglom/python_embed/pygdavalue_conversions.h
index e2e2780..ebb93b5 100644
--- a/glom/libglom/python_embed/pygdavalue_conversions.h
+++ b/glom/libglom/python_embed/pygdavalue_conversions.h
@@ -8,8 +8,8 @@
 #include <libgda/libgda.h>
 #include <boost/python.hpp>
 
-bool
-glom_pygda_value_from_pyobject(GValue *boxed, const boost::python::object& input);
+
+bool glom_pygda_value_from_pyobject(GValue *boxed, const boost::python::object& input);
 
 //PyObject *
 //glom_pygda_value_as_pyobject(const GValue *value, gboolean copy_boxed);
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index 213dbd7..a20e369 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -45,13 +45,52 @@ typedef std::vector< sharedptr<LayoutItem_Field> > type_vecLayoutFields;
 typedef std::vector< sharedptr<const LayoutItem_Field> > type_vecConstLayoutFields;
 
 //TODO: Move these to their own file:
-Glib::ustring build_sql_select_fields_to_get(const Glib::ustring& table_name, const type_vecConstLayoutFields& fieldsToGet, const type_sort_clause& sort_clause, Glib::ustring& sql_part_from, Glib::ustring& sql_part_leftouterjoin);
 
-Glib::ustring build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecLayoutFields& fieldsToGet, const Glib::ustring& where_clause = Glib::ustring(), const Glib::ustring& extra_join = Glib::ustring(), const type_sort_clause& sort_clause = type_sort_clause(), const Glib::ustring& extra_group_by = Glib::ustring());
-Glib::ustring build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecConstLayoutFields& fieldsToGet, const Glib::ustring& where_clause = Glib::ustring(), const Glib::ustring& extra_join = Glib::ustring(), const type_sort_clause& sort_clause = type_sort_clause(), const Glib::ustring& extra_group_by = Glib::ustring());
-
-Glib::ustring build_sql_select_with_key(const Glib::ustring& table_name, const type_vecLayoutFields& fieldsToGet, const sharedptr<const Field>& key_field, const Gnome::Gda::Value& key_value);
-Glib::ustring build_sql_select_with_key(const Glib::ustring& table_name, const type_vecConstLayoutFields& fieldsToGet, const sharedptr<const Field>& key_field, const Gnome::Gda::Value& key_value);
+/** Generate a SQL statement to SELECT field values,
+ * even if the fields are in related (or doubly related) records.
+ */
+Glib::ustring build_sql_select_fields_to_get(
+  const Glib::ustring& table_name,
+  const type_vecConstLayoutFields& fieldsToGet,
+  const type_sort_clause& sort_clause,
+  Glib::ustring& sql_part_from,
+  Glib::ustring& sql_part_leftouterjoin);
+
+/** Generate a SQL statement to SELECT field values,
+ * even if the fields are in related (or doubly related) records,
+ * narrowing the records down with a WHERE clause.
+ */
+Glib::ustring build_sql_select_with_where_clause(
+  const Glib::ustring& table_name,
+  const type_vecLayoutFields& fieldsToGet,
+  const Glib::ustring& where_clause = Glib::ustring(),
+  const Glib::ustring& extra_join = Glib::ustring(),
+  const type_sort_clause& sort_clause = type_sort_clause(),
+  const Glib::ustring& extra_group_by = Glib::ustring());
+
+/** Just a version of build_sql_select_with_where_clause() that takes a list of const fields.
+ */
+Glib::ustring build_sql_select_with_where_clause(
+  const Glib::ustring& table_name,
+  const type_vecConstLayoutFields& fieldsToGet,
+  const Glib::ustring& where_clause = Glib::ustring(),
+  const Glib::ustring& extra_join = Glib::ustring(),
+  const type_sort_clause& sort_clause = type_sort_clause(),
+  const Glib::ustring& extra_group_by = Glib::ustring());
+
+Glib::ustring build_sql_select_with_key(
+  const Glib::ustring& table_name,
+  const type_vecLayoutFields& fieldsToGet,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_value);
+
+/** Just a version of build_sql_select_with_key() that takes a list of const fields.
+ */
+Glib::ustring build_sql_select_with_key(
+  const Glib::ustring& table_name,
+  const type_vecConstLayoutFields& fieldsToGet,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_value);
 
 typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
 type_list_values_with_second get_choice_values(const sharedptr<const LayoutItem_Field>& field);
@@ -62,12 +101,12 @@ Glib::ustring create_name_from_title(const Glib::ustring& title);
 
 Glib::ustring string_escape_underscores(const Glib::ustring& text);
 
-/** Get just the first part of a locale, such as de_DE, 
+/** Get just the first part of a locale, such as de_DE,
  * ignoring, for instance, .UTF-8 or @euro at the end.
  */
 Glib::ustring locale_simplify(const Glib::ustring& locale_id);
 
-/** Get just the language ID part of a locale, such as de from "de_DE", 
+/** Get just the language ID part of a locale, such as de from "de_DE",
  */
 Glib::ustring locale_language_id(const Glib::ustring& locale_id);
 
@@ -97,4 +136,3 @@ bool file_exists(const Glib::ustring& uri);
 } //namespace Glom
 
 #endif //GLOM_UTILS_H
-
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index b05962f..82d11aa 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -275,7 +275,7 @@ Document::type_list_layout_groups Box_Data::get_data_layout_groups(const Glib::u
 }
 
 void Box_Data::fill_layout_group_field_info(const sharedptr<LayoutGroup>& group, const Privileges& table_privs)
-{ 
+{
   if(!group)
    return;
 
@@ -352,7 +352,8 @@ Glib::ustring Box_Data::get_layout_name() const
 
 void Box_Data::execute_button_script(const sharedptr<const LayoutItem_Button>& layout_item, const Gnome::Gda::Value& primary_key_value)
 {
-  const type_map_fields field_values = get_record_field_values_for_calculation(m_table_name, get_field_primary_key(), primary_key_value);
+  const sharedptr<Field> field_primary_key = get_field_primary_key();
+  const type_map_fields field_values = get_record_field_values_for_calculation(m_table_name, field_primary_key, primary_key_value);
 
   //We need the connection when we run the script, so that the script may use it.
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
@@ -364,8 +365,11 @@ void Box_Data::execute_button_script(const sharedptr<const LayoutItem_Button>& l
   {
 #endif // GLIBMM_EXCEPTIONS_ENABLED
 
-    glom_execute_python_function_implementation(layout_item->get_script(), field_values, //TODO: Maybe use the field's type here.
-      get_document(), get_table_name(), sharedconnection->get_gda_connection());
+    glom_execute_python_function_implementation(layout_item->get_script(),
+      field_values, //TODO: Maybe use the field's type here.
+      get_document(),
+      get_table_name(), field_primary_key, primary_key_value,
+      sharedconnection->get_gda_connection());
 #ifndef GLIBMM_EXCEPTIONS_ENABLED
   }
 #endif // !GLIBMM_EXCEPTIONS_ENABLED
diff --git a/glom/mode_design/fields/dialog_fieldcalculation.cc b/glom/mode_design/fields/dialog_fieldcalculation.cc
index 1f34d3b..3fb9c10 100644
--- a/glom/mode_design/fields/dialog_fieldcalculation.cc
+++ b/glom/mode_design/fields/dialog_fieldcalculation.cc
@@ -98,7 +98,7 @@ bool Dialog_FieldCalculation::check_for_return_statement(const Glib::ustring& ca
      Frame_Glom::show_ok_dialog(_("Calculation Error"), _("The calculation does not have a return statement."), *this);
      return false;
   }
-  
+
   return true;
 }
 
@@ -125,8 +125,14 @@ void Dialog_FieldCalculation::on_button_test()
   //We need the connection when we run the script, so that the script may use it.
   sharedptr<SharedConnection> sharedconnection = connect_to_server(this /* parent window */);
 
-  const Gnome::Gda::Value value = glom_evaluate_python_function_implementation(Field::TYPE_TEXT, calculation, field_values, //TODO: Maybe use the field's type here.
-    document, m_table_name, sharedconnection->get_gda_connection());
+  const Gnome::Gda::Value value = glom_evaluate_python_function_implementation(
+    Field::TYPE_TEXT,
+    calculation,
+    field_values, //TODO: Maybe use the field's type here.
+    document,
+    m_table_name,
+    sharedptr<Field>(), Gnome::Gda::Value(), // primary key - only used when setting values in the DB.
+    sharedconnection->get_gda_connection());
 
   Frame_Glom::show_ok_dialog(_("Calculation result"), _("The result of the calculation is:\n") + value.to_string(), *this);
 
@@ -155,6 +161,3 @@ void Dialog_FieldCalculation::on_button_test()
 }
 
 } //namespace Glom
-
-
-
diff --git a/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc b/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
index 8ecbac7..6885d7f 100644
--- a/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
+++ b/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
@@ -116,12 +116,12 @@ void Dialog_ButtonScript::on_button_test()
   //We need the connection when we run the script, so that the script may use it.
   sharedptr<SharedConnection> sharedconnection = connect_to_server(this /* parent window */);
 
-  glom_execute_python_function_implementation(calculation, field_values, //TODO: Maybe use the field's type here.
-    document, m_table_name, sharedconnection->get_gda_connection());
+  glom_execute_python_function_implementation(calculation,
+    field_values, //TODO: Maybe use the field's type here.
+    document,
+    m_table_name,
+    sharedptr<Field>(), Gnome::Gda::Value(), // primary key - only used when setting values in the DB, which we would not encourage in a test.
+    sharedconnection->get_gda_connection());
 }
 
 } //namespace Glom
-
-
-
-
diff --git a/glom/python_embed/glom_python.cc b/glom/python_embed/glom_python.cc
index 34e3715..44971cd 100644
--- a/glom/python_embed/glom_python.cc
+++ b/glom/python_embed/glom_python.cc
@@ -165,13 +165,28 @@ bool gda_python_module_is_available()
 
 
 
-void glom_execute_python_function_implementation(const Glib::ustring& func_impl, const type_map_fields& field_values, Document* pDocument, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
+void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
+  const type_map_fields& field_values,
+  Document* pDocument,
+  const Glib::ustring& table_name,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_field_value,
+  const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
 {
-  glom_evaluate_python_function_implementation(Field::TYPE_TEXT, func_impl, field_values, pDocument, table_name, opened_connection);
+  glom_evaluate_python_function_implementation(Field::TYPE_TEXT, func_impl,
+     field_values, pDocument,
+     table_name, key_field, key_field_value,
+     opened_connection);
 }
 
-Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type, const Glib::ustring& func_impl,
-    const type_map_fields& field_values, Document* pDocument, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
+Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type,
+  const Glib::ustring& func_impl,
+  const type_map_fields& field_values,
+  Document* pDocument,
+  const Glib::ustring& table_name,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_field_value,
+  const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
 {
   //std::cout << "glom_evaluate_python_function_implementation()" << std::endl;
   //for(type_map_fields::const_iterator iter = field_values.begin(); iter != field_values.end(); ++iter)
@@ -337,7 +352,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
     if(pParam)
     {
       //Fill the record's details:
-      PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, opened_connection);
+      PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, key_field, key_field_value, opened_connection);
 
       //Call the function with this parameter:
        boost::python::object pyResultCpp;
diff --git a/glom/python_embed/glom_python.h b/glom/python_embed/glom_python.h
index 0d37ed1..60f65ea 100644
--- a/glom/python_embed/glom_python.h
+++ b/glom/python_embed/glom_python.h
@@ -28,22 +28,34 @@
 namespace Glom
 {
 
-/** Check that Python can really import the Glom module, 
+/** Check that Python can really import the Glom module,
  * as a runtime sanity check.
  */
 bool glom_python_module_is_available();
 
-/** Check that Python can really import the gda module, 
+/** Check that Python can really import the gda module,
  * as a runtime sanity check.
  */
 bool gda_python_module_is_available();
 
 typedef std::map<Glib::ustring, Gnome::Gda::Value> type_map_fields;
 
-void glom_execute_python_function_implementation(const Glib::ustring& func_impl, const type_map_fields& field_values, Document* pDocument, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
-
-Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type, const Glib::ustring& func_impl,
-  const type_map_fields& field_values, Document* pDocument, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
+void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
+  const type_map_fields& field_values,
+  Document* pDocument,
+  const Glib::ustring& table_name,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_field_value,
+  const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
+
+Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type,
+  const Glib::ustring& func_impl,
+  const type_map_fields& field_values,
+  Document* pDocument,
+  const Glib::ustring& table_name,
+  const sharedptr<const Field>& key_field,
+  const Gnome::Gda::Value& key_field_value,
+  const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
 
 } //namespace Glom
 
diff --git a/glom/python_embed/python_module/py_glom_module.cc b/glom/python_embed/python_module/py_glom_module.cc
index 2b72350..155d717 100644
--- a/glom/python_embed/python_module/py_glom_module.cc
+++ b/glom/python_embed/python_module/py_glom_module.cc
@@ -38,6 +38,7 @@ BOOST_PYTHON_MODULE(glom_1_14)
     .add_property("related", &PyGlomRecord::get_related)
 
     .def("__getitem__", &PyGlomRecord::getitem)
+    .def("__setitem__", &PyGlomRecord::setitem)
     .def("__len__", &PyGlomRecord::len)
   ;
 



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