symbol-db: Avoid warning when NULL is passed to sdb_engine_add_language()
[anjuta.git] / plugins / symbol-db / symbol-db-engine-core.c
blob746dbf16019bb68892a54fea42b8d62848ecb052
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) Massimo Cora' 2007-2009 <maxcvs@email.it>
5 *
6 * Some code from IComplete of Martin Stubenschrott <stubenschrott@gmx.net>
7 * has been used here.
9 * anjuta is free software.
11 * You may redistribute it and/or modify it under the terms of the
12 * GNU General Public License, as published by the Free Software
13 * Foundation; either version 2 of the License, or (at your option)
14 * any later version.
16 * anjuta is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with anjuta. If not, write to:
23 * The Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor
25 * Boston, MA 02110-1301, USA.
28 #include <time.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <signal.h>
34 #include <fcntl.h> /* For O_* constants */
35 #include <string.h>
36 #include <regex.h>
38 #include <gio/gio.h>
39 #include <libanjuta/interfaces/ianjuta-symbol.h>
40 #include <libanjuta/anjuta-debug.h>
41 #include <libanjuta/anjuta-launcher.h>
42 #include <libanjuta/anjuta-utils.h>
43 #include <libgda/libgda.h>
44 #include <sql-parser/gda-sql-parser.h>
45 #include "readtags.h"
46 #include "symbol-db-engine-priv.h"
47 #include "symbol-db-engine-core.h"
48 #include "symbol-db-engine-utils.h"
50 #include <glib/gprintf.h>
53 * utility macros
55 #define STATIC_QUERY_POPULATE_INIT_NODE(query_list_ptr, query_type, gda_stmt) { \
56 static_query_node *q = g_new0 (static_query_node, 1); \
57 q->query_id = query_type; \
58 q->query_str = gda_stmt; \
59 q->stmt = NULL; \
60 q->plist = NULL; \
61 query_list_ptr [query_type] = q; \
65 * typedefs
67 typedef struct _TableMapTmpHeritage {
68 gint symbol_referer_id;
69 gchar *field_inherits;
70 gchar *field_struct;
71 gchar *field_typeref;
72 gchar *field_enum;
73 gchar *field_union;
74 gchar *field_class;
75 gchar *field_namespace;
77 } TableMapTmpHeritage;
79 typedef struct _TableMapSymbol {
80 gint symbol_id;
81 gint file_defined_id;
82 gchar *name;
83 gint file_position;
84 gint is_file_scope;
85 gchar *signature;
86 gchar *returntype;
87 gint scope_definition_id;
88 gint scope_id;
89 gint type_id;
90 gint kind_id;
91 gint access_kind_id;
92 gint implementation_kind_id;
93 gint update_flag;
95 } TableMapSymbol;
97 typedef struct _EngineScanDataAsync {
98 GPtrArray *files_list;
99 GPtrArray *real_files_list;
100 gboolean symbols_update;
101 gint scan_id;
103 } EngineScanDataAsync;
106 typedef void (SymbolDBEngineCallback) (SymbolDBEngine * dbe,
107 gpointer user_data);
110 * signals enum
112 enum
114 DB_CONNECTED,
115 DB_DISCONNECTED,
116 SCAN_BEGIN,
117 SINGLE_FILE_SCAN_END,
118 SCAN_END,
119 SYMBOL_INSERTED,
120 SYMBOL_UPDATED,
121 SYMBOL_SCOPE_UPDATED,
122 SYMBOL_REMOVED,
123 LAST_SIGNAL
127 * enums
129 enum {
130 DO_UPDATE_SYMS = 1,
131 DO_UPDATE_SYMS_AND_EXIT,
132 DONT_UPDATE_SYMS,
133 DONT_UPDATE_SYMS_AND_EXIT,
134 DONT_FAKE_UPDATE_SYMS,
135 END_UPDATE_GROUP_SYMS
139 * structs used for callback data.
141 typedef struct _UpdateFileSymbolsData {
142 gchar *project;
143 gboolean update_prj_analyse_time;
144 GPtrArray * files_path;
146 } UpdateFileSymbolsData;
148 typedef struct _ScanFiles1Data {
149 SymbolDBEngine *dbe;
151 gchar *real_file; /* may be NULL. If not NULL must be freed */
152 gint partial_count;
153 gint files_list_len;
154 gint symbols_update;
156 } ScanFiles1Data;
159 * global file variables
161 static GObjectClass *parent_class = NULL;
162 static unsigned int signals[LAST_SIGNAL] = { 0 };
165 #ifdef DEBUG
166 static GTimer *sym_timer_DEBUG = NULL;
167 static gint tags_total_DEBUG = 0;
168 static gdouble elapsed_total_DEBUG = 0;
169 #endif
172 * forward declarations
174 static void
175 sdb_engine_second_pass_do (SymbolDBEngine * dbe);
177 static gint
178 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
179 int file_defined_id, gboolean sym_update);
181 GNUC_INLINE const GdaStatement *
182 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id);
184 GNUC_INLINE const GdaSet *
185 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id);
187 GNUC_INLINE gint
188 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
189 gchar * param_key,
190 GValue * param_value);
193 * implementation starts here
195 static GNUC_INLINE gint
196 sdb_engine_cache_lookup (GHashTable* hash_table, const gchar* lookup)
198 gpointer orig_key = NULL;
199 gpointer value = NULL;
201 /* avoiding lazy initialization may gain some cpu cycles. Just lookup here. */
202 if (g_hash_table_lookup_extended (hash_table,
203 lookup,
204 &orig_key,
205 &value))
207 gint table_id = GPOINTER_TO_INT (value);
208 return table_id;
210 return -1;
213 static GNUC_INLINE void
214 sdb_engine_insert_cache (GHashTable* hash_table, const gchar* key,
215 gint value)
217 g_hash_table_insert (hash_table, g_strdup (key),
218 GINT_TO_POINTER (value));
221 static void
222 sdb_engine_tablemap_tmp_heritage_destroy (TableMapTmpHeritage *node)
224 g_free (node->field_inherits);
225 g_free (node->field_struct);
226 g_free (node->field_typeref);
227 g_free (node->field_enum);
228 g_free (node->field_union);
229 g_free (node->field_class);
230 g_free (node->field_namespace);
232 g_slice_free (TableMapTmpHeritage, node);
235 static void
236 sdb_engine_scan_data_destroy (gpointer data)
238 EngineScanDataAsync *esda = (EngineScanDataAsync *)data;
240 g_ptr_array_unref (esda->files_list);
241 if (esda->real_files_list)
242 g_ptr_array_unref (esda->real_files_list);
244 g_free (esda);
247 static void
248 sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
250 SymbolDBEnginePriv *priv = dbe->priv;
251 if (priv->tmp_heritage_tablemap)
253 TableMapTmpHeritage *node;
254 while ((node = g_queue_pop_head (priv->tmp_heritage_tablemap)) != NULL)
256 sdb_engine_tablemap_tmp_heritage_destroy (node);
259 /* queue should be void. Free it */
260 g_queue_free (priv->tmp_heritage_tablemap);
261 priv->tmp_heritage_tablemap = NULL;
265 static void
266 sdb_engine_clear_caches (SymbolDBEngine* dbe)
268 SymbolDBEnginePriv *priv = dbe->priv;
269 if (priv->kind_cache)
270 g_hash_table_destroy (priv->kind_cache);
271 if (priv->access_cache)
272 g_hash_table_destroy (priv->access_cache);
273 if (priv->implementation_cache)
274 g_hash_table_destroy (priv->implementation_cache);
275 if (priv->language_cache)
276 g_hash_table_destroy (priv->language_cache);
278 priv->kind_cache = NULL;
279 priv->access_cache = NULL;
280 priv->implementation_cache = NULL;
281 priv->language_cache = NULL;
284 static void
285 sdb_engine_init_table_maps (SymbolDBEngine *dbe)
287 SymbolDBEnginePriv *priv = dbe->priv;
289 /* tmp_heritage_tablemap */
290 priv->tmp_heritage_tablemap = g_queue_new ();
293 static void
294 sdb_engine_init_caches (SymbolDBEngine* dbe)
296 SymbolDBEnginePriv *priv = dbe->priv;
297 priv->kind_cache = g_hash_table_new_full (g_str_hash,
298 g_str_equal,
299 g_free,
300 NULL);
302 priv->access_cache = g_hash_table_new_full (g_str_hash,
303 g_str_equal,
304 g_free,
305 NULL);
307 priv->implementation_cache = g_hash_table_new_full (g_str_hash,
308 g_str_equal,
309 g_free,
310 NULL);
312 priv->language_cache = g_hash_table_new_full (g_str_hash,
313 g_str_equal,
314 g_free,
315 NULL);
318 /* ~~~ Thread note: this function locks the mutex ~~~ */
319 static gboolean
320 sdb_engine_execute_unknown_sql (SymbolDBEngine *dbe, const gchar *sql)
322 GdaStatement *stmt;
323 GObject *res;
324 SymbolDBEnginePriv *priv;
326 priv = dbe->priv;
328 SDB_LOCK(priv);
329 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, NULL, NULL);
331 if (stmt == NULL)
333 SDB_UNLOCK(priv);
334 return FALSE;
337 if ((res = gda_connection_statement_execute (priv->db_connection,
338 (GdaStatement*)stmt,
339 NULL,
340 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
341 NULL, NULL)) == NULL)
343 g_object_unref (stmt);
344 SDB_UNLOCK(priv);
345 return FALSE;
347 else
349 g_object_unref (res);
350 g_object_unref (stmt);
351 SDB_UNLOCK(priv);
352 return TRUE;
356 static GdaDataModel *
357 sdb_engine_execute_select_sql (SymbolDBEngine * dbe, const gchar *sql)
359 GdaStatement *stmt;
360 GdaDataModel *res;
361 SymbolDBEnginePriv *priv;
362 const gchar *remain;
364 priv = dbe->priv;
366 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, &remain, NULL);
368 if (stmt == NULL)
369 return NULL;
371 res = gda_connection_statement_execute_select (priv->db_connection,
372 (GdaStatement*)stmt, NULL, NULL);
373 if (!res)
374 DEBUG_PRINT ("Could not execute query: %s\n", sql);
376 if (remain != NULL)
378 /* this shouldn't never happen */
379 sdb_engine_execute_select_sql (dbe, remain);
382 g_object_unref (stmt);
384 return res;
387 static gint
388 sdb_engine_execute_non_select_sql (SymbolDBEngine * dbe, const gchar *sql)
390 GdaStatement *stmt;
391 gint nrows;
392 SymbolDBEnginePriv *priv;
393 const gchar *remain;
395 priv = dbe->priv;
396 stmt = gda_sql_parser_parse_string (priv->sql_parser,
397 sql, &remain, NULL);
399 if (stmt == NULL)
400 return -1;
402 nrows = gda_connection_statement_execute_non_select (priv->db_connection, stmt,
403 NULL, NULL, NULL);
404 if (remain != NULL) {
405 /* may happen for example when sql is a file-content */
406 sdb_engine_execute_non_select_sql (dbe, remain);
409 g_object_unref (stmt);
410 return nrows;
414 * ### Thread note: this function inherits the mutex lock ###
416 * Use a proxy to return an already present or a fresh new prepared query
417 * from static 'query_list'. We should perform actions in the fastest way, because
418 * these queries are time-critical.
419 * A GdaSet will also be populated once, avoiding so to create again later on.
421 GNUC_INLINE const GdaStatement *
422 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id)
424 static_query_node *node;
425 SymbolDBEnginePriv *priv;
427 priv = dbe->priv;
429 /* no way: if connection is NULL we will break here. There must be
430 * a connection established to db before using this function */
431 /*g_return_val_if_fail (priv->db_connection != NULL, NULL);*/
433 if ((node = priv->static_query_list[query_id]) == NULL)
434 return NULL;
436 if (node->stmt == NULL)
438 GError *error = NULL;
440 /* create a new GdaStatement */
441 node->stmt =
442 gda_sql_parser_parse_string (priv->sql_parser, node->query_str, NULL,
443 &error);
445 if (error)
447 g_warning ("%s", error->message);
448 g_error_free (error);
449 return NULL;
452 if (gda_statement_get_parameters ((GdaStatement*)node->stmt,
453 &node->plist, NULL) == FALSE)
455 g_warning ("Error on getting parameters for %d", query_id);
459 return node->stmt;
463 * ### Thread note: this function inherits the mutex lock ###
465 * Return a GdaSet of parameters calculated from the statement. It does not check
466 * if it's null. You *must* be sure to have called sdb_engine_get_statement_by_query_id () first.
468 GNUC_INLINE const GdaSet *
469 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id)
471 SymbolDBEnginePriv *priv;
473 priv = dbe->priv;
475 static_query_node *node;
476 node = priv->static_query_list[query_id];
477 return node->plist;
481 * Clear the static cached queries data. You should call this function when closing/
482 * destroying SymbolDBEngine object.
484 static void
485 sdb_engine_free_cached_queries (SymbolDBEngine *dbe)
487 SymbolDBEnginePriv *priv;
488 gint i;
489 static_query_node *node;
491 priv = dbe->priv;
493 for (i = 0; i < PREP_QUERY_COUNT; i++)
495 node = priv->static_query_list[i];
497 if (node != NULL && node->stmt != NULL)
499 /*DEBUG_PRINT ("sdb_engine_free_cached_queries stmt %d", i);*/
500 g_object_unref (node->stmt);
501 node->stmt = NULL;
504 if (node != NULL && node->plist != NULL)
506 /*DEBUG_PRINT ("sdb_engine_free_cached_queries plist %d", i);*/
507 g_object_unref (node->plist);
508 node->plist = NULL;
511 /* last but not the least free the node itself */
512 g_free (node);
513 priv->static_query_list[i] = NULL;
517 static gboolean
518 sdb_engine_disconnect_from_db (SymbolDBEngine * dbe)
520 SymbolDBEnginePriv *priv;
522 g_return_val_if_fail (dbe != NULL, FALSE);
523 priv = dbe->priv;
525 DEBUG_PRINT ("VACUUM command issued on %s", priv->cnc_string);
526 sdb_engine_execute_non_select_sql (dbe, "VACUUM");
528 DEBUG_PRINT ("Disconnecting from %s", priv->cnc_string);
529 g_free (priv->cnc_string);
530 priv->cnc_string = NULL;
532 if (priv->db_connection != NULL)
533 gda_connection_close (priv->db_connection);
534 priv->db_connection = NULL;
536 if (priv->sql_parser != NULL)
537 g_object_unref (priv->sql_parser);
538 priv->sql_parser = NULL;
540 return TRUE;
544 * ### Thread note: this function inherits the mutex lock ###
546 * @return -1 on error. Otherwise the id of tuple.
548 GNUC_INLINE gint
549 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
550 gchar * param_key,
551 GValue * param_value)
553 const GdaSet *plist;
554 const GdaStatement *stmt;
555 GdaHolder *param;
556 GdaDataModel *data_model;
557 const GValue *num;
558 gint table_id;
559 SymbolDBEnginePriv *priv;
561 priv = dbe->priv;
563 /* get prepared query */
564 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
566 g_warning ("Query is null");
567 return -1;
570 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
572 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key)) == NULL)
574 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
575 "from pquery!\n");
576 return -1;
579 gda_holder_set_value (param, param_value, NULL);
581 /* execute the query with parameters just set */
582 data_model = gda_connection_statement_execute_select (priv->db_connection,
583 (GdaStatement*)stmt,
584 (GdaSet*)plist, NULL);
586 if (!GDA_IS_DATA_MODEL (data_model) ||
587 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
589 if (data_model != NULL)
590 g_object_unref (data_model);
591 return -1;
594 /* get and parse the results. */
595 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
597 table_id = g_value_get_int (num);
598 g_object_unref (data_model);
600 /* set the value to a dummy string because we won't use the real value anymore */
601 return table_id;
604 /* ### Thread note: this function inherits the mutex lock ### */
605 static GNUC_INLINE gint
606 sdb_engine_get_tuple_id_by_unique_name4 (SymbolDBEngine * dbe,
607 static_query_type qtype,
608 gchar * param_key1,
609 GValue * value1,
610 gchar * param_key2,
611 GValue * value2,
612 gchar * param_key3,
613 GValue * value3,
614 gchar * param_key4,
615 GValue * value4)
617 const GdaSet *plist;
618 const GdaStatement *stmt;
619 GdaHolder *param;
620 GdaDataModel *data_model;
621 const GValue *num;
622 gint table_id;
623 SymbolDBEnginePriv *priv;
625 priv = dbe->priv;
627 /* get prepared query */
628 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
630 g_warning ("Query is null");
631 return -1;
634 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
636 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key1)) == NULL)
638 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: param is NULL "
639 "from pquery!\n");
640 return -1;
643 gda_holder_set_value (param, value1, NULL);
645 /* ...and the second one */
646 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key2)) == NULL)
648 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
649 "param is NULL from pquery!");
650 return -1;
653 gda_holder_set_value (param, value2, NULL);
655 /* ...and the third one */
656 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key3)) == NULL)
658 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
659 "param is NULL from pquery!");
660 return -1;
663 gda_holder_set_value (param, value3, NULL);
665 /* ...and the fourth one */
666 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key4)) == NULL)
668 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
669 "param is NULL from pquery!");
670 return -1;
673 gda_holder_set_value (param, value4, NULL);
675 /* execute the query with parameters just set */
676 data_model = gda_connection_statement_execute_select (priv->db_connection,
677 (GdaStatement*)stmt,
678 (GdaSet*)plist, NULL);
680 if (!GDA_IS_DATA_MODEL (data_model) ||
681 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
683 if (data_model != NULL)
684 g_object_unref (data_model);
686 return -1;
689 /* get and parse the results. */
690 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
692 table_id = g_value_get_int (num);
693 g_object_unref (data_model);
694 return table_id;
697 /** ### Thread note: this function inherits the mutex lock ### */
698 static int
699 sdb_engine_get_file_defined_id (SymbolDBEngine* dbe,
700 const gchar* base_prj_path,
701 const gchar* fake_file_on_db,
702 tagEntry* tag_entry)
704 GValue v = {0};
706 gint file_defined_id = 0;
707 if (base_prj_path != NULL && g_str_has_prefix (tag_entry->file, base_prj_path))
709 /* in this case fake_file will be ignored. */
711 /* we expect here an absolute path */
712 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file + strlen (base_prj_path));
714 else
716 /* check whether the fake_file can substitute the tag_entry->file one */
717 if (fake_file_on_db == NULL)
719 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file);
721 else
723 SDB_GVALUE_SET_STATIC_STRING(v, fake_file_on_db);
727 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
728 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
729 "filepath",
730 &v)) < 0)
732 /* if we arrive here there should be some sync problems between the filenames
733 * in database and the ones in the ctags files. We trust in db's ones,
734 * so we'll just return here.
736 g_warning ("sync problems between db and ctags filenames entries. "
737 "File was %s (base_path: %s, fake_file: %s, tag_file: %s)",
738 g_value_get_string (&v), base_prj_path, fake_file_on_db,
739 tag_entry->file);
740 return -1;
743 return file_defined_id;
747 * ### Thread note: this function inherits the mutex lock ###
749 * If fake_file is != NULL we claim and assert that tags contents which are
750 * scanned belong to the fake_file in the project.
751 * More: the fake_file refers to just one single file and cannot be used
752 * for multiple fake_files.
754 static void
755 sdb_engine_populate_db_by_tags (SymbolDBEngine * dbe, FILE* fd,
756 gchar * fake_file_on_db,
757 gboolean force_sym_update)
759 tagFile *tag_file;
760 tagFileInfo tag_file_info;
761 tagEntry tag_entry;
762 gint file_defined_id_cache = 0;
763 gchar* tag_entry_file_cache = NULL;
765 SymbolDBEnginePriv *priv = dbe->priv;
767 gchar* base_prj_path = fake_file_on_db == NULL ?
768 priv->project_directory : NULL;
770 g_return_if_fail (dbe != NULL);
772 g_return_if_fail (priv->db_connection != NULL);
773 g_return_if_fail (fd != NULL);
775 if ((tag_file = tagsOpen_1 (fd, &tag_file_info)) == NULL)
777 g_warning ("error in opening ctags file");
780 #ifdef DEBUG
781 if (sym_timer_DEBUG == NULL)
782 sym_timer_DEBUG = g_timer_new ();
783 else
784 g_timer_reset (sym_timer_DEBUG);
785 gint tags_num_DEBUG = 0;
786 #endif
787 tag_entry.file = NULL;
789 while (tagsNext (tag_file, &tag_entry) != TagFailure)
791 gint file_defined_id = 0;
792 if (tag_entry.file == NULL)
794 continue;
796 if (file_defined_id_cache > 0)
798 if (g_str_equal (tag_entry.file, tag_entry_file_cache))
800 file_defined_id = file_defined_id_cache;
803 if (file_defined_id == 0)
805 file_defined_id = sdb_engine_get_file_defined_id (dbe,
806 base_prj_path,
807 fake_file_on_db,
808 &tag_entry);
809 file_defined_id_cache = file_defined_id;
810 g_free (tag_entry_file_cache);
811 tag_entry_file_cache = g_strdup (tag_entry.file);
814 if (priv->symbols_scanned_count++ % BATCH_SYMBOL_NUMBER == 0)
816 GError *error = NULL;
818 /* if we aren't at the first cycle then we can commit the transaction */
819 if (priv->symbols_scanned_count > 1)
821 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
822 &error);
824 if (error)
826 DEBUG_PRINT ("err: %s", error->message);
827 g_error_free (error);
828 error = NULL;
832 gda_connection_begin_transaction (priv->db_connection, "symboltrans",
833 GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, &error);
835 if (error)
837 DEBUG_PRINT ("err: %s", error->message);
838 g_error_free (error);
839 error = NULL;
843 /* insert or update a symbol */
844 sdb_engine_add_new_symbol (dbe, &tag_entry, file_defined_id,
845 force_sym_update);
846 #ifdef DEBUG
847 tags_num_DEBUG++;
848 #endif
849 tag_entry.file = NULL;
851 g_free (tag_entry_file_cache);
854 #ifdef DEBUG
855 gdouble elapsed_DEBUG = g_timer_elapsed (sym_timer_DEBUG, NULL);
856 tags_total_DEBUG += tags_num_DEBUG;
857 elapsed_total_DEBUG += elapsed_DEBUG;
858 /* DEBUG_PRINT ("elapsed: %f for (%d) [%f sec/symbol] [av %f sec/symbol]", elapsed_DEBUG,
859 tags_num_DEBUG, elapsed_DEBUG / tags_num_DEBUG,
860 elapsed_total_DEBUG / tags_total_DEBUG);
862 #endif
864 /* notify listeners that another file has been scanned */
865 DBESignal *dbesig = g_slice_new0 (DBESignal);
866 dbesig->value = GINT_TO_POINTER (SINGLE_FILE_SCAN_END +1);
867 dbesig->process_id = priv->current_scan_process_id;
869 g_async_queue_push (priv->signals_aqueue, dbesig);
871 /* we've done with tag_file but we don't need to tagsClose (tag_file); */
874 /* ~~~ Thread note: this function locks the mutex ~~~ */
875 static void
876 sdb_engine_ctags_output_thread (gpointer data, gpointer user_data)
878 gint len_chars;
879 gchar *chars, *chars_ptr;
880 gint remaining_chars;
881 gint len_marker;
882 SymbolDBEnginePriv *priv;
883 SymbolDBEngine *dbe;
885 chars = chars_ptr = (gchar *)data;
886 dbe = SYMBOL_DB_ENGINE (user_data);
888 g_return_if_fail (dbe != NULL);
889 g_return_if_fail (chars_ptr != NULL);
891 priv = dbe->priv;
893 SDB_LOCK(priv);
895 remaining_chars = len_chars = strlen (chars_ptr);
896 len_marker = strlen (CTAGS_MARKER);
898 /*DEBUG_PRINT ("program output [new version]: ==>%s<==", chars);*/
899 if (len_chars >= len_marker)
901 gchar *marker_ptr = NULL;
902 gint tmp_str_length = 0;
904 /* is it an end file marker? */
905 marker_ptr = strstr (chars_ptr, CTAGS_MARKER);
909 if (marker_ptr != NULL)
911 int scan_flag;
912 gchar *real_file;
914 /* set the length of the string parsed */
915 tmp_str_length = marker_ptr - chars_ptr;
917 /* write to shm_file all the chars_ptr received without the marker ones */
918 fwrite (chars_ptr, sizeof(gchar), tmp_str_length, priv->shared_mem_file);
920 chars_ptr = marker_ptr + len_marker;
921 remaining_chars -= (tmp_str_length + len_marker);
922 fflush (priv->shared_mem_file);
924 /* get the scan flag from the queue. We need it to know whether
925 * an update of symbols must be done or not */
926 DBESignal *dbesig = g_async_queue_try_pop (priv->scan_aqueue);
927 scan_flag = GPOINTER_TO_INT(dbesig->value);
928 g_slice_free (DBESignal, dbesig);
930 dbesig = g_async_queue_try_pop (priv->scan_aqueue);
931 real_file = dbesig->value;
932 g_slice_free (DBESignal, dbesig);
934 /* and now call the populating function */
935 if (scan_flag == DO_UPDATE_SYMS ||
936 scan_flag == DO_UPDATE_SYMS_AND_EXIT)
938 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
939 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
940 TRUE);
942 else
944 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
945 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
946 FALSE);
949 /* don't forget to free the real_file, if it's a char */
950 if ((gsize)real_file != DONT_FAKE_UPDATE_SYMS)
951 g_free (real_file);
953 /* check also if, together with an end file marker, we have an
954 * end group-of-files end marker.
956 if (scan_flag == DO_UPDATE_SYMS_AND_EXIT ||
957 scan_flag == DONT_UPDATE_SYMS_AND_EXIT )
959 gint tmp_inserted;
960 gint tmp_updated;
962 /* scan has ended. Go go with second step. */
963 DEBUG_PRINT ("%s", "FOUND end-of-group-files marker.");
965 chars_ptr += len_marker;
966 remaining_chars -= len_marker;
968 /* will emit symbol_scope_updated and will flush on disk
969 * tablemaps
971 sdb_engine_second_pass_do (dbe);
973 /* Here we are. It's the right time to notify the listeners
974 * about out fresh new inserted/updated symbols...
975 * Go on by emitting them.
977 while ((tmp_inserted = GPOINTER_TO_INT(
978 g_async_queue_try_pop (priv->inserted_syms_id_aqueue))) > 0)
980 /* we must be sure to insert both signals at once */
981 g_async_queue_lock (priv->signals_aqueue);
983 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
984 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
986 dbesig1->value = GINT_TO_POINTER (SYMBOL_INSERTED + 1);
987 dbesig1->process_id = priv->current_scan_process_id;
989 dbesig2->value = GINT_TO_POINTER (tmp_inserted);
990 dbesig2->process_id = priv->current_scan_process_id;
992 g_async_queue_push_unlocked (priv->signals_aqueue,
993 dbesig1);
994 g_async_queue_push_unlocked (priv->signals_aqueue,
995 dbesig2);
997 g_async_queue_unlock (priv->signals_aqueue);
1000 while ((tmp_updated = GPOINTER_TO_INT(
1001 g_async_queue_try_pop (priv->updated_syms_id_aqueue))) > 0)
1003 g_async_queue_lock (priv->signals_aqueue);
1005 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1006 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1008 dbesig1->value = GINT_TO_POINTER (SYMBOL_UPDATED + 1);
1009 dbesig1->process_id = priv->current_scan_process_id;
1011 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1012 dbesig2->process_id = priv->current_scan_process_id;
1014 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1015 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1016 g_async_queue_unlock (priv->signals_aqueue);
1019 while ((tmp_updated = GPOINTER_TO_INT(
1020 g_async_queue_try_pop (priv->updated_scope_syms_id_aqueue))) > 0)
1022 g_async_queue_lock (priv->signals_aqueue);
1024 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1025 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1027 dbesig1->value = GINT_TO_POINTER (SYMBOL_SCOPE_UPDATED + 1);
1028 dbesig1->process_id = priv->current_scan_process_id;
1030 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1031 dbesig2->process_id = priv->current_scan_process_id;
1033 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1034 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1035 g_async_queue_unlock (priv->signals_aqueue);
1038 #ifdef DEBUG
1039 if (priv->first_scan_timer_DEBUG != NULL)
1041 DEBUG_PRINT ("~~~~~ TOTAL FIRST SCAN elapsed: %f ",
1042 g_timer_elapsed (priv->first_scan_timer_DEBUG, NULL));
1043 g_timer_destroy (priv->first_scan_timer_DEBUG);
1044 priv->first_scan_timer_DEBUG = NULL;
1046 #endif
1048 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1050 dbesig1->value = GINT_TO_POINTER (SCAN_END + 1);
1051 dbesig1->process_id = priv->current_scan_process_id;
1053 g_async_queue_push (priv->signals_aqueue, dbesig1);
1056 /* truncate the file to 0 length */
1057 ftruncate (priv->shared_mem_fd, 0);
1059 else
1061 /* marker_ptr is NULL here. We should then exit the loop. */
1062 /* write to shm_file all the chars received */
1063 fwrite (chars_ptr, sizeof(gchar), remaining_chars,
1064 priv->shared_mem_file);
1066 fflush (priv->shared_mem_file);
1067 break;
1070 /* found out a new marker */
1071 marker_ptr = strstr (marker_ptr + len_marker, CTAGS_MARKER);
1072 } while (remaining_chars + len_marker < len_chars || marker_ptr != NULL);
1075 SDB_UNLOCK(priv);
1077 g_free (chars);
1082 * This function runs on the main glib thread, so that it can safely spread signals
1084 static gboolean
1085 sdb_engine_timeout_trigger_signals (gpointer user_data)
1087 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1088 SymbolDBEnginePriv *priv;
1090 g_return_val_if_fail (user_data != NULL, FALSE);
1091 priv = dbe->priv;
1093 if (priv->signals_aqueue != NULL &&
1094 g_async_queue_length (priv->signals_aqueue) > 0)
1096 DBESignal *dbesig;
1097 gsize real_signal;
1098 gint process_id;
1100 while (priv->signals_aqueue != NULL &&
1101 (dbesig = g_async_queue_try_pop (priv->signals_aqueue)) != NULL)
1103 if (dbesig == NULL)
1105 return g_async_queue_length (priv->signals_aqueue) > 0 ? TRUE : FALSE;
1108 real_signal = GPOINTER_TO_INT (dbesig->value) -1;
1109 process_id = dbesig->process_id;
1111 switch (real_signal)
1113 case SINGLE_FILE_SCAN_END:
1115 g_signal_emit (dbe, signals[SINGLE_FILE_SCAN_END], 0);
1117 break;
1119 case SCAN_BEGIN:
1121 DEBUG_PRINT ("%s", "EMITTING scan begin.");
1122 g_signal_emit (dbe, signals[SCAN_BEGIN], 0, process_id);
1124 break;
1126 case SCAN_END:
1128 /* reset count */
1129 priv->symbols_scanned_count = 0;
1131 DEBUG_PRINT ("Committing symboltrans transaction...");
1132 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
1133 NULL);
1134 DEBUG_PRINT ("... Done!");
1136 /* perform flush on db of the tablemaps, if this is the 1st scan */
1137 if (priv->is_first_population == TRUE)
1139 /* ok, set the flag to false. We're done with it */
1140 priv->is_first_population = FALSE;
1143 priv->is_scanning = FALSE;
1145 DEBUG_PRINT ("%s", "EMITTING scan-end");
1146 g_signal_emit (dbe, signals[SCAN_END], 0, process_id);
1148 break;
1150 case SYMBOL_INSERTED:
1152 DBESignal *dbesig2;
1154 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1155 g_signal_emit (dbe, signals[SYMBOL_INSERTED], 0, dbesig2->value);
1157 g_slice_free (DBESignal, dbesig2);
1159 break;
1161 case SYMBOL_UPDATED:
1163 DBESignal *dbesig2;
1165 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1166 g_signal_emit (dbe, signals[SYMBOL_UPDATED], 0, dbesig2->value);
1168 g_slice_free (DBESignal, dbesig2);
1170 break;
1172 case SYMBOL_SCOPE_UPDATED:
1174 DBESignal *dbesig2;
1176 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1177 g_signal_emit (dbe, signals[SYMBOL_SCOPE_UPDATED], 0, dbesig2->value);
1179 g_slice_free (DBESignal, dbesig2);
1181 break;
1183 case SYMBOL_REMOVED:
1185 DBESignal *dbesig2;
1187 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1188 g_signal_emit (dbe, signals[SYMBOL_REMOVED], 0, dbesig2->value);
1190 g_slice_free (DBESignal, dbesig2);
1192 break;
1195 g_slice_free (DBESignal, dbesig);
1197 /* reset to 0 the retries */
1198 priv->trigger_closure_retries = 0;
1200 else {
1201 priv->trigger_closure_retries++;
1204 if (priv->thread_pool != NULL &&
1205 g_thread_pool_unprocessed (priv->thread_pool) == 0 &&
1206 g_thread_pool_get_num_threads (priv->thread_pool) == 0)
1208 /* remove the trigger coz we don't need it anymore... */
1209 g_source_remove (priv->timeout_trigger_handler);
1210 priv->timeout_trigger_handler = 0;
1211 return FALSE;
1214 return TRUE;
1217 static void
1218 sdb_engine_ctags_output_callback_1 (AnjutaLauncher * launcher,
1219 AnjutaLauncherOutputType output_type,
1220 const gchar * chars, gpointer user_data)
1222 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1223 SymbolDBEnginePriv *priv;
1225 g_return_if_fail (user_data != NULL);
1227 priv = dbe->priv;
1229 if (priv->shutting_down == TRUE)
1230 return;
1232 g_thread_pool_push (priv->thread_pool, g_strdup (chars), NULL);
1234 /* signals monitor */
1235 if (priv->timeout_trigger_handler <= 0)
1237 priv->timeout_trigger_handler =
1238 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, TRIGGER_SIGNALS_DELAY,
1239 sdb_engine_timeout_trigger_signals, user_data, NULL);
1240 priv->trigger_closure_retries = 0;
1244 static void
1245 on_scan_files_end_1 (AnjutaLauncher * launcher, int child_pid,
1246 int exit_status, gulong time_taken_in_seconds,
1247 gpointer user_data)
1249 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1250 SymbolDBEnginePriv *priv;
1252 g_return_if_fail (user_data != NULL);
1254 priv = dbe->priv;
1256 DEBUG_PRINT ("***** ctags ended (%s) (%s) *****", priv->ctags_path,
1257 priv->cnc_string);
1259 if (priv->shutting_down == TRUE)
1260 return;
1262 priv->ctags_path = NULL;
1265 static void
1266 sdb_engine_ctags_launcher_create (SymbolDBEngine * dbe)
1268 SymbolDBEnginePriv *priv;
1269 gchar *exe_string;
1271 priv = dbe->priv;
1273 DEBUG_PRINT ("Creating anjuta_launcher with %s for %s", priv->ctags_path,
1274 priv->cnc_string);
1276 priv->ctags_launcher = anjuta_launcher_new ();
1278 anjuta_launcher_set_check_passwd_prompt (priv->ctags_launcher, FALSE);
1279 anjuta_launcher_set_encoding (priv->ctags_launcher, NULL);
1281 g_signal_connect (G_OBJECT (priv->ctags_launcher), "child-exited",
1282 G_CALLBACK (on_scan_files_end_1), dbe);
1284 exe_string = g_strdup_printf ("%s --sort=no --fields=afmiKlnsStTz --c++-kinds=+p "
1285 "--filter=yes --filter-terminator='"CTAGS_MARKER"'",
1286 priv->ctags_path);
1287 DEBUG_PRINT ("Launching %s", exe_string);
1288 anjuta_launcher_execute (priv->ctags_launcher,
1289 exe_string, sdb_engine_ctags_output_callback_1,
1290 dbe);
1291 g_free (exe_string);
1295 * A GAsyncReadyCallback function. This function is the async continuation for
1296 * sdb_engine_scan_files_1 ().
1298 static void
1299 sdb_engine_scan_files_2 (GFile *gfile,
1300 GAsyncResult *res,
1301 gpointer user_data)
1303 ScanFiles1Data *sf_data = (ScanFiles1Data*)user_data;
1304 SymbolDBEngine *dbe;
1305 SymbolDBEnginePriv *priv;
1306 GFileInfo *ginfo;
1307 gchar *local_path;
1308 gchar *real_file;
1309 gboolean symbols_update;
1310 gint partial_count;
1311 gint files_list_len;
1313 dbe = sf_data->dbe;
1314 symbols_update = sf_data->symbols_update;
1315 real_file = sf_data->real_file;
1316 files_list_len = sf_data->files_list_len;
1317 partial_count = sf_data->partial_count;
1319 priv = dbe->priv;
1321 ginfo = g_file_query_info_finish (gfile, res, NULL);
1323 local_path = g_file_get_path (gfile);
1325 if (ginfo == NULL ||
1326 g_file_info_get_attribute_boolean (ginfo,
1327 G_FILE_ATTRIBUTE_ACCESS_CAN_READ) == FALSE)
1329 g_warning ("File does not exist or is unreadable by user (%s)", local_path);
1331 g_free (local_path);
1332 g_free (real_file);
1333 g_free (sf_data);
1335 if (ginfo)
1336 g_object_unref (ginfo);
1337 if (gfile)
1338 g_object_unref (gfile);
1339 return;
1342 /* DEBUG_PRINT ("sent to stdin %s", local_path); */
1343 anjuta_launcher_send_stdin (priv->ctags_launcher, local_path);
1344 anjuta_launcher_send_stdin (priv->ctags_launcher, "\n");
1346 if (symbols_update == TRUE)
1348 DBESignal *dbesig;
1350 /* will this be the last file in the list? */
1351 if (partial_count + 1 >= files_list_len)
1353 dbesig = g_slice_new0 (DBESignal);
1354 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS_AND_EXIT);
1355 dbesig->process_id = priv->current_scan_process_id;
1357 /* yes */
1358 g_async_queue_push (priv->scan_aqueue, dbesig);
1360 else
1362 dbesig = g_slice_new0 (DBESignal);
1363 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS);
1364 dbesig->process_id = priv->current_scan_process_id;
1366 /* no */
1367 g_async_queue_push (priv->scan_aqueue, dbesig);
1370 else
1372 DBESignal *dbesig;
1374 if (partial_count + 1 >= files_list_len)
1376 dbesig = g_slice_new0 (DBESignal);
1377 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS_AND_EXIT);
1378 dbesig->process_id = priv->current_scan_process_id;
1380 /* yes */
1381 g_async_queue_push (priv->scan_aqueue, dbesig);
1383 else
1385 dbesig = g_slice_new0 (DBESignal);
1386 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS);
1387 dbesig->process_id = priv->current_scan_process_id;
1389 /* no */
1390 g_async_queue_push (priv->scan_aqueue, dbesig);
1394 /* don't forget to add the real_files if the caller provided a list for
1395 * them! */
1396 if (real_file != NULL)
1398 DBESignal *dbesig;
1400 dbesig = g_slice_new0 (DBESignal);
1401 dbesig->value = real_file;
1402 dbesig->process_id = priv->current_scan_process_id;
1404 g_async_queue_push (priv->scan_aqueue, dbesig);
1406 else
1408 DBESignal *dbesig;
1410 dbesig = g_slice_new0 (DBESignal);
1411 dbesig->value = GINT_TO_POINTER (DONT_FAKE_UPDATE_SYMS);
1412 dbesig->process_id = priv->current_scan_process_id;
1414 /* else add a DONT_FAKE_UPDATE_SYMS marker, just to notify that this
1415 * is not a fake file scan
1417 g_async_queue_push (priv->scan_aqueue, dbesig);
1420 /* we don't need ginfo object anymore, bye */
1421 g_object_unref (ginfo);
1422 g_object_unref (gfile);
1423 g_free (local_path);
1424 g_free (sf_data);
1425 /* no need to free real_file. For two reasons: 1. it's null. 2. it has been
1426 * pushed in the async queue and will be freed later
1431 * sdb_sort_files_list:
1432 * file1: First file
1433 * file2: second file
1435 * Returns:
1436 * -1 if file1 will be sorted before file2
1437 * 0 if file1 and file2 are sorted equally
1438 * 1 if file2 will be sorted before file1
1440 static gint sdb_sort_files_list (gconstpointer file1, gconstpointer file2)
1442 const gchar* filename1 = file1;
1443 const gchar* filename2 = file2;
1445 if (g_str_has_suffix (filename1, ".h") ||
1446 g_str_has_suffix (filename1, ".hxx") ||
1447 g_str_has_suffix (filename1, ".hh"))
1449 return -1;
1451 else if (g_str_has_suffix (filename2, ".h") ||
1452 g_str_has_suffix (filename2, ".hxx") ||
1453 g_str_has_suffix (filename2, ".hh"))
1455 return 1;
1458 return 0;
1462 /* Scan with ctags and produce an output 'tags' file [shared memory file]
1463 * containing language symbols. This function will call ctags
1464 * executale and then sdb_engine_populate_db_by_tags () when it'll detect some
1465 * output.
1466 * Please note the files_list/real_files_list parameter:
1467 * this version of sdb_engine_scan_files_1 () let you scan for text buffer(s) that
1468 * will be claimed as buffers for the real files.
1469 * 1. simple mode: files_list represents the real files on disk and so we don't
1470 * need real_files_list, which will be NULL.
1471 * 2. advanced mode: files_list represents temporary flushing of buffers on disk, i.e.
1472 * /tmp/anjuta_XYZ.cxx. real_files_list is the representation of those files on
1473 * database. On the above example we can have anjuta_XYZ.cxx mapped as /src/main.c
1474 * on db. In this mode files_list and real_files_list must have the same size.
1477 static gboolean
1478 sdb_engine_scan_files_1 (SymbolDBEngine * dbe, const GPtrArray * files_list,
1479 const GPtrArray *real_files_list, gboolean symbols_update,
1480 gint scan_id)
1482 SymbolDBEnginePriv *priv;
1483 gint i;
1485 priv = dbe->priv;
1487 /* if ctags_launcher isn't initialized, then do it now. */
1488 /* lazy initialization */
1489 if (priv->ctags_launcher == NULL)
1491 sdb_engine_ctags_launcher_create (dbe);
1495 /* Enter scanning state */
1496 priv->is_scanning = TRUE;
1498 priv->current_scan_process_id = scan_id;
1500 DBESignal *dbesig;
1502 dbesig = g_slice_new0 (DBESignal);
1503 dbesig->value = GINT_TO_POINTER (SCAN_BEGIN + 1);
1504 dbesig->process_id = priv->current_scan_process_id;
1506 g_async_queue_push (priv->signals_aqueue, dbesig);
1508 #ifdef DEBUG
1509 if (priv->first_scan_timer_DEBUG == NULL)
1510 priv->first_scan_timer_DEBUG = g_timer_new ();
1511 #endif
1513 /* create the shared memory file */
1514 if (priv->shared_mem_file == 0)
1516 gchar *temp_file;
1517 gint i = 0;
1518 while (TRUE)
1520 temp_file = g_strdup_printf ("/anjuta-%d_%ld%d.tags", getpid (),
1521 time (NULL), i++);
1522 gchar *test;
1523 test = g_strconcat (SHARED_MEMORY_PREFIX, temp_file, NULL);
1524 if (g_file_test (test, G_FILE_TEST_EXISTS) == TRUE)
1526 DEBUG_PRINT ("Temp file %s already exists... retrying", test);
1527 g_free (test);
1528 g_free (temp_file);
1529 continue;
1531 else
1533 g_free (test);
1534 break;
1538 priv->shared_mem_str = temp_file;
1540 if ((priv->shared_mem_fd =
1541 shm_open (temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
1543 g_warning ("Error while trying to open a shared memory file. Be"
1544 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
1547 priv->shared_mem_file = fdopen (priv->shared_mem_fd, "a+b");
1549 /* no need to free temp_file (alias shared_mem_str). It will be freed on plugin finalize */
1552 /* Sort the files to have sources before headers */
1553 g_ptr_array_sort (files_list, sdb_sort_files_list);
1554 if (real_files_list)
1555 g_ptr_array_sort (real_files_list, sdb_sort_files_list);
1557 for (i = 0; i < files_list->len; i++)
1559 GFile *gfile;
1560 ScanFiles1Data *sf_data;
1561 gchar *node = (gchar *) g_ptr_array_index (files_list, i);
1562 gfile = g_file_new_for_path (node);
1564 /* prepare an ojbect where to store some data for the async call */
1565 sf_data = g_new0 (ScanFiles1Data, 1);
1566 sf_data->dbe = dbe;
1567 sf_data->files_list_len = files_list->len;
1568 sf_data->partial_count = i;
1569 sf_data->symbols_update = symbols_update;
1571 if (real_files_list != NULL)
1573 sf_data->real_file = g_strdup (g_ptr_array_index (real_files_list, i));
1575 else
1577 sf_data->real_file = NULL;
1580 /* call it */
1581 g_file_query_info_async (gfile,
1582 G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
1583 G_FILE_QUERY_INFO_NONE,
1584 G_PRIORITY_LOW,
1585 NULL,
1586 (GAsyncReadyCallback)sdb_engine_scan_files_2,
1587 sf_data);
1590 return TRUE;
1593 static void
1594 on_scan_files_async_end (SymbolDBEngine *dbe, gint process_id, gpointer user_data)
1596 SymbolDBEnginePriv *priv;
1597 EngineScanDataAsync *esda;
1599 priv = dbe->priv;
1601 /* fine, check on the queue if there's something left to scan */
1602 if ((esda = g_async_queue_try_pop (priv->waiting_scan_aqueue)) == NULL)
1603 return;
1605 sdb_engine_scan_files_1 (dbe, esda->files_list, esda->real_files_list,
1606 esda->symbols_update, esda->scan_id);
1608 sdb_engine_scan_data_destroy (esda);
1611 static gboolean
1612 sdb_engine_scan_files_async (SymbolDBEngine * dbe, const GPtrArray * files_list,
1613 const GPtrArray *real_files_list, gboolean symbols_update,
1614 gint scan_id)
1616 SymbolDBEnginePriv *priv;
1617 g_return_val_if_fail (files_list != NULL, FALSE);
1619 if (files_list->len == 0)
1620 return FALSE;
1622 priv = dbe->priv;
1624 if (real_files_list != NULL && (files_list->len != real_files_list->len))
1626 g_warning ("no matched size between real_files_list and files_list");
1627 return FALSE;
1630 /* is the engine scanning or is there already something waiting on the queue? */
1631 if (symbol_db_engine_is_scanning (dbe) == TRUE ||
1632 g_async_queue_length (priv->waiting_scan_aqueue) > 0)
1634 /* push the data into the queue for later retrieval */
1635 EngineScanDataAsync * esda = g_new0 (EngineScanDataAsync, 1);
1637 esda->files_list = anjuta_util_clone_string_gptrarray (files_list);
1638 if (real_files_list)
1639 esda->real_files_list = anjuta_util_clone_string_gptrarray (real_files_list);
1640 else
1641 esda->real_files_list = NULL;
1642 esda->symbols_update = symbols_update;
1643 esda->scan_id = scan_id;
1645 g_async_queue_push (priv->waiting_scan_aqueue, esda);
1646 return TRUE;
1649 /* there's no scan active right now nor data waiting on the queue.
1650 * Proceed with normal scan.
1652 sdb_engine_scan_files_1 (dbe, files_list, real_files_list, symbols_update, scan_id);
1654 return TRUE;
1657 static void
1658 sdb_engine_init (SymbolDBEngine * object)
1660 SymbolDBEngine *sdbe;
1661 GHashTable *h;
1663 sdbe = SYMBOL_DB_ENGINE (object);
1664 sdbe->priv = g_new0 (SymbolDBEnginePriv, 1);
1666 sdbe->priv->db_connection = NULL;
1667 sdbe->priv->sql_parser = NULL;
1668 sdbe->priv->db_directory = NULL;
1669 sdbe->priv->project_directory = NULL;
1670 sdbe->priv->cnc_string = NULL;
1672 /* initialize an hash table to be used and shared with Iterators */
1673 sdbe->priv->sym_type_conversion_hash =
1674 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1675 h = sdbe->priv->sym_type_conversion_hash;
1677 /* please if you change some value below here remember to change also on */
1678 g_hash_table_insert (h, g_strdup("class"),
1679 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_CLASS));
1681 g_hash_table_insert (h, g_strdup("enum"),
1682 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUM));
1684 g_hash_table_insert (h, g_strdup("enumerator"),
1685 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUMERATOR));
1687 g_hash_table_insert (h, g_strdup("field"),
1688 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FIELD));
1690 g_hash_table_insert (h, g_strdup("function"),
1691 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FUNCTION));
1693 g_hash_table_insert (h, g_strdup("interface"),
1694 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_INTERFACE));
1696 g_hash_table_insert (h, g_strdup("member"),
1697 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MEMBER));
1699 g_hash_table_insert (h, g_strdup("method"),
1700 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_METHOD));
1702 g_hash_table_insert (h, g_strdup("namespace"),
1703 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_NAMESPACE));
1705 g_hash_table_insert (h, g_strdup("package"),
1706 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PACKAGE));
1708 g_hash_table_insert (h, g_strdup("prototype"),
1709 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PROTOTYPE));
1711 g_hash_table_insert (h, g_strdup("struct"),
1712 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_STRUCT));
1714 g_hash_table_insert (h, g_strdup("typedef"),
1715 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_TYPEDEF));
1717 g_hash_table_insert (h, g_strdup("union"),
1718 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_UNION));
1720 g_hash_table_insert (h, g_strdup("variable"),
1721 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_VARIABLE));
1723 g_hash_table_insert (h, g_strdup("externvar"),
1724 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_EXTERNVAR));
1726 g_hash_table_insert (h, g_strdup("macro"),
1727 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO));
1729 g_hash_table_insert (h, g_strdup("macro_with_arg"),
1730 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG));
1732 g_hash_table_insert (h, g_strdup("file"),
1733 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FILE));
1735 g_hash_table_insert (h, g_strdup("other"),
1736 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_OTHER));
1739 /* create the hash table that will store shared memory files strings used for
1740 * buffer scanning. Un Engine destroy will unlink () them.
1742 sdbe->priv->garbage_shared_mem_files = g_hash_table_new_full (g_str_hash, g_str_equal,
1743 g_free, NULL);
1745 sdbe->priv->ctags_launcher = NULL;
1746 sdbe->priv->removed_launchers = NULL;
1747 sdbe->priv->shutting_down = FALSE;
1748 sdbe->priv->is_first_population = FALSE;
1750 sdbe->priv->symbols_scanned_count = 0;
1752 /* set the ctags executable path to NULL */
1753 sdbe->priv->ctags_path = NULL;
1755 /* NULL the name of the default db */
1756 sdbe->priv->anjuta_db_file = NULL;
1758 /* identify the scan process with an id. There can be multiple files associated
1759 * within a process. A call to scan_files () will put inside the queue an id
1760 * returned and emitted by scan-end.
1762 sdbe->priv->scan_process_id_sequence = sdbe->priv->current_scan_process_id = 1;
1764 /* the scan_aqueue? It will contain mainly
1765 * ints that refer to the force_update status.
1767 sdbe->priv->scan_aqueue = g_async_queue_new ();
1769 /* the thread pool for tags scannning */
1770 sdbe->priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
1771 sdbe, THREADS_MAX_CONCURRENT,
1772 FALSE, NULL);
1774 /* some signals queues */
1775 sdbe->priv->signals_aqueue = g_async_queue_new ();
1776 sdbe->priv->updated_syms_id_aqueue = g_async_queue_new ();
1777 sdbe->priv->updated_scope_syms_id_aqueue = g_async_queue_new ();
1778 sdbe->priv->inserted_syms_id_aqueue = g_async_queue_new ();
1779 sdbe->priv->is_scanning = FALSE;
1781 sdbe->priv->waiting_scan_aqueue = g_async_queue_new_full (sdb_engine_scan_data_destroy);
1782 sdbe->priv->waiting_scan_handler = g_signal_connect (G_OBJECT (sdbe), "scan-end",
1783 G_CALLBACK (on_scan_files_async_end), NULL);
1787 * STATIC QUERY STRUCTURE INITIALIZE
1790 /* -- workspace -- */
1791 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1792 PREP_QUERY_WORKSPACE_NEW,
1793 "INSERT INTO workspace (workspace_name, analyse_time) VALUES (\
1794 ## /* name:'wsname' type:gchararray */, \
1795 datetime ('now', 'localtime'))");
1797 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1798 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
1799 "SELECT workspace_id FROM workspace \
1800 WHERE \
1801 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1");
1803 /* -- project -- */
1804 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1805 PREP_QUERY_PROJECT_NEW,
1806 "INSERT INTO project (project_name, project_version, wrkspace_id, analyse_time) VALUES (\
1807 ## /* name:'prjname' type:gchararray */, \
1808 ## /* name:'prjversion' type:gchararray */, \
1809 (SELECT workspace_id FROM workspace \
1810 WHERE \
1811 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1), \
1812 datetime ('now', 'localtime'))");
1814 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1815 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME,
1816 "SELECT project_id FROM project \
1817 WHERE \
1818 project_name = ## /* name:'prjname' type:gchararray */ AND \
1819 project_version = ## /* name:'prjversion' type:gchararray */ \
1820 LIMIT 1");
1822 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1823 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME,
1824 "UPDATE project SET \
1825 analyse_time = datetime('now', 'localtime', '+10 seconds') \
1826 WHERE \
1827 project_name = ## /* name:'prjname' type:gchararray */");
1829 /* -- file -- */
1830 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1831 PREP_QUERY_FILE_NEW,
1832 "INSERT INTO file (file_path, prj_id, lang_id, analyse_time) VALUES (\
1833 ## /* name:'filepath' type:gchararray */, \
1834 (SELECT project_id FROM project \
1835 WHERE \
1836 project_name = ## /* name:'prjname' type:gchararray */ AND \
1837 project_version = ## /* name:'prjversion' type:gchararray */ \
1838 LIMIT 1), \
1839 ## /* name:'langid' type:gint */, \
1840 datetime ('now', 'localtime'))");
1842 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1843 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
1844 "SELECT file_id FROM file \
1845 WHERE \
1846 file_path = ## /* name:'filepath' type:gchararray */ LIMIT 1");
1848 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1849 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME,
1850 "SELECT file_id, file_path AS db_file_path, prj_id, lang_id, file.analyse_time \
1851 FROM file JOIN project ON project.project_id = file.prj_id \
1852 WHERE \
1853 project.project_name = ## /* name:'prjname' type:gchararray */");
1855 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1856 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME,
1857 "UPDATE file SET \
1858 analyse_time = datetime('now', 'localtime') \
1859 WHERE \
1860 file_path = ## /* name:'filepath' type:gchararray */");
1862 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1863 PREP_QUERY_GET_ALL_FROM_FILE_WHERE_NOT_IN_SYMBOLS,
1864 "SELECT file_id, file_path AS db_file_path FROM file \
1865 WHERE file_id NOT IN (SELECT file_defined_id FROM symbol)");
1867 /* -- language -- */
1868 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1869 PREP_QUERY_LANGUAGE_NEW,
1870 "INSERT INTO language (language_name) VALUES (\
1871 ## /* name:'langname' type:gchararray */)");
1873 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1874 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
1875 "SELECT language_id FROM language WHERE \
1876 language_name = ## /* name:'langname' type:gchararray */ LIMIT 1");
1878 /* -- sym kind -- */
1879 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1880 PREP_QUERY_SYM_KIND_NEW,
1881 "INSERT INTO sym_kind (kind_name, is_container) VALUES(\
1882 ## /* name:'kindname' type:gchararray */, \
1883 ## /* name:'container' type:gint */)");
1885 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1886 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
1887 "SELECT sym_kind_id FROM sym_kind WHERE \
1888 kind_name = ## /* name:'kindname' type:gchararray */");
1890 /* -- sym access -- */
1891 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1892 PREP_QUERY_SYM_ACCESS_NEW,
1893 "INSERT INTO sym_access (access_name) VALUES(\
1894 ## /* name:'accesskind' type:gchararray */)");
1896 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1897 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
1898 "SELECT access_kind_id FROM sym_access WHERE \
1899 access_name = ## /* name:'accesskind' type:gchararray */ LIMIT 1");
1901 /* -- sym implementation -- */
1902 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1903 PREP_QUERY_SYM_IMPLEMENTATION_NEW,
1904 "INSERT INTO sym_implementation (implementation_name) VALUES(\
1905 ## /* name:'implekind' type:gchararray */)");
1907 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1908 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
1909 "SELECT sym_impl_id FROM sym_implementation WHERE \
1910 kind = ## /* name:'implekind' type:gchararray */ LIMIT 1");
1912 /* -- heritage -- */
1913 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1914 PREP_QUERY_HERITAGE_NEW,
1915 "INSERT INTO heritage (symbol_id_base, symbol_id_derived) VALUES(\
1916 ## /* name:'symbase' type:gint */, \
1917 ## /* name:'symderived' type:gint */)");
1919 /* -- scope -- */
1920 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1921 PREP_QUERY_SCOPE_NEW,
1922 "INSERT INTO scope (scope_name) VALUES(\
1923 ## /* name:'scope' type:gchararray */)");
1925 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1926 PREP_QUERY_GET_SCOPE_ID,
1927 "SELECT scope_id FROM scope \
1928 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1929 LIMIT 1");
1931 /* -- symbol -- */
1932 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1933 PREP_QUERY_SYMBOL_NEW,
1934 "INSERT INTO symbol (file_defined_id, name, file_position, \
1935 is_file_scope, signature, returntype, \
1936 scope_definition_id, scope_id, \
1937 type_type, type_name, kind_id, access_kind_id, \
1938 implementation_kind_id, update_flag) \
1939 VALUES( \
1940 ## /* name:'filedefid' type:gint */, \
1941 ## /* name:'name' type:gchararray */, \
1942 ## /* name:'fileposition' type:gint */, \
1943 ## /* name:'isfilescope' type:gint */, \
1944 ## /* name:'signature' type:gchararray */, \
1945 ## /* name:'returntype' type:gchararray */, \
1946 CASE ## /* name:'scopedefinitionid' type:gint */ \
1947 WHEN -1 THEN (SELECT scope_id FROM scope \
1948 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1949 LIMIT 1) \
1950 ELSE ## /* name:'scopedefinitionid' type:gint */ END, \
1951 ## /* name:'scopeid' type:gint */, \
1952 ## /* name:'typetype' type:gchararray */, \
1953 ## /* name:'typename' type:gchararray */, \
1954 ## /* name:'kindid' type:gint */,## /* name:'accesskindid' type:gint */, \
1955 ## /* name:'implementationkindid' type:gint */, \
1956 ## /* name:'updateflag' type:gint */)");
1959 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1960 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
1961 "SELECT symbol_id FROM symbol \
1962 WHERE scope_id = 0 AND \
1963 type_type='class' AND \
1964 name = ## /* name:'klassname' type:gchararray */ LIMIT 1");
1966 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1967 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
1968 "SELECT symbol_id FROM symbol JOIN scope ON symbol.scope_id = scope.scope_id \
1969 WHERE symbol.name = ## /* name:'klassname' type:gchararray */ AND \
1970 scope.scope_name = ## /* name:'namespacename' type:gchararray */ AND \
1971 symbol.type_type = 'namespace' LIMIT 1");
1973 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1974 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID,
1975 "UPDATE symbol SET scope_id = (SELECT scope_definition_id FROM symbol WHERE \
1976 type_type = ## /* name:'tokenname' type:gchararray */ AND \
1977 type_name = ## /* name:'objectname' type:gchararray */ LIMIT 1) \
1978 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
1980 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1981 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
1982 "SELECT symbol_id FROM symbol \
1983 WHERE \
1984 name = ## /* name:'symname' type:gchararray */ AND \
1985 file_defined_id = ## /* name:'filedefid' type:gint */ AND \
1986 type_type = ## /* name:'typetype' type:gchararray */ AND \
1987 type_name = ## /* name:'typename' type:gchararray */ AND \
1988 update_flag = 0 LIMIT 1");
1990 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1991 PREP_QUERY_UPDATE_SYMBOL_ALL,
1992 "UPDATE symbol SET \
1993 is_file_scope = ## /* name:'isfilescope' type:gint */, \
1994 file_position = ## /* name:'fileposition' type:gint */, \
1995 signature = ## /* name:'signature' type:gchararray */, \
1996 returntype = ## /* name:'returntype' type:gchararray */, \
1997 scope_definition_id = ## /* name:'scopedefinitionid' type:gint */, \
1998 scope_id = ## /* name:'scopeid' type:gint */, \
1999 kind_id = ## /* name:'kindid' type:gint */, \
2000 access_kind_id = ## /* name:'accesskindid' type:gint */, \
2001 implementation_kind_id = ## /* name:'implementationkindid' type:gint */, \
2002 update_flag = ## /* name:'updateflag' type:gint */ \
2003 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
2005 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2006 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS,
2007 "DELETE FROM symbol WHERE \
2008 file_defined_id = (SELECT file_id FROM file \
2009 WHERE \
2010 file.file_path = ## /* name:'filepath' type:gchararray */) AND \
2011 update_flag = 0");
2013 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2014 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS,
2015 "UPDATE symbol SET \
2016 update_flag = 0 \
2017 WHERE file_defined_id = (SELECT file_id FROM file \
2018 WHERE \
2019 file_path = ## /* name:'filepath' type:gchararray */)");
2021 /* -- tmp_removed -- */
2022 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2023 PREP_QUERY_GET_REMOVED_IDS,
2024 "SELECT symbol_removed_id FROM __tmp_removed");
2026 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2027 PREP_QUERY_TMP_REMOVED_DELETE_ALL,
2028 "DELETE FROM __tmp_removed");
2030 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2031 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME,
2032 "DELETE FROM file WHERE \
2033 prj_id = (SELECT project_id FROM project \
2034 WHERE project_name = ## /* name:'prjname' type:gchararray */) AND \
2035 file_path = ## /* name:'filepath' type:gchararray */");
2037 /* init cache hashtables */
2038 sdb_engine_init_caches (sdbe);
2040 /* init table maps */
2041 sdb_engine_init_table_maps (sdbe);
2044 static void
2045 sdb_engine_unlink_shared_files (gpointer key, gpointer value, gpointer user_data)
2047 shm_unlink (key);
2050 static void
2051 sdb_engine_unref_removed_launchers (gpointer data, gpointer user_data)
2053 g_object_unref (data);
2056 static void
2057 sdb_engine_finalize (GObject * object)
2059 SymbolDBEngine *dbe;
2060 SymbolDBEnginePriv *priv;
2062 dbe = SYMBOL_DB_ENGINE (object);
2063 priv = dbe->priv;
2064 /*/ FIXME a crash here ?!
2065 g_signal_handler_disconnect (dbe, priv->waiting_scan_handler);
2066 priv->waiting_scan_handler = 0;
2067 //*/
2068 if (priv->thread_pool)
2070 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2071 priv->thread_pool = NULL;
2074 if (priv->ctags_launcher)
2076 g_object_unref (priv->ctags_launcher);
2077 priv->ctags_launcher = NULL;
2080 if (priv->removed_launchers)
2082 g_list_foreach (priv->removed_launchers,
2083 sdb_engine_unref_removed_launchers, NULL);
2084 g_list_free (priv->removed_launchers);
2085 priv->removed_launchers = NULL;
2088 if (priv->mutex)
2090 g_mutex_free (priv->mutex);
2091 priv->mutex = NULL;
2094 if (priv->timeout_trigger_handler > 0)
2095 g_source_remove (priv->timeout_trigger_handler);
2097 if (symbol_db_engine_is_connected (dbe) == TRUE)
2098 sdb_engine_disconnect_from_db (dbe);
2100 sdb_engine_free_cached_queries (dbe);
2102 if (priv->scan_aqueue)
2104 g_async_queue_unref (priv->scan_aqueue);
2105 priv->scan_aqueue = NULL;
2108 if (priv->updated_syms_id_aqueue)
2110 g_async_queue_unref (priv->updated_syms_id_aqueue);
2111 priv->updated_syms_id_aqueue = NULL;
2114 if (priv->updated_scope_syms_id_aqueue)
2116 g_async_queue_unref (priv->updated_scope_syms_id_aqueue);
2117 priv->updated_scope_syms_id_aqueue = NULL;
2120 if (priv->inserted_syms_id_aqueue)
2122 g_async_queue_unref (priv->inserted_syms_id_aqueue);
2123 priv->inserted_syms_id_aqueue = NULL;
2126 if (priv->waiting_scan_aqueue)
2128 g_async_queue_unref (priv->waiting_scan_aqueue);
2129 priv->waiting_scan_aqueue = NULL;
2132 if (priv->shared_mem_file)
2134 fclose (priv->shared_mem_file);
2135 priv->shared_mem_file = NULL;
2138 if (priv->shared_mem_str)
2140 shm_unlink (priv->shared_mem_str);
2141 g_free (priv->shared_mem_str);
2142 priv->shared_mem_str = NULL;
2145 if (priv->garbage_shared_mem_files)
2147 g_hash_table_foreach (priv->garbage_shared_mem_files,
2148 sdb_engine_unlink_shared_files,
2149 NULL);
2150 /* destroy the hash table */
2151 g_hash_table_destroy (priv->garbage_shared_mem_files);
2155 if (priv->sym_type_conversion_hash)
2156 g_hash_table_destroy (priv->sym_type_conversion_hash);
2157 priv->sym_type_conversion_hash = NULL;
2159 if (priv->signals_aqueue)
2160 g_async_queue_unref (priv->signals_aqueue);
2161 priv->signals_aqueue = NULL;
2163 sdb_engine_clear_caches (dbe);
2164 sdb_engine_clear_tablemaps (dbe);
2166 g_free (priv->anjuta_db_file);
2167 priv->anjuta_db_file = NULL;
2169 g_free (priv->ctags_path);
2170 priv->ctags_path = NULL;
2172 g_free (priv);
2174 G_OBJECT_CLASS (parent_class)->finalize (object);
2177 static void
2178 sdb_engine_class_init (SymbolDBEngineClass * klass)
2180 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2181 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2183 object_class->finalize = sdb_engine_finalize;
2185 signals[DB_CONNECTED]
2186 = g_signal_new ("db-connected",
2187 G_OBJECT_CLASS_TYPE (object_class),
2188 G_SIGNAL_RUN_LAST,
2189 G_STRUCT_OFFSET (SymbolDBEngineClass, db_connected),
2190 NULL, NULL,
2191 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2193 signals[DB_DISCONNECTED]
2194 = g_signal_new ("db-disconnected",
2195 G_OBJECT_CLASS_TYPE (object_class),
2196 G_SIGNAL_RUN_LAST,
2197 G_STRUCT_OFFSET (SymbolDBEngineClass, db_disconnected),
2198 NULL, NULL,
2199 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2201 signals[SCAN_BEGIN]
2202 = g_signal_new ("scan-begin",
2203 G_OBJECT_CLASS_TYPE (object_class),
2204 G_SIGNAL_RUN_LAST,
2205 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_begin),
2206 NULL, NULL,
2207 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2209 G_TYPE_INT);
2211 signals[SINGLE_FILE_SCAN_END]
2212 = g_signal_new ("single-file-scan-end",
2213 G_OBJECT_CLASS_TYPE (object_class),
2214 G_SIGNAL_RUN_FIRST,
2215 G_STRUCT_OFFSET (SymbolDBEngineClass, single_file_scan_end),
2216 NULL, NULL,
2217 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2219 signals[SCAN_END]
2220 = g_signal_new ("scan-end",
2221 G_OBJECT_CLASS_TYPE (object_class),
2222 G_SIGNAL_RUN_LAST,
2223 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_end),
2224 NULL, NULL,
2225 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2227 G_TYPE_INT);
2229 signals[SYMBOL_INSERTED]
2230 = g_signal_new ("symbol-inserted",
2231 G_OBJECT_CLASS_TYPE (object_class),
2232 G_SIGNAL_RUN_LAST,
2233 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_inserted),
2234 NULL, NULL,
2235 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2237 G_TYPE_INT);
2239 signals[SYMBOL_UPDATED]
2240 = g_signal_new ("symbol-updated",
2241 G_OBJECT_CLASS_TYPE (object_class),
2242 G_SIGNAL_RUN_LAST,
2243 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_updated),
2244 NULL, NULL,
2245 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2247 G_TYPE_INT);
2249 signals[SYMBOL_SCOPE_UPDATED]
2250 = g_signal_new ("symbol-scope-updated",
2251 G_OBJECT_CLASS_TYPE (object_class),
2252 G_SIGNAL_RUN_LAST,
2253 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_scope_updated),
2254 NULL, NULL,
2255 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2257 G_TYPE_INT);
2259 signals[SYMBOL_REMOVED]
2260 = g_signal_new ("symbol-removed",
2261 G_OBJECT_CLASS_TYPE (object_class),
2262 G_SIGNAL_RUN_LAST,
2263 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_removed),
2264 NULL, NULL,
2265 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2267 G_TYPE_INT);
2270 GType
2271 sdb_engine_get_type (void)
2273 static GType our_type = 0;
2275 if (our_type == 0)
2277 static const GTypeInfo our_info = {
2278 sizeof (SymbolDBEngineClass), /* class_size */
2279 (GBaseInitFunc) NULL, /* base_init */
2280 (GBaseFinalizeFunc) NULL, /* base_finalize */
2281 (GClassInitFunc) sdb_engine_class_init, /* class_init */
2282 (GClassFinalizeFunc) NULL, /* class_finalize */
2283 NULL /* class_data */ ,
2284 sizeof (SymbolDBEngine), /* instance_size */
2285 0, /* n_preallocs */
2286 (GInstanceInitFunc) sdb_engine_init, /* instance_init */
2287 NULL /* value_table */
2290 our_type = g_type_register_static (G_TYPE_OBJECT, "SymbolDBEngine",
2291 &our_info, 0);
2294 return our_type;
2298 * symbol_db_engine_set_ctags_path:
2299 * @dbe: self
2300 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2302 * Set a new path for anjuta-tags executable.
2304 * Returns: TRUE if the set is successful.
2306 gboolean
2307 symbol_db_engine_set_ctags_path (SymbolDBEngine * dbe, const gchar * ctags_path)
2309 SymbolDBEnginePriv *priv;
2311 g_return_val_if_fail (dbe != NULL, FALSE);
2312 g_return_val_if_fail (ctags_path != NULL, FALSE);
2314 priv = dbe->priv;
2316 /* Check if ctags is really installed */
2317 if (!anjuta_util_prog_is_installed (ctags_path, TRUE))
2319 g_warning ("symbol_db_engine_set_ctags_path (): Wrong path for ctags. Keeping "
2320 "the old value %s", priv->ctags_path);
2321 return priv->ctags_path != NULL;
2324 /* have we already got it? */
2325 if (priv->ctags_path != NULL &&
2326 g_strcmp0 (priv->ctags_path, ctags_path) == 0)
2327 return TRUE;
2329 /* free the old value */
2330 g_free (priv->ctags_path);
2332 /* is anjutalauncher already created? */
2333 if (priv->ctags_launcher != NULL)
2335 AnjutaLauncher *tmp;
2336 tmp = priv->ctags_launcher;
2338 /* recreate it on the fly */
2339 sdb_engine_ctags_launcher_create (dbe);
2341 /* keep the launcher alive to avoid crashes */
2342 priv->removed_launchers = g_list_prepend (priv->removed_launchers, tmp);
2345 /* set the new one */
2346 priv->ctags_path = g_strdup (ctags_path);
2347 return TRUE;
2351 * symbol_db_engine_new:
2352 * @ctags_path Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2354 * Create a new instance of an engine.
2355 * Default name of database is ANJUTA_DB_FILE (see symbol-db-engine-priv.h)
2357 * Returns: a new SymbolDBEngine object.
2359 SymbolDBEngine *
2360 symbol_db_engine_new (const gchar * ctags_path)
2362 SymbolDBEngine *sdbe;
2363 SymbolDBEnginePriv *priv;
2365 g_return_val_if_fail (ctags_path != NULL, NULL);
2366 sdbe = g_object_new (SYMBOL_TYPE_DB_ENGINE, NULL);
2368 priv = sdbe->priv;
2369 priv->mutex = g_mutex_new ();
2370 priv->anjuta_db_file = g_strdup (ANJUTA_DB_FILE);
2372 /* set the mandatory ctags_path */
2373 if (!symbol_db_engine_set_ctags_path (sdbe, ctags_path))
2375 return NULL;
2378 return sdbe;
2382 * symbol_db_engine_new_full:
2383 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2384 * @database_name: name of resulting db on disk.
2386 * Similar to symbol_db_engine_new() but you can specify the name of resulting db.
2388 SymbolDBEngine*
2389 symbol_db_engine_new_full (const gchar * ctags_path, const gchar * database_name)
2391 SymbolDBEngine* dbe;
2392 SymbolDBEnginePriv* priv;
2394 g_return_val_if_fail (database_name != NULL, NULL);
2395 dbe = symbol_db_engine_new (ctags_path);
2397 g_return_val_if_fail (dbe != NULL, NULL);
2399 priv = dbe->priv;
2400 g_free (priv->anjuta_db_file);
2401 priv->anjuta_db_file = g_strdup (database_name);
2403 return dbe;
2407 * Set some default parameters to use with the current database.
2409 static void
2410 sdb_engine_set_defaults_db_parameters (SymbolDBEngine * dbe)
2412 sdb_engine_execute_unknown_sql (dbe, "PRAGMA page_size = 32768");
2413 sdb_engine_execute_unknown_sql (dbe, "PRAGMA cache_size = 12288");
2414 sdb_engine_execute_unknown_sql (dbe, "PRAGMA synchronous = OFF");
2415 sdb_engine_execute_unknown_sql (dbe, "PRAGMA temp_store = MEMORY");
2416 sdb_engine_execute_unknown_sql (dbe, "PRAGMA journal_mode = OFF");
2417 sdb_engine_execute_unknown_sql (dbe, "PRAGMA read_uncommitted = 1");
2418 sdb_engine_execute_unknown_sql (dbe, "PRAGMA foreign_keys = OFF");
2419 symbol_db_engine_set_db_case_sensitive (dbe, TRUE);
2422 /* Will create priv->db_connection.
2423 * Connect to database identified by db_directory.
2424 * Usually db_directory is defined also into priv. We let it here as parameter
2425 * because it is required and cannot be null.
2427 static gboolean
2428 sdb_engine_connect_to_db (SymbolDBEngine * dbe, const gchar *cnc_string)
2430 SymbolDBEnginePriv *priv;
2432 g_return_val_if_fail (dbe != NULL, FALSE);
2433 priv = dbe->priv;
2435 if (priv->db_connection != NULL)
2437 /* if it's the case that the connection isn't NULL, we
2438 * should notify the user
2439 * and return FALSE. It's his task to disconnect and retry to connect */
2440 g_warning ("connection is already established. Please disconnect "
2441 "and then try to reconnect.");
2442 return FALSE;
2445 /* establish a connection. If the sqlite file does not exist it will
2446 * be created
2448 priv->db_connection = gda_connection_open_from_string ("SQLite", cnc_string, NULL,
2449 GDA_CONNECTION_OPTIONS_THREAD_SAFE, NULL);
2451 if (!GDA_IS_CONNECTION (priv->db_connection))
2453 g_warning ("Could not open connection to %s\n", cnc_string);
2454 return FALSE;
2457 priv->cnc_string = g_strdup (cnc_string);
2458 priv->sql_parser = gda_connection_create_parser (priv->db_connection);
2460 if (!GDA_IS_SQL_PARSER (priv->sql_parser))
2462 g_warning ("Could not create sql parser. Check your libgda installation");
2463 return FALSE;
2466 DEBUG_PRINT ("Connected to database %s", cnc_string);
2467 return TRUE;
2471 * symbol_db_engine_is_connected:
2472 * @dbe: self
2474 * Check whether the engine is connected to db or not.
2476 * Returns: TRUE if the db is connected.
2478 gboolean
2479 symbol_db_engine_is_connected (SymbolDBEngine * dbe)
2481 SymbolDBEnginePriv *priv;
2483 g_return_val_if_fail (dbe != NULL, FALSE);
2484 priv = dbe->priv;
2486 return priv->db_connection && priv->cnc_string && priv->sql_parser &&
2487 gda_connection_is_opened (priv->db_connection );
2491 * symbol_db_engine_is_scanning:
2492 * @dbe: self
2494 * Check if engine is scanning busy
2496 * Returns: TRUE if it is scanning.
2498 gboolean
2499 symbol_db_engine_is_scanning (SymbolDBEngine *dbe)
2501 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), FALSE);
2502 return dbe->priv->is_scanning;
2506 * Creates required tables for the database to work.
2507 * Sets is_first_population flag to TRUE.
2508 * @param tables_sql_file File containing sql code.
2510 static gboolean
2511 sdb_engine_create_db_tables (SymbolDBEngine * dbe, const gchar * tables_sql_file)
2513 SymbolDBEnginePriv *priv;
2514 gchar *contents;
2515 gchar *query;
2516 gsize sizez;
2518 g_return_val_if_fail (tables_sql_file != NULL, FALSE);
2520 priv = dbe->priv;
2522 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2524 /* read the contents of the file */
2525 if (g_file_get_contents (tables_sql_file, &contents, &sizez, NULL) == FALSE)
2527 g_warning ("Something went wrong while trying to read %s",
2528 tables_sql_file);
2530 return FALSE;
2533 sdb_engine_execute_non_select_sql (dbe, contents);
2534 g_free (contents);
2536 /* set the current symbol db database version. This may help if new tables/fields
2537 * are added/removed in future versions.
2539 query = "INSERT INTO version VALUES ("SYMBOL_DB_VERSION")";
2540 sdb_engine_execute_non_select_sql (dbe, query);
2542 priv->is_first_population = TRUE;
2544 /* no need to free query of course */
2546 return TRUE;
2550 * symbol_db_engine_db_exists:
2551 * @dbe: self
2552 * @prj_directory: absolute path of the project.
2554 * Check if the database already exists into the prj_directory
2556 * Returns: TRUE if db exists on disk.
2558 gboolean
2559 symbol_db_engine_db_exists (SymbolDBEngine * dbe, const gchar * prj_directory)
2561 SymbolDBEnginePriv *priv;
2563 g_return_val_if_fail (prj_directory != NULL, FALSE);
2565 priv = dbe->priv;
2567 /* check whether the db filename already exists.*/
2568 gchar *tmp_file = g_strdup_printf ("%s/%s.db", prj_directory,
2569 priv->anjuta_db_file);
2571 if (g_file_test (tmp_file, G_FILE_TEST_EXISTS) == FALSE)
2573 DEBUG_PRINT ("db %s does not exist", tmp_file);
2574 g_free (tmp_file);
2575 return FALSE;
2578 g_free (tmp_file);
2579 return TRUE;
2583 * symbol_db_engine_file_exists:
2584 * @dbe: self
2585 * @abs_file_path: absolute file path.
2587 * Check if a file is already present [and scanned] in db.
2588 * ~~~ Thread note: this function locks the mutex ~~~
2590 * Returns: TRUE if the file is present.
2592 gboolean
2593 symbol_db_engine_file_exists (SymbolDBEngine * dbe, const gchar * abs_file_path)
2595 SymbolDBEnginePriv *priv;
2596 const gchar *relative;
2597 gint file_defined_id;
2598 GValue v = {0};
2600 g_return_val_if_fail (dbe != NULL, FALSE);
2601 g_return_val_if_fail (abs_file_path != NULL, FALSE);
2603 priv = dbe->priv;
2605 SDB_LOCK(priv);
2607 relative = symbol_db_util_get_file_db_path (dbe, abs_file_path);
2608 if (relative == NULL)
2610 SDB_UNLOCK(priv);
2611 return FALSE;
2614 SDB_GVALUE_SET_STATIC_STRING(v, relative);
2616 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2617 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
2618 "filepath",
2619 &v)) < 0)
2621 SDB_UNLOCK(priv);
2622 return FALSE;
2625 SDB_UNLOCK(priv);
2626 return TRUE;
2629 /**
2630 * symbol_db_engine_close_db:
2631 * @dbe: self
2633 * Disconnect db, gda client and db_connection
2635 * Returns: TRUE if closing has been successful.
2637 gboolean
2638 symbol_db_engine_close_db (SymbolDBEngine *dbe)
2640 SymbolDBEnginePriv *priv;
2641 gboolean ret;
2642 g_return_val_if_fail (dbe != NULL, FALSE);
2644 priv = dbe->priv;
2646 /* terminate threads, if ever they're running... */
2647 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2648 priv->thread_pool = NULL;
2649 ret = sdb_engine_disconnect_from_db (dbe);
2651 /* reset count */
2652 priv->symbols_scanned_count = 0;
2654 g_free (priv->db_directory);
2655 priv->db_directory = NULL;
2657 g_free (priv->project_directory);
2658 priv->project_directory = NULL;
2660 priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
2661 dbe, THREADS_MAX_CONCURRENT,
2662 FALSE, NULL);
2663 g_signal_emit_by_name (dbe, "db-disconnected", NULL);
2664 return ret;
2667 static gdouble
2668 sdb_engine_get_db_version (SymbolDBEngine *dbe)
2670 GdaDataModel *data_model;
2671 const GValue *value_id;
2672 gchar *query;
2673 gdouble version_id;
2674 gint col;
2676 /* set the current symbol db database version. This may help if new tables/fields
2677 * are added/removed in future versions.
2679 query = "SELECT sdb_version FROM version";
2680 if ((data_model = sdb_engine_execute_select_sql (dbe, query)) == NULL)
2682 return -1;
2685 col = gda_data_model_get_column_index(data_model, "sdb_version");
2686 value_id = gda_data_model_get_value_at (data_model, col, 0, NULL);
2688 if (G_VALUE_HOLDS_DOUBLE (value_id))
2689 version_id = g_value_get_double (value_id);
2690 else
2691 version_id = (gdouble)g_value_get_int (value_id);
2693 g_object_unref (data_model);
2694 /* no need to free query of course */
2696 return version_id;
2699 static gboolean
2700 sdb_engine_check_db_version_and_upgrade (SymbolDBEngine *dbe,
2701 const gchar* db_file,
2702 const gchar* cnc_string)
2704 gdouble version;
2707 version = sdb_engine_get_db_version (dbe);
2708 DEBUG_PRINT ("Checking db version...");
2709 if (version <= 0)
2711 /* some error occurred */
2712 g_warning ("No version of db detected. This can produce many errors. DB"
2713 "will be recreated from scratch.");
2715 /* force version to 0 */
2716 version = 0;
2719 if (version < atof (SYMBOL_DB_VERSION))
2721 DEBUG_PRINT ("Upgrading from version %f to "SYMBOL_DB_VERSION, version);
2723 /* we need a full recreation of db. Because of the sym_kind table
2724 * which changed its data but not its fields, we must recreate the
2725 * whole database.
2728 /* 1. disconnect from current db */
2729 sdb_engine_disconnect_from_db (dbe);
2731 /* 2. remove current db file */
2732 GFile *gfile = g_file_new_for_path (db_file);
2733 if (gfile != NULL) {
2734 g_file_delete (gfile, NULL, NULL);
2735 g_object_unref (gfile);
2737 else
2739 g_warning ("Could not get the gfile");
2742 /* 3. reconnect */
2743 sdb_engine_connect_to_db (dbe, cnc_string);
2745 /* 4. create fresh new tables, indexes, triggers etc. */
2746 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2747 return TRUE;
2749 else
2751 DEBUG_PRINT ("No need to upgrade.");
2754 return FALSE;
2758 * symbol_db_engine_open_db:
2759 * @dbe: self
2760 * @base_db_path: directory where .anjuta_sym_db.db will be stored. It can be
2761 * different from project_directory
2762 * E.g: a db on '/tmp/foo/' dir.
2763 * @prj_directory: project directory. It may be different from base_db_path.
2764 * It's mainly used to map files inside the db. Say for example that you want to
2765 * add to a project a file /home/user/project/foo_prj/src/file.c with a project
2766 * directory of /home/user/project/foo_prj/. On db it'll be represented as
2767 * src/file.c. In this way you can move around the project dir without dealing
2768 * with relative paths.
2770 * Open, create or upgrade a database at given directory.
2771 * Be sure to give a base_db_path with the ending '/' for directory.
2773 * Returns: An opening status from SymbolDBEngineOpenStatus enum.
2775 SymbolDBEngineOpenStatus
2776 symbol_db_engine_open_db (SymbolDBEngine * dbe, const gchar * base_db_path,
2777 const gchar * prj_directory)
2779 SymbolDBEnginePriv *priv;
2780 gboolean needs_tables_creation = FALSE;
2781 gchar *cnc_string;
2782 gboolean connect_res;
2783 gboolean ret_status = DB_OPEN_STATUS_NORMAL;
2785 DEBUG_PRINT ("Opening project %s with base dir %s",
2786 prj_directory, base_db_path);
2788 g_return_val_if_fail (dbe != NULL, FALSE);
2789 g_return_val_if_fail (base_db_path != NULL, FALSE);
2791 priv = dbe->priv;
2793 priv->symbols_scanned_count = 0;
2795 /* check whether the db filename already exists. If it's not the case
2796 * create the tables for the database. */
2797 gchar *db_file = g_strdup_printf ("%s/%s.db", base_db_path,
2798 priv->anjuta_db_file);
2800 if (g_file_test (db_file, G_FILE_TEST_EXISTS) == FALSE)
2802 needs_tables_creation = TRUE;
2805 priv->db_directory = g_strdup (base_db_path);
2807 /* save the project_directory */
2808 priv->project_directory = g_strdup (prj_directory);
2810 cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", base_db_path,
2811 priv->anjuta_db_file);
2812 DEBUG_PRINT ("Connecting to "
2813 "database with %s...", cnc_string);
2814 connect_res = sdb_engine_connect_to_db (dbe, cnc_string);
2817 if (connect_res == FALSE)
2819 g_free (db_file);
2820 g_free (cnc_string);
2822 ret_status = DB_OPEN_STATUS_FATAL;
2823 return ret_status;
2826 if (needs_tables_creation == TRUE)
2828 DEBUG_PRINT ("Creating tables...");
2829 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2830 ret_status = DB_OPEN_STATUS_CREATE;
2832 else
2834 /* check the version of the db. If it's old we should upgrade it */
2835 if (sdb_engine_check_db_version_and_upgrade (dbe, db_file, cnc_string) == TRUE)
2837 ret_status = DB_OPEN_STATUS_UPGRADE;
2841 sdb_engine_set_defaults_db_parameters (dbe);
2843 g_free (cnc_string);
2844 g_free (db_file);
2846 /* we're now able to emit the db-connected signal: tables should be created
2847 * and libgda should be connected to an usable db.
2849 g_signal_emit_by_name (dbe, "db-connected", NULL);
2851 return ret_status;
2855 * symbol_db_engine_get_cnc_string:
2856 * @dbe: self
2858 * Getter for the connection string.
2860 * Returns: The connection string. It must be freed by caller.
2862 gchar *
2863 symbol_db_engine_get_cnc_string (SymbolDBEngine * dbe)
2865 SymbolDBEnginePriv *priv;
2867 g_return_val_if_fail (dbe != NULL, FALSE);
2868 priv = dbe->priv;
2870 return g_strdup (priv->cnc_string);
2873 /**
2874 * symbol_db_engine_add_new_workspace:
2875 * @dbe: self
2876 * @workspace_name: name of workspace.
2878 * Add a new workspace to an opened database.
2879 * ~~~ Thread note: this function locks the mutex ~~~
2881 * Returns: TRUE if operation is successful.
2883 gboolean
2884 symbol_db_engine_add_new_workspace (SymbolDBEngine * dbe,
2885 const gchar * workspace_name)
2887 const GdaSet *plist;
2888 const GdaStatement *stmt;
2889 GdaHolder *param;
2890 SymbolDBEnginePriv *priv;
2891 GValue v = {0};
2893 g_return_val_if_fail (dbe != NULL, FALSE);
2894 priv = dbe->priv;
2896 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2898 SDB_LOCK(priv);
2900 if ((stmt =
2901 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_WORKSPACE_NEW)) == NULL)
2903 g_warning ("query is null");
2904 SDB_UNLOCK(priv);
2905 return FALSE;
2908 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_WORKSPACE_NEW);
2910 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
2912 g_warning ("param is NULL from pquery!\n");
2913 SDB_UNLOCK(priv);
2914 return FALSE;
2916 SDB_PARAM_SET_STRING(param, workspace_name);
2918 /* execute the query with parameters just set */
2919 if (gda_connection_statement_execute_non_select (priv->db_connection,
2920 (GdaStatement*)stmt,
2921 (GdaSet*)plist, NULL, NULL) == -1)
2923 SDB_UNLOCK(priv);
2924 return FALSE;
2927 SDB_UNLOCK(priv);
2928 return TRUE;
2931 /**
2932 * symbol_db_engine_project_exists:
2933 * @dbe: self
2934 * @project_name: Project name.
2935 * @project_version: The version of the project.
2937 * Test project existence.
2938 * ~~~ Thread note: this function locks the mutex ~~~
2940 * Returns: FALSE if project isn't found. TRUE otherwise.
2942 gboolean
2943 symbol_db_engine_project_exists (SymbolDBEngine * dbe,
2944 const gchar * project_name,
2945 const gchar * project_version)
2947 SymbolDBEnginePriv *priv;
2948 GValue v = {0};
2949 const GdaSet *plist;
2950 const GdaStatement *stmt;
2951 GdaHolder *param;
2952 GdaDataModel *data_model;
2954 priv = dbe->priv;
2956 SDB_LOCK(priv);
2958 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2960 /* test the existence of the project in db */
2961 /* get prepared query */
2962 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
2963 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME)) == NULL)
2965 g_warning ("Query is null");
2966 SDB_UNLOCK(priv);
2967 return FALSE;
2970 plist = sdb_engine_get_query_parameters_list (dbe,
2971 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME);
2973 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
2975 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
2976 "from pquery!\n");
2977 SDB_UNLOCK(priv);
2978 return FALSE;
2981 SDB_PARAM_SET_STRING (param, project_name);
2983 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
2985 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
2986 "from pquery!\n");
2987 SDB_UNLOCK(priv);
2988 return FALSE;
2991 SDB_PARAM_SET_STRING (param, project_version);
2993 /* execute the query with parameters just set */
2994 data_model = gda_connection_statement_execute_select (priv->db_connection,
2995 (GdaStatement*)stmt,
2996 (GdaSet*)plist, NULL);
2998 if (!GDA_IS_DATA_MODEL (data_model) ||
2999 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
3001 if (data_model != NULL)
3002 g_object_unref (data_model);
3003 SDB_UNLOCK(priv);
3004 return FALSE;
3007 /* we found it and we can return */
3008 g_object_unref (data_model);
3010 SDB_UNLOCK(priv);
3012 return TRUE;
3015 /**
3016 * symbol_db_engine_add_new_project:
3017 * @dbe: self
3018 * @workspace: Can be NULL. In that case a default workspace will be created,
3019 * and project will depend on that.
3020 * @project: Project name. Must NOT be NULL.
3021 * @version: Version of the project, or of the package that project represents.
3022 * If not sure pass "1.0".
3024 * Adds a new project to db.
3025 * ~~~ Thread note: this function locks the mutex ~~~
3027 * Returns: TRUE if operation is successful.
3029 gboolean
3030 symbol_db_engine_add_new_project (SymbolDBEngine * dbe, const gchar * workspace,
3031 const gchar * project, const gchar* version)
3033 const GdaSet *plist;
3034 const GdaStatement *stmt;
3035 GdaHolder *param;
3036 const gchar *workspace_name;
3037 gint wks_id;
3038 SymbolDBEnginePriv *priv;
3039 GValue v = {0};
3041 g_return_val_if_fail (dbe != NULL, FALSE);
3042 priv = dbe->priv;
3044 SDB_LOCK(priv);
3046 if (workspace == NULL)
3048 workspace_name = "anjuta_workspace_default";
3050 DEBUG_PRINT ("adding default workspace... '%s'", workspace_name);
3051 SDB_GVALUE_SET_STATIC_STRING(v, workspace_name);
3053 if ((wks_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3054 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
3055 "wsname",
3056 &v)) <= 0)
3059 /* symbol_db_engine_add_new_workspace 'll lock so unlock here before */
3060 SDB_UNLOCK(priv);
3062 if (symbol_db_engine_add_new_workspace (dbe, workspace_name) == FALSE)
3064 DEBUG_PRINT ("%s", "Project cannot be added because a default workspace "
3065 "cannot be created");
3066 return FALSE;
3068 /* relock */
3069 SDB_LOCK(priv);
3072 else
3074 workspace_name = workspace;
3077 g_value_unset (&v);
3079 /* insert new project */
3080 if ((stmt =
3081 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_PROJECT_NEW)) == NULL)
3083 g_warning ("query is null");
3084 SDB_UNLOCK(priv);
3085 return FALSE;
3088 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_PROJECT_NEW);
3090 /* lookup parameters */
3091 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3093 g_warning ("param prjname is NULL from pquery!");
3094 SDB_UNLOCK(priv);
3095 return FALSE;
3098 SDB_PARAM_SET_STRING(param, project);
3100 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3102 g_warning ("param prjversion is NULL from pquery!");
3103 SDB_UNLOCK(priv);
3104 return FALSE;
3107 SDB_PARAM_SET_STRING(param, version);
3109 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
3111 g_warning ("param wsname is NULL from pquery!");
3112 SDB_UNLOCK(priv);
3113 return FALSE;
3116 SDB_PARAM_SET_STRING(param, workspace_name);
3118 /* execute the query with parameters just set */
3119 if (gda_connection_statement_execute_non_select (priv->db_connection,
3120 (GdaStatement*)stmt,
3121 (GdaSet*)plist, NULL, NULL) == -1)
3123 SDB_UNLOCK(priv);
3124 return FALSE;
3127 SDB_UNLOCK(priv);
3128 return TRUE;
3131 /* ### Thread note: this function inherits the mutex lock ### */
3132 /* Uses cache lookup to speed up symbols search. */
3133 static gint
3134 sdb_engine_add_new_language (SymbolDBEngine * dbe, const gchar *language)
3136 gint table_id;
3137 SymbolDBEnginePriv *priv;
3138 GValue v = {0};
3140 if (language == NULL)
3141 return -1;
3143 priv = dbe->priv;
3145 /* cache lookup */
3146 table_id = sdb_engine_cache_lookup (priv->language_cache, language);
3147 if (table_id != -1)
3149 return table_id;
3152 SDB_GVALUE_SET_STATIC_STRING (v, language);
3154 /* check for an already existing table with language "name". */
3155 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3156 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
3157 "langname",
3158 &v)) < 0)
3160 /* insert a new entry on db */
3161 const GdaSet *plist;
3162 const GdaStatement *stmt;
3163 GdaHolder *param;
3164 GdaSet *last_inserted = NULL;
3166 g_value_unset (&v);
3168 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_LANGUAGE_NEW))
3169 == NULL)
3171 g_warning ("query is null");
3172 return FALSE;
3175 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_LANGUAGE_NEW);
3177 if ((param = gda_set_get_holder ((GdaSet*)plist, "langname")) == NULL)
3179 g_warning ("param langname is NULL from pquery!");
3180 return FALSE;
3183 SDB_PARAM_SET_STRING(param, language);
3185 /* execute the query with parameters just set */
3186 if (gda_connection_statement_execute_non_select (priv->db_connection,
3187 (GdaStatement*)stmt,
3188 (GdaSet*)plist, &last_inserted,
3189 NULL) == -1)
3191 table_id = -1;
3193 else {
3194 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3195 table_id = g_value_get_int (value);
3196 sdb_engine_insert_cache (priv->language_cache, language, table_id);
3199 if (last_inserted)
3200 g_object_unref (last_inserted);
3203 return table_id;
3207 * ~~~ Thread note: this function locks the mutex ~~~
3209 * Add a file to project.
3210 * This function requires an opened db, i.e. calling before
3211 * symbol_db_engine_open_db ()
3212 * filepath: referes to a full file path.
3213 * project:
3214 * WARNING: we suppose that project_directory is already set.
3215 * WARNING2: we suppose that the given local_filepath include the project_directory path.
3216 * + correct example: local_filepath: /home/user/projects/foo_project/src/main.c
3217 * project_directory: /home/user/projects/foo_project
3218 * - wrong one: local_filepath: /tmp/foo.c
3219 * project_directory: /home/user/projects/foo_project
3221 static gboolean
3222 sdb_engine_add_new_db_file (SymbolDBEngine * dbe, const gchar * project_name,
3223 const gchar *project_version, const gchar * local_filepath,
3224 const gchar * language)
3226 const GdaSet *plist;
3227 const GdaStatement *stmt;
3228 GdaHolder *param;
3229 GError * error = NULL;
3230 SymbolDBEnginePriv *priv;
3231 gint language_id;
3232 GValue v = {0};
3234 priv = dbe->priv;
3236 /* check if the file is a correct one compared to the local_filepath */
3237 if (strstr (local_filepath, priv->project_directory) == NULL)
3238 return FALSE;
3240 SDB_LOCK(priv);
3242 /* we're gonna set the file relative to the project folder, not the full one.
3243 * e.g.: we have a file on disk: "/tmp/foo/src/file.c" and a db_directory located on
3244 * "/tmp/foo/". The entry on db will be "src/file.c"
3246 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, local_filepath);
3247 if (relative_path == NULL)
3249 DEBUG_PRINT ("%s", "relative_path == NULL");
3250 SDB_UNLOCK(priv);
3251 return FALSE;
3254 /* insert a new entry on db */
3255 language_id = sdb_engine_add_new_language (dbe, language);
3256 if (language_id < 0)
3258 DEBUG_PRINT ("Unknown language: %s", language);
3259 SDB_UNLOCK(priv);
3260 return FALSE;
3263 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_FILE_NEW))
3264 == NULL)
3266 g_warning ("query is null");
3267 SDB_UNLOCK(priv);
3268 return FALSE;
3271 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_FILE_NEW);
3273 /* filepath parameter */
3274 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
3276 g_warning ("param langname is NULL from pquery!");
3277 SDB_UNLOCK(priv);
3278 return FALSE;
3281 SDB_PARAM_SET_STRING(param, relative_path);
3283 /* project name parameter */
3284 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3286 g_warning ("param prjname is NULL from pquery!");
3287 SDB_UNLOCK(priv);
3288 return FALSE;
3291 SDB_PARAM_SET_STRING(param, project_name);
3293 /* prjversion parameter */
3294 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3296 g_warning ("param prjversion is NULL from pquery!");
3297 SDB_UNLOCK(priv);
3298 return FALSE;
3301 SDB_PARAM_SET_STRING(param, project_version);
3303 /* language id parameter */
3304 if ((param = gda_set_get_holder ((GdaSet*)plist, "langid")) == NULL)
3306 g_warning ("param langid is NULL from pquery!");
3307 SDB_UNLOCK(priv);
3308 return FALSE;
3311 SDB_PARAM_SET_INT(param, language_id);
3313 /* execute the query with parameters just set */
3314 if (gda_connection_statement_execute_non_select (priv->db_connection,
3315 (GdaStatement*)stmt,
3316 (GdaSet*)plist, NULL,
3317 &error) == -1)
3319 if (error)
3321 gchar * sql_str = gda_statement_to_sql_extended ((GdaStatement*)stmt,
3322 priv->db_connection, (GdaSet*)plist, 0, NULL, NULL);
3324 DEBUG_PRINT ("%s [%s]", error->message, sql_str);
3325 g_error_free (error);
3326 g_free (sql_str);
3329 SDB_UNLOCK(priv);
3330 return FALSE;
3333 SDB_UNLOCK(priv);
3334 return TRUE;
3337 /* ~~~ Thread note: this function locks the mutex ~~~ */
3338 static gint
3339 sdb_engine_get_unique_scan_id (SymbolDBEngine * dbe)
3341 SymbolDBEnginePriv *priv;
3342 gint ret_id;
3344 priv = dbe->priv;
3346 SDB_LOCK(priv);
3348 priv->scan_process_id_sequence++;
3349 ret_id = priv->scan_process_id_sequence;
3351 SDB_UNLOCK(priv);
3352 return ret_id;
3356 * symbol_db_engine_add_new_files_async:
3357 * @dbe: self
3358 * @lang_manager: IAnjutaLanguage language manager.
3359 * @project_name:
3360 * @project_version:
3361 * @sources_array: requires full path to files on disk. Anjuta-tags itself requires that.
3362 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3363 * a language string to represent the file.
3364 * An example of files_path array composition can be:
3365 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3366 * "/home/user/foo_project/foo3.java".
3367 * NOTE: all the files MUST exist. So check for their existence before call
3368 * this function. The function'll write entries on the db.
3370 * See symbol_db_engine_add_new_files_full () for doc.
3371 * This function adds files to db in a quicker way than
3372 * symbol_db_engine_add_new_files_full because you won't have to specify the
3373 * GPtrArray of languages, but it'll try to autodetect them.
3374 * When added, the files are forced to be scanned.
3377 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3378 * until the scanner is available. So you should use the gint id returned to identify
3379 * if a 'scan-end' signal is the one that you were expecting.
3380 * Please note also that, if db is disconnected before the waiting queue is processed,
3381 * the scan of those files won't be performed.
3383 * Returns: scan process id if insertion is successful, -1 on error.
3385 gint
3386 symbol_db_engine_add_new_files_async (SymbolDBEngine *dbe,
3387 IAnjutaLanguage* lang_manager,
3388 const gchar * project_name,
3389 const gchar * project_version,
3390 const GPtrArray *sources_array)
3392 GPtrArray *lang_array;
3393 gint i;
3395 g_return_val_if_fail (dbe != NULL, FALSE);
3396 g_return_val_if_fail (lang_manager != NULL, FALSE);
3397 g_return_val_if_fail (sources_array != NULL, FALSE);
3399 lang_array = g_ptr_array_new_with_free_func (g_free);
3401 for (i = 0; i < sources_array->len; i++)
3403 IAnjutaLanguageId lang_id;
3404 GFile *gfile;
3405 GFileInfo *gfile_info;
3406 const gchar *file_mime;
3407 const gchar *lang;
3408 const gchar *local_filename;
3410 local_filename = g_ptr_array_index (sources_array, i);
3411 gfile = g_file_new_for_path (local_filename);
3412 gfile_info = g_file_query_info (gfile,
3413 "standard::content-type",
3414 G_FILE_QUERY_INFO_NONE,
3415 NULL,
3416 NULL);
3417 if (gfile_info == NULL)
3419 g_warning ("GFileInfo corresponding to %s was NULL", local_filename);
3420 g_object_unref (gfile);
3421 continue;
3424 file_mime = g_file_info_get_attribute_string (gfile_info,
3425 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
3427 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
3428 file_mime, NULL);
3430 if (!lang_id)
3432 g_warning ("Language not found for %s was NULL", local_filename);
3433 g_object_unref (gfile);
3434 g_object_unref (gfile_info);
3435 continue;
3438 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
3439 g_ptr_array_add (lang_array, g_strdup (lang));
3440 g_object_unref (gfile);
3441 g_object_unref (gfile_info);
3444 gint res = symbol_db_engine_add_new_files_full_async (dbe, project_name, project_version,
3445 sources_array, lang_array, TRUE);
3447 /* free resources */
3448 g_ptr_array_unref (lang_array);
3450 return res;
3453 /**
3454 * symbol_db_engine_add_new_files_full_async:
3455 * @dbe: self
3456 * @project_name: something like 'foo_project', or 'helloworld_project'. Can be NULL,
3457 * for example when you're populating after abort.
3458 * @project_version: The version of the project.
3459 * @files_path: requires full path to files on disk. Anjuta-tags itself requires that.
3460 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3461 * a language string to represent the file.
3462 * An example of files_path array composition can be:
3463 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3464 * "/home/user/foo_project/foo3.java".
3465 * NOTE: all the files MUST exist. So check for their existence before call
3466 * this function. The function'll write entries on the db.
3467 * @languages: is an array of 'languages'. It must have the same number of
3468 * elments that files_path has. It should be populated like this: "C", "C++",
3469 * "Java" etc.
3470 * This is done to be normalized with the language-manager plugin.
3471 * @force_scan: If FALSE a check on db will be done to see
3472 * whether the file is already present or not. In the latter care the scan will begin.
3474 * Add a group of files to a project. It will perform also
3475 * a symbols scannig/populating of db if force_scan is TRUE.
3476 * This function requires an opened db, i.e. You must test db ststus with
3477 * symbol_db_engine_open_db () before.
3478 * The function must be called from within the main thread.
3480 * Note: If some file fails to enter into the db the function will just skip them.
3483 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3484 * until the scanner is available. So you should use the gint id returned to identify
3485 * if a 'scan-end' signal is the one that you were expecting.
3486 * Please note also that, if db is disconnected before the waiting queue is processed,
3487 * the scan of those files won't be performed.
3489 * Returns: scan process id if insertion is successful, -1 on error.
3491 gint
3492 symbol_db_engine_add_new_files_full_async (SymbolDBEngine * dbe,
3493 const gchar * project_name,
3494 const gchar * project_version,
3495 const GPtrArray * files_path,
3496 const GPtrArray * languages,
3497 gboolean force_scan)
3499 gint i;
3500 SymbolDBEnginePriv *priv;
3501 GPtrArray * filtered_files_path;
3502 gboolean ret_code;
3503 gint ret_id, scan_id;
3505 g_return_val_if_fail (dbe != NULL, FALSE);
3506 g_return_val_if_fail (files_path != NULL, FALSE);
3507 g_return_val_if_fail (languages != NULL, FALSE);
3508 priv = dbe->priv;
3510 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
3511 g_return_val_if_fail (files_path->len > 0, FALSE);
3512 g_return_val_if_fail (languages->len > 0, FALSE);
3514 filtered_files_path = g_ptr_array_new ();
3516 for (i = 0; i < files_path->len; i++)
3518 const gchar *node_file = (const gchar *) g_ptr_array_index (files_path, i);
3519 const gchar *node_lang = (const gchar *) g_ptr_array_index (languages, i);
3521 if (force_scan == FALSE)
3523 /* test the existence of the file in db */
3524 if (symbol_db_engine_file_exists (dbe, node_file) == TRUE)
3526 /* we don't want to touch the already present file... within
3527 * its symbols
3529 continue;
3533 if (project_name != NULL &&
3534 sdb_engine_add_new_db_file (dbe, project_name, project_version, node_file,
3535 node_lang) == FALSE)
3537 DEBUG_PRINT ("Error processing file %s, db_directory %s, project_name %s, "
3538 "project_version %s, project_directory %s", node_file,
3539 priv->db_directory, project_name, project_version,
3540 priv->project_directory);
3541 continue;
3544 /* note: we don't use g_strdup () here because we'll free the filtered_files_path
3545 * before returning from this function.
3547 g_ptr_array_add (filtered_files_path, (gpointer)node_file);
3550 /* perform the scan of files. It will spawn a fork() process with
3551 * AnjutaLauncher and ctags in server mode. After the ctags cmd has been
3552 * executed, the populating process'll take place.
3554 scan_id = sdb_engine_get_unique_scan_id (dbe);
3555 ret_code = sdb_engine_scan_files_async (dbe, filtered_files_path, NULL, FALSE, scan_id);
3557 if (ret_code == TRUE)
3559 ret_id = scan_id;
3561 else
3562 ret_id = -1;
3564 /* no need to free the items contained in the array */
3565 g_ptr_array_unref (filtered_files_path);
3566 return ret_id;
3571 * We'll use the GNU regular expressions instead of the glib's GRegex ones because
3572 * the latters are a wrapper of pcre (www.pcre.org) that don't implement the
3573 * \< (begin of word)) and \> (end of word) boundaries.
3574 * Since the regex used here is something complex to reproduce on GRegex
3575 * I don't see any reason to reinvent the (already) working wheel.
3576 * I didn't find a valuable replacement for \< and \> neither on
3577 * http://www.regular-expressions.info/wordboundaries.html nor elsewhere.
3578 * But if some regex geek thinks I'm wrong I'll be glad to see his solution.
3580 * @return NULL on error.
3582 #define RX_STRING "\\\".*\\\""
3583 #define RX_BRACKETEXPR "\\{.*\\}"
3584 #define RX_IDENT "[a-zA-Z_][a-zA-Z0-9_]*"
3585 #define RX_WS "[ \t\n]*"
3586 #define RX_PTR "[\\*&]?\\*?"
3587 #define RX_INITIALIZER "=(" RX_WS RX_IDENT RX_WS ")|=(" RX_WS RX_STRING RX_WS \
3588 ")|=(" RX_WS RX_BRACKETEXPR RX_WS ")" RX_WS
3589 #define RX_ARRAY RX_WS "\\[" RX_WS "[0-9]*" RX_WS "\\]" RX_WS
3591 static gchar*
3592 sdb_engine_extract_type_qualifier (const gchar *string, const gchar *expr)
3594 /* check with a regular expression for the type */
3595 regex_t re;
3596 regmatch_t pm[8]; // 7 sub expression -> 8 matches
3597 memset (&pm, -1, sizeof(pm));
3599 * this regexp catches things like:
3600 * a) std::vector<char*> exp1[124] [12], *exp2, expr;
3601 * b) QClass* expr1, expr2, expr;
3602 * c) int a,b; char r[12] = "test, argument", q[2] = { 't', 'e' }, expr;
3604 * it CAN be fooled, if you really want it, but it should
3605 * work for 99% of all situations.
3607 * QString
3608 * var;
3609 * in 2 lines does not work, because //-comments would often bring wrong results
3612 gchar *res = NULL;
3613 static char pattern[512] =
3614 "(" RX_IDENT "\\>)" /* the 'std' in example a) */
3615 "(::" RX_IDENT ")*" /* ::vector */
3616 "(" RX_WS "<[^>;]*>)?" /* <char *> */
3617 /* other variables for the same ident (string i,j,k;) */
3618 "(" RX_WS RX_PTR RX_WS RX_IDENT RX_WS "(" RX_ARRAY ")*" "(" RX_INITIALIZER ")?," RX_WS ")*"
3619 "[ \t\\*&]*"; /* check again for pointer/reference type */
3621 /* must add a 'termination' symbol to the regexp, otherwise
3622 * 'exp' would match 'expr'
3624 gchar regexp[512];
3625 g_snprintf (regexp, sizeof (regexp), "%s\\<%s\\>", pattern, expr);
3627 /* compile regular expression */
3628 int error = regcomp (&re, regexp, REG_EXTENDED) ;
3629 if (error)
3630 return NULL;
3632 /* this call to regexec finds the first match on the line */
3633 error = regexec (&re, string, 8, &pm[0], 0) ;
3635 /* while matches found */
3636 while (error == 0)
3638 /* subString found between pm.rm_so and pm.rm_eo */
3639 /* only include the ::vector part in the indentifier, if the second
3640 * subpattern matches at all
3642 int len = (pm[2].rm_so != -1 ? pm[2].rm_eo : pm[1].rm_eo) - pm[1].rm_so;
3643 if (res)
3644 free (res);
3645 res = (gchar*) g_malloc0 (len + 1);
3646 if (!res)
3648 regfree (&re);
3649 return NULL;
3651 strncpy (res, string + pm[1].rm_so, len);
3652 res[len] = '\0';
3654 /* This call to regexec finds the next match */
3655 error = regexec (&re, string + pm[0].rm_eo, 8, &pm[0], 0) ;
3656 break;
3658 regfree(&re);
3660 return res;
3663 /* ### Thread note: this function inherits the mutex lock ### */
3664 /* Uses cache lookup to speed up symbols search. */
3665 static gint
3666 sdb_engine_add_new_sym_kind (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3668 const gchar *kind_name;
3669 gint table_id;
3670 SymbolDBEnginePriv *priv;
3671 GValue v = {0};
3673 priv = dbe->priv;
3675 /* we assume that tag_entry is != NULL */
3676 kind_name = tag_entry->kind;
3678 /* no kind associated with current tag */
3679 if (kind_name == NULL)
3680 return -1;
3682 /* cache lookup */
3683 table_id = sdb_engine_cache_lookup (priv->kind_cache, kind_name);
3684 if (table_id != -1)
3686 return table_id;
3689 SDB_GVALUE_SET_STATIC_STRING (v, kind_name);
3691 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3692 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
3693 "kindname",
3694 &v)) < 0)
3696 const GdaSet *plist;
3697 const GdaStatement *stmt;
3698 GdaHolder *param;
3699 GdaSet *last_inserted = NULL;
3700 gint is_container = 0;
3701 SymType sym_type;
3702 GError * error = NULL;
3704 g_value_unset (&v);
3706 /* not found. Go on with inserting */
3707 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYM_KIND_NEW))
3708 == NULL)
3710 g_warning ("query is null");
3711 return -1;
3714 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_KIND_NEW);
3716 /* kindname parameter */
3717 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindname")) == NULL)
3719 g_warning ("param kindname is NULL from pquery!");
3720 return FALSE;
3723 SDB_PARAM_SET_STRING (param, kind_name);
3725 /* container parameter */
3726 if ((param = gda_set_get_holder ((GdaSet*)plist, "container")) == NULL)
3728 g_warning ("param container is NULL from pquery!");
3729 return FALSE;
3732 sym_type = GPOINTER_TO_SIZE (g_hash_table_lookup (priv->sym_type_conversion_hash,
3733 kind_name));
3735 if (sym_type & IANJUTA_SYMBOL_TYPE_SCOPE_CONTAINER)
3736 is_container = 1;
3738 SDB_PARAM_SET_INT (param, is_container);
3740 /* execute the query with parameters just set */
3741 if (gda_connection_statement_execute_non_select(priv->db_connection,
3742 (GdaStatement*)stmt,
3743 (GdaSet*)plist, &last_inserted,
3744 NULL) == -1)
3746 table_id = -1;
3748 else
3750 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3751 table_id = g_value_get_int (value);
3752 /* we should cache only tables which are != -1 */
3753 sdb_engine_insert_cache (priv->kind_cache, kind_name, table_id);
3755 if (last_inserted)
3756 g_object_unref (last_inserted);
3758 if (error)
3760 g_warning ("SQL error: %s", error->message);
3761 g_error_free (error);
3765 return table_id;
3768 /* ### Thread note: this function inherits the mutex lock ### */
3769 /* Uses cache lookup to speed up symbols search. */
3770 static gint
3771 sdb_engine_add_new_sym_access (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3773 const gchar *access;
3774 gint table_id;
3775 SymbolDBEnginePriv *priv;
3776 GValue v = {0};
3778 priv = dbe->priv;
3781 /* we assume that tag_entry is != NULL */
3782 if ((access = tagsField (tag_entry, "access")) == NULL)
3784 /* no access associated with current tag */
3785 return -1;
3788 /* cache lookup */
3789 table_id = sdb_engine_cache_lookup (priv->access_cache, access);
3790 if (table_id != -1)
3792 return table_id;
3795 SDB_GVALUE_SET_STATIC_STRING (v, access);
3797 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3798 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
3799 "accesskind",
3800 &v)) < 0)
3802 const GdaSet *plist;
3803 const GdaStatement *stmt;
3804 GdaHolder *param;
3805 GdaSet *last_inserted = NULL;
3807 g_value_unset (&v);
3809 /* not found. Go on with inserting */
3810 if ((stmt =
3811 sdb_engine_get_statement_by_query_id (dbe,
3812 PREP_QUERY_SYM_ACCESS_NEW)) == NULL)
3814 g_warning ("query is null");
3815 return -1;
3818 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_ACCESS_NEW);
3820 /* accesskind parameter */
3821 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskind")) == NULL)
3823 g_warning ("param accesskind is NULL from pquery!");
3824 return -1;
3827 SDB_PARAM_SET_STRING (param, access);
3829 /* execute the query with parameters just set */
3830 if (gda_connection_statement_execute_non_select (priv->db_connection,
3831 (GdaStatement*)stmt,
3832 (GdaSet*)plist, &last_inserted,
3833 NULL) == -1)
3835 table_id = -1;
3837 else
3839 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3840 table_id = g_value_get_int (value);
3841 /* we should cache only tables which are != -1 */
3842 sdb_engine_insert_cache (priv->access_cache, access, table_id);
3845 if (last_inserted)
3846 g_object_unref (last_inserted);
3849 return table_id;
3852 /* ### Thread note: this function inherits the mutex lock ### */
3853 /* Uses cache lookup to speed up symbols search. */
3854 static gint
3855 sdb_engine_add_new_sym_implementation (SymbolDBEngine * dbe,
3856 const tagEntry * tag_entry)
3858 const gchar *implementation;
3859 gint table_id;
3860 SymbolDBEnginePriv *priv;
3861 GValue v = {0};
3863 priv = dbe->priv;
3865 /* we assume that tag_entry is != NULL */
3866 if ((implementation = tagsField (tag_entry, "implementation")) == NULL)
3868 /* no implementation associated with current tag */
3869 return -1;
3872 /* cache lookup */
3873 table_id = sdb_engine_cache_lookup (priv->implementation_cache, implementation);
3874 if (table_id != -1)
3876 return table_id;
3879 SDB_GVALUE_SET_STATIC_STRING(v, implementation);
3881 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3882 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
3883 "implekind",
3884 &v)) < 0)
3886 const GdaSet *plist;
3887 const GdaStatement *stmt;
3888 GdaHolder *param;
3889 GdaSet *last_inserted = NULL;
3891 g_value_unset (&v);
3893 /* not found. Go on with inserting */
3894 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
3895 PREP_QUERY_SYM_IMPLEMENTATION_NEW)) ==
3896 NULL)
3898 g_warning ("query is null");
3899 return -1;
3902 plist = sdb_engine_get_query_parameters_list (dbe,
3903 PREP_QUERY_SYM_IMPLEMENTATION_NEW);
3905 /* implekind parameter */
3906 if ((param = gda_set_get_holder ((GdaSet*)plist, "implekind")) == NULL)
3908 g_warning ("param accesskind is NULL from pquery!");
3909 return -1;
3912 SDB_PARAM_SET_STRING(param, implementation);
3914 /* execute the query with parameters just set */
3915 if (gda_connection_statement_execute_non_select (priv->db_connection,
3916 (GdaStatement*)stmt,
3917 (GdaSet*)plist, &last_inserted,
3918 NULL) == -1)
3920 table_id = -1;
3922 else
3924 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3925 table_id = g_value_get_int (value);
3926 /* we should cache only tables which are != -1 */
3927 sdb_engine_insert_cache (priv->implementation_cache, implementation,
3928 table_id);
3930 if (last_inserted)
3931 g_object_unref (last_inserted);
3934 return table_id;
3937 /* ### Thread note: this function inherits the mutex lock ### */
3938 static void
3939 sdb_engine_add_new_heritage (SymbolDBEngine * dbe, gint base_symbol_id,
3940 gint derived_symbol_id)
3942 const GdaSet *plist;
3943 const GdaStatement *stmt;
3944 GdaHolder *param;
3945 SymbolDBEnginePriv *priv;
3946 GValue v = {0};
3948 g_return_if_fail (base_symbol_id > 0);
3949 g_return_if_fail (derived_symbol_id > 0);
3951 priv = dbe->priv;
3953 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_HERITAGE_NEW))
3954 == NULL)
3956 g_warning ("query is null");
3957 return;
3960 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_HERITAGE_NEW);
3962 /* symbase parameter */
3963 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbase")) == NULL)
3965 g_warning ("param accesskind is NULL from pquery!");
3966 return;
3969 SDB_PARAM_SET_INT(param, base_symbol_id);
3971 /* symderived id parameter */
3972 if ((param = gda_set_get_holder ((GdaSet*)plist, "symderived")) == NULL)
3974 g_warning ("param symderived is NULL from pquery!");
3975 return;
3978 SDB_PARAM_SET_INT(param, derived_symbol_id);
3980 /* execute the query with parameters just set */
3981 if (gda_connection_statement_execute_non_select (priv->db_connection,
3982 (GdaStatement*)stmt,
3983 (GdaSet*)plist, NULL,
3984 NULL) == -1)
3986 g_warning ("Error adding heritage");
3991 /* ### Thread note: this function inherits the mutex lock ### */
3992 static GNUC_INLINE gint
3993 sdb_engine_add_new_scope_definition (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3995 const gchar *scope;
3996 gint table_id;
3997 const GdaSet *plist;
3998 const GdaStatement *stmt;
3999 GdaHolder *param;
4000 GdaSet *last_inserted = NULL;
4001 SymbolDBEnginePriv *priv;
4002 GValue v = {0};
4004 g_return_val_if_fail (tag_entry->kind != NULL, -1);
4006 priv = dbe->priv;
4009 /* This symbol will define a scope which name is tag_entry->name
4010 * For example if we get a tag MyFoo with kind "namespace", it will define
4011 * the "MyFoo" scope, which type is "namespace MyFoo"
4013 scope = tag_entry->name;
4015 /* filter out 'variable' and 'member' kinds. They define no scope. */
4016 if (g_strcmp0 (tag_entry->kind, "variable") == 0 ||
4017 g_strcmp0 (tag_entry->kind, "member") == 0)
4019 return -1;
4022 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SCOPE_NEW))
4023 == NULL)
4025 g_warning ("query is null");
4026 return -1;
4029 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SCOPE_NEW);
4031 /* scope parameter */
4032 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
4034 g_warning ("param scope is NULL from pquery!");
4035 return -1;
4038 SDB_PARAM_SET_STRING (param, scope);
4040 /* execute the query with parameters just set */
4041 if (gda_connection_statement_execute_non_select (priv->db_connection,
4042 (GdaStatement*)stmt,
4043 (GdaSet*)plist, &last_inserted,
4044 NULL) == -1)
4047 GValue v = {0, };
4048 SDB_GVALUE_SET_STATIC_STRING(v, scope);
4050 /* try to get an already existing scope */
4051 table_id = sdb_engine_get_tuple_id_by_unique_name (dbe, PREP_QUERY_GET_SCOPE_ID,
4052 "scope", &v);
4054 else
4056 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4057 table_id = g_value_get_int (value);
4060 if (last_inserted)
4061 g_object_unref (last_inserted);
4063 return table_id;
4067 * ### Thread note: this function inherits the mutex lock ###
4069 * Saves the tagEntry info for a second pass parsing.
4070 * Usually we don't know all the symbol at the first scan of the tags. We need
4071 * a second one.
4074 static GNUC_INLINE void
4075 sdb_engine_add_new_tmp_heritage_scope (SymbolDBEngine * dbe,
4076 const tagEntry * tag_entry,
4077 gint symbol_referer_id)
4079 SymbolDBEnginePriv *priv;
4080 const gchar *field_inherits, *field_struct, *field_typeref,
4081 *field_enum, *field_union, *field_class, *field_namespace;
4082 TableMapTmpHeritage * node;
4084 priv = dbe->priv;
4086 node = g_slice_new0 (TableMapTmpHeritage);
4087 node->symbol_referer_id = symbol_referer_id;
4089 if ((field_inherits = tagsField (tag_entry, "inherits")) != NULL)
4091 node->field_inherits = g_strdup (field_inherits);
4094 if ((field_struct = tagsField (tag_entry, "struct")) != NULL)
4096 node->field_struct = g_strdup (field_struct);
4099 if ((field_typeref = tagsField (tag_entry, "typeref")) != NULL)
4101 node->field_typeref = g_strdup (field_typeref);
4104 if ((field_enum = tagsField (tag_entry, "enum")) != NULL)
4106 node->field_enum = g_strdup (field_enum);
4109 if ((field_union = tagsField (tag_entry, "union")) != NULL)
4111 node->field_union = g_strdup (field_union);
4114 if ((field_class = tagsField (tag_entry, "class")) != NULL)
4116 node->field_class = g_strdup (field_class);
4119 if ((field_namespace = tagsField (tag_entry, "namespace")) != NULL)
4121 node->field_namespace = g_strdup (field_namespace);
4124 g_queue_push_head (priv->tmp_heritage_tablemap, node);
4127 /**
4128 * ### Thread note: this function inherits the mutex lock ###
4130 * Return the symbol_id of the changed symbol
4132 static GNUC_INLINE void
4133 sdb_engine_second_pass_update_scope_1 (SymbolDBEngine * dbe,
4134 TableMapTmpHeritage * node,
4135 gchar * token_name,
4136 const gchar * token_value)
4138 gint symbol_referer_id;
4139 const gchar *tmp_str;
4140 gchar **tmp_str_splitted;
4141 gint tmp_str_splitted_length;
4142 gchar *object_name = NULL;
4143 gboolean free_token_name = FALSE;
4144 const GdaSet *plist;
4145 const GdaStatement *stmt;
4146 GdaHolder *param;
4147 SymbolDBEnginePriv *priv;
4148 GValue v = {0};
4150 g_return_if_fail (token_value != NULL);
4152 priv = dbe->priv;
4153 tmp_str = token_value;
4155 /* we don't need empty strings */
4156 if (strlen (tmp_str) <= 0)
4158 return;
4161 /* we could have something like "First::Second::Third::Fourth" as tmp_str, so
4162 * take only the lastscope, in this case 'Fourth'.
4164 tmp_str_splitted = g_strsplit (tmp_str, ":", 0);
4165 tmp_str_splitted_length = g_strv_length (tmp_str_splitted);
4167 if (tmp_str_splitted_length > 0)
4169 /* handle special typedef case. Usually we have something like struct:my_foo.
4170 * splitting we have [0]-> struct [1]-> my_foo
4172 if (g_strcmp0 (token_name, "typedef") == 0)
4174 free_token_name = TRUE;
4175 token_name = g_strdup (tmp_str_splitted[0]);
4178 object_name = g_strdup (tmp_str_splitted[tmp_str_splitted_length - 1]);
4180 else
4182 g_strfreev (tmp_str_splitted);
4183 return;
4186 g_strfreev (tmp_str_splitted);
4188 /* if we reach this point we should have a good scope_id.
4189 * Go on with symbol updating.
4191 symbol_referer_id = node->symbol_referer_id;
4193 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4194 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID))
4195 == NULL)
4197 g_warning ("query is null");
4198 return;
4201 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID);
4203 /* tokenname parameter */
4204 if ((param = gda_set_get_holder ((GdaSet*)plist, "tokenname")) == NULL)
4206 g_warning ("param tokenname is NULL from pquery!");
4207 return;
4210 SDB_PARAM_SET_STRING(param, token_name);
4212 /* objectname parameter */
4213 if ((param = gda_set_get_holder ((GdaSet*)plist, "objectname")) == NULL)
4215 g_warning ("param objectname is NULL from pquery!");
4216 return;
4219 SDB_PARAM_SET_STRING(param, object_name);
4221 /* symbolid parameter */
4222 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4224 g_warning ("param symbolid is NULL from pquery!");
4225 return;
4228 SDB_PARAM_SET_INT(param, symbol_referer_id);
4230 /* execute the query with parameters just set */
4231 gda_connection_statement_execute_non_select (priv->db_connection,
4232 (GdaStatement*)stmt,
4233 (GdaSet*)plist, NULL,
4234 NULL);
4236 if (free_token_name)
4237 g_free (token_name);
4238 g_free (object_name);
4240 return;
4244 * ### Thread note: this function inherits the mutex lock ###
4246 * @param data Must be filled with some values. It must have num_rows > 0
4247 * @note *CALL THIS BEFORE second_pass_update_heritage ()*
4248 * @note *DO NOT FREE data* inside this function.
4250 static void
4251 sdb_engine_second_pass_update_scope (SymbolDBEngine * dbe)
4253 SymbolDBEnginePriv *priv;
4255 * Fill up the scope.
4256 * The case: "my_foo_func_1" is the name of the current tag parsed.
4257 * Suppose we have a namespace MyFooNamespace, under which is declared
4258 * a class MyFooClass. Under that class there are some funcs like
4259 * my_foo_func_1 () etc. ctags will present us this info about
4260 * my_foo_func_1 ():
4261 * "class : MyFooNamespace::MyFooClass"
4262 * but hey! We don't need to know the namespace here, we just want to
4263 * know that my_foo_func_1 is in the scope of MyFooClass. That one will
4264 * then be mapped inside MyFooNamespace, but that's another thing.
4265 * Go on with the parsing then.
4267 gint i;
4268 gsize queue_length;
4270 priv = dbe->priv;
4272 DEBUG_PRINT ("Processing %d rows", g_queue_get_length (priv->tmp_heritage_tablemap));
4274 /* get a fixed length. There may be some tail_pushes during this loop */
4275 queue_length = g_queue_get_length (priv->tmp_heritage_tablemap);
4277 for (i = 0; i < queue_length; i++)
4279 TableMapTmpHeritage *node;
4280 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4282 if (node->field_class != NULL)
4284 sdb_engine_second_pass_update_scope_1 (dbe, node, "class", node->field_class);
4287 if (node->field_struct != NULL)
4289 sdb_engine_second_pass_update_scope_1 (dbe, node, "struct", node->field_struct);
4292 if (node->field_typeref != NULL)
4294 /* this is a "typedef", not a "typeref". */
4295 sdb_engine_second_pass_update_scope_1 (dbe, node, "typedef", node->field_typeref);
4298 if (node->field_enum != NULL)
4300 sdb_engine_second_pass_update_scope_1 (dbe, node, "enum", node->field_enum);
4303 if (node->field_union != NULL)
4305 sdb_engine_second_pass_update_scope_1 (dbe, node, "union", node->field_union);
4308 if (node->field_namespace != NULL)
4310 sdb_engine_second_pass_update_scope_1 (dbe, node, "namespace", node->field_namespace);
4313 /* last check: if inherits is not null keep the node for a later task */
4314 if (node->field_inherits != NULL)
4316 g_queue_push_tail (priv->tmp_heritage_tablemap, node);
4318 else
4320 sdb_engine_tablemap_tmp_heritage_destroy (node);
4327 * ### Thread note: this function inherits the mutex lock ###
4329 * @param data Must be filled with some values. It must have num_rows > 0
4330 * @note *CALL THIS AFTER second_pass_update_scope ()*
4332 static void
4333 sdb_engine_second_pass_update_heritage (SymbolDBEngine * dbe)
4335 #if 0
4336 gint i;
4337 SymbolDBEnginePriv *priv;
4339 g_return_if_fail (dbe != NULL);
4341 priv = dbe->priv;
4343 DEBUG_PRINT ("Updating heritage... (%d) elements",
4344 g_queue_get_length (priv->tmp_heritage_tablemap));
4346 for (i = 0; i < g_queue_get_length (priv->tmp_heritage_tablemap); i++)
4348 const gchar *inherits;
4349 gchar *item;
4350 gchar **inherits_list;
4351 gint j;
4352 TableMapTmpHeritage *node;
4354 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4355 inherits = node->field_inherits;
4357 if (inherits == NULL)
4359 g_warning ("Inherits was NULL on sym_referer id %d",
4360 node->symbol_referer_id);
4361 sdb_engine_tablemap_tmp_heritage_destroy (node);
4362 continue;
4365 /* there can be multiple inheritance. Check that. */
4366 inherits_list = g_strsplit (inherits, ",", 0);
4368 if (inherits_list != NULL)
4369 DEBUG_PRINT ("inherits %s", inherits);
4371 /* retrieve as much info as we can from the items */
4372 for (j = 0; j < g_strv_length (inherits_list); j++)
4374 gchar **namespaces;
4375 gchar *klass_name;
4376 gchar *namespace_name;
4377 gint namespaces_length;
4378 gint base_klass_id;
4379 gint derived_klass_id;
4381 item = inherits_list[j];
4382 DEBUG_PRINT ("heritage %s", item);
4384 /* A item may have this string form:
4385 * MyFooNamespace1::MyFooNamespace2::MyFooClass
4386 * We should find the field 'MyFooNamespace2' because it's the one
4387 * that is reachable by the scope_id value of the symbol.
4390 namespaces = g_strsplit (item, "::", 0);
4391 namespaces_length = g_strv_length (namespaces);
4393 if (namespaces_length > 1)
4395 /* this is the case in which we have the case with
4396 * namespace + class
4398 namespace_name = g_strdup (namespaces[namespaces_length - 2]);
4399 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4401 else
4403 /* have a last check before setting namespace_name to null.
4404 * check whether the field_namespace is void or not.
4406 const gchar *tmp_namespace;
4407 gchar **tmp_namespace_array = NULL;
4408 gint tmp_namespace_length;
4410 tmp_namespace = node->field_namespace;
4411 if (tmp_namespace != NULL)
4413 tmp_namespace_array = g_strsplit (tmp_namespace, "::", 0);
4414 tmp_namespace_length = g_strv_length (tmp_namespace_array);
4416 if (tmp_namespace_length > 0)
4418 namespace_name =
4419 g_strdup (tmp_namespace_array
4420 [tmp_namespace_length - 1]);
4422 else
4424 namespace_name = NULL;
4427 else
4429 namespace_name = NULL;
4432 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4434 g_strfreev (tmp_namespace_array);
4437 g_strfreev (namespaces);
4439 /* get the derived_klass_id. It should be the
4440 * symbol_referer_id field into __tmp_heritage_scope table
4442 if (node->symbol_referer_id > 0)
4444 derived_klass_id = node->symbol_referer_id;
4446 else
4448 derived_klass_id = 0;
4451 /* ok, search for the symbol_id of the base class */
4452 if (namespace_name == NULL)
4454 GValue *value1;
4456 MP_LEND_OBJ_STR (priv, value1);
4457 g_value_set_static_string (value1, klass_name);
4459 if ((base_klass_id =
4460 sdb_engine_get_tuple_id_by_unique_name (dbe,
4461 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
4462 "klassname",
4463 value1)) < 0)
4465 continue;
4468 else
4470 GValue *value1;
4471 GValue *value2;
4473 MP_LEND_OBJ_STR (priv, value1);
4474 g_value_set_static_string (value1, klass_name);
4476 MP_LEND_OBJ_STR (priv, value2);
4477 g_value_set_static_string (value2, namespace_name);
4479 if ((base_klass_id =
4480 sdb_engine_get_tuple_id_by_unique_name2 (dbe,
4481 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
4482 "klassname",
4483 value1,
4484 "namespacename",
4485 value2)) < 0)
4487 continue;
4491 g_free (namespace_name);
4492 g_free (klass_name);
4494 DEBUG_PRINT ("gonna sdb_engine_add_new_heritage with "
4495 "base_klass_id %d, derived_klass_id %d", base_klass_id,
4496 derived_klass_id);
4497 sdb_engine_add_new_heritage (dbe, base_klass_id, derived_klass_id);
4500 g_strfreev (inherits_list);
4502 #endif
4506 * ### Thread note: this function inherits the mutex lock ###
4508 * Process the temporary table to update the symbols on scope and inheritance
4509 * fields.
4510 * *CALL THIS FUNCTION ONLY AFTER HAVING PARSED ALL THE TAGS ONCE*
4513 static void
4514 sdb_engine_second_pass_do (SymbolDBEngine * dbe)
4516 SymbolDBEnginePriv *priv;
4518 priv = dbe->priv;
4520 /* prepare for scope second scan */
4521 if (g_queue_get_length (priv->tmp_heritage_tablemap) > 0)
4523 sdb_engine_second_pass_update_scope (dbe);
4524 sdb_engine_second_pass_update_heritage (dbe);
4528 GNUC_INLINE static void
4529 sdb_engine_add_new_symbol_case_1 (SymbolDBEngine *dbe,
4530 gint symbol_id,
4531 GdaSet **plist_ptr,
4532 GdaStatement **stmt_ptr)
4534 GdaHolder *param;
4535 GValue v = {0};
4537 const GdaSet * plist = *plist_ptr;
4538 const GdaStatement * stmt = *stmt_ptr;
4540 /* case 1 */
4542 /* create specific query for a fresh new symbol */
4543 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4544 PREP_QUERY_UPDATE_SYMBOL_ALL))
4545 == NULL)
4547 g_warning ("query is null");
4548 return;
4551 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_ALL);
4553 /* symbolid parameter */
4554 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4556 g_warning ("param isfilescope is NULL from pquery!");
4557 return;
4560 SDB_PARAM_SET_INT(param, symbol_id);
4562 *plist_ptr = (GdaSet*)plist;
4563 *stmt_ptr = (GdaStatement*)stmt;
4566 GNUC_INLINE static void
4567 sdb_engine_add_new_symbol_case_2_3 (SymbolDBEngine *dbe,
4568 gint symbol_id,
4569 GdaSet **plist_ptr,
4570 GdaStatement **stmt_ptr,
4571 gint file_defined_id,
4572 const gchar *name,
4573 const gchar *type_type,
4574 const gchar *type_name)
4576 GdaHolder *param;
4577 GValue v = {0};
4579 const GdaSet * plist = *plist_ptr;
4580 const GdaStatement * stmt = *stmt_ptr;
4582 /* create specific query for a fresh new symbol */
4583 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYMBOL_NEW))
4584 == NULL)
4586 g_warning ("query is null");
4587 return;
4590 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYMBOL_NEW);
4592 /* filedefid parameter */
4593 if ((param = gda_set_get_holder ((GdaSet*)plist, "filedefid")) == NULL)
4595 g_warning ("param filedefid is NULL from pquery!");
4596 return;
4599 SDB_PARAM_SET_INT(param, file_defined_id);
4601 /* name parameter */
4602 if ((param = gda_set_get_holder ((GdaSet*)plist, "name")) == NULL)
4604 g_warning ("param name is NULL from pquery!");
4605 return;
4608 SDB_PARAM_SET_STRING(param, name);
4610 /* typetype parameter */
4611 if ((param = gda_set_get_holder ((GdaSet*)plist, "typetype")) == NULL)
4613 g_warning ("param typetype is NULL from pquery!");
4614 return;
4617 SDB_PARAM_SET_STRING(param, type_type);
4619 /* typenameparameter */
4620 if ((param = gda_set_get_holder ((GdaSet*)plist, "typename")) == NULL)
4622 g_warning ("param typename is NULL from pquery!");
4623 return;
4626 SDB_PARAM_SET_STRING(param, type_name);
4628 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
4630 g_warning ("param scope is NULL from pquery!");
4631 return;
4634 /* scope is to be considered the tag name */
4635 SDB_PARAM_SET_STRING(param, name);
4637 *plist_ptr = (GdaSet*)plist;
4638 *stmt_ptr = (GdaStatement*)stmt;
4641 GNUC_INLINE static void
4642 sdb_engine_add_new_symbol_common_params (SymbolDBEngine *dbe,
4643 const GdaSet *plist,
4644 const GdaStatement *stmt,
4645 gint file_position,
4646 gint is_file_scope,
4647 const gchar *signature,
4648 const gchar *returntype,
4649 gint scope_definition_id,
4650 gint scope_id,
4651 gint kind_id,
4652 gint access_kind_id,
4653 gint implementation_kind_id,
4654 gboolean update_flag)
4656 GdaHolder *param;
4657 GValue v = {0};
4659 /* fileposition parameter */
4660 if ((param = gda_set_get_holder ((GdaSet*)plist, "fileposition")) == NULL)
4662 g_warning ("param fileposition is NULL from pquery!");
4663 return;
4666 SDB_PARAM_SET_INT (param, file_position);
4668 /* isfilescope parameter */
4669 if ((param = gda_set_get_holder ((GdaSet*)plist, "isfilescope")) == NULL)
4671 g_warning ("param isfilescope is NULL from pquery!");
4672 return;
4675 SDB_PARAM_SET_INT (param, is_file_scope);
4677 /* signature parameter */
4678 if ((param = gda_set_get_holder ((GdaSet*)plist, "signature")) == NULL)
4680 g_warning ("param signature is NULL from pquery!");
4681 return;
4684 SDB_PARAM_SET_STRING(param, signature);
4686 /* returntype parameter */
4687 if ((param = gda_set_get_holder ((GdaSet*)plist, "returntype")) == NULL)
4689 g_warning ("param returntype is NULL from pquery!");
4690 return;
4693 SDB_PARAM_SET_STRING(param, returntype);
4695 /* scopedefinitionid parameter */
4696 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopedefinitionid")) == NULL)
4698 g_warning ("param scopedefinitionid is NULL from pquery!");
4699 return;
4702 SDB_PARAM_SET_INT(param, scope_definition_id);
4704 /* scopeid parameter */
4705 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopeid")) == NULL)
4707 g_warning ("param scopeid is NULL from pquery!");
4708 return;
4711 SDB_PARAM_SET_INT(param, scope_id);
4713 /* kindid parameter */
4714 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindid")) == NULL)
4716 g_warning ("param kindid is NULL from pquery!");
4717 return;
4720 SDB_PARAM_SET_INT(param, kind_id);
4722 /* accesskindid parameter */
4723 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskindid")) == NULL)
4725 g_warning ("param accesskindid is NULL from pquery!");
4726 return;
4729 SDB_PARAM_SET_INT(param, access_kind_id);
4731 /* implementationkindid parameter */
4732 if ((param = gda_set_get_holder ((GdaSet*)plist, "implementationkindid")) == NULL)
4734 g_warning ("param implementationkindid is NULL from pquery!");
4735 return;
4738 SDB_PARAM_SET_INT(param, implementation_kind_id);
4740 /* updateflag parameter */
4741 if ((param = gda_set_get_holder ((GdaSet*)plist, "updateflag")) == NULL)
4743 g_warning ("param updateflag is NULL from pquery!");
4744 return;
4747 SDB_PARAM_SET_INT(param, update_flag);
4752 * ### Thread note: this function inherits the mutex lock ###
4754 * base_prj_path can be NULL. In that case path info tag_entry will be taken
4755 * as an absolute path.
4756 * fake_file can be used when a buffer updating is being executed. In that
4757 * particular case both base_prj_path and tag_entry->file will be ignored.
4758 * fake_file is real_path of file on disk
4760 static gint
4761 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
4762 gint file_defined_id,
4763 gboolean sym_update)
4765 SymbolDBEnginePriv *priv;
4766 GdaSet *plist;
4767 GdaStatement *stmt;
4768 GdaSet *last_inserted = NULL;
4769 gint table_id, symbol_id;
4770 const gchar* name;
4771 gint file_position = 0;
4772 gint is_file_scope = 0;
4773 const gchar *signature;
4774 const gchar *returntype;
4775 gint scope_definition_id = 0;
4776 gint scope_id = 0;
4777 gint kind_id = 0;
4778 gint access_kind_id = 0;
4779 gint implementation_kind_id = 0;
4780 GValue v1 = {0}, v2 = {0}, v3 = {0}, v4 = {0};
4781 gboolean sym_was_updated = FALSE;
4782 gboolean update_flag;
4783 gchar *type_regex;;
4784 const gchar *type_type;
4785 const gchar *type_name;
4786 gint nrows;
4787 GError * error = NULL;
4789 g_return_val_if_fail (dbe != NULL, -1);
4790 priv = dbe->priv;
4792 /* keep it at 0 if sym_update == false */
4793 update_flag = sym_update;
4795 g_return_val_if_fail (tag_entry != NULL, -1);
4797 /* parse the entry name */
4798 name = tag_entry->name;
4799 file_position = tag_entry->address.lineNumber;
4800 is_file_scope = tag_entry->fileScope;
4803 * signature
4805 signature = tagsField (tag_entry, "signature");
4808 * return type
4810 returntype = tagsField (tag_entry, "returntype");
4813 * sym_type
4815 /* we assume that tag_entry is != NULL */
4816 type_type = tag_entry->kind;
4817 type_regex = NULL;
4819 if (g_strcmp0 (type_type, "member") == 0 ||
4820 g_strcmp0 (type_type, "variable") == 0 ||
4821 g_strcmp0 (type_type, "field") == 0)
4823 type_regex = sdb_engine_extract_type_qualifier (tag_entry->address.pattern,
4824 tag_entry->name);
4825 /*DEBUG_PRINT ("type_regex for %s [kind %s] is %s", tag_entry->name,
4826 tag_entry->kind, type_regex);*/
4827 type_name = type_regex;
4829 /* if the extractor failed we should fallback to the default one */
4830 if (type_name == NULL)
4831 type_name = tag_entry->name;
4832 } else
4834 type_name = tag_entry->name;
4839 * scope definition
4842 /* scope_definition_id tells what scope this symbol defines */
4843 scope_definition_id = sdb_engine_add_new_scope_definition (dbe, tag_entry);
4845 /* the container scopes can be: union, struct, typeref, class, namespace etc.
4846 * this field will be parsed in the second pass.
4848 scope_id = 0;
4850 kind_id = sdb_engine_add_new_sym_kind (dbe, tag_entry);
4852 access_kind_id = sdb_engine_add_new_sym_access (dbe, tag_entry);
4854 implementation_kind_id = sdb_engine_add_new_sym_implementation (dbe, tag_entry);
4856 /* ok: was the symbol updated [at least on it's type_id/name]?
4857 * There are 3 cases:
4858 * #1. The symbol remains the same [at least on unique index key]. We will
4859 * perform only a simple update.
4860 * #2. The symbol has changed: at least on name/type/file. We will insert a
4861 * new symbol on table 'symbol'. Deletion of old one will take place
4862 * at a second stage, when a delete of all symbols with
4863 * 'tmp_flag = 0' will be done.
4864 * #3. The symbol has been deleted. As above it will be deleted at
4865 * a second stage because of the 'tmp_flag = 0'. Triggers will remove
4866 * also scope_ids and other things.
4869 if (update_flag == FALSE) /* symbol is new */
4871 symbol_id = -1;
4873 else /* symbol is updated or a force_update has been given */
4875 /* We should use more value and set them with the same values because
4876 * sdb_engine_get_tuple_id_by_unique_name () will manage them
4878 SDB_GVALUE_SET_STATIC_STRING(v1, name);
4879 SDB_GVALUE_SET_INT(v2, file_defined_id);
4880 SDB_GVALUE_SET_STATIC_STRING(v3, type_type);
4881 SDB_GVALUE_SET_STATIC_STRING(v4, type_name);
4884 * We cannot live without this select because we must know whether a similar
4885 * symbol was already present in the file or not. With this information we
4886 * can see if it's been updated or newly inserted
4888 symbol_id = sdb_engine_get_tuple_id_by_unique_name4 (dbe,
4889 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
4890 "symname", &v1,
4891 "filedefid", &v2,
4892 "typetype", &v3,
4893 "typename", &v4);
4896 /* ok then, parse the symbol id value */
4897 if (symbol_id <= 0)
4899 /* case 2 and 3 */
4900 sym_was_updated = FALSE;
4901 plist = NULL;
4902 stmt = NULL;
4904 sdb_engine_add_new_symbol_case_2_3 (dbe, symbol_id, &plist, &stmt,
4905 file_defined_id, name, type_type, type_name);
4907 else
4909 /* case 1 */
4910 sym_was_updated = TRUE;
4911 plist = NULL;
4912 stmt = NULL;
4914 sdb_engine_add_new_symbol_case_1 (dbe, symbol_id, &plist, &stmt);
4917 /* common params */
4918 sdb_engine_add_new_symbol_common_params (dbe, plist, stmt,
4919 file_position, is_file_scope,
4920 signature, returntype, scope_definition_id,
4921 scope_id, kind_id,
4922 access_kind_id, implementation_kind_id,
4923 update_flag);
4925 /* execute the query with parameters just set */
4926 nrows = gda_connection_statement_execute_non_select (priv->db_connection,
4927 (GdaStatement*)stmt,
4928 (GdaSet*)plist, &last_inserted,
4929 &error);
4931 if (error)
4933 g_warning ("SQL execute_non_select failed: %s", error->message);
4934 g_error_free (error);
4937 if (sym_was_updated == FALSE)
4939 if (nrows > 0)
4941 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4942 table_id = g_value_get_int (value);
4944 /* This is a wrong place to emit the symbol-updated signal. Infact
4945 * db is in a inconsistent state, e.g. inheritance references are still
4946 * *not* calculated.
4947 * So add the symbol id into a queue that will be parsed once and emitted.
4949 g_async_queue_push (priv->inserted_syms_id_aqueue, GINT_TO_POINTER(table_id));
4951 else
4953 table_id = -1;
4956 else
4958 if (nrows > 0)
4960 table_id = symbol_id;
4962 g_async_queue_push (priv->updated_syms_id_aqueue, GINT_TO_POINTER(table_id));
4964 else
4966 table_id = -1;
4970 if (last_inserted)
4971 g_object_unref (last_inserted);
4973 /* post population phase */
4975 /* before returning the table_id we have to fill some infoz on temporary tables
4976 * so that in a second pass we can parse also the heritage and scope fields.
4978 if (table_id > 0)
4979 sdb_engine_add_new_tmp_heritage_scope (dbe, tag_entry, table_id);
4981 g_free (type_regex);
4983 return table_id;
4987 * ### Thread note: this function inherits the mutex lock ###
4989 * Select * from __tmp_removed and emits removed signals.
4991 static void
4992 sdb_engine_detects_removed_ids (SymbolDBEngine *dbe)
4994 const GdaStatement *stmt1, *stmt2;
4995 GdaDataModel *data_model;
4996 SymbolDBEnginePriv *priv;
4997 gint i, num_rows;
4999 priv = dbe->priv;
5001 /* ok, now we should read from __tmp_removed all the symbol ids which have
5002 * been removed, and emit a signal
5004 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5005 PREP_QUERY_GET_REMOVED_IDS))
5006 == NULL)
5008 g_warning ("query is null");
5009 return;
5012 data_model = gda_connection_statement_execute_select (priv->db_connection,
5013 (GdaStatement*)stmt1,
5014 NULL, NULL);
5016 if (GDA_IS_DATA_MODEL (data_model))
5018 if ((num_rows = gda_data_model_get_n_rows (data_model)) <= 0)
5020 DEBUG_PRINT ("nothing to remove");
5021 g_object_unref (data_model);
5022 return;
5025 else
5027 if (data_model != NULL)
5028 g_object_unref (data_model);
5029 return;
5032 /* get and parse the results. */
5033 for (i = 0; i < num_rows; i++)
5035 const GValue *val;
5036 gint tmp;
5037 val = gda_data_model_get_value_at (data_model, 0, i, NULL);
5038 tmp = g_value_get_int (val);
5039 DBESignal *dbesig1;
5040 DBESignal *dbesig2;
5042 dbesig1 = g_slice_new (DBESignal);
5043 dbesig1->value = GINT_TO_POINTER (SYMBOL_REMOVED + 1);
5044 dbesig1->process_id = priv->current_scan_process_id;
5046 dbesig2 = g_slice_new (DBESignal);
5047 dbesig2->value = GINT_TO_POINTER (tmp);
5048 dbesig2->process_id = priv->current_scan_process_id;
5050 g_async_queue_push (priv->signals_aqueue, dbesig1);
5051 g_async_queue_push (priv->signals_aqueue, dbesig2);
5054 g_object_unref (data_model);
5056 /* let's clean the tmp_table */
5057 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5058 PREP_QUERY_TMP_REMOVED_DELETE_ALL))
5059 == NULL)
5061 g_warning ("query is null");
5062 return;
5065 /* bye bye */
5066 gda_connection_statement_execute_non_select (priv->db_connection,
5067 (GdaStatement*)stmt2,
5068 NULL, NULL,
5069 NULL);
5073 * ~~~ Thread note: this function locks the mutex ~~~ *
5075 * WARNING: do not use this function thinking that it would do a scan of symbols
5076 * too. Use symbol_db_engine_update_files_symbols () instead. This one will set
5077 * up some things on db, like removing the 'old' symbols which have not been
5078 * updated.
5080 static gboolean
5081 sdb_engine_update_file (SymbolDBEngine * dbe, const gchar * file_on_db)
5083 const GdaSet *plist1, *plist2, *plist3;
5084 const GdaStatement *stmt1, *stmt2, *stmt3;
5085 GdaHolder *param;
5086 SymbolDBEnginePriv *priv;
5087 GValue v = {0};
5089 priv = dbe->priv;
5091 SDB_LOCK(priv);
5093 /* if we're updating symbols we must do some other operations on db
5094 * symbols, like remove the ones which don't have an update_flag = 1
5095 * per updated file.
5098 /* good. Go on with removing of old symbols, marked by a
5099 * update_flag = 0.
5102 /* Triggers will take care of updating/deleting connected symbols
5103 * tuples, like sym_kind, sym_type etc */
5104 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5105 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS)) == NULL)
5107 g_warning ("query is null");
5108 SDB_UNLOCK(priv);
5110 return FALSE;
5113 plist1 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS);
5115 if ((param = gda_set_get_holder ((GdaSet*)plist1, "filepath")) == NULL)
5117 g_warning ("param filepath is NULL from pquery!");
5118 SDB_UNLOCK(priv);
5119 return FALSE;
5122 SDB_PARAM_SET_STRING(param, file_on_db);
5124 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt1,
5125 (GdaSet*)plist1, NULL, NULL);
5127 /* emits removed symbols signals */
5128 sdb_engine_detects_removed_ids (dbe);
5130 /* reset the update_flag to 0 */
5131 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5132 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS)) == NULL)
5134 g_warning ("query is null");
5135 SDB_UNLOCK(priv);
5136 return FALSE;
5139 plist2 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS);
5141 if ((param = gda_set_get_holder ((GdaSet*)plist2, "filepath")) == NULL)
5143 g_warning ("param filepath is NULL from pquery!");
5144 return FALSE;
5146 SDB_PARAM_SET_STRING(param, file_on_db);
5148 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt2,
5149 (GdaSet*)plist2, NULL, NULL);
5151 /* last but not least, update the file analyse_time */
5152 if ((stmt3 = sdb_engine_get_statement_by_query_id (dbe,
5153 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME))
5154 == NULL)
5156 g_warning ("query is null");
5157 SDB_UNLOCK(priv);
5158 return FALSE;
5161 plist3 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_FILE_ANALYSE_TIME);
5163 /* filepath parameter */
5164 if ((param = gda_set_get_holder ((GdaSet*)plist3, "filepath")) == NULL)
5166 g_warning ("param filepath is NULL from pquery!");
5167 SDB_UNLOCK(priv);
5168 return FALSE;
5171 SDB_PARAM_SET_STRING(param, file_on_db);
5173 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt3,
5174 (GdaSet*)plist3, NULL, NULL);
5176 SDB_UNLOCK(priv);
5177 return TRUE;
5181 * @param data is a GPtrArray *files_to_scan
5182 * It will be freed when this callback will be called.
5184 static void
5185 on_scan_update_files_symbols_end (SymbolDBEngine * dbe,
5186 gint process_id,
5187 UpdateFileSymbolsData* update_data)
5189 SymbolDBEnginePriv *priv;
5190 GPtrArray *files_to_scan;
5191 gint i;
5192 GValue v = {0};
5194 g_return_if_fail (dbe != NULL);
5195 g_return_if_fail (update_data != NULL);
5197 priv = dbe->priv;
5198 files_to_scan = update_data->files_path;
5200 sdb_engine_clear_caches (dbe);
5202 /* we need a reinitialization */
5203 sdb_engine_init_caches (dbe);
5205 for (i = 0; i < files_to_scan->len; i++)
5207 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5209 if (strstr (node, priv->project_directory) == NULL)
5211 g_warning ("node %s is shorter than "
5212 "prj_directory %s",
5213 node, priv->project_directory);
5214 continue;
5217 /* clean the db from old un-updated with the last update step () */
5218 if (sdb_engine_update_file (dbe, node +
5219 strlen (priv->project_directory)) == FALSE)
5221 g_warning ("Error processing file %s", node +
5222 strlen (priv->project_directory));
5223 return;
5227 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_files_symbols_end,
5228 update_data);
5230 /* if true, we'll update the project scanning time too.
5231 * warning: project time scanning won't could be set before files one.
5232 * This why we'll fork the process calling sdb_engine_scan_files ()
5234 if (update_data->update_prj_analyse_time == TRUE)
5236 const GdaSet *plist;
5237 const GdaStatement *stmt;
5238 GdaHolder *param;
5240 SDB_LOCK(priv);
5241 /* and the project analyse_time */
5242 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5243 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME))
5244 == NULL)
5246 g_warning ("query is null");
5247 SDB_UNLOCK(priv);
5248 return;
5251 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME);
5253 /* prjname parameter */
5254 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5256 g_warning ("param prjname is NULL from pquery!");
5257 SDB_UNLOCK(priv);
5258 return;
5261 SDB_PARAM_SET_STRING(param, update_data->project);
5263 gda_connection_statement_execute_non_select (priv->db_connection,
5264 (GdaStatement*)stmt,
5265 (GdaSet*)plist, NULL, NULL);
5267 SDB_UNLOCK(priv);
5270 /* free the GPtrArray. */
5271 g_ptr_array_unref (files_to_scan);
5273 g_free (update_data->project);
5274 g_free (update_data);
5278 * symbol_db_engine_update_files_symbols:
5279 * @dbe: self
5280 * @project: name of the project
5281 * @files_path: absolute path of files to update.
5282 * @update_prj_analyse_time: flag to force the update of project analyse time.
5284 * Update symbols of saved files.
5286 * Returns: Scan process id if insertion is successful, -1 on 'no files scanned'.
5288 gint
5289 symbol_db_engine_update_files_symbols (SymbolDBEngine * dbe, const gchar * project,
5290 const GPtrArray * files_path,
5291 gboolean update_prj_analyse_time)
5293 SymbolDBEnginePriv *priv;
5294 UpdateFileSymbolsData *update_data;
5295 gboolean ret_code;
5296 gint ret_id, scan_id;
5297 gint i;
5298 GPtrArray * ready_files;
5300 priv = dbe->priv;
5302 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5303 g_return_val_if_fail (project != NULL, FALSE);
5305 ready_files = g_ptr_array_new_with_free_func (g_free);
5307 /* check if the files exist in db before passing them to the scan procedure */
5308 for (i = 0; i < files_path->len; i++)
5310 gchar *curr_abs_file;
5312 curr_abs_file = g_strdup (g_ptr_array_index (files_path, i));
5313 /* check if the file exists in db. We will not scan buffers for files
5314 * which aren't already in db
5316 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5318 DEBUG_PRINT ("will not update file symbols claiming to be %s because not in db",
5319 curr_abs_file);
5321 g_free (curr_abs_file);
5322 continue;
5325 /* ok the file exists in db. Add it to ready_files */
5326 g_ptr_array_add (ready_files, curr_abs_file);
5329 /* if no file has been added to the array then bail out here */
5330 if (ready_files->len <= 0)
5332 g_ptr_array_unref (ready_files);
5333 DEBUG_PRINT ("not enough files to update");
5334 return -1;
5337 update_data = g_new0 (UpdateFileSymbolsData, 1);
5339 update_data->update_prj_analyse_time = update_prj_analyse_time;
5340 update_data->files_path = ready_files;
5341 update_data->project = g_strdup (project);
5344 /* data will be freed when callback will be called. The signal will be
5345 * disconnected too, don't worry about disconneting it by hand.
5347 g_signal_connect (G_OBJECT (dbe), "scan-end",
5348 G_CALLBACK (on_scan_update_files_symbols_end), update_data);
5350 scan_id = sdb_engine_get_unique_scan_id (dbe);
5351 ret_code = sdb_engine_scan_files_async (dbe, ready_files, NULL, TRUE, scan_id);
5353 if (ret_code == TRUE)
5355 ret_id = scan_id;
5357 else
5358 ret_id = -1;
5360 return ret_id;
5364 * symbol_db_engine_update_project_symbols:
5365 * @dbe: self
5366 * @project_name: The project name
5367 * @force_all_files:
5369 * Update symbols of the whole project. It scans all file symbols etc.
5370 * If force is true then update forcely all the files.
5371 * ~~~ Thread note: this function locks the mutex ~~~ *
5373 * Returns: scan id of the process, or -1 in case of problems.
5375 gint
5376 symbol_db_engine_update_project_symbols (SymbolDBEngine *dbe,
5377 const gchar *project_name, gboolean force_all_files)
5379 const GdaSet *plist;
5380 const GdaStatement *stmt;
5381 GdaHolder *param;
5382 GdaDataModel *data_model;
5383 gint num_rows = 0;
5384 gint i;
5385 GPtrArray *files_to_scan;
5386 SymbolDBEnginePriv *priv;
5387 GValue v = {0};
5389 g_return_val_if_fail (dbe != NULL, FALSE);
5391 priv = dbe->priv;
5393 g_return_val_if_fail (project_name != NULL, FALSE);
5394 g_return_val_if_fail (priv->project_directory != NULL, FALSE);
5396 SDB_LOCK(priv);
5398 DEBUG_PRINT ("Updating symbols of project-name %s (force %d)...", project_name, force_all_files);
5399 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5400 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME))
5401 == NULL)
5403 g_warning ("query is null");
5404 SDB_UNLOCK(priv);
5405 return FALSE;
5408 plist = sdb_engine_get_query_parameters_list (dbe,
5409 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME);
5411 /* prjname parameter */
5412 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5414 g_warning ("param prjid is NULL from pquery!");
5415 SDB_UNLOCK(priv);
5416 return FALSE;
5419 SDB_PARAM_SET_STRING(param, project_name);
5421 /* execute the query with parameters just set */
5422 GType gtype_array [6] = { G_TYPE_INT,
5423 G_TYPE_STRING,
5424 G_TYPE_INT,
5425 G_TYPE_INT,
5426 GDA_TYPE_TIMESTAMP,
5427 G_TYPE_NONE
5429 data_model = gda_connection_statement_execute_select_full (priv->db_connection,
5430 (GdaStatement*)stmt,
5431 (GdaSet*)plist,
5432 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
5433 gtype_array,
5434 NULL);
5436 if (!GDA_IS_DATA_MODEL (data_model) ||
5437 (num_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model))) <= 0)
5439 if (data_model != NULL)
5440 g_object_unref (data_model);
5441 data_model = NULL;
5443 g_warning ("Strange enough, no files in project ->%s<- found",
5444 project_name);
5445 SDB_UNLOCK(priv);
5446 return FALSE;
5449 /* initialize the array */
5450 files_to_scan = g_ptr_array_new_with_free_func (g_free);
5452 /* we can now scan each filename entry to check the last modification time. */
5453 for (i = 0; i < num_rows; i++)
5455 const GValue *value, *value1;
5456 const GdaTimestamp *timestamp;
5457 const gchar *file_name;
5458 gchar *file_abs_path = NULL;
5459 struct tm filetm;
5460 time_t db_time;
5461 GFile *gfile;
5462 GFileInfo* gfile_info;
5463 GFileInputStream* gfile_is;
5465 if ((value =
5466 gda_data_model_get_value_at (data_model,
5467 gda_data_model_get_column_index(data_model,
5468 "db_file_path"),
5469 i, NULL)) == NULL)
5471 continue;
5474 /* build abs path. */
5475 file_name = g_value_get_string (value);
5476 if (priv->project_directory != NULL)
5478 file_abs_path = g_build_filename (priv->project_directory,
5479 file_name, NULL);
5482 gfile = g_file_new_for_path (file_abs_path);
5483 if (gfile == NULL)
5484 continue;
5486 gfile_is = g_file_read (gfile, NULL, NULL);
5487 /* retrieve data/time info */
5488 if (gfile_is == NULL)
5490 g_message ("could not open path %s", file_abs_path);
5491 g_free (file_abs_path);
5492 g_object_unref (gfile);
5493 continue;
5495 g_object_unref (gfile_is);
5497 gfile_info = g_file_query_info (gfile, "*", G_FILE_QUERY_INFO_NONE,
5498 NULL, NULL);
5500 if (gfile_info == NULL)
5502 g_message ("cannot get file info from handle");
5503 g_free (file_abs_path);
5504 g_object_unref (gfile);
5505 continue;
5508 if ((value1 = gda_data_model_get_value_at (data_model,
5509 gda_data_model_get_column_index(data_model,
5510 "analyse_time"), i, NULL)) == NULL)
5512 continue;
5516 timestamp = gda_value_get_timestamp (value1);
5518 /* fill a struct tm with the date retrieved by the string. */
5519 /* string is something like '2007-04-18 23:51:39' */
5520 memset (&filetm, 0, sizeof (struct tm));
5521 filetm.tm_year = timestamp->year - 1900;
5522 filetm.tm_mon = timestamp->month - 1;
5523 filetm.tm_mday = timestamp->day;
5524 filetm.tm_hour = timestamp->hour;
5525 filetm.tm_min = timestamp->minute;
5526 filetm.tm_sec = timestamp->second;
5528 /* remove one hour to the db_file_time. */
5529 db_time = mktime (&filetm) - 3600;
5531 guint64 modified_time = g_file_info_get_attribute_uint64 (gfile_info,
5532 G_FILE_ATTRIBUTE_TIME_MODIFIED);
5533 if (difftime (db_time, modified_time) < 0 ||
5534 force_all_files == TRUE)
5536 g_ptr_array_add (files_to_scan, file_abs_path);
5539 g_object_unref (gfile_info);
5540 g_object_unref (gfile);
5541 /* no need to free file_abs_path, it's been added to files_to_scan */
5544 if (data_model)
5545 g_object_unref (data_model);
5547 if (files_to_scan->len > 0)
5549 SDB_UNLOCK(priv);
5551 /* at the end let the scanning function do its job */
5552 gint id = symbol_db_engine_update_files_symbols (dbe, project_name,
5553 files_to_scan, TRUE);
5555 g_ptr_array_unref (files_to_scan);
5556 return id;
5559 SDB_UNLOCK(priv);
5561 /* some error occurred */
5562 return -1;
5565 /**
5566 * symbol_db_engine_remove_file:
5567 * @dbe: self
5568 * @project: project name
5569 * @rel_file: db relative file entry of the symbols to remove.
5571 * Remove a file, together with its symbols, from a project. I.e. it won't remove
5572 * physically the file from disk.
5573 * ~~~ Thread note: this function locks the mutex
5575 * Returns: TRUE if everything went good, FALSE otherwise.
5577 gboolean
5578 symbol_db_engine_remove_file (SymbolDBEngine * dbe, const gchar *project,
5579 const gchar *rel_file)
5581 SymbolDBEnginePriv *priv;
5582 const GdaSet *plist;
5583 const GdaStatement *stmt;
5584 GdaHolder *param;
5585 GValue v = {0};
5588 g_return_val_if_fail (dbe != NULL, FALSE);
5589 g_return_val_if_fail (project != NULL, FALSE);
5590 g_return_val_if_fail (rel_file != NULL, FALSE);
5591 priv = dbe->priv;
5593 SDB_LOCK(priv);
5595 if (strlen (rel_file) <= 0)
5597 g_warning ("wrong file to delete.");
5598 SDB_UNLOCK(priv);
5599 return FALSE;
5602 DEBUG_PRINT ("deleting from db %s", rel_file);
5604 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5605 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME)) == NULL)
5607 g_warning ("query is null");
5608 SDB_UNLOCK(priv);
5609 return FALSE;
5612 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME);
5614 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5616 g_warning ("param prjname is NULL from pquery!");
5617 SDB_UNLOCK(priv);
5618 return FALSE;
5621 SDB_PARAM_SET_STRING(param, project);
5623 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
5625 g_warning ("param filepath is NULL from pquery!");
5626 SDB_UNLOCK(priv);
5627 return FALSE;
5630 SDB_PARAM_SET_STRING(param, rel_file);
5632 /* Triggers will take care of updating/deleting connected symbols
5633 * tuples, like sym_kind, sym_type etc */
5634 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt,
5635 (GdaSet*)plist, NULL, NULL);
5637 /* emits removed symbols signals */
5638 sdb_engine_detects_removed_ids (dbe);
5640 SDB_UNLOCK(priv);
5642 return TRUE;
5645 void
5646 symbol_db_engine_remove_files (SymbolDBEngine * dbe, const gchar * project,
5647 const GPtrArray * files)
5649 gint i;
5651 g_return_if_fail (dbe != NULL);
5652 g_return_if_fail (project != NULL);
5653 g_return_if_fail (files != NULL);
5655 for (i = 0; i < files->len; i++)
5657 symbol_db_engine_remove_file (dbe, project, g_ptr_array_index (files, i));
5661 static void
5662 on_scan_update_buffer_end (SymbolDBEngine * dbe, gint process_id, gpointer data)
5664 GPtrArray *files_to_scan;
5665 gint i;
5667 g_return_if_fail (dbe != NULL);
5668 g_return_if_fail (data != NULL);
5670 files_to_scan = (GPtrArray *) data;
5672 for (i = 0; i < files_to_scan->len; i++)
5674 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5675 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, node);
5676 if (relative_path != NULL)
5678 /* will be emitted removed signals */
5679 if (sdb_engine_update_file (dbe, relative_path) == FALSE)
5681 g_warning ("Error processing file %s", node);
5682 return;
5687 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_buffer_end,
5688 files_to_scan);
5690 /* free the GPtrArray. */
5691 g_ptr_array_unref (files_to_scan);
5692 data = files_to_scan = NULL;
5696 * symbol_db_engine_update_buffer_symbols:
5697 * @dbe: self
5698 * @project: project name
5699 * @real_files: full path on disk to 'real file' to update. e.g.
5700 * /home/foouser/fooproject/src/main.c.
5701 * @text_buffers: memory buffers
5702 * @buffer_sizes: one to one sizes with text_buffers.
5704 * Update symbols of a file by a memory-buffer to perform a real-time updating
5705 * of symbols.
5707 * Returns: scan process id if insertion is successful, -1 on error.
5709 gint
5710 symbol_db_engine_update_buffer_symbols (SymbolDBEngine * dbe, const gchar *project,
5711 const GPtrArray * real_files,
5712 const GPtrArray * text_buffers,
5713 const GPtrArray * buffer_sizes)
5715 SymbolDBEnginePriv *priv;
5716 gint i;
5717 gint ret_id, scan_id;
5718 gboolean ret_code;
5719 /* array that'll represent the /dev/shm/anjuta-XYZ files */
5720 GPtrArray *temp_files;
5721 GPtrArray *real_files_list;
5722 GPtrArray *real_files_on_db;
5724 g_return_val_if_fail (dbe != NULL, FALSE);
5725 priv = dbe->priv;
5727 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5728 g_return_val_if_fail (project != NULL, FALSE);
5729 g_return_val_if_fail (real_files != NULL, FALSE);
5730 g_return_val_if_fail (text_buffers != NULL, FALSE);
5731 g_return_val_if_fail (buffer_sizes != NULL, FALSE);
5733 temp_files = g_ptr_array_new_with_free_func (g_free);
5734 real_files_on_db = g_ptr_array_new_with_free_func (g_free);
5735 real_files_list = anjuta_util_clone_string_gptrarray (real_files);
5737 /* obtain a GPtrArray with real_files on database */
5738 for (i=0; i < real_files_list->len; i++)
5740 const gchar *relative_path;
5741 const gchar *curr_abs_file;
5742 FILE *buffer_mem_file;
5743 const gchar *temp_buffer;
5744 gint buffer_mem_fd;
5745 gint temp_size;
5746 gchar *shared_temp_file;
5747 gchar *base_filename;
5749 curr_abs_file = g_ptr_array_index (real_files_list, i);
5750 /* check if the file exists in db. We will not scan buffers for files
5751 * which aren't already in db
5753 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5755 DEBUG_PRINT ("will not scan buffer claiming to be %s because not in db",
5756 curr_abs_file);
5757 continue;
5760 relative_path = g_strdup (symbol_db_util_get_file_db_path (dbe, curr_abs_file));
5761 if (relative_path == NULL)
5763 g_warning ("relative_path is NULL");
5764 continue;
5766 g_ptr_array_add (real_files_on_db, (gpointer) relative_path);
5768 /* it's ok to have just the base filename to create the
5769 * target buffer one */
5770 base_filename = g_filename_display_basename (relative_path);
5772 shared_temp_file = g_strdup_printf ("/anjuta-%d-%ld-%s", getpid (),
5773 time (NULL), base_filename);
5774 g_free (base_filename);
5776 if ((buffer_mem_fd =
5777 shm_open (shared_temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
5779 g_warning ("Error while trying to open a shared memory file. Be"
5780 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
5781 return -1;
5784 buffer_mem_file = fdopen (buffer_mem_fd, "w+b");
5786 temp_buffer = g_ptr_array_index (text_buffers, i);
5787 temp_size = GPOINTER_TO_INT(g_ptr_array_index (buffer_sizes, i));
5789 fwrite (temp_buffer, sizeof(gchar), temp_size, buffer_mem_file);
5790 fflush (buffer_mem_file);
5791 fclose (buffer_mem_file);
5793 /* add the temp file to the array. */
5794 g_ptr_array_add (temp_files, g_strdup_printf (SHARED_MEMORY_PREFIX"%s",
5795 shared_temp_file));
5797 /* check if we already have an entry stored in the hash table, else
5798 * insert it
5800 if (g_hash_table_lookup (priv->garbage_shared_mem_files, shared_temp_file)
5801 == NULL)
5803 DEBUG_PRINT ("inserting into garbage hash table %s", shared_temp_file);
5804 g_hash_table_insert (priv->garbage_shared_mem_files, shared_temp_file,
5805 NULL);
5807 else
5809 /* the item is already stored. Just free it here. */
5810 g_free (shared_temp_file);
5814 /* in case we didn't have any good buffer to scan...*/
5815 ret_id = -1;
5817 /* it may happen that no buffer is correctly set up */
5818 if (real_files_on_db->len > 0)
5820 /* data will be freed when callback will be called. The signal will be
5821 * disconnected too, don't worry about disconnecting it by hand.
5823 g_signal_connect (G_OBJECT (dbe), "scan-end",
5824 G_CALLBACK (on_scan_update_buffer_end), real_files_list);
5826 scan_id = sdb_engine_get_unique_scan_id (dbe);
5827 ret_code = sdb_engine_scan_files_async (dbe, temp_files, real_files_on_db, TRUE, scan_id);
5829 if (ret_code == TRUE)
5831 ret_id = scan_id;
5833 else
5834 ret_id = -1;
5837 g_ptr_array_unref (temp_files);
5838 g_ptr_array_unref (real_files_on_db);
5839 return ret_id;
5843 * symbol_db_engine_get_files_for_project:
5844 * @dbe: self
5846 * Retrieves the list of files in project. The data model contains only 1
5847 * column, which is the file name.
5849 * Returns: data model which must be freed once used.
5851 GdaDataModel*
5852 symbol_db_engine_get_files_for_project (SymbolDBEngine *dbe)
5854 return sdb_engine_execute_select_sql (dbe, "SELECT file.file_path FROM file");
5858 * symbol_db_engine_set_db_case_sensitive:
5859 * @dbe: self
5860 * @case_sensitive: boolean flag.
5862 * Set the opened db case sensitive. The searches on this db will then be performed
5863 * taking into consideration this SQLite's PRAGMA case_sensitive_like.
5864 * ~~~ Thread note: this function locks the mutex ~~~
5867 void
5868 symbol_db_engine_set_db_case_sensitive (SymbolDBEngine *dbe, gboolean case_sensitive)
5870 g_return_if_fail (dbe != NULL);
5872 if (case_sensitive == TRUE)
5873 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 1");
5874 else
5875 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 0");
5879 * symbol_db_engine_get_type_conversion_hash:
5880 * @dbe: self
5882 * Get conversion hash table used to convert symbol type name to enum value
5884 * Returns: a GHashTable which must be freed once used.
5886 const GHashTable*
5887 symbol_db_engine_get_type_conversion_hash (SymbolDBEngine *dbe)
5889 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5890 return dbe->priv->sym_type_conversion_hash;
5894 * symbol_db_engine_get_project_directory:
5895 * @dbe: self
5897 * Gets the project directory (used to construct absolute paths)
5899 * Returns: a const gchar containing the project_directory.
5901 const gchar*
5902 symbol_db_engine_get_project_directory (SymbolDBEngine *dbe)
5904 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5905 return dbe->priv->project_directory;
5909 * symbol_db_engine_get_statement:
5910 * @dbe: self
5911 * @sql_str: sql statement.
5913 * Compiles an sql statement
5915 * Returns: a GdaStatement object which must be freed once used.
5917 GdaStatement*
5918 symbol_db_engine_get_statement (SymbolDBEngine *dbe, const gchar *sql_str)
5920 GdaStatement* stmt;
5921 GError *error = NULL;
5923 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5924 stmt = gda_sql_parser_parse_string (dbe->priv->sql_parser,
5925 sql_str,
5926 NULL, &error);
5927 if (error)
5929 g_warning ("SQL parsing failed: %s: %s", sql_str, error->message);
5930 g_error_free (error);
5932 return stmt;
5936 * symbol_db_engine_execute_select:
5937 * @dbe: self
5938 * @stmt: A compiled GdaStatement sql statement.
5939 * @params: Params for GdaStatement (i.e. a prepared statement).
5941 * Executes a parameterized sql statement
5943 * Returns: A data model which must be freed once used.
5945 GdaDataModel*
5946 symbol_db_engine_execute_select (SymbolDBEngine *dbe, GdaStatement *stmt,
5947 GdaSet *params)
5949 GdaDataModel *res;
5950 GError *error = NULL;
5952 res = gda_connection_statement_execute_select (dbe->priv->db_connection,
5953 stmt, params, &error);
5954 if (error)
5956 gchar *sql_str =
5957 gda_statement_to_sql_extended (stmt, dbe->priv->db_connection,
5958 params, 0, NULL, NULL);
5960 g_warning ("SQL select exec failed: %s, %s", sql_str, error->message);
5961 g_free (sql_str);
5962 g_error_free (error);
5964 return res;