Building SQL queries using API

We already introduced the Gnome::Gda::Query::set_sql_text() function that constructs a Gnome::Gda::Query by parsing the given SQL string. But you can also modify the query's components after it has been parsed. You could even create a new query in C++ without ever calling the set_sql_text() function, by creating a Gnome::Gda::Query object and manipulating the query structure via its methods.

Because each database server recognizes a slightly different dialect of SQL, this API can be used to create queries that work with all database servers. libgda creates the appropriate SQL text for you. This API is also helpful when writing generic applications that may need to deal with databases whose structures are not known until runtime.

Reference documentation.

Gnome::Gda::Query represents the various components of a SQL query, which we will describe in the following sub-sections.

Targets

First, there are the "targets" of a query. A target is a table or view that is affected by the query. This usually appears after the FROM keyword in SELECT and DELETE queries or after INTO in an INSERT query. While a SELECT statement might have multiple targets, DELETE, INSERT and update queries may only have one target. A target is represented by a Gnome::Gda::QueryTarget object. Methods such as add_target() are relevant.

Reference documentation.

Fields

Table fields are represented by several classes that derive from the base Gnome::Gda::QueryField class. The most interesting are probably Gnome::Gda::QueryFieldField which references a single field by its name and Gnome::Gda::QueryFieldAll which references all fields in a given target (such as all fields in a table).

Reference documentation.

Conditions

Conditions limit the effects of a query to rows that fulfill certain criteria. In SQL, a condition is represented by the WHERE clause, and in libgdamm by the Gnome::Gda::QueryCondition class. A condition might be either a node condition or a leaf condition. A node condition has one or more sub-conditions, such as AND, OR or NOT. A leaf condition is a condition that has no sub-conditions.

Reference documentation.

Simple example

The following example shows how we might construct a simple query via the Query API:

Source Code

File: main.cc

#include <libgnomedbmm.h>
#include <libgdamm.h>

#include <iostream>

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void do_example()
#else
void do_example(std::auto_ptr<Glib::Error>& error)
#endif
{
  Glib::RefPtr<Gnome::Gda::Dict> dict = Gnome::Gda::Dict::create();
  Glib::RefPtr<Gnome::Gda::Client> client = Gnome::Gda::Client::create();
  Glib::ustring connection_string = "DB_DIR=" LIBGNOMEDB_DATADIR ";DB_NAME=demo_db";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "" /* username */, "" /* password */);
  dict->set_connection(cnc);
  dict->update_dbms_meta_data();
#else
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "", "", Gnome::Gda::ConnectionOptions(0), error);
  if(error.get() != NULL) return;

  dict->set_connection(cnc);
  dict->update_dbms_meta_data(error);
  if(error.get() != NULL) return;
#endif

  Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict);

  // This adds a target to our query. A target specifies the table from
  // which to SELECT fields:
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_target(Gnome::Gda::QueryTarget::create(query, "products") );
#else
  query->add_target(Gnome::Gda::QueryTarget::create(query, "products"), error);
  if(error.get() != NULL) return;
#endif

  // This adds a field we want to SELECT:
  query->add_field(Gnome::Gda::QueryFieldField::create(query, "ref"));

  // There is also a convenience function. Note that "ref" could also be other
  // SQL expressions, for example '*'.
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_field_from_sql("category");
#else
  query->add_field_from_sql("category", error);
  if(error.get() != NULL) return;
#endif

  // Prints "SELECT ref, t1.category FROM products AS t1":
  std::cout << query->get_sql_text() << std::endl;
}

int main(int argc, char* argv[])
{
  Gnome::Db::init("Queries example", "1.0", argc, argv);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    do_example();
  }
  catch(const Glib::Error& err)
  {
    std::cerr << "Exception caught: " << err.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;
  do_example(error);
  if(error.get() != NULL)
  {
    std::cerr << "Exception caught: " << error->what() << std::endl;
    return 1;
  }
#endif

  return 0;
}

This example first acquires a Gnome::Gda::Dict object, because every query needs one. The next line then creates a query object, providing the dictionary. We could give a second argument to the create() method to specify the query's type, but if none is given then SELECT is used as the default.

We then create a target and add it to the query:

query->add_target( Gnome::Gda::QueryTarget::create(query, "products") );

This is the first thing that differs from our previous examples, which used Query::set_sql_text(). As explained above, a target specifies a table which the query will affect. The create function of Gnome::Gda::QueryTarget takes two arguments: The query it belongs to and the name of the target, usually a table name.

Note that by specifying the query when creating the Gnome::Gda::QueryTarget, this target already belongs to the query. For example, it uses the same Gnome::Gda::Dict. However, the target is not considered to affect the query until it has been explicitly added to the query.

Next, a field is added to the query:

query->add_field( Gnome::Gda::QueryFieldField::create(query, "ref") );

This causes the query to return the contents of this particular field for each row, when executed. The field is represented by an object of type Gnome::Gda::QueryFieldField. The create() again takes two arguments: The query it belongs to and the name of the field. Note that the add_field() method is actually in the Entity base class.

Additionally, you may specify a field by name by simpling calling add_field_from_sql():

query->add_field_from_sql("category");

The string given to add_field_from_sql() may be any SQL expression that specifies a field, though you'll usually just specify the name directly.

You may also add all fields from a table at once by using Gnome::Gda::QueryFieldAll or by specifying "*" or "table.*"" to the add_field_from_sql() method.

Finally, we can call the get_sql_text() method to see the SQL command that we have built:

std::cout << query->get_sql_text() << std::endl;

For this simple example, this should result in:

SELECT ref, t1.category FROM products AS t1

Note that the query knows from which table the category field comes by looking it up in the dictionary. In contrast, it does not qualify the "ref" field any nearer because no target we did not specify one when calling Gnome::Gda::QueryFieldField::create(). We could have specified a target as the third parameter to that method.

Conditions and multiple targets

This example shows how to use multiple targets within a single SELECT query and how to make use of conditions.

Source Code

File: main.cc

#include <libgnomedbmm.h>
#include <libgdamm.h>

#include <iostream>

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void do_example()
#else
void do_example(std::auto_ptr<Glib::Error>& error)
#endif // GLIBMM_EXCEPTIONS_ENABLED
{
  Glib::RefPtr<Gnome::Gda::Dict> dict = Gnome::Gda::Dict::create();
  Glib::RefPtr<Gnome::Gda::Client> client = Gnome::Gda::Client::create();
  Glib::ustring connection_string = "DB_DIR=" LIBGNOMEDB_DATADIR ";DB_NAME=demo_db";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "" /* username */, "" /* password */);
  dict->set_connection(cnc);
  dict->update_dbms_meta_data();
#else
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "", "", Gnome::Gda::ConnectionOptions(0), error);
  if(error.get() != NULL) return;

  dict->set_connection(cnc);
  dict->update_dbms_meta_data(error);
  if(error.get() != NULL) return;
#endif

  Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict);

  // This defines two targets for the SELECT query
  Glib::RefPtr<Gnome::Gda::QueryTarget> customers = Gnome::Gda::QueryTarget::create(query, "customers");
  Glib::RefPtr<Gnome::Gda::QueryTarget> orders = Gnome::Gda::QueryTarget::create(query, "orders");

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_target(customers);
  query->add_target(orders);
#else
  query->add_target(customers, error);
  query->add_target(orders, error);
  if(error.get() != NULL) return;
#endif // GLIBMM_EXCEPTIONS_ENABLED

  // This specifies a field from the products table we are going to use
  // later for the condition and ORDER BY field.
  Glib::RefPtr<Gnome::Gda::QueryFieldField> cust_id = Gnome::Gda::QueryFieldField::create(query, "id", customers);
  // Another field from the order table.
  Glib::RefPtr<Gnome::Gda::QueryFieldField> ord_customer = Gnome::Gda::QueryFieldField::create(query, "customer", orders);

  // This SELECTs the creation_date field from the orders table
  query->add_field(Gnome::Gda::QueryFieldField::create(query, "creation_date", orders));

  // This shortcut function also works in this case, but be sure to mention
  // the table from which you want to SELECT a field.
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::QueryField> cust_name = query->add_field_from_sql("customers.name");
#else
  Glib::RefPtr<Gnome::Gda::QueryField> cust_name = query->add_field_from_sql("customers.name", error);
  if(error.get() != NULL) return;
#endif // GLIBMM_EXCEPTIONS_ENABLED

  // Create a new leaf condition that tests something for equality.
  Glib::RefPtr<Gnome::Gda::QueryCondition> condition = Gnome::Gda::QueryCondition::create(query, Gnome::Gda::QUERY_CONDITION_LEAF_EQUAL);
  // This sets the left and right operator for the condition. It now checks
  // the "id" field is the customer table and the "customer" field in the
  // orders table for equality.
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_LEFT, cust_id);
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_RIGHT, ord_customer);

  // TODO: We should perhaps add a Gnome::Gda::QueryCondition::create(query, type, cond_left, cond_right) convenience function.

  query->set_condition(condition);

  // Orders the result by the customer's name (ascending)
  query->set_order_by_field(cust_name);

 // Prints "SELECT t2.creation_date, t1.name FROM customers AS t1, orders AS t2 WHERE t1.id=t2.customer ORDER BY t1.name"
  std::cout << query->get_sql_text() << std::endl;
}


int main(int argc, char* argv[])
{
  Gnome::Db::init("Queries example", "1.0", argc, argv);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    do_example();
  }
  catch(const Glib::Error& err)
  {
    std::cerr << "Exception caught: " << err.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;
  do_example(error);
  if(error.get() != NULL)
  {
    std::cerr << "Exception caught: " << error->what() << std::endl;
    return 1;
  }
#endif // GLIBMM_EXCEPTIONS_ENABLED

  return 0;
}

Glib::RefPtr<Gnome::Gda::QueryTarget> customers = Gnome::Gda::QueryTarget::create(query, "customers");
Glib::RefPtr<Gnome::Gda::QueryTarget> orders = Gnome::Gda::QueryTarget::create(query, "orders");
query->add_target(customers);
query->add_target(orders);

This time, we create and add two targets to the query. We also remember them because we need them later.

Glib::RefPtr<Gnome::Gda::QueryFieldField> cust_id = Gnome::Gda::QueryFieldField::create(query, "id", customers);
Glib::RefPtr<Gnome::Gda::QueryFieldField> ord_customer = Gnome::Gda::QueryFieldField::create(query, "customer", orders);

As in the first example, this creates two Gnome::Gda::QueryFieldField objects. The third argument to the create() method now specifies to which target the field belongs. Note that both fields are not added to the query and thus will not show up in the FROM clause of the resulting SQL statement. They are nevertheless required for the condition we specify below.

query->add_field( Gnome::Gda::QueryFieldField::create(query, "creation_date", orders) );

This line adds a field to the query. It also specifies the target for the field.

Glib::RefPtr<Gnome::Gda::QueryField> cust_name = query->add_field_from_sql("customers.name");

The add_field_from_sql method can also be used when multiple targets have been added to the query. In this case, you may qualify the field name with the table name as in this example. It could also have been omitted, in which case the query would look up the correct target from the dictionary.

Glib::RefPtr<Gnome::Gda::QueryCondition> condition = Gnome::Gda::QueryCondition::create( query, Gnome::Gda::QUERY_CONDITION_LEAF_EQUAL );

This creates a new leaf condition that tests two fields for equality.

condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_LEFT, cust_id);
condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_RIGHT, ord_customer);

Every condition needs at least one operator. For leaf conditions, they are set with Gnome::Gda::Condition::leaf_set_operator, for node conditions you should use Gnome::Gda::Condition::node_add_child. The operands for leaf conditions are of type Gnome::Gda::QueryField, which means they are fields. This example condition matches all rows whose value for the "id" field of the "customers" table matches the "customer" field of the "orders" table. It is also possible to compare a field against a constant value (namely with Gnome::Gda::QueryFieldValue). This technique is shown in the example for DELETE and UPDATE queries.

query->set_condition(condition);

This assigns the condition to the query. Each query may only have one condition, but that condition may be a node condition that consists of multiple other conditions, which might in turn be node conditions, and so on.

query->set_order_by_field(cust_name);

This specifies a field by which to sort the query result. By default, sorting takes place in ascending order. If you wish to sort in descending order, set the third argument to false. The second argument specifies the position within the ORDER BY clause. For instance, if two rows have the same value in the first sort field, they will be sorted by the second sort field.

The result of the query now looks like this:

SELECT t2.creation_date, t1.name FROM customers AS t1, orders AS t2 WHERE t1.id=t2.customer ORDER BY t1.name

INSERT queries

This example shows how to create an INSERT query.

Source Code

File: main.cc

#include <libgnomedbmm.h>
#include <libgdamm.h>

#include <iostream>

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void do_example()
#else
void do_example(std::auto_ptr<Glib::Error>& error)
#endif // GLIBMM_EXCEPTIONS_ENABLED
{
  Glib::RefPtr<Gnome::Gda::Dict> dict = Gnome::Gda::Dict::create();
  Glib::RefPtr<Gnome::Gda::Client> client = Gnome::Gda::Client::create();
  Glib::ustring connection_string = "DB_DIR=" LIBGNOMEDB_DATADIR ";DB_NAME=demo_db";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "" /* username */, "" /* password */);
  dict->set_connection(cnc);
  dict->update_dbms_meta_data();
#else
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "", "", Gnome::Gda::ConnectionOptions(0), error);
  if(error.get() != NULL) return;

  dict->set_connection(cnc);
  dict->update_dbms_meta_data(error);
  if(error.get() != NULL) return;
#endif
  
  // Specifies that this is an INSERT query
  Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict, Gnome::Gda::QUERY_TYPE_INSERT);

  // Insert queries may only have one target
  Glib::RefPtr<Gnome::Gda::QueryTarget> products = Gnome::Gda::QueryTarget::create(query, "products");

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_target(products);
#else
  query->add_target(products, error);
  if(error.get() != NULL) return;
#endif

  // This specifies the field's values
  query->add_field( Gnome::Gda::QueryFieldField::create( query, "category", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(12)) ) );
  query->add_field( Gnome::Gda::QueryFieldField::create( query, "name", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value("Highest Hopes")) ) );
  query->add_field( Gnome::Gda::QueryFieldField::create( query, "price", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(16.90)) ) );
  query->add_field( Gnome::Gda::QueryFieldField::create( query, "wh_stored", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(4)) ) );

  // Prints "INSERT INTO products (category, name, price, wh_stored) VALUES (12, 'Highest Hopes', 16.900000, 4)"
  std::cout << query->get_sql_text() << std::endl;
}

int main(int argc, char* argv[])
{
  Gnome::Db::init("Queries example", "1.0", argc, argv);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    do_example();
  }
  catch(const Glib::Error& err)
  {
    std::cerr << "Exception caught: " << err.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;
  do_example(error);
  if(error.get() != NULL)
  {
    std::cerr << "Exception caught: " << error->what() << std::endl;
    return 1;
  }
#endif // GLIBMM_EXCEPTIONS_ENABLED

  return 0;
}

Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict, Gnome::Gda::QUERY_TYPE_INSERT);

This creates a query as in the first two examples. However, we now specify the query's type as the second argument to the create() call.

Glib::RefPtr<Gnome::Gda::QueryTarget> products = Gnome::Gda::QueryTarget::create(query, "products");
query->add_target(products);

This tells the query that we would like to insert a row into the "products" table. Note that INSERT queries must have exactly one target.

query->add_field( Gnome::Gda::QueryFieldField::create(query, "category", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(12))) );
query->add_field( Gnome::Gda::QueryFieldField::create(query, "name", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value("Highest Hopes"))) );
query->add_field( Gnome::Gda::QueryFieldField::create(query, "price", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(16.90))) );
query->add_field( Gnome::Gda::QueryFieldField::create(query, "wh_stored", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(4))) );

These lines add four fields to the query. These are the fields whose values we would like to set for the new row. The first three arguments of Gnome::Gda::QueryFieldField::create are the query to which the field belongs, the field name and the corresponding target, respectively. The fourth argument is a so-called value provider. This is another Gnome::Gda::QueryField which provides a value to the field, namely the value for the new row. In this example, they are all constant, so Gnome::Gda::QueryFieldValue is used.

This query will produce the following SQL:

UPDATE products SET price=21.990000, wh_stored=5 WHERE ref=42

Delete queries

This example shows how to create a DELETE query. It is otherwise similar to the previous examples.

Source Code

File: main.cc

#include <libgnomedbmm.h>
#include <libgdamm.h>

#include <iostream>

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void do_example()
#else
void do_example(std::auto_ptr<Glib::Error>& error)
#endif // GLIBMM_EXCEPTIONS_ENABLED
{
  Glib::RefPtr<Gnome::Gda::Dict> dict = Gnome::Gda::Dict::create();
  Glib::RefPtr<Gnome::Gda::Client> client = Gnome::Gda::Client::create();
  Glib::ustring connection_string = "DB_DIR=" LIBGNOMEDB_DATADIR ";DB_NAME=demo_db";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "" /* username */, "" /* password */);
  dict->set_connection(cnc);
  dict->update_dbms_meta_data();
#else
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "", "", Gnome::Gda::ConnectionOptions(0), error);
  if(error.get() != NULL) return;

  dict->set_connection(cnc);
  dict->update_dbms_meta_data(error);
  if(error.get() != NULL) return;
#endif

  // Specifies that this is a DELETE query.
  Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict, Gnome::Gda::QUERY_TYPE_DELETE);

  // Delete queries may only have one target.
  Glib::RefPtr<Gnome::Gda::QueryTarget> products = Gnome::Gda::QueryTarget::create(query, "products");

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_target(products);
#else
  query->add_target(products, error);
  if(error.get() != NULL) return;
#endif // GLIBMM_EXCEPTIONS_ENABLED

  // Create a condition that tests two fields for equality, to not delete
  // the whole table.
  Glib::RefPtr<Gnome::Gda::QueryCondition> condition = Gnome::Gda::QueryCondition::create(query, Gnome::Gda::QUERY_CONDITION_LEAF_EQUAL);
  // Left operand is the ref field in the table
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_LEFT, Gnome::Gda::QueryFieldField::create(query, "ref", products));
  // Right operand is the constant '42'. This way, all rows whose ref field
  // contains 42 will be deleted.
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_RIGHT, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(42)));

  // Associate the condition to the query
  query->set_condition(condition);

  // Prints "DELETE FROM products WHERE ref=42"
  std::cout << query->get_sql_text() << std::endl;
}

int main(int argc, char* argv[])
{
  Gnome::Db::init("Queries example", "1.0", argc, argv);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    do_example();
  }
  catch(const Glib::Error& err)
  {
    std::cerr << "Exception caught: " << err.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;
  do_example(error);
  if(error.get() != NULL)
  {
    std::cerr << "Exception caught: " << error->what() << std::endl;
    return 1;
  }
#endif // GLIBMM_EXCEPTIONS_ENABLED

  return 0;
}

Update queries

This example shows how to create an UPDATE query. It is otherwise similar to the previous examples.

Source Code

File: main.cc

#include <libgnomedbmm.h>
#include <libgdamm.h>

#include <iostream>

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void do_example()
#else
void do_example(std::auto_ptr<Glib::Error>& error)
#endif // GLIBMM_EXCEPTIONS_ENABLED
{
  Glib::RefPtr<Gnome::Gda::Dict> dict = Gnome::Gda::Dict::create();
  Glib::RefPtr<Gnome::Gda::Client> client = Gnome::Gda::Client::create();
  Glib::ustring connection_string = "DB_DIR=" LIBGNOMEDB_DATADIR ";DB_NAME=demo_db";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "" /* username */, "" /* password */);
  dict->set_connection(cnc);
  dict->update_dbms_meta_data();
#else
  Glib::RefPtr<Gnome::Gda::Connection> cnc = client->open_connection_from_string("SQLite", connection_string, "", "", Gnome::Gda::ConnectionOptions(0), error);
  if(error.get() != NULL) return;

  dict->set_connection(cnc);
  dict->update_dbms_meta_data(error);
  if(error.get() != NULL) return;
#endif // GLIBMM_EXCEPTIONS_ENABLED

  // Specifies that this is an UPDATE query.
  Glib::RefPtr<Gnome::Gda::Query> query = Gnome::Gda::Query::create(dict, Gnome::Gda::QUERY_TYPE_UPDATE);

  // Update queries may only have one target.
  Glib::RefPtr<Gnome::Gda::QueryTarget> products = Gnome::Gda::QueryTarget::create(query, "products");

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  query->add_target(products);
#else
  query->add_target(products, error);
  if(error.get() != NULL) return;
#endif

  // Create a condition that tests two fields for equality, to not update
  // each row in the table to the same values.
  Glib::RefPtr<Gnome::Gda::QueryCondition> condition = Gnome::Gda::QueryCondition::create(query, Gnome::Gda::QUERY_CONDITION_LEAF_EQUAL);
  // Left operand is the ref field in the table
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_LEFT, Gnome::Gda::QueryFieldField::create(query, "ref", products));
  // Right operand is the constant '42'. This way, all rows whose ref field
  // contains 42 will be deleted.
  condition->leaf_set_operator(Gnome::Gda::QUERY_CONDITION_OP_RIGHT, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(42)));

  // Associate the condition to the query
  query->set_condition(condition);

  // Changes the price and wh_stored fields of the rows matching the above
  // condition to the specified values.
  query->add_field(Gnome::Gda::QueryFieldField::create(query, "price", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(21.99))));
  query->add_field(Gnome::Gda::QueryFieldField::create(query, "wh_stored", products, Gnome::Gda::QueryFieldValue::create(query, Gnome::Gda::Value(5))));

  // Prints "UPDATE products SET price=21.990000, wh_stored=5 WHERE ref=42"
  std::cout << query->get_sql_text() << std::endl;
}

int main(int argc, char* argv[])
{
  Gnome::Db::init("Queries example", "1.0", argc, argv);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    do_example();
  }
  catch(const Glib::Error& err)
  {
    std::cerr << "Exception caught: " << err.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;
  do_example(error);
  if(error.get() != NULL)
  {
    std::cerr << "Exception caught: " << error->what() << std::endl;
    return 1;
  }
#endif // GLIBMM_EXCEPTIONS_ENABLED

  return 0;
}