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