Updated French translation
[anjuta.git] / plugins / symbol-db / symbol-db-engine-core.c
blob8e331710c30d901c38cb43ed76d77bf22890411d
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) Massimo Cora' 2007-2009 <maxcvs@email.it>
5 *
6 * Some code from IComplete of Martin Stubenschrott <stubenschrott@gmx.net>
7 * has been used here.
9 * anjuta is free software.
11 * You may redistribute it and/or modify it under the terms of the
12 * GNU General Public License, as published by the Free Software
13 * Foundation; either version 2 of the License, or (at your option)
14 * any later version.
16 * anjuta is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with anjuta. If not, write to:
23 * The Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor
25 * Boston, MA 02110-1301, USA.
28 #include <time.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <signal.h>
34 #include <fcntl.h> /* For O_* constants */
35 #include <string.h>
36 #include <regex.h>
38 #include <gio/gio.h>
39 #include <libanjuta/interfaces/ianjuta-symbol.h>
40 #include <libanjuta/anjuta-debug.h>
41 #include <libanjuta/anjuta-launcher.h>
42 #include <libanjuta/anjuta-utils.h>
43 #include <libgda/libgda.h>
44 #include <sql-parser/gda-sql-parser.h>
45 #include "readtags.h"
46 #include "symbol-db-engine-priv.h"
47 #include "symbol-db-engine-core.h"
48 #include "symbol-db-engine-utils.h"
50 #include <glib/gprintf.h>
53 * utility macros
55 #define STATIC_QUERY_POPULATE_INIT_NODE(query_list_ptr, query_type, gda_stmt) { \
56 static_query_node *q = g_new0 (static_query_node, 1); \
57 q->query_id = query_type; \
58 q->query_str = gda_stmt; \
59 q->stmt = NULL; \
60 q->plist = NULL; \
61 query_list_ptr [query_type] = q; \
65 * typedefs
67 typedef struct _TableMapTmpHeritage {
68 gint symbol_referer_id;
69 gchar *field_inherits;
70 gchar *field_struct;
71 gchar *field_typeref;
72 gchar *field_enum;
73 gchar *field_union;
74 gchar *field_class;
75 gchar *field_namespace;
77 } TableMapTmpHeritage;
79 typedef struct _TableMapSymbol {
80 gint symbol_id;
81 gint file_defined_id;
82 gchar *name;
83 gint file_position;
84 gint is_file_scope;
85 gchar *signature;
86 gchar *returntype;
87 gint scope_definition_id;
88 gint scope_id;
89 gint type_id;
90 gint kind_id;
91 gint access_kind_id;
92 gint implementation_kind_id;
93 gint update_flag;
95 } TableMapSymbol;
97 typedef struct _EngineScanDataAsync {
98 GPtrArray *files_list;
99 GPtrArray *real_files_list;
100 gboolean symbols_update;
101 gint scan_id;
103 } EngineScanDataAsync;
106 typedef void (SymbolDBEngineCallback) (SymbolDBEngine * dbe,
107 gpointer user_data);
110 * signals enum
112 enum
114 DB_CONNECTED,
115 DB_DISCONNECTED,
116 SCAN_BEGIN,
117 SINGLE_FILE_SCAN_END,
118 SCAN_END,
119 SYMBOL_INSERTED,
120 SYMBOL_UPDATED,
121 SYMBOL_SCOPE_UPDATED,
122 SYMBOL_REMOVED,
123 LAST_SIGNAL
127 * enums
129 enum {
130 DO_UPDATE_SYMS = 1,
131 DO_UPDATE_SYMS_AND_EXIT,
132 DONT_UPDATE_SYMS,
133 DONT_UPDATE_SYMS_AND_EXIT,
134 DONT_FAKE_UPDATE_SYMS,
135 END_UPDATE_GROUP_SYMS
139 * structs used for callback data.
141 typedef struct _UpdateFileSymbolsData {
142 gchar *project;
143 gchar *project_directory;
144 gboolean update_prj_analyse_time;
145 GPtrArray * files_path;
147 } UpdateFileSymbolsData;
149 typedef struct _ScanFiles1Data {
150 SymbolDBEngine *dbe;
152 gchar *real_file; /* may be NULL. If not NULL must be freed */
153 gint partial_count;
154 gint files_list_len;
155 gint symbols_update;
157 } ScanFiles1Data;
160 * global file variables
162 static GObjectClass *parent_class = NULL;
163 static unsigned int signals[LAST_SIGNAL] = { 0 };
166 #ifdef DEBUG
167 static GTimer *sym_timer_DEBUG = NULL;
168 static gint tags_total_DEBUG = 0;
169 static gdouble elapsed_total_DEBUG = 0;
170 #endif
173 * forward declarations
175 static void
176 sdb_engine_second_pass_do (SymbolDBEngine * dbe);
178 static gint
179 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
180 int file_defined_id, gboolean sym_update);
182 const GdaStatement *
183 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id);
185 GQuark
186 symbol_db_engine_error_quark (void)
188 return g_quark_from_static_string ("symbol-db-engine-error-quark");
192 * implementation starts here
194 static GNUC_INLINE gint
195 sdb_engine_cache_lookup (GHashTable* hash_table, const gchar* lookup)
197 gpointer orig_key = NULL;
198 gpointer value = NULL;
200 /* avoiding lazy initialization may gain some cpu cycles. Just lookup here. */
201 if (g_hash_table_lookup_extended (hash_table,
202 lookup,
203 &orig_key,
204 &value))
206 gint table_id = GPOINTER_TO_INT (value);
207 return table_id;
209 return -1;
212 static GNUC_INLINE void
213 sdb_engine_insert_cache (GHashTable* hash_table, const gchar* key,
214 gint value)
216 g_hash_table_insert (hash_table, g_strdup (key),
217 GINT_TO_POINTER (value));
220 static void
221 sdb_engine_tablemap_tmp_heritage_destroy (TableMapTmpHeritage *node)
223 g_free (node->field_inherits);
224 g_free (node->field_struct);
225 g_free (node->field_typeref);
226 g_free (node->field_enum);
227 g_free (node->field_union);
228 g_free (node->field_class);
229 g_free (node->field_namespace);
231 g_slice_free (TableMapTmpHeritage, node);
234 static void
235 sdb_engine_scan_data_destroy (gpointer data)
237 EngineScanDataAsync *esda = (EngineScanDataAsync *)data;
239 g_ptr_array_unref (esda->files_list);
240 if (esda->real_files_list)
241 g_ptr_array_unref (esda->real_files_list);
243 g_free (esda);
246 static void
247 sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
249 SymbolDBEnginePriv *priv = dbe->priv;
250 if (priv->tmp_heritage_tablemap)
252 TableMapTmpHeritage *node;
253 while ((node = g_queue_pop_head (priv->tmp_heritage_tablemap)) != NULL)
255 sdb_engine_tablemap_tmp_heritage_destroy (node);
258 /* queue should be void. Free it */
259 g_queue_free (priv->tmp_heritage_tablemap);
260 priv->tmp_heritage_tablemap = NULL;
264 static void
265 sdb_engine_clear_caches (SymbolDBEngine* dbe)
267 SymbolDBEnginePriv *priv = dbe->priv;
268 if (priv->kind_cache)
269 g_hash_table_destroy (priv->kind_cache);
270 if (priv->access_cache)
271 g_hash_table_destroy (priv->access_cache);
272 if (priv->implementation_cache)
273 g_hash_table_destroy (priv->implementation_cache);
274 if (priv->language_cache)
275 g_hash_table_destroy (priv->language_cache);
277 priv->kind_cache = NULL;
278 priv->access_cache = NULL;
279 priv->implementation_cache = NULL;
280 priv->language_cache = NULL;
283 static void
284 sdb_engine_init_table_maps (SymbolDBEngine *dbe)
286 SymbolDBEnginePriv *priv = dbe->priv;
288 /* tmp_heritage_tablemap */
289 priv->tmp_heritage_tablemap = g_queue_new ();
292 static void
293 sdb_engine_init_caches (SymbolDBEngine* dbe)
295 SymbolDBEnginePriv *priv = dbe->priv;
296 priv->kind_cache = g_hash_table_new_full (g_str_hash,
297 g_str_equal,
298 g_free,
299 NULL);
301 priv->access_cache = g_hash_table_new_full (g_str_hash,
302 g_str_equal,
303 g_free,
304 NULL);
306 priv->implementation_cache = g_hash_table_new_full (g_str_hash,
307 g_str_equal,
308 g_free,
309 NULL);
311 priv->language_cache = g_hash_table_new_full (g_str_hash,
312 g_str_equal,
313 g_free,
314 NULL);
317 /* ~~~ Thread note: this function locks the mutex ~~~ */
318 static gboolean
319 sdb_engine_execute_unknown_sql (SymbolDBEngine *dbe, const gchar *sql)
321 GdaStatement *stmt;
322 GObject *res;
323 SymbolDBEnginePriv *priv;
325 priv = dbe->priv;
327 SDB_LOCK(priv);
328 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, NULL, NULL);
330 if (stmt == NULL)
332 SDB_UNLOCK(priv);
333 return FALSE;
336 if ((res = gda_connection_statement_execute (priv->db_connection,
337 (GdaStatement*)stmt,
338 NULL,
339 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
340 NULL, NULL)) == NULL)
342 g_object_unref (stmt);
343 SDB_UNLOCK(priv);
344 return FALSE;
346 else
348 g_object_unref (res);
349 g_object_unref (stmt);
350 SDB_UNLOCK(priv);
351 return TRUE;
355 static GdaDataModel *
356 sdb_engine_execute_select_sql (SymbolDBEngine * dbe, const gchar *sql)
358 GdaStatement *stmt;
359 GdaDataModel *res;
360 SymbolDBEnginePriv *priv;
361 const gchar *remain;
363 priv = dbe->priv;
365 stmt = gda_sql_parser_parse_string (priv->sql_parser, sql, &remain, NULL);
367 if (stmt == NULL)
368 return NULL;
370 res = gda_connection_statement_execute_select (priv->db_connection,
371 (GdaStatement*)stmt, NULL, NULL);
372 if (!res)
373 DEBUG_PRINT ("Could not execute query: %s\n", sql);
375 if (remain != NULL)
377 /* this shouldn't never happen */
378 sdb_engine_execute_select_sql (dbe, remain);
381 g_object_unref (stmt);
383 return res;
386 static gint
387 sdb_engine_execute_non_select_sql (SymbolDBEngine * dbe, const gchar *sql)
389 GdaStatement *stmt;
390 gint nrows;
391 SymbolDBEnginePriv *priv;
392 const gchar *remain;
394 priv = dbe->priv;
395 stmt = gda_sql_parser_parse_string (priv->sql_parser,
396 sql, &remain, NULL);
398 if (stmt == NULL)
399 return -1;
401 nrows = gda_connection_statement_execute_non_select (priv->db_connection, stmt,
402 NULL, NULL, NULL);
403 if (remain != NULL) {
404 /* may happen for example when sql is a file-content */
405 sdb_engine_execute_non_select_sql (dbe, remain);
408 g_object_unref (stmt);
409 return nrows;
413 * ### Thread note: this function inherits the mutex lock ###
415 * Use a proxy to return an already present or a fresh new prepared query
416 * from static 'query_list'. We should perform actions in the fastest way, because
417 * these queries are time-critical.
418 * A GdaSet will also be populated once, avoiding so to create again later on.
420 const GdaStatement *
421 sdb_engine_get_statement_by_query_id (SymbolDBEngine * dbe, static_query_type query_id)
423 static_query_node *node;
424 SymbolDBEnginePriv *priv;
426 priv = dbe->priv;
428 /* no way: if connection is NULL we will break here. There must be
429 * a connection established to db before using this function */
430 /*g_return_val_if_fail (priv->db_connection != NULL, NULL);*/
432 if ((node = priv->static_query_list[query_id]) == NULL)
433 return NULL;
435 if (node->stmt == NULL)
437 GError *error = NULL;
439 /* create a new GdaStatement */
440 node->stmt =
441 gda_sql_parser_parse_string (priv->sql_parser, node->query_str, NULL,
442 &error);
444 if (error)
446 g_warning ("%s", error->message);
447 g_error_free (error);
448 return NULL;
451 if (gda_statement_get_parameters ((GdaStatement*)node->stmt,
452 &node->plist, NULL) == FALSE)
454 g_warning ("Error on getting parameters for %d", query_id);
458 return node->stmt;
462 * ### Thread note: this function inherits the mutex lock ###
464 * Return a GdaSet of parameters calculated from the statement. It does not check
465 * if it's null. You *must* be sure to have called sdb_engine_get_statement_by_query_id () first.
467 static GNUC_INLINE const GdaSet *
468 sdb_engine_get_query_parameters_list (SymbolDBEngine *dbe, static_query_type query_id)
470 SymbolDBEnginePriv *priv;
472 priv = dbe->priv;
474 static_query_node *node;
475 node = priv->static_query_list[query_id];
476 return node->plist;
480 * Clear the static cached queries data. You should call this function when closing/
481 * destroying SymbolDBEngine object.
483 static void
484 sdb_engine_free_cached_queries (SymbolDBEngine *dbe)
486 SymbolDBEnginePriv *priv;
487 gint i;
488 static_query_node *node;
490 priv = dbe->priv;
492 for (i = 0; i < PREP_QUERY_COUNT; i++)
494 node = priv->static_query_list[i];
496 if (node != NULL && node->stmt != NULL)
498 /*DEBUG_PRINT ("sdb_engine_free_cached_queries stmt %d", i);*/
499 g_object_unref (node->stmt);
500 node->stmt = NULL;
503 if (node != NULL && node->plist != NULL)
505 /*DEBUG_PRINT ("sdb_engine_free_cached_queries plist %d", i);*/
506 g_object_unref (node->plist);
507 node->plist = NULL;
510 /* last but not the least free the node itself */
511 g_free (node);
512 priv->static_query_list[i] = NULL;
516 static gboolean
517 sdb_engine_disconnect_from_db (SymbolDBEngine * dbe)
519 SymbolDBEnginePriv *priv;
521 g_return_val_if_fail (dbe != NULL, FALSE);
522 priv = dbe->priv;
524 DEBUG_PRINT ("VACUUM command issued on %s", priv->cnc_string);
525 sdb_engine_execute_non_select_sql (dbe, "VACUUM");
527 DEBUG_PRINT ("Disconnecting from %s", priv->cnc_string);
528 g_free (priv->cnc_string);
529 priv->cnc_string = NULL;
531 if (priv->db_connection != NULL)
532 gda_connection_close (priv->db_connection);
533 priv->db_connection = NULL;
535 if (priv->sql_parser != NULL)
536 g_object_unref (priv->sql_parser);
537 priv->sql_parser = NULL;
539 return TRUE;
543 * ### Thread note: this function inherits the mutex lock ###
545 * @return -1 on error. Otherwise the id of tuple.
547 static GNUC_INLINE gint
548 sdb_engine_get_tuple_id_by_unique_name (SymbolDBEngine * dbe, static_query_type qtype,
549 gchar * param_key,
550 GValue * param_value)
552 const GdaSet *plist;
553 const GdaStatement *stmt;
554 GdaHolder *param;
555 GdaDataModel *data_model;
556 const GValue *num;
557 gint table_id;
558 SymbolDBEnginePriv *priv;
560 priv = dbe->priv;
562 /* get prepared query */
563 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
565 g_warning ("Query is null");
566 return -1;
569 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
571 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key)) == NULL)
573 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
574 "from pquery!\n");
575 return -1;
578 gda_holder_set_value (param, param_value, NULL);
580 /* execute the query with parameters just set */
581 data_model = gda_connection_statement_execute_select (priv->db_connection,
582 (GdaStatement*)stmt,
583 (GdaSet*)plist, NULL);
585 if (!GDA_IS_DATA_MODEL (data_model) ||
586 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
588 if (data_model != NULL)
589 g_object_unref (data_model);
590 return -1;
593 /* get and parse the results. */
594 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
596 table_id = g_value_get_int (num);
597 g_object_unref (data_model);
599 /* set the value to a dummy string because we won't use the real value anymore */
600 return table_id;
603 /* ### Thread note: this function inherits the mutex lock ### */
604 static GNUC_INLINE gint
605 sdb_engine_get_tuple_id_by_unique_name5 (SymbolDBEngine * dbe,
606 static_query_type qtype,
607 gchar * param_key1,
608 GValue * value1,
609 gchar * param_key2,
610 GValue * value2,
611 gchar * param_key3,
612 GValue * value3,
613 gchar * param_key4,
614 GValue * value4,
615 gchar * param_key5,
616 GValue * value5)
618 const GdaSet *plist;
619 const GdaStatement *stmt;
620 GdaHolder *param;
621 GdaDataModel *data_model;
622 const GValue *num;
623 gint table_id;
624 SymbolDBEnginePriv *priv;
626 priv = dbe->priv;
628 /* get prepared query */
629 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, qtype)) == NULL)
631 g_warning ("Query is null");
632 return -1;
635 plist = sdb_engine_get_query_parameters_list (dbe, qtype);
637 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key1)) == NULL)
639 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: param is NULL "
640 "from pquery!\n");
641 return -1;
644 gda_holder_set_value (param, value1, NULL);
646 /* ...and the second one */
647 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key2)) == NULL)
649 g_warning ("sdb_engine_get_tuple_id_by_unique_name5: "
650 "param is NULL from pquery!");
651 return -1;
654 gda_holder_set_value (param, value2, NULL);
656 /* ...and the third one */
657 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key3)) == 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, value3, NULL);
666 /* ...and the fourth one */
667 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key4)) == 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, value4, NULL);
676 /* ...and the fifth one */
677 if ((param = gda_set_get_holder ((GdaSet*)plist, param_key5)) == 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, value5, NULL);
686 /* execute the query with parameters just set */
687 data_model = gda_connection_statement_execute_select (priv->db_connection,
688 (GdaStatement*)stmt,
689 (GdaSet*)plist, NULL);
691 if (!GDA_IS_DATA_MODEL (data_model) ||
692 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
694 if (data_model != NULL)
695 g_object_unref (data_model);
697 return -1;
700 /* get and parse the results. */
701 num = gda_data_model_get_value_at (GDA_DATA_MODEL (data_model), 0, 0, NULL);
703 table_id = g_value_get_int (num);
704 g_object_unref (data_model);
705 return table_id;
708 /** ### Thread note: this function inherits the mutex lock ### */
709 static int
710 sdb_engine_get_file_defined_id (SymbolDBEngine* dbe,
711 const gchar* base_prj_path,
712 const gchar* fake_file_on_db,
713 tagEntry* tag_entry)
715 GValue v = {0};
717 gint file_defined_id = 0;
718 if (base_prj_path != NULL && g_str_has_prefix (tag_entry->file, base_prj_path))
720 /* in this case fake_file will be ignored. */
722 /* we expect here an absolute path */
723 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file + strlen (base_prj_path));
725 else
727 /* check whether the fake_file can substitute the tag_entry->file one */
728 if (fake_file_on_db == NULL)
730 SDB_GVALUE_SET_STATIC_STRING(v, tag_entry->file);
732 else
734 SDB_GVALUE_SET_STATIC_STRING(v, fake_file_on_db);
738 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
739 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
740 "filepath",
741 &v)) < 0)
743 /* if we arrive here there should be some sync problems between the filenames
744 * in database and the ones in the ctags files. We trust in db's ones,
745 * so we'll just return here.
747 g_warning ("sync problems between db and ctags filenames entries. "
748 "File was %s (base_path: %s, fake_file: %s, tag_file: %s)",
749 g_value_get_string (&v), base_prj_path, fake_file_on_db,
750 tag_entry->file);
751 return -1;
754 return file_defined_id;
758 * ### Thread note: this function inherits the mutex lock ###
760 * If fake_file is != NULL we claim and assert that tags contents which are
761 * scanned belong to the fake_file in the project.
762 * More: the fake_file refers to just one single file and cannot be used
763 * for multiple fake_files.
765 static void
766 sdb_engine_populate_db_by_tags (SymbolDBEngine * dbe, FILE* fd,
767 gchar * fake_file_on_db,
768 gboolean force_sym_update)
770 tagFile *tag_file;
771 tagFileInfo tag_file_info;
772 tagEntry tag_entry;
773 gint file_defined_id_cache = 0;
774 gchar* tag_entry_file_cache = NULL;
776 SymbolDBEnginePriv *priv = dbe->priv;
778 gchar* base_prj_path = fake_file_on_db == NULL ?
779 priv->project_directory : NULL;
781 g_return_if_fail (dbe != NULL);
783 g_return_if_fail (priv->db_connection != NULL);
784 g_return_if_fail (fd != NULL);
786 if ((tag_file = tagsOpen_1 (fd, &tag_file_info)) == NULL)
788 g_warning ("error in opening ctags file");
791 #ifdef DEBUG
792 if (sym_timer_DEBUG == NULL)
793 sym_timer_DEBUG = g_timer_new ();
794 else
795 g_timer_reset (sym_timer_DEBUG);
796 gint tags_num_DEBUG = 0;
797 #endif
798 tag_entry.file = NULL;
800 while (tagsNext (tag_file, &tag_entry) != TagFailure)
802 gint file_defined_id = 0;
803 if (tag_entry.file == NULL)
805 continue;
807 if (file_defined_id_cache > 0)
809 if (g_str_equal (tag_entry.file, tag_entry_file_cache))
811 file_defined_id = file_defined_id_cache;
814 if (file_defined_id == 0)
816 file_defined_id = sdb_engine_get_file_defined_id (dbe,
817 base_prj_path,
818 fake_file_on_db,
819 &tag_entry);
820 file_defined_id_cache = file_defined_id;
821 g_free (tag_entry_file_cache);
822 tag_entry_file_cache = g_strdup (tag_entry.file);
825 if (priv->symbols_scanned_count++ % BATCH_SYMBOL_NUMBER == 0)
827 GError *error = NULL;
829 /* if we aren't at the first cycle then we can commit the transaction */
830 if (priv->symbols_scanned_count > 1)
832 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
833 &error);
835 if (error)
837 DEBUG_PRINT ("err: %s", error->message);
838 g_error_free (error);
839 error = NULL;
843 gda_connection_begin_transaction (priv->db_connection, "symboltrans",
844 GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, &error);
846 if (error)
848 DEBUG_PRINT ("err: %s", error->message);
849 g_error_free (error);
850 error = NULL;
854 /* insert or update a symbol */
855 sdb_engine_add_new_symbol (dbe, &tag_entry, file_defined_id,
856 force_sym_update);
857 #ifdef DEBUG
858 tags_num_DEBUG++;
859 #endif
860 tag_entry.file = NULL;
862 g_free (tag_entry_file_cache);
865 #ifdef DEBUG
866 gdouble elapsed_DEBUG = g_timer_elapsed (sym_timer_DEBUG, NULL);
867 tags_total_DEBUG += tags_num_DEBUG;
868 elapsed_total_DEBUG += elapsed_DEBUG;
869 /* DEBUG_PRINT ("elapsed: %f for (%d) [%f sec/symbol] [av %f sec/symbol]", elapsed_DEBUG,
870 tags_num_DEBUG, elapsed_DEBUG / tags_num_DEBUG,
871 elapsed_total_DEBUG / tags_total_DEBUG);
873 #endif
875 /* notify listeners that another file has been scanned */
876 DBESignal *dbesig = g_slice_new0 (DBESignal);
877 dbesig->value = GINT_TO_POINTER (SINGLE_FILE_SCAN_END +1);
878 dbesig->process_id = priv->current_scan_process_id;
880 g_async_queue_push (priv->signals_aqueue, dbesig);
882 /* we've done with tag_file but we don't need to tagsClose (tag_file); */
885 /* ~~~ Thread note: this function locks the mutex ~~~ */
886 static void
887 sdb_engine_ctags_output_thread (gpointer data, gpointer user_data)
889 gint len_chars;
890 gchar *chars, *chars_ptr;
891 gint remaining_chars;
892 gint len_marker;
893 SymbolDBEnginePriv *priv;
894 SymbolDBEngine *dbe;
896 chars = chars_ptr = (gchar *)data;
897 dbe = SYMBOL_DB_ENGINE (user_data);
899 g_return_if_fail (dbe != NULL);
900 g_return_if_fail (chars_ptr != NULL);
902 priv = dbe->priv;
904 SDB_LOCK(priv);
906 remaining_chars = len_chars = strlen (chars_ptr);
907 len_marker = strlen (CTAGS_MARKER);
909 /*DEBUG_PRINT ("program output [new version]: ==>%s<==", chars);*/
910 if (len_chars >= len_marker)
912 gchar *marker_ptr = NULL;
913 gint tmp_str_length = 0;
915 /* is it an end file marker? */
916 marker_ptr = strstr (chars_ptr, CTAGS_MARKER);
920 if (marker_ptr != NULL)
922 int scan_flag;
923 gchar *real_file;
925 /* set the length of the string parsed */
926 tmp_str_length = marker_ptr - chars_ptr;
928 /* write to shm_file all the chars_ptr received without the marker ones */
929 fwrite (chars_ptr, sizeof(gchar), tmp_str_length, priv->shared_mem_file);
931 chars_ptr = marker_ptr + len_marker;
932 remaining_chars -= (tmp_str_length + len_marker);
933 fflush (priv->shared_mem_file);
935 /* get the scan flag from the queue. We need it to know whether
936 * an update of symbols must be done or not */
937 DBESignal *dbesig = g_async_queue_try_pop (priv->scan_aqueue);
938 scan_flag = GPOINTER_TO_INT(dbesig->value);
939 g_slice_free (DBESignal, dbesig);
941 dbesig = g_async_queue_try_pop (priv->scan_aqueue);
942 real_file = dbesig->value;
943 g_slice_free (DBESignal, dbesig);
945 /* and now call the populating function */
946 if (scan_flag == DO_UPDATE_SYMS ||
947 scan_flag == DO_UPDATE_SYMS_AND_EXIT)
949 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
950 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
951 TRUE);
953 else
955 sdb_engine_populate_db_by_tags (dbe, priv->shared_mem_file,
956 (gsize)real_file == DONT_FAKE_UPDATE_SYMS ? NULL : real_file,
957 FALSE);
960 /* don't forget to free the real_file, if it's a char */
961 if ((gsize)real_file != DONT_FAKE_UPDATE_SYMS)
962 g_free (real_file);
964 /* check also if, together with an end file marker, we have an
965 * end group-of-files end marker.
967 if (scan_flag == DO_UPDATE_SYMS_AND_EXIT ||
968 scan_flag == DONT_UPDATE_SYMS_AND_EXIT )
970 gint tmp_inserted;
971 gint tmp_updated;
973 /* scan has ended. Go go with second step. */
974 DEBUG_PRINT ("%s", "FOUND end-of-group-files marker.");
976 chars_ptr += len_marker;
977 remaining_chars -= len_marker;
979 /* will emit symbol_scope_updated and will flush on disk
980 * tablemaps
982 sdb_engine_second_pass_do (dbe);
984 /* Here we are. It's the right time to notify the listeners
985 * about out fresh new inserted/updated symbols...
986 * Go on by emitting them.
988 while ((tmp_inserted = GPOINTER_TO_INT(
989 g_async_queue_try_pop (priv->inserted_syms_id_aqueue))) > 0)
991 /* we must be sure to insert both signals at once */
992 g_async_queue_lock (priv->signals_aqueue);
994 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
995 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
997 dbesig1->value = GINT_TO_POINTER (SYMBOL_INSERTED + 1);
998 dbesig1->process_id = priv->current_scan_process_id;
1000 dbesig2->value = GINT_TO_POINTER (tmp_inserted);
1001 dbesig2->process_id = priv->current_scan_process_id;
1003 g_async_queue_push_unlocked (priv->signals_aqueue,
1004 dbesig1);
1005 g_async_queue_push_unlocked (priv->signals_aqueue,
1006 dbesig2);
1008 g_async_queue_unlock (priv->signals_aqueue);
1011 while ((tmp_updated = GPOINTER_TO_INT(
1012 g_async_queue_try_pop (priv->updated_syms_id_aqueue))) > 0)
1014 g_async_queue_lock (priv->signals_aqueue);
1016 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1017 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1019 dbesig1->value = GINT_TO_POINTER (SYMBOL_UPDATED + 1);
1020 dbesig1->process_id = priv->current_scan_process_id;
1022 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1023 dbesig2->process_id = priv->current_scan_process_id;
1025 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1026 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1027 g_async_queue_unlock (priv->signals_aqueue);
1030 while ((tmp_updated = GPOINTER_TO_INT(
1031 g_async_queue_try_pop (priv->updated_scope_syms_id_aqueue))) > 0)
1033 g_async_queue_lock (priv->signals_aqueue);
1035 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1036 DBESignal *dbesig2 = g_slice_new0 (DBESignal);
1038 dbesig1->value = GINT_TO_POINTER (SYMBOL_SCOPE_UPDATED + 1);
1039 dbesig1->process_id = priv->current_scan_process_id;
1041 dbesig2->value = GINT_TO_POINTER (tmp_updated);
1042 dbesig2->process_id = priv->current_scan_process_id;
1044 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig1);
1045 g_async_queue_push_unlocked (priv->signals_aqueue, dbesig2);
1046 g_async_queue_unlock (priv->signals_aqueue);
1049 #ifdef DEBUG
1050 if (priv->first_scan_timer_DEBUG != NULL)
1052 DEBUG_PRINT ("~~~~~ TOTAL FIRST SCAN elapsed: %f ",
1053 g_timer_elapsed (priv->first_scan_timer_DEBUG, NULL));
1054 g_timer_destroy (priv->first_scan_timer_DEBUG);
1055 priv->first_scan_timer_DEBUG = NULL;
1057 #endif
1059 DBESignal *dbesig1 = g_slice_new0 (DBESignal);
1061 dbesig1->value = GINT_TO_POINTER (SCAN_END + 1);
1062 dbesig1->process_id = priv->current_scan_process_id;
1064 g_async_queue_push (priv->signals_aqueue, dbesig1);
1067 /* truncate the file to 0 length */
1068 ftruncate (priv->shared_mem_fd, 0);
1070 else
1072 /* marker_ptr is NULL here. We should then exit the loop. */
1073 /* write to shm_file all the chars received */
1074 fwrite (chars_ptr, sizeof(gchar), remaining_chars,
1075 priv->shared_mem_file);
1077 fflush (priv->shared_mem_file);
1078 break;
1081 /* found out a new marker */
1082 marker_ptr = strstr (marker_ptr + len_marker, CTAGS_MARKER);
1083 } while (remaining_chars + len_marker < len_chars || marker_ptr != NULL);
1086 SDB_UNLOCK(priv);
1088 g_free (chars);
1093 * This function runs on the main glib thread, so that it can safely spread signals
1095 static gboolean
1096 sdb_engine_timeout_trigger_signals (gpointer user_data)
1098 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1099 SymbolDBEnginePriv *priv;
1101 g_return_val_if_fail (user_data != NULL, FALSE);
1102 priv = dbe->priv;
1104 if (priv->signals_aqueue != NULL &&
1105 g_async_queue_length (priv->signals_aqueue) > 0)
1107 DBESignal *dbesig;
1108 gsize real_signal;
1109 gint process_id;
1111 while (priv->signals_aqueue != NULL &&
1112 (dbesig = g_async_queue_try_pop (priv->signals_aqueue)) != NULL)
1114 if (dbesig == NULL)
1116 return g_async_queue_length (priv->signals_aqueue) > 0 ? TRUE : FALSE;
1119 real_signal = GPOINTER_TO_INT (dbesig->value) -1;
1120 process_id = dbesig->process_id;
1122 switch (real_signal)
1124 case SINGLE_FILE_SCAN_END:
1126 g_signal_emit (dbe, signals[SINGLE_FILE_SCAN_END], 0);
1128 break;
1130 case SCAN_BEGIN:
1132 DEBUG_PRINT ("%s", "EMITTING scan begin.");
1133 g_signal_emit (dbe, signals[SCAN_BEGIN], 0, process_id);
1135 break;
1137 case SCAN_END:
1139 /* reset count */
1140 priv->symbols_scanned_count = 0;
1142 DEBUG_PRINT ("Committing symboltrans transaction...");
1143 gda_connection_commit_transaction (priv->db_connection, "symboltrans",
1144 NULL);
1145 DEBUG_PRINT ("... Done!");
1147 /* perform flush on db of the tablemaps, if this is the 1st scan */
1148 if (priv->is_first_population == TRUE)
1150 /* ok, set the flag to false. We're done with it */
1151 priv->is_first_population = FALSE;
1154 priv->is_scanning = FALSE;
1156 DEBUG_PRINT ("%s", "EMITTING scan-end");
1157 g_signal_emit (dbe, signals[SCAN_END], 0, process_id);
1159 break;
1161 case SYMBOL_INSERTED:
1163 DBESignal *dbesig2;
1165 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1166 g_signal_emit (dbe, signals[SYMBOL_INSERTED], 0, dbesig2->value);
1168 g_slice_free (DBESignal, dbesig2);
1170 break;
1172 case SYMBOL_UPDATED:
1174 DBESignal *dbesig2;
1176 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1177 g_signal_emit (dbe, signals[SYMBOL_UPDATED], 0, dbesig2->value);
1179 g_slice_free (DBESignal, dbesig2);
1181 break;
1183 case SYMBOL_SCOPE_UPDATED:
1185 DBESignal *dbesig2;
1187 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1188 g_signal_emit (dbe, signals[SYMBOL_SCOPE_UPDATED], 0, dbesig2->value);
1190 g_slice_free (DBESignal, dbesig2);
1192 break;
1194 case SYMBOL_REMOVED:
1196 DBESignal *dbesig2;
1198 dbesig2 = g_async_queue_try_pop (priv->signals_aqueue);
1199 g_signal_emit (dbe, signals[SYMBOL_REMOVED], 0, dbesig2->value);
1201 g_slice_free (DBESignal, dbesig2);
1203 break;
1206 g_slice_free (DBESignal, dbesig);
1208 /* reset to 0 the retries */
1209 priv->trigger_closure_retries = 0;
1211 else {
1212 priv->trigger_closure_retries++;
1215 if (priv->thread_pool != NULL &&
1216 g_thread_pool_unprocessed (priv->thread_pool) == 0 &&
1217 g_thread_pool_get_num_threads (priv->thread_pool) == 0)
1219 /* remove the trigger coz we don't need it anymore... */
1220 g_source_remove (priv->timeout_trigger_handler);
1221 priv->timeout_trigger_handler = 0;
1222 return FALSE;
1225 return TRUE;
1228 static void
1229 sdb_engine_ctags_output_callback_1 (AnjutaLauncher * launcher,
1230 AnjutaLauncherOutputType output_type,
1231 const gchar * chars, gpointer user_data)
1233 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1234 SymbolDBEnginePriv *priv;
1236 g_return_if_fail (user_data != NULL);
1238 priv = dbe->priv;
1240 if (priv->shutting_down == TRUE)
1241 return;
1243 g_thread_pool_push (priv->thread_pool, g_strdup (chars), NULL);
1245 /* signals monitor */
1246 if (priv->timeout_trigger_handler <= 0)
1248 priv->timeout_trigger_handler =
1249 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, TRIGGER_SIGNALS_DELAY,
1250 sdb_engine_timeout_trigger_signals, user_data, NULL);
1251 priv->trigger_closure_retries = 0;
1255 static void
1256 on_scan_files_end_1 (AnjutaLauncher * launcher, int child_pid,
1257 int exit_status, gulong time_taken_in_seconds,
1258 gpointer user_data)
1260 SymbolDBEngine *dbe = (SymbolDBEngine *) user_data;
1261 SymbolDBEnginePriv *priv;
1263 g_return_if_fail (user_data != NULL);
1265 priv = dbe->priv;
1267 DEBUG_PRINT ("***** ctags ended (%s) (%s) *****", priv->ctags_path,
1268 priv->cnc_string);
1270 if (priv->shutting_down == TRUE)
1271 return;
1273 priv->ctags_path = NULL;
1276 static void
1277 sdb_engine_ctags_launcher_create (SymbolDBEngine * dbe)
1279 SymbolDBEnginePriv *priv;
1280 gchar *exe_string;
1282 priv = dbe->priv;
1284 DEBUG_PRINT ("Creating anjuta_launcher with %s for %s", priv->ctags_path,
1285 priv->cnc_string);
1287 priv->ctags_launcher = anjuta_launcher_new ();
1289 anjuta_launcher_set_check_passwd_prompt (priv->ctags_launcher, FALSE);
1290 anjuta_launcher_set_encoding (priv->ctags_launcher, NULL);
1292 g_signal_connect (G_OBJECT (priv->ctags_launcher), "child-exited",
1293 G_CALLBACK (on_scan_files_end_1), dbe);
1295 exe_string = g_strdup_printf ("%s --sort=no --fields=afmiKlnsStTz --c++-kinds=+p "
1296 "--filter=yes --filter-terminator='"CTAGS_MARKER"'",
1297 priv->ctags_path);
1298 DEBUG_PRINT ("Launching %s", exe_string);
1299 anjuta_launcher_execute (priv->ctags_launcher,
1300 exe_string, sdb_engine_ctags_output_callback_1,
1301 dbe);
1302 g_free (exe_string);
1306 * A GAsyncReadyCallback function. This function is the async continuation for
1307 * sdb_engine_scan_files_1 ().
1309 static void
1310 sdb_engine_scan_files_2 (GFile *gfile,
1311 GAsyncResult *res,
1312 gpointer user_data)
1314 ScanFiles1Data *sf_data = (ScanFiles1Data*)user_data;
1315 SymbolDBEngine *dbe;
1316 SymbolDBEnginePriv *priv;
1317 GFileInfo *ginfo;
1318 gchar *local_path;
1319 gchar *real_file;
1320 gboolean symbols_update;
1321 gint partial_count;
1322 gint files_list_len;
1324 dbe = sf_data->dbe;
1325 symbols_update = sf_data->symbols_update;
1326 real_file = sf_data->real_file;
1327 files_list_len = sf_data->files_list_len;
1328 partial_count = sf_data->partial_count;
1330 priv = dbe->priv;
1332 ginfo = g_file_query_info_finish (gfile, res, NULL);
1334 local_path = g_file_get_path (gfile);
1336 if (ginfo == NULL ||
1337 g_file_info_get_attribute_boolean (ginfo,
1338 G_FILE_ATTRIBUTE_ACCESS_CAN_READ) == FALSE)
1340 g_warning ("File does not exist or is unreadable by user (%s)", local_path);
1342 g_free (local_path);
1343 g_free (real_file);
1344 g_free (sf_data);
1346 if (ginfo)
1347 g_object_unref (ginfo);
1348 if (gfile)
1349 g_object_unref (gfile);
1350 return;
1353 /* DEBUG_PRINT ("sent to stdin %s", local_path); */
1354 anjuta_launcher_send_stdin (priv->ctags_launcher, local_path);
1355 anjuta_launcher_send_stdin (priv->ctags_launcher, "\n");
1357 if (symbols_update == TRUE)
1359 DBESignal *dbesig;
1361 /* will this be the last file in the list? */
1362 if (partial_count + 1 >= files_list_len)
1364 dbesig = g_slice_new0 (DBESignal);
1365 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS_AND_EXIT);
1366 dbesig->process_id = priv->current_scan_process_id;
1368 /* yes */
1369 g_async_queue_push (priv->scan_aqueue, dbesig);
1371 else
1373 dbesig = g_slice_new0 (DBESignal);
1374 dbesig->value = GINT_TO_POINTER (DO_UPDATE_SYMS);
1375 dbesig->process_id = priv->current_scan_process_id;
1377 /* no */
1378 g_async_queue_push (priv->scan_aqueue, dbesig);
1381 else
1383 DBESignal *dbesig;
1385 if (partial_count + 1 >= files_list_len)
1387 dbesig = g_slice_new0 (DBESignal);
1388 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS_AND_EXIT);
1389 dbesig->process_id = priv->current_scan_process_id;
1391 /* yes */
1392 g_async_queue_push (priv->scan_aqueue, dbesig);
1394 else
1396 dbesig = g_slice_new0 (DBESignal);
1397 dbesig->value = GINT_TO_POINTER (DONT_UPDATE_SYMS);
1398 dbesig->process_id = priv->current_scan_process_id;
1400 /* no */
1401 g_async_queue_push (priv->scan_aqueue, dbesig);
1405 /* don't forget to add the real_files if the caller provided a list for
1406 * them! */
1407 if (real_file != NULL)
1409 DBESignal *dbesig;
1411 dbesig = g_slice_new0 (DBESignal);
1412 dbesig->value = real_file;
1413 dbesig->process_id = priv->current_scan_process_id;
1415 g_async_queue_push (priv->scan_aqueue, dbesig);
1417 else
1419 DBESignal *dbesig;
1421 dbesig = g_slice_new0 (DBESignal);
1422 dbesig->value = GINT_TO_POINTER (DONT_FAKE_UPDATE_SYMS);
1423 dbesig->process_id = priv->current_scan_process_id;
1425 /* else add a DONT_FAKE_UPDATE_SYMS marker, just to notify that this
1426 * is not a fake file scan
1428 g_async_queue_push (priv->scan_aqueue, dbesig);
1431 /* we don't need ginfo object anymore, bye */
1432 g_object_unref (ginfo);
1433 g_object_unref (gfile);
1434 g_free (local_path);
1435 g_free (sf_data);
1436 /* no need to free real_file. For two reasons: 1. it's null. 2. it has been
1437 * pushed in the async queue and will be freed later
1442 * sdb_sort_files_list:
1443 * file1: First file
1444 * file2: second file
1446 * Returns:
1447 * -1 if file1 will be sorted before file2
1448 * 0 if file1 and file2 are sorted equally
1449 * 1 if file2 will be sorted before file1
1451 static gint sdb_sort_files_list (gconstpointer file1, gconstpointer file2)
1453 const gchar* filename1 = file1;
1454 const gchar* filename2 = file2;
1456 if (g_str_has_suffix (filename1, ".h") ||
1457 g_str_has_suffix (filename1, ".hxx") ||
1458 g_str_has_suffix (filename1, ".hh"))
1460 return -1;
1462 else if (g_str_has_suffix (filename2, ".h") ||
1463 g_str_has_suffix (filename2, ".hxx") ||
1464 g_str_has_suffix (filename2, ".hh"))
1466 return 1;
1469 return 0;
1473 /* Scan with ctags and produce an output 'tags' file [shared memory file]
1474 * containing language symbols. This function will call ctags
1475 * executale and then sdb_engine_populate_db_by_tags () when it'll detect some
1476 * output.
1477 * Please note the files_list/real_files_list parameter:
1478 * this version of sdb_engine_scan_files_1 () let you scan for text buffer(s) that
1479 * will be claimed as buffers for the real files.
1480 * 1. simple mode: files_list represents the real files on disk and so we don't
1481 * need real_files_list, which will be NULL.
1482 * 2. advanced mode: files_list represents temporary flushing of buffers on disk, i.e.
1483 * /tmp/anjuta_XYZ.cxx. real_files_list is the representation of those files on
1484 * database. On the above example we can have anjuta_XYZ.cxx mapped as /src/main.c
1485 * on db. In this mode files_list and real_files_list must have the same size.
1488 static gboolean
1489 sdb_engine_scan_files_1 (SymbolDBEngine * dbe, GPtrArray * files_list,
1490 GPtrArray *real_files_list, gboolean symbols_update,
1491 gint scan_id)
1493 SymbolDBEnginePriv *priv;
1494 gint i;
1496 priv = dbe->priv;
1498 /* if ctags_launcher isn't initialized, then do it now. */
1499 /* lazy initialization */
1500 if (priv->ctags_launcher == NULL)
1502 sdb_engine_ctags_launcher_create (dbe);
1506 /* Enter scanning state */
1507 priv->is_scanning = TRUE;
1509 priv->current_scan_process_id = scan_id;
1511 DBESignal *dbesig;
1513 dbesig = g_slice_new0 (DBESignal);
1514 dbesig->value = GINT_TO_POINTER (SCAN_BEGIN + 1);
1515 dbesig->process_id = priv->current_scan_process_id;
1517 g_async_queue_push (priv->signals_aqueue, dbesig);
1519 #ifdef DEBUG
1520 if (priv->first_scan_timer_DEBUG == NULL)
1521 priv->first_scan_timer_DEBUG = g_timer_new ();
1522 #endif
1524 /* create the shared memory file */
1525 if (priv->shared_mem_file == 0)
1527 gchar *temp_file;
1528 gint i = 0;
1529 while (TRUE)
1531 temp_file = g_strdup_printf ("/anjuta-%d_%ld%d.tags", getpid (),
1532 time (NULL), i++);
1533 gchar *test;
1534 test = g_strconcat (SHARED_MEMORY_PREFIX, temp_file, NULL);
1535 if (g_file_test (test, G_FILE_TEST_EXISTS) == TRUE)
1537 DEBUG_PRINT ("Temp file %s already exists... retrying", test);
1538 g_free (test);
1539 g_free (temp_file);
1540 continue;
1542 else
1544 g_free (test);
1545 break;
1549 priv->shared_mem_str = temp_file;
1551 if ((priv->shared_mem_fd =
1552 shm_open (temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
1554 g_warning ("Error while trying to open a shared memory file. Be"
1555 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
1558 priv->shared_mem_file = fdopen (priv->shared_mem_fd, "a+b");
1560 /* no need to free temp_file (alias shared_mem_str). It will be freed on plugin finalize */
1563 /* Sort the files to have sources before headers */
1564 g_ptr_array_sort (files_list, sdb_sort_files_list);
1565 if (real_files_list)
1566 g_ptr_array_sort (real_files_list, sdb_sort_files_list);
1568 for (i = 0; i < files_list->len; i++)
1570 GFile *gfile;
1571 ScanFiles1Data *sf_data;
1572 gchar *node = (gchar *) g_ptr_array_index (files_list, i);
1573 gfile = g_file_new_for_path (node);
1575 /* prepare an ojbect where to store some data for the async call */
1576 sf_data = g_new0 (ScanFiles1Data, 1);
1577 sf_data->dbe = dbe;
1578 sf_data->files_list_len = files_list->len;
1579 sf_data->partial_count = i;
1580 sf_data->symbols_update = symbols_update;
1582 if (real_files_list != NULL)
1584 sf_data->real_file = g_strdup (g_ptr_array_index (real_files_list, i));
1586 else
1588 sf_data->real_file = NULL;
1591 /* call it */
1592 g_file_query_info_async (gfile,
1593 G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
1594 G_FILE_QUERY_INFO_NONE,
1595 G_PRIORITY_LOW,
1596 NULL,
1597 (GAsyncReadyCallback)sdb_engine_scan_files_2,
1598 sf_data);
1601 return TRUE;
1604 static void
1605 on_scan_files_async_end (SymbolDBEngine *dbe, gint process_id, gpointer user_data)
1607 SymbolDBEnginePriv *priv;
1608 EngineScanDataAsync *esda;
1610 priv = dbe->priv;
1612 /* fine, check on the queue if there's something left to scan */
1613 if ((esda = g_async_queue_try_pop (priv->waiting_scan_aqueue)) == NULL)
1614 return;
1616 sdb_engine_scan_files_1 (dbe, esda->files_list, esda->real_files_list,
1617 esda->symbols_update, esda->scan_id);
1619 sdb_engine_scan_data_destroy (esda);
1622 static gboolean
1623 sdb_engine_scan_files_async (SymbolDBEngine * dbe, GPtrArray * files_list,
1624 GPtrArray *real_files_list, gboolean symbols_update,
1625 gint scan_id)
1627 SymbolDBEnginePriv *priv;
1628 g_return_val_if_fail (files_list != NULL, FALSE);
1630 if (files_list->len == 0)
1631 return FALSE;
1633 priv = dbe->priv;
1635 if (real_files_list != NULL && (files_list->len != real_files_list->len))
1637 g_warning ("no matched size between real_files_list and files_list");
1638 return FALSE;
1641 /* is the engine scanning or is there already something waiting on the queue? */
1642 if (symbol_db_engine_is_scanning (dbe) == TRUE ||
1643 g_async_queue_length (priv->waiting_scan_aqueue) > 0)
1645 /* push the data into the queue for later retrieval */
1646 EngineScanDataAsync * esda = g_new0 (EngineScanDataAsync, 1);
1648 esda->files_list = anjuta_util_clone_string_gptrarray (files_list);
1649 if (real_files_list)
1650 esda->real_files_list = anjuta_util_clone_string_gptrarray (real_files_list);
1651 else
1652 esda->real_files_list = NULL;
1653 esda->symbols_update = symbols_update;
1654 esda->scan_id = scan_id;
1656 g_async_queue_push (priv->waiting_scan_aqueue, esda);
1657 return TRUE;
1660 /* there's no scan active right now nor data waiting on the queue.
1661 * Proceed with normal scan.
1663 sdb_engine_scan_files_1 (dbe, files_list, real_files_list, symbols_update, scan_id);
1665 return TRUE;
1668 static void
1669 sdb_engine_init (SymbolDBEngine * object)
1671 SymbolDBEngine *sdbe;
1672 GHashTable *h;
1674 sdbe = SYMBOL_DB_ENGINE (object);
1675 sdbe->priv = g_new0 (SymbolDBEnginePriv, 1);
1677 sdbe->priv->db_connection = NULL;
1678 sdbe->priv->sql_parser = NULL;
1679 sdbe->priv->db_directory = NULL;
1680 sdbe->priv->project_directory = NULL;
1681 sdbe->priv->cnc_string = NULL;
1683 /* initialize an hash table to be used and shared with Iterators */
1684 sdbe->priv->sym_type_conversion_hash =
1685 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1686 h = sdbe->priv->sym_type_conversion_hash;
1688 /* please if you change some value below here remember to change also on */
1689 g_hash_table_insert (h, g_strdup("class"),
1690 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_CLASS));
1692 g_hash_table_insert (h, g_strdup("enum"),
1693 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUM));
1695 g_hash_table_insert (h, g_strdup("enumerator"),
1696 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_ENUMERATOR));
1698 g_hash_table_insert (h, g_strdup("field"),
1699 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FIELD));
1701 g_hash_table_insert (h, g_strdup("function"),
1702 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FUNCTION));
1704 g_hash_table_insert (h, g_strdup("interface"),
1705 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_INTERFACE));
1707 g_hash_table_insert (h, g_strdup("member"),
1708 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MEMBER));
1710 g_hash_table_insert (h, g_strdup("method"),
1711 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_METHOD));
1713 g_hash_table_insert (h, g_strdup("namespace"),
1714 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_NAMESPACE));
1716 g_hash_table_insert (h, g_strdup("package"),
1717 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PACKAGE));
1719 g_hash_table_insert (h, g_strdup("prototype"),
1720 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_PROTOTYPE));
1722 g_hash_table_insert (h, g_strdup("struct"),
1723 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_STRUCT));
1725 g_hash_table_insert (h, g_strdup("typedef"),
1726 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_TYPEDEF));
1728 g_hash_table_insert (h, g_strdup("union"),
1729 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_UNION));
1731 g_hash_table_insert (h, g_strdup("variable"),
1732 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_VARIABLE));
1734 g_hash_table_insert (h, g_strdup("externvar"),
1735 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_EXTERNVAR));
1737 g_hash_table_insert (h, g_strdup("macro"),
1738 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO));
1740 g_hash_table_insert (h, g_strdup("macro_with_arg"),
1741 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG));
1743 g_hash_table_insert (h, g_strdup("file"),
1744 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_FILE));
1746 g_hash_table_insert (h, g_strdup("other"),
1747 GINT_TO_POINTER (IANJUTA_SYMBOL_TYPE_OTHER));
1750 /* create the hash table that will store shared memory files strings used for
1751 * buffer scanning. Un Engine destroy will unlink () them.
1753 sdbe->priv->garbage_shared_mem_files = g_hash_table_new_full (g_str_hash, g_str_equal,
1754 g_free, NULL);
1756 sdbe->priv->ctags_launcher = NULL;
1757 sdbe->priv->removed_launchers = NULL;
1758 sdbe->priv->shutting_down = FALSE;
1759 sdbe->priv->is_first_population = FALSE;
1761 sdbe->priv->symbols_scanned_count = 0;
1763 /* set the ctags executable path to NULL */
1764 sdbe->priv->ctags_path = NULL;
1766 /* NULL the name of the default db */
1767 sdbe->priv->anjuta_db_file = NULL;
1769 /* identify the scan process with an id. There can be multiple files associated
1770 * within a process. A call to scan_files () will put inside the queue an id
1771 * returned and emitted by scan-end.
1773 sdbe->priv->scan_process_id_sequence = sdbe->priv->current_scan_process_id = 1;
1775 /* the scan_aqueue? It will contain mainly
1776 * ints that refer to the force_update status.
1778 sdbe->priv->scan_aqueue = g_async_queue_new ();
1780 /* the thread pool for tags scannning */
1781 sdbe->priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
1782 sdbe, THREADS_MAX_CONCURRENT,
1783 FALSE, NULL);
1785 /* initialize the sdb mutex */
1786 g_mutex_init (&sdbe->priv->mutex);
1788 /* some signals queues */
1789 sdbe->priv->signals_aqueue = g_async_queue_new ();
1790 sdbe->priv->updated_syms_id_aqueue = g_async_queue_new ();
1791 sdbe->priv->updated_scope_syms_id_aqueue = g_async_queue_new ();
1792 sdbe->priv->inserted_syms_id_aqueue = g_async_queue_new ();
1793 sdbe->priv->is_scanning = FALSE;
1795 sdbe->priv->waiting_scan_aqueue = g_async_queue_new_full (sdb_engine_scan_data_destroy);
1796 sdbe->priv->waiting_scan_handler = g_signal_connect (G_OBJECT (sdbe), "scan-end",
1797 G_CALLBACK (on_scan_files_async_end), NULL);
1801 * STATIC QUERY STRUCTURE INITIALIZE
1804 /* -- workspace -- */
1805 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1806 PREP_QUERY_WORKSPACE_NEW,
1807 "INSERT INTO workspace (workspace_name, analyse_time) VALUES (\
1808 ## /* name:'wsname' type:gchararray */, \
1809 datetime ('now', 'localtime'))");
1811 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1812 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
1813 "SELECT workspace_id FROM workspace \
1814 WHERE \
1815 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1");
1817 /* -- project -- */
1818 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1819 PREP_QUERY_PROJECT_NEW,
1820 "INSERT INTO project (project_name, project_version, wrkspace_id, analyse_time) VALUES (\
1821 ## /* name:'prjname' type:gchararray */, \
1822 ## /* name:'prjversion' type:gchararray */, \
1823 (SELECT workspace_id FROM workspace \
1824 WHERE \
1825 workspace_name = ## /* name:'wsname' type:gchararray */ LIMIT 1), \
1826 datetime ('now', 'localtime'))");
1828 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1829 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME,
1830 "SELECT project_id FROM project \
1831 WHERE \
1832 project_name = ## /* name:'prjname' type:gchararray */ AND \
1833 project_version = ## /* name:'prjversion' type:gchararray */ \
1834 LIMIT 1");
1836 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1837 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME,
1838 "UPDATE project SET \
1839 analyse_time = datetime('now', 'localtime', '+10 seconds') \
1840 WHERE \
1841 project_name = ## /* name:'prjname' type:gchararray */");
1843 /* -- file -- */
1844 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1845 PREP_QUERY_FILE_NEW,
1846 "INSERT INTO file (file_path, prj_id, lang_id, analyse_time) VALUES (\
1847 ## /* name:'filepath' type:gchararray */, \
1848 (SELECT project_id FROM project \
1849 WHERE \
1850 project_name = ## /* name:'prjname' type:gchararray */ AND \
1851 project_version = ## /* name:'prjversion' type:gchararray */ \
1852 LIMIT 1), \
1853 ## /* name:'langid' type:gint */, \
1854 datetime ('now', 'localtime'))");
1856 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1857 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
1858 "SELECT file_id FROM file \
1859 WHERE \
1860 file_path = ## /* name:'filepath' type:gchararray */ LIMIT 1");
1862 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1863 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME,
1864 "SELECT file_id, file_path AS db_file_path, prj_id, lang_id, file.analyse_time \
1865 FROM file JOIN project ON project.project_id = file.prj_id \
1866 WHERE \
1867 project.project_name = ## /* name:'prjname' type:gchararray */");
1869 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1870 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME,
1871 "UPDATE file SET \
1872 analyse_time = datetime('now', 'localtime') \
1873 WHERE \
1874 file_path = ## /* name:'filepath' type:gchararray */");
1876 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1877 PREP_QUERY_GET_ALL_FROM_FILE_WHERE_NOT_IN_SYMBOLS,
1878 "SELECT file_id, file_path AS db_file_path FROM file \
1879 WHERE file_id NOT IN (SELECT file_defined_id FROM symbol)");
1881 /* -- language -- */
1882 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1883 PREP_QUERY_LANGUAGE_NEW,
1884 "INSERT INTO language (language_name) VALUES (\
1885 ## /* name:'langname' type:gchararray */)");
1887 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1888 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
1889 "SELECT language_id FROM language WHERE \
1890 language_name = ## /* name:'langname' type:gchararray */ LIMIT 1");
1892 /* -- sym kind -- */
1893 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1894 PREP_QUERY_SYM_KIND_NEW,
1895 "INSERT INTO sym_kind (kind_name, is_container) VALUES(\
1896 ## /* name:'kindname' type:gchararray */, \
1897 ## /* name:'container' type:gint */)");
1899 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1900 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
1901 "SELECT sym_kind_id FROM sym_kind WHERE \
1902 kind_name = ## /* name:'kindname' type:gchararray */");
1904 /* -- sym access -- */
1905 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1906 PREP_QUERY_SYM_ACCESS_NEW,
1907 "INSERT INTO sym_access (access_name) VALUES(\
1908 ## /* name:'accesskind' type:gchararray */)");
1910 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1911 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
1912 "SELECT access_kind_id FROM sym_access WHERE \
1913 access_name = ## /* name:'accesskind' type:gchararray */ LIMIT 1");
1915 /* -- sym implementation -- */
1916 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1917 PREP_QUERY_SYM_IMPLEMENTATION_NEW,
1918 "INSERT INTO sym_implementation (implementation_name) VALUES(\
1919 ## /* name:'implekind' type:gchararray */)");
1921 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1922 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
1923 "SELECT sym_impl_id FROM sym_implementation WHERE \
1924 kind = ## /* name:'implekind' type:gchararray */ LIMIT 1");
1926 /* -- heritage -- */
1927 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1928 PREP_QUERY_HERITAGE_NEW,
1929 "INSERT INTO heritage (symbol_id_base, symbol_id_derived) VALUES(\
1930 ## /* name:'symbase' type:gint */, \
1931 ## /* name:'symderived' type:gint */)");
1933 /* -- scope -- */
1934 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1935 PREP_QUERY_SCOPE_NEW,
1936 "INSERT INTO scope (scope_name) VALUES(\
1937 ## /* name:'scope' type:gchararray */)");
1939 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1940 PREP_QUERY_GET_SCOPE_ID,
1941 "SELECT scope_id FROM scope \
1942 WHERE scope_name = ## /* name:'scope' type:gchararray */ \
1943 LIMIT 1");
1945 /* -- symbol -- */
1946 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1947 PREP_QUERY_SYMBOL_NEW,
1948 "INSERT INTO symbol (file_defined_id, name, file_position, \
1949 is_file_scope, signature, returntype, \
1950 scope_definition_id, scope_id, \
1951 type_type, type_name, kind_id, access_kind_id, \
1952 implementation_kind_id, update_flag) \
1953 VALUES( \
1954 ## /* name:'filedefid' type:gint */, \
1955 ## /* name:'name' type:gchararray */, \
1956 ## /* name:'fileposition' type:gint */, \
1957 ## /* name:'isfilescope' type:gint */, \
1958 ## /* name:'signature' type:gchararray */, \
1959 ## /* name:'returntype' type:gchararray */, \
1960 ## /* name:'scopedefinitionid' type:gint */, \
1961 ## /* name:'scopeid' type:gint */, \
1962 ## /* name:'typetype' type:gchararray */, \
1963 ## /* name:'typename' type:gchararray */, \
1964 ## /* name:'kindid' type:gint */,## /* name:'accesskindid' type:gint */, \
1965 ## /* name:'implementationkindid' type:gint */, \
1966 ## /* name:'updateflag' type:gint */)");
1969 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1970 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
1971 "SELECT symbol_id FROM symbol \
1972 WHERE scope_id = 0 AND \
1973 type_type='class' AND \
1974 name = ## /* name:'klassname' type:gchararray */ LIMIT 1");
1976 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1977 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
1978 "SELECT symbol_id FROM symbol JOIN scope ON symbol.scope_id = scope.scope_id \
1979 WHERE symbol.name = ## /* name:'klassname' type:gchararray */ AND \
1980 scope.scope_name = ## /* name:'namespacename' type:gchararray */ AND \
1981 symbol.type_type = 'namespace' LIMIT 1");
1983 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1984 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID,
1985 "UPDATE OR IGNORE symbol SET scope_id = (SELECT scope_definition_id FROM symbol WHERE \
1986 type_type = ## /* name:'tokenname' type:gchararray */ AND \
1987 type_name = ## /* name:'objectname' type:gchararray */ LIMIT 1) \
1988 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
1990 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
1991 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
1992 "SELECT symbol_id FROM symbol \
1993 WHERE \
1994 name = ## /* name:'symname' type:gchararray */ AND \
1995 file_defined_id = ## /* name:'filedefid' type:gint */ AND \
1996 type_type = ## /* name:'typetype' type:gchararray */ AND \
1997 type_name = ## /* name:'typename' type:gchararray */ AND \
1998 update_flag = 0 \
1999 ORDER BY abs(file_position - ## /* name:'fileposition' type:gint */) \
2000 LIMIT 1");
2002 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2003 PREP_QUERY_UPDATE_SYMBOL_ALL,
2004 "UPDATE symbol SET \
2005 is_file_scope = ## /* name:'isfilescope' type:gint */, \
2006 file_position = ## /* name:'fileposition' type:gint */, \
2007 signature = ## /* name:'signature' type:gchararray */, \
2008 returntype = ## /* name:'returntype' type:gchararray */, \
2009 scope_definition_id = ## /* name:'scopedefinitionid' type:gint */, \
2010 scope_id = ## /* name:'scopeid' type:gint */, \
2011 kind_id = ## /* name:'kindid' type:gint */, \
2012 access_kind_id = ## /* name:'accesskindid' type:gint */, \
2013 implementation_kind_id = ## /* name:'implementationkindid' type:gint */, \
2014 update_flag = ## /* name:'updateflag' type:gint */ \
2015 WHERE symbol_id = ## /* name:'symbolid' type:gint */");
2017 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2018 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS,
2019 "DELETE FROM symbol WHERE \
2020 file_defined_id = (SELECT file_id FROM file \
2021 WHERE \
2022 file.file_path = ## /* name:'filepath' type:gchararray */) AND \
2023 update_flag = 0");
2025 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2026 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS,
2027 "UPDATE symbol SET \
2028 update_flag = 0 \
2029 WHERE file_defined_id = (SELECT file_id FROM file \
2030 WHERE \
2031 file_path = ## /* name:'filepath' type:gchararray */)");
2033 /* -- tmp_removed -- */
2034 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2035 PREP_QUERY_GET_REMOVED_IDS,
2036 "SELECT symbol_removed_id FROM __tmp_removed");
2038 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2039 PREP_QUERY_TMP_REMOVED_DELETE_ALL,
2040 "DELETE FROM __tmp_removed");
2042 STATIC_QUERY_POPULATE_INIT_NODE(sdbe->priv->static_query_list,
2043 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME,
2044 "DELETE FROM file WHERE \
2045 prj_id = (SELECT project_id FROM project \
2046 WHERE project_name = ## /* name:'prjname' type:gchararray */) AND \
2047 file_path = ## /* name:'filepath' type:gchararray */");
2049 /* init cache hashtables */
2050 sdb_engine_init_caches (sdbe);
2052 /* init table maps */
2053 sdb_engine_init_table_maps (sdbe);
2056 static void
2057 sdb_engine_unlink_shared_files (gpointer key, gpointer value, gpointer user_data)
2059 shm_unlink (key);
2062 static void
2063 sdb_engine_unref_removed_launchers (gpointer data, gpointer user_data)
2065 g_object_unref (data);
2068 static void
2069 sdb_engine_finalize (GObject * object)
2071 SymbolDBEngine *dbe;
2072 SymbolDBEnginePriv *priv;
2074 dbe = SYMBOL_DB_ENGINE (object);
2075 priv = dbe->priv;
2076 /*/ FIXME a crash here ?!
2077 g_signal_handler_disconnect (dbe, priv->waiting_scan_handler);
2078 priv->waiting_scan_handler = 0;
2079 //*/
2080 if (priv->thread_pool)
2082 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2083 priv->thread_pool = NULL;
2086 if (priv->ctags_launcher)
2088 g_object_unref (priv->ctags_launcher);
2089 priv->ctags_launcher = NULL;
2092 if (priv->removed_launchers)
2094 g_list_foreach (priv->removed_launchers,
2095 sdb_engine_unref_removed_launchers, NULL);
2096 g_list_free (priv->removed_launchers);
2097 priv->removed_launchers = NULL;
2100 g_mutex_clear (&priv->mutex);
2102 if (priv->timeout_trigger_handler > 0)
2103 g_source_remove (priv->timeout_trigger_handler);
2105 if (symbol_db_engine_is_connected (dbe) == TRUE)
2106 sdb_engine_disconnect_from_db (dbe);
2108 sdb_engine_free_cached_queries (dbe);
2110 if (priv->scan_aqueue)
2112 g_async_queue_unref (priv->scan_aqueue);
2113 priv->scan_aqueue = NULL;
2116 if (priv->updated_syms_id_aqueue)
2118 g_async_queue_unref (priv->updated_syms_id_aqueue);
2119 priv->updated_syms_id_aqueue = NULL;
2122 if (priv->updated_scope_syms_id_aqueue)
2124 g_async_queue_unref (priv->updated_scope_syms_id_aqueue);
2125 priv->updated_scope_syms_id_aqueue = NULL;
2128 if (priv->inserted_syms_id_aqueue)
2130 g_async_queue_unref (priv->inserted_syms_id_aqueue);
2131 priv->inserted_syms_id_aqueue = NULL;
2134 if (priv->waiting_scan_aqueue)
2136 g_async_queue_unref (priv->waiting_scan_aqueue);
2137 priv->waiting_scan_aqueue = NULL;
2140 if (priv->shared_mem_file)
2142 fclose (priv->shared_mem_file);
2143 priv->shared_mem_file = NULL;
2146 if (priv->shared_mem_str)
2148 shm_unlink (priv->shared_mem_str);
2149 g_free (priv->shared_mem_str);
2150 priv->shared_mem_str = NULL;
2153 if (priv->garbage_shared_mem_files)
2155 g_hash_table_foreach (priv->garbage_shared_mem_files,
2156 sdb_engine_unlink_shared_files,
2157 NULL);
2158 /* destroy the hash table */
2159 g_hash_table_destroy (priv->garbage_shared_mem_files);
2163 if (priv->sym_type_conversion_hash)
2164 g_hash_table_destroy (priv->sym_type_conversion_hash);
2165 priv->sym_type_conversion_hash = NULL;
2167 if (priv->signals_aqueue)
2168 g_async_queue_unref (priv->signals_aqueue);
2169 priv->signals_aqueue = NULL;
2171 sdb_engine_clear_caches (dbe);
2172 sdb_engine_clear_tablemaps (dbe);
2174 g_free (priv->anjuta_db_file);
2175 priv->anjuta_db_file = NULL;
2177 g_free (priv->ctags_path);
2178 priv->ctags_path = NULL;
2180 g_free (priv);
2182 G_OBJECT_CLASS (parent_class)->finalize (object);
2185 static void
2186 sdb_engine_class_init (SymbolDBEngineClass * klass)
2188 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2189 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2191 object_class->finalize = sdb_engine_finalize;
2193 signals[DB_CONNECTED]
2194 = g_signal_new ("db-connected",
2195 G_OBJECT_CLASS_TYPE (object_class),
2196 G_SIGNAL_RUN_LAST,
2197 G_STRUCT_OFFSET (SymbolDBEngineClass, db_connected),
2198 NULL, NULL,
2199 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2201 signals[DB_DISCONNECTED]
2202 = g_signal_new ("db-disconnected",
2203 G_OBJECT_CLASS_TYPE (object_class),
2204 G_SIGNAL_RUN_LAST,
2205 G_STRUCT_OFFSET (SymbolDBEngineClass, db_disconnected),
2206 NULL, NULL,
2207 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2209 signals[SCAN_BEGIN]
2210 = g_signal_new ("scan-begin",
2211 G_OBJECT_CLASS_TYPE (object_class),
2212 G_SIGNAL_RUN_LAST,
2213 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_begin),
2214 NULL, NULL,
2215 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2217 G_TYPE_INT);
2219 signals[SINGLE_FILE_SCAN_END]
2220 = g_signal_new ("single-file-scan-end",
2221 G_OBJECT_CLASS_TYPE (object_class),
2222 G_SIGNAL_RUN_FIRST,
2223 G_STRUCT_OFFSET (SymbolDBEngineClass, single_file_scan_end),
2224 NULL, NULL,
2225 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2227 signals[SCAN_END]
2228 = g_signal_new ("scan-end",
2229 G_OBJECT_CLASS_TYPE (object_class),
2230 G_SIGNAL_RUN_LAST,
2231 G_STRUCT_OFFSET (SymbolDBEngineClass, scan_end),
2232 NULL, NULL,
2233 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2235 G_TYPE_INT);
2237 signals[SYMBOL_INSERTED]
2238 = g_signal_new ("symbol-inserted",
2239 G_OBJECT_CLASS_TYPE (object_class),
2240 G_SIGNAL_RUN_LAST,
2241 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_inserted),
2242 NULL, NULL,
2243 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2245 G_TYPE_INT);
2247 signals[SYMBOL_UPDATED]
2248 = g_signal_new ("symbol-updated",
2249 G_OBJECT_CLASS_TYPE (object_class),
2250 G_SIGNAL_RUN_LAST,
2251 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_updated),
2252 NULL, NULL,
2253 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2255 G_TYPE_INT);
2257 signals[SYMBOL_SCOPE_UPDATED]
2258 = g_signal_new ("symbol-scope-updated",
2259 G_OBJECT_CLASS_TYPE (object_class),
2260 G_SIGNAL_RUN_LAST,
2261 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_scope_updated),
2262 NULL, NULL,
2263 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2265 G_TYPE_INT);
2267 signals[SYMBOL_REMOVED]
2268 = g_signal_new ("symbol-removed",
2269 G_OBJECT_CLASS_TYPE (object_class),
2270 G_SIGNAL_RUN_LAST,
2271 G_STRUCT_OFFSET (SymbolDBEngineClass, symbol_removed),
2272 NULL, NULL,
2273 g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
2275 G_TYPE_INT);
2278 GType
2279 sdb_engine_get_type (void)
2281 static GType our_type = 0;
2283 if (our_type == 0)
2285 static const GTypeInfo our_info = {
2286 sizeof (SymbolDBEngineClass), /* class_size */
2287 (GBaseInitFunc) NULL, /* base_init */
2288 (GBaseFinalizeFunc) NULL, /* base_finalize */
2289 (GClassInitFunc) sdb_engine_class_init, /* class_init */
2290 (GClassFinalizeFunc) NULL, /* class_finalize */
2291 NULL /* class_data */ ,
2292 sizeof (SymbolDBEngine), /* instance_size */
2293 0, /* n_preallocs */
2294 (GInstanceInitFunc) sdb_engine_init, /* instance_init */
2295 NULL /* value_table */
2298 our_type = g_type_register_static (G_TYPE_OBJECT, "SymbolDBEngine",
2299 &our_info, 0);
2302 return our_type;
2306 * symbol_db_engine_set_ctags_path:
2307 * @dbe: self
2308 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2310 * Set a new path for anjuta-tags executable.
2312 * Returns: TRUE if the set is successful.
2314 gboolean
2315 symbol_db_engine_set_ctags_path (SymbolDBEngine * dbe, const gchar * ctags_path)
2317 SymbolDBEnginePriv *priv;
2319 g_return_val_if_fail (dbe != NULL, FALSE);
2320 g_return_val_if_fail (ctags_path != NULL, FALSE);
2322 priv = dbe->priv;
2324 /* Check if ctags is really installed */
2325 if (!anjuta_util_prog_is_installed (ctags_path, TRUE))
2327 g_warning ("symbol_db_engine_set_ctags_path (): Wrong path for ctags. Keeping "
2328 "the old value %s", priv->ctags_path);
2329 return priv->ctags_path != NULL;
2332 /* have we already got it? */
2333 if (priv->ctags_path != NULL &&
2334 g_strcmp0 (priv->ctags_path, ctags_path) == 0)
2335 return TRUE;
2337 /* free the old value */
2338 g_free (priv->ctags_path);
2340 /* is anjutalauncher already created? */
2341 if (priv->ctags_launcher != NULL)
2343 AnjutaLauncher *tmp;
2344 tmp = priv->ctags_launcher;
2346 /* recreate it on the fly */
2347 sdb_engine_ctags_launcher_create (dbe);
2349 /* keep the launcher alive to avoid crashes */
2350 priv->removed_launchers = g_list_prepend (priv->removed_launchers, tmp);
2353 /* set the new one */
2354 priv->ctags_path = g_strdup (ctags_path);
2355 return TRUE;
2359 * symbol_db_engine_new:
2360 * @ctags_path Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2362 * Create a new instance of an engine.
2363 * Default name of database is ANJUTA_DB_FILE (see symbol-db-engine-priv.h)
2365 * Returns: a new SymbolDBEngine object.
2367 SymbolDBEngine *
2368 symbol_db_engine_new (const gchar * ctags_path)
2370 SymbolDBEngine *sdbe;
2371 SymbolDBEnginePriv *priv;
2373 g_return_val_if_fail (ctags_path != NULL, NULL);
2374 sdbe = g_object_new (SYMBOL_TYPE_DB_ENGINE, NULL);
2376 priv = sdbe->priv;
2377 priv->anjuta_db_file = g_strdup (ANJUTA_DB_FILE);
2379 /* set the mandatory ctags_path */
2380 if (!symbol_db_engine_set_ctags_path (sdbe, ctags_path))
2382 return NULL;
2385 return sdbe;
2389 * symbol_db_engine_new_full:
2390 * @ctags_path: Anjuta-tags executable. It is mandatory. No NULL value is accepted.
2391 * @database_name: name of resulting db on disk.
2393 * Similar to symbol_db_engine_new() but you can specify the name of resulting db.
2395 SymbolDBEngine*
2396 symbol_db_engine_new_full (const gchar * ctags_path, const gchar * database_name)
2398 SymbolDBEngine* dbe;
2399 SymbolDBEnginePriv* priv;
2401 g_return_val_if_fail (database_name != NULL, NULL);
2402 dbe = symbol_db_engine_new (ctags_path);
2404 g_return_val_if_fail (dbe != NULL, NULL);
2406 priv = dbe->priv;
2407 g_free (priv->anjuta_db_file);
2408 priv->anjuta_db_file = g_strdup (database_name);
2410 return dbe;
2414 * Set some default parameters to use with the current database.
2416 static void
2417 sdb_engine_set_defaults_db_parameters (SymbolDBEngine * dbe)
2419 sdb_engine_execute_unknown_sql (dbe, "PRAGMA page_size = 32768");
2420 sdb_engine_execute_unknown_sql (dbe, "PRAGMA cache_size = 12288");
2421 sdb_engine_execute_unknown_sql (dbe, "PRAGMA synchronous = OFF");
2422 sdb_engine_execute_unknown_sql (dbe, "PRAGMA temp_store = MEMORY");
2423 sdb_engine_execute_unknown_sql (dbe, "PRAGMA journal_mode = OFF");
2424 sdb_engine_execute_unknown_sql (dbe, "PRAGMA read_uncommitted = 1");
2425 sdb_engine_execute_unknown_sql (dbe, "PRAGMA foreign_keys = OFF");
2426 symbol_db_engine_set_db_case_sensitive (dbe, TRUE);
2429 /* Will create priv->db_connection.
2430 * Connect to database identified by db_directory.
2431 * Usually db_directory is defined also into priv. We let it here as parameter
2432 * because it is required and cannot be null.
2434 static gboolean
2435 sdb_engine_connect_to_db (SymbolDBEngine * dbe, const gchar *cnc_string, GError **error)
2437 SymbolDBEnginePriv *priv;
2439 g_return_val_if_fail (dbe != NULL, FALSE);
2440 priv = dbe->priv;
2442 if (priv->db_connection != NULL)
2444 /* if it's the case that the connection isn't NULL, we
2445 * should notify the user
2446 * and return FALSE. It's his task to disconnect and retry to connect */
2447 g_warning ("connection is already established. Please disconnect "
2448 "and then try to reconnect.");
2449 return FALSE;
2452 /* establish a connection. If the sqlite file does not exist it will
2453 * be created
2455 priv->db_connection = gda_connection_open_from_string ("SQLite", cnc_string, NULL,
2456 GDA_CONNECTION_OPTIONS_THREAD_SAFE, error);
2458 if (!GDA_IS_CONNECTION (priv->db_connection))
2460 g_warning ("Could not open connection to %s\n", cnc_string);
2461 return FALSE;
2464 priv->cnc_string = g_strdup (cnc_string);
2465 priv->sql_parser = gda_connection_create_parser (priv->db_connection);
2467 if (!GDA_IS_SQL_PARSER (priv->sql_parser))
2469 g_set_error_literal (error, SYMBOL_DB_ENGINE_ERROR,
2470 SYMBOL_DB_ENGINE_ERROR_INVALID_PARSER,
2471 _("Could not create sql parser. Check your libgda installation"));
2472 return FALSE;
2475 DEBUG_PRINT ("Connected to database %s", cnc_string);
2476 return TRUE;
2480 * symbol_db_engine_is_connected:
2481 * @dbe: self
2483 * Check whether the engine is connected to db or not.
2485 * Returns: TRUE if the db is connected.
2487 gboolean
2488 symbol_db_engine_is_connected (SymbolDBEngine * dbe)
2490 SymbolDBEnginePriv *priv;
2492 g_return_val_if_fail (dbe != NULL, FALSE);
2493 priv = dbe->priv;
2495 return priv->db_connection && priv->cnc_string && priv->sql_parser &&
2496 gda_connection_is_opened (priv->db_connection );
2500 * symbol_db_engine_is_scanning:
2501 * @dbe: self
2503 * Check if engine is scanning busy
2505 * Returns: TRUE if it is scanning.
2507 gboolean
2508 symbol_db_engine_is_scanning (SymbolDBEngine *dbe)
2510 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), FALSE);
2511 return dbe->priv->is_scanning;
2515 * Creates required tables for the database to work.
2516 * Sets is_first_population flag to TRUE.
2517 * @param tables_sql_file File containing sql code.
2519 static gboolean
2520 sdb_engine_create_db_tables (SymbolDBEngine * dbe, const gchar * tables_sql_file)
2522 SymbolDBEnginePriv *priv;
2523 gchar *contents;
2524 gchar *query;
2525 gsize sizez;
2527 g_return_val_if_fail (tables_sql_file != NULL, FALSE);
2529 priv = dbe->priv;
2531 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2533 /* read the contents of the file */
2534 if (g_file_get_contents (tables_sql_file, &contents, &sizez, NULL) == FALSE)
2536 g_warning ("Something went wrong while trying to read %s",
2537 tables_sql_file);
2539 return FALSE;
2542 sdb_engine_execute_non_select_sql (dbe, contents);
2543 g_free (contents);
2545 /* set the current symbol db database version. This may help if new tables/fields
2546 * are added/removed in future versions.
2548 query = "INSERT INTO version VALUES ("SYMBOL_DB_VERSION")";
2549 sdb_engine_execute_non_select_sql (dbe, query);
2551 priv->is_first_population = TRUE;
2553 /* no need to free query of course */
2555 return TRUE;
2559 * symbol_db_engine_db_exists:
2560 * @dbe: self
2561 * @prj_directory: absolute path of the project.
2563 * Check if the database already exists into the prj_directory
2565 * Returns: TRUE if db exists on disk.
2567 gboolean
2568 symbol_db_engine_db_exists (SymbolDBEngine * dbe, const gchar * prj_directory)
2570 SymbolDBEnginePriv *priv;
2572 g_return_val_if_fail (prj_directory != NULL, FALSE);
2574 priv = dbe->priv;
2576 /* check whether the db filename already exists.*/
2577 gchar *tmp_file = g_strdup_printf ("%s/%s.db", prj_directory,
2578 priv->anjuta_db_file);
2580 if (g_file_test (tmp_file, G_FILE_TEST_EXISTS) == FALSE)
2582 DEBUG_PRINT ("db %s does not exist", tmp_file);
2583 g_free (tmp_file);
2584 return FALSE;
2587 g_free (tmp_file);
2588 return TRUE;
2592 * symbol_db_engine_file_exists:
2593 * @dbe: self
2594 * @abs_file_path: absolute file path.
2596 * Check if a file is already present [and scanned] in db.
2597 * ~~~ Thread note: this function locks the mutex ~~~
2599 * Returns: TRUE if the file is present.
2601 gboolean
2602 symbol_db_engine_file_exists (SymbolDBEngine * dbe, const gchar * abs_file_path)
2604 SymbolDBEnginePriv *priv;
2605 const gchar *relative;
2606 gint file_defined_id;
2607 GValue v = {0};
2609 g_return_val_if_fail (dbe != NULL, FALSE);
2610 g_return_val_if_fail (abs_file_path != NULL, FALSE);
2612 priv = dbe->priv;
2614 SDB_LOCK(priv);
2616 relative = symbol_db_util_get_file_db_path (dbe, abs_file_path);
2617 if (relative == NULL)
2619 SDB_UNLOCK(priv);
2620 return FALSE;
2623 SDB_GVALUE_SET_STATIC_STRING(v, relative);
2625 if ((file_defined_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
2626 PREP_QUERY_GET_FILE_ID_BY_UNIQUE_NAME,
2627 "filepath",
2628 &v)) < 0)
2630 SDB_UNLOCK(priv);
2631 return FALSE;
2634 SDB_UNLOCK(priv);
2635 return TRUE;
2638 /**
2639 * symbol_db_engine_close_db:
2640 * @dbe: self
2642 * Disconnect db, gda client and db_connection
2644 * Returns: TRUE if closing has been successful.
2646 gboolean
2647 symbol_db_engine_close_db (SymbolDBEngine *dbe)
2649 SymbolDBEnginePriv *priv;
2650 gboolean ret;
2651 g_return_val_if_fail (dbe != NULL, FALSE);
2653 priv = dbe->priv;
2655 /* terminate threads, if ever they're running... */
2656 g_thread_pool_free (priv->thread_pool, TRUE, TRUE);
2657 priv->thread_pool = NULL;
2658 ret = sdb_engine_disconnect_from_db (dbe);
2660 /* reset count */
2661 priv->symbols_scanned_count = 0;
2663 g_free (priv->db_directory);
2664 priv->db_directory = NULL;
2666 g_free (priv->project_directory);
2667 priv->project_directory = NULL;
2669 priv->thread_pool = g_thread_pool_new (sdb_engine_ctags_output_thread,
2670 dbe, THREADS_MAX_CONCURRENT,
2671 FALSE, NULL);
2672 g_signal_emit_by_name (dbe, "db-disconnected", NULL);
2673 return ret;
2676 static gdouble
2677 sdb_engine_get_db_version (SymbolDBEngine *dbe)
2679 GdaDataModel *data_model;
2680 const GValue *value_id;
2681 gchar *query;
2682 gdouble version_id;
2683 gint col;
2685 /* set the current symbol db database version. This may help if new tables/fields
2686 * are added/removed in future versions.
2688 query = "SELECT sdb_version FROM version";
2689 if ((data_model = sdb_engine_execute_select_sql (dbe, query)) == NULL)
2691 return -1;
2694 col = gda_data_model_get_column_index(data_model, "sdb_version");
2695 value_id = gda_data_model_get_value_at (data_model, col, 0, NULL);
2697 if (G_VALUE_HOLDS_DOUBLE (value_id))
2698 version_id = g_value_get_double (value_id);
2699 else
2700 version_id = (gdouble)g_value_get_int (value_id);
2702 g_object_unref (data_model);
2703 /* no need to free query of course */
2705 return version_id;
2708 static gboolean
2709 sdb_engine_check_db_version_and_upgrade (SymbolDBEngine *dbe,
2710 const gchar* db_file,
2711 const gchar* cnc_string)
2713 gdouble version;
2716 version = sdb_engine_get_db_version (dbe);
2717 DEBUG_PRINT ("Checking db version...");
2718 if (version <= 0)
2720 /* some error occurred */
2721 g_warning ("No version of db detected. This can produce many errors. DB"
2722 "will be recreated from scratch.");
2724 /* force version to 0 */
2725 version = 0;
2728 if (version < atof (SYMBOL_DB_VERSION))
2730 DEBUG_PRINT ("Upgrading from version %f to "SYMBOL_DB_VERSION, version);
2732 /* we need a full recreation of db. Because of the sym_kind table
2733 * which changed its data but not its fields, we must recreate the
2734 * whole database.
2737 /* 1. disconnect from current db */
2738 sdb_engine_disconnect_from_db (dbe);
2740 /* 2. remove current db file */
2741 GFile *gfile = g_file_new_for_path (db_file);
2742 if (gfile != NULL) {
2743 g_file_delete (gfile, NULL, NULL);
2744 g_object_unref (gfile);
2746 else
2748 g_warning ("Could not get the gfile");
2751 /* 3. reconnect */
2752 sdb_engine_connect_to_db (dbe, cnc_string, NULL);
2754 /* 4. create fresh new tables, indexes, triggers etc. */
2755 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2756 return TRUE;
2758 else
2760 DEBUG_PRINT ("No need to upgrade.");
2763 return FALSE;
2767 * symbol_db_engine_open_db:
2768 * @dbe: self
2769 * @base_db_path: directory where .anjuta_sym_db.db will be stored. It can be
2770 * different from project_directory
2771 * E.g: a db on '/tmp/foo/' dir.
2772 * @prj_directory: project directory. It may be different from base_db_path.
2773 * It's mainly used to map files inside the db. Say for example that you want to
2774 * add to a project a file /home/user/project/foo_prj/src/file.c with a project
2775 * directory of /home/user/project/foo_prj/. On db it'll be represented as
2776 * src/file.c. In this way you can move around the project dir without dealing
2777 * with relative paths.
2778 * @error: a place to store an error, or %NULL
2780 * Open, create or upgrade a database at given directory.
2781 * Be sure to give a base_db_path with the ending '/' for directory.
2783 * Returns: An opening status from SymbolDBEngineOpenStatus enum.
2785 SymbolDBEngineOpenStatus
2786 symbol_db_engine_open_db (SymbolDBEngine * dbe, const gchar * base_db_path,
2787 const gchar * prj_directory, GError **error)
2789 SymbolDBEnginePriv *priv;
2790 gboolean needs_tables_creation = FALSE;
2791 gchar *cnc_string;
2792 gboolean connect_res;
2793 gboolean ret_status = DB_OPEN_STATUS_NORMAL;
2795 DEBUG_PRINT ("Opening project %s with base dir %s",
2796 prj_directory, base_db_path);
2798 g_return_val_if_fail (dbe != NULL, FALSE);
2799 g_return_val_if_fail (base_db_path != NULL, FALSE);
2801 priv = dbe->priv;
2803 priv->symbols_scanned_count = 0;
2805 /* check whether the db filename already exists. If it's not the case
2806 * create the tables for the database. */
2807 gchar *db_file = g_strdup_printf ("%s/%s.db", base_db_path,
2808 priv->anjuta_db_file);
2810 if (g_file_test (db_file, G_FILE_TEST_EXISTS) == FALSE)
2812 needs_tables_creation = TRUE;
2815 priv->db_directory = g_strdup (base_db_path);
2817 /* save the project_directory */
2818 priv->project_directory = g_strdup (prj_directory);
2820 cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", base_db_path,
2821 priv->anjuta_db_file);
2822 DEBUG_PRINT ("Connecting to "
2823 "database with %s...", cnc_string);
2824 connect_res = sdb_engine_connect_to_db (dbe, cnc_string, error);
2827 if (connect_res == FALSE)
2829 g_free (db_file);
2830 g_free (cnc_string);
2832 ret_status = DB_OPEN_STATUS_FATAL;
2833 return ret_status;
2836 if (needs_tables_creation == TRUE)
2838 DEBUG_PRINT ("Creating tables...");
2839 sdb_engine_create_db_tables (dbe, TABLES_SQL);
2840 ret_status = DB_OPEN_STATUS_CREATE;
2842 else
2844 /* check the version of the db. If it's old we should upgrade it */
2845 if (sdb_engine_check_db_version_and_upgrade (dbe, db_file, cnc_string) == TRUE)
2847 ret_status = DB_OPEN_STATUS_UPGRADE;
2851 sdb_engine_set_defaults_db_parameters (dbe);
2853 g_free (cnc_string);
2854 g_free (db_file);
2856 /* we're now able to emit the db-connected signal: tables should be created
2857 * and libgda should be connected to an usable db.
2859 g_signal_emit_by_name (dbe, "db-connected", NULL);
2861 return ret_status;
2865 * symbol_db_engine_get_cnc_string:
2866 * @dbe: self
2868 * Getter for the connection string.
2870 * Returns: The connection string. It must be freed by caller.
2872 gchar *
2873 symbol_db_engine_get_cnc_string (SymbolDBEngine * dbe)
2875 SymbolDBEnginePriv *priv;
2877 g_return_val_if_fail (dbe != NULL, FALSE);
2878 priv = dbe->priv;
2880 return g_strdup (priv->cnc_string);
2883 /**
2884 * symbol_db_engine_add_new_workspace:
2885 * @dbe: self
2886 * @workspace_name: name of workspace.
2888 * Add a new workspace to an opened database.
2889 * ~~~ Thread note: this function locks the mutex ~~~
2891 * Returns: TRUE if operation is successful.
2893 gboolean
2894 symbol_db_engine_add_new_workspace (SymbolDBEngine * dbe,
2895 const gchar * workspace_name)
2897 const GdaSet *plist;
2898 const GdaStatement *stmt;
2899 GdaHolder *param;
2900 SymbolDBEnginePriv *priv;
2901 GValue v = {0};
2903 g_return_val_if_fail (dbe != NULL, FALSE);
2904 priv = dbe->priv;
2906 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2908 SDB_LOCK(priv);
2910 if ((stmt =
2911 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_WORKSPACE_NEW)) == NULL)
2913 g_warning ("query is null");
2914 SDB_UNLOCK(priv);
2915 return FALSE;
2918 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_WORKSPACE_NEW);
2920 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
2922 g_warning ("param is NULL from pquery!\n");
2923 SDB_UNLOCK(priv);
2924 return FALSE;
2926 SDB_PARAM_SET_STRING(param, workspace_name);
2928 /* execute the query with parameters just set */
2929 if (gda_connection_statement_execute_non_select (priv->db_connection,
2930 (GdaStatement*)stmt,
2931 (GdaSet*)plist, NULL, NULL) == -1)
2933 SDB_UNLOCK(priv);
2934 return FALSE;
2937 SDB_UNLOCK(priv);
2938 return TRUE;
2941 /**
2942 * symbol_db_engine_project_exists:
2943 * @dbe: self
2944 * @project_name: Project name.
2945 * @project_version: The version of the project.
2947 * Test project existence.
2948 * ~~~ Thread note: this function locks the mutex ~~~
2950 * Returns: FALSE if project isn't found. TRUE otherwise.
2952 gboolean
2953 symbol_db_engine_project_exists (SymbolDBEngine * dbe,
2954 const gchar * project_name,
2955 const gchar * project_version)
2957 SymbolDBEnginePriv *priv;
2958 GValue v = {0};
2959 const GdaSet *plist;
2960 const GdaStatement *stmt;
2961 GdaHolder *param;
2962 GdaDataModel *data_model;
2964 priv = dbe->priv;
2966 SDB_LOCK(priv);
2968 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
2970 /* test the existence of the project in db */
2971 /* get prepared query */
2972 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
2973 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME)) == NULL)
2975 g_warning ("Query is null");
2976 SDB_UNLOCK(priv);
2977 return FALSE;
2980 plist = sdb_engine_get_query_parameters_list (dbe,
2981 PREP_QUERY_GET_PROJECT_ID_BY_UNIQUE_NAME);
2983 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
2985 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
2986 "from pquery!\n");
2987 SDB_UNLOCK(priv);
2988 return FALSE;
2991 SDB_PARAM_SET_STRING (param, project_name);
2993 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
2995 g_warning ("sdb_engine_get_tuple_id_by_unique_name: param is NULL "
2996 "from pquery!\n");
2997 SDB_UNLOCK(priv);
2998 return FALSE;
3001 SDB_PARAM_SET_STRING (param, project_version);
3003 /* execute the query with parameters just set */
3004 data_model = gda_connection_statement_execute_select (priv->db_connection,
3005 (GdaStatement*)stmt,
3006 (GdaSet*)plist, NULL);
3008 if (!GDA_IS_DATA_MODEL (data_model) ||
3009 gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model)) <= 0)
3011 if (data_model != NULL)
3012 g_object_unref (data_model);
3013 SDB_UNLOCK(priv);
3014 return FALSE;
3017 /* we found it and we can return */
3018 g_object_unref (data_model);
3020 SDB_UNLOCK(priv);
3022 return TRUE;
3025 /**
3026 * symbol_db_engine_add_new_project:
3027 * @dbe: self
3028 * @workspace: Can be NULL. In that case a default workspace will be created,
3029 * and project will depend on that.
3030 * @project: Project name. Must NOT be NULL.
3031 * @version: Version of the project, or of the package that project represents.
3032 * If not sure pass "1.0".
3034 * Adds a new project to db.
3035 * ~~~ Thread note: this function locks the mutex ~~~
3037 * Returns: TRUE if operation is successful.
3039 gboolean
3040 symbol_db_engine_add_new_project (SymbolDBEngine * dbe, const gchar * workspace,
3041 const gchar * project, const gchar* version)
3043 const GdaSet *plist;
3044 const GdaStatement *stmt;
3045 GdaHolder *param;
3046 const gchar *workspace_name;
3047 gint wks_id;
3048 SymbolDBEnginePriv *priv;
3049 GValue v = {0};
3051 g_return_val_if_fail (dbe != NULL, FALSE);
3052 priv = dbe->priv;
3054 SDB_LOCK(priv);
3056 if (workspace == NULL)
3058 workspace_name = "anjuta_workspace_default";
3060 DEBUG_PRINT ("adding default workspace... '%s'", workspace_name);
3061 SDB_GVALUE_SET_STATIC_STRING(v, workspace_name);
3063 if ((wks_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3064 PREP_QUERY_GET_WORKSPACE_ID_BY_UNIQUE_NAME,
3065 "wsname",
3066 &v)) <= 0)
3069 /* symbol_db_engine_add_new_workspace 'll lock so unlock here before */
3070 SDB_UNLOCK(priv);
3072 if (symbol_db_engine_add_new_workspace (dbe, workspace_name) == FALSE)
3074 DEBUG_PRINT ("%s", "Project cannot be added because a default workspace "
3075 "cannot be created");
3076 return FALSE;
3078 /* relock */
3079 SDB_LOCK(priv);
3082 else
3084 workspace_name = workspace;
3087 g_value_unset (&v);
3089 /* insert new project */
3090 if ((stmt =
3091 sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_PROJECT_NEW)) == NULL)
3093 g_warning ("query is null");
3094 SDB_UNLOCK(priv);
3095 return FALSE;
3098 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_PROJECT_NEW);
3100 /* lookup parameters */
3101 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3103 g_warning ("param prjname is NULL from pquery!");
3104 SDB_UNLOCK(priv);
3105 return FALSE;
3108 SDB_PARAM_SET_STRING(param, project);
3110 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3112 g_warning ("param prjversion is NULL from pquery!");
3113 SDB_UNLOCK(priv);
3114 return FALSE;
3117 SDB_PARAM_SET_STRING(param, version);
3119 if ((param = gda_set_get_holder ((GdaSet*)plist, "wsname")) == NULL)
3121 g_warning ("param wsname is NULL from pquery!");
3122 SDB_UNLOCK(priv);
3123 return FALSE;
3126 SDB_PARAM_SET_STRING(param, workspace_name);
3128 /* execute the query with parameters just set */
3129 if (gda_connection_statement_execute_non_select (priv->db_connection,
3130 (GdaStatement*)stmt,
3131 (GdaSet*)plist, NULL, NULL) == -1)
3133 SDB_UNLOCK(priv);
3134 return FALSE;
3137 SDB_UNLOCK(priv);
3138 return TRUE;
3141 /* ### Thread note: this function inherits the mutex lock ### */
3142 /* Uses cache lookup to speed up symbols search. */
3143 static gint
3144 sdb_engine_add_new_language (SymbolDBEngine * dbe, const gchar *language)
3146 gint table_id;
3147 SymbolDBEnginePriv *priv;
3148 GValue v = {0};
3150 if (language == NULL)
3151 return -1;
3153 priv = dbe->priv;
3155 /* cache lookup */
3156 table_id = sdb_engine_cache_lookup (priv->language_cache, language);
3157 if (table_id != -1)
3159 return table_id;
3162 SDB_GVALUE_SET_STATIC_STRING (v, language);
3164 /* check for an already existing table with language "name". */
3165 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3166 PREP_QUERY_GET_LANGUAGE_ID_BY_UNIQUE_NAME,
3167 "langname",
3168 &v)) < 0)
3170 /* insert a new entry on db */
3171 const GdaSet *plist;
3172 const GdaStatement *stmt;
3173 GdaHolder *param;
3174 GdaSet *last_inserted = NULL;
3176 g_value_unset (&v);
3178 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_LANGUAGE_NEW))
3179 == NULL)
3181 g_warning ("query is null");
3182 return FALSE;
3185 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_LANGUAGE_NEW);
3187 if ((param = gda_set_get_holder ((GdaSet*)plist, "langname")) == NULL)
3189 g_warning ("param langname is NULL from pquery!");
3190 return FALSE;
3193 SDB_PARAM_SET_STRING(param, language);
3195 /* execute the query with parameters just set */
3196 if (gda_connection_statement_execute_non_select (priv->db_connection,
3197 (GdaStatement*)stmt,
3198 (GdaSet*)plist, &last_inserted,
3199 NULL) == -1)
3201 table_id = -1;
3203 else {
3204 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3205 table_id = g_value_get_int (value);
3206 sdb_engine_insert_cache (priv->language_cache, language, table_id);
3209 if (last_inserted)
3210 g_object_unref (last_inserted);
3213 return table_id;
3217 * ~~~ Thread note: this function locks the mutex ~~~
3219 * Add a file to project.
3220 * This function requires an opened db, i.e. calling before
3221 * symbol_db_engine_open_db ()
3222 * filepath: referes to a full file path.
3223 * project:
3224 * WARNING: we suppose that project_directory is already set.
3225 * WARNING2: we suppose that the given local_filepath include the project_directory path.
3226 * + correct example: local_filepath: /home/user/projects/foo_project/src/main.c
3227 * project_directory: /home/user/projects/foo_project
3228 * - wrong one: local_filepath: /tmp/foo.c
3229 * project_directory: /home/user/projects/foo_project
3231 static gboolean
3232 sdb_engine_add_new_db_file (SymbolDBEngine * dbe, const gchar * project_name,
3233 const gchar *project_version, const gchar * local_filepath,
3234 const gchar * language)
3236 const GdaSet *plist;
3237 const GdaStatement *stmt;
3238 GdaHolder *param;
3239 GError * error = NULL;
3240 SymbolDBEnginePriv *priv;
3241 gint language_id;
3242 GValue v = {0};
3244 priv = dbe->priv;
3246 /* check if the file is a correct one compared to the local_filepath */
3247 if (strstr (local_filepath, priv->project_directory) == NULL)
3248 return FALSE;
3250 SDB_LOCK(priv);
3252 /* we're gonna set the file relative to the project folder, not the full one.
3253 * e.g.: we have a file on disk: "/tmp/foo/src/file.c" and a db_directory located on
3254 * "/tmp/foo/". The entry on db will be "src/file.c"
3256 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, local_filepath);
3257 if (relative_path == NULL)
3259 DEBUG_PRINT ("%s", "relative_path == NULL");
3260 SDB_UNLOCK(priv);
3261 return FALSE;
3264 /* insert a new entry on db */
3265 language_id = sdb_engine_add_new_language (dbe, language);
3266 if (language_id < 0)
3268 DEBUG_PRINT ("Unknown language: %s", language);
3269 SDB_UNLOCK(priv);
3270 return FALSE;
3273 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_FILE_NEW))
3274 == NULL)
3276 g_warning ("query is null");
3277 SDB_UNLOCK(priv);
3278 return FALSE;
3281 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_FILE_NEW);
3283 /* filepath parameter */
3284 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
3286 g_warning ("param langname is NULL from pquery!");
3287 SDB_UNLOCK(priv);
3288 return FALSE;
3291 SDB_PARAM_SET_STRING(param, relative_path);
3293 /* project name parameter */
3294 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
3296 g_warning ("param prjname is NULL from pquery!");
3297 SDB_UNLOCK(priv);
3298 return FALSE;
3301 SDB_PARAM_SET_STRING(param, project_name);
3303 /* prjversion parameter */
3304 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjversion")) == NULL)
3306 g_warning ("param prjversion is NULL from pquery!");
3307 SDB_UNLOCK(priv);
3308 return FALSE;
3311 SDB_PARAM_SET_STRING(param, project_version);
3313 /* language id parameter */
3314 if ((param = gda_set_get_holder ((GdaSet*)plist, "langid")) == NULL)
3316 g_warning ("param langid is NULL from pquery!");
3317 SDB_UNLOCK(priv);
3318 return FALSE;
3321 SDB_PARAM_SET_INT(param, language_id);
3323 /* execute the query with parameters just set */
3324 if (gda_connection_statement_execute_non_select (priv->db_connection,
3325 (GdaStatement*)stmt,
3326 (GdaSet*)plist, NULL,
3327 &error) == -1)
3329 if (error)
3331 gchar * sql_str = gda_statement_to_sql_extended ((GdaStatement*)stmt,
3332 priv->db_connection, (GdaSet*)plist, 0, NULL, NULL);
3334 DEBUG_PRINT ("%s [%s]", error->message, sql_str);
3335 g_error_free (error);
3336 g_free (sql_str);
3339 SDB_UNLOCK(priv);
3340 return FALSE;
3343 SDB_UNLOCK(priv);
3344 return TRUE;
3347 /* ~~~ Thread note: this function locks the mutex ~~~ */
3348 static gint
3349 sdb_engine_get_unique_scan_id (SymbolDBEngine * dbe)
3351 SymbolDBEnginePriv *priv;
3352 gint ret_id;
3354 priv = dbe->priv;
3356 SDB_LOCK(priv);
3358 priv->scan_process_id_sequence++;
3359 ret_id = priv->scan_process_id_sequence;
3361 SDB_UNLOCK(priv);
3362 return ret_id;
3366 * symbol_db_engine_add_new_files_async:
3367 * @dbe: self
3368 * @lang_manager: IAnjutaLanguage language manager.
3369 * @project_name:
3370 * @project_version:
3371 * @sources_array: requires full path to files on disk. Anjuta-tags itself requires that.
3372 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3373 * a language string to represent the file.
3374 * An example of files_path array composition can be:
3375 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3376 * "/home/user/foo_project/foo3.java".
3377 * NOTE: all the files MUST exist. So check for their existence before call
3378 * this function. The function'll write entries on the db.
3380 * See symbol_db_engine_add_new_files_full () for doc.
3381 * This function adds files to db in a quicker way than
3382 * symbol_db_engine_add_new_files_full because you won't have to specify the
3383 * GPtrArray of languages, but it'll try to autodetect them.
3384 * When added, the files are forced to be scanned.
3387 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3388 * until the scanner is available. So you should use the gint id returned to identify
3389 * if a 'scan-end' signal is the one that you were expecting.
3390 * Please note also that, if db is disconnected before the waiting queue is processed,
3391 * the scan of those files won't be performed.
3393 * Returns: scan process id if insertion is successful, -1 on error.
3395 gint
3396 symbol_db_engine_add_new_files_async (SymbolDBEngine *dbe,
3397 IAnjutaLanguage* lang_manager,
3398 const gchar * project_name,
3399 const gchar * project_version,
3400 const GPtrArray *sources_array)
3402 GPtrArray *lang_array;
3403 gint i;
3405 g_return_val_if_fail (dbe != NULL, FALSE);
3406 g_return_val_if_fail (lang_manager != NULL, FALSE);
3407 g_return_val_if_fail (sources_array != NULL, FALSE);
3409 lang_array = g_ptr_array_new_with_free_func (g_free);
3411 for (i = 0; i < sources_array->len; i++)
3413 IAnjutaLanguageId lang_id;
3414 GFile *gfile;
3415 GFileInfo *gfile_info;
3416 const gchar *file_mime;
3417 const gchar *lang;
3418 const gchar *local_filename;
3420 local_filename = g_ptr_array_index (sources_array, i);
3421 gfile = g_file_new_for_path (local_filename);
3422 gfile_info = g_file_query_info (gfile,
3423 "standard::content-type",
3424 G_FILE_QUERY_INFO_NONE,
3425 NULL,
3426 NULL);
3427 if (gfile_info == NULL)
3429 g_warning ("GFileInfo corresponding to %s was NULL", local_filename);
3430 g_object_unref (gfile);
3431 continue;
3434 file_mime = g_file_info_get_attribute_string (gfile_info,
3435 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
3437 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
3438 file_mime, NULL);
3440 if (!lang_id)
3442 g_warning ("Language not found for %s was NULL", local_filename);
3443 g_object_unref (gfile);
3444 g_object_unref (gfile_info);
3445 continue;
3448 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
3449 g_ptr_array_add (lang_array, g_strdup (lang));
3450 g_object_unref (gfile);
3451 g_object_unref (gfile_info);
3454 gint res = symbol_db_engine_add_new_files_full_async (dbe, project_name, project_version,
3455 sources_array, lang_array, TRUE);
3457 /* free resources */
3458 g_ptr_array_unref (lang_array);
3460 return res;
3463 /**
3464 * symbol_db_engine_add_new_files_full_async:
3465 * @dbe: self
3466 * @project_name: something like 'foo_project', or 'helloworld_project'. Can be NULL,
3467 * for example when you're populating after abort.
3468 * @project_version: The version of the project.
3469 * @files_path: requires full path to files on disk. Anjuta-tags itself requires that.
3470 * it must be something like "/home/path/to/my/foo/file.xyz". Also it requires
3471 * a language string to represent the file.
3472 * An example of files_path array composition can be:
3473 * "/home/user/foo_project/foo1.c", "/home/user/foo_project/foo2.cpp",
3474 * "/home/user/foo_project/foo3.java".
3475 * NOTE: all the files MUST exist. So check for their existence before call
3476 * this function. The function'll write entries on the db.
3477 * @languages: is an array of 'languages'. It must have the same number of
3478 * elments that files_path has. It should be populated like this: "C", "C++",
3479 * "Java" etc.
3480 * This is done to be normalized with the language-manager plugin.
3481 * @force_scan: If FALSE a check on db will be done to see
3482 * whether the file is already present or not. In the latter care the scan will begin.
3484 * Add a group of files to a project. It will perform also
3485 * a symbols scannig/populating of db if force_scan is TRUE.
3486 * This function requires an opened db, i.e. You must test db ststus with
3487 * symbol_db_engine_open_db () before.
3488 * The function must be called from within the main thread.
3490 * Note: If some file fails to enter into the db the function will just skip them.
3493 * The function is suffixed with 'async'. This means that the scanning of the files is delayed
3494 * until the scanner is available. So you should use the gint id returned to identify
3495 * if a 'scan-end' signal is the one that you were expecting.
3496 * Please note also that, if db is disconnected before the waiting queue is processed,
3497 * the scan of those files won't be performed.
3499 * Returns: scan process id if insertion is successful, -1 on error.
3501 gint
3502 symbol_db_engine_add_new_files_full_async (SymbolDBEngine * dbe,
3503 const gchar * project_name,
3504 const gchar * project_version,
3505 const GPtrArray * files_path,
3506 const GPtrArray * languages,
3507 gboolean force_scan)
3509 gint i;
3510 SymbolDBEnginePriv *priv;
3511 GPtrArray * filtered_files_path;
3512 gboolean ret_code;
3513 gint ret_id, scan_id;
3515 g_return_val_if_fail (dbe != NULL, FALSE);
3516 g_return_val_if_fail (files_path != NULL, FALSE);
3517 g_return_val_if_fail (languages != NULL, FALSE);
3518 priv = dbe->priv;
3520 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
3521 g_return_val_if_fail (files_path->len > 0, FALSE);
3522 g_return_val_if_fail (languages->len > 0, FALSE);
3524 filtered_files_path = g_ptr_array_new ();
3526 for (i = 0; i < files_path->len; i++)
3528 const gchar *node_file = (const gchar *) g_ptr_array_index (files_path, i);
3529 const gchar *node_lang = (const gchar *) g_ptr_array_index (languages, i);
3531 if (force_scan == FALSE)
3533 /* test the existence of the file in db */
3534 if (symbol_db_engine_file_exists (dbe, node_file) == TRUE)
3536 /* we don't want to touch the already present file... within
3537 * its symbols
3539 continue;
3543 if (project_name != NULL &&
3544 sdb_engine_add_new_db_file (dbe, project_name, project_version, node_file,
3545 node_lang) == FALSE)
3547 DEBUG_PRINT ("Error processing file %s, db_directory %s, project_name %s, "
3548 "project_version %s, project_directory %s", node_file,
3549 priv->db_directory, project_name, project_version,
3550 priv->project_directory);
3551 continue;
3554 /* note: we don't use g_strdup () here because we'll free the filtered_files_path
3555 * before returning from this function.
3557 g_ptr_array_add (filtered_files_path, (gpointer)node_file);
3560 /* perform the scan of files. It will spawn a fork() process with
3561 * AnjutaLauncher and ctags in server mode. After the ctags cmd has been
3562 * executed, the populating process'll take place.
3564 scan_id = sdb_engine_get_unique_scan_id (dbe);
3565 ret_code = sdb_engine_scan_files_async (dbe, filtered_files_path, NULL, FALSE, scan_id);
3567 if (ret_code == TRUE)
3569 ret_id = scan_id;
3571 else
3572 ret_id = -1;
3574 /* no need to free the items contained in the array */
3575 g_ptr_array_unref (filtered_files_path);
3576 return ret_id;
3581 * We'll use the GNU regular expressions instead of the glib's GRegex ones because
3582 * the latters are a wrapper of pcre (www.pcre.org) that don't implement the
3583 * \< (begin of word)) and \> (end of word) boundaries.
3584 * Since the regex used here is something complex to reproduce on GRegex
3585 * I don't see any reason to reinvent the (already) working wheel.
3586 * I didn't find a valuable replacement for \< and \> neither on
3587 * http://www.regular-expressions.info/wordboundaries.html nor elsewhere.
3588 * But if some regex geek thinks I'm wrong I'll be glad to see his solution.
3590 * @return NULL on error.
3592 #define RX_STRING "\\\".*\\\""
3593 #define RX_BRACKETEXPR "\\{.*\\}"
3594 #define RX_IDENT "[a-zA-Z_][a-zA-Z0-9_]*"
3595 #define RX_WS "[ \t\n]*"
3596 #define RX_PTR "[\\*&]?\\*?"
3597 #define RX_INITIALIZER "=(" RX_WS RX_IDENT RX_WS ")|=(" RX_WS RX_STRING RX_WS \
3598 ")|=(" RX_WS RX_BRACKETEXPR RX_WS ")" RX_WS
3599 #define RX_ARRAY RX_WS "\\[" RX_WS "[0-9]*" RX_WS "\\]" RX_WS
3601 static gchar*
3602 sdb_engine_extract_type_qualifier (const gchar *string, const gchar *expr)
3604 /* check with a regular expression for the type */
3605 regex_t re;
3606 regmatch_t pm[8]; // 7 sub expression -> 8 matches
3607 memset (&pm, -1, sizeof(pm));
3609 * this regexp catches things like:
3610 * a) std::vector<char*> exp1[124] [12], *exp2, expr;
3611 * b) QClass* expr1, expr2, expr;
3612 * c) int a,b; char r[12] = "test, argument", q[2] = { 't', 'e' }, expr;
3614 * it CAN be fooled, if you really want it, but it should
3615 * work for 99% of all situations.
3617 * QString
3618 * var;
3619 * in 2 lines does not work, because //-comments would often bring wrong results
3622 gchar *res = NULL;
3623 static char pattern[512] =
3624 "(" RX_IDENT "\\>)" /* the 'std' in example a) */
3625 "(::" RX_IDENT ")*" /* ::vector */
3626 "(" RX_WS "<[^>;]*>)?" /* <char *> */
3627 /* other variables for the same ident (string i,j,k;) */
3628 "(" RX_WS RX_PTR RX_WS RX_IDENT RX_WS "(" RX_ARRAY ")*" "(" RX_INITIALIZER ")?," RX_WS ")*"
3629 "[ \t\\*&]*"; /* check again for pointer/reference type */
3631 /* must add a 'termination' symbol to the regexp, otherwise
3632 * 'exp' would match 'expr'
3634 gchar regexp[512];
3635 g_snprintf (regexp, sizeof (regexp), "%s\\<%s\\>", pattern, expr);
3637 /* compile regular expression */
3638 int error = regcomp (&re, regexp, REG_EXTENDED) ;
3639 if (error)
3640 return NULL;
3642 /* this call to regexec finds the first match on the line */
3643 error = regexec (&re, string, 8, &pm[0], 0) ;
3645 /* while matches found */
3646 while (error == 0)
3648 /* subString found between pm.rm_so and pm.rm_eo */
3649 /* only include the ::vector part in the indentifier, if the second
3650 * subpattern matches at all
3652 int len = (pm[2].rm_so != -1 ? pm[2].rm_eo : pm[1].rm_eo) - pm[1].rm_so;
3653 if (res)
3654 free (res);
3655 res = (gchar*) g_malloc0 (len + 1);
3656 if (!res)
3658 regfree (&re);
3659 return NULL;
3661 strncpy (res, string + pm[1].rm_so, len);
3662 res[len] = '\0';
3664 /* This call to regexec finds the next match */
3665 error = regexec (&re, string + pm[0].rm_eo, 8, &pm[0], 0) ;
3666 break;
3668 regfree(&re);
3670 return res;
3673 /* ### Thread note: this function inherits the mutex lock ### */
3674 /* Uses cache lookup to speed up symbols search. */
3675 static gint
3676 sdb_engine_add_new_sym_kind (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3678 const gchar *kind_name;
3679 gint table_id;
3680 SymbolDBEnginePriv *priv;
3681 GValue v = {0};
3683 priv = dbe->priv;
3685 /* we assume that tag_entry is != NULL */
3686 kind_name = tag_entry->kind;
3688 /* no kind associated with current tag */
3689 if (kind_name == NULL)
3690 return -1;
3692 /* cache lookup */
3693 table_id = sdb_engine_cache_lookup (priv->kind_cache, kind_name);
3694 if (table_id != -1)
3696 return table_id;
3699 SDB_GVALUE_SET_STATIC_STRING (v, kind_name);
3701 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3702 PREP_QUERY_GET_SYM_KIND_BY_UNIQUE_NAME,
3703 "kindname",
3704 &v)) < 0)
3706 const GdaSet *plist;
3707 const GdaStatement *stmt;
3708 GdaHolder *param;
3709 GdaSet *last_inserted = NULL;
3710 gint is_container = 0;
3711 SymType sym_type;
3712 GError * error = NULL;
3714 g_value_unset (&v);
3716 /* not found. Go on with inserting */
3717 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYM_KIND_NEW))
3718 == NULL)
3720 g_warning ("query is null");
3721 return -1;
3724 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_KIND_NEW);
3726 /* kindname parameter */
3727 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindname")) == NULL)
3729 g_warning ("param kindname is NULL from pquery!");
3730 return FALSE;
3733 SDB_PARAM_SET_STRING (param, kind_name);
3735 /* container parameter */
3736 if ((param = gda_set_get_holder ((GdaSet*)plist, "container")) == NULL)
3738 g_warning ("param container is NULL from pquery!");
3739 return FALSE;
3742 sym_type = GPOINTER_TO_SIZE (g_hash_table_lookup (priv->sym_type_conversion_hash,
3743 kind_name));
3745 if (sym_type & IANJUTA_SYMBOL_TYPE_SCOPE_CONTAINER)
3746 is_container = 1;
3748 SDB_PARAM_SET_INT (param, is_container);
3750 /* execute the query with parameters just set */
3751 if (gda_connection_statement_execute_non_select(priv->db_connection,
3752 (GdaStatement*)stmt,
3753 (GdaSet*)plist, &last_inserted,
3754 NULL) == -1)
3756 table_id = -1;
3758 else
3760 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3761 table_id = g_value_get_int (value);
3762 /* we should cache only tables which are != -1 */
3763 sdb_engine_insert_cache (priv->kind_cache, kind_name, table_id);
3765 if (last_inserted)
3766 g_object_unref (last_inserted);
3768 if (error)
3770 g_warning ("SQL error: %s", error->message);
3771 g_error_free (error);
3775 return table_id;
3778 /* ### Thread note: this function inherits the mutex lock ### */
3779 /* Uses cache lookup to speed up symbols search. */
3780 static gint
3781 sdb_engine_add_new_sym_access (SymbolDBEngine * dbe, const tagEntry * tag_entry)
3783 const gchar *access;
3784 gint table_id;
3785 SymbolDBEnginePriv *priv;
3786 GValue v = {0};
3788 priv = dbe->priv;
3791 /* we assume that tag_entry is != NULL */
3792 if ((access = tagsField (tag_entry, "access")) == NULL)
3794 /* no access associated with current tag */
3795 return -1;
3798 /* cache lookup */
3799 table_id = sdb_engine_cache_lookup (priv->access_cache, access);
3800 if (table_id != -1)
3802 return table_id;
3805 SDB_GVALUE_SET_STATIC_STRING (v, access);
3807 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3808 PREP_QUERY_GET_SYM_ACCESS_BY_UNIQUE_NAME,
3809 "accesskind",
3810 &v)) < 0)
3812 const GdaSet *plist;
3813 const GdaStatement *stmt;
3814 GdaHolder *param;
3815 GdaSet *last_inserted = NULL;
3817 g_value_unset (&v);
3819 /* not found. Go on with inserting */
3820 if ((stmt =
3821 sdb_engine_get_statement_by_query_id (dbe,
3822 PREP_QUERY_SYM_ACCESS_NEW)) == NULL)
3824 g_warning ("query is null");
3825 return -1;
3828 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYM_ACCESS_NEW);
3830 /* accesskind parameter */
3831 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskind")) == NULL)
3833 g_warning ("param accesskind is NULL from pquery!");
3834 return -1;
3837 SDB_PARAM_SET_STRING (param, access);
3839 /* execute the query with parameters just set */
3840 if (gda_connection_statement_execute_non_select (priv->db_connection,
3841 (GdaStatement*)stmt,
3842 (GdaSet*)plist, &last_inserted,
3843 NULL) == -1)
3845 table_id = -1;
3847 else
3849 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3850 table_id = g_value_get_int (value);
3851 /* we should cache only tables which are != -1 */
3852 sdb_engine_insert_cache (priv->access_cache, access, table_id);
3855 if (last_inserted)
3856 g_object_unref (last_inserted);
3859 return table_id;
3862 /* ### Thread note: this function inherits the mutex lock ### */
3863 /* Uses cache lookup to speed up symbols search. */
3864 static gint
3865 sdb_engine_add_new_sym_implementation (SymbolDBEngine * dbe,
3866 const tagEntry * tag_entry)
3868 const gchar *implementation;
3869 gint table_id;
3870 SymbolDBEnginePriv *priv;
3871 GValue v = {0};
3873 priv = dbe->priv;
3875 /* we assume that tag_entry is != NULL */
3876 if ((implementation = tagsField (tag_entry, "implementation")) == NULL)
3878 /* no implementation associated with current tag */
3879 return -1;
3882 /* cache lookup */
3883 table_id = sdb_engine_cache_lookup (priv->implementation_cache, implementation);
3884 if (table_id != -1)
3886 return table_id;
3889 SDB_GVALUE_SET_STATIC_STRING(v, implementation);
3891 if ((table_id = sdb_engine_get_tuple_id_by_unique_name (dbe,
3892 PREP_QUERY_GET_SYM_IMPLEMENTATION_BY_UNIQUE_NAME,
3893 "implekind",
3894 &v)) < 0)
3896 const GdaSet *plist;
3897 const GdaStatement *stmt;
3898 GdaHolder *param;
3899 GdaSet *last_inserted = NULL;
3901 g_value_unset (&v);
3903 /* not found. Go on with inserting */
3904 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
3905 PREP_QUERY_SYM_IMPLEMENTATION_NEW)) ==
3906 NULL)
3908 g_warning ("query is null");
3909 return -1;
3912 plist = sdb_engine_get_query_parameters_list (dbe,
3913 PREP_QUERY_SYM_IMPLEMENTATION_NEW);
3915 /* implekind parameter */
3916 if ((param = gda_set_get_holder ((GdaSet*)plist, "implekind")) == NULL)
3918 g_warning ("param accesskind is NULL from pquery!");
3919 return -1;
3922 SDB_PARAM_SET_STRING(param, implementation);
3924 /* execute the query with parameters just set */
3925 if (gda_connection_statement_execute_non_select (priv->db_connection,
3926 (GdaStatement*)stmt,
3927 (GdaSet*)plist, &last_inserted,
3928 NULL) == -1)
3930 table_id = -1;
3932 else
3934 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
3935 table_id = g_value_get_int (value);
3936 /* we should cache only tables which are != -1 */
3937 sdb_engine_insert_cache (priv->implementation_cache, implementation,
3938 table_id);
3940 if (last_inserted)
3941 g_object_unref (last_inserted);
3944 return table_id;
3947 /* ### Thread note: this function inherits the mutex lock ### */
3948 static void
3949 sdb_engine_add_new_heritage (SymbolDBEngine * dbe, gint base_symbol_id,
3950 gint derived_symbol_id)
3952 const GdaSet *plist;
3953 const GdaStatement *stmt;
3954 GdaHolder *param;
3955 SymbolDBEnginePriv *priv;
3956 GValue v = {0};
3958 g_return_if_fail (base_symbol_id > 0);
3959 g_return_if_fail (derived_symbol_id > 0);
3961 priv = dbe->priv;
3963 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_HERITAGE_NEW))
3964 == NULL)
3966 g_warning ("query is null");
3967 return;
3970 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_HERITAGE_NEW);
3972 /* symbase parameter */
3973 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbase")) == NULL)
3975 g_warning ("param accesskind is NULL from pquery!");
3976 return;
3979 SDB_PARAM_SET_INT(param, base_symbol_id);
3981 /* symderived id parameter */
3982 if ((param = gda_set_get_holder ((GdaSet*)plist, "symderived")) == NULL)
3984 g_warning ("param symderived is NULL from pquery!");
3985 return;
3988 SDB_PARAM_SET_INT(param, derived_symbol_id);
3990 /* execute the query with parameters just set */
3991 if (gda_connection_statement_execute_non_select (priv->db_connection,
3992 (GdaStatement*)stmt,
3993 (GdaSet*)plist, NULL,
3994 NULL) == -1)
3996 g_warning ("Error adding heritage");
4001 /* ### Thread note: this function inherits the mutex lock ### */
4002 static GNUC_INLINE gint
4003 sdb_engine_add_new_scope_definition (SymbolDBEngine * dbe, const tagEntry * tag_entry)
4005 const gchar *scope;
4006 gint table_id;
4007 const GdaSet *plist;
4008 const GdaStatement *stmt;
4009 GdaHolder *param;
4010 GdaSet *last_inserted = NULL;
4011 SymbolDBEnginePriv *priv;
4012 GValue v = {0};
4014 g_return_val_if_fail (tag_entry->kind != NULL, -1);
4016 priv = dbe->priv;
4019 /* This symbol will define a scope which name is tag_entry->name
4020 * For example if we get a tag MyFoo with kind "namespace", it will define
4021 * the "MyFoo" scope, which type is "namespace MyFoo"
4023 scope = tag_entry->name;
4025 /* filter out 'variable' and 'member' kinds. They define no scope. */
4026 if (g_strcmp0 (tag_entry->kind, "variable") == 0 ||
4027 g_strcmp0 (tag_entry->kind, "member") == 0)
4029 return -1;
4032 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SCOPE_NEW))
4033 == NULL)
4035 g_warning ("query is null");
4036 return -1;
4039 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SCOPE_NEW);
4041 /* scope parameter */
4042 if ((param = gda_set_get_holder ((GdaSet*)plist, "scope")) == NULL)
4044 g_warning ("param scope is NULL from pquery!");
4045 return -1;
4048 SDB_PARAM_SET_STRING (param, scope);
4050 /* execute the query with parameters just set */
4051 if (gda_connection_statement_execute_non_select (priv->db_connection,
4052 (GdaStatement*)stmt,
4053 (GdaSet*)plist, &last_inserted,
4054 NULL) == -1)
4057 GValue v = {0, };
4058 SDB_GVALUE_SET_STATIC_STRING(v, scope);
4060 /* try to get an already existing scope */
4061 table_id = sdb_engine_get_tuple_id_by_unique_name (dbe, PREP_QUERY_GET_SCOPE_ID,
4062 "scope", &v);
4064 else
4066 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4067 table_id = g_value_get_int (value);
4070 if (last_inserted)
4071 g_object_unref (last_inserted);
4073 return table_id;
4077 * ### Thread note: this function inherits the mutex lock ###
4079 * Saves the tagEntry info for a second pass parsing.
4080 * Usually we don't know all the symbol at the first scan of the tags. We need
4081 * a second one.
4084 static GNUC_INLINE void
4085 sdb_engine_add_new_tmp_heritage_scope (SymbolDBEngine * dbe,
4086 const tagEntry * tag_entry,
4087 gint symbol_referer_id)
4089 SymbolDBEnginePriv *priv;
4090 const gchar *field_inherits, *field_struct, *field_typeref,
4091 *field_enum, *field_union, *field_class, *field_namespace;
4092 TableMapTmpHeritage * node;
4094 priv = dbe->priv;
4096 node = g_slice_new0 (TableMapTmpHeritage);
4097 node->symbol_referer_id = symbol_referer_id;
4099 if ((field_inherits = tagsField (tag_entry, "inherits")) != NULL)
4101 node->field_inherits = g_strdup (field_inherits);
4104 if ((field_struct = tagsField (tag_entry, "struct")) != NULL)
4106 node->field_struct = g_strdup (field_struct);
4109 if ((field_typeref = tagsField (tag_entry, "typeref")) != NULL)
4111 node->field_typeref = g_strdup (field_typeref);
4114 if ((field_enum = tagsField (tag_entry, "enum")) != NULL)
4116 node->field_enum = g_strdup (field_enum);
4119 if ((field_union = tagsField (tag_entry, "union")) != NULL)
4121 node->field_union = g_strdup (field_union);
4124 if ((field_class = tagsField (tag_entry, "class")) != NULL)
4126 node->field_class = g_strdup (field_class);
4129 if ((field_namespace = tagsField (tag_entry, "namespace")) != NULL)
4131 node->field_namespace = g_strdup (field_namespace);
4134 g_queue_push_head (priv->tmp_heritage_tablemap, node);
4137 /**
4138 * ### Thread note: this function inherits the mutex lock ###
4140 * Return the symbol_id of the changed symbol
4142 static GNUC_INLINE void
4143 sdb_engine_second_pass_update_scope_1 (SymbolDBEngine * dbe,
4144 TableMapTmpHeritage * node,
4145 gchar * token_name,
4146 const gchar * token_value)
4148 gint symbol_referer_id;
4149 const gchar *tmp_str;
4150 gchar **tmp_str_splitted;
4151 gint tmp_str_splitted_length;
4152 gchar *object_name = NULL;
4153 gboolean free_token_name = FALSE;
4154 const GdaSet *plist;
4155 const GdaStatement *stmt;
4156 GdaHolder *param;
4157 SymbolDBEnginePriv *priv;
4158 GValue v = {0};
4160 g_return_if_fail (token_value != NULL);
4162 priv = dbe->priv;
4163 tmp_str = token_value;
4165 /* we don't need empty strings */
4166 if (strlen (tmp_str) <= 0)
4168 return;
4171 /* we could have something like "First::Second::Third::Fourth" as tmp_str, so
4172 * take only the lastscope, in this case 'Fourth'.
4174 tmp_str_splitted = g_strsplit (tmp_str, ":", 0);
4175 tmp_str_splitted_length = g_strv_length (tmp_str_splitted);
4177 if (tmp_str_splitted_length > 0)
4179 /* handle special typedef case. Usually we have something like struct:my_foo.
4180 * splitting we have [0]-> struct [1]-> my_foo
4182 if (g_strcmp0 (token_name, "typedef") == 0)
4184 free_token_name = TRUE;
4185 token_name = g_strdup (tmp_str_splitted[0]);
4188 object_name = g_strdup (tmp_str_splitted[tmp_str_splitted_length - 1]);
4190 else
4192 g_strfreev (tmp_str_splitted);
4193 return;
4196 g_strfreev (tmp_str_splitted);
4198 /* if we reach this point we should have a good scope_id.
4199 * Go on with symbol updating.
4201 symbol_referer_id = node->symbol_referer_id;
4203 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4204 PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID))
4205 == NULL)
4207 g_warning ("query is null");
4208 return;
4211 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_SCOPE_ID);
4213 /* tokenname parameter */
4214 if ((param = gda_set_get_holder ((GdaSet*)plist, "tokenname")) == NULL)
4216 g_warning ("param tokenname is NULL from pquery!");
4217 return;
4220 SDB_PARAM_SET_STRING(param, token_name);
4222 /* objectname parameter */
4223 if ((param = gda_set_get_holder ((GdaSet*)plist, "objectname")) == NULL)
4225 g_warning ("param objectname is NULL from pquery!");
4226 return;
4229 SDB_PARAM_SET_STRING(param, object_name);
4231 /* symbolid parameter */
4232 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4234 g_warning ("param symbolid is NULL from pquery!");
4235 return;
4238 SDB_PARAM_SET_INT(param, symbol_referer_id);
4240 /* execute the query with parameters just set */
4241 gda_connection_statement_execute_non_select (priv->db_connection,
4242 (GdaStatement*)stmt,
4243 (GdaSet*)plist, NULL,
4244 NULL);
4246 if (free_token_name)
4247 g_free (token_name);
4248 g_free (object_name);
4250 return;
4254 * ### Thread note: this function inherits the mutex lock ###
4256 * @param data Must be filled with some values. It must have num_rows > 0
4257 * @note *CALL THIS BEFORE second_pass_update_heritage ()*
4258 * @note *DO NOT FREE data* inside this function.
4260 static void
4261 sdb_engine_second_pass_update_scope (SymbolDBEngine * dbe)
4263 SymbolDBEnginePriv *priv;
4265 * Fill up the scope.
4266 * The case: "my_foo_func_1" is the name of the current tag parsed.
4267 * Suppose we have a namespace MyFooNamespace, under which is declared
4268 * a class MyFooClass. Under that class there are some funcs like
4269 * my_foo_func_1 () etc. ctags will present us this info about
4270 * my_foo_func_1 ():
4271 * "class : MyFooNamespace::MyFooClass"
4272 * but hey! We don't need to know the namespace here, we just want to
4273 * know that my_foo_func_1 is in the scope of MyFooClass. That one will
4274 * then be mapped inside MyFooNamespace, but that's another thing.
4275 * Go on with the parsing then.
4277 gint i;
4278 gsize queue_length;
4280 priv = dbe->priv;
4282 DEBUG_PRINT ("Processing %d rows", g_queue_get_length (priv->tmp_heritage_tablemap));
4284 /* get a fixed length. There may be some tail_pushes during this loop */
4285 queue_length = g_queue_get_length (priv->tmp_heritage_tablemap);
4287 for (i = 0; i < queue_length; i++)
4289 TableMapTmpHeritage *node;
4290 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4292 if (node->field_class != NULL)
4294 sdb_engine_second_pass_update_scope_1 (dbe, node, "class", node->field_class);
4297 if (node->field_struct != NULL)
4299 sdb_engine_second_pass_update_scope_1 (dbe, node, "struct", node->field_struct);
4302 if (node->field_typeref != NULL)
4304 /* this is a "typedef", not a "typeref". */
4305 sdb_engine_second_pass_update_scope_1 (dbe, node, "typedef", node->field_typeref);
4308 if (node->field_enum != NULL)
4310 sdb_engine_second_pass_update_scope_1 (dbe, node, "enum", node->field_enum);
4313 if (node->field_union != NULL)
4315 sdb_engine_second_pass_update_scope_1 (dbe, node, "union", node->field_union);
4318 if (node->field_namespace != NULL)
4320 sdb_engine_second_pass_update_scope_1 (dbe, node, "namespace", node->field_namespace);
4323 /* last check: if inherits is not null keep the node for a later task */
4324 if (node->field_inherits != NULL)
4326 g_queue_push_tail (priv->tmp_heritage_tablemap, node);
4328 else
4330 sdb_engine_tablemap_tmp_heritage_destroy (node);
4337 * ### Thread note: this function inherits the mutex lock ###
4339 * @param data Must be filled with some values. It must have num_rows > 0
4340 * @note *CALL THIS AFTER second_pass_update_scope ()*
4342 static void
4343 sdb_engine_second_pass_update_heritage (SymbolDBEngine * dbe)
4345 #if 0
4346 gint i;
4347 SymbolDBEnginePriv *priv;
4349 g_return_if_fail (dbe != NULL);
4351 priv = dbe->priv;
4353 DEBUG_PRINT ("Updating heritage... (%d) elements",
4354 g_queue_get_length (priv->tmp_heritage_tablemap));
4356 for (i = 0; i < g_queue_get_length (priv->tmp_heritage_tablemap); i++)
4358 const gchar *inherits;
4359 gchar *item;
4360 gchar **inherits_list;
4361 gint j;
4362 TableMapTmpHeritage *node;
4364 node = g_queue_pop_head (priv->tmp_heritage_tablemap);
4365 inherits = node->field_inherits;
4367 if (inherits == NULL)
4369 g_warning ("Inherits was NULL on sym_referer id %d",
4370 node->symbol_referer_id);
4371 sdb_engine_tablemap_tmp_heritage_destroy (node);
4372 continue;
4375 /* there can be multiple inheritance. Check that. */
4376 inherits_list = g_strsplit (inherits, ",", 0);
4378 if (inherits_list != NULL)
4379 DEBUG_PRINT ("inherits %s", inherits);
4381 /* retrieve as much info as we can from the items */
4382 for (j = 0; j < g_strv_length (inherits_list); j++)
4384 gchar **namespaces;
4385 gchar *klass_name;
4386 gchar *namespace_name;
4387 gint namespaces_length;
4388 gint base_klass_id;
4389 gint derived_klass_id;
4391 item = inherits_list[j];
4392 DEBUG_PRINT ("heritage %s", item);
4394 /* A item may have this string form:
4395 * MyFooNamespace1::MyFooNamespace2::MyFooClass
4396 * We should find the field 'MyFooNamespace2' because it's the one
4397 * that is reachable by the scope_id value of the symbol.
4400 namespaces = g_strsplit (item, "::", 0);
4401 namespaces_length = g_strv_length (namespaces);
4403 if (namespaces_length > 1)
4405 /* this is the case in which we have the case with
4406 * namespace + class
4408 namespace_name = g_strdup (namespaces[namespaces_length - 2]);
4409 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4411 else
4413 /* have a last check before setting namespace_name to null.
4414 * check whether the field_namespace is void or not.
4416 const gchar *tmp_namespace;
4417 gchar **tmp_namespace_array = NULL;
4418 gint tmp_namespace_length;
4420 tmp_namespace = node->field_namespace;
4421 if (tmp_namespace != NULL)
4423 tmp_namespace_array = g_strsplit (tmp_namespace, "::", 0);
4424 tmp_namespace_length = g_strv_length (tmp_namespace_array);
4426 if (tmp_namespace_length > 0)
4428 namespace_name =
4429 g_strdup (tmp_namespace_array
4430 [tmp_namespace_length - 1]);
4432 else
4434 namespace_name = NULL;
4437 else
4439 namespace_name = NULL;
4442 klass_name = g_strdup (namespaces[namespaces_length - 1]);
4444 g_strfreev (tmp_namespace_array);
4447 g_strfreev (namespaces);
4449 /* get the derived_klass_id. It should be the
4450 * symbol_referer_id field into __tmp_heritage_scope table
4452 if (node->symbol_referer_id > 0)
4454 derived_klass_id = node->symbol_referer_id;
4456 else
4458 derived_klass_id = 0;
4461 /* ok, search for the symbol_id of the base class */
4462 if (namespace_name == NULL)
4464 GValue *value1;
4466 MP_LEND_OBJ_STR (priv, value1);
4467 g_value_set_static_string (value1, klass_name);
4469 if ((base_klass_id =
4470 sdb_engine_get_tuple_id_by_unique_name (dbe,
4471 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME,
4472 "klassname",
4473 value1)) < 0)
4475 continue;
4478 else
4480 GValue *value1;
4481 GValue *value2;
4483 MP_LEND_OBJ_STR (priv, value1);
4484 g_value_set_static_string (value1, klass_name);
4486 MP_LEND_OBJ_STR (priv, value2);
4487 g_value_set_static_string (value2, namespace_name);
4489 if ((base_klass_id =
4490 sdb_engine_get_tuple_id_by_unique_name2 (dbe,
4491 PREP_QUERY_GET_SYMBOL_ID_BY_CLASS_NAME_AND_NAMESPACE,
4492 "klassname",
4493 value1,
4494 "namespacename",
4495 value2)) < 0)
4497 continue;
4501 g_free (namespace_name);
4502 g_free (klass_name);
4504 DEBUG_PRINT ("gonna sdb_engine_add_new_heritage with "
4505 "base_klass_id %d, derived_klass_id %d", base_klass_id,
4506 derived_klass_id);
4507 sdb_engine_add_new_heritage (dbe, base_klass_id, derived_klass_id);
4510 g_strfreev (inherits_list);
4512 #endif
4516 * ### Thread note: this function inherits the mutex lock ###
4518 * Process the temporary table to update the symbols on scope and inheritance
4519 * fields.
4520 * *CALL THIS FUNCTION ONLY AFTER HAVING PARSED ALL THE TAGS ONCE*
4523 static void
4524 sdb_engine_second_pass_do (SymbolDBEngine * dbe)
4526 SymbolDBEnginePriv *priv;
4528 priv = dbe->priv;
4530 /* prepare for scope second scan */
4531 if (g_queue_get_length (priv->tmp_heritage_tablemap) > 0)
4533 sdb_engine_second_pass_update_scope (dbe);
4534 sdb_engine_second_pass_update_heritage (dbe);
4538 GNUC_INLINE static void
4539 sdb_engine_add_new_symbol_case_1 (SymbolDBEngine *dbe,
4540 gint symbol_id,
4541 GdaSet **plist_ptr,
4542 GdaStatement **stmt_ptr)
4544 GdaHolder *param;
4545 GValue v = {0};
4547 const GdaSet * plist = *plist_ptr;
4548 const GdaStatement * stmt = *stmt_ptr;
4550 /* case 1 */
4552 /* create specific query for a fresh new symbol */
4553 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
4554 PREP_QUERY_UPDATE_SYMBOL_ALL))
4555 == NULL)
4557 g_warning ("query is null");
4558 return;
4561 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_SYMBOL_ALL);
4563 /* symbolid parameter */
4564 if ((param = gda_set_get_holder ((GdaSet*)plist, "symbolid")) == NULL)
4566 g_warning ("param isfilescope is NULL from pquery!");
4567 return;
4570 SDB_PARAM_SET_INT(param, symbol_id);
4572 *plist_ptr = (GdaSet*)plist;
4573 *stmt_ptr = (GdaStatement*)stmt;
4576 GNUC_INLINE static void
4577 sdb_engine_add_new_symbol_case_2_3 (SymbolDBEngine *dbe,
4578 gint symbol_id,
4579 GdaSet **plist_ptr,
4580 GdaStatement **stmt_ptr,
4581 gint file_defined_id,
4582 const gchar *name,
4583 const gchar *type_type,
4584 const gchar *type_name)
4586 GdaHolder *param;
4587 GValue v = {0};
4589 const GdaSet * plist = *plist_ptr;
4590 const GdaStatement * stmt = *stmt_ptr;
4592 /* create specific query for a fresh new symbol */
4593 if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYMBOL_NEW))
4594 == NULL)
4596 g_warning ("query is null");
4597 return;
4600 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYMBOL_NEW);
4602 /* filedefid parameter */
4603 if ((param = gda_set_get_holder ((GdaSet*)plist, "filedefid")) == NULL)
4605 g_warning ("param filedefid is NULL from pquery!");
4606 return;
4609 SDB_PARAM_SET_INT(param, file_defined_id);
4611 /* name parameter */
4612 if ((param = gda_set_get_holder ((GdaSet*)plist, "name")) == NULL)
4614 g_warning ("param name is NULL from pquery!");
4615 return;
4618 SDB_PARAM_SET_STRING(param, name);
4620 /* typetype parameter */
4621 if ((param = gda_set_get_holder ((GdaSet*)plist, "typetype")) == NULL)
4623 g_warning ("param typetype is NULL from pquery!");
4624 return;
4627 SDB_PARAM_SET_STRING(param, type_type);
4629 /* typenameparameter */
4630 if ((param = gda_set_get_holder ((GdaSet*)plist, "typename")) == NULL)
4632 g_warning ("param typename is NULL from pquery!");
4633 return;
4636 SDB_PARAM_SET_STRING(param, type_name);
4638 *plist_ptr = (GdaSet*)plist;
4639 *stmt_ptr = (GdaStatement*)stmt;
4642 GNUC_INLINE static void
4643 sdb_engine_add_new_symbol_common_params (SymbolDBEngine *dbe,
4644 const GdaSet *plist,
4645 const GdaStatement *stmt,
4646 gint file_position,
4647 gint is_file_scope,
4648 const gchar *signature,
4649 const gchar *returntype,
4650 gint scope_definition_id,
4651 gint scope_id,
4652 gint kind_id,
4653 gint access_kind_id,
4654 gint implementation_kind_id,
4655 gboolean update_flag)
4657 GdaHolder *param;
4658 GValue v = {0};
4660 /* fileposition parameter */
4661 if ((param = gda_set_get_holder ((GdaSet*)plist, "fileposition")) == NULL)
4663 g_warning ("param fileposition is NULL from pquery!");
4664 return;
4667 SDB_PARAM_SET_INT (param, file_position);
4669 /* isfilescope parameter */
4670 if ((param = gda_set_get_holder ((GdaSet*)plist, "isfilescope")) == NULL)
4672 g_warning ("param isfilescope is NULL from pquery!");
4673 return;
4676 SDB_PARAM_SET_INT (param, is_file_scope);
4678 /* signature parameter */
4679 if ((param = gda_set_get_holder ((GdaSet*)plist, "signature")) == NULL)
4681 g_warning ("param signature is NULL from pquery!");
4682 return;
4685 SDB_PARAM_SET_STRING(param, signature);
4687 /* returntype parameter */
4688 if ((param = gda_set_get_holder ((GdaSet*)plist, "returntype")) == NULL)
4690 g_warning ("param returntype is NULL from pquery!");
4691 return;
4694 SDB_PARAM_SET_STRING(param, returntype);
4696 /* scopedefinitionid parameter */
4697 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopedefinitionid")) == NULL)
4699 g_warning ("param scopedefinitionid is NULL from pquery!");
4700 return;
4703 SDB_PARAM_SET_INT(param, scope_definition_id);
4705 /* scopeid parameter */
4706 if ((param = gda_set_get_holder ((GdaSet*)plist, "scopeid")) == NULL)
4708 g_warning ("param scopeid is NULL from pquery!");
4709 return;
4712 SDB_PARAM_SET_INT(param, scope_id);
4714 /* kindid parameter */
4715 if ((param = gda_set_get_holder ((GdaSet*)plist, "kindid")) == NULL)
4717 g_warning ("param kindid is NULL from pquery!");
4718 return;
4721 SDB_PARAM_SET_INT(param, kind_id);
4723 /* accesskindid parameter */
4724 if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskindid")) == NULL)
4726 g_warning ("param accesskindid is NULL from pquery!");
4727 return;
4730 SDB_PARAM_SET_INT(param, access_kind_id);
4732 /* implementationkindid parameter */
4733 if ((param = gda_set_get_holder ((GdaSet*)plist, "implementationkindid")) == NULL)
4735 g_warning ("param implementationkindid is NULL from pquery!");
4736 return;
4739 SDB_PARAM_SET_INT(param, implementation_kind_id);
4741 /* updateflag parameter */
4742 if ((param = gda_set_get_holder ((GdaSet*)plist, "updateflag")) == NULL)
4744 g_warning ("param updateflag is NULL from pquery!");
4745 return;
4748 SDB_PARAM_SET_INT(param, update_flag);
4753 * ### Thread note: this function inherits the mutex lock ###
4755 * base_prj_path can be NULL. In that case path info tag_entry will be taken
4756 * as an absolute path.
4757 * fake_file can be used when a buffer updating is being executed. In that
4758 * particular case both base_prj_path and tag_entry->file will be ignored.
4759 * fake_file is real_path of file on disk
4761 static gint
4762 sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
4763 gint file_defined_id,
4764 gboolean sym_update)
4766 SymbolDBEnginePriv *priv;
4767 GdaSet *plist;
4768 GdaStatement *stmt;
4769 GdaSet *last_inserted = NULL;
4770 gint table_id, symbol_id;
4771 const gchar* name;
4772 gint file_position = 0;
4773 gint is_file_scope = 0;
4774 const gchar *signature;
4775 const gchar *returntype;
4776 gint scope_definition_id = 0;
4777 gint scope_id = 0;
4778 gint kind_id = 0;
4779 gint access_kind_id = 0;
4780 gint implementation_kind_id = 0;
4781 GValue v1 = {0}, v2 = {0}, v3 = {0}, v4 = {0}, v5 = {0};
4782 gboolean sym_was_updated = FALSE;
4783 gboolean update_flag;
4784 gchar *type_regex;;
4785 const gchar *type_type;
4786 const gchar *type_name;
4787 gint nrows;
4788 GError * error = NULL;
4790 g_return_val_if_fail (dbe != NULL, -1);
4791 priv = dbe->priv;
4793 /* keep it at 0 if sym_update == false */
4794 update_flag = sym_update;
4796 g_return_val_if_fail (tag_entry != NULL, -1);
4798 /* parse the entry name */
4799 name = tag_entry->name;
4800 file_position = tag_entry->address.lineNumber;
4801 is_file_scope = tag_entry->fileScope;
4804 * signature
4806 signature = tagsField (tag_entry, "signature");
4809 * return type
4811 returntype = tagsField (tag_entry, "returntype");
4814 * sym_type
4816 /* we assume that tag_entry is != NULL */
4817 type_type = tag_entry->kind;
4818 type_regex = NULL;
4820 if (g_strcmp0 (type_type, "member") == 0 ||
4821 g_strcmp0 (type_type, "variable") == 0 ||
4822 g_strcmp0 (type_type, "field") == 0)
4824 type_regex = sdb_engine_extract_type_qualifier (tag_entry->address.pattern,
4825 tag_entry->name);
4826 /*DEBUG_PRINT ("type_regex for %s [kind %s] is %s", tag_entry->name,
4827 tag_entry->kind, type_regex);*/
4828 type_name = type_regex;
4830 /* if the extractor failed we should fallback to the default one */
4831 if (type_name == NULL)
4832 type_name = tag_entry->name;
4833 } else
4835 type_name = tag_entry->name;
4840 * scope definition
4843 /* scope_definition_id tells what scope this symbol defines */
4844 scope_definition_id = sdb_engine_add_new_scope_definition (dbe, tag_entry);
4846 /* the container scopes can be: union, struct, typeref, class, namespace etc.
4847 * this field will be parsed in the second pass.
4849 scope_id = 0;
4851 kind_id = sdb_engine_add_new_sym_kind (dbe, tag_entry);
4853 access_kind_id = sdb_engine_add_new_sym_access (dbe, tag_entry);
4855 implementation_kind_id = sdb_engine_add_new_sym_implementation (dbe, tag_entry);
4857 /* ok: was the symbol updated [at least on it's type_id/name]?
4858 * There are 3 cases:
4859 * #1. The symbol remains the same [at least on unique index key]. We will
4860 * perform only a simple update.
4861 * #2. The symbol has changed: at least on name/type/file. We will insert a
4862 * new symbol on table 'symbol'. Deletion of old one will take place
4863 * at a second stage, when a delete of all symbols with
4864 * 'tmp_flag = 0' will be done.
4865 * #3. The symbol has been deleted. As above it will be deleted at
4866 * a second stage because of the 'tmp_flag = 0'. Triggers will remove
4867 * also scope_ids and other things.
4870 if (update_flag == FALSE) /* symbol is new */
4872 symbol_id = -1;
4874 else /* symbol is updated or a force_update has been given */
4876 /* We should use more value and set them with the same values because
4877 * sdb_engine_get_tuple_id_by_unique_name () will manage them
4879 SDB_GVALUE_SET_STATIC_STRING(v1, name);
4880 SDB_GVALUE_SET_INT(v2, file_defined_id);
4881 SDB_GVALUE_SET_STATIC_STRING(v3, type_type);
4882 SDB_GVALUE_SET_STATIC_STRING(v4, type_name);
4883 SDB_GVALUE_SET_INT(v5, file_position);
4886 * We cannot live without this select because we must know whether a similar
4887 * symbol was already present in the file or not. With this information we
4888 * can see if it's been updated or newly inserted
4890 symbol_id = sdb_engine_get_tuple_id_by_unique_name5 (dbe,
4891 PREP_QUERY_GET_SYMBOL_ID_BY_UNIQUE_INDEX_KEY_EXT,
4892 "symname", &v1,
4893 "filedefid", &v2,
4894 "typetype", &v3,
4895 "typename", &v4,
4896 "fileposition", &v5);
4899 /* ok then, parse the symbol id value */
4900 if (symbol_id <= 0)
4902 /* case 2 and 3 */
4903 sym_was_updated = FALSE;
4904 plist = NULL;
4905 stmt = NULL;
4907 sdb_engine_add_new_symbol_case_2_3 (dbe, symbol_id, &plist, &stmt,
4908 file_defined_id, name, type_type, type_name);
4910 else
4912 /* case 1 */
4913 sym_was_updated = TRUE;
4914 plist = NULL;
4915 stmt = NULL;
4917 sdb_engine_add_new_symbol_case_1 (dbe, symbol_id, &plist, &stmt);
4920 /* common params */
4921 sdb_engine_add_new_symbol_common_params (dbe, plist, stmt,
4922 file_position, is_file_scope,
4923 signature, returntype, scope_definition_id,
4924 scope_id, kind_id,
4925 access_kind_id, implementation_kind_id,
4926 update_flag);
4928 /* execute the query with parameters just set */
4929 nrows = gda_connection_statement_execute_non_select (priv->db_connection,
4930 (GdaStatement*)stmt,
4931 (GdaSet*)plist, &last_inserted,
4932 &error);
4934 if (error)
4936 g_warning ("SQL execute_non_select failed: %s", error->message);
4937 g_error_free (error);
4940 if (sym_was_updated == FALSE)
4942 if (nrows > 0)
4944 const GValue *value = gda_set_get_holder_value (last_inserted, "+0");
4945 table_id = g_value_get_int (value);
4947 /* This is a wrong place to emit the symbol-updated signal. Infact
4948 * db is in a inconsistent state, e.g. inheritance references are still
4949 * *not* calculated.
4950 * So add the symbol id into a queue that will be parsed once and emitted.
4952 g_async_queue_push (priv->inserted_syms_id_aqueue, GINT_TO_POINTER(table_id));
4954 else
4956 table_id = -1;
4959 else
4961 if (nrows > 0)
4963 table_id = symbol_id;
4965 g_async_queue_push (priv->updated_syms_id_aqueue, GINT_TO_POINTER(table_id));
4967 else
4969 table_id = -1;
4973 if (last_inserted)
4974 g_object_unref (last_inserted);
4976 /* post population phase */
4978 /* before returning the table_id we have to fill some infoz on temporary tables
4979 * so that in a second pass we can parse also the heritage and scope fields.
4981 if (table_id > 0)
4982 sdb_engine_add_new_tmp_heritage_scope (dbe, tag_entry, table_id);
4984 g_free (type_regex);
4986 return table_id;
4990 * ### Thread note: this function inherits the mutex lock ###
4992 * Select * from __tmp_removed and emits removed signals.
4994 static void
4995 sdb_engine_detects_removed_ids (SymbolDBEngine *dbe)
4997 const GdaStatement *stmt1, *stmt2;
4998 GdaDataModel *data_model;
4999 SymbolDBEnginePriv *priv;
5000 gint i, num_rows;
5002 priv = dbe->priv;
5004 /* ok, now we should read from __tmp_removed all the symbol ids which have
5005 * been removed, and emit a signal
5007 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5008 PREP_QUERY_GET_REMOVED_IDS))
5009 == NULL)
5011 g_warning ("query is null");
5012 return;
5015 data_model = gda_connection_statement_execute_select (priv->db_connection,
5016 (GdaStatement*)stmt1,
5017 NULL, NULL);
5019 if (GDA_IS_DATA_MODEL (data_model))
5021 if ((num_rows = gda_data_model_get_n_rows (data_model)) <= 0)
5023 DEBUG_PRINT ("nothing to remove");
5024 g_object_unref (data_model);
5025 return;
5028 else
5030 if (data_model != NULL)
5031 g_object_unref (data_model);
5032 return;
5035 /* get and parse the results. */
5036 for (i = 0; i < num_rows; i++)
5038 const GValue *val;
5039 gint tmp;
5040 val = gda_data_model_get_value_at (data_model, 0, i, NULL);
5041 tmp = g_value_get_int (val);
5042 DBESignal *dbesig1;
5043 DBESignal *dbesig2;
5045 dbesig1 = g_slice_new (DBESignal);
5046 dbesig1->value = GINT_TO_POINTER (SYMBOL_REMOVED + 1);
5047 dbesig1->process_id = priv->current_scan_process_id;
5049 dbesig2 = g_slice_new (DBESignal);
5050 dbesig2->value = GINT_TO_POINTER (tmp);
5051 dbesig2->process_id = priv->current_scan_process_id;
5053 g_async_queue_push (priv->signals_aqueue, dbesig1);
5054 g_async_queue_push (priv->signals_aqueue, dbesig2);
5057 g_object_unref (data_model);
5059 /* let's clean the tmp_table */
5060 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5061 PREP_QUERY_TMP_REMOVED_DELETE_ALL))
5062 == NULL)
5064 g_warning ("query is null");
5065 return;
5068 /* bye bye */
5069 gda_connection_statement_execute_non_select (priv->db_connection,
5070 (GdaStatement*)stmt2,
5071 NULL, NULL,
5072 NULL);
5076 * ~~~ Thread note: this function locks the mutex ~~~ *
5078 * WARNING: do not use this function thinking that it would do a scan of symbols
5079 * too. Use symbol_db_engine_update_files_symbols () instead. This one will set
5080 * up some things on db, like removing the 'old' symbols which have not been
5081 * updated.
5083 static gboolean
5084 sdb_engine_update_file (SymbolDBEngine * dbe, const gchar * file_on_db)
5086 const GdaSet *plist1, *plist2, *plist3;
5087 const GdaStatement *stmt1, *stmt2, *stmt3;
5088 GdaHolder *param;
5089 SymbolDBEnginePriv *priv;
5090 GValue v = {0};
5092 priv = dbe->priv;
5094 SDB_LOCK(priv);
5096 /* if we're updating symbols we must do some other operations on db
5097 * symbols, like remove the ones which don't have an update_flag = 1
5098 * per updated file.
5101 /* good. Go on with removing of old symbols, marked by a
5102 * update_flag = 0.
5105 /* Triggers will take care of updating/deleting connected symbols
5106 * tuples, like sym_kind, sym_type etc */
5107 if ((stmt1 = sdb_engine_get_statement_by_query_id (dbe,
5108 PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS)) == NULL)
5110 g_warning ("query is null");
5111 SDB_UNLOCK(priv);
5113 return FALSE;
5116 plist1 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_NON_UPDATED_SYMBOLS);
5118 if ((param = gda_set_get_holder ((GdaSet*)plist1, "filepath")) == NULL)
5120 g_warning ("param filepath is NULL from pquery!");
5121 SDB_UNLOCK(priv);
5122 return FALSE;
5125 SDB_PARAM_SET_STRING(param, file_on_db);
5127 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt1,
5128 (GdaSet*)plist1, NULL, NULL);
5130 /* emits removed symbols signals */
5131 sdb_engine_detects_removed_ids (dbe);
5133 /* reset the update_flag to 0 */
5134 if ((stmt2 = sdb_engine_get_statement_by_query_id (dbe,
5135 PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS)) == NULL)
5137 g_warning ("query is null");
5138 SDB_UNLOCK(priv);
5139 return FALSE;
5142 plist2 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_RESET_UPDATE_FLAG_SYMBOLS);
5144 if ((param = gda_set_get_holder ((GdaSet*)plist2, "filepath")) == NULL)
5146 g_warning ("param filepath is NULL from pquery!");
5147 return FALSE;
5149 SDB_PARAM_SET_STRING(param, file_on_db);
5151 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt2,
5152 (GdaSet*)plist2, NULL, NULL);
5154 /* last but not least, update the file analyse_time */
5155 if ((stmt3 = sdb_engine_get_statement_by_query_id (dbe,
5156 PREP_QUERY_UPDATE_FILE_ANALYSE_TIME))
5157 == NULL)
5159 g_warning ("query is null");
5160 SDB_UNLOCK(priv);
5161 return FALSE;
5164 plist3 = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_FILE_ANALYSE_TIME);
5166 /* filepath parameter */
5167 if ((param = gda_set_get_holder ((GdaSet*)plist3, "filepath")) == NULL)
5169 g_warning ("param filepath is NULL from pquery!");
5170 SDB_UNLOCK(priv);
5171 return FALSE;
5174 SDB_PARAM_SET_STRING(param, file_on_db);
5176 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt3,
5177 (GdaSet*)plist3, NULL, NULL);
5179 SDB_UNLOCK(priv);
5180 return TRUE;
5184 * @param data is a GPtrArray *files_to_scan
5185 * It will be freed when this callback will be called.
5187 static void
5188 on_scan_update_files_symbols_end (SymbolDBEngine * dbe,
5189 gint process_id,
5190 UpdateFileSymbolsData* update_data)
5192 SymbolDBEnginePriv *priv;
5193 GPtrArray *files_to_scan;
5194 gint i;
5195 GValue v = {0};
5197 g_return_if_fail (dbe != NULL);
5198 g_return_if_fail (update_data != NULL);
5200 priv = dbe->priv;
5201 files_to_scan = update_data->files_path;
5203 sdb_engine_clear_caches (dbe);
5205 /* we need a reinitialization */
5206 sdb_engine_init_caches (dbe);
5208 for (i = 0; i < files_to_scan->len; i++)
5210 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5212 if (strstr (node, update_data->project_directory) == NULL)
5214 g_warning ("node %s is shorter than "
5215 "prj_directory %s",
5216 node, update_data->project_directory);
5217 continue;
5220 /* clean the db from old un-updated with the last update step () */
5221 if (sdb_engine_update_file (dbe, node +
5222 strlen (update_data->project_directory)) == FALSE)
5224 g_warning ("Error processing file %s", node +
5225 strlen (update_data->project_directory));
5226 return;
5230 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_files_symbols_end,
5231 update_data);
5233 /* if true, we'll update the project scanning time too.
5234 * warning: project time scanning won't could be set before files one.
5235 * This why we'll fork the process calling sdb_engine_scan_files ()
5237 if (update_data->update_prj_analyse_time == TRUE)
5239 const GdaSet *plist;
5240 const GdaStatement *stmt;
5241 GdaHolder *param;
5243 SDB_LOCK(priv);
5244 /* and the project analyse_time */
5245 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5246 PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME))
5247 == NULL)
5249 g_warning ("query is null");
5250 SDB_UNLOCK(priv);
5251 return;
5254 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_UPDATE_PROJECT_ANALYSE_TIME);
5256 /* prjname parameter */
5257 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5259 g_warning ("param prjname is NULL from pquery!");
5260 SDB_UNLOCK(priv);
5261 return;
5264 SDB_PARAM_SET_STRING(param, update_data->project);
5266 gda_connection_statement_execute_non_select (priv->db_connection,
5267 (GdaStatement*)stmt,
5268 (GdaSet*)plist, NULL, NULL);
5270 SDB_UNLOCK(priv);
5273 /* free the GPtrArray. */
5274 g_ptr_array_unref (files_to_scan);
5276 g_free (update_data->project);
5277 g_free (update_data->project_directory);
5278 g_free (update_data);
5282 * symbol_db_engine_update_files_symbols:
5283 * @dbe: self
5284 * @project: name of the project
5285 * @files_path: absolute path of files to update.
5286 * @update_prj_analyse_time: flag to force the update of project analyse time.
5288 * Update symbols of saved files.
5290 * Returns: Scan process id if insertion is successful, -1 on 'no files scanned'.
5292 gint
5293 symbol_db_engine_update_files_symbols (SymbolDBEngine * dbe, const gchar * project,
5294 const GPtrArray * files_path,
5295 gboolean update_prj_analyse_time)
5297 SymbolDBEnginePriv *priv;
5298 UpdateFileSymbolsData *update_data;
5299 gboolean ret_code;
5300 gint ret_id, scan_id;
5301 gint i;
5302 GPtrArray * ready_files;
5304 priv = dbe->priv;
5306 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5307 g_return_val_if_fail (project != NULL, FALSE);
5309 ready_files = g_ptr_array_new_with_free_func (g_free);
5311 /* check if the files exist in db before passing them to the scan procedure */
5312 for (i = 0; i < files_path->len; i++)
5314 gchar *curr_abs_file;
5316 curr_abs_file = g_strdup (g_ptr_array_index (files_path, i));
5317 /* check if the file exists in db. We will not scan buffers for files
5318 * which aren't already in db
5320 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5322 DEBUG_PRINT ("will not update file symbols claiming to be %s because not in db",
5323 curr_abs_file);
5325 g_free (curr_abs_file);
5326 continue;
5329 /* ok the file exists in db. Add it to ready_files */
5330 g_ptr_array_add (ready_files, curr_abs_file);
5333 /* if no file has been added to the array then bail out here */
5334 if (ready_files->len <= 0)
5336 g_ptr_array_unref (ready_files);
5337 DEBUG_PRINT ("not enough files to update");
5338 return -1;
5341 update_data = g_new0 (UpdateFileSymbolsData, 1);
5343 update_data->update_prj_analyse_time = update_prj_analyse_time;
5344 update_data->files_path = ready_files;
5345 update_data->project = g_strdup (project);
5346 update_data->project_directory = g_strdup (priv->project_directory);
5349 /* data will be freed when callback will be called. The signal will be
5350 * disconnected too, don't worry about disconneting it by hand.
5352 g_signal_connect (G_OBJECT (dbe), "scan-end",
5353 G_CALLBACK (on_scan_update_files_symbols_end), update_data);
5355 scan_id = sdb_engine_get_unique_scan_id (dbe);
5356 ret_code = sdb_engine_scan_files_async (dbe, ready_files, NULL, TRUE, scan_id);
5358 if (ret_code == TRUE)
5360 ret_id = scan_id;
5362 else
5363 ret_id = -1;
5365 return ret_id;
5369 * symbol_db_engine_update_project_symbols:
5370 * @dbe: self
5371 * @project_name: The project name
5372 * @force_all_files:
5374 * Update symbols of the whole project. It scans all file symbols etc.
5375 * If force is true then update forcely all the files.
5376 * ~~~ Thread note: this function locks the mutex ~~~ *
5378 * Returns: scan id of the process, or -1 in case of problems.
5380 gint
5381 symbol_db_engine_update_project_symbols (SymbolDBEngine *dbe,
5382 const gchar *project_name, gboolean force_all_files)
5384 const GdaSet *plist;
5385 const GdaStatement *stmt;
5386 GdaHolder *param;
5387 GdaDataModel *data_model;
5388 gint num_rows = 0;
5389 gint i;
5390 GPtrArray *files_to_scan;
5391 SymbolDBEnginePriv *priv;
5392 GValue v = {0};
5394 g_return_val_if_fail (dbe != NULL, FALSE);
5396 priv = dbe->priv;
5398 g_return_val_if_fail (project_name != NULL, FALSE);
5399 g_return_val_if_fail (priv->project_directory != NULL, FALSE);
5401 SDB_LOCK(priv);
5403 DEBUG_PRINT ("Updating symbols of project-name %s (force %d)...", project_name, force_all_files);
5404 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5405 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME))
5406 == NULL)
5408 g_warning ("query is null");
5409 SDB_UNLOCK(priv);
5410 return FALSE;
5413 plist = sdb_engine_get_query_parameters_list (dbe,
5414 PREP_QUERY_GET_ALL_FROM_FILE_BY_PROJECT_NAME);
5416 /* prjname parameter */
5417 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5419 g_warning ("param prjid is NULL from pquery!");
5420 SDB_UNLOCK(priv);
5421 return FALSE;
5424 SDB_PARAM_SET_STRING(param, project_name);
5426 /* execute the query with parameters just set */
5427 GType gtype_array [6] = { G_TYPE_INT,
5428 G_TYPE_STRING,
5429 G_TYPE_INT,
5430 G_TYPE_INT,
5431 GDA_TYPE_TIMESTAMP,
5432 G_TYPE_NONE
5434 data_model = gda_connection_statement_execute_select_full (priv->db_connection,
5435 (GdaStatement*)stmt,
5436 (GdaSet*)plist,
5437 GDA_STATEMENT_MODEL_RANDOM_ACCESS,
5438 gtype_array,
5439 NULL);
5441 if (!GDA_IS_DATA_MODEL (data_model) ||
5442 (num_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (data_model))) <= 0)
5444 if (data_model != NULL)
5445 g_object_unref (data_model);
5446 data_model = NULL;
5448 g_warning ("Strange enough, no files in project ->%s<- found",
5449 project_name);
5450 SDB_UNLOCK(priv);
5451 return FALSE;
5454 /* initialize the array */
5455 files_to_scan = g_ptr_array_new_with_free_func (g_free);
5457 /* we can now scan each filename entry to check the last modification time. */
5458 for (i = 0; i < num_rows; i++)
5460 const GValue *value, *value1;
5461 const GdaTimestamp *timestamp;
5462 const gchar *file_name;
5463 gchar *file_abs_path = NULL;
5464 struct tm filetm;
5465 time_t db_time;
5466 GFile *gfile;
5467 GFileInfo* gfile_info;
5468 GFileInputStream* gfile_is;
5470 if ((value =
5471 gda_data_model_get_value_at (data_model,
5472 gda_data_model_get_column_index(data_model,
5473 "db_file_path"),
5474 i, NULL)) == NULL)
5476 continue;
5479 /* build abs path. */
5480 file_name = g_value_get_string (value);
5481 if (!file_name)
5482 continue;
5484 file_abs_path = g_build_filename (priv->project_directory,
5485 file_name, NULL);
5487 gfile = g_file_new_for_path (file_abs_path);
5488 gfile_is = g_file_read (gfile, NULL, NULL);
5489 /* retrieve data/time info */
5490 if (gfile_is == NULL)
5492 g_message ("could not open path %s", file_abs_path);
5493 g_free (file_abs_path);
5494 g_object_unref (gfile);
5495 continue;
5497 g_object_unref (gfile_is);
5499 gfile_info = g_file_query_info (gfile, "*", G_FILE_QUERY_INFO_NONE,
5500 NULL, NULL);
5502 if (gfile_info == NULL)
5504 g_message ("cannot get file info from handle");
5505 g_free (file_abs_path);
5506 g_object_unref (gfile);
5507 continue;
5510 if ((value1 = gda_data_model_get_value_at (data_model,
5511 gda_data_model_get_column_index(data_model,
5512 "analyse_time"), i, NULL)) == NULL)
5514 continue;
5518 timestamp = gda_value_get_timestamp (value1);
5520 /* fill a struct tm with the date retrieved by the string. */
5521 /* string is something like '2007-04-18 23:51:39' */
5522 memset (&filetm, 0, sizeof (struct tm));
5523 filetm.tm_year = timestamp->year - 1900;
5524 filetm.tm_mon = timestamp->month - 1;
5525 filetm.tm_mday = timestamp->day;
5526 filetm.tm_hour = timestamp->hour;
5527 filetm.tm_min = timestamp->minute;
5528 filetm.tm_sec = timestamp->second;
5530 /* remove one hour to the db_file_time. */
5531 db_time = mktime (&filetm) - 3600;
5533 guint64 modified_time = g_file_info_get_attribute_uint64 (gfile_info,
5534 G_FILE_ATTRIBUTE_TIME_MODIFIED);
5535 if (difftime (db_time, modified_time) < 0 ||
5536 force_all_files == TRUE)
5538 g_ptr_array_add (files_to_scan, file_abs_path);
5540 else
5542 g_free (file_abs_path);
5545 g_object_unref (gfile_info);
5546 g_object_unref (gfile);
5549 if (data_model)
5550 g_object_unref (data_model);
5552 if (files_to_scan->len > 0)
5554 SDB_UNLOCK(priv);
5556 /* at the end let the scanning function do its job */
5557 gint id = symbol_db_engine_update_files_symbols (dbe, project_name,
5558 files_to_scan, TRUE);
5560 g_ptr_array_unref (files_to_scan);
5561 return id;
5564 SDB_UNLOCK(priv);
5566 /* some error occurred */
5567 return -1;
5570 /**
5571 * symbol_db_engine_remove_file:
5572 * @dbe: self
5573 * @project: project name
5574 * @rel_file: db relative file entry of the symbols to remove.
5576 * Remove a file, together with its symbols, from a project. I.e. it won't remove
5577 * physically the file from disk.
5578 * ~~~ Thread note: this function locks the mutex
5580 * Returns: TRUE if everything went good, FALSE otherwise.
5582 gboolean
5583 symbol_db_engine_remove_file (SymbolDBEngine * dbe, const gchar *project,
5584 const gchar *rel_file)
5586 SymbolDBEnginePriv *priv;
5587 const GdaSet *plist;
5588 const GdaStatement *stmt;
5589 GdaHolder *param;
5590 GValue v = {0};
5593 g_return_val_if_fail (dbe != NULL, FALSE);
5594 g_return_val_if_fail (project != NULL, FALSE);
5595 g_return_val_if_fail (rel_file != NULL, FALSE);
5596 priv = dbe->priv;
5598 SDB_LOCK(priv);
5600 if (strlen (rel_file) <= 0)
5602 g_warning ("wrong file to delete.");
5603 SDB_UNLOCK(priv);
5604 return FALSE;
5607 DEBUG_PRINT ("deleting from db %s", rel_file);
5609 if ((stmt = sdb_engine_get_statement_by_query_id (dbe,
5610 PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME)) == NULL)
5612 g_warning ("query is null");
5613 SDB_UNLOCK(priv);
5614 return FALSE;
5617 plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_REMOVE_FILE_BY_PROJECT_NAME);
5619 if ((param = gda_set_get_holder ((GdaSet*)plist, "prjname")) == NULL)
5621 g_warning ("param prjname is NULL from pquery!");
5622 SDB_UNLOCK(priv);
5623 return FALSE;
5626 SDB_PARAM_SET_STRING(param, project);
5628 if ((param = gda_set_get_holder ((GdaSet*)plist, "filepath")) == NULL)
5630 g_warning ("param filepath is NULL from pquery!");
5631 SDB_UNLOCK(priv);
5632 return FALSE;
5635 SDB_PARAM_SET_STRING(param, rel_file);
5637 /* Triggers will take care of updating/deleting connected symbols
5638 * tuples, like sym_kind, sym_type etc */
5639 gda_connection_statement_execute_non_select (priv->db_connection, (GdaStatement*)stmt,
5640 (GdaSet*)plist, NULL, NULL);
5642 /* emits removed symbols signals */
5643 sdb_engine_detects_removed_ids (dbe);
5645 SDB_UNLOCK(priv);
5647 return TRUE;
5650 void
5651 symbol_db_engine_remove_files (SymbolDBEngine * dbe, const gchar * project,
5652 const GPtrArray * files)
5654 gint i;
5656 g_return_if_fail (dbe != NULL);
5657 g_return_if_fail (project != NULL);
5658 g_return_if_fail (files != NULL);
5660 for (i = 0; i < files->len; i++)
5662 symbol_db_engine_remove_file (dbe, project, g_ptr_array_index (files, i));
5666 static void
5667 on_scan_update_buffer_end (SymbolDBEngine * dbe, gint process_id, gpointer data)
5669 GPtrArray *files_to_scan;
5670 gint i;
5672 g_return_if_fail (dbe != NULL);
5673 g_return_if_fail (data != NULL);
5675 files_to_scan = (GPtrArray *) data;
5677 for (i = 0; i < files_to_scan->len; i++)
5679 gchar *node = (gchar *) g_ptr_array_index (files_to_scan, i);
5680 const gchar *relative_path = symbol_db_util_get_file_db_path (dbe, node);
5681 if (relative_path != NULL)
5683 /* will be emitted removed signals */
5684 if (sdb_engine_update_file (dbe, relative_path) == FALSE)
5686 g_warning ("Error processing file %s", node);
5687 return;
5692 g_signal_handlers_disconnect_by_func (dbe, on_scan_update_buffer_end,
5693 files_to_scan);
5695 /* free the GPtrArray. */
5696 g_ptr_array_unref (files_to_scan);
5697 data = files_to_scan = NULL;
5701 * symbol_db_engine_update_buffer_symbols:
5702 * @dbe: self
5703 * @project: project name
5704 * @real_files: full path on disk to 'real file' to update. e.g.
5705 * /home/foouser/fooproject/src/main.c.
5706 * @text_buffers: memory buffers
5707 * @buffer_sizes: one to one sizes with text_buffers.
5709 * Update symbols of a file by a memory-buffer to perform a real-time updating
5710 * of symbols.
5712 * Returns: scan process id if insertion is successful, -1 on error.
5714 gint
5715 symbol_db_engine_update_buffer_symbols (SymbolDBEngine * dbe, const gchar *project,
5716 const GPtrArray * real_files,
5717 const GPtrArray * text_buffers,
5718 const GPtrArray * buffer_sizes)
5720 SymbolDBEnginePriv *priv;
5721 gint i;
5722 gint ret_id, scan_id;
5723 gboolean ret_code;
5724 /* array that'll represent the /dev/shm/anjuta-XYZ files */
5725 GPtrArray *temp_files;
5726 GPtrArray *real_files_list;
5727 GPtrArray *real_files_on_db;
5729 g_return_val_if_fail (dbe != NULL, FALSE);
5730 priv = dbe->priv;
5732 g_return_val_if_fail (priv->db_connection != NULL, FALSE);
5733 g_return_val_if_fail (project != NULL, FALSE);
5734 g_return_val_if_fail (real_files != NULL, FALSE);
5735 g_return_val_if_fail (text_buffers != NULL, FALSE);
5736 g_return_val_if_fail (buffer_sizes != NULL, FALSE);
5738 temp_files = g_ptr_array_new_with_free_func (g_free);
5739 real_files_on_db = g_ptr_array_new_with_free_func (g_free);
5740 real_files_list = anjuta_util_clone_string_gptrarray (real_files);
5742 /* obtain a GPtrArray with real_files on database */
5743 for (i=0; i < real_files_list->len; i++)
5745 const gchar *relative_path;
5746 const gchar *curr_abs_file;
5747 FILE *buffer_mem_file;
5748 const gchar *temp_buffer;
5749 gint buffer_mem_fd;
5750 gint temp_size;
5751 gchar *shared_temp_file;
5752 gchar *base_filename;
5754 curr_abs_file = g_ptr_array_index (real_files_list, i);
5755 /* check if the file exists in db. We will not scan buffers for files
5756 * which aren't already in db
5758 if (symbol_db_engine_file_exists (dbe, curr_abs_file) == FALSE)
5760 DEBUG_PRINT ("will not scan buffer claiming to be %s because not in db",
5761 curr_abs_file);
5762 continue;
5765 relative_path = g_strdup (symbol_db_util_get_file_db_path (dbe, curr_abs_file));
5766 if (relative_path == NULL)
5768 g_warning ("relative_path is NULL");
5769 continue;
5771 g_ptr_array_add (real_files_on_db, (gpointer) relative_path);
5773 /* it's ok to have just the base filename to create the
5774 * target buffer one */
5775 base_filename = g_filename_display_basename (relative_path);
5777 shared_temp_file = g_strdup_printf ("/anjuta-%d-%ld-%s", getpid (),
5778 time (NULL), base_filename);
5779 g_free (base_filename);
5781 if ((buffer_mem_fd =
5782 shm_open (shared_temp_file, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0)
5784 g_warning ("Error while trying to open a shared memory file. Be"
5785 "sure to have "SHARED_MEMORY_PREFIX" mounted with tmpfs");
5786 return -1;
5789 buffer_mem_file = fdopen (buffer_mem_fd, "w+b");
5791 temp_buffer = g_ptr_array_index (text_buffers, i);
5792 temp_size = GPOINTER_TO_INT(g_ptr_array_index (buffer_sizes, i));
5794 fwrite (temp_buffer, sizeof(gchar), temp_size, buffer_mem_file);
5795 fflush (buffer_mem_file);
5796 fclose (buffer_mem_file);
5798 /* add the temp file to the array. */
5799 g_ptr_array_add (temp_files, g_strdup_printf (SHARED_MEMORY_PREFIX"%s",
5800 shared_temp_file));
5802 /* check if we already have an entry stored in the hash table, else
5803 * insert it
5805 if (g_hash_table_lookup (priv->garbage_shared_mem_files, shared_temp_file)
5806 == NULL)
5808 DEBUG_PRINT ("inserting into garbage hash table %s", shared_temp_file);
5809 g_hash_table_insert (priv->garbage_shared_mem_files, shared_temp_file,
5810 NULL);
5812 else
5814 /* the item is already stored. Just free it here. */
5815 g_free (shared_temp_file);
5819 /* in case we didn't have any good buffer to scan...*/
5820 ret_id = -1;
5822 /* it may happen that no buffer is correctly set up */
5823 if (real_files_on_db->len > 0)
5825 /* data will be freed when callback will be called. The signal will be
5826 * disconnected too, don't worry about disconnecting it by hand.
5828 g_signal_connect (G_OBJECT (dbe), "scan-end",
5829 G_CALLBACK (on_scan_update_buffer_end), real_files_list);
5831 scan_id = sdb_engine_get_unique_scan_id (dbe);
5832 ret_code = sdb_engine_scan_files_async (dbe, temp_files, real_files_on_db, TRUE, scan_id);
5834 if (ret_code == TRUE)
5836 ret_id = scan_id;
5838 else
5839 ret_id = -1;
5842 g_ptr_array_unref (temp_files);
5843 g_ptr_array_unref (real_files_on_db);
5844 return ret_id;
5848 * symbol_db_engine_get_files_for_project:
5849 * @dbe: self
5851 * Retrieves the list of files in project. The data model contains only 1
5852 * column, which is the file name.
5854 * Returns: data model which must be freed once used.
5856 GdaDataModel*
5857 symbol_db_engine_get_files_for_project (SymbolDBEngine *dbe)
5859 return sdb_engine_execute_select_sql (dbe, "SELECT file.file_path FROM file");
5863 * symbol_db_engine_set_db_case_sensitive:
5864 * @dbe: self
5865 * @case_sensitive: boolean flag.
5867 * Set the opened db case sensitive. The searches on this db will then be performed
5868 * taking into consideration this SQLite's PRAGMA case_sensitive_like.
5869 * ~~~ Thread note: this function locks the mutex ~~~
5872 void
5873 symbol_db_engine_set_db_case_sensitive (SymbolDBEngine *dbe, gboolean case_sensitive)
5875 g_return_if_fail (dbe != NULL);
5877 if (case_sensitive == TRUE)
5878 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 1");
5879 else
5880 sdb_engine_execute_unknown_sql (dbe, "PRAGMA case_sensitive_like = 0");
5884 * symbol_db_engine_get_type_conversion_hash:
5885 * @dbe: self
5887 * Get conversion hash table used to convert symbol type name to enum value
5889 * Returns: a GHashTable which must be freed once used.
5891 const GHashTable*
5892 symbol_db_engine_get_type_conversion_hash (SymbolDBEngine *dbe)
5894 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5895 return dbe->priv->sym_type_conversion_hash;
5899 * symbol_db_engine_get_project_directory:
5900 * @dbe: self
5902 * Gets the project directory (used to construct absolute paths)
5904 * Returns: a const gchar containing the project_directory.
5906 const gchar*
5907 symbol_db_engine_get_project_directory (SymbolDBEngine *dbe)
5909 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5910 return dbe->priv->project_directory;
5914 * symbol_db_engine_get_statement:
5915 * @dbe: self
5916 * @sql_str: sql statement.
5918 * Compiles an sql statement
5920 * Returns: a GdaStatement object which must be freed once used.
5922 GdaStatement*
5923 symbol_db_engine_get_statement (SymbolDBEngine *dbe, const gchar *sql_str)
5925 GdaStatement* stmt;
5926 GError *error = NULL;
5928 g_return_val_if_fail (SYMBOL_IS_DB_ENGINE (dbe), NULL);
5929 stmt = gda_sql_parser_parse_string (dbe->priv->sql_parser,
5930 sql_str,
5931 NULL, &error);
5932 if (error)
5934 g_warning ("SQL parsing failed: %s: %s", sql_str, error->message);
5935 g_error_free (error);
5937 return stmt;
5941 * symbol_db_engine_execute_select:
5942 * @dbe: self
5943 * @stmt: A compiled GdaStatement sql statement.
5944 * @params: Params for GdaStatement (i.e. a prepared statement).
5946 * Executes a parameterized sql statement
5948 * Returns: A data model which must be freed once used.
5950 GdaDataModel*
5951 symbol_db_engine_execute_select (SymbolDBEngine *dbe, GdaStatement *stmt,
5952 GdaSet *params)
5954 GdaDataModel *res;
5955 GError *error = NULL;
5957 res = gda_connection_statement_execute_select (dbe->priv->db_connection,
5958 stmt, params, &error);
5959 if (error)
5961 gchar *sql_str =
5962 gda_statement_to_sql_extended (stmt, dbe->priv->db_connection,
5963 params, 0, NULL, NULL);
5965 g_warning ("SQL select exec failed: %s, %s", sql_str, error->message);
5966 g_free (sql_str);
5967 g_error_free (error);
5969 return res;