Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
tracker-sparql-buffer.c:350:10 | clang-analyzer | Branch condition evaluates to a garbage value |
1 /*
2 * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 * Author: Carlos Garnacho <carlos@lanedo.com>
20 */
21
22 #include "config.h"
23
24 #include <libtracker-sparql/tracker-sparql.h>
25
26 #include "tracker-sparql-buffer.h"
27
28 /* Maximum time (seconds) before forcing a sparql buffer flush */
29 #define MAX_SPARQL_BUFFER_TIME 15
30
31 typedef struct _TrackerSparqlBufferPrivate TrackerSparqlBufferPrivate;
32 typedef struct _SparqlTaskData SparqlTaskData;
33 typedef struct _UpdateArrayData UpdateArrayData;
34 typedef struct _UpdateData UpdateData;
35 typedef struct _BulkOperationMerge BulkOperationMerge;
36
37 enum {
38 PROP_0,
39 PROP_CONNECTION
40 };
41
42 enum {
43 TASK_TYPE_SPARQL_STR,
44 TASK_TYPE_SPARQL,
45 TASK_TYPE_BULK
46 };
47
48 struct _TrackerSparqlBufferPrivate
49 {
50 TrackerSparqlConnection *connection;
51 guint flush_timeout_id;
52 GPtrArray *tasks;
53 gint n_updates;
54 };
55
56 struct _SparqlTaskData
57 {
58 guint type;
59
60 union {
61 gchar *str;
62 TrackerSparqlBuilder *builder;
63
64 struct {
65 gchar *str;
66 guint flags;
67 } bulk;
68 } data;
69
70 GSimpleAsyncResult *result;
71 };
72
73 struct _UpdateData {
74 TrackerSparqlBuffer *buffer;
75 TrackerTask *task;
76 };
77
78 struct _UpdateArrayData {
79 TrackerSparqlBuffer *buffer;
80 GPtrArray *tasks;
81 GArray *sparql_array;
82 GArray *error_map;
83 GPtrArray *bulk_ops;
84 gint n_bulk_operations;
85 };
86
87 struct _BulkOperationMerge {
88 const gchar *bulk_operation;
89 GList *tasks;
90 gchar *sparql;
91 };
92
93
94
95 G_DEFINE_TYPE (TrackerSparqlBuffer, tracker_sparql_buffer, TRACKER_TYPE_TASK_POOL)
96
97 static void
98 tracker_sparql_buffer_finalize (GObject *object)
99 {
100 TrackerSparqlBufferPrivate *priv;
101
102 priv = TRACKER_SPARQL_BUFFER (object)->priv;
103
104 if (priv->flush_timeout_id != 0) {
105 g_source_remove (priv->flush_timeout_id);
106 }
107
108 G_OBJECT_CLASS (tracker_sparql_buffer_parent_class)->finalize (object);
109 }
110
111 static void
112 tracker_sparql_buffer_set_property (GObject *object,
113 guint param_id,
114 const GValue *value,
115 GParamSpec *pspec)
116 {
117 TrackerSparqlBufferPrivate *priv;
118
119 priv = TRACKER_SPARQL_BUFFER (object)->priv;
120
121 switch (param_id) {
122 case PROP_CONNECTION:
123 priv->connection = g_value_dup_object (value);
124 break;
125 default:
126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
127 break;
128 }
129 }
130
131 static void
132 tracker_sparql_buffer_get_property (GObject *object,
133 guint param_id,
134 GValue *value,
135 GParamSpec *pspec)
136 {
137 TrackerSparqlBufferPrivate *priv;
138
139 priv = TRACKER_SPARQL_BUFFER (object)->priv;
140
141 switch (param_id) {
142 case PROP_CONNECTION:
143 g_value_set_object (value,
144 priv->connection);
145 break;
146 default:
147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
148 break;
149 }
150 }
151
152 static void
153 tracker_sparql_buffer_class_init (TrackerSparqlBufferClass *klass)
154 {
155 GObjectClass *object_class = G_OBJECT_CLASS (klass);
156
157 object_class->finalize = tracker_sparql_buffer_finalize;
158 object_class->set_property = tracker_sparql_buffer_set_property;
159 object_class->get_property = tracker_sparql_buffer_get_property;
160
161 g_object_class_install_property (object_class,
162 PROP_CONNECTION,
163 g_param_spec_object ("connection",
164 "sparql connection",
165 "Sparql Connection",
166 TRACKER_SPARQL_TYPE_CONNECTION,
167 G_PARAM_READWRITE |
168 G_PARAM_CONSTRUCT_ONLY));
169
170 g_type_class_add_private (object_class,
171 sizeof (TrackerSparqlBufferPrivate));
172 }
173
174 static gboolean
175 flush_timeout_cb (gpointer user_data)
176 {
177 TrackerSparqlBuffer *buffer = user_data;
178 TrackerSparqlBufferPrivate *priv = buffer->priv;
179
180 tracker_sparql_buffer_flush (buffer, "Buffer time reached");
181 priv->flush_timeout_id = 0;
182
183 return FALSE;
184 }
185
186 static void
187 reset_flush_timeout (TrackerSparqlBuffer *buffer)
188 {
189 TrackerSparqlBufferPrivate *priv;
190
191 priv = buffer->priv;
192
193 if (priv->flush_timeout_id != 0) {
194 g_source_remove (priv->flush_timeout_id);
195 }
196
197 priv->flush_timeout_id = g_timeout_add_seconds (MAX_SPARQL_BUFFER_TIME,
198 flush_timeout_cb,
199 buffer);
200 }
201
202 static void
203 tracker_sparql_buffer_init (TrackerSparqlBuffer *buffer)
204 {
205 buffer->priv = G_TYPE_INSTANCE_GET_PRIVATE (buffer,
206 TRACKER_TYPE_SPARQL_BUFFER,
207 TrackerSparqlBufferPrivate);
208 }
209
210 TrackerSparqlBuffer *
211 tracker_sparql_buffer_new (TrackerSparqlConnection *connection,
212 guint limit)
213 {
214 return g_object_new (TRACKER_TYPE_SPARQL_BUFFER,
215 "connection", connection,
216 "limit", limit,
217 NULL);
218 }
219
220 static void
221 remove_task_foreach (TrackerTask *task,
222 TrackerTaskPool *pool)
223 {
224 tracker_task_pool_remove (pool, task);
225 }
226
227 static void
228 update_array_data_free (UpdateArrayData *update_data)
229 {
230 if (!update_data)
231 return;
232
233 if (update_data->sparql_array) {
234 /* The array contains pointers to strings in the tasks, so no need to
235 * deallocate its pointed contents, just the array itself. */
236 g_array_free (update_data->sparql_array, TRUE);
237 }
238
239 if (update_data->bulk_ops) {
240 /* The BulkOperationMerge structs which contain the sparql strings
241 * are deallocated here */
242 g_ptr_array_free (update_data->bulk_ops, TRUE);
243 }
244
245 g_ptr_array_foreach (update_data->tasks,
246 (GFunc) remove_task_foreach,
247 update_data->buffer);
248 g_ptr_array_free (update_data->tasks, TRUE);
249
250 g_array_free (update_data->error_map, TRUE);
251 g_slice_free (UpdateArrayData, update_data);
252 }
253
254 static void
255 tracker_sparql_buffer_update_array_cb (GObject *object,
256 GAsyncResult *result,
257 gpointer user_data)
258 {
259 TrackerSparqlBufferPrivate *priv;
260 GError *global_error = NULL;
261 GPtrArray *sparql_array_errors;
262 UpdateArrayData *update_data;
263 gint i;
264
265 /* Get arrays of errors and queries */
266 update_data = user_data;
267 priv = TRACKER_SPARQL_BUFFER (update_data->buffer)->priv;
268 priv->n_updates--;
269
270 g_debug ("(Sparql buffer) Finished array-update with %u tasks",
271 update_data->tasks->len);
272
273 sparql_array_errors = tracker_sparql_connection_update_array_finish (priv->connection,
274 result,
275 &global_error);
276 if (global_error) {
277 g_critical (" (Sparql buffer) Error in array-update: %s",
278 global_error->message);
279 }
280
281 /* Report status on each task of the batch update */
282 for (i = 0; i < update_data->tasks->len; i++) {
283 TrackerTask *task;
284 SparqlTaskData *task_data;
285 GError *error = NULL;
286
287 task = g_ptr_array_index (update_data->tasks, i);
288 task_data = tracker_task_get_data (task);
289
290 if (global_error) {
291 error = global_error;
292 } else {
293 gint error_pos;
294
295 error_pos = g_array_index (update_data->error_map, gint, i);
296
297 /* Find the corresponing error according to the passed map,
298 * numbers >= 0 are non-bulk tasks, and < 0 are bulk tasks,
299 * so the number of bulk operations must be added, as these
300 * tasks are prepended.
301 */
302 error_pos += update_data->n_bulk_operations;
303 error = g_ptr_array_index (sparql_array_errors, error_pos);
304 if (error) {
305 g_critical (" (Sparql buffer) Error in task %u of the array-update: %s",
306 i, error->message);
307
308 if (error_pos < update_data->n_bulk_operations) {
309 BulkOperationMerge *bulk;
310 GList *tasks;
311 gint bulk_pos;
312
313 bulk_pos = ABS (error_pos - update_data->n_bulk_operations + 1);
314 bulk = g_ptr_array_index (update_data->bulk_ops, bulk_pos);
315 tasks = bulk->tasks;
316
317 g_debug (" Affected files:");
318
319 while (tasks) {
320 TrackerTask *task = tasks->data;
321 gchar *uri;
322
323 uri = g_file_get_uri (tracker_task_get_file (task));
324 g_debug (" - %s", uri);
325 g_free (uri);
326
327 tasks = tasks->next;
328 }
329
330 g_debug (" Sparql: %s", bulk->sparql);
331 } else {
332 const gchar *sparql;
333 gchar *uri;
334
335 uri = g_file_get_uri (tracker_task_get_file (task));
336 g_debug (" Affected file: %s", uri);
337 g_free (uri);
338
339 switch (task_data->type) {
340 case TASK_TYPE_SPARQL_STR:
341 sparql = task_data->data.str;
342 break;
343 case TASK_TYPE_SPARQL:
344 sparql = tracker_sparql_builder_get_result (task_data->data.builder);
345 break;
346 default:
347 break;
348 }
349
350 if (sparql) {
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
351 g_debug (" Sparql: %s", sparql);
352 }
353 }
354 }
355 }
356
357 /* Call finished handler with the error, if any */
358 g_simple_async_result_set_op_res_gpointer (task_data->result,
359 task, NULL);
360 if (error) {
361 g_simple_async_result_set_from_error (task_data->result, error);
362 }
363
364 g_simple_async_result_complete (task_data->result);
365
366 /* No need to deallocate the task here, it will be done when
367 * unref-ing the UpdateArrayData below */
368 }
369
370 /* Unref the arrays of errors and queries */
371 if (sparql_array_errors) {
372 g_ptr_array_unref (sparql_array_errors);
373 }
374
375 /* Note that tasks are actually deallocated here */
376 update_array_data_free (update_data);
377
378 if (global_error) {
379 g_error_free (global_error);
380 }
381 }
382
383 static void
384 bulk_operation_merge_finish (BulkOperationMerge *merge)
385 {
386 if (merge->sparql) {
387 g_free (merge->sparql);
388 merge->sparql = NULL;
389 }
390
391 if (merge->bulk_operation && merge->tasks) {
392 GString *equals_string = NULL, *children_string = NULL, *sparql;
393 gint n_equals = 0;
394 gboolean include_logical_resources = FALSE;
395 GList *l;
396
397 for (l = merge->tasks; l; l = l->next) {
398 SparqlTaskData *task_data;
399 TrackerTask *task = l->data;
400 gchar *uri;
401
402 task_data = tracker_task_get_data (task);
403 uri = g_file_get_uri (tracker_task_get_file (task));
404
405 if (task_data->data.bulk.flags & TRACKER_BULK_MATCH_EQUALS) {
406 if (!equals_string) {
407 equals_string = g_string_new ("");
408 } else {
409 g_string_append_c (equals_string, ',');
410 }
411
412 g_string_append_printf (equals_string, "\"%s\"", uri);
413 n_equals++;
414 }
415
416 if (task_data->data.bulk.flags & TRACKER_BULK_MATCH_CHILDREN) {
417 if (!children_string) {
418 children_string = g_string_new ("");
419 } else {
420 g_string_append_c (children_string, ',');
421 }
422
423 g_string_append_printf (children_string, "\"%s\"", uri);
424 }
425
426 if (task_data->data.bulk.flags & TRACKER_BULK_MATCH_LOGICAL_RESOURCES) {
427 include_logical_resources = TRUE;
428 }
429
430 g_free (uri);
431 }
432
433 sparql = g_string_new ("");
434
435 if (equals_string) {
436 g_string_append (sparql, merge->bulk_operation);
437 g_string_append_printf (sparql, " WHERE { ");
438
439 if (n_equals == 1) {
440 g_string_append_printf (sparql,
441 " ?f nie:url %s .",
442 equals_string->str);
443 } else {
444 g_string_append_printf (sparql,
445 " ?f nie:url ?u ."
446 " FILTER (?u IN (%s))",
447 equals_string->str);
448 }
449 g_string_free (equals_string, TRUE);
450
451 if (include_logical_resources) {
452 g_string_append (sparql, " ?ie nie:isStoredAs ?f .");
453 }
454 g_string_append_printf (sparql, " } ");
455 }
456
457 if (children_string) {
458 g_string_append (sparql, merge->bulk_operation);
459 g_string_append_printf (sparql,
460 " WHERE { "
461 " ?f nie:url ?u ."
462 " FILTER (tracker:uri-is-descendant (%s, ?u))",
463 children_string->str);
464 g_string_free (children_string, TRUE);
465
466 if (include_logical_resources) {
467 g_string_append (sparql, " ?ie nie:isStoredAs ?f .");
468 }
469 g_string_append_printf (sparql, "} ");
470 }
471
472 merge->sparql = g_string_free (sparql, FALSE);
473 }
474 }
475
476 static BulkOperationMerge *
477 bulk_operation_merge_new (const gchar *bulk_operation)
478 {
479 BulkOperationMerge *operation;
480
481 operation = g_slice_new0 (BulkOperationMerge);
482 operation->bulk_operation = bulk_operation;
483
484 return operation;
485 }
486
487 static void
488 bulk_operation_merge_free (BulkOperationMerge *operation)
489 {
490 g_list_foreach (operation->tasks,
491 (GFunc) tracker_task_unref,
492 NULL);
493 g_list_free (operation->tasks);
494 g_free (operation->sparql);
495 g_slice_free (BulkOperationMerge, operation);
496 }
497
498 gboolean
499 tracker_sparql_buffer_flush (TrackerSparqlBuffer *buffer,
500 const gchar *reason)
501 {
502 TrackerSparqlBufferPrivate *priv;
503 GPtrArray *bulk_ops = NULL;
504 GArray *sparql_array, *error_map;
505 UpdateArrayData *update_data;
506 gint i, j;
507
508 priv = buffer->priv;
509
510 if (priv->n_updates > 0) {
511 return FALSE;
512 }
513
514 if (!priv->tasks ||
515 priv->tasks->len == 0) {
516 return FALSE;
517 }
518
519 g_debug ("Flushing SPARQL buffer, reason: %s", reason);
520
521 if (priv->flush_timeout_id != 0) {
522 g_source_remove (priv->flush_timeout_id);
523 priv->flush_timeout_id = 0;
524 }
525
526 /* Loop buffer and construct array of strings */
527 sparql_array = g_array_new (FALSE, TRUE, sizeof (gchar *));
528 error_map = g_array_new (TRUE, TRUE, sizeof (gint));
529
530 for (i = 0; i < priv->tasks->len; i++) {
531 SparqlTaskData *task_data;
532 TrackerTask *task;
533 gint pos;
534
535 task = g_ptr_array_index (priv->tasks, i);
536 task_data = tracker_task_get_data (task);
537
538 if (task_data->type == TASK_TYPE_SPARQL_STR) {
539 g_array_append_val (sparql_array, task_data->data.str);
540 pos = sparql_array->len - 1;
541 } else if (task_data->type == TASK_TYPE_SPARQL) {
542 const gchar *str;
543
544 str = tracker_sparql_builder_get_result (task_data->data.builder);
545 g_array_append_val (sparql_array, str);
546 pos = sparql_array->len - 1;
547 } else if (task_data->type == TASK_TYPE_BULK) {
548 BulkOperationMerge *bulk = NULL;
549 gint j;
550
551 if (G_UNLIKELY (!bulk_ops)) {
552 bulk_ops = g_ptr_array_new_with_free_func ((GDestroyNotify) bulk_operation_merge_free);
553 }
554
555 for (j = 0; j < bulk_ops->len; j++) {
556 BulkOperationMerge *cur;
557
558 cur = g_ptr_array_index (bulk_ops, j);
559
560 /* This is a comparison of intern strings */
561 if (cur->bulk_operation == task_data->data.bulk.str) {
562 bulk = cur;
563 pos = - 1 - j;
564 break;
565 }
566 }
567
568 if (!bulk) {
569 bulk = bulk_operation_merge_new (task_data->data.bulk.str);
570 g_ptr_array_add (bulk_ops, bulk);
571 pos = - bulk_ops->len;
572 }
573
574 bulk->tasks = g_list_prepend (bulk->tasks,
575 tracker_task_ref (task));
576 }
577
578 g_array_append_val (error_map, pos);
579 }
580
581 if (bulk_ops) {
582 for (j = 0; j < bulk_ops->len; j++) {
583 BulkOperationMerge *bulk;
584
585 bulk = g_ptr_array_index (bulk_ops, j);
586 bulk_operation_merge_finish (bulk);
587
588 if (bulk->sparql) {
589 g_array_prepend_val (sparql_array,
590 bulk->sparql);
591 }
592 }
593 }
594
595 update_data = g_slice_new0 (UpdateArrayData);
596 update_data->buffer = buffer;
597 update_data->tasks = g_ptr_array_ref (priv->tasks);
598 update_data->bulk_ops = bulk_ops;
599 update_data->n_bulk_operations = bulk_ops ? bulk_ops->len : 0;
600 update_data->error_map = error_map;
601 update_data->sparql_array = sparql_array;
602
603 /* Empty pool, update_data will keep
604 * references to the tasks to keep
605 * these alive.
606 */
607 g_ptr_array_unref (priv->tasks);
608 priv->tasks = NULL;
609 priv->n_updates++;
610
611 /* Start the update */
612 tracker_sparql_connection_update_array_async (priv->connection,
613 (gchar **) update_data->sparql_array->data,
614 update_data->sparql_array->len,
615 G_PRIORITY_DEFAULT,
616 NULL,
617 tracker_sparql_buffer_update_array_cb,
618 update_data);
619
620 return TRUE;
621 }
622
623 static void
624 tracker_sparql_buffer_update_cb (GObject *object,
625 GAsyncResult *result,
626 gpointer user_data)
627 {
628 UpdateData *update_data = user_data;
629 SparqlTaskData *task_data;
630 GError *error = NULL;
631
632 tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (object),
633 result, &error);
634
635 task_data = tracker_task_get_data (update_data->task);
636
637 /* Call finished handler with the error, if any */
638 g_simple_async_result_set_op_res_gpointer (task_data->result,
639 update_data->task,
640 NULL);
641 if (error) {
642 g_simple_async_result_set_from_error (task_data->result, error);
643 g_error_free (error);
644 }
645
646 g_simple_async_result_complete (task_data->result);
647
648 tracker_task_pool_remove (TRACKER_TASK_POOL (update_data->buffer),
649 update_data->task);
650 g_slice_free (UpdateData, update_data);
651 }
652
653 void
654 tracker_sparql_buffer_push (TrackerSparqlBuffer *buffer,
655 TrackerTask *task,
656 gint priority,
657 GAsyncReadyCallback cb,
658 gpointer user_data)
659 {
660 TrackerSparqlBufferPrivate *priv;
661 SparqlTaskData *data;
662
663 g_return_if_fail (TRACKER_IS_SPARQL_BUFFER (buffer));
664 g_return_if_fail (task != NULL);
665
666 priv = buffer->priv;
667
668 data = tracker_task_get_data (task);
669 data->result = g_simple_async_result_new (G_OBJECT (buffer),
670 cb, user_data, NULL);
671
672 if (priority <= G_PRIORITY_HIGH &&
673 data->type != TASK_TYPE_BULK) {
674 UpdateData *update_data;
675 const gchar *sparql = NULL;
676
677 /* High priority task */
678 update_data = g_slice_new0 (UpdateData);
679 update_data->buffer = buffer;
680 update_data->task = task;
681
682 if (data->type == TASK_TYPE_SPARQL_STR) {
683 sparql = data->data.str;
684 } else if (data->type == TASK_TYPE_SPARQL) {
685 sparql = tracker_sparql_builder_get_result (data->data.builder);
686 }
687
688 tracker_task_pool_add (TRACKER_TASK_POOL (buffer), task);
689 tracker_sparql_connection_update_async (priv->connection,
690 sparql,
691 G_PRIORITY_HIGH,
692 NULL,
693 tracker_sparql_buffer_update_cb,
694 update_data);
695 } else {
696 if (tracker_task_pool_get_size (TRACKER_TASK_POOL (buffer)) == 0) {
697 reset_flush_timeout (buffer);
698 }
699
700 tracker_task_pool_add (TRACKER_TASK_POOL (buffer), task);
701
702 if (!priv->tasks) {
703 priv->tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) tracker_task_unref);
704 }
705
706 g_ptr_array_add (priv->tasks, task);
707
708 if (tracker_task_pool_limit_reached (TRACKER_TASK_POOL (buffer))) {
709 tracker_sparql_buffer_flush (buffer, "SPARQL buffer limit reached");
710 } else if (priv->tasks->len > tracker_task_pool_get_limit (TRACKER_TASK_POOL (buffer)) / 2) {
711 /* We've filled half of the buffer, flush it as we receive more tasks */
712 tracker_sparql_buffer_flush (buffer, "SPARQL buffer half-full");
713 }
714 }
715 }
716
717 static SparqlTaskData *
718 sparql_task_data_new (guint type,
719 gpointer data,
720 guint flags)
721 {
722 SparqlTaskData *task_data;
723
724 task_data = g_slice_new0 (SparqlTaskData);
725 task_data->type = type;
726
727 switch (type) {
728 case TASK_TYPE_SPARQL_STR:
729 task_data->data.str = data;
730 break;
731 case TASK_TYPE_SPARQL:
732 task_data->data.builder = g_object_ref (data);
733 break;
734 case TASK_TYPE_BULK:
735 task_data->data.bulk.str = data;
736 task_data->data.bulk.flags = flags;
737 break;
738 }
739
740 return task_data;
741 }
742
743 static void
744 sparql_task_data_free (SparqlTaskData *data)
745 {
746 switch (data->type) {
747 case TASK_TYPE_SPARQL_STR:
748 g_free (data->data.str);
749 break;
750 case TASK_TYPE_SPARQL:
751 g_object_unref (data->data.builder);
752 break;
753 case TASK_TYPE_BULK:
754 /* nothing to free, the string is interned */
755 break;
756 }
757
758 if (data->result) {
759 g_object_unref (data->result);
760 }
761
762 g_slice_free (SparqlTaskData, data);
763 }
764
765 TrackerTask *
766 tracker_sparql_task_new_take_sparql_str (GFile *file,
767 gchar *sparql_str)
768 {
769 SparqlTaskData *data;
770
771 data = sparql_task_data_new (TASK_TYPE_SPARQL_STR, sparql_str, 0);
772 return tracker_task_new (file, data,
773 (GDestroyNotify) sparql_task_data_free);
774 }
775
776 TrackerTask *
777 tracker_sparql_task_new_with_sparql_str (GFile *file,
778 const gchar *sparql_str)
779 {
780 SparqlTaskData *data;
781
782 data = sparql_task_data_new (TASK_TYPE_SPARQL_STR,
783 g_strdup (sparql_str), 0);
784 return tracker_task_new (file, data,
785 (GDestroyNotify) sparql_task_data_free);
786 }
787
788 TrackerTask *
789 tracker_sparql_task_new_with_sparql (GFile *file,
790 TrackerSparqlBuilder *builder)
791 {
792 SparqlTaskData *data;
793
794 data = sparql_task_data_new (TASK_TYPE_SPARQL, builder, 0);
795 return tracker_task_new (file, data,
796 (GDestroyNotify) sparql_task_data_free);
797 }
798
799 TrackerTask *
800 tracker_sparql_task_new_bulk (GFile *file,
801 const gchar *sparql_str,
802 TrackerBulkTaskFlags flags)
803 {
804 SparqlTaskData *data;
805
806 data = sparql_task_data_new (TASK_TYPE_BULK,
807 (gchar *) g_intern_string (sparql_str),
808 flags);
809 return tracker_task_new (file, data,
810 (GDestroyNotify) sparql_task_data_free);
811 }