Commit 3fedfba9 authored by Vivien Malerba's avatar Vivien Malerba

Optimized virtual tables usage

- make use of the infrastructure provided by SQLite to pre-filter
  data model's contents when possible
- require only GDA_STATEMENT_MODEL_CURSOR_FORWARD data models
parent faed5ba5
2010-10-16 Murray Cumming <murrayc@murrayc-x61>
reviewed by: <delete if not using a buddy>
* libgda/gda-meta-store.c:
* libgda/sql-parser/gda-statement-struct-compound.c:
* libgda/sql-parser/gda-statement-struct-delete.c:
* libgda/sql-parser/gda-statement-struct-insert.c:
* libgda/sql-parser/gda-statement-struct-pspec.c:
* libgda/sql-parser/gda-statement-struct-select.c:
* libgda/sql-parser/gda-statement-struct-trans.c:
* libgda/sql-parser/gda-statement-struct-unknown.c:
* libgda/sql-parser/gda-statement-struct-update.c:
The ChangeLog is auto-generated when releasing. If you
are seeing this, use 'git log' for a detailed list of changes.
......@@ -46,8 +46,8 @@ The #GdaVproviderDataModel provider to use to create such connection objects.
@data_model:
@create_columns_func:
@create_model_func:
@_gda_reserved1:
@_gda_reserved2:
@create_filter_func:
@create_filtered_model_func:
<!-- ##### USER_FUNCTION GdaVconnectionDataModelCreateColumnsFunc ##### -->
<para>
......
......@@ -62,7 +62,7 @@ This is a base virtual class for all virtual connection implementations
</para>
@cnc:
@vcnc:
@Returns:
......@@ -6,14 +6,14 @@ Virtual provider for connections based on a list of GdaDataModel
<!-- ##### SECTION Long_Description ##### -->
<para>
This provider is used to create virtual connections in which each #GdaDataModel data models can be
added as tables in the connection. Using gda_server_provider_create_connection() will generate a
#GdaVconnectionDataModel connection object.
This provider is used to create virtual connections in which each #GdaDataModel data model can be
added as a table in the connection. Using gda_virtual_connection_open() with this provider as argument
will generate a #GdaVconnectionDataModel connection object, from which data models can be added.
</para>
<!-- ##### SECTION See_Also ##### -->
<para>
See also the <link linkend="VirtualIntro">introduction to virtual connections</link>.
</para>
<!-- ##### SECTION Stability_Level ##### -->
......
......@@ -6,17 +6,18 @@ Virtual provider for connections based on other connection
<!-- ##### SECTION Long_Description ##### -->
<para>
This provider is used to create virtual connections which "incorporate" tables from other connections. This is typically
used when one need to compare or migrate data from one database to the other by creating two connections for each database,
and "binding" them into a third virtual connection using this provider.
This provider is used to create virtual connections which "incorporate" tables from other connections. This is typically
used when one need to compare or migrate data from one database to the other by creating two connections for each database,
and "binding" them into a third virtual connection using this provider.
</para>
<para>
Using gda_server_provider_create_connection() will generate a #GdaVconnectionHub connection object.
Using gda_virtual_connection_open() with this provider as argument
will generate a #GdaVconnectionHub connection object, from which connections can be added.
</para>
<!-- ##### SECTION See_Also ##### -->
<para>
See also the <link linkend="VirtualIntro">introduction to virtual connections</link>.
</para>
<!-- ##### SECTION Stability_Level ##### -->
......
......@@ -32,6 +32,8 @@ cnc = gda_virtual_connection_open (provider, NULL);
<listitem><para><filename class="directory">samples/Virtual</filename></para></listitem>
<listitem><para><filename class="directory">samples/DirDataModel</filename></para></listitem>
<listitem><para><filename class="directory">samples/F-Spot</filename></para></listitem>
<listitem><para><filename class="directory">testing/virtual-test.c</filename></para></listitem>
<listitem><para><filename class="directory">testing/virtual-test-2.c</filename></para></listitem>
</itemizedlist>
</para>
&libgda-virtual-notice;
......
......@@ -784,6 +784,12 @@ gda_data_model_set_values (GdaDataModel *model, gint row, GList *values, GError
* gda_data_model_iter_move_next() (and gda_data_model_iter_move_prev() if
* supported).
*
* Note: for the #GdaDataProxy data model (which proxies any #GdaDataModel for modifications and
* has twice the number of columns of the proxied data model), this method will create an iterator
* in which only the columns of the proxied data model appear. If you need to have a #GdaDataModelIter
* in which all the proxy's columns appear, create it using:
* <programlisting><![CDATA[iter = g_object_new (GDA_TYPE_DATA_MODEL_ITER, "data-model", proxy, NULL);]]></programlisting>
*
* Returns: (transfer full): a #GdaDataModelIter object, or %NULL if an error occurred
*/
GdaDataModelIter *
......
......@@ -3338,12 +3338,40 @@ static void create_columns (GdaDataProxy *proxy)
for (; i < 2 * proxy->priv->model_nb_cols; i++) {
GdaColumn *orig;
const gchar *cname;
gchar *newname;
gchar *newname, *id;
gint k;
orig = gda_data_model_describe_column (proxy->priv->model,
i - proxy->priv->model_nb_cols);
proxy->priv->columns[i] = gda_column_copy (orig);
g_object_get ((GObject*) proxy->priv->columns[i], "id", &id, NULL);
if (id) {
gchar *newid;
newid = g_strdup_printf ("pre%s", id);
g_object_set ((GObject*) proxy->priv->columns[i], "id", newid, NULL);
/* make sure there is no duplicate ID */
for (k = 0; ; k++) {
gint j;
for (j = 0; j < i; j++) {
gchar *id2;
g_object_get ((GObject*) proxy->priv->columns[j], "id", &id2, NULL);
if (id2 && *id2 && !strcmp (id2, newid)) {
g_free (id2);
break;
}
}
if (j == i)
break;
g_free (newid);
newid = g_strdup_printf ("pre%s_%d", id, k);
g_object_set ((GObject*) proxy->priv->columns[i], "id", newid, NULL);
}
g_free (newid);
g_free (id);
}
cname = gda_column_get_name (orig);
if (cname && *cname)
newname = g_strdup_printf ("pre%s", cname);
......
......@@ -1483,7 +1483,7 @@ gda_set_get_nth_holder (GdaSet *set, gint pos)
for (list = set->holders; list; list = list->next)
g_array_append_val (set->priv->holders_array, list->data);
}
if ((guint)pos > set->priv->holders_array->len)
if ((guint)pos >= set->priv->holders_array->len)
return NULL;
else
return g_array_index (set->priv->holders_array, GdaHolder*, pos);
......
......@@ -267,6 +267,10 @@ load_symbols (GModule *module)
goto onerror;
if (! g_module_symbol (module, "sqlite3_value_int", (gpointer*) &(s3r->sqlite3_value_int)))
goto onerror;
if (! g_module_symbol (module, "sqlite3_value_int64", (gpointer*) &(s3r->sqlite3_value_int64)))
goto onerror;
if (! g_module_symbol (module, "sqlite3_value_double", (gpointer*) &(s3r->sqlite3_value_double)))
goto onerror;
if (! g_module_symbol (module, "sqlite3_value_text", (gpointer*) &(s3r->sqlite3_value_text)))
goto onerror;
if (! g_module_symbol (module, "sqlite3_value_type", (gpointer*) &(s3r->sqlite3_value_type)))
......
......@@ -104,6 +104,8 @@ typedef struct {
const void * (*sqlite3_value_blob)(sqlite3_value*);
int (*sqlite3_value_bytes)(sqlite3_value*);
int (*sqlite3_value_int)(sqlite3_value*);
double (*sqlite3_value_double)(sqlite3_value*);
sqlite3_int64 (*sqlite3_value_int64)(sqlite3_value*);
const unsigned char * (*sqlite3_value_text)(sqlite3_value*);
int (*sqlite3_value_type)(sqlite3_value*);
......
......@@ -233,7 +233,7 @@ gda_vconnection_data_model_add (GdaVconnectionDataModel *cnc, GdaVconnectionData
g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE);
g_return_val_if_fail (table_name && *table_name, FALSE);
g_return_val_if_fail (spec, FALSE);
g_return_val_if_fail (spec->data_model || (spec->create_columns_func && spec->create_model_func), FALSE);
g_return_val_if_fail (spec->data_model || (spec->create_columns_func && (spec->create_model_func || spec->create_filtered_model_func)), FALSE);
if (spec->data_model)
g_return_val_if_fail (GDA_IS_DATA_MODEL (spec->data_model), FALSE);
......
/* GDA
* Copyright (C) 2007 - 2009 The GNOME Foundation.
/*
* Copyright (C) 2007 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba@gnome-db.org>
......@@ -24,6 +24,7 @@
#define __GDA_VCONNECTION_DATA_MODEL_H__
#include <virtual/gda-virtual-connection.h>
#include <sql-parser/gda-statement-struct-parts.h>
#define GDA_TYPE_VCONNECTION_DATA_MODEL (gda_vconnection_data_model_get_type())
#define GDA_VCONNECTION_DATA_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_VCONNECTION_DATA_MODEL, GdaVconnectionDataModel))
......@@ -37,21 +38,62 @@ typedef struct _GdaVconnectionDataModel GdaVconnectionDataModel;
typedef struct _GdaVconnectionDataModelClass GdaVconnectionDataModelClass;
typedef struct _GdaVconnectionDataModelPrivate GdaVconnectionDataModelPrivate;
typedef struct _GdaVconnectionDataModelSpec GdaVconnectionDataModelSpec;
typedef struct _GdaVconnectionDataModelFilter GdaVconnectionDataModelFilter;
typedef GList *(*GdaVconnectionDataModelCreateColumnsFunc) (GdaVconnectionDataModelSpec *, GError **);
typedef GdaDataModel *(*GdaVconnectionDataModelCreateModelFunc) (GdaVconnectionDataModelSpec *);
typedef void (*GdaVconnectionDataModelFunc) (GdaDataModel *, const gchar *, gpointer );
/*
* Enabling pre-filtering when creating a data model to be used as a table,
* (structure closely mapped with SQLite's sqlite3_index_info type), to enable
* the data model to perform some filter tasks itself.
*
* A pointer to this structure is passed to the GdaVconnectionDataModelParseFilterFunc function
* and the function has to modify the variables in the *Outputs* section (and nowhere else)
*
* The @idxNum and @idxPointer are passed to the GdaVconnectionDataModelCreateFModelFunc function call
* and they represent nothing specific except that the GdaVconnectionDataModelParseFilterFunc and
* GdaVconnectionDataModelCreateFModelFunc functions need to agree on their meaning.
*
* See the gda-vconnection-hub.c file for an usage example.
*/
struct _GdaVconnectionDataModelFilter {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct GdaVirtualConstraint {
int iColumn; /* Column on left-hand side of constraint */
GdaSqlOperatorType op; /* Constraint operator, among _EQ, _LT, _LEQ, _GT, _GEQ, _REGEXP */
} *aConstraint; /* Table of WHERE clause constraints */
int nOrderBy; /* Number of terms in the ORDER BY clause */
struct GdaVirtualOrderby {
int iColumn; /* Column number */
gboolean desc; /* TRUE for DESC. FALSE for ASC. */
} *aOrderBy; /* The ORDER BY clause */
/* Outputs */
struct GdaVirtualConstraintUsage {
int argvIndex; /* if >0, constraint is part of argv to xFilter */
gboolean omit; /* Do not code a test for this constraint if TRUE */
} *aConstraintUsage;
int idxNum; /* Number used to identify the index */
gpointer idxPointer; /* Pointer used to identify the index */
gboolean orderByConsumed; /* TRUE if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
};
typedef void (*GdaVconnectionDataModelParseFilterFunc) (GdaVconnectionDataModelSpec *, GdaVconnectionDataModelFilter *);
typedef GdaDataModel *(*GdaVconnectionDataModelCreateFModelFunc) (GdaVconnectionDataModelSpec *,
int, const char *, int, GValue **);
struct _GdaVconnectionDataModelSpec {
GdaDataModel *data_model;
GdaVconnectionDataModelCreateColumnsFunc create_columns_func;
GdaVconnectionDataModelCreateModelFunc create_model_func;
/* Padding for future expansion */
void (*_gda_reserved1) (void);
void (*_gda_reserved2) (void);
GdaVconnectionDataModelParseFilterFunc create_filter_func;
GdaVconnectionDataModelCreateFModelFunc create_filtered_model_func;
};
#define GDA_VCONNECTION_DATA_MODEL_SPEC(x) ((GdaVconnectionDataModelSpec*)(x))
struct _GdaVconnectionDataModel {
......
/*
* GDA common library
* Copyright (C) 2007 - 2008 The GNOME Foundation.
* Copyright (C) 2007 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba@gnome-db.org>
......@@ -28,6 +28,8 @@
#include <sql-parser/gda-sql-parser.h>
#include <libgda/gda-util.h>
#include <libgda/gda-data-select.h>
#include <gda-sql-builder.h>
#include "../gda-sqlite.h"
typedef struct {
GdaVconnectionHub *hub;
......@@ -345,72 +347,499 @@ static void meta_changed_cb (GdaMetaStore *store, GSList *changes, HubConnection
typedef struct {
GdaVconnectionDataModelSpec spec;
GValue *table_name;
GValue *table_name;
HubConnection *hc;
GError *cols_error;
gint ncols;
gchar **col_names; /* free using g_strfreev */
GType *col_gtypes;/* free using g_free */
gchar **col_dtypes;/* free using g_strfreev */
GHashTable *filters_hash; /* key = string; value = a ComputedFilter pointer */
} LocalSpec;
static void local_spec_free (LocalSpec *spec)
{
gda_value_free (spec->table_name);
if (spec->col_names)
g_strfreev (spec->col_names);
if (spec->col_gtypes)
g_free (spec->col_gtypes);
if (spec->col_dtypes)
g_strfreev (spec->col_dtypes);
g_clear_error (&(spec->cols_error));
if (spec->filters_hash)
g_hash_table_destroy (spec->filters_hash);
g_free (spec);
}
static GList *
dict_table_create_columns_func (GdaVconnectionDataModelSpec *spec, GError **error)
static void
compute_column_specs (GdaVconnectionDataModelSpec *spec)
{
LocalSpec *lspec = (LocalSpec *) spec;
gint i, nrows;
GList *columns = NULL;
GdaDataModel *model;
if (lspec->col_names)
return;
model = gda_connection_get_meta_store_data (lspec->hc->cnc,
GDA_CONNECTION_META_FIELDS, NULL, 1, "name", lspec->table_name);
if (!model)
return NULL;
return;
nrows = gda_data_model_get_n_rows (model);
lspec->col_names = g_new0 (gchar *, nrows+1);
lspec->col_gtypes = g_new0 (GType, nrows);
lspec->col_dtypes = g_new0 (gchar *, nrows+1);
for (i = 0; i < nrows; i++) {
GdaColumn *col;
const GValue *v0, *v1, *v2;
v0 = gda_data_model_get_value_at (model, 0, i, error);
v1 = gda_data_model_get_value_at (model, 1, i, error);
v2 = gda_data_model_get_value_at (model, 2, i, error);
v0 = gda_data_model_get_value_at (model, 0, i, NULL);
v1 = gda_data_model_get_value_at (model, 1, i, NULL);
v2 = gda_data_model_get_value_at (model, 2, i, NULL);
if (!v0 || !v1 || !v2) {
if (columns) {
g_list_foreach (columns, (GFunc) g_object_unref, NULL);
g_list_free (columns);
columns = NULL;
}
break;
}
lspec->col_names[i] = g_value_dup_string (v0);
lspec->col_gtypes[i] = gda_g_type_from_string (g_value_get_string (v2));
lspec->col_dtypes[i] = g_value_dup_string (v1);
}
g_object_unref (model);
if (i != nrows) {
/* there has been an error */
g_strfreev (lspec->col_names);
lspec->col_names = NULL;
g_free (lspec->col_gtypes);
lspec->col_gtypes = NULL;
g_strfreev (lspec->col_dtypes);
lspec->col_dtypes = NULL;
g_set_error (&(lspec->cols_error), GDA_META_STORE_ERROR, GDA_META_STORE_INTERNAL_ERROR,
_("Unable to get information about table '%s'"),
g_value_get_string (lspec->table_name));
}
else
lspec->ncols = nrows;
}
static GList *
dict_table_create_columns_func (GdaVconnectionDataModelSpec *spec, GError **error)
{
LocalSpec *lspec = (LocalSpec *) spec;
GList *columns = NULL;
gint i;
compute_column_specs (spec);
if (lspec->cols_error) {
if (error)
*error = g_error_copy (lspec->cols_error);
return NULL;
}
for (i = 0; i < lspec->ncols; i++) {
GdaColumn *col;
col = gda_column_new ();
gda_column_set_name (col, g_value_get_string (v0));
gda_column_set_g_type (col, gda_g_type_from_string (g_value_get_string (v2)));
gda_column_set_dbms_type (col, g_value_get_string (v1));
gda_column_set_name (col, lspec->col_names[i]);
gda_column_set_g_type (col, lspec->col_gtypes[i]);
gda_column_set_dbms_type (col, lspec->col_dtypes[i]);
columns = g_list_prepend (columns, col);
}
g_object_unref (model);
return g_list_reverse (columns);
}
static GdaDataModel *
dict_table_create_model_func (GdaVconnectionDataModelSpec *spec)
static gchar *
make_string_for_sqlite3_index_info (sqlite3_index_info *info)
{
GdaDataModel *model;
GString *string;
gint i;
string = g_string_new ("");
for (i = 0; i < info->nConstraint; i++) {
const struct sqlite3_index_constraint *cons;
cons = &(info->aConstraint [i]);
if (! cons->usable)
continue;
g_string_append_printf (string, "|%d,%d", cons->iColumn, cons->op);
}
g_string_append_c (string, '/');
for (i = 0; i < info->nOrderBy; i++) {
struct sqlite3_index_orderby *order;
order = &(info->aOrderBy[i]);
g_string_append_printf (string, "|%d,%d", order->iColumn, order->desc ? 1 : 0);
}
return g_string_free (string, FALSE);
}
typedef struct {
GdaStatement *stmt;
gchar *tmp;
int orderByConsumed;
struct sqlite3_index_constraint_usage *out_const;
} ComputedFilter;
static void
computed_filter_free (ComputedFilter *filter)
{
g_object_unref (filter->stmt);
g_free (filter->out_const);
g_free (filter);
}
static void
dict_table_create_filter (GdaVconnectionDataModelSpec *spec, sqlite3_index_info *info)
{
LocalSpec *lspec = (LocalSpec *) spec;
GdaSqlBuilder *b;
gint i;
gchar *hash;
compute_column_specs (spec);
if (lspec->cols_error)
return;
hash = make_string_for_sqlite3_index_info (info);
if (lspec->filters_hash) {
ComputedFilter *filter;
filter = g_hash_table_lookup (lspec->filters_hash, hash);
if (filter) {
info->idxStr = (char*) filter->stmt;
info->needToFreeIdxStr = FALSE;
info->orderByConsumed = filter->orderByConsumed;
memcpy (info->aConstraintUsage,
filter->out_const,
sizeof (struct sqlite3_index_constraint_usage) * info->nConstraint);
/*g_print ("Reusing filter %p, hash=[%s]\n", filter, hash);*/
g_free (hash);
return;
}
}
/* SELECT core */
b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
for (i = 0; i < lspec->ncols; i++)
gda_sql_builder_select_add_field (b, lspec->col_names[i], NULL, NULL);
gda_sql_builder_select_add_target_id (b,
gda_sql_builder_add_id (b, g_value_get_string (lspec->table_name)),
NULL);
/* WHERE part */
gint argpos;
GdaSqlBuilderId *op_ids;
op_ids = g_new (GdaSqlBuilderId, info->nConstraint);
for (i = 0, argpos = 0; i < info->nConstraint; i++) {
const struct sqlite3_index_constraint *cons;
cons = &(info->aConstraint [i]);
if (! cons->usable)
continue;
if (cons->iColumn >= lspec->ncols) {
g_warning ("Internal error: column known by SQLite's virtual table %d is not known for "
"table '%s', which has %d column(s)", cons->iColumn,
g_value_get_string (lspec->table_name), lspec->ncols);
continue;
}
GdaSqlBuilderId fid, pid, eid;
gchar *pname;
if (lspec->col_gtypes[cons->iColumn] == GDA_TYPE_BLOB) /* ignore BLOBs */
continue;
fid = gda_sql_builder_add_id (b, lspec->col_names[cons->iColumn]);
pname = g_strdup_printf ("param%d", argpos);
pid = gda_sql_builder_add_param (b, pname, lspec->col_gtypes[cons->iColumn], TRUE);
g_free (pname);
eid = gda_sql_builder_add_cond (b, cons->op, fid, pid, 0);
op_ids[argpos] = eid;
/* update info->aConstraintUsage */
info->aConstraintUsage [i].argvIndex = argpos+1;
info->aConstraintUsage [i].omit = 1;
argpos++;
}
if (argpos > 0) {
GdaSqlBuilderId whid;
whid = gda_sql_builder_add_cond_v (b, GDA_SQL_OPERATOR_TYPE_AND, op_ids, argpos);
gda_sql_builder_set_where (b, whid);
}
g_free (op_ids);
tmp = g_strdup_printf ("SELECT * FROM %s", g_value_get_string (lspec->table_name));
stmt = gda_sql_parser_parse_string (internal_parser, tmp, NULL, NULL);
g_free (tmp);
model = gda_connection_statement_execute_select (lspec->hc->cnc, stmt, NULL, NULL);
/* ORDER BY part */
info->orderByConsumed = TRUE;
for (i = 0; i < info->nOrderBy; i++) {
struct sqlite3_index_orderby *ao;
GdaSqlBuilderId fid;
ao = &(info->aOrderBy [i]);
if (ao->iColumn >= lspec->ncols) {
g_warning ("Internal error: column known by SQLite's virtual table %d is not known for "
"table '%s', which has %d column(s)", ao->iColumn,
g_value_get_string (lspec->table_name), lspec->ncols);
info->orderByConsumed = FALSE;
continue;
}
fid = gda_sql_builder_add_id (b, lspec->col_names[ao->iColumn]);
gda_sql_builder_select_order_by (b, fid, ao->desc ? FALSE : TRUE, NULL);
}
GdaStatement *stmt;
stmt = gda_sql_builder_get_statement (b, NULL);
g_object_unref (b);
if (stmt) {
ComputedFilter *filter;
filter = g_new0 (ComputedFilter, 1);
filter->stmt = stmt;
filter->orderByConsumed = info->orderByConsumed;
filter->out_const = g_new (struct sqlite3_index_constraint_usage, info->nConstraint);
memcpy (filter->out_const,
info->aConstraintUsage,
sizeof (struct sqlite3_index_constraint_usage) * info->nConstraint);
gchar *sql;
sql = gda_statement_to_sql (stmt, NULL, NULL);
/*g_print ("Filter %p for [%s] hash=[%s]\n", filter, sql, hash);*/
g_free (sql);
if (! lspec->filters_hash)
lspec->filters_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) computed_filter_free);
g_hash_table_insert (lspec->filters_hash, hash, filter);
info->idxStr = (char*) filter->stmt;
/*g_print ("There are now %d statements in store...\n", g_hash_table_size (lspec->filters_hash));*/
}
else {
for (i = 0, argpos = 0; i < info->nConstraint; i++) {
info->aConstraintUsage[i].argvIndex = 0;
info->aConstraintUsage[i].omit = 0;
}
info->idxStr = NULL;
info->orderByConsumed = 0;
g_free (hash);
}
}
/*
* Takes as input #GValue created when calling spec->create_filtered_model_func()
* and creates a GValue with the correct requested type
*/
static GValue *
create_value_from_sqlite3_gvalue (GType type, GValue *svalue, GError **error)
{
GValue *value;
gboolean allok = TRUE;
value = g_new0 (GValue, 1);
if (type != GDA_TYPE_NULL)
g_value_init (value, type);
if (type == GDA_TYPE_NULL)
;
else if (type == G_TYPE_INT) {
if (G_VALUE_TYPE (svalue) != G_TYPE_INT64)
allok = FALSE;
else {
gint64 i;
i = g_value_get_int64 (svalue);