[glom/sqlbuilder2] Use Gnome::Gda::SqlExpr for where clauses.



commit 99daa7fa8017a312ca5c1c155c0116ccc2d68644
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed May 12 11:43:11 2010 +0200

    Use Gnome::Gda::SqlExpr for where clauses.
    
    	* glom/libglom/utils.[h|cc]: Added build_simple_where_expression()
        and build_combined_where_expression() to make it easier to work with
        Gnome::Gda::SqlExpr.
        build_sql_select_with_key(): Return a SqlExpr instead of a string.
    	* glom/base_db.[h|cc]:
    	* glom/base_db_table_data.cc:
    	* glom/frame_glom.[h|cc]:
    	* glom/libglom/data_structure/foundset.[h|cc]:
    	* glom/mode_data/box_data.[h|cc]:
    	* glom/mode_data/box_data_calendar_related.cc:
    	* glom/mode_data/box_data_details.cc:
    	* glom/mode_data/box_data_list.cc:
    	* glom/mode_data/box_data_portal.cc:
    	* glom/mode_data/datawidget/dialog_choose_id..[h|cc]:
    	* glom/mode_find/notebook_find.[h|cc]:
    	* glom/print_layout/canvas_print_layout.cc:
    	* glom/report_builder.cc:
    	* glom/utility_widgets/db_adddel/glom_db_treemodel.cc:
        Adapt, using SqlExpr instead of a string for where clauses.

 ChangeLog                                          |   26 ++++-
 glom/base_db.cc                                    |  128 +++++++-----------
 glom/base_db.h                                     |    2 +-
 glom/base_db_table_data.cc                         |    4 +-
 glom/frame_glom.cc                                 |   20 ++--
 glom/frame_glom.h                                  |    2 +-
 glom/libglom/data_structure/foundset.cc            |    4 +-
 glom/libglom/data_structure/foundset.h             |    2 +-
 glom/libglom/utils.cc                              |  133 ++++++++++++------
 glom/libglom/utils.h                               |   21 ++-
 glom/mode_data/box_data.cc                         |   44 ++++---
 glom/mode_data/box_data.h                          |    4 +-
 glom/mode_data/box_data_calendar_related.cc        |  145 +++++++++++---------
 glom/mode_data/box_data_details.cc                 |    7 +-
 glom/mode_data/box_data_list.cc                    |   31 ++--
 glom/mode_data/box_data_portal.cc                  |   92 ++++++------
 glom/mode_data/datawidget/dialog_choose_id.cc      |    6 +-
 glom/mode_data/datawidget/dialog_choose_id.h       |    2 +-
 glom/mode_find/notebook_find.cc                    |    2 +-
 glom/mode_find/notebook_find.h                     |    4 +-
 glom/print_layout/canvas_print_layout.cc           |    4 +-
 glom/report_builder.cc                             |   13 ++-
 .../utility_widgets/db_adddel/glom_db_treemodel.cc |   44 +++---
 23 files changed, 406 insertions(+), 334 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 80f4ab1..3ed73bb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,28 @@
-2010-05-06  Murray Cumming  <murrayc murrayc-desktop>
+2010-05-12  Murray Cumming  <murrayc murrayc com>
+
+    Use Gnome::Gda::SqlExpr for where clauses.
+
+	* glom/libglom/utils.[h|cc]: Added build_simple_where_expression()
+    and build_combined_where_expression() to make it easier to work with
+    Gnome::Gda::SqlExpr.
+    build_sql_select_with_key(): Return a SqlExpr instead of a string.
+	* glom/base_db.[h|cc]:
+	* glom/base_db_table_data.cc:
+	* glom/frame_glom.[h|cc]:
+	* glom/libglom/data_structure/foundset.[h|cc]:
+	* glom/mode_data/box_data.[h|cc]:
+	* glom/mode_data/box_data_calendar_related.cc:
+	* glom/mode_data/box_data_details.cc:
+	* glom/mode_data/box_data_list.cc:
+	* glom/mode_data/box_data_portal.cc:
+	* glom/mode_data/datawidget/dialog_choose_id..[h|cc]:
+	* glom/mode_find/notebook_find.[h|cc]:
+	* glom/print_layout/canvas_print_layout.cc:
+	* glom/report_builder.cc:
+	* glom/utility_widgets/db_adddel/glom_db_treemodel.cc:
+    Adapt, using SqlExpr instead of a string for where clauses.
+
+2010-05-06  Murray Cumming  <murrayc murrayc com>
 
     Utils::get_choice_values(): Complete the use of SqlBuilder.
 
diff --git a/glom/base_db.cc b/glom/base_db.cc
index f169ef5..6deaf1b 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -1417,9 +1417,9 @@ Base_DB::type_map_fields Base_DB::get_record_field_values_for_calculation(const
     {
       //sharedptr<const Field> fieldPrimaryKey = get_field_primary_key();
 
-      const Glib::ustring query = Utils::build_sql_select_with_key(table_name, fieldsToGet, primary_key, primary_key_value);
+      Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_key(table_name, fieldsToGet, primary_key, primary_key_value);
 
-      Glib::RefPtr<Gnome::Gda::DataModel> data_model;
+      Glib::RefPtr<const Gnome::Gda::DataModel> data_model;
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
       try
       {
@@ -1595,10 +1595,10 @@ Gnome::Gda::Value Base_DB::get_field_value_in_database(const LayoutFieldInRecord
   type_vecConstLayoutFields list_fields;
   sharedptr<const LayoutItem_Field> layout_item = field_in_record.m_field;
   list_fields.push_back(layout_item);
-  Glib::ustring sql_query = Utils::build_sql_select_with_key(field_in_record.m_table_name,
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_key(field_in_record.m_table_name,
       list_fields, field_in_record.m_key, field_in_record.m_key_value, 1);
 
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(sql_query);
+  Glib::RefPtr<const Gnome::Gda::DataModel> data_model = query_execute_select(sql_query);
   if(data_model)
   {
     if(data_model->get_n_rows())
@@ -1640,13 +1640,13 @@ Gnome::Gda::Value Base_DB::get_field_value_in_database(const sharedptr<Field>& f
   sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
   layout_item->set_full_field_details(field);
   list_fields.push_back(layout_item);
-  const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
     list_fields,
     found_set.m_where_clause,
     Glib::ustring(), type_sort_clause(), Glib::ustring(),
     1 /* limit */);
 
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(sql_query);
+  Glib::RefPtr<const Gnome::Gda::DataModel> data_model = query_execute_select(sql_query);
   if(data_model)
   {
     if(data_model->get_n_rows())
@@ -2150,17 +2150,31 @@ bool Base_DB::get_primary_key_is_in_foundset(const FoundSet& found_set, const Gn
   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::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  builder->select_add_target(found_set.m_table_name);
 
-  Glib::ustring where_clause;
-  if(!found_set.m_where_clause.empty())
-    where_clause = "(" + found_set.m_where_clause + ") AND ";
+  const guint eq_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
+        builder->add_id(primary_key->get_name()),
+        builder->add_expr_as_value(primary_key_value));
+  guint cond_id = 0;
+  if(found_set.m_where_clause.empty())
+  {
+    cond_id = eq_id;
+  }
+  else
+  {
+    cond_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND,
+      builder->import_expression(found_set.m_where_clause),
+      eq_id);
+  }
 
-  where_clause += "(\"" + primary_key->get_name() + "\" = ##primary_key::" + primary_key->get_gda_type_name() + ")";
+  builder->set_where(cond_id); //This might be unnecessary.
+    cond_id = eq_id;
 
-  const Glib::ustring query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsToGet, where_clause);
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(query, params);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> query =
+    Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsToGet,
+      builder->export_expression(cond_id));
+  Glib::RefPtr<const Gnome::Gda::DataModel> data_model = query_execute_select(query);
 
   if(data_model && data_model->get_n_rows())
   {
@@ -2171,64 +2185,31 @@ bool Base_DB::get_primary_key_is_in_foundset(const FoundSet& found_set, const Gn
     return false;
 }
 
-int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
+int Base_DB::count_rows_returned_by(const Glib::RefPtr<Gnome::Gda::SqlBuilder>& sql_query)
 {
+  if(!sql_query)
+  {
+    std::cerr << "Base_DB::count_rows_returned_by(): sql_query was null." << std::endl;
+    return 0;
+  }
+
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  const guint target_id = builder->add_sub_select( sql_query->get_sql_statement() );
+  builder->select_add_target_id(target_id);
+
+  builder->add_function("COUNT", builder->add_id("*"));
+
+
   int result = 0;
 
   //TODO: Use SqlBuilder for this?
   //TODO: Is this inefficient?
   //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";
-
-  /* TODO: Use SqlBuilder when we discover how to use a sub-query, or when this function can take a Sqlbuilder.
-  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
-    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
-  builder->add_function("count", builder->add_id("*")); //TODO: Is * allowed here?
-  builder->select_add_target(m_found_set.m_table_name);
-  */
+  //TODO: Add alias too? const Glib::ustring query_count = "SELECT COUNT (*) FROM (" + sql_query + ") AS glomarbitraryalias";
 
-  const Application* app = Application::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
-      std::cout << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
-#endif
-    }
-  }
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  sharedptr<SharedConnection> sharedconnection = connect_to_server();
-#else
-  std::auto_ptr<ExceptionConnection> error;
-  sharedptr<SharedConnection> sharedconnection = connect_to_server(0, error);
-  // TODO: Rethrow?
-#endif
-
-  if(!sharedconnection)
-  {
-    g_warning("Base_DB::count_rows_returned_by(): connection failed.");
-    return 0;
-  }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  try
-  {
-    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = sharedconnection->get_gda_connection()->statement_execute_select(query_count);
-#else
-    std::auto_ptr<Glib::Error> model_error;
-    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = sharedconnection->get_gda_connection()->statement_execute_select(query_count, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS, model_error);
-    if(model_error.get())
-    {
-      std::cerr << "count_rows_returned_by(): exception caught: " << model_error->what() << std::endl;
-      return result;
-    }
-#endif
+    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(builder);
     if(datamodel && datamodel->get_n_rows() && datamodel->get_n_columns())
     {
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
@@ -2244,17 +2225,7 @@ int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
       else
         result = value.get_int();
     }
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
-  }
-  catch(const Glib::Exception& ex)
-  {
-    std::cerr << "count_rows_returned_by(): exception caught: " << ex.what() << std::endl;
-  }
-  catch(const std::exception& ex)
-  {
-    std::cerr << "count_rows_returned_by(): exception caught: " << ex.what() << std::endl;
-  }
-#endif
+
   //std::cout << "DEBUG: count_rows_returned_by(): Returning " << result << std::endl;
   return result;
 }
@@ -2263,7 +2234,7 @@ int Base_DB::count_rows_returned_by(const Glib::ustring& sql_query)
 void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const sharedptr<LayoutItem_Portal>& portal, const Gnome::Gda::Value& foreign_key_value)
 {
   found_set.m_table_name = Glib::ustring();
-  found_set.m_where_clause = Glib::ustring();
+  found_set.m_where_clause = Gnome::Gda::SqlExpr();
   found_set.m_extra_join = Glib::ustring();
   found_set.m_extra_group_by = Glib::ustring();
 
@@ -2325,7 +2296,10 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
 
   // TODO: Where is this used? Should we use parameters for this query instead of sql()?
   if(where_clause_to_key_field)
-    found_set.m_where_clause = "\"" + where_clause_to_table_name + "\".\"" + relationship->get_to_field() + "\" = " + where_clause_to_key_field->sql(foreign_key_value);
+  {
+    found_set.m_where_clause =
+      Utils::build_simple_where_expression(where_clause_to_table_name, where_clause_to_key_field, foreign_key_value);
+  }
 }
 
 bool Base_DB::add_user(const Glib::ustring& user, const Glib::ustring& password, const Glib::ustring& group)
diff --git a/glom/base_db.h b/glom/base_db.h
index 571522c..5292297 100644
--- a/glom/base_db.h
+++ b/glom/base_db.h
@@ -93,7 +93,7 @@ public:
   static bool query_execute(const Glib::RefPtr<const Gnome::Gda::SqlBuilder>& builder,
                             const Glib::RefPtr<const Gnome::Gda::Set>& params = Glib::RefPtr<const Gnome::Gda::Set>(0));
 
-  static int count_rows_returned_by(const Glib::ustring& sql_query);
+  static int count_rows_returned_by(const Glib::RefPtr<Gnome::Gda::SqlBuilder>& sql_query);
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   sharedptr<Field> change_column(const Glib::ustring& table_name, const sharedptr<const Field>& field_old, const sharedptr<const Field>& field, Gtk::Window* parent_window) const;
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index c139ec3..2258aa6 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -519,10 +519,10 @@ void Base_DB_Table_Data::refresh_related_fields(const LayoutFieldInRecord& field
 
   if(!fieldsToGet.empty())
   {
-    const Glib::ustring query = Utils::build_sql_select_with_key(field_in_record_changed.m_table_name, fieldsToGet, field_in_record_changed.m_key, field_in_record_changed.m_key_value);
+    Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_key(field_in_record_changed.m_table_name, fieldsToGet, field_in_record_changed.m_key, field_in_record_changed.m_key_value);
     //std::cout << "DEBUG: Base_DB_Table_Data::refresh_related_fields(): query=" << query << std::endl;
 
-    Glib::RefPtr<Gnome::Gda::DataModel> result = query_execute_select(query);
+    Glib::RefPtr<const Gnome::Gda::DataModel> result = query_execute_select(query);
     if(!result)
     {
       std::cerr << "Base_DB_Table_Data::refresh_related_fields(): no result." << std::endl;
diff --git a/glom/frame_glom.cc b/glom/frame_glom.cc
index 47077d4..4832d6b 100644
--- a/glom/frame_glom.cc
+++ b/glom/frame_glom.cc
@@ -471,7 +471,7 @@ void Frame_Glom::show_table_allow_empty(const Glib::ustring& table_name, const G
           layout_item_temp->set_full_field_details(field_primary_key);
           type_vecLayoutFields layout_fields;
           layout_fields.push_back(layout_item_temp);
-          const Glib::ustring sql_query_without_sort = Utils::build_sql_select_with_where_clause(found_set.m_table_name, layout_fields, found_set.m_where_clause, found_set.m_extra_join, type_sort_clause(), found_set.m_extra_group_by);
+          Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query_without_sort = Utils::build_sql_select_with_where_clause(found_set.m_table_name, layout_fields, found_set.m_where_clause, found_set.m_extra_join, type_sort_clause(), found_set.m_extra_group_by);
           const int count = Base_DB::count_rows_returned_by(sql_query_without_sort);
           if(count < 10000) //Arbitrary large number.
             found_set.m_sort_clause.push_back( type_pair_sort_field(layout_item_sort, true /* ascending */) );
@@ -687,7 +687,7 @@ void Frame_Glom::export_data_to_vector(Document::type_example_rows& the_vector,
     return;
   }
 
-  const Glib::ustring query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
 
   //TODO: Lock the database (prevent changes) during export.
   Glib::RefPtr<Gnome::Gda::DataModel> result = query_execute_select(query);
@@ -737,10 +737,10 @@ void Frame_Glom::export_data_to_string(Glib::ustring& the_string, const FoundSet
     return;
   }
 
-  const Glib::ustring query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
 
   //TODO: Lock the database (prevent changes) during export.
-  Glib::RefPtr<Gnome::Gda::DataModel> result = query_execute_select(query);
+  Glib::RefPtr<const Gnome::Gda::DataModel> result = query_execute_select(query);
 
   guint rows_count = 0;
   if(result)
@@ -789,10 +789,10 @@ void Frame_Glom::export_data_to_stream(std::ostream& the_stream, const FoundSet&
     return;
   }
 
-  const Glib::ustring query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
 
   //TODO: Lock the database (prevent changes) during export.
-  Glib::RefPtr<Gnome::Gda::DataModel> result = query_execute_select(query);
+  Glib::RefPtr<const Gnome::Gda::DataModel> result = query_execute_select(query);
 
   guint rows_count = 0;
   if(result)
@@ -1460,13 +1460,13 @@ void Frame_Glom::on_button_quickfind()
   }
   else
   {
-    const Glib::ustring where_clause = Utils::get_find_where_clause_quick(get_document(), m_table_name, Gnome::Gda::Value(criteria));
+    const Gnome::Gda::SqlExpr where_clause = Utils::get_find_where_clause_quick(get_document(), m_table_name, Gnome::Gda::Value(criteria));
     //std::cout << "Frame_Glom::on_button_quickfind(): where_clause=" << where_clause << std::endl;
     on_notebook_find_criteria(where_clause);
   }
 }
 
-void Frame_Glom::on_notebook_find_criteria(const Glib::ustring& where_clause)
+void Frame_Glom::on_notebook_find_criteria(const Gnome::Gda::SqlExpr& where_clause)
 {
   //std::cout << "Frame_Glom::on_notebook_find_criteria(): " << where_clause << std::endl;
   //on_menu_Mode_Data();
@@ -2455,14 +2455,14 @@ bool Frame_Glom::create_database(const Glib::ustring& database_name, const Glib:
 
   Gtk::Window* pWindowApp = get_app_window();
   g_assert(pWindowApp);
-      
+
   {
     BusyCursor busycursor(*pWindowApp);
 
     sigc::slot<void> onProgress; //TODO: Show visual feedback.
     result = DbUtils::create_database(get_document(), database_name, title, onProgress);
   }
-  
+
   if(!result)
   {
     //Tell the user:
diff --git a/glom/frame_glom.h b/glom/frame_glom.h
index 94fec74..8847060 100644
--- a/glom/frame_glom.h
+++ b/glom/frame_glom.h
@@ -230,7 +230,7 @@ protected:
   void alert_no_table();
 
   //Signal handlers:
-  void on_notebook_find_criteria(const Glib::ustring& where_clause);
+  void on_notebook_find_criteria(const Gnome::Gda::SqlExpr& where_clause);
   void on_button_quickfind();
   void on_button_find_all();
   void on_notebook_data_switch_page(GtkNotebookPage* page, guint page_num);
diff --git a/glom/libglom/data_structure/foundset.cc b/glom/libglom/data_structure/foundset.cc
index b724a17..7b4ac89 100644
--- a/glom/libglom/data_structure/foundset.cc
+++ b/glom/libglom/data_structure/foundset.cc
@@ -51,7 +51,7 @@ bool FoundSet::operator==(const FoundSet& src) const
 {
   return (m_table_name == src.m_table_name)
       && (m_extra_join == src.m_extra_join)
-      && (m_where_clause == src.m_where_clause)
+      /* TODO: && (m_where_clause == src.m_where_clause) */
       && (m_extra_group_by == src.m_extra_group_by)
       && (m_sort_clause == src.m_sort_clause);
 }
@@ -63,5 +63,3 @@ bool FoundSet::has_no_criteria() const
 }
 
 } //namespace Glom
-
-
diff --git a/glom/libglom/data_structure/foundset.h b/glom/libglom/data_structure/foundset.h
index 2bf996f..af26856 100644
--- a/glom/libglom/data_structure/foundset.h
+++ b/glom/libglom/data_structure/foundset.h
@@ -49,7 +49,7 @@ public:
 
   Glib::ustring m_table_name;
   Glib::ustring m_extra_join; // Only used for doubly-related related records (portals), in which case the WHERE clause is also slightly different.
-  Glib::ustring m_where_clause;
+  Gnome::Gda::SqlExpr m_where_clause;
   Glib::ustring m_extra_group_by;  // Only used for doubly-related related records (portals), in which case the WHERE clause is also slightly different.
 
   ///field, ascending
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index d2787a7..c10c26b 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -195,7 +195,7 @@ Glib::ustring Utils::string_replace(const Glib::ustring& src, const Glib::ustrin
 }
 
 
-Glib::ustring Utils::build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecLayoutFields& fieldsToGet, const Glib::ustring& where_clause, const Glib::ustring& extra_join, const type_sort_clause& sort_clause, const Glib::ustring& extra_group_by, guint limit)
+Glib::RefPtr<Gnome::Gda::SqlBuilder> Utils::build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecLayoutFields& fieldsToGet, const Gnome::Gda::SqlExpr& where_clause, const Glib::ustring& extra_join, const type_sort_clause& sort_clause, const Glib::ustring& extra_group_by, guint limit)
 {
   //TODO_Performance:
   type_vecConstLayoutFields constFieldsToGet;
@@ -331,18 +331,21 @@ Glib::ustring Utils::build_sql_select_fields_to_get(const Glib::ustring& table_n
 }
 
 
-Glib::ustring Utils::build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecConstLayoutFields& fieldsToGet, const Glib::ustring& where_clause, const Glib::ustring& extra_join, const type_sort_clause& sort_clause, const Glib::ustring& extra_group_by, guint limit)
+Glib::RefPtr<Gnome::Gda::SqlBuilder> Utils::build_sql_select_with_where_clause(const Glib::ustring& table_name, const type_vecConstLayoutFields& fieldsToGet, const Gnome::Gda::SqlExpr& where_clause, const Glib::ustring& extra_join, const type_sort_clause& sort_clause, const Glib::ustring& extra_group_by, guint limit)
 {
-  //Get the list of fields to SELECT, plus the tables that they are selected FROM.
+
+  //Build the whole SQL statement:
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  builder->select_add_target(table_name);
+
+  //Get the fields to SELECT, plus the tables that they are selected FROM.
   Glib::ustring sql_part_from;
   Glib::ustring sql_part_leftouterjoin;
-  const Glib::ustring sql_part_fields = Utils::build_sql_select_fields_to_get(
-    table_name, fieldsToGet, sort_clause, sql_part_from, sql_part_leftouterjoin);
+  //TODO: sql_sort_clause_ids;
 
-  //Build the whole SQL statement:
-  Glib::ustring result =
-    "SELECT " + sql_part_fields +
-    " FROM \"" + table_name + '\"';
+/* TODO:
+  Utils::build_sql_select_add_fields_to_get(builder, table_name, fieldsToGet, sort_clause, sql_part_from, sql_part_leftouterjoin);
+  //builder->select_add_field(primary_key->get_name(), table_name);
 
   if(!sql_part_from.empty())
     result += (',' + sql_part_from);
@@ -356,7 +359,10 @@ Glib::ustring Utils::build_sql_select_with_where_clause(const Glib::ustring& tab
 
   //Add the WHERE clause:
   if(!where_clause.empty())
-    result += " WHERE " + where_clause;
+  {
+    const int id = builder->import_expression(where_clause);
+    builder->set_where(id);
+  }
 
   //Extra GROUP_BY clause for doubly-related records. This must be before the ORDER BY sort clause:
   if(!extra_group_by.empty())
@@ -393,12 +399,12 @@ Glib::ustring Utils::build_sql_select_with_where_clause(const Glib::ustring& tab
     sprintf(pchLimit, "%d", limit);
     result += " LIMIT " + Glib::ustring(pchLimit);
   }
-
-  return result;
+*/
+  return builder;
 }
 
 
-Glib::ustring Utils::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, guint limit)
+Glib::RefPtr<Gnome::Gda::SqlBuilder> Utils::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, guint limit)
 {
   //TODO_Performance:
   type_vecConstLayoutFields constFieldsToGet;
@@ -410,17 +416,40 @@ Glib::ustring Utils::build_sql_select_with_key(const Glib::ustring& table_name,
   return build_sql_select_with_key(table_name, constFieldsToGet, key_field, key_value, limit);
 }
 
-Glib::ustring Utils::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, guint limit)
+Gnome::Gda::SqlExpr Utils::build_simple_where_expression(const Glib::ustring& table_name, const sharedptr<const Field>& key_field, const Gnome::Gda::Value& key_value)
+{
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  builder->select_add_target(table_name);  //This might not be necessary.
+  const guint id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
+    builder->add_id(key_field->get_name()),
+    builder->add_expr(key_value));
+  builder->set_where(id); //This might not be necessary.
+
+  return builder->export_expression(id);
+}
+
+Gnome::Gda::SqlExpr Utils::build_combined_where_expression(const Gnome::Gda::SqlExpr& a, const Gnome::Gda::SqlExpr& b, Gnome::Gda::SqlOperatorType op)
+{
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+
+  const guint id = builder->add_cond(op,
+    builder->import_expression(a),
+    builder->import_expression(b));
+   builder->set_where(id);
+  return builder->export_expression(id);
+}
+
+Glib::RefPtr<Gnome::Gda::SqlBuilder> Utils::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, guint limit)
 {
   if(!Conversions::value_is_empty(key_value)) //If there is a record to show:
   {
-    //TODO: Use a SQL parameter instead of using sql():
-    const Glib::ustring where_clause = '\"' + table_name + "\".\"" + key_field->get_name() + "\" = " + key_field->sql(key_value);
+    const Gnome::Gda::SqlExpr where_clause = build_simple_where_expression(table_name, key_field, key_value);
     return Utils::build_sql_select_with_where_clause(table_name, fieldsToGet, where_clause,
       Glib::ustring(), type_sort_clause(),  Glib::ustring(), limit);
   }
 
-  return Glib::ustring();
+  return Glib::RefPtr<Gnome::Gda::SqlBuilder>();
 }
 
 Utils::type_list_values_with_second Utils::get_choice_values(const sharedptr<const LayoutItem_Field>& field)
@@ -948,46 +977,62 @@ std::string Utils::sqlbuilder_get_full_query(
   return std::string(buf.get());
 }
 
-Glib::ustring Utils::get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search)
+Gnome::Gda::SqlExpr Utils::get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search)
 {
-  Glib::ustring strClause;
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  builder->select_add_target(table_name);
 
-  if(document)
+  if(!document)
   {
-    //TODO: Cache the list of all fields, as well as caching (m_Fields) the list of all visible fields:
-    const Document::type_vec_fields fields = document->get_table_fields(table_name);
+    std::cerr << "Utils::get_find_where_clause_quick(): document was null." << std::endl;
+    return Gnome::Gda::SqlExpr();
+  }
 
-    typedef std::vector< sharedptr<LayoutItem_Field> > type_vecLayoutFields;
-    type_vecLayoutFields fieldsToGet;
-    for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
-    {
-      Glib::ustring strClausePart;
+  //TODO: Cache the list of all fields, as well as caching (m_Fields) the list of all visible fields:
+  const Document::type_vec_fields fields = document->get_table_fields(table_name);
 
-      sharedptr<const Field> field = *iter;
+  guint previous_and_id = 0;
+  typedef std::vector< sharedptr<LayoutItem_Field> > type_vecLayoutFields;
+  type_vecLayoutFields fieldsToGet;
+  for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+  {
+    Glib::ustring strClausePart;
 
-      bool use_this_field = true;
-      if(field->get_glom_type() != Field::TYPE_TEXT)
-      {
-          use_this_field = false;
-      }
+    sharedptr<const Field> field = *iter;
 
-      if(use_this_field)
-      {
-        //TODO: Use a SQL parameter instead of using sql().
-        strClausePart = "\"" + table_name + "\".\"" + field->get_name() + "\" " + field->sql_find_operator() + " " +  field->sql_find(quick_search);
-      }
+    bool use_this_field = true;
+    if(field->get_glom_type() != Field::TYPE_TEXT)
+    {
+      use_this_field = false;
+    }
 
-      if(!strClausePart.empty())
-      {
-        if(!strClause.empty())
-          strClause += " OR ";
+    if(use_this_field)
+    {
+      const guint eq_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ, //TODO: Ue field->sql_find_operator().
+        builder->add_id(field->get_name()),
+        builder->add_expr(quick_search)); //Use  field->sql_find(quick_search);
 
-        strClause += strClausePart;
+      guint and_id = 0;
+      if(previous_and_id)
+      {
+        and_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND,
+        previous_and_id, eq_id);
       }
+
+      previous_and_id = and_id;
     }
   }
 
-  return strClause;
+  if(previous_and_id)
+  {
+    builder->set_where(previous_and_id); //This might be unnecessary.
+    return builder->export_expression(previous_and_id);
+  }
+  else
+  {
+    return Gnome::Gda::SqlExpr();
+  }
 }
 
 } //namespace Glom
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index a792647..41d97d1 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -26,6 +26,7 @@
 #include <libglom/document/document.h>
 
 #include <libglom/data_structure/layout/layoutitem_field.h>
+#include <libgdamm/sqlexpr.h>
 
 namespace Glom
 {
@@ -47,6 +48,12 @@ typedef std::vector< sharedptr<const LayoutItem_Field> > type_vecConstLayoutFiel
 
 //TODO: Move these to their own file:
 
+// Create a Gnome::Gda::SqlExpr.
+Gnome::Gda::SqlExpr build_simple_where_expression(const Glib::ustring& table_name, const sharedptr<const Field>& key_field, const Gnome::Gda::Value& key_value);
+
+// Create a where clause that is two other conditions combined together.
+Gnome::Gda::SqlExpr build_combined_where_expression(const Gnome::Gda::SqlExpr& a, const Gnome::Gda::SqlExpr& b, Gnome::Gda::SqlOperatorType op);
+
 /** Generate a SQL statement to SELECT field values,
  * even if the fields are in related (or doubly related) records.
  */
@@ -61,10 +68,10 @@ Glib::ustring build_sql_select_fields_to_get(
  * 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(
+Glib::RefPtr<Gnome::Gda::SqlBuilder> build_sql_select_with_where_clause(
   const Glib::ustring& table_name,
   const type_vecLayoutFields& fieldsToGet,
-  const Glib::ustring& where_clause = Glib::ustring(),
+  const Gnome::Gda::SqlExpr& where_clause = Gnome::Gda::SqlExpr(),
   const Glib::ustring& extra_join = Glib::ustring(),
   const type_sort_clause& sort_clause = type_sort_clause(),
   const Glib::ustring& extra_group_by = Glib::ustring(),
@@ -72,16 +79,16 @@ Glib::ustring build_sql_select_with_where_clause(
 
 /** 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(
+Glib::RefPtr<Gnome::Gda::SqlBuilder> build_sql_select_with_where_clause(
   const Glib::ustring& table_name,
   const type_vecConstLayoutFields& fieldsToGet,
-  const Glib::ustring& where_clause = Glib::ustring(),
+  const Gnome::Gda::SqlExpr& where_clause = Gnome::Gda::SqlExpr(),
   const Glib::ustring& extra_join = Glib::ustring(),
   const type_sort_clause& sort_clause = type_sort_clause(),
   const Glib::ustring& extra_group_by = Glib::ustring(),
   guint limit = 0);
 
-Glib::ustring build_sql_select_with_key(
+Glib::RefPtr<Gnome::Gda::SqlBuilder> build_sql_select_with_key(
   const Glib::ustring& table_name,
   const type_vecLayoutFields& fieldsToGet,
   const sharedptr<const Field>& key_field,
@@ -90,14 +97,14 @@ Glib::ustring build_sql_select_with_key(
 
 /** Just a version of build_sql_select_with_key() that takes a list of const fields.
  */
-Glib::ustring build_sql_select_with_key(
+Glib::RefPtr<Gnome::Gda::SqlBuilder> 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,
   guint limit = 0);
 
-Glib::ustring get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search);
+Gnome::Gda::SqlExpr get_find_where_clause_quick(Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search);
 
 
 typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index 153a26c..acd0063 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -85,15 +85,16 @@ FoundSet Box_Data::get_found_set() const
   return m_found_set;
 }
 
-Glib::ustring Box_Data::get_find_where_clause() const
+Gnome::Gda::SqlExpr Box_Data::get_find_where_clause() const
 {
-  Glib::ustring strClause;
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+    Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+  builder->select_add_target(m_table_name);  //This might not be necessary.
+  guint where_cond_id = 0;
 
   //Look at each field entry and build e.g. 'Name = "Bob"'
   for(type_vecLayoutFields::const_iterator iter = m_FieldsShown.begin(); iter != m_FieldsShown.end(); ++iter)
   {
-    Glib::ustring strClausePart;
-
     const Gnome::Gda::Value data = get_entered_field_data(*iter);
 
     if(!Conversions::value_is_empty(data))
@@ -110,22 +111,31 @@ Glib::ustring Box_Data::get_find_where_clause() const
 
         if(use_this_field)
         {
-          //TODO: Use a SQL parameter instead of using sql_find().
-          strClausePart = "\"" + m_table_name + "\".\"" + field->get_name() + "\" " + field->sql_find_operator() + " " +  field->sql_find(data); //% is mysql wildcard for 0 or more characters.
+          const guint cond_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ, //TODO: Use field->sql_find_operator()
+            builder->add_id(field->get_name()), //TODO: Specify m_table_name too?
+            builder->add_expr(data));
+
+          //And with previous condition, if any:
+          if(where_cond_id)
+          {
+            where_cond_id = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_AND, //TODO: Use field->sql_find_operator()
+              where_cond_id,
+              cond_id);
+          }
+          else
+            where_cond_id = cond_id;
         }
       }
     }
-
-    if(!strClausePart.empty())
-    {
-      if(!strClause.empty())
-        strClause += "AND ";
-
-      strClause += '(' + strClausePart + ") ";
-    }
   }
 
-  return strClause;
+  if(where_cond_id)
+  {
+    builder->set_where(where_cond_id); //This might not be necessary.
+    return builder->export_expression(where_cond_id);
+  }
+  else
+    return Gnome::Gda::SqlExpr();
 }
 
 void Box_Data::on_Button_Find()
@@ -133,10 +143,10 @@ void Box_Data::on_Button_Find()
   //Make sure that the cell is updated:
   //m_AddDel.finish_editing();
 
-  const Glib::ustring where_clause = get_find_where_clause();
+  const Gnome::Gda::SqlExpr where_clause = get_find_where_clause();
   if(where_clause.empty())
   {
-    Glib::ustring message = _("You have not entered any find criteria. Try entering information in the fields.");
+    const Glib::ustring message = _("You have not entered any find criteria. Try entering information in the fields.");
 
 #ifdef GLOM_ENABLE_MAEMO
     Hildon::Note dialog(Hildon::NOTE_TYPE_INFORMATION, *get_app_window(), message);
diff --git a/glom/mode_data/box_data.h b/glom/mode_data/box_data.h
index 6168929..67a601f 100644
--- a/glom/mode_data/box_data.h
+++ b/glom/mode_data/box_data.h
@@ -58,7 +58,7 @@ public:
   ///Get the existing where clause, previously supplied to init_db_details().
   FoundSet get_found_set() const;
 
-  virtual Glib::ustring get_find_where_clause() const;
+  virtual Gnome::Gda::SqlExpr get_find_where_clause() const;
 
   virtual void set_unstored_data(bool bVal);
   virtual bool get_unstored_data() const;
@@ -80,7 +80,7 @@ public:
    */
   //Should be a MI class, derived by those sub-classes. TODO.
   //where_clause.
-  sigc::signal<void, Glib::ustring> signal_find_criteria;
+  sigc::signal<void, Gnome::Gda::SqlExpr> signal_find_criteria;
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   //g++ 3.4 needs this to be public when used from Box_Data_Details. I'm not sure why. murrayc.
diff --git a/glom/mode_data/box_data_calendar_related.cc b/glom/mode_data/box_data_calendar_related.cc
index 7387f42..666a413 100644
--- a/glom/mode_data/box_data_calendar_related.cc
+++ b/glom/mode_data/box_data_calendar_related.cc
@@ -38,16 +38,16 @@ Box_Data_Calendar_Related::Box_Data_Calendar_Related()
 
   m_Alignment.add(m_calendar);
   m_calendar.show();
-  
+
   //m_calendar.set_show_details();
   m_calendar.set_detail_width_chars(7);
-  m_calendar.set_detail_height_rows(2); 
-  
+  m_calendar.set_detail_height_rows(2);
+
   //Tell the calendar how to get the record details to show:
   m_calendar.set_detail_func( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_details) );
-  
+
   m_calendar.signal_month_changed().connect( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_month_changed) );
-  
+
   setup_menu();
   //m_calendar.add_events(Gdk::BUTTON_PRESS_MASK); //Allow us to catch button_press_event and button_release_event
   m_calendar.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_button_press_event) );
@@ -79,7 +79,7 @@ bool Box_Data_Calendar_Related::init_db_details(const Glib::ustring& parent_tabl
   m_parent_table = parent_table;
 
   if(m_portal)
-    LayoutWidgetBase::m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table_name, not used. */); 
+    LayoutWidgetBase::m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table_name, not used. */);
   else
     LayoutWidgetBase::m_table_name = Glib::ustring();
 
@@ -126,7 +126,7 @@ bool Box_Data_Calendar_Related::fill_from_database()
 {
   if(!m_portal)
     return false;
-  
+
   bool result = false;
 
   if(m_key_field && m_found_set.m_where_clause.empty()) //There's a key field, but no value.
@@ -141,24 +141,24 @@ bool Box_Data_Calendar_Related::fill_from_database()
   {
     if(m_query_column_date_field == -1)
       return false; //This is useless without the date in the result.
-       
+
     //Create a date range from the beginning to end of the selected month:
     Glib::Date calendar_date;
     m_calendar.get_date(calendar_date);
     const Glib::Date date_start(1, calendar_date.get_month(), calendar_date.get_year());
     Glib::Date date_end = date_start;
     date_end.add_months(1);
-    
+
     Gnome::Gda::Value date_start_value(date_start);
     Gnome::Gda::Value date_end_value(date_end);
 
     //Add a WHERE clause for this date range:
     sharedptr<Relationship> relationship = m_portal->get_relationship();
     Glib::ustring where_clause_to_table_name = relationship->get_to_table();
-  
+
     sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
     const Glib::ustring date_field_name = derived_portal->get_date_field()->get_name();
-    
+
     sharedptr<const Relationship> relationship_related = m_portal->get_related_relationship();
     if(relationship_related)
     {
@@ -171,65 +171,76 @@ bool Box_Data_Calendar_Related::fill_from_database()
     //Add an AND to the existing where clause, to get only records within these dates, if any:
     sharedptr<const Field> date_field = derived_portal->get_date_field();
     //TODO: Use a SQL parameter instead of using sql().
-    const Glib::ustring extra_where_clause = "\"" + where_clause_to_table_name + "\".\"" + date_field->get_name() + "\""
-      " BETWEEN DATE " + date_field->sql(date_start_value) + 
-      " AND DATE " + date_field->sql(date_end_value);
-    
-    Glib::ustring where_clause;
+
+    Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+      Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+    const guint cond = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_BETWEEN,
+       builder->add_id(date_field->get_name()),
+       builder->add_expr_as_value(date_start_value),
+       builder->add_expr_as_value(date_end_value));
+    builder->set_where(cond); //Might be unnecessary.
+    const Gnome::Gda::SqlExpr extra_where_clause = builder->export_expression(cond);
+
+    Gnome::Gda::SqlExpr where_clause;
     if(m_found_set.m_where_clause.empty())
+    {
       where_clause = extra_where_clause;
+    }
     else
-      where_clause = "( " + m_found_set.m_where_clause + " ) AND ( " + extra_where_clause + " )";
-    
-    
+    {
+      where_clause = Utils::build_combined_where_expression(
+        m_found_set.m_where_clause, extra_where_clause,
+        Gnome::Gda::SQL_OPERATOR_TYPE_AND);
+    }
+
     //Do one SQL query for the whole month and store the cached values here:
     clear_cached_database_values();
-    
-    const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_FieldsShown, where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
+
+    Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_FieldsShown, where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
     //std::cout << "DEBUG: sql_query=" << sql_query << std::endl;
-    Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
+    Glib::RefPtr<const Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
     if(!(datamodel))
       return true;
-    
+
     const int rows_count = datamodel->get_n_rows();
     if(!(rows_count > 0))
       return true;
-    
+
     //Get the data:
     for(int row_index = 0; row_index < rows_count; ++row_index)
     {
       const int columns_count = datamodel->get_n_columns();
       if(m_query_column_date_field > columns_count)
        continue;
-       
+
       //Get the date value for this row:
-#ifdef GLIBMM_EXCEPTIONS_ENABLED      
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
       Gnome::Gda::Value value_date = datamodel->get_value_at(m_query_column_date_field, row_index);
 #else
-      std::auto_ptr<Glib::Error> error;      
+      std::auto_ptr<Glib::Error> error;
       Gnome::Gda::Value value_date = datamodel->get_value_at(m_query_column_date_field, row_index, error);
-#endif      
+#endif
       const Glib::Date date = value_date.get_date();
-      
+
       //Get all the values for this row:
       type_vector_values* pVector = new type_vector_values(m_FieldsShown.size());
       for(int column_index = 0; column_index < columns_count; ++column_index)
       {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED 
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
         (*pVector)[column_index] = datamodel->get_value_at(column_index, row_index);
 #else
-        std::auto_ptr<Glib::Error> error;      
+        std::auto_ptr<Glib::Error> error;
           (*pVector)[column_index] = datamodel->get_value_at(column_index, row_index, error);
         if (error.get())
           break;
-#endif 
+#endif
       }
-      
+
       m_map_values[date].push_back(pVector);
     }
   }
 
- 
+
   return result;
 }
 
@@ -245,8 +256,8 @@ void Box_Data_Calendar_Related::clear_cached_database_values()
         delete pValues;
     }
   }
-  
-  m_map_values.clear(); 
+
+  m_map_values.clear();
 }
 
 //TODO: Make this generic in Box_Data_Portal:
@@ -286,7 +297,7 @@ void Box_Data_Calendar_Related::on_record_added(const Gnome::Gda::Value& primary
 
     //Create the link by setting the foreign key
     if(m_key_field && m_portal)
-    {      
+    {
       Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
       builder->set_table(m_portal->get_table_used(Glib::ustring() /* not relevant */));
       builder->add_field_value_as_value(m_key_field->get_name(), m_key_value);
@@ -294,7 +305,7 @@ void Box_Data_Calendar_Related::on_record_added(const Gnome::Gda::Value& primary
         builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
           builder->add_id(field_primary_key->get_name()),
           builder->add_expr_as_value(primary_key_value)));
-      
+
       const bool test = query_execute(builder);
       if(test)
       {
@@ -313,15 +324,15 @@ void Box_Data_Calendar_Related::on_record_added(const Gnome::Gda::Value& primary
 Box_Data_Calendar_Related::type_vecLayoutFields Box_Data_Calendar_Related::get_fields_to_show() const
 {
   type_vecLayoutFields layout_fields = Box_Data_Portal::get_fields_to_show();
-  
+
   sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
   if(!derived_portal)
     return layout_fields;
-  
+
   sharedptr<const Field> date_field = derived_portal->get_date_field();
   if(!date_field)
     return layout_fields;
-  
+
   //Add it to the list to ensure that we request the date (though it will not really be shown in the calendar):
   sharedptr<LayoutItem_Field> layout_item_date_field = sharedptr<LayoutItem_Field>::create();
   layout_item_date_field->set_full_field_details(date_field);
@@ -340,7 +351,7 @@ void Box_Data_Calendar_Related::on_dialog_layout_hide()
 
   //Update the UI:
   sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
-  init_db_details(derived_portal); 
+  init_db_details(derived_portal);
 
   Box_Data::on_dialog_layout_hide();
 
@@ -350,7 +361,7 @@ void Box_Data_Calendar_Related::on_dialog_layout_hide()
     sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
     if(derived_portal)
       *pLayoutItem = *derived_portal;
-    
+
     signal_layout_changed().emit(); //TODO: Check whether it has really changed.
   }
 }
@@ -368,7 +379,7 @@ void Box_Data_Calendar_Related::prepare_layout_dialog(Dialog_Layout* dialog)
 {
   Dialog_Layout_Calendar_Related* related_dialog = dynamic_cast<Dialog_Layout_Calendar_Related*>(dialog);
   g_assert(related_dialog);
-  
+
   sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
   if(derived_portal && derived_portal->get_has_relationship_name())
   {
@@ -395,11 +406,11 @@ Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint m
     //std::cout << "DEBUG: Box_Data_Calendar_Related::on_calendar_details(): date_field is NULL" << std::endl;
     return Glib::ustring();
   }
-  
+
   sharedptr<const Field> date_field = derived_portal->get_date_field();
   if(!date_field)
     return Glib::ustring();
-  
+
   //TODO: month seems to be 143710360 sometimes, which seems to be a GtkCalendar bug:
   //std::cout << "Box_Data_Calendar_Related::on_calendar_details(): year=" << year << ", month=" << month << " day=" << day << std::endl;
 
@@ -408,15 +419,15 @@ Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint m
   if(datemonth > Glib::Date::DECEMBER)
     datemonth = Glib::Date::JANUARY;
   Glib::Date date(day, datemonth, year);
-  
+
   //Examine the cached data:
   type_map_values::const_iterator iter_find = m_map_values.find(date);
   if(iter_find == m_map_values.end())
     return Glib::ustring(); //No data was found for this date.
-  
-  
+
+
   Glib::ustring result;
-  
+
   //Look at each row for this date:
   const type_list_vectors& rows = iter_find->second;
   for(type_list_vectors::const_iterator iter = rows.begin(); iter != rows.end(); ++iter)
@@ -424,23 +435,23 @@ Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint m
     type_vector_values* pRow = *iter;
     if(!pRow)
       continue;
-    
+
     //Get the data for each column in the row:
     Glib::ustring row_text;
     int column_index = 0;
-    
+
     //We iterate over the original list of items from the portal,
     //instead of the ones used by the query (m_FieldsShown),
     //because we really don't want to show the extra fields (at the end) to the user:
     LayoutGroup::type_list_items items = m_portal->get_items();
     for(LayoutGroup::type_list_items::const_iterator iter = items.begin(); iter != items.end(); ++iter)
-    {   
+    {
       sharedptr<const LayoutItem> layout_item = *iter;
       if(!layout_item)
         continue;
-            
+
       Glib::ustring text;
-      
+
       //Text for a text item:
       sharedptr<const LayoutItem_Text> layout_item_text = sharedptr<const LayoutItem_Text>::cast_dynamic(layout_item);
       if(layout_item_text)
@@ -449,33 +460,33 @@ Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint m
       {
         //Text for a field:
         sharedptr<const LayoutItem_Field> layout_item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(layout_item);
-        
+
         const Gnome::Gda::Value value = (*pRow)[column_index];
         text = Conversions::get_text_for_gda_value(layout_item_field->get_glom_type(), value, layout_item_field->get_formatting_used().m_numeric_format);
-        
+
         ++column_index;
       }
-      
+
       //Add the field text to the row:
       if(!text.empty())
       {
         if(!row_text.empty())
           row_text += ", "; //TODO: Internationalization?
-      
+
         row_text += text;
       }
     }
-    
+
     //Add the row text to the result:
     if(!row_text.empty())
     {
       if(!result.empty())
         result += '\n';
-      
+
       result += row_text;
     }
   }
-  
+
   return result;
 }
 
@@ -502,7 +513,7 @@ void Box_Data_Calendar_Related::setup_menu()
   if(pApp)
   {
     pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
-    pApp->update_userlevel_ui(); //Update our action's sensitivity. 
+    pApp->update_userlevel_ui(); //Update our action's sensitivity.
   }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
@@ -516,7 +527,7 @@ void Box_Data_Calendar_Related::setup_menu()
   try
   {
 #endif
-    Glib::ustring ui_info = 
+    Glib::ustring ui_info =
         "<ui>"
         "  <popup name='ContextMenu'>"
         "    <menuitem action='ContextEdit'/>"
@@ -543,11 +554,11 @@ void Box_Data_Calendar_Related::setup_menu()
 #endif //GLIBMM_EXCEPTIONS_ENABLED
 
   //Get the menu:
-  m_pMenuPopup = dynamic_cast<Gtk::Menu*>( m_refUIManager->get_widget("/ContextMenu") ); 
+  m_pMenuPopup = dynamic_cast<Gtk::Menu*>( m_refUIManager->get_widget("/ContextMenu") );
   if(!m_pMenuPopup)
     g_warning("menu not found");
 
- 
+
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   if(pApp)
     m_refContextLayout->set_sensitive(pApp->get_userlevel() == AppState::USERLEVEL_DEVELOPER);
@@ -563,7 +574,7 @@ void Box_Data_Calendar_Related::on_calendar_button_press_event(GdkEventButton *e
   if(pApp)
   {
     pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
-    pApp->update_userlevel_ui(); //Update our action's sensitivity. 
+    pApp->update_userlevel_ui(); //Update our action's sensitivity.
   }
 #endif
 
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index 3f56902..0e64ee6 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -179,9 +179,8 @@ void Box_Data_Details::set_found_set_from_primary_key_value()
 
   if(!m_primary_key_value.is_null())
   {
-    //TODO: Use a SQL parameter instead of using sql().
-    m_found_set.m_where_clause = "\"" + m_table_name + "\".\"" + m_field_primary_key->get_name() +
-      "\" = " + m_field_primary_key->sql(m_primary_key_value);
+    m_found_set.m_where_clause = Utils::build_simple_where_expression(
+       m_table_name, m_field_primary_key, m_primary_key_value);
     //std::cout << "  DEBUG: Box_Data_Details::set_primary_key_value(): m_found_set.m_where_clause = " << m_found_set.m_where_clause << std::endl;
   }
 }
@@ -356,7 +355,7 @@ bool Box_Data_Details::fill_from_database()
           }
         }
 
-        const Glib::ustring query = Utils::build_sql_select_with_key(m_table_name, fieldsToGet, m_field_primary_key, m_primary_key_value);
+        Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_key(m_table_name, fieldsToGet, m_field_primary_key, m_primary_key_value);
         Glib::RefPtr<Gnome::Gda::DataModel> result;
 
         if(!primary_key_is_empty)
diff --git a/glom/mode_data/box_data_list.cc b/glom/mode_data/box_data_list.cc
index 2922961..c781bf9 100644
--- a/glom/mode_data/box_data_list.cc
+++ b/glom/mode_data/box_data_list.cc
@@ -49,7 +49,7 @@ Box_Data_List::Box_Data_List()
   m_AddDel.signal_user_requested_edit().connect(sigc::mem_fun(*this, &Box_Data_List::on_adddel_user_requested_edit));
   m_AddDel.signal_script_button_clicked().connect(sigc::mem_fun(*this, &Box_Data_List::on_adddel_script_button_clicked));
   m_AddDel.signal_sort_clause_changed().connect(sigc::mem_fun(*this, &Box_Data_List::on_adddel_user_sort_clause_changed));
-  
+
   //TODO: Re-add this signal if this is really wanted, but make it part of a complete drag-and-drop feature for list views:
   //m_AddDel.signal_user_reordered_columns().connect(sigc::mem_fun(*this, &Box_Data_List::on_adddel_user_reordered_columns));
 
@@ -91,7 +91,7 @@ void Box_Data_List::enable_buttons()
 void Box_Data_List::refresh_data_from_database_blank()
 {
   FoundSet found_set = m_found_set;
-  found_set.m_where_clause = Glib::ustring();
+  found_set.m_where_clause = Gnome::Gda::SqlExpr();
   m_AddDel.set_found_set(found_set);
 
   std::cout << "debug: Box_Data_List::refresh_data_from_database_blank(): before refresh_from_database_blank()." << std::endl;
@@ -206,13 +206,13 @@ void Box_Data_List::on_adddel_user_reordered_columns()
     {
       sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
       layout_item->set_name(*iter);
-      group->add_item(layout_item); 
+      group->add_item(layout_item);
     }
 
     Document::type_list_layout_groups mapGroups;
     mapGroups[1] = group;
 
-    pDoc->set_data_layout_groups("list", m_table_name, m_layout_platform, mapGroups);  
+    pDoc->set_data_layout_groups("list", m_table_name, m_layout_platform, mapGroups);
   }
 }
 
@@ -220,10 +220,10 @@ void Box_Data_List::on_adddel_script_button_clicked(const sharedptr<const Layout
 {
   if(!layout_item)
     return;
-  
+
   const Gnome::Gda::Value primary_key_value = get_primary_key_value(row);
 
-  // TODO: Calling refresh_data_from_database(), 
+  // TODO: Calling refresh_data_from_database(),
   // or navigating to a different table from inside the Python script,
   // causes a crash somewhere down in GTK+, so it is done in an idle handler here.
   // We are currently in a callback from the CellRendererButton_Text cell
@@ -231,7 +231,7 @@ void Box_Data_List::on_adddel_script_button_clicked(const sharedptr<const Layout
   // Probably this causes issues somewhere.
   Glib::signal_idle().connect(
     sigc::bind(
-      sigc::mem_fun(*this, &Box_Data_List::on_script_button_idle), 
+      sigc::mem_fun(*this, &Box_Data_List::on_script_button_idle),
       layout_item,
       primary_key_value));
 }
@@ -253,7 +253,7 @@ bool Box_Data_List::on_script_button_idle(const sharedptr<const LayoutItem_Butto
 
   refresh_data_from_database();
   set_primary_key_value_selected(primary_key);
-  
+
   return false;
 }
 
@@ -308,7 +308,7 @@ void Box_Data_List::on_details_nav_last()
     m_AddDel.select_item(iter);
     signal_user_requested_details().emit(m_AddDel.get_value_key_selected());
   }
-  
+
   //No, don't do this. When would that ever be a good idea? murrayc:
   //signal_user_requested_details().emit(Gnome::Gda::Value()); //Show a blank record if there are no records.
 }
@@ -449,7 +449,7 @@ Document::type_list_layout_groups Box_Data_List::create_layout_get_layout()
 {
   //This method is overriden in Box_Data_List_Related.
 
-  return get_data_layout_groups(m_layout_name, m_layout_platform); 
+  return get_data_layout_groups(m_layout_name, m_layout_platform);
 }
 
 void Box_Data_List::create_layout()
@@ -476,7 +476,7 @@ void Box_Data_List::create_layout()
       //std::cout << "DEBUG: Box_Data_List::create_layout(): primary_key=" << field_primary_key->get_name() << std::endl;
 
       m_AddDel.set_key_field(field_primary_key);
- 
+
       //This map of layout groups will also contain the field information from the database:
       Document::type_list_layout_groups layout_groups = create_layout_get_layout();
 
@@ -582,20 +582,20 @@ void Box_Data_List::get_record_counts(gulong& total, gulong& found) const
 
   Glib::RefPtr<Gtk::TreeModel> refModel = m_AddDel.get_model();
   Glib::RefPtr<DbTreeModel> refModelDerived = Glib::RefPtr<DbTreeModel>::cast_dynamic(refModel);
-  
+
   if(refModelDerived)
     refModelDerived->get_record_counts(total, found);
 }
 
 void Box_Data_List::on_adddel_user_sort_clause_changed()
 {
-  //Remember details about the previously viewed table, 
-  //so we don't forget the sort order and where clause when 
+  //Remember details about the previously viewed table,
+  //so we don't forget the sort order and where clause when
   //navigating back, which would annoy the user:
 
   m_found_set = m_AddDel.get_found_set();
 
-  Document* document = get_document(); 
+  Document* document = get_document();
   if(document)
     document->set_criteria_current(m_table_name, m_found_set);
 }
@@ -626,4 +626,3 @@ void Box_Data_List::prepare_layout_dialog(Dialog_Layout* dialog)
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
 } //namespace Glom
-
diff --git a/glom/mode_data/box_data_portal.cc b/glom/mode_data/box_data_portal.cc
index 93f28bd..294fd9f 100644
--- a/glom/mode_data/box_data_portal.cc
+++ b/glom/mode_data/box_data_portal.cc
@@ -61,11 +61,11 @@ Box_Data_Portal::Box_Data_Portal()
   add(m_Frame);
 
   m_layout_name = "list_portal"; //Replaced by derived classes.
-  
+
   #ifdef GLOM_ENABLE_MAEMO
   #ifndef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
   signal_realize().connect(sigc::mem_fun(*this, &Box_Data_Portal::on_realize));
-  signal_unrealize().connect(sigc::mem_fun(*this, &Box_Data_Portal::on_unrealize));  
+  signal_unrealize().connect(sigc::mem_fun(*this, &Box_Data_Portal::on_unrealize));
   #endif //GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
 
   m_maemo_appmenubutton_add.signal_clicked().connect(
@@ -78,7 +78,7 @@ Box_Data_Portal::~Box_Data_Portal()
   #ifdef GLOM_ENABLE_MAEMO
   if(m_window_maemo_details)
     delete m_window_maemo_details;
-    
+
   if(m_box_maemo_details)
   {
     remove_view(m_box_maemo_details);
@@ -96,17 +96,17 @@ void Box_Data_Portal::make_record_related(const Gnome::Gda::Value& related_recor
   {
     std::cerr << "Box_Data_Portal::make_record_related(): m_key_field was null." << std::endl;
   }
-  
+
   if(Conversions::value_is_empty(m_key_value))
   {
     std::cerr << "Box_Data_Portal::make_record_related(): m_key_value was empty." << std::endl;
   }
-  
-  
+
+
   if(!m_portal)
   {
     std::cerr << "Box_Data_Portal::make_record_related(): m_portal was null." << std::endl;
-  } 
+  }
 
   Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
     builder->set_table(m_portal->get_table_used(Glib::ustring() /* not relevant */));
@@ -115,7 +115,7 @@ void Box_Data_Portal::make_record_related(const Gnome::Gda::Value& related_recor
       builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
         builder->add_id(field_primary_key->get_name()),
         builder->add_expr_as_value(related_record_primary_key_value)));
-          
+
   //std::cout << "Box_Data_Portal::make_record_related(): setting value in db=" << primary_key_value.to_string() << std::endl;
   const bool test = query_execute(builder);
   if(!test)
@@ -130,57 +130,57 @@ void Box_Data_Portal::on_maemo_appmenubutton_add()
 {
   if(!m_portal)
     return;
-    
+
   if(m_window_maemo_details)
     delete m_window_maemo_details;
-    
+
   if(m_box_maemo_details)
   {
     remove_view(m_box_maemo_details);
     delete m_box_maemo_details;
   }
-  
+
   m_box_maemo_details = new Box_Data_Details();
   add_view(m_box_maemo_details);
   m_box_maemo_details->show_all();
-  
+
   m_window_maemo_details = new Window_BoxHolder(m_box_maemo_details, _("Details"));
-  
+
   //Let this window have the main AppMenu:
   Hildon::Program::get_instance()->add_window(*m_window_maemo_details);
-  
+
   Gtk::Window* pWindow = get_app_window();
   if(pWindow)
     m_window_maemo_details->set_transient_for(*pWindow);
-    
+
   //Refresh the portal when the window is closed:
   //TODO: Refresh the parent Details too.
   m_window_maemo_details->signal_hide().connect(
     sigc::mem_fun(*this, &Box_Data_Portal::on_window_maemo_details_closed));
 
-  const Glib::ustring title = 
-    Glib::ustring::compose(_("New Related %1"), 
+  const Glib::ustring title =
+    Glib::ustring::compose(_("New Related %1"),
       get_title_singular());
   m_window_maemo_details->set_title(title);
-  
+
   FoundSet found_set;
   found_set.m_table_name = m_portal->get_table_used(Glib::ustring());
   Gnome::Gda::Value related_record_primary_key_value; //null for a new record.
-  m_box_maemo_details->init_db_details(found_set, 
-    get_active_layout_platform(get_document()), 
+  m_box_maemo_details->init_db_details(found_set,
+    get_active_layout_platform(get_document()),
     related_record_primary_key_value);
-    
+
   m_box_maemo_details->do_new_record(); //Doesn't block.
-  
+
   //Make the new record related:
   //TODO: This only makes sense if the primary key is not auto-generated.
-  related_record_primary_key_value = 
+  related_record_primary_key_value =
     m_box_maemo_details->get_primary_key_value_selected();
   make_record_related(related_record_primary_key_value);
-  
+
   //Show the data in the UI:
   m_box_maemo_details->refresh_data_from_database_with_primary_key(related_record_primary_key_value);
-  
+
   m_window_maemo_details->show();
 }
 
@@ -194,13 +194,13 @@ void Box_Data_Portal::on_realize()
 {
   if(!m_portal)
     return;
-    
+
   // Add an Add Related Something button to the application's AppMenu.
   // This will be removed when the portal is hidden.
   //TODO: Use the ustring compose thingy. murrayc.
-  //TODO: Allow the designer to specify a singluar form for tables (and portals), 
+  //TODO: Allow the designer to specify a singluar form for tables (and portals),
   //so we can say Add Related Something instead of Somethings: Add Related.
-  const Glib::ustring title = 
+  const Glib::ustring title =
     Glib::ustring::compose(_("Add Related %1"), get_title_singular());
   m_maemo_appmenubutton_add.set_title(title);
   m_maemo_appmenubutton_add.set_value(_("Add related record"));
@@ -222,7 +222,7 @@ void Box_Data_Portal::on_realize()
 
 void Box_Data_Portal::on_unrealize()
 {
-  // Remove the AppMenu button when the portal is no longer shown: 
+  // Remove the AppMenu button when the portal is no longer shown:
   Application* app = Application::get_application();
   g_assert(app);
   if(app)
@@ -246,7 +246,7 @@ bool Box_Data_Portal::init_db_details(const sharedptr<const LayoutItem_Portal>&
   Glib::ustring parent_table;
   if(m_portal)
     parent_table = m_portal->get_from_table();
-      
+
   return init_db_details(parent_table, show_title);
 }
 
@@ -261,7 +261,7 @@ Glib::ustring Box_Data_Portal::get_title() const
     //Note to translators: This text is shown instead of a table title, when the table has not yet been chosen.
     relationship_title = _("Undefined Table");
   }
-  
+
   return relationship_title;
 }
 
@@ -275,7 +275,7 @@ Glib::ustring Box_Data_Portal::get_title_singular() const
     //Note to translators: This text is shown instead of a table title, when the table has not yet been chosen.
     relationship_title = _("Undefined Table");
   }
-  
+
   return relationship_title;
 }
 
@@ -285,7 +285,7 @@ bool Box_Data_Portal::init_db_details(const Glib::ustring& parent_table, bool sh
   m_parent_table = parent_table;
 
   if(m_portal)
-    LayoutWidgetBase::m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table_name, not used. */); 
+    LayoutWidgetBase::m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table_name, not used. */);
   else
     LayoutWidgetBase::m_table_name = Glib::ustring();
 
@@ -317,7 +317,7 @@ bool Box_Data_Portal::refresh_data_from_database_with_foreign_key(const Gnome::G
 {
   m_key_value = foreign_key_value;
   //std::cout << "DEBUG: Box_Data_Portal::refresh_data_from_database_with_foreign_key(): m_key_value=" << m_key_value.to_string() << std::endl;
-  
+
 
   if(m_key_field && m_portal)
   {
@@ -325,7 +325,7 @@ bool Box_Data_Portal::refresh_data_from_database_with_foreign_key(const Gnome::G
     {
       FoundSet found_set;
       set_found_set_where_clause_for_portal(found_set, m_portal, m_key_value);
-   
+
       //std::cout << "DEBUG: refresh_data_from_database_with_foreign_key(): where_clause=" << found_set.m_where_clause << std::endl;
       return Box_Data::refresh_data_from_database_with_where_clause(found_set);
     }
@@ -340,7 +340,7 @@ bool Box_Data_Portal::refresh_data_from_database_with_foreign_key(const Gnome::G
   {
     //If there is no to field then this relationship specifies all records in the table.
     FoundSet found_set = m_found_set;
-    found_set.m_where_clause = Glib::ustring();
+    found_set.m_where_clause = Gnome::Gda::SqlExpr();
     return Box_Data::refresh_data_from_database_with_where_clause(found_set);
   }
 }
@@ -485,7 +485,7 @@ void Box_Data_Portal::get_suitable_record_to_view_details(const Gnome::Gda::Valu
   Glib::ustring navigation_table_name;
   sharedptr<const UsesRelationship> navigation_relationship;
   get_suitable_table_to_view_details(navigation_table_name, navigation_relationship);
- 
+
   if(navigation_table_name.empty())
     return;
 
@@ -512,8 +512,8 @@ void Box_Data_Portal::get_suitable_record_to_view_details(const Gnome::Gda::Valu
   sharedptr<const Field> key_field = get_field_primary_key_for_table(related_table);
   //std::cout << "DEBUG: related table=" << related_table << ", whose primary_key=" << key_field->get_name() << std::endl;
 
-  const Glib::ustring query = Utils::build_sql_select_with_key(related_table, fieldsToGet, key_field, primary_key_value);
-  Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(query);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> query = Utils::build_sql_select_with_key(related_table, fieldsToGet, key_field, primary_key_value);
+  Glib::RefPtr<const Gnome::Gda::DataModel> data_model = query_execute_select(query);
 
 
   bool value_found = true;
@@ -521,12 +521,12 @@ void Box_Data_Portal::get_suitable_record_to_view_details(const Gnome::Gda::Valu
   {
     //Set the output parameters:
     table_name = navigation_table_name;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED    
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
     table_primary_key_value = data_model->get_value_at(0, 0);
 #else
-    std::auto_ptr<Glib::Error> error;    
+    std::auto_ptr<Glib::Error> error;
     table_primary_key_value = data_model->get_value_at(0, 0, error);
-#endif    
+#endif
     //std::cout << "Box_Data_Portal::get_suitable_record_to_view_details(): table_primary_key_value=" << table_primary_key_value.to_string() << std::endl;
 
     //The value is empty when there there is no record to match the key in the related table:
@@ -541,9 +541,9 @@ void Box_Data_Portal::get_suitable_record_to_view_details(const Gnome::Gda::Valu
   {
     value_found = false;
 
-    std::cout << "DEBUG: Box_Data_Portal::get_suitable_record_to_view_details(): SQL query returned no suitable primary key. table=" 
-      << related_table  
-      << ", field=" << layout_item->get_layout_display_name() 
+    std::cout << "DEBUG: Box_Data_Portal::get_suitable_record_to_view_details(): SQL query returned no suitable primary key. table="
+      << related_table
+      << ", field=" << layout_item->get_layout_display_name()
       << ", key_field=" << key_field->get_name()
       << ", primary_key_value=" << primary_key_value.to_string() << std::endl;
 
@@ -568,7 +568,7 @@ Document::type_list_layout_groups Box_Data_Portal::create_layout_get_layout()
 
   if(m_portal)
     result.push_back(m_portal);
-  
+
   return result;
 }
 
diff --git a/glom/mode_data/datawidget/dialog_choose_id.cc b/glom/mode_data/datawidget/dialog_choose_id.cc
index 2320e06..e6791f5 100644
--- a/glom/mode_data/datawidget/dialog_choose_id.cc
+++ b/glom/mode_data/datawidget/dialog_choose_id.cc
@@ -121,14 +121,14 @@ void Dialog_ChooseID::on_button_quickfind()
   }
   else
   {
-    const Glib::ustring where_clause = 
-      Utils::get_find_where_clause_quick(get_document(), m_table_name, 
+    const Gnome::Gda::SqlExpr where_clause =
+      Utils::get_find_where_clause_quick(get_document(), m_table_name,
         Gnome::Gda::Value(criteria));
     on_box_find_criteria(where_clause);
   }
 }
 
-void Dialog_ChooseID::on_box_find_criteria(const Glib::ustring& where_clause)
+void Dialog_ChooseID::on_box_find_criteria(const Gnome::Gda::SqlExpr& where_clause)
 {
   //Use the find criteria to show a list of results:
   if(!where_clause.empty())
diff --git a/glom/mode_data/datawidget/dialog_choose_id.h b/glom/mode_data/datawidget/dialog_choose_id.h
index f0ae6af..bfc4e2c 100644
--- a/glom/mode_data/datawidget/dialog_choose_id.h
+++ b/glom/mode_data/datawidget/dialog_choose_id.h
@@ -62,7 +62,7 @@ private:
   void update_ui_for_stage();
 
   void on_button_quickfind();
-  void on_box_find_criteria(const Glib::ustring& where_clause);
+  void on_box_find_criteria(const Gnome::Gda::SqlExpr& where_clause);
   void on_box_select_selected(const Gnome::Gda::Value& primary_key);
 
   Gtk::Label* m_label_table_name;
diff --git a/glom/mode_find/notebook_find.cc b/glom/mode_find/notebook_find.cc
index 605c740..96bd9c6 100644
--- a/glom/mode_find/notebook_find.cc
+++ b/glom/mode_find/notebook_find.cc
@@ -77,7 +77,7 @@ bool Notebook_Find::init_db_details(const Glib::ustring& table_name, const Glib:
   return result;
 }
 
-void Notebook_Find::on_page_find_criteria(const Glib::ustring& where_clause)
+void Notebook_Find::on_page_find_criteria(const Gnome::Gda::SqlExpr& where_clause)
 {
   //Pass it up to the application.
   signal_find_criteria.emit(where_clause);
diff --git a/glom/mode_find/notebook_find.h b/glom/mode_find/notebook_find.h
index a91d7fd..53e5cab 100644
--- a/glom/mode_find/notebook_find.h
+++ b/glom/mode_find/notebook_find.h
@@ -42,13 +42,13 @@ public:
    * should be used to find and display records.
    * @param find_criteria The SQL where clause.
    */
-  sigc::signal<void, Glib::ustring> signal_find_criteria;
+  sigc::signal<void, Gnome::Gda::SqlExpr> signal_find_criteria;
 
 private:
 
 
   //Signal handlers:
-  void on_page_find_criteria(const Glib::ustring& where_clause);
+  void on_page_find_criteria(const Gnome::Gda::SqlExpr& where_clause);
 
   //Member widgets:
   #ifndef GLOM_ENABLE_MAEMO
diff --git a/glom/print_layout/canvas_print_layout.cc b/glom/print_layout/canvas_print_layout.cc
index c90f6bc..ce24fdf 100644
--- a/glom/print_layout/canvas_print_layout.cc
+++ b/glom/print_layout/canvas_print_layout.cc
@@ -624,7 +624,7 @@ void Canvas_PrintLayout::fill_with_data(const Glib::RefPtr<Goocanvas::Group>& ca
   if(fieldsToGet.empty())
     return;
 
-  const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
     fieldsToGet,
     found_set.m_where_clause, Glib::ustring() /* extra_join */, found_set.m_sort_clause, 
     Glib::ustring(),
@@ -731,7 +731,7 @@ void Canvas_PrintLayout::fill_with_data_portal(const Glib::RefPtr<CanvasLayoutIt
   found_set.m_table_name = portal->get_table_used(Glib::ustring() /* parent table_name, not used. */);
   set_found_set_where_clause_for_portal(found_set, portal, foreign_key_value);
 
-  const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fields_shown, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fields_shown, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
   //std::cout << "DEBUG: sql_query=" << sql_query << std::endl;
   Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
   if(!(datamodel))
diff --git a/glom/report_builder.cc b/glom/report_builder.cc
index f34cec9..4a2bfcc 100644
--- a/glom/report_builder.cc
+++ b/glom/report_builder.cc
@@ -184,7 +184,7 @@ void ReportBuilder::report_build_groupby(const FoundSet& found_set_parent, xmlpp
 
     if(!found_set_parent.m_where_clause.empty())
     {
-      builder->set_where( builder->add_id(found_set_parent.m_where_clause) ); //Is this allowed?
+      builder->set_where( builder->import_expression(found_set_parent.m_where_clause) );
     }
 
     builder->select_group_by( builder->add_id(field_group_by->get_name()) ); //TODO: And restrict to the current found set.
@@ -212,9 +212,14 @@ void ReportBuilder::report_build_groupby(const FoundSet& found_set_parent, xmlpp
           Conversions::get_text_for_gda_value(field_group_by->get_glom_type(), group_value, field_group_by->get_formatting_used().m_numeric_format) );
 
         //TODO: Use a SQL parameter instead of using sql().
-        Glib::ustring where_clause = "(\"" + group_field_table_name + "\".\"" + field_group_by->get_name() + "\" = " + field_group_by->get_full_field_details()->sql(group_value) + ")";
+        Gnome::Gda::SqlExpr where_clause =
+          Utils::build_simple_where_expression(group_field_table_name, field_group_by->get_full_field_details(), group_value);
+
         if(!found_set_parent.m_where_clause.empty())
-          where_clause += " AND (" + found_set_parent.m_where_clause + ')';
+        {
+          where_clause = Utils::build_combined_where_expression(where_clause, found_set_parent.m_where_clause,
+            Gnome::Gda::SQL_OPERATOR_TYPE_AND);
+        }
 
         FoundSet found_set_records = found_set_parent;
         found_set_records.m_where_clause = where_clause;
@@ -315,7 +320,7 @@ void ReportBuilder::report_build_records(const FoundSet& found_set, xmlpp::Eleme
     if(one_record_only)
       limit = 1;
 
-    const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
+    Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(found_set.m_table_name,
       fieldsToGet,
       found_set.m_where_clause, Glib::ustring() /* extra_join */, found_set.m_sort_clause,
       Glib::ustring(),
diff --git a/glom/utility_widgets/db_adddel/glom_db_treemodel.cc b/glom/utility_widgets/db_adddel/glom_db_treemodel.cc
index b2ac294..e78e35a 100644
--- a/glom/utility_widgets/db_adddel/glom_db_treemodel.cc
+++ b/glom/utility_widgets/db_adddel/glom_db_treemodel.cc
@@ -44,7 +44,7 @@ void DbTreeModelRow::fill_values_if_necessary(DbTreeModel& model, int row)
   //std::cout << "DbTreeModelRow::fill_values_if_necessary(): row=" << row << std::endl;
   //if(row == 1000)
   //{
-  //  std::cout << "1000" << std::endl;  
+  //  std::cout << "1000" << std::endl;
   //}
 
   if(m_values_retrieved)
@@ -54,7 +54,7 @@ void DbTreeModelRow::fill_values_if_necessary(DbTreeModel& model, int row)
   else
   {
     //std::cout << "debug: DbTreeModelRow::fill_values_if_necessary(): retrieving for row=" << row << std::endl;
-  
+
     if((row < (int)model.m_data_model_rows_count) && model.m_gda_datamodel)
     {
       Glib::RefPtr<Gnome::Gda::DataModelIter> iter = model.m_gda_datamodel->create_iter();
@@ -71,7 +71,7 @@ void DbTreeModelRow::fill_values_if_necessary(DbTreeModel& model, int row)
             m_db_values[i] = holder->get_value(); //TODO_gda: Why not just use get_value_at()?
           else
           {
-            // This is quite possible, for example for unset dates. jhs 
+            // This is quite possible, for example for unset dates. jhs
             //std::cerr << "DbTreeModelRow::fill_values_if_necessary(): NULL Gnome::Gda::Holder for field=" << i << std::endl;
           }
 
@@ -94,7 +94,7 @@ void DbTreeModelRow::fill_values_if_necessary(DbTreeModel& model, int row)
       if(m_extra)
       {
         //std::cout << "  debug: DbTreeModelRow::fill_values_if_necessary(): using default value" << std::endl;
-  
+
         //It is an extra row, added with append().
       }
       else if(!m_removed)
@@ -111,7 +111,7 @@ void DbTreeModelRow::fill_values_if_necessary(DbTreeModel& model, int row)
         {
           Glib::RefPtr<Gnome::Gda::Column> column = model.m_gda_datamodel->describe_column(col);
 
-          //We don't just create a Gda::Value of the column's gda type, 
+          //We don't just create a Gda::Value of the column's gda type,
           //because we should use a NULL-type Gda::Value as the initial value for some fields:
           const Field::glom_field_type glom_type = Field::get_glom_type_for_gda_type(column->get_g_type());
           m_db_values[col] = Glom::Conversions::get_empty_value(glom_type);
@@ -222,7 +222,7 @@ bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
   {
     m_get_records = false; //Otherwise it would not make sense.
 
-    //Use a dummy DataModel that has the same columns and types, 
+    //Use a dummy DataModel that has the same columns and types,
     //but which does not use a real database table,
     //so we can use it to add find criteria.
     Glib::RefPtr<Gnome::Gda::DataModelArray> model_array = Gnome::Gda::DataModelArray::create(m_column_fields.size());
@@ -246,8 +246,8 @@ bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
   m_gda_datamodel->append_row(); //TODO: Handle adding.
 #else
   std::auto_ptr<Glib::Error> error;
-  m_gda_datamodel->append_row(error); //TODO: Handle adding. 
-#endif  
+  m_gda_datamodel->append_row(error); //TODO: Handle adding.
+#endif
     return true;
   }
 
@@ -267,10 +267,10 @@ bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
 
   if(m_found_set.m_table_name.empty())
     std::cerr << "DEBUG: refresh_from_database(): found_set.m_table_name is empty." << std::endl;
-    
+
   if(m_connection && !m_found_set.m_table_name.empty() && m_get_records)
   {
-    const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_column_fields, m_found_set.m_where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
+    Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_column_fields, m_found_set.m_where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
     //std::cout << "  Debug: DbTreeModel::refresh_from_database():  " << sql_query << std::endl;
 
     const Application* app = Application::get_application();
@@ -294,7 +294,7 @@ bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
     try
     {
-      Glib::RefPtr<Gnome::Gda::Statement> stmt = parser->parse_string(sql_query);
+      Glib::RefPtr<Gnome::Gda::Statement> stmt = sql_query->get_statement();
       //Specify the STATEMENT_MODEL_CURSOR, so that libgda only gets the rows that we actually use.
       m_gda_datamodel = m_connection->get_gda_connection()->statement_execute_select(stmt, Gnome::Gda::STATEMENT_MODEL_CURSOR_FORWARD);
       //Examine the columns in the returned DataModel:
@@ -354,7 +354,7 @@ bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
 
       //This doesn't work with cursor-based models: const int count = m_gda_datamodel->get_n_rows();
       //because rows count is -1 until we have iterated to the last row.
-      const Glib::ustring sql_query_without_sort = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_column_fields, m_found_set.m_where_clause, m_found_set.m_extra_join, type_sort_clause(), m_found_set.m_extra_group_by);
+      Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query_without_sort = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_column_fields, m_found_set.m_where_clause, m_found_set.m_extra_join, type_sort_clause(), m_found_set.m_extra_group_by);
       const int count = Base_DB::count_rows_returned_by(sql_query_without_sort);
       if(count < 0)
       {
@@ -467,7 +467,7 @@ void DbTreeModel::get_value_vfunc(const TreeModel::iterator& iter, int column, G
             //const GType gtype_expected = column->get_g_type();
 
             result = row_details.get_value(const_cast<DbTreeModel&>(*this), column_sql, datamodel_row); //m_gda_datamodel->get_value_at(column_sql, datamodel_row); //dataRow.m_db_values[column];
-  
+
             /*
             if((result.get_value_type() != 0) && (result.get_value_type() != gtype_expected))
             {
@@ -484,7 +484,7 @@ void DbTreeModel::get_value_vfunc(const TreeModel::iterator& iter, int column, G
         GType debug_type = result.get_value_type();
         std::cout << "  debug: DbTreeModel::get_value_vfunc(): result value type: GType=" << debug_type << std::endl;
         if(debug_type)
-          std::cout << "    GType name=\"" << g_type_name(debug_type) << "\"" << std::endl; 
+          std::cout << "    GType name=\"" << g_type_name(debug_type) << "\"" << std::endl;
         */
 
         value_specific.set(result); //The compiler would complain if the type was wrong.
@@ -556,7 +556,7 @@ bool DbTreeModel::iter_nth_child_vfunc(const iterator& parent, int /* n */, iter
     return false;
   }
 
-  iter = iterator(); //Set is as invalid, as the TreeModel documentation says that it should be.  
+  iter = iterator(); //Set is as invalid, as the TreeModel documentation says that it should be.
   return false; //There are no children.
 }
 
@@ -650,7 +650,7 @@ bool DbTreeModel::create_iterator(const type_datamodel_row_index& datamodel_row,
   }
   else
   {
-    iter.set_stamp(m_stamp); 
+    iter.set_stamp(m_stamp);
     //Store the std::list iterator in the GtkTreeIter:
     //See also iter_next_vfunc()
 
@@ -675,7 +675,7 @@ bool DbTreeModel::get_iter_vfunc(const Path& path, iterator& iter) const
    if(sz > 1) //There are no children.
    {
      invalidate_iter(iter); //Set is as invalid, as the TreeModel documentation says that it should be.
-     return false; 
+     return false;
    }
 
    return iter_nth_root_child_vfunc(path[0], iter);
@@ -691,7 +691,7 @@ bool DbTreeModel::check_treeiter_validity(const iterator& iter) const
 {
   if(!(iter->get_model_gobject()))
     return false;
-    
+
   // Anything that modifies the model's structure should change the model's stamp,
   // so that old iters are ignored.
   return m_stamp == iter.get_stamp();
@@ -723,7 +723,7 @@ DbTreeModel::iterator DbTreeModel::append()
   ++m_count_extra_rows; //So that create_iterator() can succeed.
 
   //Create the row:
-  //datamodel_row->m_db_values.resize(m_columns_count); 
+  //datamodel_row->m_db_values.resize(m_columns_count);
 
   for(unsigned int column_number = 0; column_number < m_columns_count; ++column_number)
   {
@@ -830,7 +830,7 @@ void DbTreeModel::set_key_value(const TreeModel::iterator& iter, const DbValue&
 }
 
 DbTreeModel::DbValue DbTreeModel::get_key_value(const TreeModel::iterator& iter) const
-{   
+{
   if(check_treeiter_validity(iter))
   {
     type_datamodel_row_index datamodel_row = get_datamodel_row_index_from_tree_row_iter(iter);
@@ -958,7 +958,7 @@ void DbTreeModel::get_record_counts(gulong& total, gulong& found) const
     {
       //Ask the database how many records there are in the whole table:
       //TODO: Apparently, this is very slow:
-      
+
       Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
         Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
       builder->add_function("count", builder->add_id("*")); //TODO: Is * allowed here?
@@ -976,7 +976,7 @@ void DbTreeModel::get_record_counts(gulong& total, gulong& found) const
       {
         if(datamodel->get_n_rows())
         {
-#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;



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