[libgda/LIBGDA_4.2] Virtual connection correction & improvements
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda/LIBGDA_4.2] Virtual connection correction & improvements
- Date: Thu, 14 Apr 2011 18:53:51 +0000 (UTC)
commit c16ef39695dfcc8bca60803deaa85b598547df17
Author: Vivien Malerba <malerba gnome-db org>
Date: Thu Apr 14 20:53:26 2011 +0200
Virtual connection correction & improvements
correctly handle the list of virtual tables and emit signals when a
virtual table is added or removed
libgda/gda-connection-internal.h | 12 ++-
libgda/gda-connection.c | 79 ++++++++++++++-
libgda/sqlite/virtual/gda-vconnection-data-model.c | 105 ++++++++++++++++++--
libgda/sqlite/virtual/gda-vconnection-data-model.h | 9 +-
libgda/sqlite/virtual/gda-vconnection-hub.c | 6 +
libgda/sqlite/virtual/gda-virtual-connection.c | 3 +-
libgda/sqlite/virtual/gda-vprovider-data-model.c | 75 ++++++++++++++
7 files changed, 269 insertions(+), 20 deletions(-)
---
diff --git a/libgda/gda-connection-internal.h b/libgda/gda-connection-internal.h
index 40edfeb..36274e0 100644
--- a/libgda/gda-connection-internal.h
+++ b/libgda/gda-connection-internal.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -73,6 +73,14 @@ typedef struct {
void _gda_connection_force_transaction_status (GdaConnection *cnc, GdaConnection *wrapped_cnc);
GdaServerProvider *_gda_connection_get_internal_thread_provider (void);
+/*
+ * Used by virtual connections to keep meta data up to date when a table
+ * is added or removed, without using the update_meta_store_after_statement_exec()
+ * because it may not be called everytime
+ */
+void _gda_connection_signal_meta_table_update (GdaConnection *cnc, const gchar *table_name);
+gchar *_gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *table_name);
+
G_END_DECLS
#endif
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 48de177..6ad04a4 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -48,6 +48,7 @@
#include <libgda/thread-wrapper/gda-thread-provider.h>
#include <libgda/gda-repetitive-statement.h>
#include <gda-statement-priv.h>
+#include <sqlite/virtual/gda-vconnection-data-model.h>
#include <glib/gstdio.h>
#include <fcntl.h>
@@ -6216,6 +6217,12 @@ get_next_word (gchar *str, gboolean for_ident, gchar **out_next)
static GdaMetaContext *
meta_data_context_from_statement (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params)
{
+ if (GDA_IS_VCONNECTION_DATA_MODEL (cnc))
+ /* meta data is updated when the virtual connection emits the
+ * "vtable-created" or "vtable-dropped" signals
+ */
+ return NULL;
+
GdaMetaContext *context = NULL;
gchar *sql, *current, *next;
sql = gda_statement_to_sql (stmt, params, NULL);
@@ -6225,18 +6232,20 @@ meta_data_context_from_statement (GdaConnection *cnc, GdaStatement *stmt, GdaSet
current = get_next_word (sql, FALSE, &next);
if (current && (!strcmp (current, "CREATE") || !strcmp (current, "DROP") ||
!strcmp (current, "ALTER"))) {
+ const gchar *tname = NULL;
current = get_next_word (next, FALSE, &next);
- if (current && (!strcmp (current, "TABLE") || !strcmp (current, "VIEW"))) {
+ if (current && (!strcmp (current, "TABLE") || !strcmp (current, "VIEW")))
+ tname = get_next_word (next, TRUE, &next);
+ if (tname) {
gchar *tmp;
- current = get_next_word (next, TRUE, &next);
- /*g_print ("CONTEXT: update for table [%s]\n", current);*/
+ /*g_print ("CONTEXT: update for table [%s]\n", tname);*/
context = g_new0 (GdaMetaContext, 1);
context->table_name = "_tables";
context->size = 1;
context->column_names = g_new0 (gchar *, 1);
context->column_names[0] = "table_name";
context->column_values = g_new0 (GValue *, 1);
- tmp = gda_sql_identifier_quote (current, cnc, cnc->priv->provider_obj,
+ tmp = gda_sql_identifier_quote (tname, cnc, cnc->priv->provider_obj,
TRUE,
cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
@@ -6327,6 +6336,34 @@ update_meta_store_after_statement_exec (GdaConnection *cnc, GdaStatement *stmt,
}
}
+void
+_gda_connection_signal_meta_table_update (GdaConnection *cnc, const gchar *table_name)
+{
+ GdaMetaContext *context;
+ gchar *tmp;
+ /*g_print ("CONTEXT: update for table [%s]\n", tname);*/
+ context = g_new0 (GdaMetaContext, 1);
+ context->table_name = "_tables";
+ context->size = 1;
+ context->column_names = g_new0 (gchar *, 1);
+ context->column_names[0] = "table_name";
+ context->column_values = g_new0 (GValue *, 1);
+ tmp = gda_sql_identifier_quote (table_name, cnc, cnc->priv->provider_obj,
+ TRUE,
+ cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
+ g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
+ tmp);
+
+ GError *lerror = NULL;
+ if (! gda_connection_update_meta_store (cnc, context, &lerror))
+ add_connection_event_from_error (cnc, &lerror);
+
+ if (cnc->priv->trans_meta_context)
+ g_array_prepend_val (cnc->priv->trans_meta_context, context);
+ else
+ auto_update_meta_context_free (context);
+}
+
/*
* Free @context which must have been created by meta_data_context_from_statement()
*/
@@ -6341,3 +6378,37 @@ auto_update_meta_context_free (GdaMetaContext *context)
g_free (context->column_values);
g_free (context);
}
+
+
+/*
+ * _gda_connection_get_table_virtual_name
+ * @table_name: a non %NULL string
+ *
+ * Returns: a new string.
+ */
+gchar *
+_gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *table_name)
+{
+ gchar **array;
+ gchar *tmp;
+ GString *string = NULL;
+ gint i;
+
+ g_assert (table_name && *table_name);
+ array = gda_sql_identifier_split (table_name);
+ for (i = 0; ; i++) {
+ if (array [i]) {
+ tmp = gda_sql_identifier_quote (array[i], cnc, NULL, TRUE, FALSE);
+ if (string) {
+ g_string_append_c (string, '.');
+ g_string_append (string, tmp);
+ }
+ else
+ string = g_string_new (tmp);
+ }
+ else
+ break;
+ }
+ g_strfreev (array);
+ return g_string_free (string, FALSE);
+}
diff --git a/libgda/sqlite/virtual/gda-vconnection-data-model.c b/libgda/sqlite/virtual/gda-vconnection-data-model.c
index 091ebf0..fe0f285 100644
--- a/libgda/sqlite/virtual/gda-vconnection-data-model.c
+++ b/libgda/sqlite/virtual/gda-vconnection-data-model.c
@@ -26,6 +26,7 @@
#include "gda-vconnection-data-model-private.h"
#include "gda-virtual-provider.h"
#include <libgda/gda-connection-private.h>
+#include <libgda/gda-connection-internal.h>
#include "../gda-sqlite.h"
struct _GdaVconnectionDataModelPrivate {
@@ -35,8 +36,52 @@ struct _GdaVconnectionDataModelPrivate {
static void gda_vconnection_data_model_class_init (GdaVconnectionDataModelClass *klass);
static void gda_vconnection_data_model_init (GdaVconnectionDataModel *cnc, GdaVconnectionDataModelClass *klass);
static void gda_vconnection_data_model_dispose (GObject *object);
+
+enum {
+ VTABLE_CREATED,
+ VTABLE_DROPPED,
+ LAST_SIGNAL
+};
+
+static gint gda_vconnection_data_model_signals[LAST_SIGNAL] = { 0, 0 };
+
static GObjectClass *parent_class = NULL;
+#ifdef GDA_DEBUG
+static void
+dump_all_tables (GdaVconnectionDataModel *cnc)
+{
+ GSList *list;
+ g_print ("GdaVconnectionDataModel's tables:\n");
+ for (list = cnc->priv->table_data_list; list; list = list->next) {
+ GdaVConnectionTableData *td = (GdaVConnectionTableData *) list->data;
+ g_print (" table %s, td=%p, spec=%p\n", td->table_name, td, td->spec);
+ }
+}
+#endif
+
+static void
+vtable_created (GdaVconnectionDataModel *cnc, const gchar *table_name)
+{
+ _gda_connection_signal_meta_table_update ((GdaConnection *)cnc, table_name);
+#ifdef GDA_DEBUG
+ dump_all_tables (cnc);
+#endif
+}
+
+static void
+vtable_dropped (GdaVconnectionDataModel *cnc, const gchar *table_name)
+{
+ GdaVConnectionTableData *td;
+ td = gda_vconnection_get_table_data_by_name (cnc, table_name);
+ if (td)
+ cnc->priv->table_data_list = g_slist_remove (cnc->priv->table_data_list, td);
+ _gda_connection_signal_meta_table_update ((GdaConnection *)cnc, table_name);
+#ifdef GDA_DEBUG
+ dump_all_tables (cnc);
+#endif
+}
+
/*
* GdaVconnectionDataModel class implementation
*/
@@ -47,6 +92,40 @@ gda_vconnection_data_model_class_init (GdaVconnectionDataModelClass *klass)
parent_class = g_type_class_peek_parent (klass);
+ /**
+ * GdaVconnectionDataModel::vtable-created
+ * @cnc: the #GdaVconnectionDataModel connection
+ * @spec: the #GdaVconnectionDataModelSpec for the new virtual table
+ *
+ * Signal emitted when a new virtual table has been declared
+ */
+ gda_vconnection_data_model_signals[VTABLE_CREATED] =
+ g_signal_new ("vtable-created",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdaVconnectionDataModelClass, vtable_created),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+ /**
+ * GdaVconnectionDataModel::vtable-dropped
+ * @cnc: the #GdaVconnectionDataModel connection
+ * @spec: the #GdaVconnectionDataModelSpec for the new virtual table
+ *
+ * Signal emitted when a new virtual table has been undeclared
+ */
+ gda_vconnection_data_model_signals[VTABLE_DROPPED] =
+ g_signal_new ("vtable-dropped",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdaVconnectionDataModelClass, vtable_dropped),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ klass->vtable_created = vtable_created;
+ klass->vtable_dropped = vtable_dropped;
+
object_class->dispose = gda_vconnection_data_model_dispose;
}
@@ -122,7 +201,7 @@ spec_destroy_func (GdaVconnectionDataModelSpec *spec)
}
static GList *
-create_columns (GdaVconnectionDataModelSpec *spec, GError **error)
+create_columns (GdaVconnectionDataModelSpec *spec, G_GNUC_UNUSED GError **error)
{
g_return_val_if_fail (spec->data_model, NULL);
@@ -231,13 +310,13 @@ gda_vconnection_data_model_add (GdaVconnectionDataModel *cnc, GdaVconnectionData
td = g_new0 (GdaVConnectionTableData, 1);
td->spec = spec;
td->spec_free_func = spec_free_func;
- td->table_name = g_strdup (table_name);
+ td->table_name = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name);
td->unique_name = g_strdup_printf ("Spec%d", counter++);
cnc->priv->table_data_list = g_slist_append (cnc->priv->table_data_list, td);
/* actually create the virtual table in @cnc */
prov = (GdaVirtualProvider *) gda_connection_get_provider (GDA_CONNECTION (cnc));
- str = g_strdup_printf ("CREATE VIRTUAL TABLE %s USING %s ('%s')", table_name, G_OBJECT_TYPE_NAME (prov), td->unique_name);
+ str = g_strdup_printf ("CREATE VIRTUAL TABLE %s USING %s ('%s')", td->table_name, G_OBJECT_TYPE_NAME (prov), td->unique_name);
rc = SQLITE3_CALL (sqlite3_exec) (scnc->connection, str, NULL, 0, &zErrMsg);
g_free (str);
if (rc != SQLITE_OK) {
@@ -247,10 +326,11 @@ gda_vconnection_data_model_add (GdaVconnectionDataModel *cnc, GdaVconnectionData
cnc->priv->table_data_list = g_slist_remove (cnc->priv->table_data_list, td);
retval = FALSE;
}
- /*
- else
- g_print ("Virtual connection: added table %s (model = %p)\n", td->table_name, td->spec->data_model);
- */
+ else {
+ g_signal_emit (G_OBJECT (cnc), gda_vconnection_data_model_signals[VTABLE_CREATED], 0,
+ td->table_name);
+ /*g_print ("Virtual connection: added table %s (spec = %p)\n", td->table_name, td->spec);*/
+ }
return retval;
}
@@ -306,6 +386,8 @@ gda_vconnection_data_model_remove (GdaVconnectionDataModel *cnc, const gchar *ta
else {
/* clean the cnc->priv->table_data_list list */
cnc->priv->table_data_list = g_slist_remove (cnc->priv->table_data_list, td);
+ g_signal_emit (G_OBJECT (cnc), gda_vconnection_data_model_signals[VTABLE_DROPPED], 0,
+ td->table_name);
/*g_print ("Virtual connection: removed table %s (%p)\n", td->table_name, td->spec->data_model);*/
gda_vconnection_data_model_table_data_free (td);
return TRUE;
@@ -432,10 +514,17 @@ GdaVConnectionTableData *
gda_vconnection_get_table_data_by_name (GdaVconnectionDataModel *cnc, const gchar *table_name)
{
GSList *list;
+ gchar *quoted;
+ if (!table_name || !*table_name)
+ return NULL;
+ quoted = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name);
for (list = cnc->priv->table_data_list; list; list = list->next) {
- if (!strcmp (((GdaVConnectionTableData*) list->data)->table_name, table_name))
+ if (!strcmp (((GdaVConnectionTableData*) list->data)->table_name, quoted)) {
+ g_free (quoted);
return (GdaVConnectionTableData*) list->data;
+ }
}
+ g_free (quoted);
return NULL;
}
diff --git a/libgda/sqlite/virtual/gda-vconnection-data-model.h b/libgda/sqlite/virtual/gda-vconnection-data-model.h
index 381066b..a0aff97 100644
--- a/libgda/sqlite/virtual/gda-vconnection-data-model.h
+++ b/libgda/sqlite/virtual/gda-vconnection-data-model.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 - 2010 The GNOME Foundation.
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -185,9 +185,10 @@ struct _GdaVconnectionDataModel {
struct _GdaVconnectionDataModelClass {
GdaVirtualConnectionClass parent_class;
- /* Padding for future expansion */
- void (*_gda_reserved1) (void);
- void (*_gda_reserved2) (void);
+ void (*vtable_created) (GdaVconnectionDataModel *cnc,
+ const gchar *table_name);
+ void (*vtable_dropped) (GdaVconnectionDataModel *cnc,
+ const gchar *table_name);
};
GType gda_vconnection_data_model_get_type (void) G_GNUC_CONST;
diff --git a/libgda/sqlite/virtual/gda-vconnection-hub.c b/libgda/sqlite/virtual/gda-vconnection-hub.c
index efda161..06bc17e 100644
--- a/libgda/sqlite/virtual/gda-vconnection-hub.c
+++ b/libgda/sqlite/virtual/gda-vconnection-hub.c
@@ -768,6 +768,12 @@ dict_table_create_model_func (GdaVconnectionDataModelSpec *spec, int idxNum, con
g_assert (stmt);
}
GError *lerror = NULL;
+#ifdef GDA_DEBUG_NO
+ gchar *sql;
+ sql = gda_statement_to_sql (stmt, params, NULL);
+ g_print ("Executed: [%s]\n", sql);
+ g_free (sql);
+#endif
model = gda_connection_statement_execute_select_full (lspec->hc->cnc, stmt, params,
GDA_STATEMENT_MODEL_CURSOR_FORWARD, NULL,
&lerror);
diff --git a/libgda/sqlite/virtual/gda-virtual-connection.c b/libgda/sqlite/virtual/gda-virtual-connection.c
index 74eaebb..92c00a6 100644
--- a/libgda/sqlite/virtual/gda-virtual-connection.c
+++ b/libgda/sqlite/virtual/gda-virtual-connection.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 - 2010 The GNOME Foundation.
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -22,7 +22,6 @@
#include <glib/gi18n-lib.h>
#include <string.h>
-#include <sqlite3.h>
#include "gda-virtual-connection.h"
#include <gda-connection-private.h>
#include <libgda/gda-connection-internal.h>
diff --git a/libgda/sqlite/virtual/gda-vprovider-data-model.c b/libgda/sqlite/virtual/gda-vprovider-data-model.c
index 8b6f423..c5b4e3a 100644
--- a/libgda/sqlite/virtual/gda-vprovider-data-model.c
+++ b/libgda/sqlite/virtual/gda-vprovider-data-model.c
@@ -27,6 +27,7 @@
#include "gda-vconnection-data-model-private.h"
#include <sqlite3.h>
#include <libgda/gda-connection-private.h>
+#include <libgda/gda-connection-internal.h>
#include <libgda/gda-data-model-iter.h>
#include <libgda/gda-blob-op.h>
#include "../gda-sqlite.h"
@@ -51,6 +52,12 @@ static gboolean gda_vprovider_data_model_open_connection (GdaServerProvide
gpointer cb_data);
static gboolean gda_vprovider_data_model_close_connection (GdaServerProvider *provider,
GdaConnection *cnc);
+static GObject *gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types, GdaSet **last_inserted_row,
+ guint *task_id, GdaServerProviderExecCallback async_cb,
+ gpointer cb_data, GError **error);
static const gchar *gda_vprovider_data_model_get_name (GdaServerProvider *provider);
/*
@@ -68,6 +75,7 @@ gda_vprovider_data_model_class_init (GdaVproviderDataModelClass *klass)
server_class->create_connection = gda_vprovider_data_model_create_connection;
server_class->open_connection = gda_vprovider_data_model_open_connection;
server_class->close_connection = gda_vprovider_data_model_close_connection;
+ server_class->statement_execute = gda_vprovider_data_model_statement_execute;
server_class->get_name = gda_vprovider_data_model_get_name;
@@ -313,6 +321,73 @@ gda_vprovider_data_model_close_connection (GdaServerProvider *provider, GdaConne
return GDA_SERVER_PROVIDER_CLASS (parent_class)->close_connection (GDA_SERVER_PROVIDER (provider), cnc);
}
+static GObject *
+gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types, GdaSet **last_inserted_row,
+ guint *task_id, GdaServerProviderExecCallback async_cb,
+ gpointer cb_data, GError **error)
+{
+ GObject *retval;
+ if (async_cb) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Provider does not support asynchronous statement execution"));
+ return NULL;
+ }
+
+ retval = GDA_SERVER_PROVIDER_CLASS (parent_class)->statement_execute (provider, cnc, stmt, params,
+ model_usage, col_types,
+ last_inserted_row, task_id,
+ async_cb, cb_data, error);
+ if (retval) {
+ gchar *sql;
+ sql = gda_statement_to_sql (stmt, params, NULL);
+ if (sql) {
+ gchar *ptr = NULL;
+ /* look for DROP TABLE to signal table removal */
+ if (! g_ascii_strncasecmp (sql, "DROP", 4))
+ ptr = sql + 4;
+ else if (! g_ascii_strncasecmp (sql, "CREATE", 6))
+ ptr = sql + 6;
+ if (ptr) {
+ /* skip spaces */
+ for (; *ptr && (g_ascii_isspace (*ptr) || (*ptr == '\n')); ptr++);
+
+ if (! g_ascii_strncasecmp (ptr, "TABLE", 5)) {
+ /* skip spaces */
+ gchar delim = 0;
+ gchar *table_name, *quoted;
+ for (ptr = ptr+5;
+ *ptr && (g_ascii_isspace (*ptr) || (*ptr == '\n'));
+ ptr++);
+ if (*ptr == '\'') {
+ delim = '\'';
+ ptr++;
+ }
+ else if (*ptr == '"') {
+ delim = '"';
+ ptr++;
+ }
+ table_name = ptr;
+ if (delim)
+ for (; *ptr && (*ptr != delim) ; ptr++);
+ else
+ for (; *ptr && g_ascii_isalnum (*ptr); ptr++);
+ *ptr = 0;
+ quoted = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name);
+ /*g_print ("%s() emits the 'vtable-dropped' signal for table [%s]\n",
+ __FUNCTION__, quoted);*/
+ g_signal_emit_by_name (cnc, "vtable-dropped", quoted);
+ g_free (quoted);
+ }
+ }
+ g_free (sql);
+ }
+ }
+ return retval;
+}
+
static const gchar *
gda_vprovider_data_model_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]