symbol-db: misc fixes.
[anjuta.git] / plugins / symbol-db / symbol-db-engine-core.c
blob582ae4592b81622543e670628e239a0983a67129
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 void (SymbolDBEngineCallback) (SymbolDBEngine * dbe,
98 gpointer user_data);
101 * signals enum
103 enum
105 DB_CONNECTED,
106 DB_DISCONNECTED,
107 SCAN_BEGIN,
108 SINGLE_FILE_SCAN_END,
109 SCAN_END,
110 SYMBOL_INSERTED,
111 SYMBOL_UPDATED,
112 SYMBOL_SCOPE_UPDATED,
113 SYMBOL_REMOVED,
114 LAST_SIGNAL
118 * enums
120 enum {
121 DO_UPDATE_SYMS = 1,
122 DO_UPDATE_SYMS_AND_EXIT,
123 DONT_UPDATE_SYMS,
124 DONT_UPDATE_SYMS_AND_EXIT,
125 DONT_FAKE_UPDATE_SYMS,
126 END_UPDATE_GROUP_SYMS
130 * structs used for callback data.
132 typedef struct _UpdateFileSymbolsData {
133 gchar *project;
134 gboolean update_prj_analyse_time;
135 GPtrArray * files_path;
137 } UpdateFileSymbolsData;
139 typedef struct _ScanFiles1Data {
140 SymbolDBEngine *dbe;
142 gchar *real_file; /* may be NULL. If not NULL must be freed */
143 gint partial_count;
144 gint files_list_len;
145 gint symbols_update;
147 } ScanFiles1Data;
150 * global file variables
152 static GObjectClass *parent_class = NULL;
153 static unsigned int signals[LAST_SIGNAL] = { 0 };
156 #ifdef DEBUG
157 static GTimer *sym_timer_DEBUG = NULL;
158 static gint tags_total_DEBUG = 0;
159 static gdouble elapsed_total_DEBUG = 0;
160 #endif
163 * forward declarations
165 static void
166 sdb_engine_second_pass_do (SymbolDBEngine * dbe);
168 static gint
169 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
170 int file_defined_id, gboolean sym_update);
172 GNUC_INLINE const GdaStatement *
173 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id);
175 GNUC_INLINE const GdaSet *
176 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id);
178 GNUC_INLINE gint
179 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
180 gchar * param_key,
181 GValue * param_value);
184 * implementation starts here
186 static GNUC_INLINE gint
187 sdb_engine_cache_lookup (GHashTable* hash_table, const gchar* lookup)
189 gpointer orig_key = NULL;
190 gpointer value = NULL;
192 /* avoiding lazy initialization may gain some cpu cycles. Just lookup here. */
193 if (g_hash_table_lookup_extended (hash_table,
194 lookup,
195 &orig_key,
196 &value))
198 gint table_id = GPOINTER_TO_INT (value);
199 return table_id;
201 return -1;
204 static GNUC_INLINE void
205 sdb_engine_insert_cache (GHashTable* hash_table, const gchar* key,
206 gint value)
208 g_hash_table_insert (hash_table, g_strdup (key),
209 GINT_TO_POINTER (value));
212 static void
213 sdb_engine_tablemap_tmp_heritage_destroy (TableMapTmpHeritage *node)
215 g_free (node->field_inherits);
216 g_free (node->field_struct);
217 g_free (node->field_typeref);
218 g_free (node->field_enum);
219 g_free (node->field_union);
220 g_free (node->field_class);
221 g_free (node->field_namespace);
223 g_slice_free (TableMapTmpHeritage, node);
226 static void
227 sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
229 SymbolDBEnginePriv *priv = dbe->priv;
230 if (priv->tmp_heritage_tablemap)
232 TableMapTmpHeritage *node;
233 while ((node = g_queue_pop_head (priv->tmp_heritage_tablemap)) != NULL)
235 sdb_engine_tablemap_tmp_heritage_destroy (node);
238 /* queue should be void. Free it */
239 g_queue_free (priv->tmp_heritage_tablemap);
240 priv->tmp_heritage_tablemap = NULL;
244 static void
245 sdb_engine_clear_caches (SymbolDBEngine* dbe)
247 SymbolDBEnginePriv *priv = dbe->priv;
248 if (priv->kind_cache)
249 g_hash_table_destroy (priv->kind_cache);
250 if (priv->access_cache)
251 g_hash_table_destroy (priv->access_cache);
252 if (priv->implementation_cache)
253 g_hash_table_destroy (priv->implementation_cache);
254 if (priv->language_cache)
255 g_hash_table_destroy (priv->language_cache);
257 priv->kind_cache = NULL;
258 priv->access_cache = NULL;
259 priv->implementation_cache = NULL;
260 priv->language_cache = NULL;
263 static void
264 sdb_engine_init_table_maps (SymbolDBEngine *dbe)
266 SymbolDBEnginePriv *priv = dbe->priv;
268 /* tmp_heritage_tablemap */
269 priv->tmp_heritage_tablemap = g_queue_new ();
272 static void
273 sdb_engine_init_caches (SymbolDBEngine* dbe)
275 SymbolDBEnginePriv *priv = dbe->priv;
276 priv->kind_cache = g_hash_table_new_full (g_str_hash,
277 g_str_equal,
278 g_free,
279 NULL);
281 priv->access_cache = g_hash_table_new_full (g_str_hash,
282 g_str_equal,
283 g_free,
284 NULL);
286 priv->implementation_cache = g_hash_table_new_full (g_str_hash,
287 g_str_equal,
288 g_free,
289 NULL);
291 priv->language_cache = g_hash_table_new_full (g_str_hash,
292 g_str_equal,
293 g_free,
294 NULL);
297 /* ~~~ Thread note: this function locks the mutex ~~~ */
298 static gboolean
299 sdb_engine_execute_unknown_sql (SymbolDBEngine *dbe, const gchar *sql)
301 GdaStatement *stmt;
302 GObject *res;
303 SymbolDBEnginePriv *priv;
305 priv = dbe->priv;
307 SDB_LOCK(priv);
308 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, NULL, NULL);
310 if (stmt == NULL)
312 SDB_UNLOCK(priv);
313 return FALSE;
316 if ((res = gda_connection_statement_execute (priv->db_connection,
317 (GdaStatement*)stmt,
318 NULL,
319 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
320 NULL, NULL)) == NULL)
322 g_object_unref (stmt);
323 SDB_UNLOCK(priv);
324 return FALSE;
326 else
328 g_object_unref (res);
329 g_object_unref (stmt);
330 SDB_UNLOCK(priv);
331 return TRUE;
335 static GdaDataModel *
336 sdb_engine_execute_select_sql (SymbolDBEngine * dbe, const gchar *sql)
338 GdaStatement *stmt;
339 GdaDataModel *res;
340 SymbolDBEnginePriv *priv;
341 const gchar *remain;
343 priv = dbe->priv;
345 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, &remain, NULL);
347 if (stmt == NULL)
348 return NULL;
350 res = gda_connection_statement_execute_select (priv->db_connection,
351 (GdaStatement*)stmt, NULL, NULL);
352 if (!res)
353 DEBUG_PRINT ("Could not execute query: %s\n", sql);
355 if (remain != NULL)
357 /* this shouldn't never happen */
358 sdb_engine_execute_select_sql (dbe, remain);
361 g_object_unref (stmt);
363 return res;
366 static gint
367 sdb_engine_execute_non_select_sql (SymbolDBEngine * dbe, const gchar *sql)
369 GdaStatement *stmt;
370 gint nrows;
371 SymbolDBEnginePriv *priv;
372 const gchar *remain;
374 priv = dbe->priv;
375 stmt = gda_sql_parser_parse_string (priv->sql_parser,
376 sql, &remain, NULL);
378 if (stmt == NULL)
379 return -1;
381 nrows = gda_connection_statement_execute_non_select (priv->db_connection, stmt,
382 NULL, NULL, NULL);
383 if (remain != NULL) {
384 /* may happen for example when sql is a file-content */
385 sdb_engine_execute_non_select_sql (dbe, remain);
388 g_object_unref (stmt);
389 return nrows;
393 * ### Thread note: this function inherits the mutex lock ###
395 * Use a proxy to return an already present or a fresh new prepared query
396 * from static 'query_list'. We should perform actions in the fastest way, because
397 * these queries are time-critical.
398 * A GdaSet will also be populated once, avoiding so to create again later on.
400 GNUC_INLINE const GdaStatement *
401 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id)
403 static_query_node *node;
404 SymbolDBEnginePriv *priv;
406 priv = dbe->priv;
408 /* no way: if connection is NULL we will break here. There must be
409 * a connection established to db before using this function */
410 /*g_return_val_if_fail (priv->db_connection != NULL, NULL);*/
412 if ((node = priv->static_query_list[query_id]) == NULL)
413 return NULL;
415 if (node->stmt == NULL)
417 GError *error = NULL;
419 /* create a new GdaStatement */
420 node->stmt =
421 gda_sql_parser_parse_string (priv->sql_parser, node->query_str, NULL,
422 &error);
424 if (error)
426 g_warning (error->message);
427 g_error_free (error);
428 return NULL;
431 if (gda_statement_get_parameters ((GdaStatement*)node->stmt,
432 &node->plist, NULL) == FALSE)
434 g_warning ("Error on getting parameters for %d", query_id);
438 return node->stmt;
442 * ### Thread note: this function inherits the mutex lock ###
444 * Return a GdaSet of parameters calculated from the statement. It does not check
445 * if it's null. You *must* be sure to have called sdb_engine_get_statement_by_query_id () first.
447 GNUC_INLINE const GdaSet *
448 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id)
450 SymbolDBEnginePriv *priv;
452 priv = dbe->priv;
454 static_query_node *node;
455 node = priv->static_query_list[query_id];
456 return node->plist;
460 * Clear the static cached queries data. You should call this function when closing/
461 * destroying SymbolDBEngine object.
463 static void
464 sdb_engine_free_cached_queries (SymbolDBEngine *dbe)
466 SymbolDBEnginePriv *priv;
467 gint i;
468 static_query_node *node;
470 priv = dbe->priv;
472 for (i = 0; i < PREP_QUERY_COUNT; i++)
474 node = priv->static_query_list[i];
476 if (node != NULL && node->stmt != NULL)
478 /*DEBUG_PRINT ("sdb_engine_free_cached_queries stmt %d", i);*/
479 g_object_unref (node->stmt);
480 node->stmt = NULL;
483 if (node != NULL && node->plist != NULL)
485 /*DEBUG_PRINT ("sdb_engine_free_cached_queries plist %d", i);*/
486 g_object_unref (node->plist);
487 node->plist = NULL;
490 /* last but not the least free the node itself */
491 g_free (node);
492 priv->static_query_list[i] = NULL;
496 static gboolean
497 sdb_engine_disconnect_from_db (SymbolDBEngine * dbe)
499 SymbolDBEnginePriv *priv;
501 g_return_val_if_fail (dbe != NULL, FALSE);
502 priv = dbe->priv;
504 DEBUG_PRINT ("VACUUM command issued on %s", priv->cnc_string);
505 sdb_engine_execute_non_select_sql (dbe, "VACUUM");
507 DEBUG_PRINT ("Disconnecting from %s", priv->cnc_string);
508 g_free (priv->cnc_string);
509 priv->cnc_string = NULL;
511 if (priv->db_connection != NULL)
512 gda_connection_close (priv->db_connection);
513 priv->db_connection = NULL;
515 if (priv->sql_parser != NULL)
516 g_object_unref (priv->sql_parser);
517 priv->sql_parser = NULL;
519 return TRUE;
523 * ### Thread note: this function inherits the mutex lock ###
525 * @return -1 on error. Otherwise the id of tuple.
527 GNUC_INLINE gint
528 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
529 gchar * param_key,
530 GValue * param_value)
532 const GdaSet *plist;
533 const GdaStatement *stmt;
534 GdaHolder *param;
535 GdaDataModel *data_model;
536 const GValue *num;
537 gint table_id;
538 SymbolDBEnginePriv *priv;
540 priv = dbe->priv;
542 /* get prepared query */
543 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
545 g_warning ("Query is null");
546 return -1;
549 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
551 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key)) == NULL)
553 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
554 "from pquery!\n");
555 return -1;
558 gda_holder_set_value (param, param_value, NULL);
560 /* execute the query with parametes just set */
561 data_model = gda_connection_statement_execute_select (priv->db_connection,
562 (GdaStatement*)stmt,
563 (GdaSet*)plist, NULL);
565 if (!GDA_IS_DATA_MODEL (data_model) ||
566 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
568 if (data_model != NULL)
569 g_object_unref (data_model);
570 return -1;
573 /* get and parse the results. */
574 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
576 table_id = g_value_get_int (num);
577 g_object_unref (data_model);
579 /* set the value to a dummy string because we won't use the real value anymore */
580 return table_id;
583 /* ### Thread note: this function inherits the mutex lock ### */
584 static GNUC_INLINE gint
585 sdb_engine_get_tuple_id_by_unique_name4 (SymbolDBEngine * dbe,
586 static_query_type qtype,
587 gchar * param_key1,
588 GValue * value1,
589 gchar * param_key2,
590 GValue * value2,
591 gchar * param_key3,
592 GValue * value3,
593 gchar * param_key4,
594 GValue * value4)
596 const GdaSet *plist;
597 const GdaStatement *stmt;
598 GdaHolder *param;
599 GdaDataModel *data_model;
600 const GValue *num;
601 gint table_id;
602 SymbolDBEnginePriv *priv;
604 priv = dbe->priv;
606 /* get prepared query */
607 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
609 g_warning ("Query is null");
610 return -1;
613 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
615 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key1)) == NULL)
617 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: param is NULL "
618 "from pquery!\n");
619 return -1;
622 gda_holder_set_value (param, value1, NULL);
624 /* ...and the second one */
625 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key2)) == NULL)
627 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
628 "param is NULL from pquery!");
629 return -1;
632 gda_holder_set_value (param, value2, NULL);
634 /* ...and the third one */
635 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key3)) == NULL)
637 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
638 "param is NULL from pquery!");
639 return -1;
642 gda_holder_set_value (param, value3, NULL);
644 /* ...and the fourth one */
645 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key4)) == NULL)
647 g_warning ("sdb_engine_get_tuple_id_by_unique_name4: "
648 "param is NULL from pquery!");
649 return -1;
652 gda_holder_set_value (param, value4, NULL);
654 /* execute the query with parametes just set */
655 data_model = gda_connection_statement_execute_select (priv->db_connection,
656 (GdaStatement*)stmt,
657 (GdaSet*)plist, NULL);
659 if (!GDA_IS_DATA_MODEL (data_model) ||
660 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
662 if (data_model != NULL)
663 g_object_unref (data_model);
665 return -1;
668 /* get and parse the results. */
669 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
671 table_id = g_value_get_int (num);
672 g_object_unref (data_model);
673 return table_id;
676 /** ### Thread note: this function inherits the mutex lock ### */
677 static int
678 sdb_engine_get_file_defined_id (SymbolDBEngine* dbe,
679 const gchar* base_prj_path,
680 const gchar* fake_file_on_db,
681 tagEntry* tag_entry)
683 SymbolDBEnginePriv *priv;
684 GValue v = {0};
686 priv = dbe->priv;
688 gint file_defined_id = 0;
689 if (base_prj_path != NULL && g_str_has_prefix (tag_entry->file, base_prj_path))
691 /* in this case fake_file will be ignored. */
693 /* we expect here an absolute path */
694 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file + strlen (base_prj_path));
696 else
698 /* check whether the fake_file can substitute the tag_entry->file one */
699 if (fake_file_on_db == NULL)
701 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file);
703 else
705 SDB_GVALUE_SET_STATIC_STRING(v, fake_file_on_db);
709 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
710 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
711 "filepath",
712 &v)) < 0)
714 /* if we arrive here there should be some sync problems between the filenames
715 * in database and the ones in the ctags files. We trust in db's ones,
716 * so we'll just return here.
718 g_warning ("sync problems between db and ctags filenames entries. "
719 "File was %s (base_path: %s, fake_file: %s, tag_file: %s)",
720 g_value_get_string (&v), base_prj_path, fake_file_on_db,
721 tag_entry->file);
722 return -1;
725 return file_defined_id;
729 * ### Thread note: this function inherits the mutex lock ###
731 * If fake_file is != NULL we claim and assert that tags contents which are
732 * scanned belong to the fake_file in the project.
733 * More: the fake_file refers to just one single file and cannot be used
734 * for multiple fake_files.
736 static void
737 sdb_engine_populate_db_by_tags (SymbolDBEngine * dbe, FILE* fd,
738 gchar * fake_file_on_db,
739 gboolean force_sym_update)
741 tagFile *tag_file;
742 tagFileInfo tag_file_info;
743 tagEntry tag_entry;
744 gint file_defined_id_cache = 0;
745 gchar* tag_entry_file_cache = NULL;
747 SymbolDBEnginePriv *priv = dbe->priv;
749 gchar* base_prj_path = fake_file_on_db == NULL ?
750 priv->project_directory : NULL;
752 g_return_if_fail (dbe != NULL);
754 g_return_if_fail (priv->db_connection != NULL);
755 g_return_if_fail (fd != NULL);
757 if ((tag_file = tagsOpen_1 (fd, &tag_file_info)) == NULL)
759 g_warning ("error in opening ctags file");
762 #ifdef DEBUG
763 if (sym_timer_DEBUG == NULL)
764 sym_timer_DEBUG = g_timer_new ();
765 else
766 g_timer_reset (sym_timer_DEBUG);
767 gint tags_num_DEBUG = 0;
768 #endif
769 tag_entry.file = NULL;
771 while (tagsNext (tag_file, &tag_entry) != TagFailure)
773 gint file_defined_id = 0;
774 if (tag_entry.file == NULL)
776 continue;
778 if (file_defined_id_cache > 0)
780 if (g_str_equal (tag_entry.file, tag_entry_file_cache))
782 file_defined_id = file_defined_id_cache;
785 if (file_defined_id == 0)
787 file_defined_id = sdb_engine_get_file_defined_id (dbe,
788 base_prj_path,
789 fake_file_on_db,
790 &tag_entry);
791 file_defined_id_cache = file_defined_id;
792 g_free (tag_entry_file_cache);
793 tag_entry_file_cache = g_strdup (tag_entry.file);
796 if (priv->symbols_scanned_count++ % BATCH_SYMBOL_NUMBER == 0)
798 GError *error = NULL;
800 /* if we aren't at the first cycle then we can commit the transaction */
801 if (priv->symbols_scanned_count > 1)
803 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
804 &error);
806 if (error)
808 DEBUG_PRINT ("err: %s", error->message);
809 g_error_free (error);
810 error = NULL;
814 gda_connection_begin_transaction (priv->db_connection, "symboltrans",
815 GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, &error);
817 if (error)
819 DEBUG_PRINT ("err: %s", error->message);
820 g_error_free (error);
821 error = NULL;
825 /* insert or update a symbol */
826 sdb_engine_add_new_symbol (dbe, &tag_entry, file_defined_id,
827 force_sym_update);
828 #ifdef DEBUG
829 tags_num_DEBUG++;
830 #endif
831 tag_entry.file = NULL;
833 g_free (tag_entry_file_cache);
836 #ifdef DEBUG
837 gdouble elapsed_DEBUG = g_timer_elapsed (sym_timer_DEBUG, NULL);
838 tags_total_DEBUG += tags_num_DEBUG;
839 elapsed_total_DEBUG += elapsed_DEBUG;
840 DEBUG_PRINT ("elapsed: %f for (%d) [%f sec/symbol] [av %f sec/symbol]", elapsed_DEBUG,
841 tags_num_DEBUG, elapsed_DEBUG / tags_num_DEBUG,
842 elapsed_total_DEBUG / tags_total_DEBUG);
843 #endif
845 /* notify listeners that another file has been scanned */
846 g_async_queue_push (priv->signals_queue, GINT_TO_POINTER (SINGLE_FILE_SCAN_END +1));
848 /* we've done with tag_file but we don't need to tagsClose (tag_file); */
851 /* ~~~ Thread note: this function locks the mutex ~~~ */
852 static void
853 sdb_engine_ctags_output_thread (gpointer data, gpointer user_data)
855 gint len_chars;
856 gchar *chars, *chars_ptr;
857 gint remaining_chars;
858 gint len_marker;
859 SymbolDBEnginePriv *priv;
860 SymbolDBEngine *dbe;
862 chars = chars_ptr = (gchar *)data;
863 dbe = SYMBOL_DB_ENGINE (user_data);
865 g_return_if_fail (dbe != NULL);
866 g_return_if_fail (chars_ptr != NULL);
868 priv = dbe->priv;
870 SDB_LOCK(priv);
872 remaining_chars = len_chars = strlen (chars_ptr);
873 len_marker = strlen (CTAGS_MARKER);
875 /*DEBUG_PRINT ("program output [new version]: ==>%s<==", chars);*/
876 if (len_chars >= len_marker)
878 gchar *marker_ptr = NULL;
879 gint tmp_str_length = 0;
881 /* is it an end file marker? */
882 marker_ptr = strstr (chars_ptr, CTAGS_MARKER);
886 if (marker_ptr != NULL)
888 int scan_flag;
889 gchar *real_file;
891 /* set the length of the string parsed */
892 tmp_str_length = marker_ptr - chars_ptr;
894 /* write to shm_file all the chars_ptr received without the marker ones */
895 fwrite (chars_ptr, sizeof(gchar), tmp_str_length, priv->shared_mem_file);
897 chars_ptr = marker_ptr + len_marker;
898 remaining_chars -= (tmp_str_length + len_marker);
899 fflush (priv->shared_mem_file);
901 /* get the scan flag from the queue. We need it to know whether
902 * an update of symbols must be done or not */
903 scan_flag = GPOINTER_TO_INT(g_async_queue_try_pop (priv->scan_queue));
904 real_file = g_async_queue_try_pop (priv->scan_queue);
906 /* and now call the populating function */
907 if (scan_flag == DO_UPDATE_SYMS ||
908 scan_flag == DO_UPDATE_SYMS_AND_EXIT)
910 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
911 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
912 TRUE);
914 else
916 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
917 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
918 FALSE);
921 /* don't forget to free the real_file, if it's a char */
922 if ((gsize)real_file != DONT_FAKE_UPDATE_SYMS)
923 g_free (real_file);
925 /* check also if, together with an end file marker, we have an
926 * end group-of-files end marker.
928 if (scan_flag == DO_UPDATE_SYMS_AND_EXIT ||
929 scan_flag == DONT_UPDATE_SYMS_AND_EXIT )
931 gint tmp_inserted;
932 gint tmp_updated;
934 /* scan has ended. Go go with second step. */
935 DEBUG_PRINT ("%s", "FOUND end-of-group-files marker.");
937 chars_ptr += len_marker;
938 remaining_chars -= len_marker;
940 /* will emit symbol_scope_updated and will flush on disk
941 * tablemaps
943 sdb_engine_second_pass_do (dbe);
945 /* Here we are. It's the right time to notify the listeners
946 * about out fresh new inserted/updated symbols...
947 * Go on by emitting them.
949 while ((tmp_inserted = GPOINTER_TO_INT(
950 g_async_queue_try_pop (priv->inserted_symbols_id))) > 0)
952 /* we must be sure to insert both signals at once */
953 g_async_queue_lock (priv->signals_queue);
955 /* the +1 is because asyn_queue doesn't want NULL values */
956 g_async_queue_push_unlocked (priv->signals_queue,
957 GINT_TO_POINTER(SYMBOL_INSERTED + 1));
958 g_async_queue_push_unlocked (priv->signals_queue,
959 GINT_TO_POINTER(tmp_inserted));
960 g_async_queue_unlock (priv->signals_queue);
963 while ((tmp_updated = GPOINTER_TO_INT(
964 g_async_queue_try_pop (priv->updated_symbols_id))) > 0)
966 g_async_queue_lock (priv->signals_queue);
967 g_async_queue_push_unlocked (priv->signals_queue, GINT_TO_POINTER
968 (SYMBOL_UPDATED + 1));
969 g_async_queue_push_unlocked (priv->signals_queue,
970 GINT_TO_POINTER(tmp_updated));
971 g_async_queue_unlock (priv->signals_queue);
974 while ((tmp_updated = GPOINTER_TO_INT(
975 g_async_queue_try_pop (priv->updated_scope_symbols_id))) > 0)
977 g_async_queue_lock (priv->signals_queue);
978 g_async_queue_push_unlocked (priv->signals_queue, GINT_TO_POINTER (
979 SYMBOL_SCOPE_UPDATED + 1));
980 g_async_queue_push_unlocked (priv->signals_queue,
981 GINT_TO_POINTER(tmp_updated));
982 g_async_queue_unlock (priv->signals_queue);
986 /* emit signal. The end of files-group can be cannot be
987 * determined by the caller. This is the only way.
989 DEBUG_PRINT ("%s", "EMITTING scan-end");
990 #ifdef DEBUG
991 if (priv->first_scan_timer_DEBUG != NULL)
993 DEBUG_PRINT ("~~~~~ TOTAL FIRST SCAN elapsed: %f ",
994 g_timer_elapsed (priv->first_scan_timer_DEBUG, NULL));
995 g_timer_destroy (priv->first_scan_timer_DEBUG);
996 priv->first_scan_timer_DEBUG = NULL;
998 #endif
1000 g_async_queue_push (priv->signals_queue, GINT_TO_POINTER(SCAN_END + 1));
1003 /* truncate the file to 0 length */
1004 ftruncate (priv->shared_mem_fd, 0);
1006 else
1008 /* marker_ptr is NULL here. We should then exit the loop. */
1009 /* write to shm_file all the chars received */
1010 fwrite (chars_ptr, sizeof(gchar), remaining_chars,
1011 priv->shared_mem_file);
1013 fflush (priv->shared_mem_file);
1014 break;
1017 /* found out a new marker */
1018 marker_ptr = strstr (marker_ptr + len_marker, CTAGS_MARKER);
1019 } while (remaining_chars + len_marker < len_chars || marker_ptr != NULL);
1022 SDB_UNLOCK(priv);
1024 g_free (chars);
1029 * This function runs on the main glib thread, so that it can safely spread signals
1031 static gboolean
1032 sdb_engine_timeout_trigger_signals (gpointer user_data)
1034 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1035 SymbolDBEnginePriv *priv;
1037 g_return_val_if_fail (user_data != NULL, FALSE);
1038 priv = dbe->priv;
1040 if (priv->signals_queue != NULL &&
1041 g_async_queue_length (priv->signals_queue) > 0)
1043 gpointer tmp;
1044 gpointer sign = NULL;
1045 gsize real_signal;
1047 while (priv->signals_queue != NULL &&
1048 (sign = g_async_queue_try_pop (priv->signals_queue)) != NULL)
1050 if (sign == NULL)
1052 return g_async_queue_length (priv->signals_queue) > 0 ? TRUE : FALSE;
1055 real_signal = (gsize)sign -1;
1057 switch (real_signal)
1059 case SINGLE_FILE_SCAN_END:
1060 g_signal_emit (dbe, signals[SINGLE_FILE_SCAN_END], 0);
1061 break;
1063 case SCAN_END:
1065 /* reset count */
1066 priv->symbols_scanned_count = 0;
1068 DEBUG_PRINT ("Committing symboltrans transaction...");
1069 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
1070 NULL);
1071 DEBUG_PRINT ("... Done!");
1073 /* perform flush on db of the tablemaps, if this is the 1st scan */
1074 if (priv->is_first_population == TRUE)
1076 /* ok, set the flag to false. We're done with it */
1077 priv->is_first_population = FALSE;
1080 /* get the process id from the queue */
1081 gint int_tmp = GPOINTER_TO_INT(g_async_queue_pop (priv->scan_process_id_queue));
1082 priv->scanning--;
1083 g_signal_emit (dbe, signals[SCAN_END], 0, int_tmp);
1085 break;
1087 case SYMBOL_INSERTED:
1088 tmp = g_async_queue_try_pop (priv->signals_queue);
1089 g_signal_emit (dbe, signals[SYMBOL_INSERTED], 0, tmp);
1090 break;
1092 case SYMBOL_UPDATED:
1093 tmp = g_async_queue_try_pop (priv->signals_queue);
1094 g_signal_emit (dbe, signals[SYMBOL_UPDATED], 0, tmp);
1095 break;
1097 case SYMBOL_SCOPE_UPDATED:
1098 tmp = g_async_queue_try_pop (priv->signals_queue);
1099 g_signal_emit (dbe, signals[SYMBOL_SCOPE_UPDATED], 0, tmp);
1100 break;
1102 case SYMBOL_REMOVED:
1103 tmp = g_async_queue_try_pop (priv->signals_queue);
1104 g_signal_emit (dbe, signals[SYMBOL_REMOVED], 0, tmp);
1105 break;
1108 /* reset to 0 the retries */
1109 priv->trigger_closure_retries = 0;
1111 else {
1112 priv->trigger_closure_retries++;
1115 if (priv->thread_pool != NULL &&
1116 g_thread_pool_unprocessed (priv->thread_pool) == 0 &&
1117 g_thread_pool_get_num_threads (priv->thread_pool) == 0)
1119 /* remove the trigger coz we don't need it anymore... */
1120 g_source_remove (priv->timeout_trigger_handler);
1121 priv->timeout_trigger_handler = 0;
1122 return FALSE;
1125 return TRUE;
1128 static void
1129 sdb_engine_ctags_output_callback_1 (AnjutaLauncher * launcher,
1130 AnjutaLauncherOutputType output_type,
1131 const gchar * chars, gpointer user_data)
1133 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1134 SymbolDBEnginePriv *priv;
1136 g_return_if_fail (user_data != NULL);
1138 priv = dbe->priv;
1140 if (priv->shutting_down == TRUE)
1141 return;
1143 g_thread_pool_push (priv->thread_pool, g_strdup (chars), NULL);
1145 /* signals monitor */
1146 if (priv->timeout_trigger_handler <= 0)
1148 priv->timeout_trigger_handler =
1149 g_timeout_add_full (G_PRIORITY_LOW, TRIGGER_SIGNALS_DELAY,
1150 sdb_engine_timeout_trigger_signals, user_data, NULL);
1151 priv->trigger_closure_retries = 0;
1155 static void
1156 on_scan_files_end_1 (AnjutaLauncher * launcher, int child_pid,
1157 int exit_status, gulong time_taken_in_seconds,
1158 gpointer user_data)
1160 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1161 SymbolDBEnginePriv *priv;
1163 g_return_if_fail (user_data != NULL);
1165 priv = dbe->priv;
1167 DEBUG_PRINT ("***** ctags ended (%s) (%s) *****", priv->ctags_path,
1168 priv->cnc_string);
1170 if (priv->shutting_down == TRUE)
1171 return;
1173 priv->ctags_path = NULL;
1176 static void
1177 sdb_engine_ctags_launcher_create (SymbolDBEngine * dbe)
1179 SymbolDBEnginePriv *priv;
1180 gchar *exe_string;
1182 priv = dbe->priv;
1184 DEBUG_PRINT ("Creating anjuta_launcher with %s for %s", priv->ctags_path,
1185 priv->cnc_string);
1187 priv->ctags_launcher = anjuta_launcher_new ();
1189 anjuta_launcher_set_check_passwd_prompt (priv->ctags_launcher, FALSE);
1190 anjuta_launcher_set_encoding (priv->ctags_launcher, NULL);
1192 g_signal_connect (G_OBJECT (priv->ctags_launcher), "child-exited",
1193 G_CALLBACK (on_scan_files_end_1), dbe);
1195 exe_string = g_strdup_printf ("%s --sort=no --fields=afmiKlnsStTz --c++-kinds=+p "
1196 "--filter=yes --filter-terminator='"CTAGS_MARKER"'",
1197 priv->ctags_path);
1198 DEBUG_PRINT ("Launching %s", exe_string);
1199 anjuta_launcher_execute (priv->ctags_launcher,
1200 exe_string, sdb_engine_ctags_output_callback_1,
1201 dbe);
1202 g_free (exe_string);
1206 * A GAsyncReadyCallback function. This function is the async continuation for
1207 * sdb_engine_scan_files_1 ().
1209 static void
1210 sdb_engine_scan_files_2 (GFile *gfile,
1211 GAsyncResult *res,
1212 gpointer user_data)
1214 ScanFiles1Data *sf_data = (ScanFiles1Data*)user_data;
1215 SymbolDBEngine *dbe;
1216 SymbolDBEnginePriv *priv;
1217 GFileInfo *ginfo;
1218 gchar *local_path;
1219 gchar *real_file;
1220 gboolean symbols_update;
1221 gint partial_count;
1222 gint files_list_len;
1224 dbe = sf_data->dbe;
1225 symbols_update = sf_data->symbols_update;
1226 real_file = sf_data->real_file;
1227 files_list_len = sf_data->files_list_len;
1228 partial_count = sf_data->partial_count;
1230 priv = dbe->priv;
1232 ginfo = g_file_query_info_finish (gfile, res, NULL);
1234 local_path = g_file_get_path (gfile);
1236 if (ginfo == NULL ||
1237 g_file_info_get_attribute_boolean (ginfo,
1238 G_FILE_ATTRIBUTE_ACCESS_CAN_READ) == FALSE)
1240 g_warning ("File does not exist or is unreadable by user (%s)", local_path);
1242 g_free (local_path);
1243 g_free (real_file);
1244 g_free (sf_data);
1246 if (ginfo)
1247 g_object_unref (ginfo);
1248 if (gfile)
1249 g_object_unref (gfile);
1250 return;
1253 /* DEBUG_PRINT ("sent to stdin %s", local_path); */
1254 anjuta_launcher_send_stdin (priv->ctags_launcher, local_path);
1255 anjuta_launcher_send_stdin (priv->ctags_launcher, "\n");
1257 if (symbols_update == TRUE)
1259 /* will this be the last file in the list? */
1260 if (partial_count + 1 >= files_list_len)
1262 /* yes */
1263 g_async_queue_push (priv->scan_queue, GINT_TO_POINTER (DO_UPDATE_SYMS_AND_EXIT));
1265 else
1267 /* no */
1268 g_async_queue_push (priv->scan_queue, GINT_TO_POINTER (DO_UPDATE_SYMS));
1271 else
1273 if (partial_count + 1 >= files_list_len)
1275 /* yes */
1276 g_async_queue_push (priv->scan_queue, GINT_TO_POINTER (DONT_UPDATE_SYMS_AND_EXIT));
1278 else {
1279 /* no */
1280 g_async_queue_push (priv->scan_queue, GINT_TO_POINTER (DONT_UPDATE_SYMS));
1284 /* don't forget to add the real_files if the caller provided a list for
1285 * them! */
1286 if (real_file != NULL)
1288 g_async_queue_push (priv->scan_queue,
1289 real_file);
1291 else
1293 /* else add a DONT_FAKE_UPDATE_SYMS marker, just to notify that this
1294 * is not a fake file scan
1296 g_async_queue_push (priv->scan_queue, GINT_TO_POINTER (DONT_FAKE_UPDATE_SYMS));
1299 /* we don't need ginfo object anymore, bye */
1300 g_object_unref (ginfo);
1301 g_object_unref (gfile);
1302 g_free (local_path);
1303 g_free (sf_data);
1304 /* no need to free real_file. For two reasons: 1. it's null. 2. it has been
1305 * pushed in the async queue and will be freed later
1309 /* Scans with ctags and produce an output 'tags' file [shared memory file]
1310 * containing language symbols. This function will call ctags
1311 * executale and then sdb_engine_populate_db_by_tags () when it'll detect some
1312 * output.
1313 * Please note the files_list/real_files_list parameter:
1314 * this version of sdb_engine_scan_files_1 () let you scan for text buffer(s) that
1315 * will be claimed as buffers for the real files.
1316 * 1. simple mode: files_list represents the real files on disk and so we don't
1317 * need real_files_list, which will be NULL.
1318 * 2. advanced mode: files_list represents temporary flushing of buffers on disk, i.e.
1319 * /tmp/anjuta_XYZ.cxx. real_files_list is the representation of those files on
1320 * database. On the above example we can have anjuta_XYZ.cxx mapped as /src/main.c
1321 * on db. In this mode files_list and real_files_list must have the same size.
1324 /* server mode version */
1325 static gboolean
1326 sdb_engine_scan_files_1 (SymbolDBEngine * dbe, const GPtrArray * files_list,
1327 const GPtrArray *real_files_list, gboolean symbols_update)
1329 SymbolDBEnginePriv *priv;
1330 gint i;
1332 g_return_val_if_fail (files_list != NULL, FALSE);
1334 if (files_list->len == 0)
1335 return FALSE;
1337 /* start process in server mode */
1338 priv = dbe->priv;
1340 if (real_files_list != NULL && (files_list->len != real_files_list->len))
1342 g_warning ("no matched size between real_files_list and files_list");
1343 return FALSE;
1346 /* if ctags_launcher isn't initialized, then do it now. */
1347 /* lazy initialization */
1348 if (priv->ctags_launcher == NULL)
1350 sdb_engine_ctags_launcher_create (dbe);
1353 priv->scanning++; /* Enter scanning state */
1354 DEBUG_PRINT ("%s", "EMITTING scan begin.");
1355 g_signal_emit_by_name (dbe, "scan-begin",
1356 anjuta_launcher_get_child_pid (priv->ctags_launcher));
1358 #ifdef DEBUG
1359 if (priv->first_scan_timer_DEBUG == NULL)
1360 priv->first_scan_timer_DEBUG = g_timer_new ();
1361 #endif
1363 /* create the shared memory file */
1364 if (priv->shared_mem_file == 0)
1366 gchar *temp_file;
1367 gint i = 0;
1368 while (TRUE)
1370 temp_file = g_strdup_printf ("/anjuta-%d_%ld%d.tags", getpid (),
1371 time (NULL), i++);
1372 gchar *test;
1373 test = g_strconcat (SHARED_MEMORY_PREFIX, temp_file, NULL);
1374 if (g_file_test (test, G_FILE_TEST_EXISTS) == TRUE)
1376 DEBUG_PRINT ("file %s already exists... retrying", test);
1377 g_free (test);
1378 g_free (temp_file);
1379 continue;
1381 else
1383 g_free (test);
1384 break;
1388 priv->shared_mem_str = temp_file;
1390 if ((priv->shared_mem_fd =
1391 shm_open (temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
1393 g_warning ("Error while trying to open a shared memory file. Be"
1394 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
1397 priv->shared_mem_file = fdopen (priv->shared_mem_fd, "a+b");
1398 /*DEBUG_PRINT ("temp_file %s", temp_file);*/
1400 /* no need to free temp_file (alias shared_mem_str). It will be freed on plugin finalize */
1403 for (i = 0; i < files_list->len; i++)
1405 GFile *gfile;
1406 ScanFiles1Data *sf_data;
1407 gchar *node = (gchar *) g_ptr_array_index (files_list, i);
1408 gfile = g_file_new_for_path (node);
1410 /* prepare an ojbect where to store some data for the async call */
1411 sf_data = g_new0 (ScanFiles1Data, 1);
1412 sf_data->dbe = dbe;
1413 sf_data->files_list_len = files_list->len;
1414 sf_data->partial_count = i;
1415 sf_data->symbols_update = symbols_update;
1417 if (real_files_list != NULL)
1419 sf_data->real_file = g_strdup (g_ptr_array_index (real_files_list, i));
1421 else
1423 sf_data->real_file = NULL;
1426 /* call it */
1427 g_file_query_info_async (gfile,
1428 G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
1429 G_FILE_QUERY_INFO_NONE,
1430 G_PRIORITY_LOW,
1431 NULL,
1432 (GAsyncReadyCallback)sdb_engine_scan_files_2,
1433 sf_data);
1436 return TRUE;
1439 static void
1440 sdb_engine_init (SymbolDBEngine * object)
1442 SymbolDBEngine *sdbe;
1443 GHashTable *h;
1445 sdbe = SYMBOL_DB_ENGINE (object);
1446 sdbe->priv = g_new0 (SymbolDBEnginePriv, 1);
1448 sdbe->priv->db_connection = NULL;
1449 sdbe->priv->sql_parser = NULL;
1450 sdbe->priv->db_directory = NULL;
1451 sdbe->priv->project_directory = NULL;
1452 sdbe->priv->cnc_string = NULL;
1454 /* initialize an hash table to be used and shared with Iterators */
1455 sdbe->priv->sym_type_conversion_hash =
1456 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1457 h = sdbe->priv->sym_type_conversion_hash;
1459 /* please if you change some value below here remember to change also on */
1460 g_hash_table_insert (h, g_strdup("class"),
1461 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_CLASS));
1463 g_hash_table_insert (h, g_strdup("enum"),
1464 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUM));
1466 g_hash_table_insert (h, g_strdup("enumerator"),
1467 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUMERATOR));
1469 g_hash_table_insert (h, g_strdup("field"),
1470 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FIELD));
1472 g_hash_table_insert (h, g_strdup("function"),
1473 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FUNCTION));
1475 g_hash_table_insert (h, g_strdup("interface"),
1476 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_INTERFACE));
1478 g_hash_table_insert (h, g_strdup("member"),
1479 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MEMBER));
1481 g_hash_table_insert (h, g_strdup("method"),
1482 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_METHOD));
1484 g_hash_table_insert (h, g_strdup("namespace"),
1485 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_NAMESPACE));
1487 g_hash_table_insert (h, g_strdup("package"),
1488 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PACKAGE));
1490 g_hash_table_insert (h, g_strdup("prototype"),
1491 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PROTOTYPE));
1493 g_hash_table_insert (h, g_strdup("struct"),
1494 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_STRUCT));
1496 g_hash_table_insert (h, g_strdup("typedef"),
1497 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_TYPEDEF));
1499 g_hash_table_insert (h, g_strdup("union"),
1500 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_UNION));
1502 g_hash_table_insert (h, g_strdup("variable"),
1503 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_VARIABLE));
1505 g_hash_table_insert (h, g_strdup("externvar"),
1506 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_EXTERNVAR));
1508 g_hash_table_insert (h, g_strdup("macro"),
1509 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO));
1511 g_hash_table_insert (h, g_strdup("macro_with_arg"),
1512 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG));
1514 g_hash_table_insert (h, g_strdup("file"),
1515 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FILE));
1517 g_hash_table_insert (h, g_strdup("other"),
1518 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_OTHER));
1521 /* create the hash table that will store shared memory files strings used for
1522 * buffer scanning. Un Engine destroy will unlink () them.
1524 sdbe->priv->garbage_shared_mem_files = g_hash_table_new_full (g_str_hash, g_str_equal,
1525 g_free, NULL);
1527 sdbe->priv->ctags_launcher = NULL;
1528 sdbe->priv->removed_launchers = NULL;
1529 sdbe->priv->shutting_down = FALSE;
1530 sdbe->priv->is_first_population = FALSE;
1532 sdbe->priv->symbols_scanned_count = 0;
1534 /* set the ctags executable path to NULL */
1535 sdbe->priv->ctags_path = NULL;
1537 /* NULL the name of the default db */
1538 sdbe->priv->anjuta_db_file = NULL;
1540 /* identify the scan process with an id. There can be multiple files associated
1541 * within a process. A call to scan_files () will put inside the queue an id
1542 * returned and emitted by scan-end.
1544 sdbe->priv->scan_process_id_queue = g_async_queue_new ();
1545 sdbe->priv->scan_process_id = 1;
1547 /* the scan_queue? It will contain mainly
1548 * ints that refer to the force_update status.
1550 sdbe->priv->scan_queue = g_async_queue_new ();
1552 /* the thread pool for tags scannning */
1553 sdbe->priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
1554 sdbe, THREADS_MAX_CONCURRENT,
1555 FALSE, NULL);
1557 /* some signals queues */
1558 sdbe->priv->signals_queue = g_async_queue_new ();
1559 sdbe->priv->updated_symbols_id = g_async_queue_new ();
1560 sdbe->priv->updated_scope_symbols_id = g_async_queue_new ();
1561 sdbe->priv->inserted_symbols_id = g_async_queue_new ();
1562 sdbe->priv->scanning = 0;
1565 * STATIC QUERY STRUCTURE INITIALIZE
1568 /* -- workspace -- */
1569 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1570 PREP_QUERY_WORKSPACE_NEW,
1571 "INSERT INTO workspace (workspace_name, analyse_time) VALUES (\
1572 ## /* name:'wsname' type:gchararray */, \
1573 datetime ('now', 'localtime'))");
1575 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1576 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
1577 "SELECT workspace_id FROM workspace \
1578 WHERE \
1579 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1");
1581 /* -- project -- */
1582 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1583 PREP_QUERY_PROJECT_NEW,
1584 "INSERT INTO project (project_name, wrkspace_id, analyse_time) VALUES (\
1585 ## /* name:'prjname' type:gchararray */, \
1586 (SELECT workspace_id FROM workspace \
1587 WHERE \
1588 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1), \
1589 datetime ('now', 'localtime'))");
1591 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1592 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME,
1593 "SELECT project_id FROM project \
1594 WHERE \
1595 project_name = ## /* name:'prjname' type:gchararray */ LIMIT 1");
1597 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1598 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME,
1599 "UPDATE project SET \
1600 analyse_time = datetime('now', 'localtime', '+10 seconds') \
1601 WHERE \
1602 project_name = ## /* name:'prjname' type:gchararray */");
1604 /* -- file -- */
1605 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1606 PREP_QUERY_FILE_NEW,
1607 "INSERT INTO file (file_path, prj_id, lang_id, analyse_time) VALUES (\
1608 ## /* name:'filepath' type:gchararray */, \
1609 (SELECT project_id FROM project \
1610 WHERE \
1611 project_name = ## /* name:'prjname' type:gchararray */ LIMIT 1), \
1612 ## /* name:'langid' type:gint */, \
1613 datetime ('now', 'localtime'))");
1615 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1616 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
1617 "SELECT file_id FROM file \
1618 WHERE \
1619 file_path = ## /* name:'filepath' type:gchararray */ LIMIT 1");
1621 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1622 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME,
1623 "SELECT file_id, file_path AS db_file_path, prj_id, lang_id, file.analyse_time \
1624 FROM file JOIN project ON project.project_id = file.prj_id \
1625 WHERE \
1626 project.project_name = ## /* name:'prjname' type:gchararray */");
1628 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1629 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME,
1630 "UPDATE file SET \
1631 analyse_time = datetime('now', 'localtime') \
1632 WHERE \
1633 file_path = ## /* name:'filepath' type:gchararray */");
1635 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1636 PREP_QUERY_GET_ALL_FROM_FILE_WHERE_NOT_IN_SYMBOLS,
1637 "SELECT file_id, file_path AS db_file_path FROM file \
1638 WHERE file_id NOT IN (SELECT file_defined_id FROM symbol)");
1640 /* -- language -- */
1641 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1642 PREP_QUERY_LANGUAGE_NEW,
1643 "INSERT INTO language (language_name) VALUES (\
1644 ## /* name:'langname' type:gchararray */)");
1646 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1647 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
1648 "SELECT language_id FROM language WHERE \
1649 language_name = ## /* name:'langname' type:gchararray */ LIMIT 1");
1651 /* -- sym kind -- */
1652 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1653 PREP_QUERY_SYM_KIND_NEW,
1654 "INSERT INTO sym_kind (kind_name, is_container) VALUES(\
1655 ## /* name:'kindname' type:gchararray */, \
1656 ## /* name:'container' type:gint */)");
1658 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1659 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
1660 "SELECT sym_kind_id FROM sym_kind WHERE \
1661 kind_name = ## /* name:'kindname' type:gchararray */");
1663 /* -- sym access -- */
1664 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1665 PREP_QUERY_SYM_ACCESS_NEW,
1666 "INSERT INTO sym_access (access_name) VALUES(\
1667 ## /* name:'accesskind' type:gchararray */)");
1669 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1670 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
1671 "SELECT access_kind_id FROM sym_access WHERE \
1672 access_name = ## /* name:'accesskind' type:gchararray */ LIMIT 1");
1674 /* -- sym implementation -- */
1675 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1676 PREP_QUERY_SYM_IMPLEMENTATION_NEW,
1677 "INSERT INTO sym_implementation (implementation_name) VALUES(\
1678 ## /* name:'implekind' type:gchararray */)");
1680 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1681 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
1682 "SELECT sym_impl_id FROM sym_implementation WHERE \
1683 kind = ## /* name:'implekind' type:gchararray */ LIMIT 1");
1685 /* -- heritage -- */
1686 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1687 PREP_QUERY_HERITAGE_NEW,
1688 "INSERT INTO heritage (symbol_id_base, symbol_id_derived) VALUES(\
1689 ## /* name:'symbase' type:gint */, \
1690 ## /* name:'symderived' type:gint */)");
1692 /* -- scope -- */
1693 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1694 PREP_QUERY_SCOPE_NEW,
1695 "INSERT INTO scope (scope_name) VALUES(\
1696 ## /* name:'scope' type:gchararray */)");
1698 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1699 PREP_QUERY_GET_SCOPE_ID,
1700 "SELECT scope_id FROM scope \
1701 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1702 LIMIT 1");
1704 /* -- symbol -- */
1705 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1706 PREP_QUERY_SYMBOL_NEW,
1707 "INSERT INTO symbol (file_defined_id, name, file_position, \
1708 is_file_scope, signature, returntype, \
1709 scope_definition_id, scope_id, \
1710 type_type, type_name, kind_id, access_kind_id, \
1711 implementation_kind_id, update_flag) \
1712 VALUES( \
1713 ## /* name:'filedefid' type:gint */, \
1714 ## /* name:'name' type:gchararray */, \
1715 ## /* name:'fileposition' type:gint */, \
1716 ## /* name:'isfilescope' type:gint */, \
1717 ## /* name:'signature' type:gchararray */, \
1718 ## /* name:'returntype' type:gchararray */, \
1719 CASE ## /* name:'scopedefinitionid' type:gint */ \
1720 WHEN -1 THEN (SELECT scope_id FROM scope \
1721 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1722 LIMIT 1) \
1723 ELSE ## /* name:'scopedefinitionid' type:gint */ END, \
1724 ## /* name:'scopeid' type:gint */, \
1725 ## /* name:'typetype' type:gchararray */, \
1726 ## /* name:'typename' type:gchararray */, \
1727 ## /* name:'kindid' type:gint */,## /* name:'accesskindid' type:gint */, \
1728 ## /* name:'implementationkindid' type:gint */, \
1729 ## /* name:'updateflag' type:gint */)");
1732 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1733 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
1734 "SELECT symbol_id FROM symbol \
1735 WHERE scope_id = 0 AND \
1736 type_type='class' AND \
1737 name = ## /* name:'klassname' type:gchararray */ LIMIT 1");
1739 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1740 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
1741 "SELECT symbol_id FROM symbol JOIN scope ON symbol.scope_id = scope.scope_id \
1742 WHERE symbol.name = ## /* name:'klassname' type:gchararray */ AND \
1743 scope.scope_name = ## /* name:'namespacename' type:gchararray */ AND \
1744 symbol.type_type = 'namespace' LIMIT 1");
1746 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1747 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID,
1748 "UPDATE symbol SET scope_id = (SELECT scope_definition_id FROM symbol WHERE \
1749 type_type = ## /* name:'tokenname' type:gchararray */ AND \
1750 type_name = ## /* name:'objectname' type:gchararray */ LIMIT 1) \
1751 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
1753 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1754 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
1755 "SELECT symbol_id FROM symbol \
1756 WHERE \
1757 name = ## /* name:'symname' type:gchararray */ AND \
1758 file_defined_id = ## /* name:'filedefid' type:gint */ AND \
1759 type_type = ## /* name:'typetype' type:gchararray */ AND \
1760 type_name = ## /* name:'typename' type:gchararray */ AND \
1761 update_flag = 0 LIMIT 1");
1763 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1764 PREP_QUERY_UPDATE_SYMBOL_ALL,
1765 "UPDATE symbol SET \
1766 is_file_scope = ## /* name:'isfilescope' type:gint */, \
1767 file_position = ## /* name:'fileposition' type:gint */, \
1768 signature = ## /* name:'signature' type:gchararray */, \
1769 returntype = ## /* name:'returntype' type:gchararray */, \
1770 scope_definition_id = ## /* name:'scopedefinitionid' type:gint */, \
1771 scope_id = ## /* name:'scopeid' type:gint */, \
1772 kind_id = ## /* name:'kindid' type:gint */, \
1773 access_kind_id = ## /* name:'accesskindid' type:gint */, \
1774 implementation_kind_id = ## /* name:'implementationkindid' type:gint */, \
1775 update_flag = ## /* name:'updateflag' type:gint */ \
1776 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
1778 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1779 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS,
1780 "DELETE FROM symbol WHERE \
1781 file_defined_id = (SELECT file_id FROM file \
1782 WHERE \
1783 file.file_path = ## /* name:'filepath' type:gchararray */) AND \
1784 update_flag = 0");
1786 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1787 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS,
1788 "UPDATE symbol SET \
1789 update_flag = 0 \
1790 WHERE file_defined_id = (SELECT file_id FROM file \
1791 WHERE \
1792 file_path = ## /* name:'filepath' type:gchararray */)");
1794 /* -- tmp_removed -- */
1795 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1796 PREP_QUERY_GET_REMOVED_IDS,
1797 "SELECT symbol_removed_id FROM __tmp_removed");
1799 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1800 PREP_QUERY_TMP_REMOVED_DELETE_ALL,
1801 "DELETE FROM __tmp_removed");
1803 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1804 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME,
1805 "DELETE FROM file WHERE \
1806 prj_id = (SELECT project_id FROM project \
1807 WHERE project_name = ## /* name:'prjname' type:gchararray */) AND \
1808 file_path = ## /* name:'filepath' type:gchararray */");
1810 /* init cache hashtables */
1811 sdb_engine_init_caches (sdbe);
1813 /* init table maps */
1814 sdb_engine_init_table_maps (sdbe);
1817 static void
1818 sdb_engine_unlink_shared_files (gpointer key, gpointer value, gpointer user_data)
1820 shm_unlink (key);
1823 static void
1824 sdb_engine_unref_removed_launchers (gpointer data, gpointer user_data)
1826 g_object_unref (data);
1829 static void
1830 sdb_engine_finalize (GObject * object)
1832 SymbolDBEngine *dbe;
1833 SymbolDBEnginePriv *priv;
1835 dbe = SYMBOL_DB_ENGINE (object);
1836 priv = dbe->priv;
1838 if (priv->thread_pool)
1840 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
1841 priv->thread_pool = NULL;
1844 if (priv->ctags_launcher)
1846 g_object_unref (priv->ctags_launcher);
1847 priv->ctags_launcher = NULL;
1850 if (priv->removed_launchers)
1852 g_list_foreach (priv->removed_launchers,
1853 sdb_engine_unref_removed_launchers, NULL);
1854 g_list_free (priv->removed_launchers);
1855 priv->removed_launchers = NULL;
1858 if (priv->mutex)
1860 g_mutex_free (priv->mutex);
1861 priv->mutex = NULL;
1864 if (priv->timeout_trigger_handler > 0)
1865 g_source_remove (priv->timeout_trigger_handler);
1867 if (symbol_db_engine_is_connected (dbe) == TRUE)
1868 sdb_engine_disconnect_from_db (dbe);
1870 sdb_engine_free_cached_queries (dbe);
1872 if (priv->scan_process_id_queue)
1874 g_async_queue_unref (priv->scan_process_id_queue);
1875 priv->scan_process_id_queue = NULL;
1878 if (priv->scan_queue)
1880 g_async_queue_unref (priv->scan_queue);
1881 priv->scan_queue = NULL;
1884 if (priv->updated_symbols_id)
1886 g_async_queue_unref (priv->updated_symbols_id);
1887 priv->updated_symbols_id = NULL;
1890 if (priv->updated_scope_symbols_id)
1892 g_async_queue_unref (priv->updated_scope_symbols_id);
1893 priv->updated_scope_symbols_id = NULL;
1896 if (priv->inserted_symbols_id)
1898 g_async_queue_unref (priv->inserted_symbols_id);
1899 priv->inserted_symbols_id = NULL;
1902 if (priv->shared_mem_file)
1904 fclose (priv->shared_mem_file);
1905 priv->shared_mem_file = NULL;
1908 if (priv->shared_mem_str)
1910 shm_unlink (priv->shared_mem_str);
1911 g_free (priv->shared_mem_str);
1912 priv->shared_mem_str = NULL;
1915 if (priv->garbage_shared_mem_files)
1917 g_hash_table_foreach (priv->garbage_shared_mem_files,
1918 sdb_engine_unlink_shared_files,
1919 NULL);
1920 /* destroy the hash table */
1921 g_hash_table_destroy (priv->garbage_shared_mem_files);
1925 if (priv->sym_type_conversion_hash)
1926 g_hash_table_destroy (priv->sym_type_conversion_hash);
1927 priv->sym_type_conversion_hash = NULL;
1929 if (priv->signals_queue)
1930 g_async_queue_unref (priv->signals_queue);
1931 priv->signals_queue = NULL;
1933 sdb_engine_clear_caches (dbe);
1934 sdb_engine_clear_tablemaps (dbe);
1936 g_free (priv->anjuta_db_file);
1937 priv->anjuta_db_file = NULL;
1939 g_free (priv->ctags_path);
1940 priv->ctags_path = NULL;
1942 g_free (priv);
1944 G_OBJECT_CLASS (parent_class)->finalize (object);
1947 static void
1948 sdb_engine_class_init (SymbolDBEngineClass * klass)
1950 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1951 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
1953 object_class->finalize = sdb_engine_finalize;
1955 signals[DB_CONNECTED]
1956 = g_signal_new ("db-connected",
1957 G_OBJECT_CLASS_TYPE (object_class),
1958 G_SIGNAL_RUN_FIRST,
1959 G_STRUCT_OFFSET (SymbolDBEngineClass, db_connected),
1960 NULL, NULL,
1961 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1963 signals[DB_DISCONNECTED]
1964 = g_signal_new ("db-disconnected",
1965 G_OBJECT_CLASS_TYPE (object_class),
1966 G_SIGNAL_RUN_FIRST,
1967 G_STRUCT_OFFSET (SymbolDBEngineClass, db_disconnected),
1968 NULL, NULL,
1969 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1971 signals[SCAN_BEGIN]
1972 = g_signal_new ("scan-begin",
1973 G_OBJECT_CLASS_TYPE (object_class),
1974 G_SIGNAL_RUN_FIRST,
1975 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_begin),
1976 NULL, NULL,
1977 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
1979 G_TYPE_INT);
1981 signals[SINGLE_FILE_SCAN_END]
1982 = g_signal_new ("single-file-scan-end",
1983 G_OBJECT_CLASS_TYPE (object_class),
1984 G_SIGNAL_RUN_FIRST,
1985 G_STRUCT_OFFSET (SymbolDBEngineClass, single_file_scan_end),
1986 NULL, NULL,
1987 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1989 signals[SCAN_END]
1990 = g_signal_new ("scan-end",
1991 G_OBJECT_CLASS_TYPE (object_class),
1992 G_SIGNAL_RUN_FIRST,
1993 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_end),
1994 NULL, NULL,
1995 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
1997 G_TYPE_INT);
1999 signals[SYMBOL_INSERTED]
2000 = g_signal_new ("symbol-inserted",
2001 G_OBJECT_CLASS_TYPE (object_class),
2002 G_SIGNAL_RUN_FIRST,
2003 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_inserted),
2004 NULL, NULL,
2005 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2007 G_TYPE_INT);
2009 signals[SYMBOL_UPDATED]
2010 = g_signal_new ("symbol-updated",
2011 G_OBJECT_CLASS_TYPE (object_class),
2012 G_SIGNAL_RUN_FIRST,
2013 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_updated),
2014 NULL, NULL,
2015 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2017 G_TYPE_INT);
2019 signals[SYMBOL_SCOPE_UPDATED]
2020 = g_signal_new ("symbol-scope-updated",
2021 G_OBJECT_CLASS_TYPE (object_class),
2022 G_SIGNAL_RUN_FIRST,
2023 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_scope_updated),
2024 NULL, NULL,
2025 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2027 G_TYPE_INT);
2029 signals[SYMBOL_REMOVED]
2030 = g_signal_new ("symbol-removed",
2031 G_OBJECT_CLASS_TYPE (object_class),
2032 G_SIGNAL_RUN_FIRST,
2033 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_removed),
2034 NULL, NULL,
2035 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2037 G_TYPE_INT);
2040 GType
2041 sdb_engine_get_type (void)
2043 static GType our_type = 0;
2045 if (our_type == 0)
2047 static const GTypeInfo our_info = {
2048 sizeof (SymbolDBEngineClass), /* class_size */
2049 (GBaseInitFunc) NULL, /* base_init */
2050 (GBaseFinalizeFunc) NULL, /* base_finalize */
2051 (GClassInitFunc) sdb_engine_class_init, /* class_init */
2052 (GClassFinalizeFunc) NULL, /* class_finalize */
2053 NULL /* class_data */ ,
2054 sizeof (SymbolDBEngine), /* instance_size */
2055 0, /* n_preallocs */
2056 (GInstanceInitFunc) sdb_engine_init, /* instance_init */
2057 NULL /* value_table */
2060 our_type = g_type_register_static (G_TYPE_OBJECT, "SymbolDBEngine",
2061 &our_info, 0);
2064 return our_type;
2067 gboolean
2068 symbol_db_engine_set_ctags_path (SymbolDBEngine * dbe, const gchar * ctags_path)
2070 SymbolDBEnginePriv *priv;
2072 g_return_val_if_fail (dbe != NULL, FALSE);
2073 g_return_val_if_fail (ctags_path != NULL, FALSE);
2075 priv = dbe->priv;
2077 /* Check if ctags is really installed */
2078 if (!anjuta_util_prog_is_installed (ctags_path, TRUE))
2080 g_warning ("symbol_db_engine_set_ctags_path (): Wrong path for ctags. Keeping "
2081 "the old value %s", priv->ctags_path);
2082 return priv->ctags_path != NULL;
2085 /* have we already got it? */
2086 if (priv->ctags_path != NULL &&
2087 g_strcmp0 (priv->ctags_path, ctags_path) == 0)
2088 return TRUE;
2090 /* free the old value */
2091 g_free (priv->ctags_path);
2093 /* is anjutalauncher already created? */
2094 if (priv->ctags_launcher != NULL)
2096 AnjutaLauncher *tmp;
2097 tmp = priv->ctags_launcher;
2099 /* recreate it on the fly */
2100 sdb_engine_ctags_launcher_create (dbe);
2102 /* keep the launcher alive to avoid crashes */
2103 priv->removed_launchers = g_list_prepend (priv->removed_launchers, tmp);
2106 /* set the new one */
2107 priv->ctags_path = g_strdup (ctags_path);
2108 return TRUE;
2111 SymbolDBEngine *
2112 symbol_db_engine_new (const gchar * ctags_path)
2114 SymbolDBEngine *sdbe;
2115 SymbolDBEnginePriv *priv;
2117 g_return_val_if_fail (ctags_path != NULL, NULL);
2118 sdbe = g_object_new (SYMBOL_TYPE_DB_ENGINE, NULL);
2120 priv = sdbe->priv;
2121 priv->mutex = g_mutex_new ();
2122 priv->anjuta_db_file = g_strdup (ANJUTA_DB_FILE);
2124 /* set the mandatory ctags_path */
2125 if (!symbol_db_engine_set_ctags_path (sdbe, ctags_path))
2127 return NULL;
2130 return sdbe;
2133 SymbolDBEngine*
2134 symbol_db_engine_new_full (const gchar * ctags_path, const gchar * database_name)
2136 SymbolDBEngine* dbe;
2137 SymbolDBEnginePriv* priv;
2139 g_return_val_if_fail (database_name != NULL, NULL);
2140 dbe = symbol_db_engine_new (ctags_path);
2142 g_return_val_if_fail (dbe != NULL, NULL);
2144 priv = dbe->priv;
2145 g_free (priv->anjuta_db_file);
2146 priv->anjuta_db_file = g_strdup (database_name);
2148 return dbe;
2152 * Set some default parameters to use with the current database.
2154 static void
2155 sdb_engine_set_defaults_db_parameters (SymbolDBEngine * dbe)
2157 sdb_engine_execute_unknown_sql (dbe, "PRAGMA page_size = 32768");
2158 sdb_engine_execute_unknown_sql (dbe, "PRAGMA cache_size = 12288");
2159 sdb_engine_execute_unknown_sql (dbe, "PRAGMA synchronous = OFF");
2160 sdb_engine_execute_unknown_sql (dbe, "PRAGMA temp_store = MEMORY");
2161 sdb_engine_execute_unknown_sql (dbe, "PRAGMA journal_mode = OFF");
2162 sdb_engine_execute_unknown_sql (dbe, "PRAGMA read_uncommitted = 1");
2163 sdb_engine_execute_unknown_sql (dbe, "PRAGMA foreign_keys = OFF");
2164 symbol_db_engine_set_db_case_sensitive (dbe, TRUE);
2167 /* Will create priv->db_connection.
2168 * Connect to database identified by db_directory.
2169 * Usually db_directory is defined also into priv. We let it here as parameter
2170 * because it is required and cannot be null.
2172 static gboolean
2173 sdb_engine_connect_to_db (SymbolDBEngine * dbe, const gchar *cnc_string)
2175 SymbolDBEnginePriv *priv;
2177 g_return_val_if_fail (dbe != NULL, FALSE);
2178 priv = dbe->priv;
2180 if (priv->db_connection != NULL)
2182 /* if it's the case that the connection isn't NULL, we
2183 * should notify the user
2184 * and return FALSE. It's his task to disconnect and retry to connect */
2185 g_warning ("connection is already established. Please disconnect "
2186 "and then try to reconnect.");
2187 return FALSE;
2190 /* establish a connection. If the sqlite file does not exist it will
2191 * be created
2193 priv->db_connection = gda_connection_open_from_string ("SQLite", cnc_string, NULL,
2194 GDA_CONNECTION_OPTIONS_THREAD_SAFE, NULL);
2196 if (!GDA_IS_CONNECTION (priv->db_connection))
2198 g_warning ("Could not open connection to %s\n", cnc_string);
2199 return FALSE;
2202 priv->cnc_string = g_strdup (cnc_string);
2203 priv->sql_parser = gda_connection_create_parser (priv->db_connection);
2205 if (!GDA_IS_SQL_PARSER (priv->sql_parser))
2207 g_warning ("Could not create sql parser. Check your libgda installation");
2208 return FALSE;
2211 DEBUG_PRINT ("Connected to database %s", cnc_string);
2212 g_signal_emit_by_name (dbe, "db-connected", NULL);
2213 return TRUE;
2216 gboolean
2217 symbol_db_engine_is_connected (SymbolDBEngine * dbe)
2219 SymbolDBEnginePriv *priv;
2221 g_return_val_if_fail (dbe != NULL, FALSE);
2222 priv = dbe->priv;
2224 return priv->db_connection && priv->cnc_string && priv->sql_parser &&
2225 gda_connection_is_opened (priv->db_connection );
2228 gboolean
2229 symbol_db_engine_is_scanning (SymbolDBEngine *dbe)
2231 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), FALSE);
2232 return (dbe->priv->scanning > 0);
2236 * Creates required tables for the database to work.
2237 * Sets is_first_population flag to TRUE.
2238 * @param tables_sql_file File containing sql code.
2240 static gboolean
2241 sdb_engine_create_db_tables (SymbolDBEngine * dbe, const gchar * tables_sql_file)
2243 SymbolDBEnginePriv *priv;
2244 gchar *contents;
2245 gchar *query;
2246 gsize sizez;
2248 g_return_val_if_fail (tables_sql_file != NULL, FALSE);
2250 priv = dbe->priv;
2252 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2254 /* read the contents of the file */
2255 if (g_file_get_contents (tables_sql_file, &contents, &sizez, NULL) == FALSE)
2257 g_warning ("Something went wrong while trying to read %s",
2258 tables_sql_file);
2260 return FALSE;
2263 sdb_engine_execute_non_select_sql (dbe, contents);
2264 g_free (contents);
2266 /* set the current symbol db database version. This may help if new tables/fields
2267 * are added/removed in future versions.
2269 query = "INSERT INTO version VALUES ("SYMBOL_DB_VERSION")";
2270 sdb_engine_execute_non_select_sql (dbe, query);
2272 priv->is_first_population = TRUE;
2274 /* no need to free query of course */
2276 return TRUE;
2279 gboolean
2280 symbol_db_engine_db_exists (SymbolDBEngine * dbe, const gchar * prj_directory)
2282 SymbolDBEnginePriv *priv;
2284 g_return_val_if_fail (prj_directory != NULL, FALSE);
2286 priv = dbe->priv;
2288 /* check whether the db filename already exists.*/
2289 gchar *tmp_file = g_strdup_printf ("%s/%s.db", prj_directory,
2290 priv->anjuta_db_file);
2292 if (g_file_test (tmp_file, G_FILE_TEST_EXISTS) == FALSE)
2294 DEBUG_PRINT ("db %s does not exist", tmp_file);
2295 g_free (tmp_file);
2296 return FALSE;
2299 g_free (tmp_file);
2300 return TRUE;
2303 /* ~~~ Thread note: this function locks the mutex ~~~ */
2304 gboolean
2305 symbol_db_engine_file_exists (SymbolDBEngine * dbe, const gchar * abs_file_path)
2307 SymbolDBEnginePriv *priv;
2308 const gchar *relative;
2309 gint file_defined_id;
2310 GValue v = {0};
2312 g_return_val_if_fail (dbe != NULL, FALSE);
2313 g_return_val_if_fail (abs_file_path != NULL, FALSE);
2315 priv = dbe->priv;
2317 SDB_LOCK(priv);
2319 relative = symbol_db_util_get_file_db_path (dbe, abs_file_path);
2320 if (relative == NULL)
2322 SDB_UNLOCK(priv);
2323 return FALSE;
2326 SDB_GVALUE_SET_STATIC_STRING(v, relative);
2328 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2329 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
2330 "filepath",
2331 &v)) < 0)
2333 SDB_UNLOCK(priv);
2334 return FALSE;
2337 SDB_UNLOCK(priv);
2338 return TRUE;
2341 gboolean
2342 symbol_db_engine_close_db (SymbolDBEngine *dbe)
2344 SymbolDBEnginePriv *priv;
2345 gboolean ret;
2346 g_return_val_if_fail (dbe != NULL, FALSE);
2348 priv = dbe->priv;
2350 /* terminate threads, if ever they're running... */
2351 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2352 priv->thread_pool = NULL;
2353 ret = sdb_engine_disconnect_from_db (dbe);
2355 /* reset count */
2356 priv->symbols_scanned_count = 0;
2358 g_free (priv->db_directory);
2359 priv->db_directory = NULL;
2361 g_free (priv->project_directory);
2362 priv->project_directory = NULL;
2364 priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
2365 dbe, THREADS_MAX_CONCURRENT,
2366 FALSE, NULL);
2367 g_signal_emit_by_name (dbe, "db-disconnected", NULL);
2368 return ret;
2371 static gdouble
2372 sdb_engine_get_db_version (SymbolDBEngine *dbe)
2374 GdaDataModel *data_model;
2375 const GValue *value_id;
2376 gchar *query;
2377 gdouble version_id;
2378 gint col;
2380 /* set the current symbol db database version. This may help if new tables/fields
2381 * are added/removed in future versions.
2383 query = "SELECT sdb_version FROM version";
2384 if ((data_model = sdb_engine_execute_select_sql (dbe, query)) == NULL)
2386 return -1;
2389 col = gda_data_model_get_column_index(data_model, "sdb_version");
2390 value_id = gda_data_model_get_value_at (data_model, col, 0, NULL);
2392 if (G_VALUE_HOLDS_DOUBLE (value_id))
2393 version_id = g_value_get_double (value_id);
2394 else
2395 version_id = (gdouble)g_value_get_int (value_id);
2397 g_object_unref (data_model);
2398 /* no need to free query of course */
2400 return version_id;
2403 static gboolean
2404 sdb_engine_check_db_version_and_upgrade (SymbolDBEngine *dbe,
2405 const gchar* db_file,
2406 const gchar* cnc_string)
2408 SymbolDBEnginePriv *priv;
2409 gdouble version;
2411 priv = dbe->priv;
2413 version = sdb_engine_get_db_version (dbe);
2414 DEBUG_PRINT ("Checking db version...");
2415 if (version <= 0)
2417 /* some error occurred */
2418 g_warning ("No version of db detected. This can produce many errors.");
2419 return FALSE;
2422 /* FIXME: in the future versions, if the changes grow up, add a better
2423 * automatic upgrading system. Deleting & recreating the db is anyway
2424 * the best option to do.
2426 if (version < atof (SYMBOL_DB_VERSION))
2428 DEBUG_PRINT ("Upgrading from version %f to "SYMBOL_DB_VERSION, version);
2430 /* we need a full recreation of db. Because of the sym_kind table
2431 * which changed its data but not its fields, we must recreate the
2432 * whole database.
2435 /* 1. disconnect from current db */
2436 sdb_engine_disconnect_from_db (dbe);
2438 /* 2. remove current db file */
2439 GFile *gfile = g_file_new_for_path (db_file);
2440 if (gfile != NULL) {
2441 g_file_delete (gfile, NULL, NULL);
2442 g_object_unref (gfile);
2444 else
2446 g_warning ("Could not get the gfile");
2449 /* 3. reconnect */
2450 sdb_engine_connect_to_db (dbe, cnc_string);
2452 /* 4. create fresh new tables, indexes, triggers etc. */
2453 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2454 return TRUE;
2456 else
2458 DEBUG_PRINT ("No need to upgrade.");
2461 return FALSE;
2464 gint
2465 symbol_db_engine_open_db (SymbolDBEngine * dbe, const gchar * base_db_path,
2466 const gchar * prj_directory)
2468 SymbolDBEnginePriv *priv;
2469 gboolean needs_tables_creation = FALSE;
2470 gchar *cnc_string;
2471 gboolean connect_res;
2472 gboolean ret_status = DB_OPEN_STATUS_NORMAL;
2474 DEBUG_PRINT ("Opening project %s with base dir %s",
2475 prj_directory, base_db_path);
2477 g_return_val_if_fail (dbe != NULL, FALSE);
2478 g_return_val_if_fail (base_db_path != NULL, FALSE);
2480 priv = dbe->priv;
2482 priv->symbols_scanned_count = 0;
2484 /* check whether the db filename already exists. If it's not the case
2485 * create the tables for the database. */
2486 gchar *db_file = g_strdup_printf ("%s/%s.db", base_db_path,
2487 priv->anjuta_db_file);
2489 if (g_file_test (db_file, G_FILE_TEST_EXISTS) == FALSE)
2491 needs_tables_creation = TRUE;
2494 priv->db_directory = g_strdup (base_db_path);
2496 /* save the project_directory */
2497 priv->project_directory = g_strdup (prj_directory);
2499 cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", base_db_path,
2500 priv->anjuta_db_file);
2501 DEBUG_PRINT ("Connecting to "
2502 "database with %s...", cnc_string);
2503 connect_res = sdb_engine_connect_to_db (dbe, cnc_string);
2506 if (connect_res == FALSE)
2508 g_free (db_file);
2509 g_free (cnc_string);
2511 ret_status = DB_OPEN_STATUS_FATAL;
2512 return ret_status;
2515 if (needs_tables_creation == TRUE)
2517 DEBUG_PRINT ("Creating tables...");
2518 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2519 ret_status = DB_OPEN_STATUS_CREATE;
2521 else
2523 /* check the version of the db. If it's old we should upgrade it */
2524 if (sdb_engine_check_db_version_and_upgrade (dbe, db_file, cnc_string) == TRUE)
2526 ret_status = DB_OPEN_STATUS_UPGRADE;
2530 sdb_engine_set_defaults_db_parameters (dbe);
2532 g_free (cnc_string);
2533 g_free (db_file);
2535 return ret_status;
2538 gchar *
2539 symbol_db_engine_get_cnc_string (SymbolDBEngine * dbe)
2541 SymbolDBEnginePriv *priv;
2543 g_return_val_if_fail (dbe != NULL, FALSE);
2544 priv = dbe->priv;
2546 return g_strdup (priv->cnc_string);
2549 /* ~~~ Thread note: this function locks the mutex ~~~ */
2550 gboolean
2551 symbol_db_engine_add_new_workspace (SymbolDBEngine * dbe,
2552 const gchar * workspace_name)
2554 const GdaSet *plist;
2555 const GdaStatement *stmt;
2556 GdaHolder *param;
2557 SymbolDBEnginePriv *priv;
2558 GValue v = {0};
2560 g_return_val_if_fail (dbe != NULL, FALSE);
2561 priv = dbe->priv;
2563 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2565 SDB_LOCK(priv);
2567 if ((stmt =
2568 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_WORKSPACE_NEW)) == NULL)
2570 g_warning ("query is null");
2571 SDB_UNLOCK(priv);
2572 return FALSE;
2575 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_WORKSPACE_NEW);
2577 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
2579 g_warning ("param is NULL from pquery!\n");
2580 SDB_UNLOCK(priv);
2581 return FALSE;
2583 SDB_PARAM_SET_STRING(param, workspace_name);
2585 /* execute the query with parametes just set */
2586 if (gda_connection_statement_execute_non_select (priv->db_connection,
2587 (GdaStatement*)stmt,
2588 (GdaSet*)plist, NULL, NULL) == -1)
2590 SDB_UNLOCK(priv);
2591 return FALSE;
2594 SDB_UNLOCK(priv);
2595 return TRUE;
2598 /* ~~~ Thread note: this function locks the mutex ~~~ */
2599 gboolean
2600 symbol_db_engine_project_exists (SymbolDBEngine * dbe, /*gchar* workspace, */
2601 const gchar * project_name)
2603 SymbolDBEnginePriv *priv;
2604 gint prj_id;
2605 GValue v = {0};
2607 priv = dbe->priv;
2609 SDB_LOCK(priv);
2611 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2612 SDB_GVALUE_SET_STATIC_STRING(v, project_name);
2614 /* test the existence of the project in db */
2615 if ((prj_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2616 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME,
2617 "prjname",
2618 &v)) <= 0)
2620 SDB_UNLOCK(priv);
2621 return FALSE;
2624 SDB_UNLOCK(priv);
2625 /* we found it */
2626 return TRUE;
2629 /* ~~~ Thread note: this function locks the mutex ~~~ */
2630 gboolean
2631 symbol_db_engine_add_new_project (SymbolDBEngine * dbe, const gchar * workspace,
2632 const gchar * project)
2634 const GdaSet *plist;
2635 const GdaStatement *stmt;
2636 GdaHolder *param;
2637 const gchar *workspace_name;
2638 gint wks_id;
2639 SymbolDBEnginePriv *priv;
2640 GValue v = {0};
2642 g_return_val_if_fail (dbe != NULL, FALSE);
2643 priv = dbe->priv;
2645 SDB_LOCK(priv);
2647 if (workspace == NULL)
2649 workspace_name = "anjuta_workspace_default";
2651 DEBUG_PRINT ("adding default workspace... '%s'", workspace_name);
2652 SDB_GVALUE_SET_STATIC_STRING(v, workspace_name);
2654 if ((wks_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2655 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
2656 "wsname",
2657 &v)) <= 0)
2660 /* symbol_db_engine_add_new_workspace 'll lock so unlock here before */
2661 SDB_UNLOCK(priv);
2663 if (symbol_db_engine_add_new_workspace (dbe, workspace_name) == FALSE)
2665 DEBUG_PRINT ("%s", "Project cannot be added because a default workspace "
2666 "cannot be created");
2667 return FALSE;
2669 /* relock */
2670 SDB_LOCK(priv);
2673 else
2675 workspace_name = workspace;
2678 g_value_unset (&v);
2680 /* insert new project */
2681 if ((stmt =
2682 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_PROJECT_NEW)) == NULL)
2684 g_warning ("query is null");
2685 SDB_UNLOCK(priv);
2686 return FALSE;
2689 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_PROJECT_NEW);
2691 /* lookup parameters */
2692 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
2694 g_warning ("param prjname is NULL from pquery!");
2695 SDB_UNLOCK(priv);
2696 return FALSE;
2699 SDB_PARAM_SET_STRING(param, project);
2701 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
2703 g_warning ("param wsname is NULL from pquery!");
2704 SDB_UNLOCK(priv);
2705 return FALSE;
2708 SDB_PARAM_SET_STRING(param, workspace_name);
2710 /* execute the query with parametes just set */
2711 if (gda_connection_statement_execute_non_select (priv->db_connection,
2712 (GdaStatement*)stmt,
2713 (GdaSet*)plist, NULL, NULL) == -1)
2715 SDB_UNLOCK(priv);
2716 return FALSE;
2719 SDB_UNLOCK(priv);
2720 return TRUE;
2723 /* ### Thread note: this function inherits the mutex lock ### */
2724 /* Uses cache lookup to speed up symbols search. */
2725 static gint
2726 sdb_engine_add_new_language (SymbolDBEngine * dbe, const gchar *language)
2728 gint table_id;
2729 SymbolDBEnginePriv *priv;
2730 GValue v = {0};
2732 g_return_val_if_fail (language != NULL, -1);
2734 priv = dbe->priv;
2736 /* cache lookup */
2737 table_id = sdb_engine_cache_lookup (priv->language_cache, language);
2738 if (table_id != -1)
2740 return table_id;
2743 SDB_GVALUE_SET_STATIC_STRING (v, language);
2745 /* check for an already existing table with language "name". */
2746 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2747 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
2748 "langname",
2749 &v)) < 0)
2751 /* insert a new entry on db */
2752 const GdaSet *plist;
2753 const GdaStatement *stmt;
2754 GdaHolder *param;
2755 GdaSet *last_inserted = NULL;
2757 g_value_unset (&v);
2759 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_LANGUAGE_NEW))
2760 == NULL)
2762 g_warning ("query is null");
2763 return FALSE;
2766 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_LANGUAGE_NEW);
2768 if ((param = gda_set_get_holder ((GdaSet*)plist, "langname")) == NULL)
2770 g_warning ("param langname is NULL from pquery!");
2771 return FALSE;
2774 SDB_PARAM_SET_STRING(param, language);
2776 /* execute the query with parametes just set */
2777 if (gda_connection_statement_execute_non_select (priv->db_connection,
2778 (GdaStatement*)stmt,
2779 (GdaSet*)plist, &last_inserted,
2780 NULL) == -1)
2782 table_id = -1;
2784 else {
2785 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
2786 table_id = g_value_get_int (value);
2787 sdb_engine_insert_cache (priv->language_cache, language, table_id);
2790 if (last_inserted)
2791 g_object_unref (last_inserted);
2794 return table_id;
2798 * ~~~ Thread note: this function locks the mutex ~~~
2800 * Add a file to project.
2801 * This function requires an opened db, i.e. calling before
2802 * symbol_db_engine_open_db ()
2803 * filepath: referes to a full file path.
2804 * project:
2805 * WARNING: we suppose that project_directory is already set.
2806 * WARNING2: we suppose that the given local_filepath include the project_directory path.
2807 * + correct example: local_filepath: /home/user/projects/foo_project/src/main.c
2808 * project_directory: /home/user/projects/foo_project
2809 * - wrong one: local_filepath: /tmp/foo.c
2810 * project_directory: /home/user/projects/foo_project
2812 static gboolean
2813 sdb_engine_add_new_db_file (SymbolDBEngine * dbe, const gchar * project_name,
2814 const gchar * local_filepath, const gchar * language)
2816 const GdaSet *plist;
2817 const GdaStatement *stmt;
2818 GdaHolder *param;
2819 GError * error = NULL;
2820 SymbolDBEnginePriv *priv;
2821 gint language_id;
2822 GValue v = {0};
2824 priv = dbe->priv;
2826 /* check if the file is a correct one compared to the local_filepath */
2827 if (strstr (local_filepath, priv->project_directory) == NULL)
2828 return FALSE;
2830 SDB_LOCK(priv);
2832 /* we're gonna set the file relative to the project folder, not the full one.
2833 * e.g.: we have a file on disk: "/tmp/foo/src/file.c" and a db_directory located on
2834 * "/tmp/foo/". The entry on db will be "src/file.c"
2836 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, local_filepath);
2837 if (relative_path == NULL)
2839 DEBUG_PRINT ("%s", "relative_path == NULL");
2840 SDB_UNLOCK(priv);
2841 return FALSE;
2844 /* insert a new entry on db */
2845 language_id = sdb_engine_add_new_language (dbe, language);
2847 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_FILE_NEW))
2848 == NULL)
2850 g_warning ("query is null");
2851 SDB_UNLOCK(priv);
2852 return FALSE;
2855 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_FILE_NEW);
2857 /* filepath parameter */
2858 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
2860 g_warning ("param langname is NULL from pquery!");
2861 SDB_UNLOCK(priv);
2862 return FALSE;
2865 SDB_PARAM_SET_STRING(param, relative_path);
2867 /* project name parameter */
2868 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
2870 g_warning ("param prjname is NULL from pquery!");
2871 SDB_UNLOCK(priv);
2872 return FALSE;
2875 SDB_PARAM_SET_STRING(param, project_name);
2877 /* language id parameter */
2878 if ((param = gda_set_get_holder ((GdaSet*)plist, "langid")) == NULL)
2880 g_warning ("param langid is NULL from pquery!");
2881 SDB_UNLOCK(priv);
2882 return FALSE;
2885 SDB_PARAM_SET_INT(param, language_id);
2887 /* execute the query with parametes just set */
2888 if (gda_connection_statement_execute_non_select (priv->db_connection,
2889 (GdaStatement*)stmt,
2890 (GdaSet*)plist, NULL,
2891 &error) == -1)
2893 if (error)
2895 gchar * sql_str = gda_statement_to_sql_extended ((GdaStatement*)stmt,
2896 priv->db_connection, (GdaSet*)plist, 0, NULL, NULL);
2898 g_warning ("%s [%s]", error->message, sql_str);
2899 g_error_free (error);
2900 g_free (sql_str);
2903 SDB_UNLOCK(priv);
2904 return FALSE;
2907 SDB_UNLOCK(priv);
2908 return TRUE;
2911 /* ~~~ Thread note: this function locks the mutex ~~~ */
2912 static gint
2913 sdb_engine_get_unique_scan_id (SymbolDBEngine * dbe)
2915 SymbolDBEnginePriv *priv;
2916 gint ret_id;
2918 priv = dbe->priv;
2920 SDB_LOCK(priv);
2922 priv->scan_process_id++;
2923 ret_id = priv->scan_process_id;
2925 /* add the current scan_process id into a queue */
2926 g_async_queue_push (priv->scan_process_id_queue,
2927 GINT_TO_POINTER(priv->scan_process_id));
2929 SDB_UNLOCK(priv);
2930 return ret_id;
2933 gint
2934 symbol_db_engine_add_new_files (SymbolDBEngine *dbe,
2935 IAnjutaLanguage* lang_manager,
2936 const gchar * project_name,
2937 const GPtrArray *sources_array)
2939 SymbolDBEnginePriv *priv;
2940 GPtrArray *lang_array;
2941 gint i;
2943 g_return_val_if_fail (dbe != NULL, FALSE);
2944 g_return_val_if_fail (lang_manager != NULL, FALSE);
2945 g_return_val_if_fail (sources_array != NULL, FALSE);
2947 priv = dbe->priv;
2949 lang_array = g_ptr_array_new ();
2951 for (i = 0; i < sources_array->len; i++)
2953 IAnjutaLanguageId lang_id;
2954 GFile *gfile;
2955 GFileInfo *gfile_info;
2956 const gchar *file_mime;
2957 const gchar *lang;
2958 const gchar *local_filename;
2960 local_filename = g_ptr_array_index (sources_array, i);
2961 gfile = g_file_new_for_path (local_filename);
2962 gfile_info = g_file_query_info (gfile,
2963 "standard::content-type",
2964 G_FILE_QUERY_INFO_NONE,
2965 NULL,
2966 NULL);
2967 if (gfile_info == NULL)
2969 g_warning ("GFileInfo corresponding to %s was NULL", local_filename);
2970 g_object_unref (gfile);
2971 continue;
2974 file_mime = g_file_info_get_attribute_string (gfile_info,
2975 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
2977 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
2978 file_mime, NULL);
2980 if (!lang_id)
2982 g_warning ("Language not found for %s was NULL", local_filename);
2983 g_object_unref (gfile);
2984 g_object_unref (gfile_info);
2985 continue;
2988 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
2989 g_ptr_array_add (lang_array, g_strdup (lang));
2990 g_object_unref (gfile);
2991 g_object_unref (gfile_info);
2994 gint res = symbol_db_engine_add_new_files_full (dbe, project_name, sources_array,
2995 lang_array, TRUE);
2997 /* free resources */
2998 g_ptr_array_foreach (lang_array, (GFunc)g_free, NULL);
2999 g_ptr_array_free (lang_array, TRUE);
3001 return res;
3004 gint
3005 symbol_db_engine_add_new_files_full (SymbolDBEngine * dbe,
3006 const gchar * project_name,
3007 const GPtrArray * files_path,
3008 const GPtrArray * languages,
3009 gboolean force_scan)
3011 gint i;
3012 SymbolDBEnginePriv *priv;
3013 GPtrArray * filtered_files_path;
3014 GPtrArray * filtered_languages;
3015 gboolean ret_code;
3016 gint ret_id;
3018 g_return_val_if_fail (dbe != NULL, FALSE);
3019 g_return_val_if_fail (files_path != NULL, FALSE);
3020 g_return_val_if_fail (languages != NULL, FALSE);
3021 priv = dbe->priv;
3023 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
3024 g_return_val_if_fail (files_path->len > 0, FALSE);
3025 g_return_val_if_fail (languages->len > 0, FALSE);
3027 filtered_files_path = g_ptr_array_new ();
3028 filtered_languages = g_ptr_array_new ();
3030 for (i = 0; i < files_path->len; i++)
3032 const gchar *node_file = (const gchar *) g_ptr_array_index (files_path, i);
3033 const gchar *node_lang = (const gchar *) g_ptr_array_index (languages, i);
3035 if (force_scan == FALSE)
3037 /* test the existence of the file in db */
3038 if (symbol_db_engine_file_exists (dbe, node_file) == TRUE)
3040 /* we don't want to touch the already present file... within
3041 * its symbols
3043 continue;
3047 if (project_name != NULL &&
3048 sdb_engine_add_new_db_file (dbe, project_name, node_file,
3049 node_lang) == FALSE)
3051 g_warning ("symbol_db_engine_add_new_files (): "
3052 "Error processing file %s, db_directory %s, project_name %s, "
3053 "project_directory %s", node_file,
3054 priv->db_directory, project_name, priv->project_directory);
3055 return -1;
3058 /* note: we don't use g_strdup () here because we'll free the filtered_files_path
3059 * before returning from this function.
3061 g_ptr_array_add (filtered_files_path, (gpointer)node_file);
3064 /* perform the scan of files. It will spawn a fork() process with
3065 * AnjutaLauncher and ctags in server mode. After the ctags cmd has been
3066 * executed, the populating process'll take place.
3068 ret_code = sdb_engine_scan_files_1 (dbe, filtered_files_path, NULL, FALSE);
3070 if (ret_code == TRUE)
3071 ret_id = sdb_engine_get_unique_scan_id (dbe);
3072 else
3073 ret_id = -1;
3075 g_ptr_array_free (filtered_files_path, TRUE);
3076 return ret_id;
3081 * We'll use the GNU regular expressions instead of the glib's GRegex ones because
3082 * the latters are a wrapper of pcre (www.pcre.org) that don't implement the
3083 * \< (begin of word)) and \> (end of word) boundaries.
3084 * Since the regex used here is something complex to reproduce on GRegex
3085 * I don't see any reason to reinvent the (already) working wheel.
3086 * I didn't find a valuable replacement for \< and \> neither on
3087 * http://www.regular-expressions.info/wordboundaries.html nor elsewhere.
3088 * But if some regex geek thinks I'm wrong I'll be glad to see his solution.
3090 * @return NULL on error.
3092 #define RX_STRING "\\\".*\\\""
3093 #define RX_BRACKETEXPR "\\{.*\\}"
3094 #define RX_IDENT "[a-zA-Z_][a-zA-Z0-9_]*"
3095 #define RX_WS "[ \t\n]*"
3096 #define RX_PTR "[\\*&]?\\*?"
3097 #define RX_INITIALIZER "=(" RX_WS RX_IDENT RX_WS ")|=(" RX_WS RX_STRING RX_WS \
3098 ")|=(" RX_WS RX_BRACKETEXPR RX_WS ")" RX_WS
3099 #define RX_ARRAY RX_WS "\\[" RX_WS "[0-9]*" RX_WS "\\]" RX_WS
3101 static gchar*
3102 sdb_engine_extract_type_qualifier (const gchar *string, const gchar *expr)
3104 /* check with a regular expression for the type */
3105 regex_t re;
3106 regmatch_t pm[8]; // 7 sub expression -> 8 matches
3107 memset (&pm, -1, sizeof(pm));
3109 * this regexp catches things like:
3110 * a) std::vector<char*> exp1[124] [12], *exp2, expr;
3111 * b) QClass* expr1, expr2, expr;
3112 * c) int a,b; char r[12] = "test, argument", q[2] = { 't', 'e' }, expr;
3114 * it CAN be fooled, if you really want it, but it should
3115 * work for 99% of all situations.
3117 * QString
3118 * var;
3119 * in 2 lines does not work, because //-comments would often bring wrong results
3122 gchar *res = NULL;
3123 static char pattern[512] =
3124 "(" RX_IDENT "\\>)" /* the 'std' in example a) */
3125 "(::" RX_IDENT ")*" /* ::vector */
3126 "(" RX_WS "<[^>;]*>)?" /* <char *> */
3127 /* other variables for the same ident (string i,j,k;) */
3128 "(" RX_WS RX_PTR RX_WS RX_IDENT RX_WS "(" RX_ARRAY ")*" "(" RX_INITIALIZER ")?," RX_WS ")*"
3129 "[ \t\\*&]*"; /* check again for pointer/reference type */
3131 /* must add a 'termination' symbol to the regexp, otherwise
3132 * 'exp' would match 'expr'
3134 gchar regexp[512];
3135 g_snprintf (regexp, sizeof (regexp), "%s\\<%s\\>", pattern, expr);
3137 /* compile regular expression */
3138 int error = regcomp (&re, regexp, REG_EXTENDED) ;
3139 if (error)
3140 return NULL;
3142 /* this call to regexec finds the first match on the line */
3143 error = regexec (&re, string, 8, &pm[0], 0) ;
3145 /* while matches found */
3146 while (error == 0)
3148 /* subString found between pm.rm_so and pm.rm_eo */
3149 /* only include the ::vector part in the indentifier, if the second
3150 * subpattern matches at all
3152 int len = (pm[2].rm_so != -1 ? pm[2].rm_eo : pm[1].rm_eo) - pm[1].rm_so;
3153 if (res)
3154 free (res);
3155 res = (gchar*) g_malloc0 (len + 1);
3156 if (!res)
3158 regfree (&re);
3159 return NULL;
3161 strncpy (res, string + pm[1].rm_so, len);
3162 res[len] = '\0';
3164 /* This call to regexec finds the next match */
3165 error = regexec (&re, string + pm[0].rm_eo, 8, &pm[0], 0) ;
3166 break;
3168 regfree(&re);
3170 return res;
3173 /* ### Thread note: this function inherits the mutex lock ### */
3174 /* Uses cache lookup to speed up symbols search. */
3175 static gint
3176 sdb_engine_add_new_sym_kind (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3178 const gchar *kind_name;
3179 gint table_id;
3180 SymbolDBEnginePriv *priv;
3181 GValue v = {0};
3183 priv = dbe->priv;
3185 /* we assume that tag_entry is != NULL */
3186 kind_name = tag_entry->kind;
3188 /* no kind associated with current tag */
3189 if (kind_name == NULL)
3190 return -1;
3192 /* cache lookup */
3193 table_id = sdb_engine_cache_lookup (priv->kind_cache, kind_name);
3194 if (table_id != -1)
3196 return table_id;
3199 SDB_GVALUE_SET_STATIC_STRING (v, kind_name);
3201 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3202 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
3203 "kindname",
3204 &v)) < 0)
3206 const GdaSet *plist;
3207 const GdaStatement *stmt;
3208 GdaHolder *param;
3209 GdaSet *last_inserted = NULL;
3210 gint is_container = 0;
3211 SymType sym_type;
3212 GError * error = NULL;
3214 g_value_unset (&v);
3216 /* not found. Go on with inserting */
3217 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYM_KIND_NEW))
3218 == NULL)
3220 g_warning ("query is null");
3221 return -1;
3224 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_KIND_NEW);
3226 /* kindname parameter */
3227 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindname")) == NULL)
3229 g_warning ("param kindname is NULL from pquery!");
3230 return FALSE;
3233 SDB_PARAM_SET_STRING (param, kind_name);
3235 /* container parameter */
3236 if ((param = gda_set_get_holder ((GdaSet*)plist, "container")) == NULL)
3238 g_warning ("param container is NULL from pquery!");
3239 return FALSE;
3242 sym_type = GPOINTER_TO_SIZE (g_hash_table_lookup (priv->sym_type_conversion_hash,
3243 kind_name));
3245 if (sym_type & IANJUTA_SYMBOL_TYPE_SCOPE_CONTAINER)
3246 is_container = 1;
3248 SDB_PARAM_SET_INT (param, is_container);
3250 /* execute the query with parametes just set */
3251 if (gda_connection_statement_execute_non_select(priv->db_connection,
3252 (GdaStatement*)stmt,
3253 (GdaSet*)plist, &last_inserted,
3254 NULL) == -1)
3256 table_id = -1;
3258 else
3260 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3261 table_id = g_value_get_int (value);
3262 /* we should cache only tables which are != -1 */
3263 sdb_engine_insert_cache (priv->kind_cache, kind_name, table_id);
3265 if (last_inserted)
3266 g_object_unref (last_inserted);
3268 if (error)
3270 g_warning ("SQL error: %s", error->message);
3271 g_error_free (error);
3275 return table_id;
3278 /* ### Thread note: this function inherits the mutex lock ### */
3279 /* Uses cache lookup to speed up symbols search. */
3280 static gint
3281 sdb_engine_add_new_sym_access (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3283 const gchar *access;
3284 gint table_id;
3285 SymbolDBEnginePriv *priv;
3286 GValue v = {0};
3288 priv = dbe->priv;
3291 /* we assume that tag_entry is != NULL */
3292 if ((access = tagsField (tag_entry, "access")) == NULL)
3294 /* no access associated with current tag */
3295 return -1;
3298 /* cache lookup */
3299 table_id = sdb_engine_cache_lookup (priv->access_cache, access);
3300 if (table_id != -1)
3302 return table_id;
3305 SDB_GVALUE_SET_STATIC_STRING (v, access);
3307 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3308 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
3309 "accesskind",
3310 &v)) < 0)
3312 const GdaSet *plist;
3313 const GdaStatement *stmt;
3314 GdaHolder *param;
3315 GdaSet *last_inserted = NULL;
3317 g_value_unset (&v);
3319 /* not found. Go on with inserting */
3320 if ((stmt =
3321 sdb_engine_get_statement_by_query_id (dbe,
3322 PREP_QUERY_SYM_ACCESS_NEW)) == NULL)
3324 g_warning ("query is null");
3325 return -1;
3328 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_ACCESS_NEW);
3330 /* accesskind parameter */
3331 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskind")) == NULL)
3333 g_warning ("param accesskind is NULL from pquery!");
3334 return -1;
3337 SDB_PARAM_SET_STRING (param, access);
3339 /* execute the query with parametes just set */
3340 if (gda_connection_statement_execute_non_select (priv->db_connection,
3341 (GdaStatement*)stmt,
3342 (GdaSet*)plist, &last_inserted,
3343 NULL) == -1)
3345 table_id = -1;
3347 else
3349 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3350 table_id = g_value_get_int (value);
3351 /* we should cache only tables which are != -1 */
3352 sdb_engine_insert_cache (priv->access_cache, access, table_id);
3355 if (last_inserted)
3356 g_object_unref (last_inserted);
3359 return table_id;
3362 /* ### Thread note: this function inherits the mutex lock ### */
3363 /* Uses cache lookup to speed up symbols search. */
3364 static gint
3365 sdb_engine_add_new_sym_implementation (SymbolDBEngine * dbe,
3366 const tagEntry * tag_entry)
3368 const gchar *implementation;
3369 gint table_id;
3370 SymbolDBEnginePriv *priv;
3371 GValue v = {0};
3373 priv = dbe->priv;
3375 /* we assume that tag_entry is != NULL */
3376 if ((implementation = tagsField (tag_entry, "implementation")) == NULL)
3378 /* no implementation associated with current tag */
3379 return -1;
3382 /* cache lookup */
3383 table_id = sdb_engine_cache_lookup (priv->implementation_cache, implementation);
3384 if (table_id != -1)
3386 return table_id;
3389 SDB_GVALUE_SET_STATIC_STRING(v, implementation);
3391 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3392 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
3393 "implekind",
3394 &v)) < 0)
3396 const GdaSet *plist;
3397 const GdaStatement *stmt;
3398 GdaHolder *param;
3399 GdaSet *last_inserted = NULL;
3401 g_value_unset (&v);
3403 /* not found. Go on with inserting */
3404 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
3405 PREP_QUERY_SYM_IMPLEMENTATION_NEW)) ==
3406 NULL)
3408 g_warning ("query is null");
3409 return -1;
3412 plist = sdb_engine_get_query_parameters_list (dbe,
3413 PREP_QUERY_SYM_IMPLEMENTATION_NEW);
3415 /* implekind parameter */
3416 if ((param = gda_set_get_holder ((GdaSet*)plist, "implekind")) == NULL)
3418 g_warning ("param accesskind is NULL from pquery!");
3419 return -1;
3422 SDB_PARAM_SET_STRING(param, implementation);
3424 /* execute the query with parametes just set */
3425 if (gda_connection_statement_execute_non_select (priv->db_connection,
3426 (GdaStatement*)stmt,
3427 (GdaSet*)plist, &last_inserted,
3428 NULL) == -1)
3430 table_id = -1;
3432 else
3434 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3435 table_id = g_value_get_int (value);
3436 /* we should cache only tables which are != -1 */
3437 sdb_engine_insert_cache (priv->implementation_cache, implementation,
3438 table_id);
3440 if (last_inserted)
3441 g_object_unref (last_inserted);
3444 return table_id;
3447 /* ### Thread note: this function inherits the mutex lock ### */
3448 static void
3449 sdb_engine_add_new_heritage (SymbolDBEngine * dbe, gint base_symbol_id,
3450 gint derived_symbol_id)
3452 const GdaSet *plist;
3453 const GdaStatement *stmt;
3454 GdaHolder *param;
3455 SymbolDBEnginePriv *priv;
3456 GValue v = {0};
3458 g_return_if_fail (base_symbol_id > 0);
3459 g_return_if_fail (derived_symbol_id > 0);
3461 priv = dbe->priv;
3463 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_HERITAGE_NEW))
3464 == NULL)
3466 g_warning ("query is null");
3467 return;
3470 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_HERITAGE_NEW);
3472 /* symbase parameter */
3473 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbase")) == NULL)
3475 g_warning ("param accesskind is NULL from pquery!");
3476 return;
3479 SDB_PARAM_SET_INT(param, base_symbol_id);
3481 /* symderived id parameter */
3482 if ((param = gda_set_get_holder ((GdaSet*)plist, "symderived")) == NULL)
3484 g_warning ("param symderived is NULL from pquery!");
3485 return;
3488 SDB_PARAM_SET_INT(param, derived_symbol_id);
3490 /* execute the query with parametes just set */
3491 if (gda_connection_statement_execute_non_select (priv->db_connection,
3492 (GdaStatement*)stmt,
3493 (GdaSet*)plist, NULL,
3494 NULL) == -1)
3496 g_warning ("Error adding heritage");
3501 /* ### Thread note: this function inherits the mutex lock ### */
3502 static GNUC_INLINE gint
3503 sdb_engine_add_new_scope_definition (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3505 const gchar *scope;
3506 gint table_id;
3507 const GdaSet *plist;
3508 const GdaStatement *stmt;
3509 GdaHolder *param;
3510 GdaSet *last_inserted = NULL;
3511 SymbolDBEnginePriv *priv;
3512 GValue v = {0};
3514 g_return_val_if_fail (tag_entry->kind != NULL, -1);
3516 priv = dbe->priv;
3519 /* This symbol will define a scope which name is tag_entry->name
3520 * For example if we get a tag MyFoo with kind "namespace", it will define
3521 * the "MyFoo" scope, which type is "namespace MyFoo"
3523 scope = tag_entry->name;
3525 /* filter out 'variable' and 'member' kinds. They define no scope. */
3526 if (g_strcmp0 (tag_entry->kind, "variable") == 0 ||
3527 g_strcmp0 (tag_entry->kind, "member") == 0)
3529 return -1;
3532 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SCOPE_NEW))
3533 == NULL)
3535 g_warning ("query is null");
3536 return -1;
3539 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SCOPE_NEW);
3541 /* scope parameter */
3542 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
3544 g_warning ("param scope is NULL from pquery!");
3545 return -1;
3548 SDB_PARAM_SET_STRING (param, scope);
3550 /* execute the query with parameters just set */
3551 if (gda_connection_statement_execute_non_select (priv->db_connection,
3552 (GdaStatement*)stmt,
3553 (GdaSet*)plist, &last_inserted,
3554 NULL) == -1)
3556 table_id = -1;
3558 else
3560 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3561 table_id = g_value_get_int (value);
3564 if (last_inserted)
3565 g_object_unref (last_inserted);
3567 return table_id;
3571 * ### Thread note: this function inherits the mutex lock ###
3573 * Saves the tagEntry info for a second pass parsing.
3574 * Usually we don't know all the symbol at the first scan of the tags. We need
3575 * a second one.
3578 static GNUC_INLINE void
3579 sdb_engine_add_new_tmp_heritage_scope (SymbolDBEngine * dbe,
3580 const tagEntry * tag_entry,
3581 gint symbol_referer_id)
3583 SymbolDBEnginePriv *priv;
3584 const gchar *field_inherits, *field_struct, *field_typeref,
3585 *field_enum, *field_union, *field_class, *field_namespace;
3586 TableMapTmpHeritage * node;
3588 priv = dbe->priv;
3590 node = g_slice_new0 (TableMapTmpHeritage);
3591 node->symbol_referer_id = symbol_referer_id;
3593 if ((field_inherits = tagsField (tag_entry, "inherits")) != NULL)
3595 node->field_inherits = g_strdup (field_inherits);
3598 if ((field_struct = tagsField (tag_entry, "struct")) != NULL)
3600 node->field_struct = g_strdup (field_struct);
3603 if ((field_typeref = tagsField (tag_entry, "typeref")) != NULL)
3605 node->field_typeref = g_strdup (field_typeref);
3608 if ((field_enum = tagsField (tag_entry, "enum")) != NULL)
3610 node->field_enum = g_strdup (field_enum);
3613 if ((field_union = tagsField (tag_entry, "union")) != NULL)
3615 node->field_union = g_strdup (field_union);
3618 if ((field_class = tagsField (tag_entry, "class")) != NULL)
3620 node->field_class = g_strdup (field_class);
3623 if ((field_namespace = tagsField (tag_entry, "namespace")) != NULL)
3625 node->field_namespace = g_strdup (field_namespace);
3628 g_queue_push_head (priv->tmp_heritage_tablemap, node);
3631 /**
3632 * ### Thread note: this function inherits the mutex lock ###
3634 * Return the symbol_id of the changed symbol
3636 static GNUC_INLINE void
3637 sdb_engine_second_pass_update_scope_1 (SymbolDBEngine * dbe,
3638 TableMapTmpHeritage * node,
3639 gchar * token_name,
3640 const gchar * token_value)
3642 gint symbol_referer_id;
3643 const gchar *tmp_str;
3644 gchar **tmp_str_splitted;
3645 gint tmp_str_splitted_length;
3646 gchar *object_name = NULL;
3647 gboolean free_token_name = FALSE;
3648 const GdaSet *plist;
3649 const GdaStatement *stmt;
3650 GdaHolder *param;
3651 SymbolDBEnginePriv *priv;
3652 GValue v = {0};
3654 g_return_if_fail (token_value != NULL);
3656 priv = dbe->priv;
3657 tmp_str = token_value;
3659 /* we don't need empty strings */
3660 if (strlen (tmp_str) <= 0)
3662 return;
3665 /* we could have something like "First::Second::Third::Fourth" as tmp_str, so
3666 * take only the lastscope, in this case 'Fourth'.
3668 tmp_str_splitted = g_strsplit (tmp_str, ":", 0);
3669 tmp_str_splitted_length = g_strv_length (tmp_str_splitted);
3671 if (tmp_str_splitted_length > 0)
3673 /* handle special typedef case. Usually we have something like struct:my_foo.
3674 * splitting we have [0]-> struct [1]-> my_foo
3676 if (g_strcmp0 (token_name, "typedef") == 0)
3678 free_token_name = TRUE;
3679 token_name = g_strdup (tmp_str_splitted[0]);
3682 object_name = g_strdup (tmp_str_splitted[tmp_str_splitted_length - 1]);
3684 else
3686 g_strfreev (tmp_str_splitted);
3687 return;
3690 g_strfreev (tmp_str_splitted);
3692 /* if we reach this point we should have a good scope_id.
3693 * Go on with symbol updating.
3695 symbol_referer_id = node->symbol_referer_id;
3697 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
3698 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID))
3699 == NULL)
3701 g_warning ("query is null");
3702 return;
3705 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID);
3707 /* tokenname parameter */
3708 if ((param = gda_set_get_holder ((GdaSet*)plist, "tokenname")) == NULL)
3710 g_warning ("param tokenname is NULL from pquery!");
3711 return;
3714 SDB_PARAM_SET_STRING(param, token_name);
3716 /* objectname parameter */
3717 if ((param = gda_set_get_holder ((GdaSet*)plist, "objectname")) == NULL)
3719 g_warning ("param objectname is NULL from pquery!");
3720 return;
3723 SDB_PARAM_SET_STRING(param, object_name);
3725 /* symbolid parameter */
3726 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
3728 g_warning ("param symbolid is NULL from pquery!");
3729 return;
3732 SDB_PARAM_SET_INT(param, symbol_referer_id);
3734 /* execute the query with parametes just set */
3735 gda_connection_statement_execute_non_select (priv->db_connection,
3736 (GdaStatement*)stmt,
3737 (GdaSet*)plist, NULL,
3738 NULL);
3740 if (free_token_name)
3741 g_free (token_name);
3743 return;
3747 * ### Thread note: this function inherits the mutex lock ###
3749 * @param data Must be filled with some values. It must have num_rows > 0
3750 * @note *CALL THIS BEFORE second_pass_update_heritage ()*
3751 * @note *DO NOT FREE data* inside this function.
3753 static void
3754 sdb_engine_second_pass_update_scope (SymbolDBEngine * dbe)
3756 SymbolDBEnginePriv *priv;
3758 * Fill up the scope.
3759 * The case: "my_foo_func_1" is the name of the current tag parsed.
3760 * Suppose we have a namespace MyFooNamespace, under which is declared
3761 * a class MyFooClass. Under that class there are some funcs like
3762 * my_foo_func_1 () etc. ctags will present us this info about
3763 * my_foo_func_1 ():
3764 * "class : MyFooNamespace::MyFooClass"
3765 * but hey! We don't need to know the namespace here, we just want to
3766 * know that my_foo_func_1 is in the scope of MyFooClass. That one will
3767 * then be mapped inside MyFooNamespace, but that's another thing.
3768 * Go on with the parsing then.
3770 gint i;
3771 gsize queue_length;
3773 priv = dbe->priv;
3775 DEBUG_PRINT ("Processing %d rows", g_queue_get_length (priv->tmp_heritage_tablemap));
3777 /* get a fixed length. There may be some tail_pushes during this loop */
3778 queue_length = g_queue_get_length (priv->tmp_heritage_tablemap);
3780 for (i = 0; i < queue_length; i++)
3782 TableMapTmpHeritage *node;
3783 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
3785 if (node->field_class != NULL)
3787 sdb_engine_second_pass_update_scope_1 (dbe, node, "class", node->field_class);
3790 if (node->field_struct != NULL)
3792 sdb_engine_second_pass_update_scope_1 (dbe, node, "struct", node->field_struct);
3795 if (node->field_typeref != NULL)
3797 /* this is a "typedef", not a "typeref". */
3798 sdb_engine_second_pass_update_scope_1 (dbe, node, "typedef", node->field_typeref);
3801 if (node->field_enum != NULL)
3803 sdb_engine_second_pass_update_scope_1 (dbe, node, "enum", node->field_enum);
3806 if (node->field_union != NULL)
3808 sdb_engine_second_pass_update_scope_1 (dbe, node, "union", node->field_union);
3811 if (node->field_namespace != NULL)
3813 sdb_engine_second_pass_update_scope_1 (dbe, node, "namespace", node->field_namespace);
3816 /* last check: if inherits is not null keep the node for a later task */
3817 if (node->field_inherits != NULL)
3819 g_queue_push_tail (priv->tmp_heritage_tablemap, node);
3821 else
3823 sdb_engine_tablemap_tmp_heritage_destroy (node);
3830 * ### Thread note: this function inherits the mutex lock ###
3832 * @param data Must be filled with some values. It must have num_rows > 0
3833 * @note *CALL THIS AFTER second_pass_update_scope ()*
3835 static void
3836 sdb_engine_second_pass_update_heritage (SymbolDBEngine * dbe)
3838 #if 0
3839 gint i;
3840 SymbolDBEnginePriv *priv;
3842 g_return_if_fail (dbe != NULL);
3844 priv = dbe->priv;
3846 DEBUG_PRINT ("Updating heritage... (%d) elements",
3847 g_queue_get_length (priv->tmp_heritage_tablemap));
3849 for (i = 0; i < g_queue_get_length (priv->tmp_heritage_tablemap); i++)
3851 const gchar *inherits;
3852 gchar *item;
3853 gchar **inherits_list;
3854 gint j;
3855 TableMapTmpHeritage *node;
3857 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
3858 inherits = node->field_inherits;
3860 if (inherits == NULL)
3862 g_warning ("Inherits was NULL on sym_referer id %d",
3863 node->symbol_referer_id);
3864 sdb_engine_tablemap_tmp_heritage_destroy (node);
3865 continue;
3868 /* there can be multiple inheritance. Check that. */
3869 inherits_list = g_strsplit (inherits, ",", 0);
3871 if (inherits_list != NULL)
3872 DEBUG_PRINT ("inherits %s", inherits);
3874 /* retrieve as much info as we can from the items */
3875 for (j = 0; j < g_strv_length (inherits_list); j++)
3877 gchar **namespaces;
3878 gchar *klass_name;
3879 gchar *namespace_name;
3880 gint namespaces_length;
3881 gint base_klass_id;
3882 gint derived_klass_id;
3884 item = inherits_list[j];
3885 DEBUG_PRINT ("heritage %s", item);
3887 /* A item may have this string form:
3888 * MyFooNamespace1::MyFooNamespace2::MyFooClass
3889 * We should find the field 'MyFooNamespace2' because it's the one
3890 * that is reachable by the scope_id value of the symbol.
3893 namespaces = g_strsplit (item, "::", 0);
3894 namespaces_length = g_strv_length (namespaces);
3896 if (namespaces_length > 1)
3898 /* this is the case in which we have the case with
3899 * namespace + class
3901 namespace_name = g_strdup (namespaces[namespaces_length - 2]);
3902 klass_name = g_strdup (namespaces[namespaces_length - 1]);
3904 else
3906 /* have a last check before setting namespace_name to null.
3907 * check whether the field_namespace is void or not.
3909 const gchar *tmp_namespace;
3910 gchar **tmp_namespace_array = NULL;
3911 gint tmp_namespace_length;
3913 tmp_namespace = node->field_namespace;
3914 if (tmp_namespace != NULL)
3916 tmp_namespace_array = g_strsplit (tmp_namespace, "::", 0);
3917 tmp_namespace_length = g_strv_length (tmp_namespace_array);
3919 if (tmp_namespace_length > 0)
3921 namespace_name =
3922 g_strdup (tmp_namespace_array
3923 [tmp_namespace_length - 1]);
3925 else
3927 namespace_name = NULL;
3930 else
3932 namespace_name = NULL;
3935 klass_name = g_strdup (namespaces[namespaces_length - 1]);
3937 g_strfreev (tmp_namespace_array);
3940 g_strfreev (namespaces);
3942 /* get the derived_klass_id. It should be the
3943 * symbol_referer_id field into __tmp_heritage_scope table
3945 if (node->symbol_referer_id > 0)
3947 derived_klass_id = node->symbol_referer_id;
3949 else
3951 derived_klass_id = 0;
3954 /* ok, search for the symbol_id of the base class */
3955 if (namespace_name == NULL)
3957 GValue *value1;
3959 MP_LEND_OBJ_STR (priv, value1);
3960 g_value_set_static_string (value1, klass_name);
3962 if ((base_klass_id =
3963 sdb_engine_get_tuple_id_by_unique_name (dbe,
3964 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
3965 "klassname",
3966 value1)) < 0)
3968 continue;
3971 else
3973 GValue *value1;
3974 GValue *value2;
3976 MP_LEND_OBJ_STR (priv, value1);
3977 g_value_set_static_string (value1, klass_name);
3979 MP_LEND_OBJ_STR (priv, value2);
3980 g_value_set_static_string (value2, namespace_name);
3982 if ((base_klass_id =
3983 sdb_engine_get_tuple_id_by_unique_name2 (dbe,
3984 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
3985 "klassname",
3986 value1,
3987 "namespacename",
3988 value2)) < 0)
3990 continue;
3994 g_free (namespace_name);
3995 g_free (klass_name);
3997 DEBUG_PRINT ("gonna sdb_engine_add_new_heritage with "
3998 "base_klass_id %d, derived_klass_id %d", base_klass_id,
3999 derived_klass_id);
4000 sdb_engine_add_new_heritage (dbe, base_klass_id, derived_klass_id);
4003 g_strfreev (inherits_list);
4005 #endif
4009 * ### Thread note: this function inherits the mutex lock ###
4011 * Process the temporary table to update the symbols on scope and inheritance
4012 * fields.
4013 * *CALL THIS FUNCTION ONLY AFTER HAVING PARSED ALL THE TAGS ONCE*
4016 static void
4017 sdb_engine_second_pass_do (SymbolDBEngine * dbe)
4019 SymbolDBEnginePriv *priv;
4021 priv = dbe->priv;
4023 /* prepare for scope second scan */
4024 if (g_queue_get_length (priv->tmp_heritage_tablemap) > 0)
4026 sdb_engine_second_pass_update_scope (dbe);
4027 sdb_engine_second_pass_update_heritage (dbe);
4031 GNUC_INLINE static void
4032 sdb_engine_add_new_symbol_case_1 (SymbolDBEngine *dbe,
4033 gint symbol_id,
4034 GdaSet **plist_ptr,
4035 GdaStatement **stmt_ptr)
4037 GdaHolder *param;
4038 GValue v = {0};
4040 const GdaSet * plist = *plist_ptr;
4041 const GdaStatement * stmt = *stmt_ptr;
4043 /* case 1 */
4045 /* create specific query for a fresh new symbol */
4046 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4047 PREP_QUERY_UPDATE_SYMBOL_ALL))
4048 == NULL)
4050 g_warning ("query is null");
4051 return;
4054 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_ALL);
4056 /* symbolid parameter */
4057 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4059 g_warning ("param isfilescope is NULL from pquery!");
4060 return;
4063 SDB_PARAM_SET_INT(param, symbol_id);
4065 *plist_ptr = (GdaSet*)plist;
4066 *stmt_ptr = (GdaStatement*)stmt;
4069 GNUC_INLINE static void
4070 sdb_engine_add_new_symbol_case_2_3 (SymbolDBEngine *dbe,
4071 gint symbol_id,
4072 GdaSet **plist_ptr,
4073 GdaStatement **stmt_ptr,
4074 gint file_defined_id,
4075 const gchar *name,
4076 const gchar *type_type,
4077 const gchar *type_name)
4079 GdaHolder *param;
4080 GValue v = {0};
4082 const GdaSet * plist = *plist_ptr;
4083 const GdaStatement * stmt = *stmt_ptr;
4085 /* create specific query for a fresh new symbol */
4086 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYMBOL_NEW))
4087 == NULL)
4089 g_warning ("query is null");
4090 return;
4093 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYMBOL_NEW);
4095 /* filedefid parameter */
4096 if ((param = gda_set_get_holder ((GdaSet*)plist, "filedefid")) == NULL)
4098 g_warning ("param filedefid is NULL from pquery!");
4099 return;
4102 SDB_PARAM_SET_INT(param, file_defined_id);
4104 /* name parameter */
4105 if ((param = gda_set_get_holder ((GdaSet*)plist, "name")) == NULL)
4107 g_warning ("param name is NULL from pquery!");
4108 return;
4111 SDB_PARAM_SET_STRING(param, name);
4113 /* typetype parameter */
4114 if ((param = gda_set_get_holder ((GdaSet*)plist, "typetype")) == NULL)
4116 g_warning ("param typetype is NULL from pquery!");
4117 return;
4120 SDB_PARAM_SET_STRING(param, type_type);
4122 /* typenameparameter */
4123 if ((param = gda_set_get_holder ((GdaSet*)plist, "typename")) == NULL)
4125 g_warning ("param typename is NULL from pquery!");
4126 return;
4129 SDB_PARAM_SET_STRING(param, type_name);
4131 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
4133 g_warning ("param scope is NULL from pquery!");
4134 return;
4137 /* scope is to be considered the tag name */
4138 SDB_PARAM_SET_STRING(param, name);
4140 *plist_ptr = (GdaSet*)plist;
4141 *stmt_ptr = (GdaStatement*)stmt;
4144 GNUC_INLINE static void
4145 sdb_engine_add_new_symbol_common_params (SymbolDBEngine *dbe,
4146 const GdaSet *plist,
4147 const GdaStatement *stmt,
4148 gint file_position,
4149 gint is_file_scope,
4150 const gchar *signature,
4151 const gchar *returntype,
4152 gint scope_definition_id,
4153 gint scope_id,
4154 gint kind_id,
4155 gint access_kind_id,
4156 gint implementation_kind_id,
4157 gboolean update_flag)
4159 GdaHolder *param;
4160 GValue v = {0};
4162 /* fileposition parameter */
4163 if ((param = gda_set_get_holder ((GdaSet*)plist, "fileposition")) == NULL)
4165 g_warning ("param fileposition is NULL from pquery!");
4166 return;
4169 SDB_PARAM_SET_INT (param, file_position);
4171 /* isfilescope parameter */
4172 if ((param = gda_set_get_holder ((GdaSet*)plist, "isfilescope")) == NULL)
4174 g_warning ("param isfilescope is NULL from pquery!");
4175 return;
4178 SDB_PARAM_SET_INT (param, is_file_scope);
4180 /* signature parameter */
4181 if ((param = gda_set_get_holder ((GdaSet*)plist, "signature")) == NULL)
4183 g_warning ("param signature is NULL from pquery!");
4184 return;
4187 SDB_PARAM_SET_STRING(param, signature);
4189 /* returntype parameter */
4190 if ((param = gda_set_get_holder ((GdaSet*)plist, "returntype")) == NULL)
4192 g_warning ("param returntype is NULL from pquery!");
4193 return;
4196 SDB_PARAM_SET_STRING(param, returntype);
4198 /* scopedefinitionid parameter */
4199 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopedefinitionid")) == NULL)
4201 g_warning ("param scopedefinitionid is NULL from pquery!");
4202 return;
4205 SDB_PARAM_SET_INT(param, scope_definition_id);
4207 /* scopeid parameter */
4208 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopeid")) == NULL)
4210 g_warning ("param scopeid is NULL from pquery!");
4211 return;
4214 SDB_PARAM_SET_INT(param, scope_id);
4216 /* kindid parameter */
4217 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindid")) == NULL)
4219 g_warning ("param kindid is NULL from pquery!");
4220 return;
4223 SDB_PARAM_SET_INT(param, kind_id);
4225 /* accesskindid parameter */
4226 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskindid")) == NULL)
4228 g_warning ("param accesskindid is NULL from pquery!");
4229 return;
4232 SDB_PARAM_SET_INT(param, access_kind_id);
4234 /* implementationkindid parameter */
4235 if ((param = gda_set_get_holder ((GdaSet*)plist, "implementationkindid")) == NULL)
4237 g_warning ("param implementationkindid is NULL from pquery!");
4238 return;
4241 SDB_PARAM_SET_INT(param, implementation_kind_id);
4243 /* updateflag parameter */
4244 if ((param = gda_set_get_holder ((GdaSet*)plist, "updateflag")) == NULL)
4246 g_warning ("param updateflag is NULL from pquery!");
4247 return;
4250 SDB_PARAM_SET_INT(param, update_flag);
4255 * ### Thread note: this function inherits the mutex lock ###
4257 * base_prj_path can be NULL. In that case path info tag_entry will be taken
4258 * as an absolute path.
4259 * fake_file can be used when a buffer updating is being executed. In that
4260 * particular case both base_prj_path and tag_entry->file will be ignored.
4261 * fake_file is real_path of file on disk
4263 static gint
4264 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
4265 gint file_defined_id,
4266 gboolean sym_update)
4268 SymbolDBEnginePriv *priv;
4269 GdaSet *plist;
4270 GdaStatement *stmt;
4271 GdaSet *last_inserted = NULL;
4272 gint table_id, symbol_id;
4273 const gchar* name;
4274 gint file_position = 0;
4275 gint is_file_scope = 0;
4276 const gchar *signature;
4277 const gchar *returntype;
4278 gint scope_definition_id = 0;
4279 gint scope_id = 0;
4280 gint kind_id = 0;
4281 gint access_kind_id = 0;
4282 gint implementation_kind_id = 0;
4283 GValue v1 = {0}, v2 = {0}, v3 = {0}, v4 = {0};
4284 gboolean sym_was_updated = FALSE;
4285 gboolean update_flag;
4286 gchar *type_regex;;
4287 const gchar *type_type;
4288 const gchar *type_name;
4289 gint nrows;
4290 GError * error = NULL;
4292 g_return_val_if_fail (dbe != NULL, -1);
4293 priv = dbe->priv;
4295 /* keep it at 0 if sym_update == false */
4296 update_flag = sym_update;
4298 g_return_val_if_fail (tag_entry != NULL, -1);
4300 /* parse the entry name */
4301 name = tag_entry->name;
4302 file_position = tag_entry->address.lineNumber;
4303 is_file_scope = tag_entry->fileScope;
4306 * signature
4308 signature = tagsField (tag_entry, "signature");
4311 * return type
4313 returntype = tagsField (tag_entry, "returntype");
4316 * sym_type
4318 /* we assume that tag_entry is != NULL */
4319 type_type = tag_entry->kind;
4320 type_regex = NULL;
4322 if (g_strcmp0 (type_type, "member") == 0 ||
4323 g_strcmp0 (type_type, "variable") == 0 ||
4324 g_strcmp0 (type_type, "field") == 0)
4326 type_regex = sdb_engine_extract_type_qualifier (tag_entry->address.pattern,
4327 tag_entry->name);
4328 /*DEBUG_PRINT ("type_regex for %s [kind %s] is %s", tag_entry->name,
4329 tag_entry->kind, type_regex);*/
4330 type_name = type_regex;
4332 /* if the extractor failed we should fallback to the default one */
4333 if (type_name == NULL)
4334 type_name = tag_entry->name;
4335 } else
4337 type_name = tag_entry->name;
4342 * scope definition
4345 /* scope_definition_id tells what scope this symbol defines */
4346 scope_definition_id = sdb_engine_add_new_scope_definition (dbe, tag_entry);
4348 /* the container scopes can be: union, struct, typeref, class, namespace etc.
4349 * this field will be parsed in the second pass.
4351 scope_id = 0;
4353 kind_id = sdb_engine_add_new_sym_kind (dbe, tag_entry);
4355 access_kind_id = sdb_engine_add_new_sym_access (dbe, tag_entry);
4357 implementation_kind_id = sdb_engine_add_new_sym_implementation (dbe, tag_entry);
4359 /* ok: was the symbol updated [at least on it's type_id/name]?
4360 * There are 3 cases:
4361 * #1. The symbol remains the same [at least on unique index key]. We will
4362 * perform only a simple update.
4363 * #2. The symbol has changed: at least on name/type/file. We will insert a
4364 * new symbol on table 'symbol'. Deletion of old one will take place
4365 * at a second stage, when a delete of all symbols with
4366 * 'tmp_flag = 0' will be done.
4367 * #3. The symbol has been deleted. As above it will be deleted at
4368 * a second stage because of the 'tmp_flag = 0'. Triggers will remove
4369 * also scope_ids and other things.
4372 if (update_flag == FALSE) /* symbol is new */
4374 symbol_id = -1;
4376 else /* symbol is updated or a force_update has been given */
4378 /* We should use more value and set them with the same values because
4379 * sdb_engine_get_tuple_id_by_unique_name () will manage them
4381 SDB_GVALUE_SET_STATIC_STRING(v1, name);
4382 SDB_GVALUE_SET_INT(v2, file_defined_id);
4383 SDB_GVALUE_SET_STATIC_STRING(v3, type_type);
4384 SDB_GVALUE_SET_STATIC_STRING(v4, type_name);
4387 * We cannot live without this select because we must know whether a similar
4388 * symbol was already present in the file or not. With this information we
4389 * can see if it's been updated or newly inserted
4391 symbol_id = sdb_engine_get_tuple_id_by_unique_name4 (dbe,
4392 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
4393 "symname", &v1,
4394 "filedefid", &v2,
4395 "typetype", &v3,
4396 "typename", &v4);
4399 /* ok then, parse the symbol id value */
4400 if (symbol_id <= 0)
4402 /* case 2 and 3 */
4403 sym_was_updated = FALSE;
4404 plist = NULL;
4405 stmt = NULL;
4407 sdb_engine_add_new_symbol_case_2_3 (dbe, symbol_id, &plist, &stmt,
4408 file_defined_id, name, type_type, type_name);
4410 else
4412 /* case 1 */
4413 sym_was_updated = TRUE;
4414 plist = NULL;
4415 stmt = NULL;
4417 sdb_engine_add_new_symbol_case_1 (dbe, symbol_id, &plist, &stmt);
4420 /* common params */
4421 sdb_engine_add_new_symbol_common_params (dbe, plist, stmt,
4422 file_position, is_file_scope,
4423 signature, returntype, scope_definition_id,
4424 scope_id, kind_id,
4425 access_kind_id, implementation_kind_id,
4426 update_flag);
4428 /* execute the query with parametes just set */
4429 nrows = gda_connection_statement_execute_non_select (priv->db_connection,
4430 (GdaStatement*)stmt,
4431 (GdaSet*)plist, &last_inserted,
4432 &error);
4434 if (error)
4436 DEBUG_PRINT ("SQL parsing failed: %s", error->message);
4437 g_error_free (error);
4440 if (sym_was_updated == FALSE)
4442 if (nrows > 0)
4444 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4445 table_id = g_value_get_int (value);
4447 /* This is a wrong place to emit the symbol-updated signal. Infact
4448 * db is in a inconsistent state, e.g. inheritance references are still
4449 * *not* calculated.
4450 * So add the symbol id into a queue that will be parsed once and emitted.
4452 g_async_queue_push (priv->inserted_symbols_id, GINT_TO_POINTER(table_id));
4454 else
4456 table_id = -1;
4459 else
4461 if (nrows > 0)
4463 table_id = symbol_id;
4465 g_async_queue_push (priv->updated_symbols_id, GINT_TO_POINTER(table_id));
4467 else
4469 table_id = -1;
4473 if (last_inserted)
4474 g_object_unref (last_inserted);
4476 /* post population phase */
4478 /* before returning the table_id we have to fill some infoz on temporary tables
4479 * so that in a second pass we can parse also the heritage and scope fields.
4481 if (table_id > 0)
4482 sdb_engine_add_new_tmp_heritage_scope (dbe, tag_entry, table_id);
4484 g_free (type_regex);
4486 return table_id;
4490 * ### Thread note: this function inherits the mutex lock ###
4492 * Select * from __tmp_removed and emits removed signals.
4494 static void
4495 sdb_engine_detects_removed_ids (SymbolDBEngine *dbe)
4497 const GdaStatement *stmt1, *stmt2;
4498 GdaDataModel *data_model;
4499 SymbolDBEnginePriv *priv;
4500 gint i, num_rows;
4502 priv = dbe->priv;
4504 /* ok, now we should read from __tmp_removed all the symbol ids which have
4505 * been removed, and emit a signal
4507 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
4508 PREP_QUERY_GET_REMOVED_IDS))
4509 == NULL)
4511 g_warning ("query is null");
4512 return;
4515 data_model = gda_connection_statement_execute_select (priv->db_connection,
4516 (GdaStatement*)stmt1,
4517 NULL, NULL);
4519 if (GDA_IS_DATA_MODEL (data_model))
4521 if ((num_rows = gda_data_model_get_n_rows (data_model)) <= 0)
4523 DEBUG_PRINT ("nothing to remove");
4524 g_object_unref (data_model);
4525 return;
4528 else
4530 if (data_model != NULL)
4531 g_object_unref (data_model);
4532 return;
4535 /* get and parse the results. */
4536 for (i = 0; i < num_rows; i++)
4538 const GValue *val;
4539 gint tmp;
4540 val = gda_data_model_get_value_at (data_model, 0, i, NULL);
4541 tmp = g_value_get_int (val);
4543 g_async_queue_push (priv->signals_queue, GINT_TO_POINTER(SYMBOL_REMOVED + 1));
4544 g_async_queue_push (priv->signals_queue, GINT_TO_POINTER(tmp));
4547 g_object_unref (data_model);
4549 /* let's clean the tmp_table */
4550 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
4551 PREP_QUERY_TMP_REMOVED_DELETE_ALL))
4552 == NULL)
4554 g_warning ("query is null");
4555 return;
4558 /* bye bye */
4559 gda_connection_statement_execute_non_select (priv->db_connection,
4560 (GdaStatement*)stmt2,
4561 NULL, NULL,
4562 NULL);
4566 * ~~~ Thread note: this function locks the mutex ~~~ *
4568 * WARNING: do not use this function thinking that it would do a scan of symbols
4569 * too. Use symbol_db_engine_update_files_symbols () instead. This one will set
4570 * up some things on db, like removing the 'old' symbols which have not been
4571 * updated.
4573 static gboolean
4574 sdb_engine_update_file (SymbolDBEngine * dbe, const gchar * file_on_db)
4576 const GdaSet *plist1, *plist2, *plist3;
4577 const GdaStatement *stmt1, *stmt2, *stmt3;
4578 GdaHolder *param;
4579 SymbolDBEnginePriv *priv;
4580 GValue v = {0};
4582 priv = dbe->priv;
4584 SDB_LOCK(priv);
4586 /* if we're updating symbols we must do some other operations on db
4587 * symbols, like remove the ones which don't have an update_flag = 1
4588 * per updated file.
4591 /* good. Go on with removing of old symbols, marked by a
4592 * update_flag = 0.
4595 /* Triggers will take care of updating/deleting connected symbols
4596 * tuples, like sym_kind, sym_type etc */
4597 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
4598 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS)) == NULL)
4600 g_warning ("query is null");
4601 SDB_UNLOCK(priv);
4603 return FALSE;
4606 plist1 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS);
4608 if ((param = gda_set_get_holder ((GdaSet*)plist1, "filepath")) == NULL)
4610 g_warning ("param filepath is NULL from pquery!");
4611 SDB_UNLOCK(priv);
4612 return FALSE;
4615 SDB_PARAM_SET_STRING(param, file_on_db);
4617 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt1,
4618 (GdaSet*)plist1, NULL, NULL);
4620 /* emits removed symbols signals */
4621 sdb_engine_detects_removed_ids (dbe);
4623 /* reset the update_flag to 0 */
4624 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
4625 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS)) == NULL)
4627 g_warning ("query is null");
4628 SDB_UNLOCK(priv);
4629 return FALSE;
4632 plist2 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS);
4634 if ((param = gda_set_get_holder ((GdaSet*)plist2, "filepath")) == NULL)
4636 g_warning ("param filepath is NULL from pquery!");
4637 return FALSE;
4639 SDB_PARAM_SET_STRING(param, file_on_db);
4641 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt2,
4642 (GdaSet*)plist2, NULL, NULL);
4644 /* last but not least, update the file analyse_time */
4645 if ((stmt3 = sdb_engine_get_statement_by_query_id (dbe,
4646 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME))
4647 == NULL)
4649 g_warning ("query is null");
4650 SDB_UNLOCK(priv);
4651 return FALSE;
4654 plist3 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_FILE_ANALYSE_TIME);
4656 /* filepath parameter */
4657 if ((param = gda_set_get_holder ((GdaSet*)plist3, "filepath")) == NULL)
4659 g_warning ("param filepath is NULL from pquery!");
4660 SDB_UNLOCK(priv);
4661 return FALSE;
4664 SDB_PARAM_SET_STRING(param, file_on_db);
4666 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt3,
4667 (GdaSet*)plist3, NULL, NULL);
4669 SDB_UNLOCK(priv);
4670 return TRUE;
4674 * @param data is a GPtrArray *files_to_scan
4675 * It will be freed when this callback will be called.
4677 static void
4678 on_scan_update_files_symbols_end (SymbolDBEngine * dbe,
4679 gint process_id,
4680 UpdateFileSymbolsData* update_data)
4682 SymbolDBEnginePriv *priv;
4683 GPtrArray *files_to_scan;
4684 gint i;
4685 GValue v = {0};
4687 g_return_if_fail (dbe != NULL);
4688 g_return_if_fail (update_data != NULL);
4690 priv = dbe->priv;
4691 files_to_scan = update_data->files_path;
4693 sdb_engine_clear_caches (dbe);
4695 /* we need a reinitialization */
4696 sdb_engine_init_caches (dbe);
4698 for (i = 0; i < files_to_scan->len; i++)
4700 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
4702 if (strstr (node, priv->project_directory) == NULL)
4704 g_warning ("node %s is shorter than "
4705 "prj_directory %s",
4706 node, priv->project_directory);
4707 continue;
4710 /* clean the db from old un-updated with the last update step () */
4711 if (sdb_engine_update_file (dbe, node +
4712 strlen (priv->project_directory)) == FALSE)
4714 g_warning ("Error processing file %s", node +
4715 strlen (priv->project_directory));
4716 return;
4718 g_free (node);
4721 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_files_symbols_end,
4722 update_data);
4724 /* if true, we'll update the project scanning time too.
4725 * warning: project time scanning won't could be set before files one.
4726 * This why we'll fork the process calling sdb_engine_scan_files ()
4728 if (update_data->update_prj_analyse_time == TRUE)
4730 const GdaSet *plist;
4731 const GdaStatement *stmt;
4732 GdaHolder *param;
4734 SDB_LOCK(priv);
4735 /* and the project analyse_time */
4736 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4737 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME))
4738 == NULL)
4740 g_warning ("query is null");
4741 SDB_UNLOCK(priv);
4742 return;
4745 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME);
4747 /* prjname parameter */
4748 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
4750 g_warning ("param prjname is NULL from pquery!");
4751 SDB_UNLOCK(priv);
4752 return;
4755 SDB_PARAM_SET_STRING(param, update_data->project);
4757 gda_connection_statement_execute_non_select (priv->db_connection,
4758 (GdaStatement*)stmt,
4759 (GdaSet*)plist, NULL, NULL);
4761 SDB_UNLOCK(priv);
4764 /* free the GPtrArray. */
4765 g_ptr_array_free (files_to_scan, TRUE);
4767 g_free (update_data->project);
4768 g_free (update_data);
4771 gint
4772 symbol_db_engine_update_files_symbols (SymbolDBEngine * dbe, const gchar * project,
4773 GPtrArray * files_path,
4774 gboolean update_prj_analyse_time)
4776 SymbolDBEnginePriv *priv;
4777 UpdateFileSymbolsData *update_data;
4778 gboolean ret_code;
4779 gint ret_id;
4780 gint i;
4781 GPtrArray * ready_files;
4783 priv = dbe->priv;
4785 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
4786 g_return_val_if_fail (project != NULL, FALSE);
4788 ready_files = g_ptr_array_new ();
4790 /* check if the files exist in db before passing them to the scan procedure */
4791 for (i = 0; i < files_path->len; i++)
4793 gchar *curr_abs_file;
4795 curr_abs_file = g_ptr_array_index (files_path, i);
4796 /* check if the file exists in db. We will not scan buffers for files
4797 * which aren't already in db
4799 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
4801 DEBUG_PRINT ("will not update file symbols claiming to be %s because not in db",
4802 curr_abs_file);
4804 g_free (curr_abs_file);
4805 continue;
4808 /* ok the file exists in db. Add it to ready_files */
4809 g_ptr_array_add (ready_files, curr_abs_file);
4812 /* free just the array but not its values */
4813 g_ptr_array_free (files_path, FALSE);
4815 /* if no file has been added to the array then bail out here */
4816 if (ready_files->len <= 0)
4818 g_ptr_array_free (ready_files, TRUE);
4819 DEBUG_PRINT ("not enough files to update");
4820 return -1;
4823 update_data = g_new0 (UpdateFileSymbolsData, 1);
4825 update_data->update_prj_analyse_time = update_prj_analyse_time;
4826 update_data->files_path = ready_files;
4827 update_data->project = g_strdup (project);
4830 /* data will be freed when callback will be called. The signal will be
4831 * disconnected too, don't worry about disconneting it by hand.
4833 g_signal_connect (G_OBJECT (dbe), "scan-end",
4834 G_CALLBACK (on_scan_update_files_symbols_end), update_data);
4836 ret_code = sdb_engine_scan_files_1 (dbe, ready_files, NULL, TRUE);
4837 if (ret_code == TRUE)
4838 ret_id = sdb_engine_get_unique_scan_id (dbe);
4839 else
4840 ret_id = -1;
4842 return ret_id;
4846 * ~~~ Thread note: this function locks the mutex ~~~ *
4848 * Update symbols of the whole project. It scans all file symbols etc.
4850 gint
4851 symbol_db_engine_update_project_symbols (SymbolDBEngine *dbe,
4852 const gchar *project_name, gboolean force_all_files)
4854 const GdaSet *plist;
4855 const GdaStatement *stmt;
4856 GdaHolder *param;
4857 GdaDataModel *data_model;
4858 gint num_rows = 0;
4859 gint i;
4860 GPtrArray *files_to_scan;
4861 SymbolDBEnginePriv *priv;
4862 GValue v = {0};
4864 g_return_val_if_fail (dbe != NULL, FALSE);
4866 priv = dbe->priv;
4868 g_return_val_if_fail (project_name != NULL, FALSE);
4869 g_return_val_if_fail (priv->project_directory != NULL, FALSE);
4871 SDB_LOCK(priv);
4873 DEBUG_PRINT ("Updating project symbols (force %d)...", force_all_files);
4874 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4875 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME))
4876 == NULL)
4878 g_warning ("query is null");
4879 SDB_UNLOCK(priv);
4880 return FALSE;
4883 plist = sdb_engine_get_query_parameters_list (dbe,
4884 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME);
4886 /* prjname parameter */
4887 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
4889 g_warning ("param prjid is NULL from pquery!");
4890 SDB_UNLOCK(priv);
4891 return FALSE;
4894 SDB_PARAM_SET_STRING(param, project_name);
4896 /* execute the query with parametes just set */
4897 GType gtype_array [6] = { G_TYPE_INT,
4898 G_TYPE_STRING,
4899 G_TYPE_INT,
4900 G_TYPE_INT,
4901 GDA_TYPE_TIMESTAMP,
4902 G_TYPE_NONE
4904 data_model = gda_connection_statement_execute_select_full (priv->db_connection,
4905 (GdaStatement*)stmt,
4906 (GdaSet*)plist,
4907 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
4908 gtype_array,
4909 NULL);
4911 if (!GDA_IS_DATA_MODEL (data_model) ||
4912 (num_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model))) <= 0)
4914 if (data_model != NULL)
4915 g_object_unref (data_model);
4916 data_model = NULL;
4918 DEBUG_PRINT ("Strange enough, no files in project ->%s<- found",
4919 project_name);
4920 SDB_UNLOCK(priv);
4921 return FALSE;
4924 /* initialize the array */
4925 files_to_scan = g_ptr_array_new ();
4927 /* we can now scan each filename entry to check the last modification time. */
4928 for (i = 0; i < num_rows; i++)
4930 const GValue *value, *value1;
4931 const GdaTimestamp *timestamp;
4932 const gchar *file_name;
4933 gchar *file_abs_path = NULL;
4934 struct tm filetm;
4935 time_t db_time;
4936 GFile *gfile;
4937 GFileInfo* gfile_info;
4938 GFileInputStream* gfile_is;
4940 if ((value =
4941 gda_data_model_get_value_at (data_model,
4942 gda_data_model_get_column_index(data_model,
4943 "db_file_path"),
4944 i, NULL)) == NULL)
4946 continue;
4949 /* build abs path. */
4950 file_name = g_value_get_string (value);
4951 if (priv->project_directory != NULL)
4953 file_abs_path = g_build_filename (priv->project_directory,
4954 file_name, NULL);
4957 gfile = g_file_new_for_path (file_abs_path);
4958 if (gfile == NULL)
4959 continue;
4961 gfile_is = g_file_read (gfile, NULL, NULL);
4962 /* retrieve data/time info */
4963 if (gfile_is == NULL)
4965 g_message ("could not open path %s", file_abs_path);
4966 g_free (file_abs_path);
4967 g_object_unref (gfile);
4968 continue;
4970 g_object_unref (gfile_is);
4972 gfile_info = g_file_query_info (gfile, "*", G_FILE_QUERY_INFO_NONE,
4973 NULL, NULL);
4975 if (gfile_info == NULL)
4977 g_message ("cannot get file info from handle");
4978 g_free (file_abs_path);
4979 g_object_unref (gfile);
4980 continue;
4983 if ((value1 = gda_data_model_get_value_at (data_model,
4984 gda_data_model_get_column_index(data_model,
4985 "analyse_time"), i, NULL)) == NULL)
4987 continue;
4991 timestamp = gda_value_get_timestamp (value1);
4993 /* fill a struct tm with the date retrieved by the string. */
4994 /* string is something like '2007-04-18 23:51:39' */
4995 memset (&filetm, 0, sizeof (struct tm));
4996 filetm.tm_year = timestamp->year - 1900;
4997 filetm.tm_mon = timestamp->month - 1;
4998 filetm.tm_mday = timestamp->day;
4999 filetm.tm_hour = timestamp->hour;
5000 filetm.tm_min = timestamp->minute;
5001 filetm.tm_sec = timestamp->second;
5003 /* remove one hour to the db_file_time. */
5004 db_time = mktime (&filetm) - 3600;
5006 guint64 modified_time = g_file_info_get_attribute_uint64 (gfile_info,
5007 G_FILE_ATTRIBUTE_TIME_MODIFIED);
5008 if (difftime (db_time, modified_time) < 0 ||
5009 force_all_files == TRUE)
5011 g_ptr_array_add (files_to_scan, file_abs_path);
5014 g_object_unref (gfile_info);
5015 g_object_unref (gfile);
5016 /* no need to free file_abs_path, it's been added to files_to_scan */
5019 if (data_model)
5020 g_object_unref (data_model);
5022 if (files_to_scan->len > 0)
5024 SDB_UNLOCK(priv);
5026 /* at the end let the scanning function do its job */
5027 return symbol_db_engine_update_files_symbols (dbe, project_name,
5028 files_to_scan, TRUE);
5031 SDB_UNLOCK(priv);
5033 /* some error occurred */
5034 return -1;
5037 /* ~~~ Thread note: this function locks the mutex ~~~ */
5038 gboolean
5039 symbol_db_engine_remove_file (SymbolDBEngine * dbe, const gchar *project,
5040 const gchar *rel_file)
5042 SymbolDBEnginePriv *priv;
5043 const GdaSet *plist;
5044 const GdaStatement *stmt;
5045 GdaHolder *param;
5046 GValue v = {0};
5049 g_return_val_if_fail (dbe != NULL, FALSE);
5050 g_return_val_if_fail (project != NULL, FALSE);
5051 g_return_val_if_fail (rel_file != NULL, FALSE);
5052 priv = dbe->priv;
5054 SDB_LOCK(priv);
5056 if (strlen (rel_file) <= 0)
5058 g_warning ("wrong file to delete.");
5059 SDB_UNLOCK(priv);
5060 return FALSE;
5063 DEBUG_PRINT ("deleting from db %s", rel_file);
5065 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5066 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME)) == NULL)
5068 g_warning ("query is null");
5069 SDB_UNLOCK(priv);
5070 return FALSE;
5073 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME);
5075 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5077 g_warning ("param prjname is NULL from pquery!");
5078 SDB_UNLOCK(priv);
5079 return FALSE;
5082 SDB_PARAM_SET_STRING(param, project);
5084 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
5086 g_warning ("param filepath is NULL from pquery!");
5087 SDB_UNLOCK(priv);
5088 return FALSE;
5091 SDB_PARAM_SET_STRING(param, rel_file);
5093 /* Triggers will take care of updating/deleting connected symbols
5094 * tuples, like sym_kind, sym_type etc */
5095 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt,
5096 (GdaSet*)plist, NULL, NULL);
5098 /* emits removed symbols signals */
5099 sdb_engine_detects_removed_ids (dbe);
5101 SDB_UNLOCK(priv);
5103 return TRUE;
5106 void
5107 symbol_db_engine_remove_files (SymbolDBEngine * dbe, const gchar * project,
5108 const GPtrArray * files)
5110 SymbolDBEnginePriv *priv;
5111 gint i;
5113 g_return_if_fail (dbe != NULL);
5114 g_return_if_fail (project != NULL);
5115 g_return_if_fail (files != NULL);
5116 priv = dbe->priv;
5118 for (i = 0; i < files->len; i++)
5120 symbol_db_engine_remove_file (dbe, project, g_ptr_array_index (files, i));
5124 static void
5125 on_scan_update_buffer_end (SymbolDBEngine * dbe, gint process_id, gpointer data)
5127 SymbolDBEnginePriv *priv;
5128 GPtrArray *files_to_scan;
5129 gint i;
5131 g_return_if_fail (dbe != NULL);
5132 g_return_if_fail (data != NULL);
5134 priv = dbe->priv;
5135 files_to_scan = (GPtrArray *) data;
5137 for (i = 0; i < files_to_scan->len; i++)
5139 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5140 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, node);
5141 if (relative_path != NULL)
5143 /* will be emitted removed signals */
5144 if (sdb_engine_update_file (dbe, relative_path) == FALSE)
5146 g_warning ("Error processing file %s", node);
5147 return;
5150 g_free (node);
5153 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_buffer_end,
5154 files_to_scan);
5156 /* free the GPtrArray. */
5157 g_ptr_array_free (files_to_scan, TRUE);
5158 data = files_to_scan = NULL;
5161 gint
5162 symbol_db_engine_update_buffer_symbols (SymbolDBEngine * dbe, const gchar *project,
5163 GPtrArray * real_files_list,
5164 const GPtrArray * text_buffers,
5165 const GPtrArray * buffer_sizes)
5167 SymbolDBEnginePriv *priv;
5168 gint i;
5169 gint ret_id;
5170 gboolean ret_code;
5171 /* array that'll represent the /dev/shm/anjuta-XYZ files */
5172 GPtrArray *temp_files;
5173 GPtrArray *real_files_on_db;
5175 g_return_val_if_fail (dbe != NULL, FALSE);
5176 priv = dbe->priv;
5178 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5179 g_return_val_if_fail (project != NULL, FALSE);
5180 g_return_val_if_fail (real_files_list != NULL, FALSE);
5181 g_return_val_if_fail (text_buffers != NULL, FALSE);
5182 g_return_val_if_fail (buffer_sizes != NULL, FALSE);
5184 temp_files = g_ptr_array_new();
5185 real_files_on_db = g_ptr_array_new();
5187 /* obtain a GPtrArray with real_files on database */
5188 for (i=0; i < real_files_list->len; i++)
5190 const gchar *relative_path;
5191 const gchar *curr_abs_file;
5192 FILE *buffer_mem_file;
5193 const gchar *temp_buffer;
5194 gint buffer_mem_fd;
5195 gint temp_size;
5196 gchar *shared_temp_file;
5197 gchar *base_filename;
5199 curr_abs_file = g_ptr_array_index (real_files_list, i);
5200 /* check if the file exists in db. We will not scan buffers for files
5201 * which aren't already in db
5203 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5205 DEBUG_PRINT ("will not scan buffer claiming to be %s because not in db",
5206 curr_abs_file);
5207 continue;
5210 relative_path = symbol_db_util_get_file_db_path (dbe, curr_abs_file);
5211 if (relative_path == NULL)
5213 g_warning ("symbol_db_engine_update_buffer_symbols (): "
5214 "relative_path is NULL");
5215 continue;
5217 g_ptr_array_add (real_files_on_db, (gpointer) relative_path);
5219 /* it's ok to have just the base filename to create the
5220 * target buffer one */
5221 base_filename = g_filename_display_basename (relative_path);
5223 shared_temp_file = g_strdup_printf ("/anjuta-%d-%ld-%s", getpid (),
5224 time (NULL), base_filename);
5225 g_free (base_filename);
5227 if ((buffer_mem_fd =
5228 shm_open (shared_temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
5230 g_warning ("Error while trying to open a shared memory file. Be"
5231 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
5232 return -1;
5235 buffer_mem_file = fdopen (buffer_mem_fd, "w+b");
5237 temp_buffer = g_ptr_array_index (text_buffers, i);
5238 temp_size = GPOINTER_TO_INT(g_ptr_array_index (buffer_sizes, i));
5240 fwrite (temp_buffer, sizeof(gchar), temp_size, buffer_mem_file);
5241 fflush (buffer_mem_file);
5242 fclose (buffer_mem_file);
5244 /* add the temp file to the array. */
5245 g_ptr_array_add (temp_files, g_strdup_printf (SHARED_MEMORY_PREFIX"%s",
5246 shared_temp_file));
5248 /* check if we already have an entry stored in the hash table, else
5249 * insert it
5251 if (g_hash_table_lookup (priv->garbage_shared_mem_files, shared_temp_file)
5252 == NULL)
5254 DEBUG_PRINT ("inserting into garbage hash table %s", shared_temp_file);
5255 g_hash_table_insert (priv->garbage_shared_mem_files, shared_temp_file,
5256 NULL);
5258 else
5260 /* the item is already stored. Just free it here. */
5261 g_free (shared_temp_file);
5265 /* in case we didn't have any good buffer to scan...*/
5266 ret_id = -1;
5268 /* it may happen that no buffer is correctly set up */
5269 if (real_files_on_db->len > 0)
5271 /* data will be freed when callback will be called. The signal will be
5272 * disconnected too, don't worry about disconnecting it by hand.
5274 g_signal_connect (G_OBJECT (dbe), "scan-end",
5275 G_CALLBACK (on_scan_update_buffer_end), real_files_list);
5277 ret_code = sdb_engine_scan_files_1 (dbe, temp_files, real_files_on_db, TRUE);
5278 if (ret_code == TRUE)
5279 ret_id = sdb_engine_get_unique_scan_id (dbe);
5280 else
5281 ret_id = -1;
5284 /* let's free the temp_files array */
5285 for (i=0; i < temp_files->len; i++)
5286 g_free (g_ptr_array_index (temp_files, i));
5288 g_ptr_array_free (temp_files, TRUE);
5290 g_ptr_array_free (real_files_on_db, TRUE);
5291 return ret_id;
5294 GdaDataModel*
5295 symbol_db_engine_get_files_for_project (SymbolDBEngine *dbe)
5297 return sdb_engine_execute_select_sql (dbe, "SELECT file.file_path FROM file");
5300 /* ~~~ Thread note: this function locks the mutex ~~~ */
5301 void
5302 symbol_db_engine_set_db_case_sensitive (SymbolDBEngine *dbe, gboolean case_sensitive)
5304 SymbolDBEnginePriv *priv;
5306 g_return_if_fail (dbe != NULL);
5307 priv = dbe->priv;
5309 if (case_sensitive == TRUE)
5310 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 1");
5311 else
5312 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 0");
5315 const GHashTable*
5316 symbol_db_engine_get_type_conversion_hash (SymbolDBEngine *dbe)
5318 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5319 return dbe->priv->sym_type_conversion_hash;
5322 const gchar*
5323 symbol_db_engine_get_project_directory (SymbolDBEngine *dbe)
5325 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5326 return dbe->priv->project_directory;
5329 GdaStatement*
5330 symbol_db_engine_get_statement (SymbolDBEngine *dbe, const gchar *sql_str)
5332 GdaStatement* stmt;
5333 GError *error = NULL;
5335 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5336 stmt = gda_sql_parser_parse_string (dbe->priv->sql_parser,
5337 sql_str,
5338 NULL, &error);
5339 if (error)
5341 g_warning ("SQL parsing failed: %s: %s", sql_str, error->message);
5342 g_error_free (error);
5344 return stmt;
5347 GdaDataModel*
5348 symbol_db_engine_execute_select (SymbolDBEngine *dbe, GdaStatement *stmt,
5349 GdaSet *params)
5351 GdaDataModel *res;
5352 GError *error = NULL;
5354 res = gda_connection_statement_execute_select (dbe->priv->db_connection,
5355 stmt, params, &error);
5356 if (error)
5358 gchar *sql_str =
5359 gda_statement_to_sql_extended (stmt, dbe->priv->db_connection,
5360 params, 0, NULL, NULL);
5362 g_warning ("SQL select exec failed: %s, %s", sql_str, error->message);
5363 g_free (sql_str);
5364 g_error_free (error);
5366 return res;