# HOWTO for common tasks

This section is a list of small HOWTOs to get started quickly for some specific tasks, without the need to read all the documentation: quickly get to the code and read the corresponding documentation for further details.

## Open a connection

Opening a connection to a database creates a GdaConnection object which is required to execute commands. The connections' parameters (which are specific to each type of database) can be either specified when opening the connection, or be used to define a data source (DSN) and the DSN name is then specified to open the connection.

For example, opening a connection to a PostgreSQL database named "mydb" one could use the following code:

    GdaConnection *connection;
    connection = gda_connection_open_from_string ("PostgreSQL", "DB_NAME=mydb",
                                                  "USERNAME=martin;PASSWORD=luther",
                                                  GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
    if (!connection)
        g_print ("CONNECTION FAILED\n");
    else {
        /* use the opened connection */

        /* close the connection (assuming it's not used by another object) */
        g_object_unref (connection);
    }

## Define a data source (DSN)

The Configuration section details how to manage data sources definitions. To define a data source, one needs to create and fill a GdaDsnInfo structure, and use the gda_config_define_dsn() function.

For example the following code defines a data source:

    GError *error = NULL;
    GdaDsnInfo dsn_info = {
        "My DSN",
        "MySQL",
        "Sample MySQL data source",
        "HOST=myserver;DB_NAME=testdb"
        NULL,
        FALSE
    };
    if (!gda_config_define_dsn (&dsn_info, &error)) {
        /* an error occurred, the details are in error */
        g_error_free (error);
    }

## Build statements without using a parser

Statements can be created using a GdaSqlParser object to parse SQL strings, but an easier way is to use a GdaSqlBuilder object and the associated APIs to construct the statement. This section gives examples to create various statements. Please note that only the DML statements (SELECT, INSERT, UPDATE or DELETE statements can be built using a GdaSqlBuilder object, other types of statements can only be built using a parser).

Each of the examples in this section show the statement construction part, the usage part is not shown for clarity reasons (replaced with [...]). Typically one would use the gda_sql_builder_get_statement() method to actually obtain a GdaStatement object and execute it.

### INSERT INTO customers (e, f, g) VALUES (##p1::string, 15, 'joe')

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
    gda_sql_builder_set_table (b, "customers");
    gda_sql_builder_add_field_value_id (b,
                                        gda_sql_builder_add_id (b, "e"),
                                        gda_sql_builder_add_param (b, "p1", G_TYPE_STRING, FALSE));
    gda_sql_builder_add_field_value (b, "f", G_TYPE_INT, 15);
    gda_sql_builder_add_field_value (b, "g", G_TYPE_STRING, "joe")
    [...]
    g_object_unref (b);

### SELECT people.firstname AS person, people.lastname, "date" AS birthdate, age FROM people

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_select_add_field (b, "firstname", "people", "person");
    gda_sql_builder_select_add_field (b, "lastname", "people", NULL);
    gda_sql_builder_select_add_field (b, "date", NULL, "birthdate");
    gda_sql_builder_select_add_field (b, "age", NULL, NULL);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "people"),
    				      NULL);
    [...]
    g_object_unref (b);

### SELECT c."date", name AS person FROM "select" AS c INNER JOIN orders USING (id)

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    GdaSqlBuilderId id_table = gda_sql_builder_add_id (b, "select"); /* SELECT is an SQL reserved keyword */
    GdaSqlBuilderId id_target1 = gda_sql_builder_select_add_target_id (b, id_table, "c");
    GdaSqlBuilderId id_target2 = gda_sql_builder_select_add_target_id (b,
                                                                       gda_sql_builder_add_id (b, "orders"),
    				                                   NULL);
    GdaSqlBuilderId id_join = gda_sql_builder_select_join_targets (b, id_target1, id_target2, GDA_SQL_SELECT_JOIN_INNER, 0);

    /* DATE is an SQL reserved keyword */
    gda_sql_builder_add_field_value_id (b,
                                        gda_sql_builder_add_id (b, "c.date"), 0);
    gda_sql_builder_add_field_value_id (b,
    			            gda_sql_builder_add_id (b, "name"),
    		  	            gda_sql_builder_add_id (b, "person"));

    gda_sql_builder_join_add_field (b, id_join, "id");
    [...]
    g_object_unref (b);

### UPDATE products set ref='A0E''FESP' WHERE id = 14

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
    gda_sql_builder_set_table (b, "products");
    gda_sql_builder_add_field_value (b, "ref", G_TYPE_STRING, "A0E'FESP");
    GdaSqlBuilderId id_field = gda_sql_builder_add_id (b, "id");
    GdaSqlBuilderId id_value = gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 14);
    GdaSqlBuilderId id_cond = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id_field, id_value, 0);
    gda_sql_builder_set_where (b, id_cond);
    [...]
    g_object_unref (b);

### DELETE FROM items WHERE id = ##theid::int

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_DELETE);
    gda_sql_builder_set_table (b, "items");
    GdaSqlBuilderId id_field = gda_sql_builder_add_id (b, "id");
    GdaSqlBuilderId id_param = gda_sql_builder_add_param (b, "theid", G_TYPE_INT, FALSE);
    GdaSqlBuilderId id_cond = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id_field, id_param, 0);
    gda_sql_builder_set_where (b, id_cond);
    [...]
    g_object_unref (b);

### SELECT myfunc (a, 5, 'Joe') FROM mytable

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_select_add_target_id (b,
    				   gda_sql_builder_add_id (b, "mytable"),
    				   NULL);
    GdaSqlBuilderId id_function = gda_sql_builder_add_function (b, "myfunc",
    			            gda_sql_builder_add_id (b, "a"),
    			            gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 5),
    			            gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "Joe"),
    			            0);
    gda_sql_builder_add_field_value_id (b, id_function, 0);
    [...]
    g_object_unref (b);

### SELECT name FROM master WHERE id IN (SELECT id FROM subdata)

    GdaSqlBuilder *b;
    GdaSqlStatement *sub;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "id"), 0);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "subdata"),
    				      NULL);
    sub = gda_sql_builder_get_sql_statement (b, FALSE);
    g_object_unref (b);

    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "name"), 0);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "master"),
    				      NULL);
    GdaSqlBuilderId id_field = gda_sql_builder_add_id (b, "id");
    GdaSqlBuilderId id_subselect = gda_sql_builder_add_sub_select (b, sub, TRUE);
    GdaSqlBuilderId id_cond = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_IN, id_field, id_subselect, 0);
    gda_sql_builder_set_where (b, id_cond);
    [...]
    g_object_unref (b);

### INSERT INTO customers (e, f, g) SELECT id, name, location FROM subdate

    GdaSqlBuilder *b;
    GdaSqlStatement *sub;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "id"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "name"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "location"), 0);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "subdate"),
    				      NULL);
    sub = gda_sql_builder_get_sql_statement (b, FALSE);
    g_object_unref (b);

    b = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
    gda_sql_builder_set_table (b, "customers");
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "e"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "f"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "g"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_sub_select (b, sub, TRUE), 0);
    [...]
    g_object_unref (b);

### SELECT id, name FROM subdata1 UNION SELECT ident, lastname FROM subdata2

    GdaSqlBuilder *b;
    GdaSqlStatement *sub1, *sub2;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "id"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "name"), 0);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "subdata1"),
    				      NULL);
    sub1 = gda_sql_builder_get_sql_statement (b, FALSE);
    g_object_unref (b);

    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "ident"), 0);
    gda_sql_builder_add_field_value_id (b, gda_sql_builder_add_id (b, "lastname"), 0);
    gda_sql_builder_select_add_target_id (b,
    				      gda_sql_builder_add_id (b, "subdata2"),
    				      NULL);
    sub2 = gda_sql_builder_get_sql_statement (b, FALSE);
    g_object_unref (b);

    b = gda_sql_builder_new (GDA_SQL_STATEMENT_COMPOUND);
    gda_sql_builder_compound_add_sub_select (b, sub1, TRUE);
    gda_sql_builder_compound_add_sub_select (b, sub2, TRUE);
    [...]
    g_object_unref (b);

### SELECT CASE tag WHEN 'Alpha' THEN 1 WHEN 'Bravo' THEN 2 WHEN 'Charlie' THEN 3 ELSE 0 END FROM data

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    GdaSqlBuilderId id_case = gda_sql_builder_add_case (b,
    			                            gda_sql_builder_add_id (b, "tag"),
    			                            0,
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "Alpha"),
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 1),
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "Bravo"),
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 2),
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "Charlie"),
    			                            gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 3),
    			                            0);
    gda_sql_builder_add_field_value_id (b, id_case, 0);
    gda_sql_builder_select_add_target_id (b,
    				   gda_sql_builder_add_id (b, "data"),
    				   NULL);
    [...]
    g_object_unref (b);

### SELECT product_id, name, sum (4 * 5 * price * 1.200000) FROM invoice_lines

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    gda_sql_builder_select_add_field (b, "product_id", NULL, NULL);
    gda_sql_builder_select_add_field (b, "name", NULL, NULL);

    GdaSqlBuilderId op_ids[4], id_function;
    op_ids[0] = gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 4);
    op_ids[1] = gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 5);
    op_ids[2] = gda_sql_builder_add_id (b, "price");
    op_ids[3] = gda_sql_builder_add_expr (b, NULL, G_TYPE_FLOAT, 1.2);
    id_function = gda_sql_builder_add_function (b, "sum",
                                       gda_sql_builder_add_cond_v (b, GDA_SQL_OPERATOR_TYPE_STAR, op_ids, 4),
                                       0);
    gda_sql_builder_add_field_value_id (b, id_function, 0);
    gda_sql_builder_select_add_target_id (b,
                                          gda_sql_builder_add_id (b, "invoice_lines"),
    				      NULL);
    [...]
    g_object_unref (b);

### SELECT id, name, adress, cntry_id, countries.name FROM customers INNER JOIN countries ON (countries.id = cntry_id)

    GdaSqlBuilder *b;
    b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
    GdaSqlBuilderId t1, t2;
    GdaSqlBuilderId id1, id2;
    GdaSqlBuilderId jid;
    t1 = gda_sql_builder_select_add_target_id (b,
                                               gda_sql_builder_add_id (b, "customers"),
                                               NULL);
    t2 = gda_sql_builder_select_add_target_id (b,
                                               gda_sql_builder_add_id (b, "countries"),
                                               NULL);
    gda_sql_builder_select_add_field (b, "id", NULL, NULL);
    gda_sql_builder_select_add_field (b, "name", NULL, NULL);
    gda_sql_builder_select_add_field (b, "adress", NULL, NULL);
    id1 = gda_sql_builder_select_add_field (b, "cntry_id", NULL, NULL);
    gda_sql_builder_select_add_field (b, "name", "countries", NULL);
    id2 = gda_sql_builder_add_field_id (b, "id", "countries");
    jid = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id2, id1, 0);
    gda_sql_builder_select_join_targets (b, t1, t2, GDA_SQL_SELECT_JOIN_INNER, jid);
    [...]
    g_object_unref (b);

## Execute a SELECT command

Any SQL command in &LIBGDA; must be converted to a GdaStatement object which is then executed; if the statement defines some variable (place holders), then variables binding (assigning values to variables) is done at execution time. Each database provider (database driver or adapter) can implement its own parser to be able to parse its specific SQL dialect. Except for binding variables, and for reusability, the GdaStatement object guarantees that it contains only one SQL statement (it's not possible for it to contain several ones separated by a semicolon).

Parsing an SQL statement into a GdaStatement object is the job of an SqlParser.

However when one only wants to run a simple SQL statement, &LIBGDA; provides the gda_connection_statement_execute_select_command() function which does everything in one step. The following codes illustrates parsing and executing a SELECT statement:

    GdaSqlParser *parser;
    GdaStatement *stmt;
    GError *error = NULL;

    parser = gda_connection_create_parser (cnc);
    if (!parser) {
        /* the database provider used by cnc does not implement its own parser,
         * let's use a generic one */
        parser = gda_sql_parser_new ();
    stmt = gda_sql_parser_parse_string (parser, "SELECT * FROM customers", NULL, &error);
    g_object_unref (parser);
    if (!stmt) {
        /* there was an error while parsing */
    }
    else {
        GdaDataModel *model;
        model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
        if (model) {
            /* dump to results to STDOUT */
            gda_data_model_dump (model, stdout);
            g_object_unref (model);
        }
        else {
            /* there was an error while executing the statement */
        }
    }
    g_object_unref (stmt);

## Modify the result of a SELECT command

The GdaDataSelect data model (which is the data model returned after the successful execution of a SELECT statement) is by default read-only, but can be made writable after giving it information about:

- how to identify a single row in the modified table (the columns composing the primary key)

- which statements to execute when the data model's values are modified or some rows are inserted or removed

The following example illustrates this using a table created as (SQLite syntax): CREATE TABLE customers (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name string NOT NULL, last_update timestamp NOT NULL, country string);, where we select all the rows where the "country" column is "SP" and we modify only one row:

    GError *error = NULL;
    GdaDataModel *model;
    GdaStatement *stmt, *mod_stmt;
    GdaSet *params;
    GValue *value;

    /* create GdaDataSelect */
    stmt = stmt_from_string ("SELECT * FROM customers WHERE country = ##country::string");
    if (!gda_statement_get_parameters (stmt, &params, &error)) {
       /* treat error */
    }
    if (! gda_set_set_holder_value (params, &error, "country", "SP")) {
       /* treat error */
    }
    model = gda_connection_statement_execute_select (cnc, stmt, params, &error);
    g_object_unref (params);

    /* specify an UPDATE query */
    mod_stmt = stmt_from_string ("UPDATE customers SET name = ##+1::string, last_update = ##+2::timestamp WHERE id = ##-0::gint");
    if (!gda_data_select_set_modification_statement (GDA_DATA_SELECT (model), mod_stmt, &error)) {
       /* treat error */
    }

    /* Now modify the data model */
    g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "Jack");
    if (! check_set_value_at (model, 1, 0, value, cnc, stmt, NULL)) {
       /* treat error */
    }
    gda_value_free (value);

Note that in the code sample above, it would not have been possible to add or remove a row as no INSERT or DELETE statement have been specified.

Now, if the meta data associated to the connection is up to date (after having called gda_connection_update_meta_store()), then the code above can be simplified as (and as a side benefit, it would also be possible to add or remove rows):

    GError *error = NULL;
    GdaDataModel *model;
    GdaStatement *stmt;
    GdaSet *params;
    GValue *value;

    /* create GdaDataSelect */
    stmt = stmt_from_string ("SELECT * FROM customers WHERE country = ##country::string");
    if (!gda_statement_get_parameters (stmt, &params, &error)) {
       /* treat error */
    }
    if (! gda_set_set_holder_value (params, &error, "country", "SP")) {
       /* treat error */
    }
    model = gda_connection_statement_execute_select (cnc, stmt, params, &error);
    g_object_unref (params);

    /* specify that the data model can be writable */
    if (! gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), &error)) {
       /* treat error */
    }

    /* Now modify the data model */
    g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "Jack");
    if (! check_set_value_at (model, 1, 0, value, cnc, stmt, NULL)) {
       /* treat error */
    }
    gda_value_free (value);

## Execute an INSERT, UPDATE or DELETE command

INSERT, UPDATE or DELETE are treated in the same way as the SELECT command (see the HOWTO about executing a SELECT command), except that the function to execute the command is different because the returned value is not a data model but a success/failure value.

The following codes illustrates parsing and executing an UPDATE statement:

    GdaSqlParser *parser;
    GdaStatement *stmt;
    GError *error = NULL;

    parser = gda_connection_create_parser (cnc);
    if (!parser) {
        /* the database provider used by cnc does not implement its own parser,
         * let's use a generic one */
        parser = gda_sql_parser_new ();
    stmt = gda_sql_parser_parse_string (parser, "UPDATE customers set name='Joe' WHERE id=123", NULL, &error);
    g_object_unref (parser);
    if (!stmt) {
        /* there was an error while parsing */
    }
    else {
        gint res;
        res = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, &error);
        if (res == -1) {
            /* there was an error while executing the statement */
        }
        else if (res >= 0)
            g_print ("Command Ok, %d row(s) impacted\n", res);
        else
            g_print ("Command Ok, number of rows impacted is not reported\n");
    }
    g_object_unref (stmt);

Note that the example above includes in the SQL statement the values of the data to use in the UPDATE (namely 'Joe' and '123'). Even though it's simple, a better practice is to use variables, as it prevents SQL injection and avoids formatting problems. For more intormation, see the GdaSqlParser object's documentation; or the section about convenience functions

## Get the last inserted row

&LIBGDA; allows one to get the last inserted row right after an INSERT statement has been executed. &LIBGDA; returns a new GdaSet object (which the caller must unref when not needed anymore) which contains named values, one for each column of the table in which data has been inserted. To get that object, pass a place holder to the `last_insert_row` of gda_connection_statement_execute_non_select()

The following code example show how to use the returned GdaSet object:

    GdaSet *last_row;
    GdaStatement *stmt;
    stmt = gda_sql_parser_parse_string (parser, "INSERT INTO mytable (name) VALUES ('joe')", NULL, NULL);
    if (gda_connection_statement_execute_non_select (connection, stmt, NULL, &last_row, &error) == -1) {
        g_warning ("Can't execute INSERT: %s\n",
                  error && error->message ? error->message : "???");
        if (error)
            g_error_free (error);
    }
    else {
        if (!last_row)
            g_print ("Last row not reported\n");
        else {
            GSList *list;
            for (list = last_row->holders; list; list = list->next) {
                GdaHolder *h = GDA_HOLDER (list->data);
                gchar *str;
                str = gda_value_stringify (gda_holder_get_value (h));
                g_print ("\t%s => %s\n", gda_holder_get_id (h), str);
                g_free (str);
            }
        g_object_unref (last_row);
    }
    g_object_unref (stmt);

Which gives the following output (considering that in the example the "mytable" table has two columns: an Id and a Name columns):

            +0 => 1
            +1 => joe

## Execute a DDL command

DDL commands (commands to modify the database schema such as create tables and views, change users' access rights, etc) are treated in the same way as non select commands (refer to the HOWTO about executing non SELECT commands). However &LIBGDA; offers a better and more portable way of executing such commands: using a GdaServerOperation object.

Executing a DDL command involves the following steps:

1. Request a new GdaServerOperation object from the database provider for a specific operation using the gda_server_provider_create_operation() function.

2. Specify the GdaServerOperation object's behaviour by setting some pre-defined parameters; for example when creating a table, the parameters to be set include the tables name, the names of the columns, the constraints, etc. The list of parameters to set is listed by the gda-list-server-op program.

3. Ask the server provider to execute the operation based on the GdaServerOperation object

The following code in part illustrates how to create a view:

    GdaServerOperation *op;

    op = gda_connection_create_operation (cnc, GDA_SERVER_OPERATION_CREATE_VIEW, NULL, &error);
    if (!op)
        /* there was an error while creating the GdaServerOperation object */
    else {
        /* define the view to create */
        if (!gda_server_operation_set_value_at (op, "myview", &error,
                                                "/VIEW_DEF_P/VIEW_NAME") ||
            !gda_server_operation_set_value_at (op, "SELECT * FROM customers", &error,
                                                "/VIEW_DEF_P/VIEW_DEF"))
            /* there was an error */
        else {
            if (! gda_connection_perform_operation (cnc, op, &error))
                g_print ("Error\n");
            else
                g_print ("View created\n");
        }
        g_object_unref (op);
    }

Please also note that &LIBGDA; provides some convenience functions to wrap this process, see the Convenience functions section for more information.

## Get information about a table's columns

&LIBGDA; supports reporting meta data about a database (for which there is an opened connection). The meta data are stored in a database (usually an in-memory database) which structure is close to the information schema SQL standard (ISO/IEC 9075), and adapted (form information, this database is managed by a GdaMetaStore object). As databases don't notify the changes made to their objects, it is necessary to update (or synchronize) the meta data if the database's schema has been changed, or if the meta data has not yet been extracted: call gda_connection_update_meta_store() for this purpose.

One then needs to find the data requested among the (rather large) quantity of meta data available, there are two possibilities:

- Knowing the information schema's structure (tables and views) used, run some SELECT commands on the GdaMetaStore object's internal connection: this solution is the most powerful but requires some knowledge of the information schema's structure, and the data is not easy to use.

- Use a GdaMetaStruct object which exports the meta data as a dynamic tree of pre-defined data structures, easy to use.

The following code shows how to list all the colums of the "customers" table of a connection (the connection is assumed to already be opened):

    GdaMetaStruct *mstruct;
    GdaMetaDbObject *dbo;
    GValue *table_name;
    if (!gda_connection_update_meta_store (cnc, NULL, &error)) {
        /* there was an error */
        return;
    }
    mstruct = gda_meta_struct_new (store, GDA_META_STRUCT_FEATURE_NONE);
    table_name = gda_value_new (G_TYPE_STRING);
    g_value_set_string (value, "customers");
    dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE,
                                      NULL, NULL,
                                      table_name, &error);
    gda_value_free (table_name);
    if (dbo) {
        /* the "customers" table has been found, its details are in dbo */
        GdaMetaTable *table = GDA_META_TABLE (dbo);
        GSList *list;
        for (list = table->columns: list; list = list->next)
            g_print ("Column: %s\n", ((GdaMetaTableColumn*) list->data)->column_name);
    }
    else
        g_print ("Table not found\n");
    g_object_unref (mstruct);

## Update the meta data about a table

For a general overview of the mete data problem, see the Get information about a table's columns section. Updating the meta data can be done by calling gda_connection_update_meta_store() with a %NULL "context" argument, but this call updates the whole meta data which will always do the job, but sometimes one knows that only a part of the meta data need to be updated. Here is an example of how to use a specific GdaMetaContext argument.

Specifically the following code updates the meta data regarding the "customers" table:

    GdaConnection *connection=...
    GError *error = NULL;
    GValue *table;
    GdaMetaContext *mcontext = gda_meta_context_new ();
    /* This is a table in the dababase schema for Meta Store to update */
    gda_meta_context_set_table ("_tables");
    /* Next setup a value to be used as the column in the last table to be used as a condition in the update
       in this case we will use the column 'table_name' and update for 'customers'*/
    table = gda_value_new (G_TYPE_STRING);
    g_value_set_string (table, "customers");
    gda_meta_context_set_column ("table_name", table);
    gboolean result;
    result = gda_connection_update_meta_store (connection, mcontext, &error);
    gda_value_free (table);
    gda_meta_context_free (mcontext);
    if (!result) {
        /* handle the error */
        g_error_free (error);
    }

Internally gda_meta_context_set_column() calls gda_sql_identifier_quote() which ensure that the contents of `mcontext.column_values` values is conform to the convention used by the GdaMetaStore to represent SQL identifiers when the values represent an SQL identifier (which is the case in the example above). For more information, see the meta data section about SQL identifiers. Even though not strictly necessary, it used all the time. For example if the table name for which a meta data update is requested had been "Customers" (note the upper case C at the beginning and the double quotes) because this is how the database know it, then not using gda_sql_identifier_quote() may not have done as expected.

## Validate a DML statement

&LIBGDA; supports validating DML (SELECT, INSERT, UPDATE and DELETE) statements: making sure every database object referenced in the statement actually exists in the database being accessed through a connection. The validation process involves the meta data associated to a connection, son one must make that meta data is up to date with the database being accessed, using gda_connection_update_meta_store() (also see the Get information about a table's columns section).

The following code shows how to validate a statement (assuming the statement already exists):

    if (!gda_statement_check_validity (stmt, cnc, &error))
        g_print ("Invalid statement: %s\n",
                 error && error->message ? error->message : "No detail");
    else
        g_print ("Statement is valid\n");

## Control value's assignment to various objects

&LIBGDA; has builtin support to allow the programmer to control what values are acceptable for some objects which hold values (namely the GdaHolder, GdaSet and GdaDataProxy objects). For more information about this topic, see the custom data validation section.

## Add your own data to a GdaMetaStore

Adding your own data in the GdaMetaStore associated to a connection is a possibility to avoid for example to have another file to store your program-specific data (which you obviously don't want to store in a connection).

Doing so is as easy as getting a pointer to the internal connection used by the GdaMetaStore associated the connection, and then use that connection directly as any other connection object.

However &LIBGDA; has some specific API to make this easier, described in the section about adding custom data to a GdaMetaStore.