Fix Spanish translation header
[anjuta.git] / plugins / symbol-db / symbol-db-engine-core.c
blob37d6e048a7b6f5d4e1379b1ff78be08251cb711e
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 <config.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/mman.h>
35 #include <signal.h>
36 #include <fcntl.h> /* For O_* constants */
37 #include <string.h>
38 #include <regex.h>
40 #include <gio/gio.h>
41 #include <libanjuta/interfaces/ianjuta-symbol.h>
42 #include <libanjuta/anjuta-debug.h>
43 #include <libanjuta/anjuta-launcher.h>
44 #include <libanjuta/anjuta-utils.h>
45 #include <libgda/libgda.h>
46 #include <sql-parser/gda-sql-parser.h>
47 #include "readtags.h"
48 #include "symbol-db-engine-priv.h"
49 #include "symbol-db-engine-core.h"
50 #include "symbol-db-engine-utils.h"
52 #include <glib/gprintf.h>
55 * utility macros
57 #define STATIC_QUERY_POPULATE_INIT_NODE(query_list_ptr, query_type, gda_stmt) { \
58 static_query_node *q = g_new0 (static_query_node, 1); \
59 q->query_id = query_type; \
60 q->query_str = gda_stmt; \
61 q->stmt = NULL; \
62 q->plist = NULL; \
63 query_list_ptr [query_type] = q; \
67 * typedefs
69 typedef struct _TableMapTmpHeritage {
70 gint symbol_referer_id;
71 gchar *field_inherits;
72 gchar *field_struct;
73 gchar *field_typeref;
74 gchar *field_enum;
75 gchar *field_union;
76 gchar *field_class;
77 gchar *field_namespace;
79 } TableMapTmpHeritage;
81 typedef struct _TableMapSymbol {
82 gint symbol_id;
83 gint file_defined_id;
84 gchar *name;
85 gint file_position;
86 gint is_file_scope;
87 gchar *signature;
88 gchar *returntype;
89 gint scope_definition_id;
90 gint scope_id;
91 gint type_id;
92 gint kind_id;
93 gint access_kind_id;
94 gint implementation_kind_id;
95 gint update_flag;
97 } TableMapSymbol;
99 typedef struct _EngineScanDataAsync {
100 GPtrArray *files_list;
101 GPtrArray *real_files_list;
102 gboolean symbols_update;
103 gint scan_id;
105 } EngineScanDataAsync;
108 typedef void (SymbolDBEngineCallback) (SymbolDBEngine * dbe,
109 gpointer user_data);
112 * signals enum
114 enum
116 DB_CONNECTED,
117 DB_DISCONNECTED,
118 SCAN_BEGIN,
119 SINGLE_FILE_SCAN_END,
120 SCAN_END,
121 SYMBOL_INSERTED,
122 SYMBOL_UPDATED,
123 SYMBOL_SCOPE_UPDATED,
124 SYMBOL_REMOVED,
125 LAST_SIGNAL
129 * enums
131 enum {
132 DO_UPDATE_SYMS = 1,
133 DO_UPDATE_SYMS_AND_EXIT,
134 DONT_UPDATE_SYMS,
135 DONT_UPDATE_SYMS_AND_EXIT,
136 DONT_FAKE_UPDATE_SYMS,
137 END_UPDATE_GROUP_SYMS
141 * structs used for callback data.
143 typedef struct _UpdateFileSymbolsData {
144 gchar *project;
145 gchar *project_directory;
146 gboolean update_prj_analyse_time;
147 GPtrArray * files_path;
149 } UpdateFileSymbolsData;
151 typedef struct _ScanFiles1Data {
152 SymbolDBEngine *dbe;
154 gchar *real_file; /* may be NULL. If not NULL must be freed */
155 gint partial_count;
156 gint files_list_len;
157 gint symbols_update;
159 } ScanFiles1Data;
162 * global file variables
164 static GObjectClass *parent_class = NULL;
165 static unsigned int signals[LAST_SIGNAL] = { 0 };
168 #ifdef DEBUG
169 static GTimer *sym_timer_DEBUG = NULL;
170 static gint tags_total_DEBUG = 0;
171 static gdouble elapsed_total_DEBUG = 0;
172 #endif
175 * forward declarations
177 static void
178 sdb_engine_second_pass_do (SymbolDBEngine * dbe);
180 static gint
181 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
182 int file_defined_id, gboolean sym_update);
184 const GdaStatement *
185 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id);
187 GQuark
188 symbol_db_engine_error_quark (void)
190 return g_quark_from_static_string ("symbol-db-engine-error-quark");
194 * implementation starts here
196 static GNUC_INLINE gint
197 sdb_engine_cache_lookup (GHashTable* hash_table, const gchar* lookup)
199 gpointer orig_key = NULL;
200 gpointer value = NULL;
202 /* avoiding lazy initialization may gain some cpu cycles. Just lookup here. */
203 if (g_hash_table_lookup_extended (hash_table,
204 lookup,
205 &orig_key,
206 &value))
208 gint table_id = GPOINTER_TO_INT (value);
209 return table_id;
211 return -1;
214 static GNUC_INLINE void
215 sdb_engine_insert_cache (GHashTable* hash_table, const gchar* key,
216 gint value)
218 g_hash_table_insert (hash_table, g_strdup (key),
219 GINT_TO_POINTER (value));
222 static void
223 sdb_engine_tablemap_tmp_heritage_destroy (TableMapTmpHeritage *node)
225 g_free (node->field_inherits);
226 g_free (node->field_struct);
227 g_free (node->field_typeref);
228 g_free (node->field_enum);
229 g_free (node->field_union);
230 g_free (node->field_class);
231 g_free (node->field_namespace);
233 g_slice_free (TableMapTmpHeritage, node);
236 static void
237 sdb_engine_scan_data_destroy (gpointer data)
239 EngineScanDataAsync *esda = (EngineScanDataAsync *)data;
241 g_ptr_array_unref (esda->files_list);
242 if (esda->real_files_list)
243 g_ptr_array_unref (esda->real_files_list);
245 g_free (esda);
248 static void
249 sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
251 SymbolDBEnginePriv *priv = dbe->priv;
252 if (priv->tmp_heritage_tablemap)
254 TableMapTmpHeritage *node;
255 while ((node = g_queue_pop_head (priv->tmp_heritage_tablemap)) != NULL)
257 sdb_engine_tablemap_tmp_heritage_destroy (node);
260 /* queue should be void. Free it */
261 g_queue_free (priv->tmp_heritage_tablemap);
262 priv->tmp_heritage_tablemap = NULL;
266 static void
267 sdb_engine_clear_caches (SymbolDBEngine* dbe)
269 SymbolDBEnginePriv *priv = dbe->priv;
270 if (priv->kind_cache)
271 g_hash_table_destroy (priv->kind_cache);
272 if (priv->access_cache)
273 g_hash_table_destroy (priv->access_cache);
274 if (priv->implementation_cache)
275 g_hash_table_destroy (priv->implementation_cache);
276 if (priv->language_cache)
277 g_hash_table_destroy (priv->language_cache);
279 priv->kind_cache = NULL;
280 priv->access_cache = NULL;
281 priv->implementation_cache = NULL;
282 priv->language_cache = NULL;
285 static void
286 sdb_engine_init_table_maps (SymbolDBEngine *dbe)
288 SymbolDBEnginePriv *priv = dbe->priv;
290 /* tmp_heritage_tablemap */
291 priv->tmp_heritage_tablemap = g_queue_new ();
294 static void
295 sdb_engine_init_caches (SymbolDBEngine* dbe)
297 SymbolDBEnginePriv *priv = dbe->priv;
298 priv->kind_cache = g_hash_table_new_full (g_str_hash,
299 g_str_equal,
300 g_free,
301 NULL);
303 priv->access_cache = g_hash_table_new_full (g_str_hash,
304 g_str_equal,
305 g_free,
306 NULL);
308 priv->implementation_cache = g_hash_table_new_full (g_str_hash,
309 g_str_equal,
310 g_free,
311 NULL);
313 priv->language_cache = g_hash_table_new_full (g_str_hash,
314 g_str_equal,
315 g_free,
316 NULL);
319 /* ~~~ Thread note: this function locks the mutex ~~~ */
320 static gboolean
321 sdb_engine_execute_unknown_sql (SymbolDBEngine *dbe, const gchar *sql)
323 GdaStatement *stmt;
324 GObject *res;
325 SymbolDBEnginePriv *priv;
327 priv = dbe->priv;
329 SDB_LOCK(priv);
330 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, NULL, NULL);
332 if (stmt == NULL)
334 SDB_UNLOCK(priv);
335 return FALSE;
338 if ((res = gda_connection_statement_execute (priv->db_connection,
339 (GdaStatement*)stmt,
340 NULL,
341 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
342 NULL, NULL)) == NULL)
344 g_object_unref (stmt);
345 SDB_UNLOCK(priv);
346 return FALSE;
348 else
350 g_object_unref (res);
351 g_object_unref (stmt);
352 SDB_UNLOCK(priv);
353 return TRUE;
357 static GdaDataModel *
358 sdb_engine_execute_select_sql (SymbolDBEngine * dbe, const gchar *sql)
360 GdaStatement *stmt;
361 GdaDataModel *res;
362 SymbolDBEnginePriv *priv;
363 const gchar *remain;
365 priv = dbe->priv;
367 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, &remain, NULL);
369 if (stmt == NULL)
370 return NULL;
372 res = gda_connection_statement_execute_select (priv->db_connection,
373 (GdaStatement*)stmt, NULL, NULL);
374 if (!res)
375 DEBUG_PRINT ("Could not execute query: %s\n", sql);
377 if (remain != NULL)
379 /* this shouldn't never happen */
380 sdb_engine_execute_select_sql (dbe, remain);
383 g_object_unref (stmt);
385 return res;
388 static gint
389 sdb_engine_execute_non_select_sql (SymbolDBEngine * dbe, const gchar *sql)
391 GdaStatement *stmt;
392 gint nrows;
393 SymbolDBEnginePriv *priv;
394 const gchar *remain;
396 priv = dbe->priv;
397 stmt = gda_sql_parser_parse_string (priv->sql_parser,
398 sql, &remain, NULL);
400 if (stmt == NULL)
401 return -1;
403 nrows = gda_connection_statement_execute_non_select (priv->db_connection, stmt,
404 NULL, NULL, NULL);
405 if (remain != NULL) {
406 /* may happen for example when sql is a file-content */
407 sdb_engine_execute_non_select_sql (dbe, remain);
410 g_object_unref (stmt);
411 return nrows;
415 * ### Thread note: this function inherits the mutex lock ###
417 * Use a proxy to return an already present or a fresh new prepared query
418 * from static 'query_list'. We should perform actions in the fastest way, because
419 * these queries are time-critical.
420 * A GdaSet will also be populated once, avoiding so to create again later on.
422 const GdaStatement *
423 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id)
425 static_query_node *node;
426 SymbolDBEnginePriv *priv;
428 priv = dbe->priv;
430 /* no way: if connection is NULL we will break here. There must be
431 * a connection established to db before using this function */
432 /*g_return_val_if_fail (priv->db_connection != NULL, NULL);*/
434 if ((node = priv->static_query_list[query_id]) == NULL)
435 return NULL;
437 if (node->stmt == NULL)
439 GError *error = NULL;
441 /* create a new GdaStatement */
442 node->stmt =
443 gda_sql_parser_parse_string (priv->sql_parser, node->query_str, NULL,
444 &error);
446 if (error)
448 g_warning ("%s", error->message);
449 g_error_free (error);
450 return NULL;
453 if (gda_statement_get_parameters ((GdaStatement*)node->stmt,
454 &node->plist, NULL) == FALSE)
456 g_warning ("Error on getting parameters for %d", query_id);
460 return node->stmt;
464 * ### Thread note: this function inherits the mutex lock ###
466 * Return a GdaSet of parameters calculated from the statement. It does not check
467 * if it's null. You *must* be sure to have called sdb_engine_get_statement_by_query_id () first.
469 static GNUC_INLINE const GdaSet *
470 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id)
472 SymbolDBEnginePriv *priv;
474 priv = dbe->priv;
476 static_query_node *node;
477 node = priv->static_query_list[query_id];
478 return node->plist;
482 * Clear the static cached queries data. You should call this function when closing/
483 * destroying SymbolDBEngine object.
485 static void
486 sdb_engine_free_cached_queries (SymbolDBEngine *dbe)
488 SymbolDBEnginePriv *priv;
489 gint i;
490 static_query_node *node;
492 priv = dbe->priv;
494 for (i = 0; i < PREP_QUERY_COUNT; i++)
496 node = priv->static_query_list[i];
498 if (node != NULL && node->stmt != NULL)
500 /*DEBUG_PRINT ("sdb_engine_free_cached_queries stmt %d", i);*/
501 g_object_unref (node->stmt);
502 node->stmt = NULL;
505 if (node != NULL && node->plist != NULL)
507 /*DEBUG_PRINT ("sdb_engine_free_cached_queries plist %d", i);*/
508 g_object_unref (node->plist);
509 node->plist = NULL;
512 /* last but not the least free the node itself */
513 g_free (node);
514 priv->static_query_list[i] = NULL;
518 static gboolean
519 sdb_engine_disconnect_from_db (SymbolDBEngine * dbe)
521 SymbolDBEnginePriv *priv;
523 g_return_val_if_fail (dbe != NULL, FALSE);
524 priv = dbe->priv;
526 DEBUG_PRINT ("VACUUM command issued on %s", priv->cnc_string);
527 sdb_engine_execute_non_select_sql (dbe, "VACUUM");
529 DEBUG_PRINT ("Disconnecting from %s", priv->cnc_string);
530 g_free (priv->cnc_string);
531 priv->cnc_string = NULL;
533 if (priv->db_connection != NULL) {
534 #ifdef HAVE_GDA6
535 GError* err = NULL;
536 gda_connection_close (priv->db_connection, &err);
537 if (err != NULL)
538 return FALSE;
539 #else
540 gda_connection_close (priv->db_connection);
541 #endif
543 priv->db_connection = NULL;
545 if (priv->sql_parser != NULL)
546 g_object_unref (priv->sql_parser);
547 priv->sql_parser = NULL;
549 return TRUE;
553 * ### Thread note: this function inherits the mutex lock ###
555 * @return -1 on error. Otherwise the id of tuple.
557 static GNUC_INLINE gint
558 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
559 gchar * param_key,
560 GValue * param_value)
562 const GdaSet *plist;
563 const GdaStatement *stmt;
564 GdaHolder *param;
565 GdaDataModel *data_model;
566 const GValue *num;
567 gint table_id;
568 SymbolDBEnginePriv *priv;
570 priv = dbe->priv;
572 /* get prepared query */
573 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
575 g_warning ("Query is null");
576 return -1;
579 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
581 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key)) == NULL)
583 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
584 "from pquery!\n");
585 return -1;
588 gda_holder_set_value (param, param_value, NULL);
590 /* execute the query with parameters just set */
591 data_model = gda_connection_statement_execute_select (priv->db_connection,
592 (GdaStatement*)stmt,
593 (GdaSet*)plist, NULL);
595 if (!GDA_IS_DATA_MODEL (data_model) ||
596 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
598 if (data_model != NULL)
599 g_object_unref (data_model);
600 return -1;
603 /* get and parse the results. */
604 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
606 table_id = g_value_get_int (num);
607 g_object_unref (data_model);
609 /* set the value to a dummy string because we won't use the real value anymore */
610 return table_id;
613 /* ### Thread note: this function inherits the mutex lock ### */
614 static GNUC_INLINE gint
615 sdb_engine_get_tuple_id_by_unique_name5 (SymbolDBEngine * dbe,
616 static_query_type qtype,
617 gchar * param_key1,
618 GValue * value1,
619 gchar * param_key2,
620 GValue * value2,
621 gchar * param_key3,
622 GValue * value3,
623 gchar * param_key4,
624 GValue * value4,
625 gchar * param_key5,
626 GValue * value5)
628 const GdaSet *plist;
629 const GdaStatement *stmt;
630 GdaHolder *param;
631 GdaDataModel *data_model;
632 const GValue *num;
633 gint table_id;
634 SymbolDBEnginePriv *priv;
636 priv = dbe->priv;
638 /* get prepared query */
639 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
641 g_warning ("Query is null");
642 return -1;
645 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
647 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key1)) == NULL)
649 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: param is NULL "
650 "from pquery!\n");
651 return -1;
654 gda_holder_set_value (param, value1, NULL);
656 /* ...and the second one */
657 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key2)) == NULL)
659 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: "
660 "param is NULL from pquery!");
661 return -1;
664 gda_holder_set_value (param, value2, NULL);
666 /* ...and the third one */
667 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key3)) == NULL)
669 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: "
670 "param is NULL from pquery!");
671 return -1;
674 gda_holder_set_value (param, value3, NULL);
676 /* ...and the fourth one */
677 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key4)) == NULL)
679 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: "
680 "param is NULL from pquery!");
681 return -1;
684 gda_holder_set_value (param, value4, NULL);
686 /* ...and the fifth one */
687 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key5)) == NULL)
689 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: "
690 "param is NULL from pquery!");
691 return -1;
694 gda_holder_set_value (param, value5, NULL);
696 /* execute the query with parameters just set */
697 data_model = gda_connection_statement_execute_select (priv->db_connection,
698 (GdaStatement*)stmt,
699 (GdaSet*)plist, NULL);
701 if (!GDA_IS_DATA_MODEL (data_model) ||
702 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
704 if (data_model != NULL)
705 g_object_unref (data_model);
707 return -1;
710 /* get and parse the results. */
711 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
713 table_id = g_value_get_int (num);
714 g_object_unref (data_model);
715 return table_id;
718 /** ### Thread note: this function inherits the mutex lock ### */
719 static int
720 sdb_engine_get_file_defined_id (SymbolDBEngine* dbe,
721 const gchar* base_prj_path,
722 const gchar* fake_file_on_db,
723 tagEntry* tag_entry)
725 GValue v = {0};
727 gint file_defined_id = 0;
728 if (base_prj_path != NULL && g_str_has_prefix (tag_entry->file, base_prj_path))
730 /* in this case fake_file will be ignored. */
732 /* we expect here an absolute path */
733 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file + strlen (base_prj_path));
735 else
737 /* check whether the fake_file can substitute the tag_entry->file one */
738 if (fake_file_on_db == NULL)
740 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file);
742 else
744 SDB_GVALUE_SET_STATIC_STRING(v, fake_file_on_db);
748 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
749 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
750 "filepath",
751 &v)) < 0)
753 /* if we arrive here there should be some sync problems between the filenames
754 * in database and the ones in the ctags files. We trust in db's ones,
755 * so we'll just return here.
757 g_warning ("sync problems between db and ctags filenames entries. "
758 "File was %s (base_path: %s, fake_file: %s, tag_file: %s)",
759 g_value_get_string (&v), base_prj_path, fake_file_on_db,
760 tag_entry->file);
761 return -1;
764 return file_defined_id;
768 * ### Thread note: this function inherits the mutex lock ###
770 * If fake_file is != NULL we claim and assert that tags contents which are
771 * scanned belong to the fake_file in the project.
772 * More: the fake_file refers to just one single file and cannot be used
773 * for multiple fake_files.
775 static void
776 sdb_engine_populate_db_by_tags (SymbolDBEngine * dbe, FILE* fd,
777 gchar * fake_file_on_db,
778 gboolean force_sym_update)
780 tagFile *tag_file;
781 tagFileInfo tag_file_info;
782 tagEntry tag_entry;
783 gint file_defined_id_cache = 0;
784 gchar* tag_entry_file_cache = NULL;
786 SymbolDBEnginePriv *priv = dbe->priv;
788 gchar* base_prj_path = fake_file_on_db == NULL ?
789 priv->project_directory : NULL;
791 g_return_if_fail (dbe != NULL);
793 g_return_if_fail (priv->db_connection != NULL);
794 g_return_if_fail (fd != NULL);
796 if ((tag_file = tagsOpen_1 (fd, &tag_file_info)) == NULL)
798 g_warning ("error in opening ctags file");
801 #ifdef DEBUG
802 if (sym_timer_DEBUG == NULL)
803 sym_timer_DEBUG = g_timer_new ();
804 else
805 g_timer_reset (sym_timer_DEBUG);
806 gint tags_num_DEBUG = 0;
807 #endif
808 tag_entry.file = NULL;
810 while (tagsNext (tag_file, &tag_entry) != TagFailure)
812 gint file_defined_id = 0;
813 if (tag_entry.file == NULL)
815 continue;
817 if (file_defined_id_cache > 0)
819 if (g_str_equal (tag_entry.file, tag_entry_file_cache))
821 file_defined_id = file_defined_id_cache;
824 if (file_defined_id == 0)
826 file_defined_id = sdb_engine_get_file_defined_id (dbe,
827 base_prj_path,
828 fake_file_on_db,
829 &tag_entry);
830 file_defined_id_cache = file_defined_id;
831 g_free (tag_entry_file_cache);
832 tag_entry_file_cache = g_strdup (tag_entry.file);
835 if (priv->symbols_scanned_count++ % BATCH_SYMBOL_NUMBER == 0)
837 GError *error = NULL;
839 /* if we aren't at the first cycle then we can commit the transaction */
840 if (priv->symbols_scanned_count > 1)
842 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
843 &error);
845 if (error)
847 DEBUG_PRINT ("err: %s", error->message);
848 g_error_free (error);
849 error = NULL;
853 gda_connection_begin_transaction (priv->db_connection, "symboltrans",
854 GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, &error);
856 if (error)
858 DEBUG_PRINT ("err: %s", error->message);
859 g_error_free (error);
860 error = NULL;
864 /* insert or update a symbol */
865 sdb_engine_add_new_symbol (dbe, &tag_entry, file_defined_id,
866 force_sym_update);
867 #ifdef DEBUG
868 tags_num_DEBUG++;
869 #endif
870 tag_entry.file = NULL;
872 g_free (tag_entry_file_cache);
875 #ifdef DEBUG
876 gdouble elapsed_DEBUG = g_timer_elapsed (sym_timer_DEBUG, NULL);
877 tags_total_DEBUG += tags_num_DEBUG;
878 elapsed_total_DEBUG += elapsed_DEBUG;
879 /* DEBUG_PRINT ("elapsed: %f for (%d) [%f sec/symbol] [av %f sec/symbol]", elapsed_DEBUG,
880 tags_num_DEBUG, elapsed_DEBUG / tags_num_DEBUG,
881 elapsed_total_DEBUG / tags_total_DEBUG);
883 #endif
885 /* notify listeners that another file has been scanned */
886 DBESignal *dbesig = g_slice_new0 (DBESignal);
887 dbesig->value = GINT_TO_POINTER (SINGLE_FILE_SCAN_END +1);
888 dbesig->process_id = priv->current_scan_process_id;
890 g_async_queue_push (priv->signals_aqueue, dbesig);
892 /* we've done with tag_file but we don't need to tagsClose (tag_file); */
895 /* ~~~ Thread note: this function locks the mutex ~~~ */
896 static void
897 sdb_engine_ctags_output_thread (gpointer data, gpointer user_data)
899 gint len_chars;
900 gchar *chars, *chars_ptr;
901 gint remaining_chars;
902 gint len_marker;
903 SymbolDBEnginePriv *priv;
904 SymbolDBEngine *dbe;
906 chars = chars_ptr = (gchar *)data;
907 dbe = SYMBOL_DB_ENGINE (user_data);
909 g_return_if_fail (dbe != NULL);
910 g_return_if_fail (chars_ptr != NULL);
912 priv = dbe->priv;
914 SDB_LOCK(priv);
916 remaining_chars = len_chars = strlen (chars_ptr);
917 len_marker = strlen (CTAGS_MARKER);
919 /*DEBUG_PRINT ("program output [new version]: ==>%s<==", chars);*/
920 if (len_chars >= len_marker)
922 gchar *marker_ptr = NULL;
923 gint tmp_str_length = 0;
925 /* is it an end file marker? */
926 marker_ptr = strstr (chars_ptr, CTAGS_MARKER);
930 if (marker_ptr != NULL)
932 int scan_flag;
933 gchar *real_file;
935 /* set the length of the string parsed */
936 tmp_str_length = marker_ptr - chars_ptr;
938 /* write to shm_file all the chars_ptr received without the marker ones */
939 fwrite (chars_ptr, sizeof(gchar), tmp_str_length, priv->shared_mem_file);
941 chars_ptr = marker_ptr + len_marker;
942 remaining_chars -= (tmp_str_length + len_marker);
943 fflush (priv->shared_mem_file);
945 /* get the scan flag from the queue. We need it to know whether
946 * an update of symbols must be done or not */
947 DBESignal *dbesig = g_async_queue_try_pop (priv->scan_aqueue);
948 scan_flag = GPOINTER_TO_INT(dbesig->value);
949 g_slice_free (DBESignal, dbesig);
951 dbesig = g_async_queue_try_pop (priv->scan_aqueue);
952 real_file = dbesig->value;
953 g_slice_free (DBESignal, dbesig);
955 /* and now call the populating function */
956 if (scan_flag == DO_UPDATE_SYMS ||
957 scan_flag == DO_UPDATE_SYMS_AND_EXIT)
959 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
960 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
961 TRUE);
963 else
965 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
966 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
967 FALSE);
970 /* don't forget to free the real_file, if it's a char */
971 if ((gsize)real_file != DONT_FAKE_UPDATE_SYMS)
972 g_free (real_file);
974 /* check also if, together with an end file marker, we have an
975 * end group-of-files end marker.
977 if (scan_flag == DO_UPDATE_SYMS_AND_EXIT ||
978 scan_flag == DONT_UPDATE_SYMS_AND_EXIT )
980 gint tmp_inserted;
981 gint tmp_updated;
983 /* scan has ended. Go go with second step. */
984 DEBUG_PRINT ("%s", "FOUND end-of-group-files marker.");
986 chars_ptr += len_marker;
987 remaining_chars -= len_marker;
989 /* will emit symbol_scope_updated and will flush on disk
990 * tablemaps
992 sdb_engine_second_pass_do (dbe);
994 /* Here we are. It's the right time to notify the listeners
995 * about out fresh new inserted/updated symbols...
996 * Go on by emitting them.
998 while ((tmp_inserted = GPOINTER_TO_INT(
999 g_async_queue_try_pop (priv->inserted_syms_id_aqueue))) > 0)
1001 /* we must be sure to insert both signals at once */
1002 g_async_queue_lock (priv->signals_aqueue);
1004 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1005 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1007 dbesig1->value = GINT_TO_POINTER (SYMBOL_INSERTED + 1);
1008 dbesig1->process_id = priv->current_scan_process_id;
1010 dbesig2->value = GINT_TO_POINTER (tmp_inserted);
1011 dbesig2->process_id = priv->current_scan_process_id;
1013 g_async_queue_push_unlocked (priv->signals_aqueue,
1014 dbesig1);
1015 g_async_queue_push_unlocked (priv->signals_aqueue,
1016 dbesig2);
1018 g_async_queue_unlock (priv->signals_aqueue);
1021 while ((tmp_updated = GPOINTER_TO_INT(
1022 g_async_queue_try_pop (priv->updated_syms_id_aqueue))) > 0)
1024 g_async_queue_lock (priv->signals_aqueue);
1026 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1027 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1029 dbesig1->value = GINT_TO_POINTER (SYMBOL_UPDATED + 1);
1030 dbesig1->process_id = priv->current_scan_process_id;
1032 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1033 dbesig2->process_id = priv->current_scan_process_id;
1035 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1036 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1037 g_async_queue_unlock (priv->signals_aqueue);
1040 while ((tmp_updated = GPOINTER_TO_INT(
1041 g_async_queue_try_pop (priv->updated_scope_syms_id_aqueue))) > 0)
1043 g_async_queue_lock (priv->signals_aqueue);
1045 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1046 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1048 dbesig1->value = GINT_TO_POINTER (SYMBOL_SCOPE_UPDATED + 1);
1049 dbesig1->process_id = priv->current_scan_process_id;
1051 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1052 dbesig2->process_id = priv->current_scan_process_id;
1054 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1055 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1056 g_async_queue_unlock (priv->signals_aqueue);
1059 #ifdef DEBUG
1060 if (priv->first_scan_timer_DEBUG != NULL)
1062 DEBUG_PRINT ("~~~~~ TOTAL FIRST SCAN elapsed: %f ",
1063 g_timer_elapsed (priv->first_scan_timer_DEBUG, NULL));
1064 g_timer_destroy (priv->first_scan_timer_DEBUG);
1065 priv->first_scan_timer_DEBUG = NULL;
1067 #endif
1069 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1071 dbesig1->value = GINT_TO_POINTER (SCAN_END + 1);
1072 dbesig1->process_id = priv->current_scan_process_id;
1074 g_async_queue_push (priv->signals_aqueue, dbesig1);
1077 /* truncate the file to 0 length */
1078 ftruncate (priv->shared_mem_fd, 0);
1080 else
1082 /* marker_ptr is NULL here. We should then exit the loop. */
1083 /* write to shm_file all the chars received */
1084 fwrite (chars_ptr, sizeof(gchar), remaining_chars,
1085 priv->shared_mem_file);
1087 fflush (priv->shared_mem_file);
1088 break;
1091 /* found out a new marker */
1092 marker_ptr = strstr (marker_ptr + len_marker, CTAGS_MARKER);
1093 } while (remaining_chars + len_marker < len_chars || marker_ptr != NULL);
1096 SDB_UNLOCK(priv);
1098 g_free (chars);
1103 * This function runs on the main glib thread, so that it can safely spread signals
1105 static gboolean
1106 sdb_engine_timeout_trigger_signals (gpointer user_data)
1108 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1109 SymbolDBEnginePriv *priv;
1111 g_return_val_if_fail (user_data != NULL, FALSE);
1112 priv = dbe->priv;
1114 if (priv->signals_aqueue != NULL &&
1115 g_async_queue_length (priv->signals_aqueue) > 0)
1117 DBESignal *dbesig;
1118 gsize real_signal;
1119 gint process_id;
1121 while (priv->signals_aqueue != NULL &&
1122 (dbesig = g_async_queue_try_pop (priv->signals_aqueue)) != NULL)
1124 if (dbesig == NULL)
1126 return g_async_queue_length (priv->signals_aqueue) > 0 ? TRUE : FALSE;
1129 real_signal = GPOINTER_TO_INT (dbesig->value) -1;
1130 process_id = dbesig->process_id;
1132 switch (real_signal)
1134 case SINGLE_FILE_SCAN_END:
1136 g_signal_emit (dbe, signals[SINGLE_FILE_SCAN_END], 0);
1138 break;
1140 case SCAN_BEGIN:
1142 DEBUG_PRINT ("%s", "EMITTING scan begin.");
1143 g_signal_emit (dbe, signals[SCAN_BEGIN], 0, process_id);
1145 break;
1147 case SCAN_END:
1149 /* reset count */
1150 priv->symbols_scanned_count = 0;
1152 DEBUG_PRINT ("Committing symboltrans transaction...");
1153 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
1154 NULL);
1155 DEBUG_PRINT ("... Done!");
1157 /* perform flush on db of the tablemaps, if this is the 1st scan */
1158 if (priv->is_first_population == TRUE)
1160 /* ok, set the flag to false. We're done with it */
1161 priv->is_first_population = FALSE;
1164 priv->is_scanning = FALSE;
1166 DEBUG_PRINT ("%s", "EMITTING scan-end");
1167 g_signal_emit (dbe, signals[SCAN_END], 0, process_id);
1169 break;
1171 case SYMBOL_INSERTED:
1173 DBESignal *dbesig2;
1175 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1176 g_signal_emit (dbe, signals[SYMBOL_INSERTED], 0, dbesig2->value);
1178 g_slice_free (DBESignal, dbesig2);
1180 break;
1182 case SYMBOL_UPDATED:
1184 DBESignal *dbesig2;
1186 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1187 g_signal_emit (dbe, signals[SYMBOL_UPDATED], 0, dbesig2->value);
1189 g_slice_free (DBESignal, dbesig2);
1191 break;
1193 case SYMBOL_SCOPE_UPDATED:
1195 DBESignal *dbesig2;
1197 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1198 g_signal_emit (dbe, signals[SYMBOL_SCOPE_UPDATED], 0, dbesig2->value);
1200 g_slice_free (DBESignal, dbesig2);
1202 break;
1204 case SYMBOL_REMOVED:
1206 DBESignal *dbesig2;
1208 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1209 g_signal_emit (dbe, signals[SYMBOL_REMOVED], 0, dbesig2->value);
1211 g_slice_free (DBESignal, dbesig2);
1213 break;
1216 g_slice_free (DBESignal, dbesig);
1218 /* reset to 0 the retries */
1219 priv->trigger_closure_retries = 0;
1221 else {
1222 priv->trigger_closure_retries++;
1225 if (priv->thread_pool != NULL &&
1226 g_thread_pool_unprocessed (priv->thread_pool) == 0 &&
1227 g_thread_pool_get_num_threads (priv->thread_pool) == 0)
1229 /* remove the trigger coz we don't need it anymore... */
1230 g_source_remove (priv->timeout_trigger_handler);
1231 priv->timeout_trigger_handler = 0;
1232 return FALSE;
1235 return TRUE;
1238 static void
1239 sdb_engine_ctags_output_callback_1 (AnjutaLauncher * launcher,
1240 AnjutaLauncherOutputType output_type,
1241 const gchar * chars, gpointer user_data)
1243 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1244 SymbolDBEnginePriv *priv;
1246 g_return_if_fail (user_data != NULL);
1248 priv = dbe->priv;
1250 if (priv->shutting_down == TRUE)
1251 return;
1253 g_thread_pool_push (priv->thread_pool, g_strdup (chars), NULL);
1255 /* signals monitor */
1256 if (priv->timeout_trigger_handler <= 0)
1258 priv->timeout_trigger_handler =
1259 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, TRIGGER_SIGNALS_DELAY,
1260 sdb_engine_timeout_trigger_signals, user_data, NULL);
1261 priv->trigger_closure_retries = 0;
1265 static void
1266 on_scan_files_end_1 (AnjutaLauncher * launcher, int child_pid,
1267 int exit_status, gulong time_taken_in_seconds,
1268 gpointer user_data)
1270 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1271 SymbolDBEnginePriv *priv;
1273 g_return_if_fail (user_data != NULL);
1275 priv = dbe->priv;
1277 DEBUG_PRINT ("***** ctags ended (%s) (%s) *****", priv->ctags_path,
1278 priv->cnc_string);
1280 if (priv->shutting_down == TRUE)
1281 return;
1283 priv->ctags_path = NULL;
1286 static void
1287 sdb_engine_ctags_launcher_create (SymbolDBEngine * dbe)
1289 SymbolDBEnginePriv *priv;
1290 gchar *exe_string;
1292 priv = dbe->priv;
1294 DEBUG_PRINT ("Creating anjuta_launcher with %s for %s", priv->ctags_path,
1295 priv->cnc_string);
1297 priv->ctags_launcher = anjuta_launcher_new ();
1299 anjuta_launcher_set_check_passwd_prompt (priv->ctags_launcher, FALSE);
1300 anjuta_launcher_set_encoding (priv->ctags_launcher, NULL);
1302 g_signal_connect (G_OBJECT (priv->ctags_launcher), "child-exited",
1303 G_CALLBACK (on_scan_files_end_1), dbe);
1305 exe_string = g_strdup_printf ("%s --sort=no --fields=afmiKlnsStTz --c++-kinds=+p "
1306 "--filter=yes --filter-terminator='"CTAGS_MARKER"'",
1307 priv->ctags_path);
1308 DEBUG_PRINT ("Launching %s", exe_string);
1309 anjuta_launcher_execute (priv->ctags_launcher,
1310 exe_string, sdb_engine_ctags_output_callback_1,
1311 dbe);
1312 g_free (exe_string);
1316 * A GAsyncReadyCallback function. This function is the async continuation for
1317 * sdb_engine_scan_files_1 ().
1319 static void
1320 sdb_engine_scan_files_2 (GFile *gfile,
1321 GAsyncResult *res,
1322 gpointer user_data)
1324 ScanFiles1Data *sf_data = (ScanFiles1Data*)user_data;
1325 SymbolDBEngine *dbe;
1326 SymbolDBEnginePriv *priv;
1327 GFileInfo *ginfo;
1328 gchar *local_path;
1329 gchar *real_file;
1330 gboolean symbols_update;
1331 gint partial_count;
1332 gint files_list_len;
1334 dbe = sf_data->dbe;
1335 symbols_update = sf_data->symbols_update;
1336 real_file = sf_data->real_file;
1337 files_list_len = sf_data->files_list_len;
1338 partial_count = sf_data->partial_count;
1340 priv = dbe->priv;
1342 ginfo = g_file_query_info_finish (gfile, res, NULL);
1344 local_path = g_file_get_path (gfile);
1346 if (ginfo == NULL ||
1347 g_file_info_get_attribute_boolean (ginfo,
1348 G_FILE_ATTRIBUTE_ACCESS_CAN_READ) == FALSE)
1350 g_warning ("File does not exist or is unreadable by user (%s)", local_path);
1352 g_free (local_path);
1353 g_free (real_file);
1354 g_free (sf_data);
1356 if (ginfo)
1357 g_object_unref (ginfo);
1358 if (gfile)
1359 g_object_unref (gfile);
1360 return;
1363 /* DEBUG_PRINT ("sent to stdin %s", local_path); */
1364 anjuta_launcher_send_stdin (priv->ctags_launcher, local_path);
1365 anjuta_launcher_send_stdin (priv->ctags_launcher, "\n");
1367 if (symbols_update == TRUE)
1369 DBESignal *dbesig;
1371 /* will this be the last file in the list? */
1372 if (partial_count + 1 >= files_list_len)
1374 dbesig = g_slice_new0 (DBESignal);
1375 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS_AND_EXIT);
1376 dbesig->process_id = priv->current_scan_process_id;
1378 /* yes */
1379 g_async_queue_push (priv->scan_aqueue, dbesig);
1381 else
1383 dbesig = g_slice_new0 (DBESignal);
1384 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS);
1385 dbesig->process_id = priv->current_scan_process_id;
1387 /* no */
1388 g_async_queue_push (priv->scan_aqueue, dbesig);
1391 else
1393 DBESignal *dbesig;
1395 if (partial_count + 1 >= files_list_len)
1397 dbesig = g_slice_new0 (DBESignal);
1398 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS_AND_EXIT);
1399 dbesig->process_id = priv->current_scan_process_id;
1401 /* yes */
1402 g_async_queue_push (priv->scan_aqueue, dbesig);
1404 else
1406 dbesig = g_slice_new0 (DBESignal);
1407 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS);
1408 dbesig->process_id = priv->current_scan_process_id;
1410 /* no */
1411 g_async_queue_push (priv->scan_aqueue, dbesig);
1415 /* don't forget to add the real_files if the caller provided a list for
1416 * them! */
1417 if (real_file != NULL)
1419 DBESignal *dbesig;
1421 dbesig = g_slice_new0 (DBESignal);
1422 dbesig->value = real_file;
1423 dbesig->process_id = priv->current_scan_process_id;
1425 g_async_queue_push (priv->scan_aqueue, dbesig);
1427 else
1429 DBESignal *dbesig;
1431 dbesig = g_slice_new0 (DBESignal);
1432 dbesig->value = GINT_TO_POINTER (DONT_FAKE_UPDATE_SYMS);
1433 dbesig->process_id = priv->current_scan_process_id;
1435 /* else add a DONT_FAKE_UPDATE_SYMS marker, just to notify that this
1436 * is not a fake file scan
1438 g_async_queue_push (priv->scan_aqueue, dbesig);
1441 /* we don't need ginfo object anymore, bye */
1442 g_object_unref (ginfo);
1443 g_object_unref (gfile);
1444 g_free (local_path);
1445 g_free (sf_data);
1446 /* no need to free real_file. For two reasons: 1. it's null. 2. it has been
1447 * pushed in the async queue and will be freed later
1452 * sdb_sort_files_list:
1453 * file1: First file
1454 * file2: second file
1456 * Returns:
1457 * -1 if file1 will be sorted before file2
1458 * 0 if file1 and file2 are sorted equally
1459 * 1 if file2 will be sorted before file1
1461 static gint sdb_sort_files_list (gconstpointer file1, gconstpointer file2)
1463 const gchar* filename1 = file1;
1464 const gchar* filename2 = file2;
1466 if (g_str_has_suffix (filename1, ".h") ||
1467 g_str_has_suffix (filename1, ".hxx") ||
1468 g_str_has_suffix (filename1, ".hh"))
1470 return -1;
1472 else if (g_str_has_suffix (filename2, ".h") ||
1473 g_str_has_suffix (filename2, ".hxx") ||
1474 g_str_has_suffix (filename2, ".hh"))
1476 return 1;
1479 return 0;
1483 /* Scan with ctags and produce an output 'tags' file [shared memory file]
1484 * containing language symbols. This function will call ctags
1485 * executale and then sdb_engine_populate_db_by_tags () when it'll detect some
1486 * output.
1487 * Please note the files_list/real_files_list parameter:
1488 * this version of sdb_engine_scan_files_1 () let you scan for text buffer(s) that
1489 * will be claimed as buffers for the real files.
1490 * 1. simple mode: files_list represents the real files on disk and so we don't
1491 * need real_files_list, which will be NULL.
1492 * 2. advanced mode: files_list represents temporary flushing of buffers on disk, i.e.
1493 * /tmp/anjuta_XYZ.cxx. real_files_list is the representation of those files on
1494 * database. On the above example we can have anjuta_XYZ.cxx mapped as /src/main.c
1495 * on db. In this mode files_list and real_files_list must have the same size.
1498 static gboolean
1499 sdb_engine_scan_files_1 (SymbolDBEngine * dbe, GPtrArray * files_list,
1500 GPtrArray *real_files_list, gboolean symbols_update,
1501 gint scan_id)
1503 SymbolDBEnginePriv *priv;
1504 gint i;
1506 priv = dbe->priv;
1508 /* if ctags_launcher isn't initialized, then do it now. */
1509 /* lazy initialization */
1510 if (priv->ctags_launcher == NULL)
1512 sdb_engine_ctags_launcher_create (dbe);
1516 /* Enter scanning state */
1517 priv->is_scanning = TRUE;
1519 priv->current_scan_process_id = scan_id;
1521 DBESignal *dbesig;
1523 dbesig = g_slice_new0 (DBESignal);
1524 dbesig->value = GINT_TO_POINTER (SCAN_BEGIN + 1);
1525 dbesig->process_id = priv->current_scan_process_id;
1527 g_async_queue_push (priv->signals_aqueue, dbesig);
1529 #ifdef DEBUG
1530 if (priv->first_scan_timer_DEBUG == NULL)
1531 priv->first_scan_timer_DEBUG = g_timer_new ();
1532 #endif
1534 /* create the shared memory file */
1535 if (priv->shared_mem_file == 0)
1537 gchar *temp_file;
1538 gint i = 0;
1539 while (TRUE)
1541 temp_file = g_strdup_printf ("/anjuta-%d_%ld%d.tags", getpid (),
1542 time (NULL), i++);
1543 gchar *test;
1544 test = g_strconcat (SHARED_MEMORY_PREFIX, temp_file, NULL);
1545 if (g_file_test (test, G_FILE_TEST_EXISTS) == TRUE)
1547 DEBUG_PRINT ("Temp file %s already exists... retrying", test);
1548 g_free (test);
1549 g_free (temp_file);
1550 continue;
1552 else
1554 g_free (test);
1555 break;
1559 priv->shared_mem_str = temp_file;
1561 if ((priv->shared_mem_fd =
1562 shm_open (temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
1564 g_error ("Error while trying to open a shared memory file. Be"
1565 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
1568 priv->shared_mem_file = fdopen (priv->shared_mem_fd, "a+b");
1570 /* no need to free temp_file (alias shared_mem_str). It will be freed on plugin finalize */
1573 /* Sort the files to have sources before headers */
1574 g_ptr_array_sort (files_list, sdb_sort_files_list);
1575 if (real_files_list)
1576 g_ptr_array_sort (real_files_list, sdb_sort_files_list);
1578 for (i = 0; i < files_list->len; i++)
1580 GFile *gfile;
1581 ScanFiles1Data *sf_data;
1582 gchar *node = (gchar *) g_ptr_array_index (files_list, i);
1583 gfile = g_file_new_for_path (node);
1585 /* prepare an ojbect where to store some data for the async call */
1586 sf_data = g_new0 (ScanFiles1Data, 1);
1587 sf_data->dbe = dbe;
1588 sf_data->files_list_len = files_list->len;
1589 sf_data->partial_count = i;
1590 sf_data->symbols_update = symbols_update;
1592 if (real_files_list != NULL)
1594 sf_data->real_file = g_strdup (g_ptr_array_index (real_files_list, i));
1596 else
1598 sf_data->real_file = NULL;
1601 /* call it */
1602 g_file_query_info_async (gfile,
1603 G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
1604 G_FILE_QUERY_INFO_NONE,
1605 G_PRIORITY_LOW,
1606 NULL,
1607 (GAsyncReadyCallback)sdb_engine_scan_files_2,
1608 sf_data);
1611 return TRUE;
1614 static void
1615 on_scan_files_async_end (SymbolDBEngine *dbe, gint process_id, gpointer user_data)
1617 SymbolDBEnginePriv *priv;
1618 EngineScanDataAsync *esda;
1620 priv = dbe->priv;
1622 /* fine, check on the queue if there's something left to scan */
1623 if ((esda = g_async_queue_try_pop (priv->waiting_scan_aqueue)) == NULL)
1624 return;
1626 sdb_engine_scan_files_1 (dbe, esda->files_list, esda->real_files_list,
1627 esda->symbols_update, esda->scan_id);
1629 sdb_engine_scan_data_destroy (esda);
1632 static gboolean
1633 sdb_engine_scan_files_async (SymbolDBEngine * dbe, GPtrArray * files_list,
1634 GPtrArray *real_files_list, gboolean symbols_update,
1635 gint scan_id)
1637 SymbolDBEnginePriv *priv;
1638 g_return_val_if_fail (files_list != NULL, FALSE);
1640 if (files_list->len == 0)
1641 return FALSE;
1643 priv = dbe->priv;
1645 if (real_files_list != NULL && (files_list->len != real_files_list->len))
1647 g_warning ("no matched size between real_files_list and files_list");
1648 return FALSE;
1651 /* is the engine scanning or is there already something waiting on the queue? */
1652 if (symbol_db_engine_is_scanning (dbe) == TRUE ||
1653 g_async_queue_length (priv->waiting_scan_aqueue) > 0)
1655 /* push the data into the queue for later retrieval */
1656 EngineScanDataAsync * esda = g_new0 (EngineScanDataAsync, 1);
1658 esda->files_list = anjuta_util_clone_string_gptrarray (files_list);
1659 if (real_files_list)
1660 esda->real_files_list = anjuta_util_clone_string_gptrarray (real_files_list);
1661 else
1662 esda->real_files_list = NULL;
1663 esda->symbols_update = symbols_update;
1664 esda->scan_id = scan_id;
1666 g_async_queue_push (priv->waiting_scan_aqueue, esda);
1667 return TRUE;
1670 /* there's no scan active right now nor data waiting on the queue.
1671 * Proceed with normal scan.
1673 sdb_engine_scan_files_1 (dbe, files_list, real_files_list, symbols_update, scan_id);
1675 return TRUE;
1678 static void
1679 sdb_engine_init (SymbolDBEngine * object)
1681 SymbolDBEngine *sdbe;
1682 GHashTable *h;
1684 sdbe = SYMBOL_DB_ENGINE (object);
1685 sdbe->priv = g_new0 (SymbolDBEnginePriv, 1);
1687 sdbe->priv->db_connection = NULL;
1688 sdbe->priv->sql_parser = NULL;
1689 sdbe->priv->db_directory = NULL;
1690 sdbe->priv->project_directory = NULL;
1691 sdbe->priv->cnc_string = NULL;
1693 /* initialize an hash table to be used and shared with Iterators */
1694 sdbe->priv->sym_type_conversion_hash =
1695 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1696 h = sdbe->priv->sym_type_conversion_hash;
1698 /* please if you change some value below here remember to change also on */
1699 g_hash_table_insert (h, g_strdup("class"),
1700 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_CLASS));
1702 g_hash_table_insert (h, g_strdup("enum"),
1703 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUM));
1705 g_hash_table_insert (h, g_strdup("enumerator"),
1706 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUMERATOR));
1708 g_hash_table_insert (h, g_strdup("field"),
1709 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FIELD));
1711 g_hash_table_insert (h, g_strdup("function"),
1712 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FUNCTION));
1714 g_hash_table_insert (h, g_strdup("interface"),
1715 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_INTERFACE));
1717 g_hash_table_insert (h, g_strdup("member"),
1718 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MEMBER));
1720 g_hash_table_insert (h, g_strdup("method"),
1721 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_METHOD));
1723 g_hash_table_insert (h, g_strdup("namespace"),
1724 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_NAMESPACE));
1726 g_hash_table_insert (h, g_strdup("package"),
1727 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PACKAGE));
1729 g_hash_table_insert (h, g_strdup("prototype"),
1730 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PROTOTYPE));
1732 g_hash_table_insert (h, g_strdup("struct"),
1733 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_STRUCT));
1735 g_hash_table_insert (h, g_strdup("typedef"),
1736 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_TYPEDEF));
1738 g_hash_table_insert (h, g_strdup("union"),
1739 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_UNION));
1741 g_hash_table_insert (h, g_strdup("variable"),
1742 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_VARIABLE));
1744 g_hash_table_insert (h, g_strdup("externvar"),
1745 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_EXTERNVAR));
1747 g_hash_table_insert (h, g_strdup("macro"),
1748 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO));
1750 g_hash_table_insert (h, g_strdup("macro_with_arg"),
1751 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG));
1753 g_hash_table_insert (h, g_strdup("file"),
1754 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FILE));
1756 g_hash_table_insert (h, g_strdup("other"),
1757 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_OTHER));
1760 /* create the hash table that will store shared memory files strings used for
1761 * buffer scanning. Un Engine destroy will unlink () them.
1763 sdbe->priv->garbage_shared_mem_files = g_hash_table_new_full (g_str_hash, g_str_equal,
1764 g_free, NULL);
1766 sdbe->priv->ctags_launcher = NULL;
1767 sdbe->priv->removed_launchers = NULL;
1768 sdbe->priv->shutting_down = FALSE;
1769 sdbe->priv->is_first_population = FALSE;
1771 sdbe->priv->symbols_scanned_count = 0;
1773 /* set the ctags executable path to NULL */
1774 sdbe->priv->ctags_path = NULL;
1776 /* NULL the name of the default db */
1777 sdbe->priv->anjuta_db_file = NULL;
1779 /* identify the scan process with an id. There can be multiple files associated
1780 * within a process. A call to scan_files () will put inside the queue an id
1781 * returned and emitted by scan-end.
1783 sdbe->priv->scan_process_id_sequence = sdbe->priv->current_scan_process_id = 1;
1785 /* the scan_aqueue? It will contain mainly
1786 * ints that refer to the force_update status.
1788 sdbe->priv->scan_aqueue = g_async_queue_new ();
1790 /* the thread pool for tags scannning */
1791 sdbe->priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
1792 sdbe, THREADS_MAX_CONCURRENT,
1793 FALSE, NULL);
1795 /* initialize the sdb mutex */
1796 g_mutex_init (&sdbe->priv->mutex);
1798 /* some signals queues */
1799 sdbe->priv->signals_aqueue = g_async_queue_new ();
1800 sdbe->priv->updated_syms_id_aqueue = g_async_queue_new ();
1801 sdbe->priv->updated_scope_syms_id_aqueue = g_async_queue_new ();
1802 sdbe->priv->inserted_syms_id_aqueue = g_async_queue_new ();
1803 sdbe->priv->is_scanning = FALSE;
1805 sdbe->priv->waiting_scan_aqueue = g_async_queue_new_full (sdb_engine_scan_data_destroy);
1806 sdbe->priv->waiting_scan_handler = g_signal_connect (G_OBJECT (sdbe), "scan-end",
1807 G_CALLBACK (on_scan_files_async_end), NULL);
1811 * STATIC QUERY STRUCTURE INITIALIZE
1814 /* -- workspace -- */
1815 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1816 PREP_QUERY_WORKSPACE_NEW,
1817 "INSERT INTO workspace (workspace_name, analyse_time) VALUES (\
1818 ## /* name:'wsname' type:gchararray */, \
1819 datetime ('now', 'localtime'))");
1821 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1822 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
1823 "SELECT workspace_id FROM workspace \
1824 WHERE \
1825 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1");
1827 /* -- project -- */
1828 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1829 PREP_QUERY_PROJECT_NEW,
1830 "INSERT INTO project (project_name, project_version, wrkspace_id, analyse_time) VALUES (\
1831 ## /* name:'prjname' type:gchararray */, \
1832 ## /* name:'prjversion' type:gchararray */, \
1833 (SELECT workspace_id FROM workspace \
1834 WHERE \
1835 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1), \
1836 datetime ('now', 'localtime'))");
1838 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1839 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME,
1840 "SELECT project_id FROM project \
1841 WHERE \
1842 project_name = ## /* name:'prjname' type:gchararray */ AND \
1843 project_version = ## /* name:'prjversion' type:gchararray */ \
1844 LIMIT 1");
1846 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1847 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME,
1848 "UPDATE project SET \
1849 analyse_time = datetime('now', 'localtime', '+10 seconds') \
1850 WHERE \
1851 project_name = ## /* name:'prjname' type:gchararray */");
1853 /* -- file -- */
1854 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1855 PREP_QUERY_FILE_NEW,
1856 "INSERT INTO file (file_path, prj_id, lang_id, analyse_time) VALUES (\
1857 ## /* name:'filepath' type:gchararray */, \
1858 (SELECT project_id FROM project \
1859 WHERE \
1860 project_name = ## /* name:'prjname' type:gchararray */ AND \
1861 project_version = ## /* name:'prjversion' type:gchararray */ \
1862 LIMIT 1), \
1863 ## /* name:'langid' type:gint */, \
1864 datetime ('now', 'localtime'))");
1866 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1867 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
1868 "SELECT file_id FROM file \
1869 WHERE \
1870 file_path = ## /* name:'filepath' type:gchararray */ LIMIT 1");
1872 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1873 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME,
1874 "SELECT file_id, file_path AS db_file_path, prj_id, lang_id, file.analyse_time \
1875 FROM file JOIN project ON project.project_id = file.prj_id \
1876 WHERE \
1877 project.project_name = ## /* name:'prjname' type:gchararray */");
1879 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1880 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME,
1881 "UPDATE file SET \
1882 analyse_time = datetime('now', 'localtime') \
1883 WHERE \
1884 file_path = ## /* name:'filepath' type:gchararray */");
1886 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1887 PREP_QUERY_GET_ALL_FROM_FILE_WHERE_NOT_IN_SYMBOLS,
1888 "SELECT file_id, file_path AS db_file_path FROM file \
1889 WHERE file_id NOT IN (SELECT file_defined_id FROM symbol)");
1891 /* -- language -- */
1892 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1893 PREP_QUERY_LANGUAGE_NEW,
1894 "INSERT INTO language (language_name) VALUES (\
1895 ## /* name:'langname' type:gchararray */)");
1897 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1898 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
1899 "SELECT language_id FROM language WHERE \
1900 language_name = ## /* name:'langname' type:gchararray */ LIMIT 1");
1902 /* -- sym kind -- */
1903 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1904 PREP_QUERY_SYM_KIND_NEW,
1905 "INSERT INTO sym_kind (kind_name, is_container) VALUES(\
1906 ## /* name:'kindname' type:gchararray */, \
1907 ## /* name:'container' type:gint */)");
1909 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1910 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
1911 "SELECT sym_kind_id FROM sym_kind WHERE \
1912 kind_name = ## /* name:'kindname' type:gchararray */");
1914 /* -- sym access -- */
1915 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1916 PREP_QUERY_SYM_ACCESS_NEW,
1917 "INSERT INTO sym_access (access_name) VALUES(\
1918 ## /* name:'accesskind' type:gchararray */)");
1920 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1921 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
1922 "SELECT access_kind_id FROM sym_access WHERE \
1923 access_name = ## /* name:'accesskind' type:gchararray */ LIMIT 1");
1925 /* -- sym implementation -- */
1926 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1927 PREP_QUERY_SYM_IMPLEMENTATION_NEW,
1928 "INSERT INTO sym_implementation (implementation_name) VALUES(\
1929 ## /* name:'implekind' type:gchararray */)");
1931 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1932 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
1933 "SELECT sym_impl_id FROM sym_implementation WHERE \
1934 kind = ## /* name:'implekind' type:gchararray */ LIMIT 1");
1936 /* -- heritage -- */
1937 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1938 PREP_QUERY_HERITAGE_NEW,
1939 "INSERT INTO heritage (symbol_id_base, symbol_id_derived) VALUES(\
1940 ## /* name:'symbase' type:gint */, \
1941 ## /* name:'symderived' type:gint */)");
1943 /* -- scope -- */
1944 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1945 PREP_QUERY_SCOPE_NEW,
1946 "INSERT INTO scope (scope_name) VALUES(\
1947 ## /* name:'scope' type:gchararray */)");
1949 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1950 PREP_QUERY_GET_SCOPE_ID,
1951 "SELECT scope_id FROM scope \
1952 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1953 LIMIT 1");
1955 /* -- symbol -- */
1956 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1957 PREP_QUERY_SYMBOL_NEW,
1958 "INSERT INTO symbol (file_defined_id, name, file_position, \
1959 is_file_scope, signature, returntype, \
1960 scope_definition_id, scope_id, \
1961 type_type, type_name, kind_id, access_kind_id, \
1962 implementation_kind_id, update_flag) \
1963 VALUES( \
1964 ## /* name:'filedefid' type:gint */, \
1965 ## /* name:'name' type:gchararray */, \
1966 ## /* name:'fileposition' type:gint */, \
1967 ## /* name:'isfilescope' type:gint */, \
1968 ## /* name:'signature' type:gchararray */, \
1969 ## /* name:'returntype' type:gchararray */, \
1970 ## /* name:'scopedefinitionid' type:gint */, \
1971 ## /* name:'scopeid' type:gint */, \
1972 ## /* name:'typetype' type:gchararray */, \
1973 ## /* name:'typename' type:gchararray */, \
1974 ## /* name:'kindid' type:gint */,## /* name:'accesskindid' type:gint */, \
1975 ## /* name:'implementationkindid' type:gint */, \
1976 ## /* name:'updateflag' type:gint */)");
1979 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1980 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
1981 "SELECT symbol_id FROM symbol \
1982 WHERE scope_id = 0 AND \
1983 type_type='class' AND \
1984 name = ## /* name:'klassname' type:gchararray */ LIMIT 1");
1986 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1987 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
1988 "SELECT symbol_id FROM symbol JOIN scope ON symbol.scope_id = scope.scope_id \
1989 WHERE symbol.name = ## /* name:'klassname' type:gchararray */ AND \
1990 scope.scope_name = ## /* name:'namespacename' type:gchararray */ AND \
1991 symbol.type_type = 'namespace' LIMIT 1");
1993 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1994 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID,
1995 "UPDATE OR IGNORE symbol SET scope_id = (SELECT scope_definition_id FROM symbol WHERE \
1996 type_type = ## /* name:'tokenname' type:gchararray */ AND \
1997 type_name = ## /* name:'objectname' type:gchararray */ LIMIT 1) \
1998 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
2000 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2001 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
2002 "SELECT symbol_id FROM symbol \
2003 WHERE \
2004 name = ## /* name:'symname' type:gchararray */ AND \
2005 file_defined_id = ## /* name:'filedefid' type:gint */ AND \
2006 type_type = ## /* name:'typetype' type:gchararray */ AND \
2007 type_name = ## /* name:'typename' type:gchararray */ AND \
2008 update_flag = 0 \
2009 ORDER BY abs(file_position - ## /* name:'fileposition' type:gint */) \
2010 LIMIT 1");
2012 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2013 PREP_QUERY_UPDATE_SYMBOL_ALL,
2014 "UPDATE symbol SET \
2015 is_file_scope = ## /* name:'isfilescope' type:gint */, \
2016 file_position = ## /* name:'fileposition' type:gint */, \
2017 signature = ## /* name:'signature' type:gchararray */, \
2018 returntype = ## /* name:'returntype' type:gchararray */, \
2019 scope_definition_id = ## /* name:'scopedefinitionid' type:gint */, \
2020 scope_id = ## /* name:'scopeid' type:gint */, \
2021 kind_id = ## /* name:'kindid' type:gint */, \
2022 access_kind_id = ## /* name:'accesskindid' type:gint */, \
2023 implementation_kind_id = ## /* name:'implementationkindid' type:gint */, \
2024 update_flag = ## /* name:'updateflag' type:gint */ \
2025 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
2027 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2028 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS,
2029 "DELETE FROM symbol WHERE \
2030 file_defined_id = (SELECT file_id FROM file \
2031 WHERE \
2032 file.file_path = ## /* name:'filepath' type:gchararray */) AND \
2033 update_flag = 0");
2035 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2036 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS,
2037 "UPDATE symbol SET \
2038 update_flag = 0 \
2039 WHERE file_defined_id = (SELECT file_id FROM file \
2040 WHERE \
2041 file_path = ## /* name:'filepath' type:gchararray */)");
2043 /* -- tmp_removed -- */
2044 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2045 PREP_QUERY_GET_REMOVED_IDS,
2046 "SELECT symbol_removed_id FROM __tmp_removed");
2048 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2049 PREP_QUERY_TMP_REMOVED_DELETE_ALL,
2050 "DELETE FROM __tmp_removed");
2052 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2053 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME,
2054 "DELETE FROM file WHERE \
2055 prj_id = (SELECT project_id FROM project \
2056 WHERE project_name = ## /* name:'prjname' type:gchararray */) AND \
2057 file_path = ## /* name:'filepath' type:gchararray */");
2059 /* init cache hashtables */
2060 sdb_engine_init_caches (sdbe);
2062 /* init table maps */
2063 sdb_engine_init_table_maps (sdbe);
2066 static void
2067 sdb_engine_unlink_shared_files (gpointer key, gpointer value, gpointer user_data)
2069 shm_unlink (key);
2072 static void
2073 sdb_engine_unref_removed_launchers (gpointer data, gpointer user_data)
2075 g_object_unref (data);
2078 static void
2079 sdb_engine_finalize (GObject * object)
2081 SymbolDBEngine *dbe;
2082 SymbolDBEnginePriv *priv;
2084 dbe = SYMBOL_DB_ENGINE (object);
2085 priv = dbe->priv;
2086 /*/ FIXME a crash here ?!
2087 g_signal_handler_disconnect (dbe, priv->waiting_scan_handler);
2088 priv->waiting_scan_handler = 0;
2089 //*/
2090 if (priv->thread_pool)
2092 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2093 priv->thread_pool = NULL;
2096 if (priv->ctags_launcher)
2098 g_object_unref (priv->ctags_launcher);
2099 priv->ctags_launcher = NULL;
2102 if (priv->removed_launchers)
2104 g_list_foreach (priv->removed_launchers,
2105 sdb_engine_unref_removed_launchers, NULL);
2106 g_list_free (priv->removed_launchers);
2107 priv->removed_launchers = NULL;
2110 g_mutex_clear (&priv->mutex);
2112 if (priv->timeout_trigger_handler > 0)
2113 g_source_remove (priv->timeout_trigger_handler);
2115 if (symbol_db_engine_is_connected (dbe) == TRUE)
2116 sdb_engine_disconnect_from_db (dbe);
2118 sdb_engine_free_cached_queries (dbe);
2120 if (priv->scan_aqueue)
2122 g_async_queue_unref (priv->scan_aqueue);
2123 priv->scan_aqueue = NULL;
2126 if (priv->updated_syms_id_aqueue)
2128 g_async_queue_unref (priv->updated_syms_id_aqueue);
2129 priv->updated_syms_id_aqueue = NULL;
2132 if (priv->updated_scope_syms_id_aqueue)
2134 g_async_queue_unref (priv->updated_scope_syms_id_aqueue);
2135 priv->updated_scope_syms_id_aqueue = NULL;
2138 if (priv->inserted_syms_id_aqueue)
2140 g_async_queue_unref (priv->inserted_syms_id_aqueue);
2141 priv->inserted_syms_id_aqueue = NULL;
2144 if (priv->waiting_scan_aqueue)
2146 g_async_queue_unref (priv->waiting_scan_aqueue);
2147 priv->waiting_scan_aqueue = NULL;
2150 if (priv->shared_mem_file)
2152 fclose (priv->shared_mem_file);
2153 priv->shared_mem_file = NULL;
2156 if (priv->shared_mem_str)
2158 shm_unlink (priv->shared_mem_str);
2159 g_free (priv->shared_mem_str);
2160 priv->shared_mem_str = NULL;
2163 if (priv->garbage_shared_mem_files)
2165 g_hash_table_foreach (priv->garbage_shared_mem_files,
2166 sdb_engine_unlink_shared_files,
2167 NULL);
2168 /* destroy the hash table */
2169 g_hash_table_destroy (priv->garbage_shared_mem_files);
2173 if (priv->sym_type_conversion_hash)
2174 g_hash_table_destroy (priv->sym_type_conversion_hash);
2175 priv->sym_type_conversion_hash = NULL;
2177 if (priv->signals_aqueue)
2178 g_async_queue_unref (priv->signals_aqueue);
2179 priv->signals_aqueue = NULL;
2181 sdb_engine_clear_caches (dbe);
2182 sdb_engine_clear_tablemaps (dbe);
2184 g_free (priv->anjuta_db_file);
2185 priv->anjuta_db_file = NULL;
2187 g_free (priv->ctags_path);
2188 priv->ctags_path = NULL;
2190 g_free (priv);
2192 G_OBJECT_CLASS (parent_class)->finalize (object);
2195 static void
2196 sdb_engine_class_init (SymbolDBEngineClass * klass)
2198 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2199 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2201 object_class->finalize = sdb_engine_finalize;
2203 signals[DB_CONNECTED]
2204 = g_signal_new ("db-connected",
2205 G_OBJECT_CLASS_TYPE (object_class),
2206 G_SIGNAL_RUN_LAST,
2207 G_STRUCT_OFFSET (SymbolDBEngineClass, db_connected),
2208 NULL, NULL,
2209 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2211 signals[DB_DISCONNECTED]
2212 = g_signal_new ("db-disconnected",
2213 G_OBJECT_CLASS_TYPE (object_class),
2214 G_SIGNAL_RUN_LAST,
2215 G_STRUCT_OFFSET (SymbolDBEngineClass, db_disconnected),
2216 NULL, NULL,
2217 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2219 signals[SCAN_BEGIN]
2220 = g_signal_new ("scan-begin",
2221 G_OBJECT_CLASS_TYPE (object_class),
2222 G_SIGNAL_RUN_LAST,
2223 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_begin),
2224 NULL, NULL,
2225 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2227 G_TYPE_INT);
2229 signals[SINGLE_FILE_SCAN_END]
2230 = g_signal_new ("single-file-scan-end",
2231 G_OBJECT_CLASS_TYPE (object_class),
2232 G_SIGNAL_RUN_FIRST,
2233 G_STRUCT_OFFSET (SymbolDBEngineClass, single_file_scan_end),
2234 NULL, NULL,
2235 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2237 signals[SCAN_END]
2238 = g_signal_new ("scan-end",
2239 G_OBJECT_CLASS_TYPE (object_class),
2240 G_SIGNAL_RUN_LAST,
2241 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_end),
2242 NULL, NULL,
2243 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2245 G_TYPE_INT);
2247 signals[SYMBOL_INSERTED]
2248 = g_signal_new ("symbol-inserted",
2249 G_OBJECT_CLASS_TYPE (object_class),
2250 G_SIGNAL_RUN_LAST,
2251 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_inserted),
2252 NULL, NULL,
2253 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2255 G_TYPE_INT);
2257 signals[SYMBOL_UPDATED]
2258 = g_signal_new ("symbol-updated",
2259 G_OBJECT_CLASS_TYPE (object_class),
2260 G_SIGNAL_RUN_LAST,
2261 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_updated),
2262 NULL, NULL,
2263 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2265 G_TYPE_INT);
2267 signals[SYMBOL_SCOPE_UPDATED]
2268 = g_signal_new ("symbol-scope-updated",
2269 G_OBJECT_CLASS_TYPE (object_class),
2270 G_SIGNAL_RUN_LAST,
2271 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_scope_updated),
2272 NULL, NULL,
2273 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2275 G_TYPE_INT);
2277 signals[SYMBOL_REMOVED]
2278 = g_signal_new ("symbol-removed",
2279 G_OBJECT_CLASS_TYPE (object_class),
2280 G_SIGNAL_RUN_LAST,
2281 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_removed),
2282 NULL, NULL,
2283 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2285 G_TYPE_INT);
2288 GType
2289 sdb_engine_get_type (void)
2291 static GType our_type = 0;
2293 if (our_type == 0)
2295 static const GTypeInfo our_info = {
2296 sizeof (SymbolDBEngineClass), /* class_size */
2297 (GBaseInitFunc) NULL, /* base_init */
2298 (GBaseFinalizeFunc) NULL, /* base_finalize */
2299 (GClassInitFunc) sdb_engine_class_init, /* class_init */
2300 (GClassFinalizeFunc) NULL, /* class_finalize */
2301 NULL /* class_data */ ,
2302 sizeof (SymbolDBEngine), /* instance_size */
2303 0, /* n_preallocs */
2304 (GInstanceInitFunc) sdb_engine_init, /* instance_init */
2305 NULL /* value_table */
2308 our_type = g_type_register_static (G_TYPE_OBJECT, "SymbolDBEngine",
2309 &our_info, 0);
2312 return our_type;
2316 * symbol_db_engine_set_ctags_path:
2317 * @dbe: self
2318 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2320 * Set a new path for anjuta-tags executable.
2322 * Returns: TRUE if the set is successful.
2324 gboolean
2325 symbol_db_engine_set_ctags_path (SymbolDBEngine * dbe, const gchar * ctags_path)
2327 SymbolDBEnginePriv *priv;
2329 g_return_val_if_fail (dbe != NULL, FALSE);
2330 g_return_val_if_fail (ctags_path != NULL, FALSE);
2332 priv = dbe->priv;
2334 /* Check if ctags is really installed */
2335 if (!anjuta_util_prog_is_installed (ctags_path, TRUE))
2337 g_warning ("symbol_db_engine_set_ctags_path (): Wrong path for ctags. Keeping "
2338 "the old value %s", priv->ctags_path);
2339 return priv->ctags_path != NULL;
2342 /* have we already got it? */
2343 if (priv->ctags_path != NULL &&
2344 g_strcmp0 (priv->ctags_path, ctags_path) == 0)
2345 return TRUE;
2347 /* free the old value */
2348 g_free (priv->ctags_path);
2350 /* is anjutalauncher already created? */
2351 if (priv->ctags_launcher != NULL)
2353 AnjutaLauncher *tmp;
2354 tmp = priv->ctags_launcher;
2356 /* recreate it on the fly */
2357 sdb_engine_ctags_launcher_create (dbe);
2359 /* keep the launcher alive to avoid crashes */
2360 priv->removed_launchers = g_list_prepend (priv->removed_launchers, tmp);
2363 /* set the new one */
2364 priv->ctags_path = g_strdup (ctags_path);
2365 return TRUE;
2369 * symbol_db_engine_new:
2370 * @ctags_path Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2372 * Create a new instance of an engine.
2373 * Default name of database is ANJUTA_DB_FILE (see symbol-db-engine-priv.h)
2375 * Returns: a new SymbolDBEngine object.
2377 SymbolDBEngine *
2378 symbol_db_engine_new (const gchar * ctags_path)
2380 SymbolDBEngine *sdbe;
2381 SymbolDBEnginePriv *priv;
2383 g_return_val_if_fail (ctags_path != NULL, NULL);
2384 sdbe = g_object_new (SYMBOL_TYPE_DB_ENGINE, NULL);
2386 priv = sdbe->priv;
2387 priv->anjuta_db_file = g_strdup (ANJUTA_DB_FILE);
2389 /* set the mandatory ctags_path */
2390 if (!symbol_db_engine_set_ctags_path (sdbe, ctags_path))
2392 return NULL;
2395 return sdbe;
2399 * symbol_db_engine_new_full:
2400 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2401 * @database_name: name of resulting db on disk.
2403 * Similar to symbol_db_engine_new() but you can specify the name of resulting db.
2405 SymbolDBEngine*
2406 symbol_db_engine_new_full (const gchar * ctags_path, const gchar * database_name)
2408 SymbolDBEngine* dbe;
2409 SymbolDBEnginePriv* priv;
2411 g_return_val_if_fail (database_name != NULL, NULL);
2412 dbe = symbol_db_engine_new (ctags_path);
2414 g_return_val_if_fail (dbe != NULL, NULL);
2416 priv = dbe->priv;
2417 g_free (priv->anjuta_db_file);
2418 priv->anjuta_db_file = g_strdup (database_name);
2420 return dbe;
2424 * Set some default parameters to use with the current database.
2426 static void
2427 sdb_engine_set_defaults_db_parameters (SymbolDBEngine * dbe)
2429 sdb_engine_execute_unknown_sql (dbe, "PRAGMA page_size = 32768");
2430 sdb_engine_execute_unknown_sql (dbe, "PRAGMA cache_size = 12288");
2431 sdb_engine_execute_unknown_sql (dbe, "PRAGMA synchronous = OFF");
2432 sdb_engine_execute_unknown_sql (dbe, "PRAGMA temp_store = MEMORY");
2433 sdb_engine_execute_unknown_sql (dbe, "PRAGMA journal_mode = OFF");
2434 sdb_engine_execute_unknown_sql (dbe, "PRAGMA read_uncommitted = 1");
2435 sdb_engine_execute_unknown_sql (dbe, "PRAGMA foreign_keys = OFF");
2436 symbol_db_engine_set_db_case_sensitive (dbe, TRUE);
2439 /* Will create priv->db_connection.
2440 * Connect to database identified by db_directory.
2441 * Usually db_directory is defined also into priv. We let it here as parameter
2442 * because it is required and cannot be null.
2444 static gboolean
2445 sdb_engine_connect_to_db (SymbolDBEngine * dbe, const gchar *cnc_string, GError **error)
2447 SymbolDBEnginePriv *priv;
2449 g_return_val_if_fail (dbe != NULL, FALSE);
2450 priv = dbe->priv;
2452 if (priv->db_connection != NULL)
2454 /* if it's the case that the connection isn't NULL, we
2455 * should notify the user
2456 * and return FALSE. It's his task to disconnect and retry to connect */
2457 g_warning ("connection is already established. Please disconnect "
2458 "and then try to reconnect.");
2459 return FALSE;
2462 /* establish a connection. If the sqlite file does not exist it will
2463 * be created
2465 priv->db_connection = gda_connection_open_from_string ("SQLite", cnc_string, NULL,
2466 #ifdef HAVE_GDA6
2467 GDA_CONNECTION_OPTIONS_NONE,
2468 #else
2469 GDA_CONNECTION_OPTIONS_THREAD_SAFE,
2470 #endif
2471 error);
2473 if (!GDA_IS_CONNECTION (priv->db_connection))
2475 g_warning ("Could not open connection to %s\n", cnc_string);
2476 return FALSE;
2479 priv->cnc_string = g_strdup (cnc_string);
2480 priv->sql_parser = gda_connection_create_parser (priv->db_connection);
2482 if (!GDA_IS_SQL_PARSER (priv->sql_parser))
2484 g_set_error_literal (error, SYMBOL_DB_ENGINE_ERROR,
2485 SYMBOL_DB_ENGINE_ERROR_INVALID_PARSER,
2486 _("Could not create sql parser. Check your libgda installation"));
2487 return FALSE;
2490 DEBUG_PRINT ("Connected to database %s", cnc_string);
2491 return TRUE;
2495 * symbol_db_engine_is_connected:
2496 * @dbe: self
2498 * Check whether the engine is connected to db or not.
2500 * Returns: TRUE if the db is connected.
2502 gboolean
2503 symbol_db_engine_is_connected (SymbolDBEngine * dbe)
2505 SymbolDBEnginePriv *priv;
2507 g_return_val_if_fail (dbe != NULL, FALSE);
2508 priv = dbe->priv;
2510 return priv->db_connection && priv->cnc_string && priv->sql_parser &&
2511 gda_connection_is_opened (priv->db_connection );
2515 * symbol_db_engine_is_scanning:
2516 * @dbe: self
2518 * Check if engine is scanning busy
2520 * Returns: TRUE if it is scanning.
2522 gboolean
2523 symbol_db_engine_is_scanning (SymbolDBEngine *dbe)
2525 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), FALSE);
2526 return dbe->priv->is_scanning;
2530 * Creates required tables for the database to work.
2531 * Sets is_first_population flag to TRUE.
2532 * @param tables_sql_file File containing sql code.
2534 static gboolean
2535 sdb_engine_create_db_tables (SymbolDBEngine * dbe, const gchar * tables_sql_file)
2537 SymbolDBEnginePriv *priv;
2538 gchar *contents;
2539 gchar *query;
2540 gsize sizez;
2542 g_return_val_if_fail (tables_sql_file != NULL, FALSE);
2544 priv = dbe->priv;
2546 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2548 /* read the contents of the file */
2549 if (g_file_get_contents (tables_sql_file, &contents, &sizez, NULL) == FALSE)
2551 g_warning ("Something went wrong while trying to read %s",
2552 tables_sql_file);
2554 return FALSE;
2557 sdb_engine_execute_non_select_sql (dbe, contents);
2558 g_free (contents);
2560 /* set the current symbol db database version. This may help if new tables/fields
2561 * are added/removed in future versions.
2563 query = "INSERT INTO version VALUES ("SYMBOL_DB_VERSION")";
2564 sdb_engine_execute_non_select_sql (dbe, query);
2566 priv->is_first_population = TRUE;
2568 /* no need to free query of course */
2570 return TRUE;
2574 * symbol_db_engine_db_exists:
2575 * @dbe: self
2576 * @prj_directory: absolute path of the project.
2578 * Check if the database already exists into the prj_directory
2580 * Returns: TRUE if db exists on disk.
2582 gboolean
2583 symbol_db_engine_db_exists (SymbolDBEngine * dbe, const gchar * prj_directory)
2585 SymbolDBEnginePriv *priv;
2587 g_return_val_if_fail (prj_directory != NULL, FALSE);
2589 priv = dbe->priv;
2591 /* check whether the db filename already exists.*/
2592 gchar *tmp_file = g_strdup_printf ("%s/%s.db", prj_directory,
2593 priv->anjuta_db_file);
2595 if (g_file_test (tmp_file, G_FILE_TEST_EXISTS) == FALSE)
2597 DEBUG_PRINT ("db %s does not exist", tmp_file);
2598 g_free (tmp_file);
2599 return FALSE;
2602 g_free (tmp_file);
2603 return TRUE;
2607 * symbol_db_engine_file_exists:
2608 * @dbe: self
2609 * @abs_file_path: absolute file path.
2611 * Check if a file is already present [and scanned] in db.
2612 * ~~~ Thread note: this function locks the mutex ~~~
2614 * Returns: TRUE if the file is present.
2616 gboolean
2617 symbol_db_engine_file_exists (SymbolDBEngine * dbe, const gchar * abs_file_path)
2619 SymbolDBEnginePriv *priv;
2620 const gchar *relative;
2621 gint file_defined_id;
2622 GValue v = {0};
2624 g_return_val_if_fail (dbe != NULL, FALSE);
2625 g_return_val_if_fail (abs_file_path != NULL, FALSE);
2627 priv = dbe->priv;
2629 SDB_LOCK(priv);
2631 relative = symbol_db_util_get_file_db_path (dbe, abs_file_path);
2632 if (relative == NULL)
2634 SDB_UNLOCK(priv);
2635 return FALSE;
2638 SDB_GVALUE_SET_STATIC_STRING(v, relative);
2640 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2641 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
2642 "filepath",
2643 &v)) < 0)
2645 SDB_UNLOCK(priv);
2646 return FALSE;
2649 SDB_UNLOCK(priv);
2650 return TRUE;
2653 /**
2654 * symbol_db_engine_close_db:
2655 * @dbe: self
2657 * Disconnect db, gda client and db_connection
2659 * Returns: TRUE if closing has been successful.
2661 gboolean
2662 symbol_db_engine_close_db (SymbolDBEngine *dbe)
2664 SymbolDBEnginePriv *priv;
2665 gboolean ret;
2666 g_return_val_if_fail (dbe != NULL, FALSE);
2668 priv = dbe->priv;
2670 /* terminate threads, if ever they're running... */
2671 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2672 priv->thread_pool = NULL;
2673 ret = sdb_engine_disconnect_from_db (dbe);
2675 /* reset count */
2676 priv->symbols_scanned_count = 0;
2678 g_free (priv->db_directory);
2679 priv->db_directory = NULL;
2681 g_free (priv->project_directory);
2682 priv->project_directory = NULL;
2684 priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
2685 dbe, THREADS_MAX_CONCURRENT,
2686 FALSE, NULL);
2687 g_signal_emit_by_name (dbe, "db-disconnected", NULL);
2688 return ret;
2691 static gdouble
2692 sdb_engine_get_db_version (SymbolDBEngine *dbe)
2694 GdaDataModel *data_model;
2695 const GValue *value_id;
2696 gchar *query;
2697 gdouble version_id;
2698 gint col;
2700 /* set the current symbol db database version. This may help if new tables/fields
2701 * are added/removed in future versions.
2703 query = "SELECT sdb_version FROM version";
2704 if ((data_model = sdb_engine_execute_select_sql (dbe, query)) == NULL)
2706 return -1;
2709 col = gda_data_model_get_column_index(data_model, "sdb_version");
2710 value_id = gda_data_model_get_value_at (data_model, col, 0, NULL);
2712 if (G_VALUE_HOLDS_DOUBLE (value_id))
2713 version_id = g_value_get_double (value_id);
2714 else
2715 version_id = (gdouble)g_value_get_int (value_id);
2717 g_object_unref (data_model);
2718 /* no need to free query of course */
2720 return version_id;
2723 static gboolean
2724 sdb_engine_check_db_version_and_upgrade (SymbolDBEngine *dbe,
2725 const gchar* db_file,
2726 const gchar* cnc_string)
2728 gdouble version;
2731 version = sdb_engine_get_db_version (dbe);
2732 DEBUG_PRINT ("Checking db version...");
2733 if (version <= 0)
2735 /* some error occurred */
2736 g_warning ("No version of db detected. This can produce many errors. DB"
2737 "will be recreated from scratch.");
2739 /* force version to 0 */
2740 version = 0;
2743 if (version < atof (SYMBOL_DB_VERSION))
2745 DEBUG_PRINT ("Upgrading from version %f to "SYMBOL_DB_VERSION, version);
2747 /* we need a full recreation of db. Because of the sym_kind table
2748 * which changed its data but not its fields, we must recreate the
2749 * whole database.
2752 /* 1. disconnect from current db */
2753 sdb_engine_disconnect_from_db (dbe);
2755 /* 2. remove current db file */
2756 GFile *gfile = g_file_new_for_path (db_file);
2757 if (gfile != NULL) {
2758 g_file_delete (gfile, NULL, NULL);
2759 g_object_unref (gfile);
2761 else
2763 g_warning ("Could not get the gfile");
2766 /* 3. reconnect */
2767 sdb_engine_connect_to_db (dbe, cnc_string, NULL);
2769 /* 4. create fresh new tables, indexes, triggers etc. */
2770 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2771 return TRUE;
2773 else
2775 DEBUG_PRINT ("No need to upgrade.");
2778 return FALSE;
2782 * symbol_db_engine_open_db:
2783 * @dbe: self
2784 * @base_db_path: directory where .anjuta_sym_db.db will be stored. It can be
2785 * different from project_directory
2786 * E.g: a db on '/tmp/foo/' dir.
2787 * @prj_directory: project directory. It may be different from base_db_path.
2788 * It's mainly used to map files inside the db. Say for example that you want to
2789 * add to a project a file /home/user/project/foo_prj/src/file.c with a project
2790 * directory of /home/user/project/foo_prj/. On db it'll be represented as
2791 * src/file.c. In this way you can move around the project dir without dealing
2792 * with relative paths.
2793 * @error: a place to store an error, or %NULL
2795 * Open, create or upgrade a database at given directory.
2796 * Be sure to give a base_db_path with the ending '/' for directory.
2798 * Returns: An opening status from SymbolDBEngineOpenStatus enum.
2800 SymbolDBEngineOpenStatus
2801 symbol_db_engine_open_db (SymbolDBEngine * dbe, const gchar * base_db_path,
2802 const gchar * prj_directory, GError **error)
2804 SymbolDBEnginePriv *priv;
2805 gboolean needs_tables_creation = FALSE;
2806 gchar *cnc_string;
2807 gboolean connect_res;
2808 gboolean ret_status = DB_OPEN_STATUS_NORMAL;
2810 DEBUG_PRINT ("Opening project %s with base dir %s",
2811 prj_directory, base_db_path);
2813 g_return_val_if_fail (dbe != NULL, FALSE);
2814 g_return_val_if_fail (base_db_path != NULL, FALSE);
2816 priv = dbe->priv;
2818 priv->symbols_scanned_count = 0;
2820 /* check whether the db filename already exists. If it's not the case
2821 * create the tables for the database. */
2822 gchar *db_file = g_strdup_printf ("%s/%s.db", base_db_path,
2823 priv->anjuta_db_file);
2825 if (g_file_test (db_file, G_FILE_TEST_EXISTS) == FALSE)
2827 needs_tables_creation = TRUE;
2830 priv->db_directory = g_strdup (base_db_path);
2832 /* save the project_directory */
2833 priv->project_directory = g_strdup (prj_directory);
2835 cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", base_db_path,
2836 priv->anjuta_db_file);
2837 DEBUG_PRINT ("Connecting to "
2838 "database with %s...", cnc_string);
2839 connect_res = sdb_engine_connect_to_db (dbe, cnc_string, error);
2842 if (connect_res == FALSE)
2844 g_free (db_file);
2845 g_free (cnc_string);
2847 ret_status = DB_OPEN_STATUS_FATAL;
2848 return ret_status;
2851 if (needs_tables_creation == TRUE)
2853 DEBUG_PRINT ("Creating tables...");
2854 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2855 ret_status = DB_OPEN_STATUS_CREATE;
2857 else
2859 /* check the version of the db. If it's old we should upgrade it */
2860 if (sdb_engine_check_db_version_and_upgrade (dbe, db_file, cnc_string) == TRUE)
2862 ret_status = DB_OPEN_STATUS_UPGRADE;
2866 sdb_engine_set_defaults_db_parameters (dbe);
2868 g_free (cnc_string);
2869 g_free (db_file);
2871 /* we're now able to emit the db-connected signal: tables should be created
2872 * and libgda should be connected to an usable db.
2874 g_signal_emit_by_name (dbe, "db-connected", NULL);
2876 return ret_status;
2880 * symbol_db_engine_get_cnc_string:
2881 * @dbe: self
2883 * Getter for the connection string.
2885 * Returns: The connection string. It must be freed by caller.
2887 gchar *
2888 symbol_db_engine_get_cnc_string (SymbolDBEngine * dbe)
2890 SymbolDBEnginePriv *priv;
2892 g_return_val_if_fail (dbe != NULL, FALSE);
2893 priv = dbe->priv;
2895 return g_strdup (priv->cnc_string);
2898 /**
2899 * symbol_db_engine_add_new_workspace:
2900 * @dbe: self
2901 * @workspace_name: name of workspace.
2903 * Add a new workspace to an opened database.
2904 * ~~~ Thread note: this function locks the mutex ~~~
2906 * Returns: TRUE if operation is successful.
2908 gboolean
2909 symbol_db_engine_add_new_workspace (SymbolDBEngine * dbe,
2910 const gchar * workspace_name)
2912 const GdaSet *plist;
2913 const GdaStatement *stmt;
2914 GdaHolder *param;
2915 SymbolDBEnginePriv *priv;
2916 GValue v = {0};
2918 g_return_val_if_fail (dbe != NULL, FALSE);
2919 priv = dbe->priv;
2921 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2923 SDB_LOCK(priv);
2925 if ((stmt =
2926 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_WORKSPACE_NEW)) == NULL)
2928 g_warning ("query is null");
2929 SDB_UNLOCK(priv);
2930 return FALSE;
2933 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_WORKSPACE_NEW);
2935 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
2937 g_warning ("param is NULL from pquery!\n");
2938 SDB_UNLOCK(priv);
2939 return FALSE;
2941 SDB_PARAM_SET_STRING(param, workspace_name);
2943 /* execute the query with parameters just set */
2944 if (gda_connection_statement_execute_non_select (priv->db_connection,
2945 (GdaStatement*)stmt,
2946 (GdaSet*)plist, NULL, NULL) == -1)
2948 SDB_UNLOCK(priv);
2949 return FALSE;
2952 SDB_UNLOCK(priv);
2953 return TRUE;
2956 /**
2957 * symbol_db_engine_project_exists:
2958 * @dbe: self
2959 * @project_name: Project name.
2960 * @project_version: The version of the project.
2962 * Test project existence.
2963 * ~~~ Thread note: this function locks the mutex ~~~
2965 * Returns: FALSE if project isn't found. TRUE otherwise.
2967 gboolean
2968 symbol_db_engine_project_exists (SymbolDBEngine * dbe,
2969 const gchar * project_name,
2970 const gchar * project_version)
2972 SymbolDBEnginePriv *priv;
2973 GValue v = {0};
2974 const GdaSet *plist;
2975 const GdaStatement *stmt;
2976 GdaHolder *param;
2977 GdaDataModel *data_model;
2979 priv = dbe->priv;
2981 SDB_LOCK(priv);
2983 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2985 /* test the existence of the project in db */
2986 /* get prepared query */
2987 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
2988 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME)) == NULL)
2990 g_warning ("Query is null");
2991 SDB_UNLOCK(priv);
2992 return FALSE;
2995 plist = sdb_engine_get_query_parameters_list (dbe,
2996 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME);
2998 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3000 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
3001 "from pquery!\n");
3002 SDB_UNLOCK(priv);
3003 return FALSE;
3006 SDB_PARAM_SET_STRING (param, project_name);
3008 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3010 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
3011 "from pquery!\n");
3012 SDB_UNLOCK(priv);
3013 return FALSE;
3016 SDB_PARAM_SET_STRING (param, project_version);
3018 /* execute the query with parameters just set */
3019 data_model = gda_connection_statement_execute_select (priv->db_connection,
3020 (GdaStatement*)stmt,
3021 (GdaSet*)plist, NULL);
3023 if (!GDA_IS_DATA_MODEL (data_model) ||
3024 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
3026 if (data_model != NULL)
3027 g_object_unref (data_model);
3028 SDB_UNLOCK(priv);
3029 return FALSE;
3032 /* we found it and we can return */
3033 g_object_unref (data_model);
3035 SDB_UNLOCK(priv);
3037 return TRUE;
3040 /**
3041 * symbol_db_engine_add_new_project:
3042 * @dbe: self
3043 * @workspace: Can be NULL. In that case a default workspace will be created,
3044 * and project will depend on that.
3045 * @project: Project name. Must NOT be NULL.
3046 * @version: Version of the project, or of the package that project represents.
3047 * If not sure pass "1.0".
3049 * Adds a new project to db.
3050 * ~~~ Thread note: this function locks the mutex ~~~
3052 * Returns: TRUE if operation is successful.
3054 gboolean
3055 symbol_db_engine_add_new_project (SymbolDBEngine * dbe, const gchar * workspace,
3056 const gchar * project, const gchar* version)
3058 const GdaSet *plist;
3059 const GdaStatement *stmt;
3060 GdaHolder *param;
3061 const gchar *workspace_name;
3062 gint wks_id;
3063 SymbolDBEnginePriv *priv;
3064 GValue v = {0};
3066 g_return_val_if_fail (dbe != NULL, FALSE);
3067 priv = dbe->priv;
3069 SDB_LOCK(priv);
3071 if (workspace == NULL)
3073 workspace_name = "anjuta_workspace_default";
3075 DEBUG_PRINT ("adding default workspace... '%s'", workspace_name);
3076 SDB_GVALUE_SET_STATIC_STRING(v, workspace_name);
3078 if ((wks_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3079 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
3080 "wsname",
3081 &v)) <= 0)
3084 /* symbol_db_engine_add_new_workspace 'll lock so unlock here before */
3085 SDB_UNLOCK(priv);
3087 if (symbol_db_engine_add_new_workspace (dbe, workspace_name) == FALSE)
3089 DEBUG_PRINT ("%s", "Project cannot be added because a default workspace "
3090 "cannot be created");
3091 return FALSE;
3093 /* relock */
3094 SDB_LOCK(priv);
3097 else
3099 workspace_name = workspace;
3102 g_value_unset (&v);
3104 /* insert new project */
3105 if ((stmt =
3106 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_PROJECT_NEW)) == NULL)
3108 g_warning ("query is null");
3109 SDB_UNLOCK(priv);
3110 return FALSE;
3113 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_PROJECT_NEW);
3115 /* lookup parameters */
3116 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3118 g_warning ("param prjname is NULL from pquery!");
3119 SDB_UNLOCK(priv);
3120 return FALSE;
3123 SDB_PARAM_SET_STRING(param, project);
3125 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3127 g_warning ("param prjversion is NULL from pquery!");
3128 SDB_UNLOCK(priv);
3129 return FALSE;
3132 SDB_PARAM_SET_STRING(param, version);
3134 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
3136 g_warning ("param wsname is NULL from pquery!");
3137 SDB_UNLOCK(priv);
3138 return FALSE;
3141 SDB_PARAM_SET_STRING(param, workspace_name);
3143 /* execute the query with parameters just set */
3144 if (gda_connection_statement_execute_non_select (priv->db_connection,
3145 (GdaStatement*)stmt,
3146 (GdaSet*)plist, NULL, NULL) == -1)
3148 SDB_UNLOCK(priv);
3149 return FALSE;
3152 SDB_UNLOCK(priv);
3153 return TRUE;
3156 /* ### Thread note: this function inherits the mutex lock ### */
3157 /* Uses cache lookup to speed up symbols search. */
3158 static gint
3159 sdb_engine_add_new_language (SymbolDBEngine * dbe, const gchar *language)
3161 gint table_id;
3162 SymbolDBEnginePriv *priv;
3163 GValue v = {0};
3165 if (language == NULL)
3166 return -1;
3168 priv = dbe->priv;
3170 /* cache lookup */
3171 table_id = sdb_engine_cache_lookup (priv->language_cache, language);
3172 if (table_id != -1)
3174 return table_id;
3177 SDB_GVALUE_SET_STATIC_STRING (v, language);
3179 /* check for an already existing table with language "name". */
3180 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3181 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
3182 "langname",
3183 &v)) < 0)
3185 /* insert a new entry on db */
3186 const GdaSet *plist;
3187 const GdaStatement *stmt;
3188 GdaHolder *param;
3189 GdaSet *last_inserted = NULL;
3191 g_value_unset (&v);
3193 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_LANGUAGE_NEW))
3194 == NULL)
3196 g_warning ("query is null");
3197 return FALSE;
3200 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_LANGUAGE_NEW);
3202 if ((param = gda_set_get_holder ((GdaSet*)plist, "langname")) == NULL)
3204 g_warning ("param langname is NULL from pquery!");
3205 return FALSE;
3208 SDB_PARAM_SET_STRING(param, language);
3210 /* execute the query with parameters just set */
3211 if (gda_connection_statement_execute_non_select (priv->db_connection,
3212 (GdaStatement*)stmt,
3213 (GdaSet*)plist, &last_inserted,
3214 NULL) == -1)
3216 table_id = -1;
3218 else {
3219 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3220 table_id = g_value_get_int (value);
3221 sdb_engine_insert_cache (priv->language_cache, language, table_id);
3224 if (last_inserted)
3225 g_object_unref (last_inserted);
3228 return table_id;
3232 * ~~~ Thread note: this function locks the mutex ~~~
3234 * Add a file to project.
3235 * This function requires an opened db, i.e. calling before
3236 * symbol_db_engine_open_db ()
3237 * filepath: referes to a full file path.
3238 * project:
3239 * WARNING: we suppose that project_directory is already set.
3240 * WARNING2: we suppose that the given local_filepath include the project_directory path.
3241 * + correct example: local_filepath: /home/user/projects/foo_project/src/main.c
3242 * project_directory: /home/user/projects/foo_project
3243 * - wrong one: local_filepath: /tmp/foo.c
3244 * project_directory: /home/user/projects/foo_project
3246 static gboolean
3247 sdb_engine_add_new_db_file (SymbolDBEngine * dbe, const gchar * project_name,
3248 const gchar *project_version, const gchar * local_filepath,
3249 const gchar * language)
3251 const GdaSet *plist;
3252 const GdaStatement *stmt;
3253 GdaHolder *param;
3254 GError * error = NULL;
3255 SymbolDBEnginePriv *priv;
3256 gint language_id;
3257 GValue v = {0};
3259 priv = dbe->priv;
3261 /* check if the file is a correct one compared to the local_filepath */
3262 if (strstr (local_filepath, priv->project_directory) == NULL)
3263 return FALSE;
3265 SDB_LOCK(priv);
3267 /* we're gonna set the file relative to the project folder, not the full one.
3268 * e.g.: we have a file on disk: "/tmp/foo/src/file.c" and a db_directory located on
3269 * "/tmp/foo/". The entry on db will be "src/file.c"
3271 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, local_filepath);
3272 if (relative_path == NULL)
3274 DEBUG_PRINT ("%s", "relative_path == NULL");
3275 SDB_UNLOCK(priv);
3276 return FALSE;
3279 /* insert a new entry on db */
3280 language_id = sdb_engine_add_new_language (dbe, language);
3281 if (language_id < 0)
3283 DEBUG_PRINT ("Unknown language: %s", language);
3284 SDB_UNLOCK(priv);
3285 return FALSE;
3288 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_FILE_NEW))
3289 == NULL)
3291 g_warning ("query is null");
3292 SDB_UNLOCK(priv);
3293 return FALSE;
3296 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_FILE_NEW);
3298 /* filepath parameter */
3299 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
3301 g_warning ("param langname is NULL from pquery!");
3302 SDB_UNLOCK(priv);
3303 return FALSE;
3306 SDB_PARAM_SET_STRING(param, relative_path);
3308 /* project name parameter */
3309 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3311 g_warning ("param prjname is NULL from pquery!");
3312 SDB_UNLOCK(priv);
3313 return FALSE;
3316 SDB_PARAM_SET_STRING(param, project_name);
3318 /* prjversion parameter */
3319 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3321 g_warning ("param prjversion is NULL from pquery!");
3322 SDB_UNLOCK(priv);
3323 return FALSE;
3326 SDB_PARAM_SET_STRING(param, project_version);
3328 /* language id parameter */
3329 if ((param = gda_set_get_holder ((GdaSet*)plist, "langid")) == NULL)
3331 g_warning ("param langid is NULL from pquery!");
3332 SDB_UNLOCK(priv);
3333 return FALSE;
3336 SDB_PARAM_SET_INT(param, language_id);
3338 /* execute the query with parameters just set */
3339 if (gda_connection_statement_execute_non_select (priv->db_connection,
3340 (GdaStatement*)stmt,
3341 (GdaSet*)plist, NULL,
3342 &error) == -1)
3344 if (error)
3346 gchar * sql_str = gda_statement_to_sql_extended ((GdaStatement*)stmt,
3347 priv->db_connection, (GdaSet*)plist, 0, NULL, NULL);
3349 DEBUG_PRINT ("%s [%s]", error->message, sql_str);
3350 g_error_free (error);
3351 g_free (sql_str);
3354 SDB_UNLOCK(priv);
3355 return FALSE;
3358 SDB_UNLOCK(priv);
3359 return TRUE;
3362 /* ~~~ Thread note: this function locks the mutex ~~~ */
3363 static gint
3364 sdb_engine_get_unique_scan_id (SymbolDBEngine * dbe)
3366 SymbolDBEnginePriv *priv;
3367 gint ret_id;
3369 priv = dbe->priv;
3371 SDB_LOCK(priv);
3373 priv->scan_process_id_sequence++;
3374 ret_id = priv->scan_process_id_sequence;
3376 SDB_UNLOCK(priv);
3377 return ret_id;
3381 * symbol_db_engine_add_new_files_async:
3382 * @dbe: self
3383 * @lang_manager: IAnjutaLanguage language manager.
3384 * @project_name:
3385 * @project_version:
3386 * @sources_array: requires full path to files on disk. Anjuta-tags itself requires that.
3387 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3388 * a language string to represent the file.
3389 * An example of files_path array composition can be:
3390 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3391 * "/home/user/foo_project/foo3.java".
3392 * NOTE: all the files MUST exist. So check for their existence before call
3393 * this function. The function'll write entries on the db.
3395 * See symbol_db_engine_add_new_files_full () for doc.
3396 * This function adds files to db in a quicker way than
3397 * symbol_db_engine_add_new_files_full because you won't have to specify the
3398 * GPtrArray of languages, but it'll try to autodetect them.
3399 * When added, the files are forced to be scanned.
3402 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3403 * until the scanner is available. So you should use the gint id returned to identify
3404 * if a 'scan-end' signal is the one that you were expecting.
3405 * Please note also that, if db is disconnected before the waiting queue is processed,
3406 * the scan of those files won't be performed.
3408 * Returns: scan process id if insertion is successful, -1 on error.
3410 gint
3411 symbol_db_engine_add_new_files_async (SymbolDBEngine *dbe,
3412 IAnjutaLanguage* lang_manager,
3413 const gchar * project_name,
3414 const gchar * project_version,
3415 const GPtrArray *sources_array)
3417 GPtrArray *lang_array;
3418 gint i;
3420 g_return_val_if_fail (dbe != NULL, FALSE);
3421 g_return_val_if_fail (lang_manager != NULL, FALSE);
3422 g_return_val_if_fail (sources_array != NULL, FALSE);
3424 lang_array = g_ptr_array_new_with_free_func (g_free);
3426 for (i = 0; i < sources_array->len; i++)
3428 IAnjutaLanguageId lang_id;
3429 GFile *gfile;
3430 GFileInfo *gfile_info;
3431 const gchar *file_mime;
3432 const gchar *lang;
3433 const gchar *local_filename;
3435 local_filename = g_ptr_array_index (sources_array, i);
3436 gfile = g_file_new_for_path (local_filename);
3437 gfile_info = g_file_query_info (gfile,
3438 "standard::content-type",
3439 G_FILE_QUERY_INFO_NONE,
3440 NULL,
3441 NULL);
3442 if (gfile_info == NULL)
3444 g_warning ("GFileInfo corresponding to %s was NULL", local_filename);
3445 g_object_unref (gfile);
3446 continue;
3449 file_mime = g_file_info_get_attribute_string (gfile_info,
3450 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
3452 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
3453 file_mime, NULL);
3455 if (!lang_id)
3457 g_warning ("Language not found for %s was NULL", local_filename);
3458 g_object_unref (gfile);
3459 g_object_unref (gfile_info);
3460 continue;
3463 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
3464 g_ptr_array_add (lang_array, g_strdup (lang));
3465 g_object_unref (gfile);
3466 g_object_unref (gfile_info);
3469 gint res = symbol_db_engine_add_new_files_full_async (dbe, project_name, project_version,
3470 sources_array, lang_array, TRUE);
3472 /* free resources */
3473 g_ptr_array_unref (lang_array);
3475 return res;
3478 /**
3479 * symbol_db_engine_add_new_files_full_async:
3480 * @dbe: self
3481 * @project_name: something like 'foo_project', or 'helloworld_project'. Can be NULL,
3482 * for example when you're populating after abort.
3483 * @project_version: The version of the project.
3484 * @files_path: requires full path to files on disk. Anjuta-tags itself requires that.
3485 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3486 * a language string to represent the file.
3487 * An example of files_path array composition can be:
3488 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3489 * "/home/user/foo_project/foo3.java".
3490 * NOTE: all the files MUST exist. So check for their existence before call
3491 * this function. The function'll write entries on the db.
3492 * @languages: is an array of 'languages'. It must have the same number of
3493 * elments that files_path has. It should be populated like this: "C", "C++",
3494 * "Java" etc.
3495 * This is done to be normalized with the language-manager plugin.
3496 * @force_scan: If FALSE a check on db will be done to see
3497 * whether the file is already present or not. In the latter care the scan will begin.
3499 * Add a group of files to a project. It will perform also
3500 * a symbols scannig/populating of db if force_scan is TRUE.
3501 * This function requires an opened db, i.e. You must test db ststus with
3502 * symbol_db_engine_open_db () before.
3503 * The function must be called from within the main thread.
3505 * Note: If some file fails to enter into the db the function will just skip them.
3508 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3509 * until the scanner is available. So you should use the gint id returned to identify
3510 * if a 'scan-end' signal is the one that you were expecting.
3511 * Please note also that, if db is disconnected before the waiting queue is processed,
3512 * the scan of those files won't be performed.
3514 * Returns: scan process id if insertion is successful, -1 on error.
3516 gint
3517 symbol_db_engine_add_new_files_full_async (SymbolDBEngine * dbe,
3518 const gchar * project_name,
3519 const gchar * project_version,
3520 const GPtrArray * files_path,
3521 const GPtrArray * languages,
3522 gboolean force_scan)
3524 gint i;
3525 SymbolDBEnginePriv *priv;
3526 GPtrArray * filtered_files_path;
3527 gboolean ret_code;
3528 gint ret_id, scan_id;
3530 g_return_val_if_fail (dbe != NULL, FALSE);
3531 g_return_val_if_fail (files_path != NULL, FALSE);
3532 g_return_val_if_fail (languages != NULL, FALSE);
3533 priv = dbe->priv;
3535 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
3536 g_return_val_if_fail (files_path->len > 0, FALSE);
3537 g_return_val_if_fail (languages->len > 0, FALSE);
3539 filtered_files_path = g_ptr_array_new ();
3541 for (i = 0; i < files_path->len; i++)
3543 const gchar *node_file = (const gchar *) g_ptr_array_index (files_path, i);
3544 const gchar *node_lang = (const gchar *) g_ptr_array_index (languages, i);
3546 if (force_scan == FALSE)
3548 /* test the existence of the file in db */
3549 if (symbol_db_engine_file_exists (dbe, node_file) == TRUE)
3551 /* we don't want to touch the already present file... within
3552 * its symbols
3554 continue;
3558 if (project_name != NULL &&
3559 sdb_engine_add_new_db_file (dbe, project_name, project_version, node_file,
3560 node_lang) == FALSE)
3562 DEBUG_PRINT ("Error processing file %s, db_directory %s, project_name %s, "
3563 "project_version %s, project_directory %s", node_file,
3564 priv->db_directory, project_name, project_version,
3565 priv->project_directory);
3566 continue;
3569 /* note: we don't use g_strdup () here because we'll free the filtered_files_path
3570 * before returning from this function.
3572 g_ptr_array_add (filtered_files_path, (gpointer)node_file);
3575 /* perform the scan of files. It will spawn a fork() process with
3576 * AnjutaLauncher and ctags in server mode. After the ctags cmd has been
3577 * executed, the populating process'll take place.
3579 scan_id = sdb_engine_get_unique_scan_id (dbe);
3580 ret_code = sdb_engine_scan_files_async (dbe, filtered_files_path, NULL, FALSE, scan_id);
3582 if (ret_code == TRUE)
3584 ret_id = scan_id;
3586 else
3587 ret_id = -1;
3589 /* no need to free the items contained in the array */
3590 g_ptr_array_unref (filtered_files_path);
3591 return ret_id;
3596 * We'll use the GNU regular expressions instead of the glib's GRegex ones because
3597 * the latters are a wrapper of pcre (www.pcre.org) that don't implement the
3598 * \< (begin of word)) and \> (end of word) boundaries.
3599 * Since the regex used here is something complex to reproduce on GRegex
3600 * I don't see any reason to reinvent the (already) working wheel.
3601 * I didn't find a valuable replacement for \< and \> neither on
3602 * http://www.regular-expressions.info/wordboundaries.html nor elsewhere.
3603 * But if some regex geek thinks I'm wrong I'll be glad to see his solution.
3605 * @return NULL on error.
3607 #define RX_STRING "\\\".*\\\""
3608 #define RX_BRACKETEXPR "\\{.*\\}"
3609 #define RX_IDENT "[a-zA-Z_][a-zA-Z0-9_]*"
3610 #define RX_WS "[ \t\n]*"
3611 #define RX_PTR "[\\*&]?\\*?"
3612 #define RX_INITIALIZER "=(" RX_WS RX_IDENT RX_WS ")|=(" RX_WS RX_STRING RX_WS \
3613 ")|=(" RX_WS RX_BRACKETEXPR RX_WS ")" RX_WS
3614 #define RX_ARRAY RX_WS "\\[" RX_WS "[0-9]*" RX_WS "\\]" RX_WS
3616 static gchar*
3617 sdb_engine_extract_type_qualifier (const gchar *string, const gchar *expr)
3619 /* check with a regular expression for the type */
3620 regex_t re;
3621 regmatch_t pm[8]; // 7 sub expression -> 8 matches
3622 memset (&pm, -1, sizeof(pm));
3624 * this regexp catches things like:
3625 * a) std::vector<char*> exp1[124] [12], *exp2, expr;
3626 * b) QClass* expr1, expr2, expr;
3627 * c) int a,b; char r[12] = "test, argument", q[2] = { 't', 'e' }, expr;
3629 * it CAN be fooled, if you really want it, but it should
3630 * work for 99% of all situations.
3632 * QString
3633 * var;
3634 * in 2 lines does not work, because //-comments would often bring wrong results
3637 gchar *res = NULL;
3638 static char pattern[512] =
3639 "(" RX_IDENT "\\>)" /* the 'std' in example a) */
3640 "(::" RX_IDENT ")*" /* ::vector */
3641 "(" RX_WS "<[^>;]*>)?" /* <char *> */
3642 /* other variables for the same ident (string i,j,k;) */
3643 "(" RX_WS RX_PTR RX_WS RX_IDENT RX_WS "(" RX_ARRAY ")*" "(" RX_INITIALIZER ")?," RX_WS ")*"
3644 "[ \t\\*&]*"; /* check again for pointer/reference type */
3646 /* must add a 'termination' symbol to the regexp, otherwise
3647 * 'exp' would match 'expr'
3649 gchar regexp[512];
3650 g_snprintf (regexp, sizeof (regexp), "%s\\<%s\\>", pattern, expr);
3652 /* compile regular expression */
3653 int error = regcomp (&re, regexp, REG_EXTENDED) ;
3654 if (error)
3655 return NULL;
3657 /* this call to regexec finds the first match on the line */
3658 error = regexec (&re, string, 8, &pm[0], 0) ;
3660 /* while matches found */
3661 while (error == 0)
3663 /* subString found between pm.rm_so and pm.rm_eo */
3664 /* only include the ::vector part in the indentifier, if the second
3665 * subpattern matches at all
3667 int len = (pm[2].rm_so != -1 ? pm[2].rm_eo : pm[1].rm_eo) - pm[1].rm_so;
3668 if (res)
3669 free (res);
3670 res = (gchar*) g_malloc0 (len + 1);
3671 if (!res)
3673 regfree (&re);
3674 return NULL;
3676 strncpy (res, string + pm[1].rm_so, len);
3677 res[len] = '\0';
3679 /* This call to regexec finds the next match */
3680 error = regexec (&re, string + pm[0].rm_eo, 8, &pm[0], 0) ;
3681 break;
3683 regfree(&re);
3685 return res;
3688 /* ### Thread note: this function inherits the mutex lock ### */
3689 /* Uses cache lookup to speed up symbols search. */
3690 static gint
3691 sdb_engine_add_new_sym_kind (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3693 const gchar *kind_name;
3694 gint table_id;
3695 SymbolDBEnginePriv *priv;
3696 GValue v = {0};
3698 priv = dbe->priv;
3700 /* we assume that tag_entry is != NULL */
3701 kind_name = tag_entry->kind;
3703 /* no kind associated with current tag */
3704 if (kind_name == NULL)
3705 return -1;
3707 /* cache lookup */
3708 table_id = sdb_engine_cache_lookup (priv->kind_cache, kind_name);
3709 if (table_id != -1)
3711 return table_id;
3714 SDB_GVALUE_SET_STATIC_STRING (v, kind_name);
3716 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3717 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
3718 "kindname",
3719 &v)) < 0)
3721 const GdaSet *plist;
3722 const GdaStatement *stmt;
3723 GdaHolder *param;
3724 GdaSet *last_inserted = NULL;
3725 gint is_container = 0;
3726 SymType sym_type;
3727 GError * error = NULL;
3729 g_value_unset (&v);
3731 /* not found. Go on with inserting */
3732 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYM_KIND_NEW))
3733 == NULL)
3735 g_warning ("query is null");
3736 return -1;
3739 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_KIND_NEW);
3741 /* kindname parameter */
3742 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindname")) == NULL)
3744 g_warning ("param kindname is NULL from pquery!");
3745 return FALSE;
3748 SDB_PARAM_SET_STRING (param, kind_name);
3750 /* container parameter */
3751 if ((param = gda_set_get_holder ((GdaSet*)plist, "container")) == NULL)
3753 g_warning ("param container is NULL from pquery!");
3754 return FALSE;
3757 sym_type = GPOINTER_TO_SIZE (g_hash_table_lookup (priv->sym_type_conversion_hash,
3758 kind_name));
3760 if (sym_type & IANJUTA_SYMBOL_TYPE_SCOPE_CONTAINER)
3761 is_container = 1;
3763 SDB_PARAM_SET_INT (param, is_container);
3765 /* execute the query with parameters just set */
3766 if (gda_connection_statement_execute_non_select(priv->db_connection,
3767 (GdaStatement*)stmt,
3768 (GdaSet*)plist, &last_inserted,
3769 NULL) == -1)
3771 table_id = -1;
3773 else
3775 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3776 table_id = g_value_get_int (value);
3777 /* we should cache only tables which are != -1 */
3778 sdb_engine_insert_cache (priv->kind_cache, kind_name, table_id);
3780 if (last_inserted)
3781 g_object_unref (last_inserted);
3783 if (error)
3785 g_warning ("SQL error: %s", error->message);
3786 g_error_free (error);
3790 return table_id;
3793 /* ### Thread note: this function inherits the mutex lock ### */
3794 /* Uses cache lookup to speed up symbols search. */
3795 static gint
3796 sdb_engine_add_new_sym_access (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3798 const gchar *access;
3799 gint table_id;
3800 SymbolDBEnginePriv *priv;
3801 GValue v = {0};
3803 priv = dbe->priv;
3806 /* we assume that tag_entry is != NULL */
3807 if ((access = tagsField (tag_entry, "access")) == NULL)
3809 /* no access associated with current tag */
3810 return -1;
3813 /* cache lookup */
3814 table_id = sdb_engine_cache_lookup (priv->access_cache, access);
3815 if (table_id != -1)
3817 return table_id;
3820 SDB_GVALUE_SET_STATIC_STRING (v, access);
3822 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3823 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
3824 "accesskind",
3825 &v)) < 0)
3827 const GdaSet *plist;
3828 const GdaStatement *stmt;
3829 GdaHolder *param;
3830 GdaSet *last_inserted = NULL;
3832 g_value_unset (&v);
3834 /* not found. Go on with inserting */
3835 if ((stmt =
3836 sdb_engine_get_statement_by_query_id (dbe,
3837 PREP_QUERY_SYM_ACCESS_NEW)) == NULL)
3839 g_warning ("query is null");
3840 return -1;
3843 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_ACCESS_NEW);
3845 /* accesskind parameter */
3846 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskind")) == NULL)
3848 g_warning ("param accesskind is NULL from pquery!");
3849 return -1;
3852 SDB_PARAM_SET_STRING (param, access);
3854 /* execute the query with parameters just set */
3855 if (gda_connection_statement_execute_non_select (priv->db_connection,
3856 (GdaStatement*)stmt,
3857 (GdaSet*)plist, &last_inserted,
3858 NULL) == -1)
3860 table_id = -1;
3862 else
3864 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3865 table_id = g_value_get_int (value);
3866 /* we should cache only tables which are != -1 */
3867 sdb_engine_insert_cache (priv->access_cache, access, table_id);
3870 if (last_inserted)
3871 g_object_unref (last_inserted);
3874 return table_id;
3877 /* ### Thread note: this function inherits the mutex lock ### */
3878 /* Uses cache lookup to speed up symbols search. */
3879 static gint
3880 sdb_engine_add_new_sym_implementation (SymbolDBEngine * dbe,
3881 const tagEntry * tag_entry)
3883 const gchar *implementation;
3884 gint table_id;
3885 SymbolDBEnginePriv *priv;
3886 GValue v = {0};
3888 priv = dbe->priv;
3890 /* we assume that tag_entry is != NULL */
3891 if ((implementation = tagsField (tag_entry, "implementation")) == NULL)
3893 /* no implementation associated with current tag */
3894 return -1;
3897 /* cache lookup */
3898 table_id = sdb_engine_cache_lookup (priv->implementation_cache, implementation);
3899 if (table_id != -1)
3901 return table_id;
3904 SDB_GVALUE_SET_STATIC_STRING(v, implementation);
3906 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3907 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
3908 "implekind",
3909 &v)) < 0)
3911 const GdaSet *plist;
3912 const GdaStatement *stmt;
3913 GdaHolder *param;
3914 GdaSet *last_inserted = NULL;
3916 g_value_unset (&v);
3918 /* not found. Go on with inserting */
3919 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
3920 PREP_QUERY_SYM_IMPLEMENTATION_NEW)) ==
3921 NULL)
3923 g_warning ("query is null");
3924 return -1;
3927 plist = sdb_engine_get_query_parameters_list (dbe,
3928 PREP_QUERY_SYM_IMPLEMENTATION_NEW);
3930 /* implekind parameter */
3931 if ((param = gda_set_get_holder ((GdaSet*)plist, "implekind")) == NULL)
3933 g_warning ("param accesskind is NULL from pquery!");
3934 return -1;
3937 SDB_PARAM_SET_STRING(param, implementation);
3939 /* execute the query with parameters just set */
3940 if (gda_connection_statement_execute_non_select (priv->db_connection,
3941 (GdaStatement*)stmt,
3942 (GdaSet*)plist, &last_inserted,
3943 NULL) == -1)
3945 table_id = -1;
3947 else
3949 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3950 table_id = g_value_get_int (value);
3951 /* we should cache only tables which are != -1 */
3952 sdb_engine_insert_cache (priv->implementation_cache, implementation,
3953 table_id);
3955 if (last_inserted)
3956 g_object_unref (last_inserted);
3959 return table_id;
3962 /* ### Thread note: this function inherits the mutex lock ### */
3963 static void
3964 sdb_engine_add_new_heritage (SymbolDBEngine * dbe, gint base_symbol_id,
3965 gint derived_symbol_id)
3967 const GdaSet *plist;
3968 const GdaStatement *stmt;
3969 GdaHolder *param;
3970 SymbolDBEnginePriv *priv;
3971 GValue v = {0};
3973 g_return_if_fail (base_symbol_id > 0);
3974 g_return_if_fail (derived_symbol_id > 0);
3976 priv = dbe->priv;
3978 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_HERITAGE_NEW))
3979 == NULL)
3981 g_warning ("query is null");
3982 return;
3985 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_HERITAGE_NEW);
3987 /* symbase parameter */
3988 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbase")) == NULL)
3990 g_warning ("param accesskind is NULL from pquery!");
3991 return;
3994 SDB_PARAM_SET_INT(param, base_symbol_id);
3996 /* symderived id parameter */
3997 if ((param = gda_set_get_holder ((GdaSet*)plist, "symderived")) == NULL)
3999 g_warning ("param symderived is NULL from pquery!");
4000 return;
4003 SDB_PARAM_SET_INT(param, derived_symbol_id);
4005 /* execute the query with parameters just set */
4006 if (gda_connection_statement_execute_non_select (priv->db_connection,
4007 (GdaStatement*)stmt,
4008 (GdaSet*)plist, NULL,
4009 NULL) == -1)
4011 g_warning ("Error adding heritage");
4016 /* ### Thread note: this function inherits the mutex lock ### */
4017 static GNUC_INLINE gint
4018 sdb_engine_add_new_scope_definition (SymbolDBEngine * dbe, const tagEntry * tag_entry)
4020 const gchar *scope;
4021 gint table_id;
4022 const GdaSet *plist;
4023 const GdaStatement *stmt;
4024 GdaHolder *param;
4025 GdaSet *last_inserted = NULL;
4026 SymbolDBEnginePriv *priv;
4027 GValue v = {0};
4029 g_return_val_if_fail (tag_entry->kind != NULL, -1);
4031 priv = dbe->priv;
4034 /* This symbol will define a scope which name is tag_entry->name
4035 * For example if we get a tag MyFoo with kind "namespace", it will define
4036 * the "MyFoo" scope, which type is "namespace MyFoo"
4038 scope = tag_entry->name;
4040 /* filter out 'variable' and 'member' kinds. They define no scope. */
4041 if (g_strcmp0 (tag_entry->kind, "variable") == 0 ||
4042 g_strcmp0 (tag_entry->kind, "member") == 0)
4044 return -1;
4047 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SCOPE_NEW))
4048 == NULL)
4050 g_warning ("query is null");
4051 return -1;
4054 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SCOPE_NEW);
4056 /* scope parameter */
4057 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
4059 g_warning ("param scope is NULL from pquery!");
4060 return -1;
4063 SDB_PARAM_SET_STRING (param, scope);
4065 /* execute the query with parameters just set */
4066 if (gda_connection_statement_execute_non_select (priv->db_connection,
4067 (GdaStatement*)stmt,
4068 (GdaSet*)plist, &last_inserted,
4069 NULL) == -1)
4072 GValue v = {0, };
4073 SDB_GVALUE_SET_STATIC_STRING(v, scope);
4075 /* try to get an already existing scope */
4076 table_id = sdb_engine_get_tuple_id_by_unique_name (dbe, PREP_QUERY_GET_SCOPE_ID,
4077 "scope", &v);
4079 else
4081 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4082 table_id = g_value_get_int (value);
4085 if (last_inserted)
4086 g_object_unref (last_inserted);
4088 return table_id;
4092 * ### Thread note: this function inherits the mutex lock ###
4094 * Saves the tagEntry info for a second pass parsing.
4095 * Usually we don't know all the symbol at the first scan of the tags. We need
4096 * a second one.
4099 static GNUC_INLINE void
4100 sdb_engine_add_new_tmp_heritage_scope (SymbolDBEngine * dbe,
4101 const tagEntry * tag_entry,
4102 gint symbol_referer_id)
4104 SymbolDBEnginePriv *priv;
4105 const gchar *field_inherits, *field_struct, *field_typeref,
4106 *field_enum, *field_union, *field_class, *field_namespace;
4107 TableMapTmpHeritage * node;
4109 priv = dbe->priv;
4111 node = g_slice_new0 (TableMapTmpHeritage);
4112 node->symbol_referer_id = symbol_referer_id;
4114 if ((field_inherits = tagsField (tag_entry, "inherits")) != NULL)
4116 node->field_inherits = g_strdup (field_inherits);
4119 if ((field_struct = tagsField (tag_entry, "struct")) != NULL)
4121 node->field_struct = g_strdup (field_struct);
4124 if ((field_typeref = tagsField (tag_entry, "typeref")) != NULL)
4126 node->field_typeref = g_strdup (field_typeref);
4129 if ((field_enum = tagsField (tag_entry, "enum")) != NULL)
4131 node->field_enum = g_strdup (field_enum);
4134 if ((field_union = tagsField (tag_entry, "union")) != NULL)
4136 node->field_union = g_strdup (field_union);
4139 if ((field_class = tagsField (tag_entry, "class")) != NULL)
4141 node->field_class = g_strdup (field_class);
4144 if ((field_namespace = tagsField (tag_entry, "namespace")) != NULL)
4146 node->field_namespace = g_strdup (field_namespace);
4149 g_queue_push_head (priv->tmp_heritage_tablemap, node);
4152 /**
4153 * ### Thread note: this function inherits the mutex lock ###
4155 * Return the symbol_id of the changed symbol
4157 static GNUC_INLINE void
4158 sdb_engine_second_pass_update_scope_1 (SymbolDBEngine * dbe,
4159 TableMapTmpHeritage * node,
4160 gchar * token_name,
4161 const gchar * token_value)
4163 gint symbol_referer_id;
4164 const gchar *tmp_str;
4165 gchar **tmp_str_splitted;
4166 gint tmp_str_splitted_length;
4167 gchar *object_name = NULL;
4168 gboolean free_token_name = FALSE;
4169 const GdaSet *plist;
4170 const GdaStatement *stmt;
4171 GdaHolder *param;
4172 SymbolDBEnginePriv *priv;
4173 GValue v = {0};
4175 g_return_if_fail (token_value != NULL);
4177 priv = dbe->priv;
4178 tmp_str = token_value;
4180 /* we don't need empty strings */
4181 if (strlen (tmp_str) <= 0)
4183 return;
4186 /* we could have something like "First::Second::Third::Fourth" as tmp_str, so
4187 * take only the lastscope, in this case 'Fourth'.
4189 tmp_str_splitted = g_strsplit (tmp_str, ":", 0);
4190 tmp_str_splitted_length = g_strv_length (tmp_str_splitted);
4192 if (tmp_str_splitted_length > 0)
4194 /* handle special typedef case. Usually we have something like struct:my_foo.
4195 * splitting we have [0]-> struct [1]-> my_foo
4197 if (g_strcmp0 (token_name, "typedef") == 0)
4199 free_token_name = TRUE;
4200 token_name = g_strdup (tmp_str_splitted[0]);
4203 object_name = g_strdup (tmp_str_splitted[tmp_str_splitted_length - 1]);
4205 else
4207 g_strfreev (tmp_str_splitted);
4208 return;
4211 g_strfreev (tmp_str_splitted);
4213 /* if we reach this point we should have a good scope_id.
4214 * Go on with symbol updating.
4216 symbol_referer_id = node->symbol_referer_id;
4218 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4219 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID))
4220 == NULL)
4222 g_warning ("query is null");
4223 return;
4226 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID);
4228 /* tokenname parameter */
4229 if ((param = gda_set_get_holder ((GdaSet*)plist, "tokenname")) == NULL)
4231 g_warning ("param tokenname is NULL from pquery!");
4232 return;
4235 SDB_PARAM_SET_STRING(param, token_name);
4237 /* objectname parameter */
4238 if ((param = gda_set_get_holder ((GdaSet*)plist, "objectname")) == NULL)
4240 g_warning ("param objectname is NULL from pquery!");
4241 return;
4244 SDB_PARAM_SET_STRING(param, object_name);
4246 /* symbolid parameter */
4247 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4249 g_warning ("param symbolid is NULL from pquery!");
4250 return;
4253 SDB_PARAM_SET_INT(param, symbol_referer_id);
4255 /* execute the query with parameters just set */
4256 gda_connection_statement_execute_non_select (priv->db_connection,
4257 (GdaStatement*)stmt,
4258 (GdaSet*)plist, NULL,
4259 NULL);
4261 if (free_token_name)
4262 g_free (token_name);
4263 g_free (object_name);
4265 return;
4269 * ### Thread note: this function inherits the mutex lock ###
4271 * @param data Must be filled with some values. It must have num_rows > 0
4272 * @note *CALL THIS BEFORE second_pass_update_heritage ()*
4273 * @note *DO NOT FREE data* inside this function.
4275 static void
4276 sdb_engine_second_pass_update_scope (SymbolDBEngine * dbe)
4278 SymbolDBEnginePriv *priv;
4280 * Fill up the scope.
4281 * The case: "my_foo_func_1" is the name of the current tag parsed.
4282 * Suppose we have a namespace MyFooNamespace, under which is declared
4283 * a class MyFooClass. Under that class there are some funcs like
4284 * my_foo_func_1 () etc. ctags will present us this info about
4285 * my_foo_func_1 ():
4286 * "class : MyFooNamespace::MyFooClass"
4287 * but hey! We don't need to know the namespace here, we just want to
4288 * know that my_foo_func_1 is in the scope of MyFooClass. That one will
4289 * then be mapped inside MyFooNamespace, but that's another thing.
4290 * Go on with the parsing then.
4292 gint i;
4293 gsize queue_length;
4295 priv = dbe->priv;
4297 DEBUG_PRINT ("Processing %d rows", g_queue_get_length (priv->tmp_heritage_tablemap));
4299 /* get a fixed length. There may be some tail_pushes during this loop */
4300 queue_length = g_queue_get_length (priv->tmp_heritage_tablemap);
4302 for (i = 0; i < queue_length; i++)
4304 TableMapTmpHeritage *node;
4305 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4307 if (node->field_class != NULL)
4309 sdb_engine_second_pass_update_scope_1 (dbe, node, "class", node->field_class);
4312 if (node->field_struct != NULL)
4314 sdb_engine_second_pass_update_scope_1 (dbe, node, "struct", node->field_struct);
4317 if (node->field_typeref != NULL)
4319 /* this is a "typedef", not a "typeref". */
4320 sdb_engine_second_pass_update_scope_1 (dbe, node, "typedef", node->field_typeref);
4323 if (node->field_enum != NULL)
4325 sdb_engine_second_pass_update_scope_1 (dbe, node, "enum", node->field_enum);
4328 if (node->field_union != NULL)
4330 sdb_engine_second_pass_update_scope_1 (dbe, node, "union", node->field_union);
4333 if (node->field_namespace != NULL)
4335 sdb_engine_second_pass_update_scope_1 (dbe, node, "namespace", node->field_namespace);
4338 /* last check: if inherits is not null keep the node for a later task */
4339 if (node->field_inherits != NULL)
4341 g_queue_push_tail (priv->tmp_heritage_tablemap, node);
4343 else
4345 sdb_engine_tablemap_tmp_heritage_destroy (node);
4352 * ### Thread note: this function inherits the mutex lock ###
4354 * @param data Must be filled with some values. It must have num_rows > 0
4355 * @note *CALL THIS AFTER second_pass_update_scope ()*
4357 static void
4358 sdb_engine_second_pass_update_heritage (SymbolDBEngine * dbe)
4360 #if 0
4361 gint i;
4362 SymbolDBEnginePriv *priv;
4364 g_return_if_fail (dbe != NULL);
4366 priv = dbe->priv;
4368 DEBUG_PRINT ("Updating heritage... (%d) elements",
4369 g_queue_get_length (priv->tmp_heritage_tablemap));
4371 for (i = 0; i < g_queue_get_length (priv->tmp_heritage_tablemap); i++)
4373 const gchar *inherits;
4374 gchar *item;
4375 gchar **inherits_list;
4376 gint j;
4377 TableMapTmpHeritage *node;
4379 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4380 inherits = node->field_inherits;
4382 if (inherits == NULL)
4384 g_warning ("Inherits was NULL on sym_referer id %d",
4385 node->symbol_referer_id);
4386 sdb_engine_tablemap_tmp_heritage_destroy (node);
4387 continue;
4390 /* there can be multiple inheritance. Check that. */
4391 inherits_list = g_strsplit (inherits, ",", 0);
4393 if (inherits_list != NULL)
4394 DEBUG_PRINT ("inherits %s", inherits);
4396 /* retrieve as much info as we can from the items */
4397 for (j = 0; j < g_strv_length (inherits_list); j++)
4399 gchar **namespaces;
4400 gchar *klass_name;
4401 gchar *namespace_name;
4402 gint namespaces_length;
4403 gint base_klass_id;
4404 gint derived_klass_id;
4406 item = inherits_list[j];
4407 DEBUG_PRINT ("heritage %s", item);
4409 /* A item may have this string form:
4410 * MyFooNamespace1::MyFooNamespace2::MyFooClass
4411 * We should find the field 'MyFooNamespace2' because it's the one
4412 * that is reachable by the scope_id value of the symbol.
4415 namespaces = g_strsplit (item, "::", 0);
4416 namespaces_length = g_strv_length (namespaces);
4418 if (namespaces_length > 1)
4420 /* this is the case in which we have the case with
4421 * namespace + class
4423 namespace_name = g_strdup (namespaces[namespaces_length - 2]);
4424 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4426 else
4428 /* have a last check before setting namespace_name to null.
4429 * check whether the field_namespace is void or not.
4431 const gchar *tmp_namespace;
4432 gchar **tmp_namespace_array = NULL;
4433 gint tmp_namespace_length;
4435 tmp_namespace = node->field_namespace;
4436 if (tmp_namespace != NULL)
4438 tmp_namespace_array = g_strsplit (tmp_namespace, "::", 0);
4439 tmp_namespace_length = g_strv_length (tmp_namespace_array);
4441 if (tmp_namespace_length > 0)
4443 namespace_name =
4444 g_strdup (tmp_namespace_array
4445 [tmp_namespace_length - 1]);
4447 else
4449 namespace_name = NULL;
4452 else
4454 namespace_name = NULL;
4457 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4459 g_strfreev (tmp_namespace_array);
4462 g_strfreev (namespaces);
4464 /* get the derived_klass_id. It should be the
4465 * symbol_referer_id field into __tmp_heritage_scope table
4467 if (node->symbol_referer_id > 0)
4469 derived_klass_id = node->symbol_referer_id;
4471 else
4473 derived_klass_id = 0;
4476 /* ok, search for the symbol_id of the base class */
4477 if (namespace_name == NULL)
4479 GValue *value1;
4481 MP_LEND_OBJ_STR (priv, value1);
4482 g_value_set_static_string (value1, klass_name);
4484 if ((base_klass_id =
4485 sdb_engine_get_tuple_id_by_unique_name (dbe,
4486 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
4487 "klassname",
4488 value1)) < 0)
4490 continue;
4493 else
4495 GValue *value1;
4496 GValue *value2;
4498 MP_LEND_OBJ_STR (priv, value1);
4499 g_value_set_static_string (value1, klass_name);
4501 MP_LEND_OBJ_STR (priv, value2);
4502 g_value_set_static_string (value2, namespace_name);
4504 if ((base_klass_id =
4505 sdb_engine_get_tuple_id_by_unique_name2 (dbe,
4506 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
4507 "klassname",
4508 value1,
4509 "namespacename",
4510 value2)) < 0)
4512 continue;
4516 g_free (namespace_name);
4517 g_free (klass_name);
4519 DEBUG_PRINT ("gonna sdb_engine_add_new_heritage with "
4520 "base_klass_id %d, derived_klass_id %d", base_klass_id,
4521 derived_klass_id);
4522 sdb_engine_add_new_heritage (dbe, base_klass_id, derived_klass_id);
4525 g_strfreev (inherits_list);
4527 #endif
4531 * ### Thread note: this function inherits the mutex lock ###
4533 * Process the temporary table to update the symbols on scope and inheritance
4534 * fields.
4535 * *CALL THIS FUNCTION ONLY AFTER HAVING PARSED ALL THE TAGS ONCE*
4538 static void
4539 sdb_engine_second_pass_do (SymbolDBEngine * dbe)
4541 SymbolDBEnginePriv *priv;
4543 priv = dbe->priv;
4545 /* prepare for scope second scan */
4546 if (g_queue_get_length (priv->tmp_heritage_tablemap) > 0)
4548 sdb_engine_second_pass_update_scope (dbe);
4549 sdb_engine_second_pass_update_heritage (dbe);
4553 GNUC_INLINE static void
4554 sdb_engine_add_new_symbol_case_1 (SymbolDBEngine *dbe,
4555 gint symbol_id,
4556 GdaSet **plist_ptr,
4557 GdaStatement **stmt_ptr)
4559 GdaHolder *param;
4560 GValue v = {0};
4562 const GdaSet * plist = *plist_ptr;
4563 const GdaStatement * stmt = *stmt_ptr;
4565 /* case 1 */
4567 /* create specific query for a fresh new symbol */
4568 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4569 PREP_QUERY_UPDATE_SYMBOL_ALL))
4570 == NULL)
4572 g_warning ("query is null");
4573 return;
4576 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_ALL);
4578 /* symbolid parameter */
4579 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4581 g_warning ("param isfilescope is NULL from pquery!");
4582 return;
4585 SDB_PARAM_SET_INT(param, symbol_id);
4587 *plist_ptr = (GdaSet*)plist;
4588 *stmt_ptr = (GdaStatement*)stmt;
4591 GNUC_INLINE static void
4592 sdb_engine_add_new_symbol_case_2_3 (SymbolDBEngine *dbe,
4593 gint symbol_id,
4594 GdaSet **plist_ptr,
4595 GdaStatement **stmt_ptr,
4596 gint file_defined_id,
4597 const gchar *name,
4598 const gchar *type_type,
4599 const gchar *type_name)
4601 GdaHolder *param;
4602 GValue v = {0};
4604 const GdaSet * plist = *plist_ptr;
4605 const GdaStatement * stmt = *stmt_ptr;
4607 /* create specific query for a fresh new symbol */
4608 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYMBOL_NEW))
4609 == NULL)
4611 g_warning ("query is null");
4612 return;
4615 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYMBOL_NEW);
4617 /* filedefid parameter */
4618 if ((param = gda_set_get_holder ((GdaSet*)plist, "filedefid")) == NULL)
4620 g_warning ("param filedefid is NULL from pquery!");
4621 return;
4624 SDB_PARAM_SET_INT(param, file_defined_id);
4626 /* name parameter */
4627 if ((param = gda_set_get_holder ((GdaSet*)plist, "name")) == NULL)
4629 g_warning ("param name is NULL from pquery!");
4630 return;
4633 SDB_PARAM_SET_STRING(param, name);
4635 /* typetype parameter */
4636 if ((param = gda_set_get_holder ((GdaSet*)plist, "typetype")) == NULL)
4638 g_warning ("param typetype is NULL from pquery!");
4639 return;
4642 SDB_PARAM_SET_STRING(param, type_type);
4644 /* typenameparameter */
4645 if ((param = gda_set_get_holder ((GdaSet*)plist, "typename")) == NULL)
4647 g_warning ("param typename is NULL from pquery!");
4648 return;
4651 SDB_PARAM_SET_STRING(param, type_name);
4653 *plist_ptr = (GdaSet*)plist;
4654 *stmt_ptr = (GdaStatement*)stmt;
4657 GNUC_INLINE static void
4658 sdb_engine_add_new_symbol_common_params (SymbolDBEngine *dbe,
4659 const GdaSet *plist,
4660 const GdaStatement *stmt,
4661 gint file_position,
4662 gint is_file_scope,
4663 const gchar *signature,
4664 const gchar *returntype,
4665 gint scope_definition_id,
4666 gint scope_id,
4667 gint kind_id,
4668 gint access_kind_id,
4669 gint implementation_kind_id,
4670 gboolean update_flag)
4672 GdaHolder *param;
4673 GValue v = {0};
4675 /* fileposition parameter */
4676 if ((param = gda_set_get_holder ((GdaSet*)plist, "fileposition")) == NULL)
4678 g_warning ("param fileposition is NULL from pquery!");
4679 return;
4682 SDB_PARAM_SET_INT (param, file_position);
4684 /* isfilescope parameter */
4685 if ((param = gda_set_get_holder ((GdaSet*)plist, "isfilescope")) == NULL)
4687 g_warning ("param isfilescope is NULL from pquery!");
4688 return;
4691 SDB_PARAM_SET_INT (param, is_file_scope);
4693 /* signature parameter */
4694 if ((param = gda_set_get_holder ((GdaSet*)plist, "signature")) == NULL)
4696 g_warning ("param signature is NULL from pquery!");
4697 return;
4700 SDB_PARAM_SET_STRING(param, signature);
4702 /* returntype parameter */
4703 if ((param = gda_set_get_holder ((GdaSet*)plist, "returntype")) == NULL)
4705 g_warning ("param returntype is NULL from pquery!");
4706 return;
4709 SDB_PARAM_SET_STRING(param, returntype);
4711 /* scopedefinitionid parameter */
4712 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopedefinitionid")) == NULL)
4714 g_warning ("param scopedefinitionid is NULL from pquery!");
4715 return;
4718 SDB_PARAM_SET_INT(param, scope_definition_id);
4720 /* scopeid parameter */
4721 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopeid")) == NULL)
4723 g_warning ("param scopeid is NULL from pquery!");
4724 return;
4727 SDB_PARAM_SET_INT(param, scope_id);
4729 /* kindid parameter */
4730 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindid")) == NULL)
4732 g_warning ("param kindid is NULL from pquery!");
4733 return;
4736 SDB_PARAM_SET_INT(param, kind_id);
4738 /* accesskindid parameter */
4739 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskindid")) == NULL)
4741 g_warning ("param accesskindid is NULL from pquery!");
4742 return;
4745 SDB_PARAM_SET_INT(param, access_kind_id);
4747 /* implementationkindid parameter */
4748 if ((param = gda_set_get_holder ((GdaSet*)plist, "implementationkindid")) == NULL)
4750 g_warning ("param implementationkindid is NULL from pquery!");
4751 return;
4754 SDB_PARAM_SET_INT(param, implementation_kind_id);
4756 /* updateflag parameter */
4757 if ((param = gda_set_get_holder ((GdaSet*)plist, "updateflag")) == NULL)
4759 g_warning ("param updateflag is NULL from pquery!");
4760 return;
4763 SDB_PARAM_SET_INT(param, update_flag);
4768 * ### Thread note: this function inherits the mutex lock ###
4770 * base_prj_path can be NULL. In that case path info tag_entry will be taken
4771 * as an absolute path.
4772 * fake_file can be used when a buffer updating is being executed. In that
4773 * particular case both base_prj_path and tag_entry->file will be ignored.
4774 * fake_file is real_path of file on disk
4776 static gint
4777 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
4778 gint file_defined_id,
4779 gboolean sym_update)
4781 SymbolDBEnginePriv *priv;
4782 GdaSet *plist;
4783 GdaStatement *stmt;
4784 GdaSet *last_inserted = NULL;
4785 gint table_id, symbol_id;
4786 const gchar* name;
4787 gint file_position = 0;
4788 gint is_file_scope = 0;
4789 const gchar *signature;
4790 const gchar *returntype;
4791 gint scope_definition_id = 0;
4792 gint scope_id = 0;
4793 gint kind_id = 0;
4794 gint access_kind_id = 0;
4795 gint implementation_kind_id = 0;
4796 GValue v1 = {0}, v2 = {0}, v3 = {0}, v4 = {0}, v5 = {0};
4797 gboolean sym_was_updated = FALSE;
4798 gboolean update_flag;
4799 gchar *type_regex;;
4800 const gchar *type_type;
4801 const gchar *type_name;
4802 gint nrows;
4803 GError * error = NULL;
4805 g_return_val_if_fail (dbe != NULL, -1);
4806 priv = dbe->priv;
4808 /* keep it at 0 if sym_update == false */
4809 update_flag = sym_update;
4811 g_return_val_if_fail (tag_entry != NULL, -1);
4813 /* parse the entry name */
4814 name = tag_entry->name;
4815 file_position = tag_entry->address.lineNumber;
4816 is_file_scope = tag_entry->fileScope;
4819 * signature
4821 signature = tagsField (tag_entry, "signature");
4824 * return type
4826 returntype = tagsField (tag_entry, "returntype");
4829 * sym_type
4831 /* we assume that tag_entry is != NULL */
4832 type_type = tag_entry->kind;
4833 type_regex = NULL;
4835 if (g_strcmp0 (type_type, "member") == 0 ||
4836 g_strcmp0 (type_type, "variable") == 0 ||
4837 g_strcmp0 (type_type, "field") == 0)
4839 type_regex = sdb_engine_extract_type_qualifier (tag_entry->address.pattern,
4840 tag_entry->name);
4841 /*DEBUG_PRINT ("type_regex for %s [kind %s] is %s", tag_entry->name,
4842 tag_entry->kind, type_regex);*/
4843 type_name = type_regex;
4845 /* if the extractor failed we should fallback to the default one */
4846 if (type_name == NULL)
4847 type_name = tag_entry->name;
4848 } else
4850 type_name = tag_entry->name;
4855 * scope definition
4858 /* scope_definition_id tells what scope this symbol defines */
4859 scope_definition_id = sdb_engine_add_new_scope_definition (dbe, tag_entry);
4861 /* the container scopes can be: union, struct, typeref, class, namespace etc.
4862 * this field will be parsed in the second pass.
4864 scope_id = 0;
4866 kind_id = sdb_engine_add_new_sym_kind (dbe, tag_entry);
4868 access_kind_id = sdb_engine_add_new_sym_access (dbe, tag_entry);
4870 implementation_kind_id = sdb_engine_add_new_sym_implementation (dbe, tag_entry);
4872 /* ok: was the symbol updated [at least on it's type_id/name]?
4873 * There are 3 cases:
4874 * #1. The symbol remains the same [at least on unique index key]. We will
4875 * perform only a simple update.
4876 * #2. The symbol has changed: at least on name/type/file. We will insert a
4877 * new symbol on table 'symbol'. Deletion of old one will take place
4878 * at a second stage, when a delete of all symbols with
4879 * 'tmp_flag = 0' will be done.
4880 * #3. The symbol has been deleted. As above it will be deleted at
4881 * a second stage because of the 'tmp_flag = 0'. Triggers will remove
4882 * also scope_ids and other things.
4885 if (update_flag == FALSE) /* symbol is new */
4887 symbol_id = -1;
4889 else /* symbol is updated or a force_update has been given */
4891 /* We should use more value and set them with the same values because
4892 * sdb_engine_get_tuple_id_by_unique_name () will manage them
4894 SDB_GVALUE_SET_STATIC_STRING(v1, name);
4895 SDB_GVALUE_SET_INT(v2, file_defined_id);
4896 SDB_GVALUE_SET_STATIC_STRING(v3, type_type);
4897 SDB_GVALUE_SET_STATIC_STRING(v4, type_name);
4898 SDB_GVALUE_SET_INT(v5, file_position);
4901 * We cannot live without this select because we must know whether a similar
4902 * symbol was already present in the file or not. With this information we
4903 * can see if it's been updated or newly inserted
4905 symbol_id = sdb_engine_get_tuple_id_by_unique_name5 (dbe,
4906 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
4907 "symname", &v1,
4908 "filedefid", &v2,
4909 "typetype", &v3,
4910 "typename", &v4,
4911 "fileposition", &v5);
4914 /* ok then, parse the symbol id value */
4915 if (symbol_id <= 0)
4917 /* case 2 and 3 */
4918 sym_was_updated = FALSE;
4919 plist = NULL;
4920 stmt = NULL;
4922 sdb_engine_add_new_symbol_case_2_3 (dbe, symbol_id, &plist, &stmt,
4923 file_defined_id, name, type_type, type_name);
4925 else
4927 /* case 1 */
4928 sym_was_updated = TRUE;
4929 plist = NULL;
4930 stmt = NULL;
4932 sdb_engine_add_new_symbol_case_1 (dbe, symbol_id, &plist, &stmt);
4935 /* common params */
4936 sdb_engine_add_new_symbol_common_params (dbe, plist, stmt,
4937 file_position, is_file_scope,
4938 signature, returntype, scope_definition_id,
4939 scope_id, kind_id,
4940 access_kind_id, implementation_kind_id,
4941 update_flag);
4943 /* execute the query with parameters just set */
4944 nrows = gda_connection_statement_execute_non_select (priv->db_connection,
4945 (GdaStatement*)stmt,
4946 (GdaSet*)plist, &last_inserted,
4947 &error);
4949 if (error)
4951 g_warning ("SQL execute_non_select failed: %s", error->message);
4952 g_error_free (error);
4955 if (sym_was_updated == FALSE)
4957 if (nrows > 0)
4959 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4960 table_id = g_value_get_int (value);
4962 /* This is a wrong place to emit the symbol-updated signal. Infact
4963 * db is in a inconsistent state, e.g. inheritance references are still
4964 * *not* calculated.
4965 * So add the symbol id into a queue that will be parsed once and emitted.
4967 g_async_queue_push (priv->inserted_syms_id_aqueue, GINT_TO_POINTER(table_id));
4969 else
4971 table_id = -1;
4974 else
4976 if (nrows > 0)
4978 table_id = symbol_id;
4980 g_async_queue_push (priv->updated_syms_id_aqueue, GINT_TO_POINTER(table_id));
4982 else
4984 table_id = -1;
4988 if (last_inserted)
4989 g_object_unref (last_inserted);
4991 /* post population phase */
4993 /* before returning the table_id we have to fill some infoz on temporary tables
4994 * so that in a second pass we can parse also the heritage and scope fields.
4996 if (table_id > 0)
4997 sdb_engine_add_new_tmp_heritage_scope (dbe, tag_entry, table_id);
4999 g_free (type_regex);
5001 return table_id;
5005 * ### Thread note: this function inherits the mutex lock ###
5007 * Select * from __tmp_removed and emits removed signals.
5009 static void
5010 sdb_engine_detects_removed_ids (SymbolDBEngine *dbe)
5012 const GdaStatement *stmt1, *stmt2;
5013 GdaDataModel *data_model;
5014 SymbolDBEnginePriv *priv;
5015 gint i, num_rows;
5017 priv = dbe->priv;
5019 /* ok, now we should read from __tmp_removed all the symbol ids which have
5020 * been removed, and emit a signal
5022 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5023 PREP_QUERY_GET_REMOVED_IDS))
5024 == NULL)
5026 g_warning ("query is null");
5027 return;
5030 data_model = gda_connection_statement_execute_select (priv->db_connection,
5031 (GdaStatement*)stmt1,
5032 NULL, NULL);
5034 if (GDA_IS_DATA_MODEL (data_model))
5036 if ((num_rows = gda_data_model_get_n_rows (data_model)) <= 0)
5038 DEBUG_PRINT ("nothing to remove");
5039 g_object_unref (data_model);
5040 return;
5043 else
5045 if (data_model != NULL)
5046 g_object_unref (data_model);
5047 return;
5050 /* get and parse the results. */
5051 for (i = 0; i < num_rows; i++)
5053 const GValue *val;
5054 gint tmp;
5055 val = gda_data_model_get_value_at (data_model, 0, i, NULL);
5056 tmp = g_value_get_int (val);
5057 DBESignal *dbesig1;
5058 DBESignal *dbesig2;
5060 dbesig1 = g_slice_new (DBESignal);
5061 dbesig1->value = GINT_TO_POINTER (SYMBOL_REMOVED + 1);
5062 dbesig1->process_id = priv->current_scan_process_id;
5064 dbesig2 = g_slice_new (DBESignal);
5065 dbesig2->value = GINT_TO_POINTER (tmp);
5066 dbesig2->process_id = priv->current_scan_process_id;
5068 g_async_queue_push (priv->signals_aqueue, dbesig1);
5069 g_async_queue_push (priv->signals_aqueue, dbesig2);
5072 g_object_unref (data_model);
5074 /* let's clean the tmp_table */
5075 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5076 PREP_QUERY_TMP_REMOVED_DELETE_ALL))
5077 == NULL)
5079 g_warning ("query is null");
5080 return;
5083 /* bye bye */
5084 gda_connection_statement_execute_non_select (priv->db_connection,
5085 (GdaStatement*)stmt2,
5086 NULL, NULL,
5087 NULL);
5091 * ~~~ Thread note: this function locks the mutex ~~~ *
5093 * WARNING: do not use this function thinking that it would do a scan of symbols
5094 * too. Use symbol_db_engine_update_files_symbols () instead. This one will set
5095 * up some things on db, like removing the 'old' symbols which have not been
5096 * updated.
5098 static gboolean
5099 sdb_engine_update_file (SymbolDBEngine * dbe, const gchar * file_on_db)
5101 const GdaSet *plist1, *plist2, *plist3;
5102 const GdaStatement *stmt1, *stmt2, *stmt3;
5103 GdaHolder *param;
5104 SymbolDBEnginePriv *priv;
5105 GValue v = {0};
5107 priv = dbe->priv;
5109 SDB_LOCK(priv);
5111 /* if we're updating symbols we must do some other operations on db
5112 * symbols, like remove the ones which don't have an update_flag = 1
5113 * per updated file.
5116 /* good. Go on with removing of old symbols, marked by a
5117 * update_flag = 0.
5120 /* Triggers will take care of updating/deleting connected symbols
5121 * tuples, like sym_kind, sym_type etc */
5122 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5123 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS)) == NULL)
5125 g_warning ("query is null");
5126 SDB_UNLOCK(priv);
5128 return FALSE;
5131 plist1 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS);
5133 if ((param = gda_set_get_holder ((GdaSet*)plist1, "filepath")) == NULL)
5135 g_warning ("param filepath is NULL from pquery!");
5136 SDB_UNLOCK(priv);
5137 return FALSE;
5140 SDB_PARAM_SET_STRING(param, file_on_db);
5142 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt1,
5143 (GdaSet*)plist1, NULL, NULL);
5145 /* emits removed symbols signals */
5146 sdb_engine_detects_removed_ids (dbe);
5148 /* reset the update_flag to 0 */
5149 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5150 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS)) == NULL)
5152 g_warning ("query is null");
5153 SDB_UNLOCK(priv);
5154 return FALSE;
5157 plist2 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS);
5159 if ((param = gda_set_get_holder ((GdaSet*)plist2, "filepath")) == NULL)
5161 g_warning ("param filepath is NULL from pquery!");
5162 return FALSE;
5164 SDB_PARAM_SET_STRING(param, file_on_db);
5166 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt2,
5167 (GdaSet*)plist2, NULL, NULL);
5169 /* last but not least, update the file analyse_time */
5170 if ((stmt3 = sdb_engine_get_statement_by_query_id (dbe,
5171 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME))
5172 == NULL)
5174 g_warning ("query is null");
5175 SDB_UNLOCK(priv);
5176 return FALSE;
5179 plist3 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_FILE_ANALYSE_TIME);
5181 /* filepath parameter */
5182 if ((param = gda_set_get_holder ((GdaSet*)plist3, "filepath")) == NULL)
5184 g_warning ("param filepath is NULL from pquery!");
5185 SDB_UNLOCK(priv);
5186 return FALSE;
5189 SDB_PARAM_SET_STRING(param, file_on_db);
5191 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt3,
5192 (GdaSet*)plist3, NULL, NULL);
5194 SDB_UNLOCK(priv);
5195 return TRUE;
5199 * @param data is a GPtrArray *files_to_scan
5200 * It will be freed when this callback will be called.
5202 static void
5203 on_scan_update_files_symbols_end (SymbolDBEngine * dbe,
5204 gint process_id,
5205 UpdateFileSymbolsData* update_data)
5207 SymbolDBEnginePriv *priv;
5208 GPtrArray *files_to_scan;
5209 gint i;
5210 GValue v = {0};
5212 g_return_if_fail (dbe != NULL);
5213 g_return_if_fail (update_data != NULL);
5215 priv = dbe->priv;
5216 files_to_scan = update_data->files_path;
5218 sdb_engine_clear_caches (dbe);
5220 /* we need a reinitialization */
5221 sdb_engine_init_caches (dbe);
5223 for (i = 0; i < files_to_scan->len; i++)
5225 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5227 if (strstr (node, update_data->project_directory) == NULL)
5229 g_warning ("node %s is shorter than "
5230 "prj_directory %s",
5231 node, update_data->project_directory);
5232 continue;
5235 /* clean the db from old un-updated with the last update step () */
5236 if (sdb_engine_update_file (dbe, node +
5237 strlen (update_data->project_directory)) == FALSE)
5239 g_warning ("Error processing file %s", node +
5240 strlen (update_data->project_directory));
5241 return;
5245 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_files_symbols_end,
5246 update_data);
5248 /* if true, we'll update the project scanning time too.
5249 * warning: project time scanning won't could be set before files one.
5250 * This why we'll fork the process calling sdb_engine_scan_files ()
5252 if (update_data->update_prj_analyse_time == TRUE)
5254 const GdaSet *plist;
5255 const GdaStatement *stmt;
5256 GdaHolder *param;
5258 SDB_LOCK(priv);
5259 /* and the project analyse_time */
5260 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5261 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME))
5262 == NULL)
5264 g_warning ("query is null");
5265 SDB_UNLOCK(priv);
5266 return;
5269 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME);
5271 /* prjname parameter */
5272 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5274 g_warning ("param prjname is NULL from pquery!");
5275 SDB_UNLOCK(priv);
5276 return;
5279 SDB_PARAM_SET_STRING(param, update_data->project);
5281 gda_connection_statement_execute_non_select (priv->db_connection,
5282 (GdaStatement*)stmt,
5283 (GdaSet*)plist, NULL, NULL);
5285 SDB_UNLOCK(priv);
5288 /* free the GPtrArray. */
5289 g_ptr_array_unref (files_to_scan);
5291 g_free (update_data->project);
5292 g_free (update_data->project_directory);
5293 g_free (update_data);
5297 * symbol_db_engine_update_files_symbols:
5298 * @dbe: self
5299 * @project: name of the project
5300 * @files_path: absolute path of files to update.
5301 * @update_prj_analyse_time: flag to force the update of project analyse time.
5303 * Update symbols of saved files.
5305 * Returns: Scan process id if insertion is successful, -1 on 'no files scanned'.
5307 gint
5308 symbol_db_engine_update_files_symbols (SymbolDBEngine * dbe, const gchar * project,
5309 const GPtrArray * files_path,
5310 gboolean update_prj_analyse_time)
5312 SymbolDBEnginePriv *priv;
5313 UpdateFileSymbolsData *update_data;
5314 gboolean ret_code;
5315 gint ret_id, scan_id;
5316 gint i;
5317 GPtrArray * ready_files;
5319 priv = dbe->priv;
5321 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5322 g_return_val_if_fail (project != NULL, FALSE);
5324 ready_files = g_ptr_array_new_with_free_func (g_free);
5326 /* check if the files exist in db before passing them to the scan procedure */
5327 for (i = 0; i < files_path->len; i++)
5329 gchar *curr_abs_file;
5331 curr_abs_file = g_strdup (g_ptr_array_index (files_path, i));
5332 /* check if the file exists in db. We will not scan buffers for files
5333 * which aren't already in db
5335 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5337 DEBUG_PRINT ("will not update file symbols claiming to be %s because not in db",
5338 curr_abs_file);
5340 g_free (curr_abs_file);
5341 continue;
5344 /* ok the file exists in db. Add it to ready_files */
5345 g_ptr_array_add (ready_files, curr_abs_file);
5348 /* if no file has been added to the array then bail out here */
5349 if (ready_files->len <= 0)
5351 g_ptr_array_unref (ready_files);
5352 DEBUG_PRINT ("not enough files to update");
5353 return -1;
5356 update_data = g_new0 (UpdateFileSymbolsData, 1);
5358 update_data->update_prj_analyse_time = update_prj_analyse_time;
5359 update_data->files_path = ready_files;
5360 update_data->project = g_strdup (project);
5361 update_data->project_directory = g_strdup (priv->project_directory);
5364 /* data will be freed when callback will be called. The signal will be
5365 * disconnected too, don't worry about disconneting it by hand.
5367 g_signal_connect (G_OBJECT (dbe), "scan-end",
5368 G_CALLBACK (on_scan_update_files_symbols_end), update_data);
5370 scan_id = sdb_engine_get_unique_scan_id (dbe);
5371 ret_code = sdb_engine_scan_files_async (dbe, ready_files, NULL, TRUE, scan_id);
5373 if (ret_code == TRUE)
5375 ret_id = scan_id;
5377 else
5378 ret_id = -1;
5380 return ret_id;
5384 * symbol_db_engine_update_project_symbols:
5385 * @dbe: self
5386 * @project_name: The project name
5387 * @force_all_files:
5389 * Update symbols of the whole project. It scans all file symbols etc.
5390 * If force is true then update forcely all the files.
5391 * ~~~ Thread note: this function locks the mutex ~~~ *
5393 * Returns: scan id of the process, or -1 in case of problems.
5395 gint
5396 symbol_db_engine_update_project_symbols (SymbolDBEngine *dbe,
5397 const gchar *project_name, gboolean force_all_files)
5399 const GdaSet *plist;
5400 const GdaStatement *stmt;
5401 GdaHolder *param;
5402 GdaDataModel *data_model;
5403 gint num_rows = 0;
5404 gint i;
5405 GPtrArray *files_to_scan;
5406 SymbolDBEnginePriv *priv;
5407 GValue v = {0};
5409 g_return_val_if_fail (dbe != NULL, FALSE);
5411 priv = dbe->priv;
5413 g_return_val_if_fail (project_name != NULL, FALSE);
5414 g_return_val_if_fail (priv->project_directory != NULL, FALSE);
5416 SDB_LOCK(priv);
5418 DEBUG_PRINT ("Updating symbols of project-name %s (force %d)...", project_name, force_all_files);
5419 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5420 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME))
5421 == NULL)
5423 g_warning ("query is null");
5424 SDB_UNLOCK(priv);
5425 return FALSE;
5428 plist = sdb_engine_get_query_parameters_list (dbe,
5429 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME);
5431 /* prjname parameter */
5432 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5434 g_warning ("param prjid is NULL from pquery!");
5435 SDB_UNLOCK(priv);
5436 return FALSE;
5439 SDB_PARAM_SET_STRING(param, project_name);
5441 /* execute the query with parameters just set */
5442 GType gtype_array [6] = { G_TYPE_INT,
5443 G_TYPE_STRING,
5444 G_TYPE_INT,
5445 G_TYPE_INT,
5446 GDA_TYPE_TIMESTAMP,
5447 G_TYPE_NONE
5449 data_model = gda_connection_statement_execute_select_full (priv->db_connection,
5450 (GdaStatement*)stmt,
5451 (GdaSet*)plist,
5452 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
5453 gtype_array,
5454 NULL);
5456 if (!GDA_IS_DATA_MODEL (data_model) ||
5457 (num_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model))) <= 0)
5459 if (data_model != NULL)
5460 g_object_unref (data_model);
5461 data_model = NULL;
5463 g_warning ("Strange enough, no files in project ->%s<- found",
5464 project_name);
5465 SDB_UNLOCK(priv);
5466 return FALSE;
5469 /* initialize the array */
5470 files_to_scan = g_ptr_array_new_with_free_func (g_free);
5472 /* we can now scan each filename entry to check the last modification time. */
5473 for (i = 0; i < num_rows; i++)
5475 const GValue *value, *value1;
5476 const GdaTimestamp *timestamp;
5477 const gchar *file_name;
5478 gchar *file_abs_path = NULL;
5479 struct tm filetm;
5480 time_t db_time;
5481 GFile *gfile;
5482 GFileInfo* gfile_info;
5483 GFileInputStream* gfile_is;
5485 if ((value =
5486 gda_data_model_get_value_at (data_model,
5487 gda_data_model_get_column_index(data_model,
5488 "db_file_path"),
5489 i, NULL)) == NULL)
5491 continue;
5494 /* build abs path. */
5495 file_name = g_value_get_string (value);
5496 if (!file_name)
5497 continue;
5499 file_abs_path = g_build_filename (priv->project_directory,
5500 file_name, NULL);
5502 gfile = g_file_new_for_path (file_abs_path);
5503 gfile_is = g_file_read (gfile, NULL, NULL);
5504 /* retrieve data/time info */
5505 if (gfile_is == NULL)
5507 g_message ("could not open path %s", file_abs_path);
5508 g_free (file_abs_path);
5509 g_object_unref (gfile);
5510 continue;
5512 g_object_unref (gfile_is);
5514 gfile_info = g_file_query_info (gfile, "*", G_FILE_QUERY_INFO_NONE,
5515 NULL, NULL);
5517 if (gfile_info == NULL)
5519 g_message ("cannot get file info from handle");
5520 g_free (file_abs_path);
5521 g_object_unref (gfile);
5522 continue;
5525 if ((value1 = gda_data_model_get_value_at (data_model,
5526 gda_data_model_get_column_index(data_model,
5527 "analyse_time"), i, NULL)) == NULL)
5529 continue;
5533 timestamp = gda_value_get_timestamp (value1);
5535 /* fill a struct tm with the date retrieved by the string. */
5536 /* string is something like '2007-04-18 23:51:39' */
5537 memset (&filetm, 0, sizeof (struct tm));
5538 filetm.tm_year = timestamp->year - 1900;
5539 filetm.tm_mon = timestamp->month - 1;
5540 filetm.tm_mday = timestamp->day;
5541 filetm.tm_hour = timestamp->hour;
5542 filetm.tm_min = timestamp->minute;
5543 filetm.tm_sec = timestamp->second;
5545 /* remove one hour to the db_file_time. */
5546 db_time = mktime (&filetm) - 3600;
5548 guint64 modified_time = g_file_info_get_attribute_uint64 (gfile_info,
5549 G_FILE_ATTRIBUTE_TIME_MODIFIED);
5550 if (difftime (db_time, modified_time) < 0 ||
5551 force_all_files == TRUE)
5553 g_ptr_array_add (files_to_scan, file_abs_path);
5555 else
5557 g_free (file_abs_path);
5560 g_object_unref (gfile_info);
5561 g_object_unref (gfile);
5564 if (data_model)
5565 g_object_unref (data_model);
5567 if (files_to_scan->len > 0)
5569 SDB_UNLOCK(priv);
5571 /* at the end let the scanning function do its job */
5572 gint id = symbol_db_engine_update_files_symbols (dbe, project_name,
5573 files_to_scan, TRUE);
5575 g_ptr_array_unref (files_to_scan);
5576 return id;
5579 SDB_UNLOCK(priv);
5581 /* some error occurred */
5582 return -1;
5585 /**
5586 * symbol_db_engine_remove_file:
5587 * @dbe: self
5588 * @project: project name
5589 * @rel_file: db relative file entry of the symbols to remove.
5591 * Remove a file, together with its symbols, from a project. I.e. it won't remove
5592 * physically the file from disk.
5593 * ~~~ Thread note: this function locks the mutex
5595 * Returns: TRUE if everything went good, FALSE otherwise.
5597 gboolean
5598 symbol_db_engine_remove_file (SymbolDBEngine * dbe, const gchar *project,
5599 const gchar *rel_file)
5601 SymbolDBEnginePriv *priv;
5602 const GdaSet *plist;
5603 const GdaStatement *stmt;
5604 GdaHolder *param;
5605 GValue v = {0};
5608 g_return_val_if_fail (dbe != NULL, FALSE);
5609 g_return_val_if_fail (project != NULL, FALSE);
5610 g_return_val_if_fail (rel_file != NULL, FALSE);
5611 priv = dbe->priv;
5613 SDB_LOCK(priv);
5615 if (strlen (rel_file) <= 0)
5617 g_warning ("wrong file to delete.");
5618 SDB_UNLOCK(priv);
5619 return FALSE;
5622 DEBUG_PRINT ("deleting from db %s", rel_file);
5624 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5625 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME)) == NULL)
5627 g_warning ("query is null");
5628 SDB_UNLOCK(priv);
5629 return FALSE;
5632 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME);
5634 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5636 g_warning ("param prjname is NULL from pquery!");
5637 SDB_UNLOCK(priv);
5638 return FALSE;
5641 SDB_PARAM_SET_STRING(param, project);
5643 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
5645 g_warning ("param filepath is NULL from pquery!");
5646 SDB_UNLOCK(priv);
5647 return FALSE;
5650 SDB_PARAM_SET_STRING(param, rel_file);
5652 /* Triggers will take care of updating/deleting connected symbols
5653 * tuples, like sym_kind, sym_type etc */
5654 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt,
5655 (GdaSet*)plist, NULL, NULL);
5657 /* emits removed symbols signals */
5658 sdb_engine_detects_removed_ids (dbe);
5660 SDB_UNLOCK(priv);
5662 return TRUE;
5665 void
5666 symbol_db_engine_remove_files (SymbolDBEngine * dbe, const gchar * project,
5667 const GPtrArray * files)
5669 gint i;
5671 g_return_if_fail (dbe != NULL);
5672 g_return_if_fail (project != NULL);
5673 g_return_if_fail (files != NULL);
5675 for (i = 0; i < files->len; i++)
5677 symbol_db_engine_remove_file (dbe, project, g_ptr_array_index (files, i));
5681 static void
5682 on_scan_update_buffer_end (SymbolDBEngine * dbe, gint process_id, gpointer data)
5684 GPtrArray *files_to_scan;
5685 gint i;
5687 g_return_if_fail (dbe != NULL);
5688 g_return_if_fail (data != NULL);
5690 files_to_scan = (GPtrArray *) data;
5692 for (i = 0; i < files_to_scan->len; i++)
5694 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5695 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, node);
5696 if (relative_path != NULL)
5698 /* will be emitted removed signals */
5699 if (sdb_engine_update_file (dbe, relative_path) == FALSE)
5701 g_warning ("Error processing file %s", node);
5702 return;
5707 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_buffer_end,
5708 files_to_scan);
5710 /* free the GPtrArray. */
5711 g_ptr_array_unref (files_to_scan);
5712 data = files_to_scan = NULL;
5716 * symbol_db_engine_update_buffer_symbols:
5717 * @dbe: self
5718 * @project: project name
5719 * @real_files: full path on disk to 'real file' to update. e.g.
5720 * /home/foouser/fooproject/src/main.c.
5721 * @text_buffers: memory buffers
5722 * @buffer_sizes: one to one sizes with text_buffers.
5724 * Update symbols of a file by a memory-buffer to perform a real-time updating
5725 * of symbols.
5727 * Returns: scan process id if insertion is successful, -1 on error.
5729 gint
5730 symbol_db_engine_update_buffer_symbols (SymbolDBEngine * dbe, const gchar *project,
5731 const GPtrArray * real_files,
5732 const GPtrArray * text_buffers,
5733 const GPtrArray * buffer_sizes)
5735 SymbolDBEnginePriv *priv;
5736 gint i;
5737 gint ret_id, scan_id;
5738 gboolean ret_code;
5739 /* array that'll represent the /dev/shm/anjuta-XYZ files */
5740 GPtrArray *temp_files;
5741 GPtrArray *real_files_list;
5742 GPtrArray *real_files_on_db;
5744 g_return_val_if_fail (dbe != NULL, FALSE);
5745 priv = dbe->priv;
5747 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5748 g_return_val_if_fail (project != NULL, FALSE);
5749 g_return_val_if_fail (real_files != NULL, FALSE);
5750 g_return_val_if_fail (text_buffers != NULL, FALSE);
5751 g_return_val_if_fail (buffer_sizes != NULL, FALSE);
5753 temp_files = g_ptr_array_new_with_free_func (g_free);
5754 real_files_on_db = g_ptr_array_new_with_free_func (g_free);
5755 real_files_list = anjuta_util_clone_string_gptrarray (real_files);
5757 /* obtain a GPtrArray with real_files on database */
5758 for (i=0; i < real_files_list->len; i++)
5760 const gchar *relative_path;
5761 const gchar *curr_abs_file;
5762 FILE *buffer_mem_file;
5763 const gchar *temp_buffer;
5764 gint buffer_mem_fd;
5765 gint temp_size;
5766 gchar *shared_temp_file;
5767 gchar *base_filename;
5769 curr_abs_file = g_ptr_array_index (real_files_list, i);
5770 /* check if the file exists in db. We will not scan buffers for files
5771 * which aren't already in db
5773 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5775 DEBUG_PRINT ("will not scan buffer claiming to be %s because not in db",
5776 curr_abs_file);
5777 continue;
5780 relative_path = g_strdup (symbol_db_util_get_file_db_path (dbe, curr_abs_file));
5781 if (relative_path == NULL)
5783 g_warning ("relative_path is NULL");
5784 continue;
5786 g_ptr_array_add (real_files_on_db, (gpointer) relative_path);
5788 /* it's ok to have just the base filename to create the
5789 * target buffer one */
5790 base_filename = g_filename_display_basename (relative_path);
5792 shared_temp_file = g_strdup_printf ("/anjuta-%d-%ld-%s", getpid (),
5793 time (NULL), base_filename);
5794 g_free (base_filename);
5796 if ((buffer_mem_fd =
5797 shm_open (shared_temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
5799 g_warning ("Error while trying to open a shared memory file. Be"
5800 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
5801 return -1;
5804 buffer_mem_file = fdopen (buffer_mem_fd, "w+b");
5806 temp_buffer = g_ptr_array_index (text_buffers, i);
5807 temp_size = GPOINTER_TO_INT(g_ptr_array_index (buffer_sizes, i));
5809 fwrite (temp_buffer, sizeof(gchar), temp_size, buffer_mem_file);
5810 fflush (buffer_mem_file);
5811 fclose (buffer_mem_file);
5813 /* add the temp file to the array. */
5814 g_ptr_array_add (temp_files, g_strdup_printf (SHARED_MEMORY_PREFIX"%s",
5815 shared_temp_file));
5817 /* check if we already have an entry stored in the hash table, else
5818 * insert it
5820 if (g_hash_table_lookup (priv->garbage_shared_mem_files, shared_temp_file)
5821 == NULL)
5823 DEBUG_PRINT ("inserting into garbage hash table %s", shared_temp_file);
5824 g_hash_table_insert (priv->garbage_shared_mem_files, shared_temp_file,
5825 NULL);
5827 else
5829 /* the item is already stored. Just free it here. */
5830 g_free (shared_temp_file);
5834 /* in case we didn't have any good buffer to scan...*/
5835 ret_id = -1;
5837 /* it may happen that no buffer is correctly set up */
5838 if (real_files_on_db->len > 0)
5840 /* data will be freed when callback will be called. The signal will be
5841 * disconnected too, don't worry about disconnecting it by hand.
5843 g_signal_connect (G_OBJECT (dbe), "scan-end",
5844 G_CALLBACK (on_scan_update_buffer_end), real_files_list);
5846 scan_id = sdb_engine_get_unique_scan_id (dbe);
5847 ret_code = sdb_engine_scan_files_async (dbe, temp_files, real_files_on_db, TRUE, scan_id);
5849 if (ret_code == TRUE)
5851 ret_id = scan_id;
5853 else
5854 ret_id = -1;
5857 g_ptr_array_unref (temp_files);
5858 g_ptr_array_unref (real_files_on_db);
5859 return ret_id;
5863 * symbol_db_engine_get_files_for_project:
5864 * @dbe: self
5866 * Retrieves the list of files in project. The data model contains only 1
5867 * column, which is the file name.
5869 * Returns: data model which must be freed once used.
5871 GdaDataModel*
5872 symbol_db_engine_get_files_for_project (SymbolDBEngine *dbe)
5874 return sdb_engine_execute_select_sql (dbe, "SELECT file.file_path FROM file");
5878 * symbol_db_engine_set_db_case_sensitive:
5879 * @dbe: self
5880 * @case_sensitive: boolean flag.
5882 * Set the opened db case sensitive. The searches on this db will then be performed
5883 * taking into consideration this SQLite's PRAGMA case_sensitive_like.
5884 * ~~~ Thread note: this function locks the mutex ~~~
5887 void
5888 symbol_db_engine_set_db_case_sensitive (SymbolDBEngine *dbe, gboolean case_sensitive)
5890 g_return_if_fail (dbe != NULL);
5892 if (case_sensitive == TRUE)
5893 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 1");
5894 else
5895 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 0");
5899 * symbol_db_engine_get_type_conversion_hash:
5900 * @dbe: self
5902 * Get conversion hash table used to convert symbol type name to enum value
5904 * Returns: a GHashTable which must be freed once used.
5906 const GHashTable*
5907 symbol_db_engine_get_type_conversion_hash (SymbolDBEngine *dbe)
5909 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5910 return dbe->priv->sym_type_conversion_hash;
5914 * symbol_db_engine_get_project_directory:
5915 * @dbe: self
5917 * Gets the project directory (used to construct absolute paths)
5919 * Returns: a const gchar containing the project_directory.
5921 const gchar*
5922 symbol_db_engine_get_project_directory (SymbolDBEngine *dbe)
5924 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5925 return dbe->priv->project_directory;
5929 * symbol_db_engine_get_statement:
5930 * @dbe: self
5931 * @sql_str: sql statement.
5933 * Compiles an sql statement
5935 * Returns: a GdaStatement object which must be freed once used.
5937 GdaStatement*
5938 symbol_db_engine_get_statement (SymbolDBEngine *dbe, const gchar *sql_str)
5940 GdaStatement* stmt;
5941 GError *error = NULL;
5943 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5944 stmt = gda_sql_parser_parse_string (dbe->priv->sql_parser,
5945 sql_str,
5946 NULL, &error);
5947 if (error)
5949 g_warning ("SQL parsing failed: %s: %s", sql_str, error->message);
5950 g_error_free (error);
5952 return stmt;
5956 * symbol_db_engine_execute_select:
5957 * @dbe: self
5958 * @stmt: A compiled GdaStatement sql statement.
5959 * @params: Params for GdaStatement (i.e. a prepared statement).
5961 * Executes a parameterized sql statement
5963 * Returns: A data model which must be freed once used.
5965 GdaDataModel*
5966 symbol_db_engine_execute_select (SymbolDBEngine *dbe, GdaStatement *stmt,
5967 GdaSet *params)
5969 GdaDataModel *res;
5970 GError *error = NULL;
5972 res = gda_connection_statement_execute_select (dbe->priv->db_connection,
5973 stmt, params, &error);
5974 if (error)
5976 gchar *sql_str =
5977 gda_statement_to_sql_extended (stmt, dbe->priv->db_connection,
5978 params, 0, NULL, NULL);
5980 g_warning ("SQL select exec failed: %s, %s", sql_str, error->message);
5981 g_free (sql_str);
5982 g_error_free (error);
5984 return res;