[anjuta] symbol-db: added queries to get the scope chain of a symbol



commit 76db8a131d661dbdd7e89d9ce371742a909882da
Author: Massimo Corà <mcora src gnome org>
Date:   Tue Jul 21 23:50:43 2009 +0200

    symbol-db: added queries to get the scope chain of a symbol
    
    I needed to implement a particular GdaDataModelConcat object that'll accept multiple
    data models. This because it's not possible to get the scope chain in one go with a sql query.

 plugins/symbol-db/Makefile.am                      |    4 +-
 .../symbol-db/libgda-extra/gda-data-model-concat.c |  366 ++++++++++++++++++++
 .../symbol-db/libgda-extra/gda-data-model-concat.h |   62 ++++
 plugins/symbol-db/symbol-db-engine-iterator.c      |    4 +-
 plugins/symbol-db/symbol-db-engine-queries.c       |  262 ++++++++++-----
 plugins/symbol-db/symbol-db-engine-queries.h       |   23 ++
 plugins/symbol-db/test/Makefile.am                 |    6 +-
 plugins/symbol-db/test/benchmark.c                 |    2 -
 8 files changed, 641 insertions(+), 88 deletions(-)
---
diff --git a/plugins/symbol-db/Makefile.am b/plugins/symbol-db/Makefile.am
index 404080d..fc7ea7b 100644
--- a/plugins/symbol-db/Makefile.am
+++ b/plugins/symbol-db/Makefile.am
@@ -67,7 +67,9 @@ libanjuta_symbol_db_la_SOURCES = plugin.c plugin.h \
 	symbol-db-engine-core.c  symbol-db-engine-core.h \
 	symbol-db-engine.h  symbol-db-iface.c \
 	symbol-db-iface.h  symbol-db-search-command.h \
-	symbol-db-search-command.c
+	symbol-db-search-command.c \
+	libgda-extra/gda-data-model-concat.c \
+	libgda-extra/gda-data-model-concat.h
 
 libanjuta_symbol_db_la_LDFLAGS = $(ANJUTA_PLUGIN_LDFLAGS)
 
diff --git a/plugins/symbol-db/libgda-extra/gda-data-model-concat.c b/plugins/symbol-db/libgda-extra/gda-data-model-concat.c
new file mode 100644
index 0000000..8d2faed
--- /dev/null
+++ b/plugins/symbol-db/libgda-extra/gda-data-model-concat.c
@@ -0,0 +1,366 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) Massimo Cora' 2009 <maxcvs email it>
+ * 
+ * anjuta is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * anjuta is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gda-data-model-concat.h"
+
+/**
+ *
+ * An external user won't recognize that the GdaDataModel is composed
+ * by more than a GdaDataModel with the same structure (n_rows, n_cols etc)
+ *
+ * |------------------- GdaDataModel -------------------|    (external vision)
+ * |<----- ModelSlice 1 -----><----- ModelSlice 2 ----->|    (internal vision)
+ */
+
+/*
+ * I would rather present it as the following because each data model concatenated
+ * need to have the same number an types of columns, but can have any number of rows.
+ *
+ * col0 | col1  | ...   
+ * -----+-------+---------
+ * ...
+ * Rows from Slice 0
+ * ...
+ * -----+-------+---------
+ * ...
+ * Rows from Slice 1
+ * ...
+ * -----+-------+---------
+ * ...
+ * Rows from Slice N
+ * ...
+ *
+ */
+typedef struct _ModelSlice {
+	GdaDataModel *model;
+
+	/* In a general way these number represents the boundaries 
+	 * mapped on the GdaDataModel as seen from an external user. See ascii above.
+	 */
+	gint lower_bound;
+	gint upper_bound;
+	
+} ModelSlice;
+
+struct _GdaDataModelConcatPrivate {
+	
+	/* a list of ModelSlice(s) */
+	GList *slices;
+	ModelSlice *curr_model_slice;
+
+	/* num of records which is the total of the different models appended */
+	gint tot_items;
+};
+
+
+static GObjectClass *parent_class = NULL;
+
+
+static void
+gdm_concat_iface_impl_init (GdaDataModelIface *iface);
+
+static void
+gdm_concat_model_slice_destroy (ModelSlice *slice)
+{
+	g_object_unref (slice->model);
+	g_free (slice);
+}
+
+static void
+gdm_concat_init (GdaDataModelConcat *mconcat)
+{
+	g_return_if_fail (GDA_IS_DATA_MODEL_CONCAT (mconcat));
+	mconcat->priv = g_new0 (GdaDataModelConcatPrivate, 1);
+	mconcat->priv->slices = NULL;
+	mconcat->priv->curr_model_slice = NULL;
+	mconcat->priv->tot_items = 0;
+}
+
+static void
+gdm_concat_dispose (GObject *object)
+{
+	GdaDataModelConcat *mconcat = GDA_DATA_MODEL_CONCAT (object);
+	GdaDataModelConcatPrivate *priv;
+
+	priv = mconcat->priv;
+	
+	/* we'll just point curr_moodel_slice to NULL because it's already
+	 * in the slices list
+	 */
+	priv->curr_model_slice = NULL;
+	
+	GList *node = priv->slices;
+	while (node != NULL)
+	{
+		gdm_concat_model_slice_destroy ((ModelSlice*) node->data);
+
+		node = node->next;
+	}
+	
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gdm_concat_finalize (GObject *object)
+{
+	GdaDataModelConcat *mconcat = (GdaDataModelConcat *) object;
+	
+	/* free memory */
+	if (mconcat->priv) 
+	{
+		g_free (mconcat->priv);
+		mconcat->priv = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gdm_concat_class_init (GdaDataModelConcatClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = gdm_concat_dispose;	
+	object_class->finalize = gdm_concat_finalize;
+}
+
+/**
+ * gdm_concat_get_type
+ *
+ * Returns: the #GType of GdaDataModelConcat.
+ */
+GType
+gdm_concat_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static const GTypeInfo info = {
+			sizeof (GdaDataModelConcatClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gdm_concat_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaDataModelConcat),
+			0,
+			(GInstanceInitFunc) gdm_concat_init
+		};
+
+		static const GInterfaceInfo data_model_info = {
+			(GInterfaceInitFunc) gdm_concat_iface_impl_init,
+			NULL,
+			NULL
+		};
+
+		g_static_mutex_lock (&registering);
+		if (type == 0) {
+			type = g_type_register_static (G_TYPE_OBJECT, "GdaDataModelConcat", &info, 0);
+			g_type_add_interface_static (type, GDA_TYPE_DATA_MODEL, &data_model_info);
+		}
+		g_static_mutex_unlock (&registering);
+	}
+	return type;
+}
+
+static gint
+gdm_concat_get_n_rows (GdaDataModel *model)
+{
+	GdaDataModelConcat *mconcat = GDA_DATA_MODEL_CONCAT (model);
+	GdaDataModelConcatPrivate *priv;
+
+	g_return_val_if_fail (model != NULL, -1);
+
+	priv = mconcat->priv;
+
+	return priv->tot_items;	
+}
+
+static gint
+gdm_concat_get_n_columns (GdaDataModel *model)
+{
+	GdaDataModelConcat *mconcat = GDA_DATA_MODEL_CONCAT (model);
+	GdaDataModelConcatPrivate *priv;
+
+	g_return_val_if_fail (model != NULL, -1);
+
+	priv = mconcat->priv;
+
+	if (priv->curr_model_slice == NULL)
+	{
+		g_warning ("No model has been appended yet");
+		return -1;
+	}
+
+	return gda_data_model_get_n_columns (priv->curr_model_slice->model);
+}
+
+static GdaColumn *
+gdm_concat_describe_column (GdaDataModel *model, gint col)
+{
+	GdaDataModelConcat *mconcat = GDA_DATA_MODEL_CONCAT (model);
+	GdaDataModelConcatPrivate *priv;
+
+	g_return_val_if_fail (model != NULL, NULL);
+
+	priv = mconcat->priv;
+
+	if (priv->curr_model_slice == NULL)
+	{
+		g_warning ("No model has been appended yet");
+		return NULL;
+	}
+
+	return gda_data_model_describe_column (priv->curr_model_slice->model, col);
+}
+
+
+static gint
+gdm_concat_set_curr_slice_by_row_num (GdaDataModelConcat *mconcat, gint row)
+{	
+	GdaDataModelConcatPrivate *priv;
+	ModelSlice *found_slice = NULL;
+	
+	priv = mconcat->priv;
+
+	/* iterate and search for the correct slice (e.g. the one that suits the bounds) */
+	GList *node = priv->slices;
+	
+    while (node) 
+	{
+		ModelSlice *curr_slice = node->data;
+		
+    	if (curr_slice && row >= curr_slice->lower_bound && 
+		    row <= curr_slice->upper_bound)
+		{
+			found_slice = curr_slice;
+			break;
+		}
+      	node = g_list_next (node);
+    }
+
+	/* if not found it'll be set to NULL */
+	priv->curr_model_slice = found_slice;
+
+	/* if NULL return -1, otherwise return the relative row value */	 
+	return priv->curr_model_slice == NULL ? -1 : 
+		row - priv->curr_model_slice->lower_bound;
+}
+
+static const GValue * 
+gdm_concat_get_value_at (GdaDataModel *model, gint col, gint row, 
+    GError **error)
+{
+	GdaDataModelConcat *mconcat = GDA_DATA_MODEL_CONCAT (model);
+	GdaDataModelConcatPrivate *priv;
+	gint relative_row;
+
+	g_return_val_if_fail (model != NULL, NULL);
+
+	priv = mconcat->priv;
+	
+	if ( (relative_row = gdm_concat_set_curr_slice_by_row_num (mconcat, row)) < 0) 
+	{
+		/* maybe an array out of bound error occurred */
+		return NULL;
+	}
+	
+	return gda_data_model_get_value_at (priv->curr_model_slice->model, col, relative_row, 
+	    error);
+}
+
+static GdaDataModelAccessFlags
+gda_concat_get_access_flags (GdaDataModel *model)
+{
+	return GDA_DATA_MODEL_ACCESS_RANDOM;
+}
+
+static void
+gdm_concat_iface_impl_init (GdaDataModelIface *iface)
+{
+	iface->i_get_n_rows = gdm_concat_get_n_rows;
+	iface->i_get_n_columns = gdm_concat_get_n_columns;
+	iface->i_create_iter = NULL;	
+    
+	iface->i_get_value_at = gdm_concat_get_value_at;
+	iface->i_iter_at_row = NULL;
+	iface->i_iter_next = NULL;
+	iface->i_iter_prev = NULL;
+
+	iface->i_get_attributes_at = NULL;
+	iface->i_get_access_flags = gda_concat_get_access_flags;
+	iface->i_describe_column = gdm_concat_describe_column;
+	
+	iface->i_set_value_at = NULL;
+	iface->i_iter_set_value = NULL;
+	iface->i_set_values = NULL;
+    iface->i_append_values = NULL;
+	iface->i_append_row = NULL;
+	iface->i_remove_row = NULL;
+	iface->i_find_row = NULL;
+	
+	iface->i_set_notify = NULL;
+	iface->i_get_notify = NULL;
+	iface->i_send_hint = NULL;
+}
+
+GdaDataModel *
+gda_data_model_concat_new (void)
+{
+	GdaDataModelConcat *mconcat;
+
+	mconcat = g_object_new (GDA_TYPE_DATA_MODEL_CONCAT, NULL);
+
+	return GDA_DATA_MODEL (mconcat);
+}
+
+void 
+gda_data_model_concat_append_model (GdaDataModelConcat *mconcat, GdaDataModel *model)
+{
+	GdaDataModelConcatPrivate *priv;
+	gint new_model_rows;
+
+	g_return_if_fail (GDA_IS_DATA_MODEL_CONCAT (mconcat));
+	g_return_if_fail (GDA_IS_DATA_MODEL (model));
+
+	/* we want random access data models */
+	g_return_if_fail (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM);
+
+	priv = mconcat->priv;
+
+	/* get the n rows of the new model to be attached */
+	new_model_rows = gda_data_model_get_n_rows (model);
+	
+	ModelSlice *slice = g_new0 (ModelSlice, 1);
+	slice->model = g_object_ref (model);
+
+	slice->lower_bound = priv->tot_items;
+	slice->upper_bound = priv->tot_items + new_model_rows -1;
+	
+	/* append the new object to the list */
+	priv->slices = g_list_append (priv->slices, slice);
+
+	priv->tot_items += new_model_rows;
+
+	if (priv->curr_model_slice == NULL)
+		priv->curr_model_slice = slice;
+}    
+
diff --git a/plugins/symbol-db/libgda-extra/gda-data-model-concat.h b/plugins/symbol-db/libgda-extra/gda-data-model-concat.h
new file mode 100644
index 0000000..45183db
--- /dev/null
+++ b/plugins/symbol-db/libgda-extra/gda-data-model-concat.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) Massimo Cora' 2009 <maxcvs email it>
+ * 
+ * anjuta is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * anjuta is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GDA_DATA_MODEL_CONCAT_H_
+#define _GDA_DATA_MODEL_CONCAT_H_
+
+#include <libgda/gda-data-model.h>
+#include <libgda/gda-data-select.h>
+#include <libgda/gda-data-model-iter.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_DATA_MODEL_CONCAT             (gdm_concat_get_type ())
+#define GDA_DATA_MODEL_CONCAT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDA_TYPE_DATA_MODEL_CONCAT, GdaDataModelConcat))
+#define GDA_DATA_MODEL_CONCAT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GDA_TYPE_DATA_MODEL_CONCAT, GdaDataModelConcatClass))
+#define GDA_IS_DATA_MODEL_CONCAT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDA_TYPE_DATA_MODEL_CONCAT))
+#define GDA_IS_DATA_MODEL_CONCAT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_DATA_MODEL_CONCAT))
+#define GDA_DATA_MODEL_CONCAT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GDA_TYPE_DATA_MODEL_CONCAT, GdaDataModelConcatClass))
+
+typedef struct _GdaDataModelConcat 			GdaDataModelConcat;
+typedef struct _GdaDataModelConcatClass 	GdaDataModelConcatClass;
+typedef struct _GdaDataModelConcatPrivate 	GdaDataModelConcatPrivate;
+
+struct _GdaDataModelConcat
+{
+	GObject parent_instance;
+	GdaDataModelConcatPrivate *priv;
+};
+
+struct _GdaDataModelConcatClass
+{
+	GObjectClass parent_class;	
+};
+
+
+GType gdm_concat_get_type (void) G_GNUC_CONST;
+
+GdaDataModel *gda_data_model_concat_new (void);
+
+void gda_data_model_concat_append_model (GdaDataModelConcat *mconcat, 
+    										GdaDataModel *model);
+
+G_END_DECLS
+
+#endif /* _GDA_DATA_MODEL_CONCAT_H_ */
diff --git a/plugins/symbol-db/symbol-db-engine-iterator.c b/plugins/symbol-db/symbol-db-engine-iterator.c
index 5b4374b..b41154a 100644
--- a/plugins/symbol-db/symbol-db-engine-iterator.c
+++ b/plugins/symbol-db/symbol-db-engine-iterator.c
@@ -91,9 +91,9 @@ symbol_db_engine_iterator_new (GdaDataModel *model,
 	dbi = g_object_new (SYMBOL_TYPE_DB_ENGINE_ITERATOR, NULL);
 	priv = dbi->priv;
 	
-	priv->data_model = model;
+	priv->data_model = model;	
 	priv->data_iter = gda_data_model_create_iter (model);	
-
+	
 	/* because gda_data_model_get_n_rows () could be cpu-intensive, we'll 
 	 * proxy this value, e.g. it's calculated if it is really needed */
 	priv->total_rows = -1; 
diff --git a/plugins/symbol-db/symbol-db-engine-queries.c b/plugins/symbol-db/symbol-db-engine-queries.c
index e125026..bca3e9d 100644
--- a/plugins/symbol-db/symbol-db-engine-queries.c
+++ b/plugins/symbol-db/symbol-db-engine-queries.c
@@ -26,7 +26,7 @@
 
 #include "symbol-db-engine-queries.h"
 #include "symbol-db-engine-priv.h"
-
+#include "libgda-extra/gda-data-model-concat.h"
 
 /*
  * extern declarations 
@@ -1570,87 +1570,6 @@ symbol_db_engine_get_file_symbols (SymbolDBEngine *dbe,
 												priv->project_directory);	
 }
 
-SymbolDBEngineIterator *
-symbol_db_engine_get_symbol_info_by_id (SymbolDBEngine *dbe, 
-									gint sym_id, SymExtraInfo sym_info)
-{
-	SymbolDBEnginePriv *priv;
-	gchar *query_str;	
-	GdaDataModel *data;
-	GString *info_data;
-	GString *join_data;
-	GdaHolder *param;
-	const DynChildQueryNode *dyn_node;
-	GValue *ret_value;
-	gboolean ret_bool;
-	
-	
-	g_return_val_if_fail (dbe != NULL, NULL);
-	priv = dbe->priv;
-
-	SDB_LOCK(priv);
-
-	if ((dyn_node = sdb_engine_get_dyn_query_node_by_id (dbe, 
-		DYN_PREP_QUERY_GET_SYMBOL_INFO_BY_ID, sym_info, 0)) == NULL)
-	{
-		/* info_data contains the stuff after SELECT and befor FROM */
-		info_data = g_string_new ("");
-	
-		/* join_data contains the optionals joins to do to retrieve new data on other
-	 	 * tables.
-	 	 */
-		join_data = g_string_new ("");
-
-		/* fill info_data and join data with optional sql */
-		sdb_engine_prepare_symbol_info_sql (dbe, info_data, join_data, sym_info);
-	
-		query_str = g_strdup_printf ("SELECT symbol.symbol_id AS symbol_id, "
-			"symbol.name AS name, symbol.file_position AS file_position, "
-			"symbol.is_file_scope AS is_file_scope, symbol.signature AS signature, "
-		    "symbol.returntype AS returntype "
-			"%s FROM symbol "
-			"%s WHERE symbol.symbol_id = ## /* name:'symid' type:gint */", 
-									info_data->str, join_data->str);
-		
-		dyn_node = sdb_engine_insert_dyn_query_node_by_id (dbe, 
-						DYN_PREP_QUERY_GET_SYMBOL_INFO_BY_ID,
-						sym_info, 0,
-						query_str);
-		
-		g_free (query_str);
-		g_string_free (info_data, TRUE);
-		g_string_free (join_data, TRUE);	
-	}
-	
-	if ((param = gda_set_get_holder ((GdaSet*)dyn_node->plist, "symid")) == NULL)
-	{
-		SDB_UNLOCK(priv);
-		return NULL;
-	}
-	
-	MP_SET_HOLDER_BATCH_INT(priv, param, sym_id, ret_bool, ret_value);		
-	
-	/* execute the query with parametes just set */
-	data = gda_connection_statement_execute_select (priv->db_connection, 
-												  (GdaStatement*)dyn_node->stmt, 
-												  (GdaSet*)dyn_node->plist, NULL);
-	
-	if (!GDA_IS_DATA_MODEL (data) ||
-		gda_data_model_get_n_rows (data) <= 0)
-	{
-		if (data != NULL)
-			g_object_unref (data);
-		
-		SDB_UNLOCK(priv);
-		return NULL;
-	}
-	
-	SDB_UNLOCK(priv);
-	return (SymbolDBEngineIterator *)symbol_db_engine_iterator_new (data, 
-												priv->sym_type_conversion_hash,
-												priv->project_directory);	
-}
-
 #define DYN_FIND_SYMBOL_NAME_BY_PATTERN_EXTRA_PAR_EXACT_MATCH_YES			0x010000
 #define DYN_FIND_SYMBOL_NAME_BY_PATTERN_EXTRA_PAR_EXACT_MATCH_NO			0x020000
 
@@ -2028,6 +1947,185 @@ select * from symbol where scope_definition_id = (
 	return res;
 }
 
+/**
+ * On some queries we need to know the GdaDataModel instead of the iterator.
+ */
+static GdaDataModel *
+sdb_engine_get_symbol_info_by_id_1 (SymbolDBEngine *dbe, 
+									gint sym_id, SymExtraInfo sym_info)
+{
+	SymbolDBEnginePriv *priv;
+	gchar *query_str;	
+	GdaDataModel *data;
+	GString *info_data;
+	GString *join_data;
+	GdaHolder *param;
+	const DynChildQueryNode *dyn_node;
+	GValue *ret_value;
+	gboolean ret_bool;
+	
+		
+	priv = dbe->priv;
+
+	SDB_LOCK(priv);
+
+	if ((dyn_node = sdb_engine_get_dyn_query_node_by_id (dbe, 
+		DYN_PREP_QUERY_GET_SYMBOL_INFO_BY_ID, sym_info, 0)) == NULL)
+	{
+		/* info_data contains the stuff after SELECT and befor FROM */
+		info_data = g_string_new ("");
+	
+		/* join_data contains the optionals joins to do to retrieve new data on other
+	 	 * tables.
+	 	 */
+		join_data = g_string_new ("");
+
+		/* fill info_data and join data with optional sql */
+		sdb_engine_prepare_symbol_info_sql (dbe, info_data, join_data, sym_info);
+	
+		query_str = g_strdup_printf ("SELECT symbol.symbol_id AS symbol_id, "
+			"symbol.name AS name, symbol.file_position AS file_position, "
+			"symbol.is_file_scope AS is_file_scope, symbol.signature AS signature, "
+		    "symbol.returntype AS returntype "
+			"%s FROM symbol "
+			"%s WHERE symbol.symbol_id = ## /* name:'symid' type:gint */", 
+									info_data->str, join_data->str);
+
+		dyn_node = sdb_engine_insert_dyn_query_node_by_id (dbe, 
+						DYN_PREP_QUERY_GET_SYMBOL_INFO_BY_ID,
+						sym_info, 0,
+						query_str);
+		
+		g_free (query_str);
+		g_string_free (info_data, TRUE);
+		g_string_free (join_data, TRUE);	
+	}
+	
+	if ((param = gda_set_get_holder ((GdaSet*)dyn_node->plist, "symid")) == NULL)
+	{
+		SDB_UNLOCK(priv);
+		return NULL;
+	}
+	
+	MP_SET_HOLDER_BATCH_INT(priv, param, sym_id, ret_bool, ret_value);		
+	
+	/* execute the query with parameters just set */
+	data = gda_connection_statement_execute_select (priv->db_connection, 
+												  (GdaStatement*)dyn_node->stmt, 
+												  (GdaSet*)dyn_node->plist, NULL);
+	
+	if (!GDA_IS_DATA_MODEL (data) ||
+		gda_data_model_get_n_rows (data) <= 0)
+	{
+		if (data != NULL)
+			g_object_unref (data);
+		
+		SDB_UNLOCK(priv);
+		return NULL;
+	}
+	
+	SDB_UNLOCK(priv);
+	return data;
+}
+
+SymbolDBEngineIterator *
+symbol_db_engine_get_symbol_info_by_id (SymbolDBEngine *dbe, 
+									gint sym_id, SymExtraInfo sym_info)
+{
+	SymbolDBEnginePriv *priv;
+	GdaDataModel *data;
+
+	g_return_val_if_fail (dbe != NULL, NULL);
+	priv = dbe->priv;
+	
+	data = sdb_engine_get_symbol_info_by_id_1 (dbe, sym_id, sym_info);
+	return data == NULL ? NULL : 
+		(SymbolDBEngineIterator *)symbol_db_engine_iterator_new (data, 
+												priv->sym_type_conversion_hash,
+												priv->project_directory);	
+}
+
+SymbolDBEngineIterator *
+symbol_db_engine_get_scope_chain (SymbolDBEngine *dbe,
+    								gint scoped_symbol_id,
+    								const gchar* db_file,
+    								SymExtraInfo sym_info)
+{
+	SymbolDBEnginePriv *priv;
+	GdaDataModel *tmp_res_data = NULL;	
+	GdaDataModel *final_data;
+	gint parent_sym_id;
+	gint i;
+	
+	g_return_val_if_fail (dbe != NULL, NULL);
+	priv = dbe->priv;
+
+	/* use an hacked GdaDataModel that can receive multiple datamodels in sequence. 
+	 * This is necessary because unfortunately there's no way to retrieve the 
+	 * scopes in one go: the returned query would always order them by id and there's no way
+	 * to keep the results unsorted.
+	 */	 
+	final_data = gda_data_model_concat_new ();
+	
+	tmp_res_data = sdb_engine_get_symbol_info_by_id_1 (dbe, scoped_symbol_id, sym_info);
+	gda_data_model_concat_append_model (GDA_DATA_MODEL_CONCAT (final_data), 
+	    tmp_res_data);	
+	
+	/* no need to get a lock */
+	/* first item is considered separately */
+	parent_sym_id = symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe, 
+	    					scoped_symbol_id, db_file);
+	
+	if (parent_sym_id <= 0)
+	{
+		return NULL;
+	}
+
+	tmp_res_data = sdb_engine_get_symbol_info_by_id_1 (dbe, parent_sym_id, sym_info);
+
+	/* did something go wrong? */
+	if (!GDA_IS_DATA_MODEL (tmp_res_data) ||
+		gda_data_model_get_n_rows (GDA_DATA_MODEL (tmp_res_data)) <= 0	)
+	{
+		return NULL;
+	}
+
+	gda_data_model_concat_append_model (GDA_DATA_MODEL_CONCAT (final_data), 
+	    tmp_res_data);
+
+	/* a ref will be taken into the GdaDataModelConcat object so it's safe to 
+	 * unref here 
+	 */
+	g_object_unref (tmp_res_data);
+
+	/* we're ready for the big loop. The 100 is an infinite-loop protection. */
+	for (i = 0; i < 100; i++) 
+	{
+		/* get the parent scope */
+		parent_sym_id = symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe, 
+	    					parent_sym_id, db_file);
+		/* DEBUG_PRINT ("got parent symbol_id  %d", parent_sym_id); */
+		if (parent_sym_id <= 0)
+		{
+			break;
+		}
+		else 
+		{
+			tmp_res_data = sdb_engine_get_symbol_info_by_id_1 (dbe, parent_sym_id, 
+			    sym_info);
+
+			/* merge into the result data */
+			gda_data_model_concat_append_model (GDA_DATA_MODEL_CONCAT (final_data), 
+			    tmp_res_data);
+			g_object_unref (tmp_res_data);
+		}
+	}
+	
+	return (SymbolDBEngineIterator *)symbol_db_engine_iterator_new (final_data, 
+												priv->sym_type_conversion_hash,
+												priv->project_directory);
+}
+
 #define DYN_FIND_SYMBOL_BY_NAME_PATTERN_FILE_EXTRA_PAR_INCLUDE_KINDS_YES		0x010000
 #define DYN_FIND_SYMBOL_BY_NAME_PATTERN_FILE_EXTRA_PAR_INCLUDE_KINDS_NO			0x020000
 #define DYN_FIND_SYMBOL_BY_NAME_PATTERN_FILE_EXTRA_PAR_LIMIT					0x040000
diff --git a/plugins/symbol-db/symbol-db-engine-queries.h b/plugins/symbol-db/symbol-db-engine-queries.h
index fdfa55d..b5e0c0b 100644
--- a/plugins/symbol-db/symbol-db-engine-queries.h
+++ b/plugins/symbol-db/symbol-db-engine-queries.h
@@ -153,6 +153,29 @@ symbol_db_engine_get_parent_scope_id_by_symbol_id (SymbolDBEngine *dbe,
 									gint scoped_symbol_id,
 									const gchar* db_file);
 
+/**
+ * Walk the path up to the root scope given a scoped_symbol_id parameter.
+ * The returned iterator will be populated with SymbolDBEngineIteratorNode(s)
+ * so that it could be easily browsed by a client app.
+ *
+ * e.g.
+ * namespace FooBase {
+ * class FooKlass {
+ *	
+ * }
+ *
+ * void FooKlass::foo_func () {			<-------------- this is the scoped symbol
+ *              
+ * }
+ * 
+ * the returned iterator'll contain symbols in this order: foo_func, FooKlass, FooBase.
+ */
+SymbolDBEngineIterator *
+symbol_db_engine_get_scope_chain (SymbolDBEngine *dbe,
+    								gint scoped_symbol_id,
+    								const gchar* db_file,
+    								SymExtraInfo sym_info);
+
 /** 
  * scope_path cannot be NULL.
  * scope_path will be something like "scope1_kind", "scope1_name", "scope2_kind", 
diff --git a/plugins/symbol-db/test/Makefile.am b/plugins/symbol-db/test/Makefile.am
index dd56cae..29b1444 100644
--- a/plugins/symbol-db/test/Makefile.am
+++ b/plugins/symbol-db/test/Makefile.am
@@ -26,7 +26,11 @@ benchmark_SOURCES = \
 	../symbol-db-engine-iterator-node.c \
 	../symbol-db-engine-iterator-node.h \
 	../symbol-db-view.h \
-	../symbol-db-view.c
+	../symbol-db-view.c \
+	../symbol-db-engine-iterator.h \
+	../symbol-db-engine-queries.h \
+	../libgda-extra/gda-data-model-concat.c \
+	../libgda-extra/gda-data-model-concat.h
  
 
 benchmark_LDFLAGS = \
diff --git a/plugins/symbol-db/test/benchmark.c b/plugins/symbol-db/test/benchmark.c
index efd3860..af2a771 100644
--- a/plugins/symbol-db/test/benchmark.c
+++ b/plugins/symbol-db/test/benchmark.c
@@ -13,8 +13,6 @@ static void on_single_file_scan_end (SymbolDBEngine* engine, GPtrArray* files)
 
 static GPtrArray* get_files (const gchar* dir)
 {
-	GList* list = NULL;
-	GList* node;
 	GPtrArray* files = g_ptr_array_new();
 	GFile *file;
 	GFileEnumerator *enumerator;



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