1 /*
2  * Copyright (C) 2008, 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 
20 #include "config.h"
21 
22 #include <glib/gstdio.h>
23 
24 #include <sqlite3.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <errno.h>
28 
29 #include <libtracker-common/tracker-date-time.h>
30 #include <libtracker-common/tracker-debug.h>
31 #include <libtracker-common/tracker-locale.h>
32 #include <libtracker-common/tracker-parser.h>
33 
34 #include <libtracker-sparql/tracker-cursor.h>
35 #include <libtracker-sparql/tracker-private.h>
36 
37 #include <libtracker-fts/tracker-fts.h>
38 
39 
40 #ifdef HAVE_LIBUNISTRING
41 /* libunistring versions prior to 9.1.2 need this hack */
42 #define _UNUSED_PARAMETER_
43 #include <unistr.h>
44 #include <unicase.h>
45 #elif defined(HAVE_LIBICU)
46 #include <unicode/utypes.h>
47 #include <unicode/uregex.h>
48 #include <unicode/ustring.h>
49 #include <unicode/ucol.h>
50 #include <unicode/unorm2.h>
51 #endif
52 
53 #include "tracker-collation.h"
54 
55 #include "tracker-db-interface-sqlite.h"
56 #include "tracker-db-manager.h"
57 #include "tracker-data-enum-types.h"
58 #include "tracker-uuid.h"
59 #include "tracker-vtab-service.h"
60 #include "tracker-vtab-triples.h"
61 
62 typedef struct {
63 	TrackerDBStatement *head;
64 	TrackerDBStatement *tail;
65 	guint size;
66 	guint max;
67 } TrackerDBStatementLru;
68 
69 typedef struct {
70 	GRegex *syntax_check;
71 	GRegex *replacement;
72 	GRegex *unescape;
73 } TrackerDBReplaceFuncChecks;
74 
75 struct TrackerDBInterface {
76 	GObject parent_instance;
77 
78 	gchar *filename;
79 	gchar *shared_cache_key;
80 	sqlite3 *db;
81 
82 	GHashTable *dynamic_statements;
83 
84 	/* Compiled regular expressions */
85 	TrackerDBReplaceFuncChecks replace_func_checks;
86 
87 	/* Number of users (e.g. active cursors) */
88 	gint n_users;
89 
90 	guint flags;
91 	GCancellable *cancellable;
92 
93 	TrackerDBStatementLru select_stmt_lru;
94 	TrackerDBStatementLru update_stmt_lru;
95 
96 	gchar *fts_properties;
97 
98 	/* Used if TRACKER_DB_INTERFACE_USE_MUTEX is set */
99 	GMutex mutex;
100 
101 	/* User data */
102 	gpointer user_data;
103 	GDestroyNotify user_data_destroy_notify;
104 };
105 
106 struct TrackerDBInterfaceClass {
107 	GObjectClass parent_class;
108 };
109 
110 struct TrackerDBCursor {
111 	TrackerSparqlCursor parent_instance;
112 	sqlite3_stmt *stmt;
113 	TrackerDBStatement *ref_stmt;
114 	gboolean finished;
115 	TrackerPropertyType *types;
116 	gint n_types;
117 	gchar **variable_names;
118 	gint n_variable_names;
119 };
120 
121 struct TrackerDBCursorClass {
122 	TrackerSparqlCursorClass parent_class;
123 };
124 
125 struct TrackerDBStatement {
126 	GInitiallyUnowned parent_instance;
127 	TrackerDBInterface *db_interface;
128 	sqlite3_stmt *stmt;
129 	guint stmt_is_used : 1;
130 	guint stmt_is_owned : 1;
131 	TrackerDBStatement *next;
132 	TrackerDBStatement *prev;
133 };
134 
135 struct TrackerDBStatementClass {
136 	GObjectClass parent_class;
137 };
138 
139 static void                tracker_db_interface_initable_iface_init (GInitableIface        *iface);
140 static TrackerDBStatement *tracker_db_statement_sqlite_new          (TrackerDBInterface    *db_interface,
141                                                                      sqlite3_stmt          *sqlite_stmt);
142 static void                tracker_db_statement_sqlite_reset        (TrackerDBStatement    *stmt);
143 static TrackerDBCursor    *tracker_db_cursor_sqlite_new             (TrackerDBStatement    *ref_stmt,
144                                                                      TrackerPropertyType   *types,
145                                                                      gint                   n_types,
146                                                                      const gchar * const   *variable_names,
147                                                                      gint                   n_variable_names);
148 static gboolean            tracker_db_cursor_get_boolean            (TrackerSparqlCursor   *cursor,
149                                                                      guint                  column);
150 static gboolean            db_cursor_iter_next                      (TrackerDBCursor       *cursor,
151                                                                      GCancellable          *cancellable,
152                                                                      GError               **error);
153 
154 enum {
155 	PROP_0,
156 	PROP_FILENAME,
157 	PROP_FLAGS,
158 	PROP_SHARED_CACHE_KEY,
159 };
160 
161 enum {
162 	TRACKER_DB_CURSOR_PROP_0,
163 	TRACKER_DB_CURSOR_PROP_N_COLUMNS
164 };
165 
166 G_DEFINE_TYPE_WITH_CODE (TrackerDBInterface, tracker_db_interface, G_TYPE_OBJECT,
167                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
168                                                 tracker_db_interface_initable_iface_init));
169 
G_DEFINE_TYPE(TrackerDBStatement,tracker_db_statement,G_TYPE_INITIALLY_UNOWNED)170 G_DEFINE_TYPE (TrackerDBStatement, tracker_db_statement, G_TYPE_INITIALLY_UNOWNED)
171 
172 G_DEFINE_TYPE (TrackerDBCursor, tracker_db_cursor, TRACKER_SPARQL_TYPE_CURSOR)
173 
174 void
175 tracker_db_interface_sqlite_enable_shared_cache (void)
176 {
177 	sqlite3_enable_shared_cache (1);
178 }
179 
180 static void
result_context_function_error(sqlite3_context * context,const gchar * sparql_function,const gchar * error_message)181 result_context_function_error (sqlite3_context *context,
182 			       const gchar     *sparql_function,
183 			       const gchar     *error_message)
184 {
185 	gchar *message;
186 
187 	message = g_strdup_printf ("%s: %s", sparql_function, error_message);
188 	sqlite3_result_error (context, message, -1);
189 
190 	g_free (message);
191 }
192 
193 static void
function_sparql_string_join(sqlite3_context * context,int argc,sqlite3_value * argv[])194 function_sparql_string_join (sqlite3_context *context,
195                              int              argc,
196                              sqlite3_value   *argv[])
197 {
198 	const gchar *fn = "fn:string-join";
199 	GString *str = NULL;
200 	const gchar *separator;
201 	gint i;
202 
203 	/* fn:string-join (str1, str2, ..., separator) */
204 
205 	if (sqlite3_value_type (argv[argc-1]) != SQLITE_TEXT) {
206 		result_context_function_error (context, fn, "Invalid separator");
207 		return;
208 	}
209 
210 	separator = (gchar *)sqlite3_value_text (argv[argc-1]);
211 
212 	for (i = 0;i < argc-1; i++) {
213 		if (sqlite3_value_type (argv[argc-1]) == SQLITE_TEXT) {
214 			const gchar *text = (gchar *)sqlite3_value_text (argv[i]);
215 
216 			if (text != NULL) {
217 				if (!str) {
218 					str = g_string_new (text);
219 				} else {
220 					g_string_append_printf (str, "%s%s", separator, text);
221 				}
222 			}
223 		}
224 	}
225 
226 	if (str) {
227 		sqlite3_result_text (context, str->str, str->len, g_free);
228 		g_string_free (str, FALSE);
229 	} else {
230 		sqlite3_result_null (context);
231 	}
232 
233 	return;
234 }
235 
236 /* Create a title-type string from the filename for replacing missing ones */
237 static void
function_sparql_string_from_filename(sqlite3_context * context,int argc,sqlite3_value * argv[])238 function_sparql_string_from_filename (sqlite3_context *context,
239                                       int              argc,
240                                       sqlite3_value   *argv[])
241 {
242 	const gchar *fn = "fn:string-from-filename";
243 	gchar  *name = NULL;
244 	gchar  *suffix = NULL;
245 
246 	if (argc != 1) {
247 		result_context_function_error (context, fn, "Invalid argument count");
248 		return;
249 	}
250 
251 	/* "/home/user/path/title_of_the_movie.movie" -> "title of the movie"
252 	 * Only for local files currently, do we need to change? */
253 
254 	name = g_filename_display_basename ((gchar *)sqlite3_value_text (argv[0]));
255 
256 	if (!name) {
257 		sqlite3_result_null (context);
258 		return;
259 	}
260 
261 	suffix = g_strrstr (name, ".");
262 
263 	if (suffix) {
264 		*suffix = '\0';
265 	}
266 
267 	g_strdelimit (name, "._", ' ');
268 
269 	sqlite3_result_text (context, name, -1, g_free);
270 }
271 
272 static void
function_sparql_uri_is_parent(sqlite3_context * context,int argc,sqlite3_value * argv[])273 function_sparql_uri_is_parent (sqlite3_context *context,
274                                int              argc,
275                                sqlite3_value   *argv[])
276 {
277 	const gchar *fn = "tracker:uri-is-parent";
278 	const gchar *uri, *parent, *remaining;
279 	gboolean match = FALSE;
280 	guint parent_len;
281 
282 	if (argc != 2) {
283 		result_context_function_error (context, fn, "Invalid argument count");
284 		return;
285 	}
286 
287 	parent = (gchar *)sqlite3_value_text (argv[0]);
288 	uri = (gchar *)sqlite3_value_text (argv[1]);
289 
290 	if (!parent || !uri) {
291 		sqlite3_result_int (context, FALSE);
292 		return;
293 	}
294 
295 	parent_len = sqlite3_value_bytes (argv[0]);
296 
297 	/* Check only one argument, it's going to
298 	 * be compared with the other anyway.
299 	 */
300 
301 	if (!(parent_len >= 7 && (parent[4] == ':' && parent[5] == '/' && parent[6] == '/'))) {
302 		if (strstr (parent, "://") == NULL) {
303 			sqlite3_result_int (context, FALSE);
304 			return;
305 		}
306 	}
307 
308 	/* Remove trailing '/', will
309 	 * be checked later on uri.
310 	 */
311 	while (parent[parent_len - 1] == '/') {
312 		parent_len--;
313 	}
314 
315 	if (strncmp (uri, parent, parent_len) == 0 && uri[parent_len] == '/') {
316 		const gchar *slash;
317 
318 		while (uri[parent_len] == '/') {
319 			parent_len++;
320 		}
321 
322 		remaining = &uri[parent_len];
323 
324 		if (*remaining == '\0') {
325 			/* Exact match, not a child */
326 			match = FALSE;
327 		} else if ((slash = strchr (remaining, '/')) == NULL) {
328 			/* Remaining doesn't have uri
329 			 * separator, it's a direct child.
330 			 */
331 			match = TRUE;
332 		} else {
333 			/* Check it's not trailing slashes */
334 			while (*slash == '/') {
335 				slash++;
336 			}
337 
338 			match = (*slash == '\0');
339 		}
340 	}
341 
342 	sqlite3_result_int (context, match);
343 }
344 
345 static gboolean
check_uri_is_descendant(const gchar * parent,guint parent_len,const gchar * uri)346 check_uri_is_descendant (const gchar *parent,
347                          guint        parent_len,
348                          const gchar *uri)
349 {
350 	const gchar *remaining;
351 	gboolean match = FALSE;
352 
353 	/* Check only one argument, it's going to
354 	 * be compared with the other anyway.
355 	 */
356 
357 	if (!(parent_len >= 7 && (parent[4] == ':' && parent[5] == '/' && parent[6] == '/'))) {
358 		if (strstr (parent, "://") == NULL) {
359 			return FALSE;
360 		}
361 	}
362 
363 	/* Remove trailing '/', will
364 	 * be checked later on uri.
365 	 */
366 	while (parent[parent_len - 1] == '/') {
367 		parent_len--;
368 	}
369 
370 	if (strncmp (uri, parent, parent_len) == 0 && uri[parent_len] == '/') {
371 		while (uri[parent_len] == '/') {
372 			parent_len++;
373 		}
374 
375 		remaining = &uri[parent_len];
376 
377 		if (remaining && *remaining) {
378 			match = TRUE;
379 		}
380 	}
381 
382 	return match;
383 }
384 
385 static void
function_sparql_uri_is_descendant(sqlite3_context * context,int argc,sqlite3_value * argv[])386 function_sparql_uri_is_descendant (sqlite3_context *context,
387                                    int              argc,
388                                    sqlite3_value   *argv[])
389 {
390 	const gchar *fn = "tracker:uri-is-descendant";
391 	const gchar *child;
392 	gboolean match = FALSE;
393 	gint i;
394 
395 	/* fn:uri-is-descendant (parent1, parent2, ..., parentN, child) */
396 
397 	if (argc < 2) {
398 		result_context_function_error (context, fn, "Invalid argument count");
399 		return;
400 	}
401 
402 	for (i = 0; i < argc; i++) {
403 		if (sqlite3_value_type (argv[i]) == SQLITE_NULL) {
404 			sqlite3_result_int (context, FALSE);
405 			return;
406 		} else if (sqlite3_value_type (argv[i]) != SQLITE_TEXT) {
407 			result_context_function_error (context, fn, "Invalid non-text argument");
408 			return;
409 		}
410 	}
411 
412 	child = (gchar *)sqlite3_value_text (argv[argc-1]);
413 
414 	for (i = 0; i < argc - 1 && !match; i++) {
415 		if (sqlite3_value_type (argv[i]) == SQLITE_TEXT) {
416 			const gchar *parent = (gchar *)sqlite3_value_text (argv[i]);
417 			guint parent_len = sqlite3_value_bytes (argv[i]);
418 
419 			if (!parent)
420 				continue;
421 
422 			match = check_uri_is_descendant (parent, parent_len, child);
423 		}
424 	}
425 
426 	sqlite3_result_int (context, match);
427 }
428 
429 static void
function_sparql_format_time(sqlite3_context * context,int argc,sqlite3_value * argv[])430 function_sparql_format_time (sqlite3_context *context,
431                              int              argc,
432                              sqlite3_value   *argv[])
433 {
434 	const gchar *fn = "SparqlFormatTime helper";
435 
436 	if (argc != 1) {
437 		result_context_function_error (context, fn, "Invalid argument count");
438 		return;
439 	}
440 
441 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
442 		sqlite3_result_null (context);
443 		return;
444 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) {
445 		GDateTime *datetime;
446 		gint64 timestamp;
447 
448 		timestamp = sqlite3_value_int64 (argv[0]);
449 		datetime = g_date_time_new_from_unix_utc (timestamp);
450 
451 		if (datetime) {
452 			sqlite3_result_text (context,
453 					     tracker_date_format_iso8601 (datetime),
454 					     -1, g_free);
455 			g_date_time_unref (datetime);
456 		} else {
457 			result_context_function_error (context, fn, "Datetime conversion error");
458 		}
459 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
460 		const gchar *str;
461 
462 		str = sqlite3_value_text (argv[0]);
463 		sqlite3_result_text (context, g_strdup (str), -1, g_free);
464 	} else {
465 		result_context_function_error (context, fn, "Invalid argument type");
466 	}
467 }
468 
469 static void
function_sparql_timestamp(sqlite3_context * context,int argc,sqlite3_value * argv[])470 function_sparql_timestamp (sqlite3_context *context,
471                            int              argc,
472                            sqlite3_value   *argv[])
473 {
474 	const gchar *fn = "SparqlTimestamp helper";
475 
476 	if (argc != 1) {
477 		result_context_function_error (context, fn, "Invalid argument count");
478 		return;
479 	}
480 
481 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
482 		sqlite3_result_null (context);
483 		return;
484 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) {
485 		gdouble seconds;
486 
487 		seconds = sqlite3_value_double (argv[0]);
488 		sqlite3_result_double (context, seconds);
489 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
490 		GError *error = NULL;
491 		GDateTime *datetime;
492 		const gchar *str;
493 
494 		str = sqlite3_value_text (argv[0]);
495 		datetime = tracker_date_new_from_iso8601 (str, &error);
496 		if (error) {
497 			result_context_function_error (context, fn, "Failed time string conversion");
498 			g_error_free (error);
499 			return;
500 		}
501 
502 		sqlite3_result_int64 (context,
503 				      g_date_time_to_unix (datetime) +
504 				      (g_date_time_get_utc_offset (datetime) / G_USEC_PER_SEC));
505 		g_date_time_unref (datetime);
506 	} else {
507 		result_context_function_error (context, fn, "Invalid argument type");
508 	}
509 }
510 
511 static void
function_sparql_time_sort(sqlite3_context * context,int argc,sqlite3_value * argv[])512 function_sparql_time_sort (sqlite3_context *context,
513                            int              argc,
514                            sqlite3_value   *argv[])
515 {
516 	const gchar *fn = "SparqlTimeSort helper";
517 	gint64 sort_key;
518 
519 	if (argc != 1) {
520 		result_context_function_error (context, fn, "Invalid argument count");
521 		return;
522 	}
523 
524 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
525 		sqlite3_result_null (context);
526 		return;
527 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER ||
528 	           sqlite3_value_numeric_type (argv[0]) == SQLITE_FLOAT) {
529 		gdouble value;
530 
531 		value = sqlite3_value_double (argv[0]);
532 		sort_key = (gint64) (value * G_USEC_PER_SEC);
533 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
534 		GDateTime *datetime;
535 		const gchar *value;
536 		GError *error = NULL;
537 
538 		value = sqlite3_value_text (argv[0]);
539 		datetime = tracker_date_new_from_iso8601 (value, &error);
540 		if (error) {
541 			result_context_function_error (context, fn, error->message);
542 			g_error_free (error);
543 			return;
544 		}
545 
546 		sort_key = ((g_date_time_to_unix (datetime) * G_USEC_PER_SEC) +
547 			    g_date_time_get_microsecond (datetime));
548 		g_date_time_unref (datetime);
549 	} else {
550 		result_context_function_error (context, fn, "Invalid argument type");
551 		return;
552 	}
553 
554 	sqlite3_result_int64 (context, sort_key);
555 }
556 
557 static void
function_sparql_time_zone_duration(sqlite3_context * context,int argc,sqlite3_value * argv[])558 function_sparql_time_zone_duration (sqlite3_context *context,
559                                     int              argc,
560                                     sqlite3_value   *argv[])
561 {
562 	const gchar *fn = "timezone-from-dateTime";
563 	if (argc != 1) {
564 		result_context_function_error (context, fn, "Invalid argument count");
565 		return;
566 	}
567 
568 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
569 		sqlite3_result_null (context);
570 		return;
571 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) {
572 		sqlite3_result_int (context, 0);
573 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
574 		GError *error = NULL;
575 		GDateTime *datetime;
576 		const gchar *str;
577 
578 		str = sqlite3_value_text (argv[0]);
579 		datetime = tracker_date_new_from_iso8601 (str, &error);
580 		if (error) {
581 			result_context_function_error (context, fn, "Invalid date");
582 			g_error_free (error);
583 			return;
584 		}
585 
586 		sqlite3_result_int64 (context,
587 				      g_date_time_get_utc_offset (datetime) /
588 				      G_USEC_PER_SEC);
589 		g_date_time_unref (datetime);
590 	} else {
591 		result_context_function_error (context, fn, "Invalid argument type");
592 	}
593 }
594 
595 static void
function_sparql_time_zone_substr(sqlite3_context * context,int argc,sqlite3_value * argv[])596 function_sparql_time_zone_substr (sqlite3_context *context,
597                                   int              argc,
598                                   sqlite3_value   *argv[])
599 {
600 	if (argc != 1) {
601 		sqlite3_result_error (context, "Invalid argument count converting timezone to string", -1);
602 		return;
603 	}
604 
605 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
606 		sqlite3_result_null (context);
607 		return;
608 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) {
609 		sqlite3_result_text (context, "", -1, NULL);
610 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
611 		const gchar *str;
612 		gint len;
613 
614 		str = sqlite3_value_text (argv[0]);
615 		len = strlen (str);
616 
617 		if (g_str_has_suffix (str, "Z")) {
618 			sqlite3_result_text (context, "Z", -1, NULL);
619 		} else if (len > strlen ("0000-00-00T00:00:00Z")) {
620 			const gchar *tz = "";
621 
622 			/* [+-]HHMM */
623 			if (str[len - 5] == '+' || str[len - 5] == '-')
624 				tz = &str[len - 5];
625 			/* [+-]HH:MM */
626 			else if (str[len - 6] == '+' || str[len - 6] == '-')
627 				tz = &str[len - 6];
628 
629 			sqlite3_result_text (context, g_strdup (tz), -1, g_free);
630 		} else {
631 			sqlite3_result_text (context, "", -1, NULL);
632 		}
633 	} else {
634 		sqlite3_result_error (context, "Invalid argument type converting timezone to string", -1);
635 	}
636 }
637 
638 static gchar *
offset_to_duration(gint offset)639 offset_to_duration (gint offset)
640 {
641 	GString *str = g_string_new (NULL);
642 	gint hours, minutes, seconds;
643 
644 	if (offset > 0)
645 		g_string_append (str, "+PT");
646 	else
647 		g_string_append (str, "-PT");
648 
649 	offset = ABS (offset);
650 	hours = offset / 3600;
651 	minutes = offset % 3600 / 60;
652 	seconds = offset % 60;
653 
654 	if (hours > 0)
655 		g_string_append_printf (str, "%dH", hours);
656 	if (minutes > 0)
657 		g_string_append_printf (str, "%dM", minutes);
658 	if (seconds > 0)
659 		g_string_append_printf (str, "%dS", seconds);
660 
661 	return g_string_free (str, FALSE);
662 }
663 
664 static void
function_sparql_time_zone(sqlite3_context * context,int argc,sqlite3_value * argv[])665 function_sparql_time_zone (sqlite3_context *context,
666                            int              argc,
667                            sqlite3_value   *argv[])
668 {
669 	const gchar *fn = "SparqlTimezone helper";
670 
671 	if (argc != 1) {
672 		result_context_function_error (context, fn, "Invalid argument count");
673 		return;
674 	}
675 
676 	if (sqlite3_value_type (argv[0]) == SQLITE_NULL) {
677 		sqlite3_result_null (context);
678 		return;
679 	} else if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) {
680 		sqlite3_result_text (context, "PT0S", -1, NULL);
681 	} else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) {
682 		GError *error = NULL;
683 		GDateTime *datetime;
684 		const gchar *str;
685 		gchar *duration;
686 
687 		str = sqlite3_value_text (argv[0]);
688 		datetime = tracker_date_new_from_iso8601 (str, &error);
689 		if (error) {
690 			result_context_function_error (context, fn, "Invalid date");
691 			g_error_free (error);
692 			return;
693 		}
694 
695 		duration = offset_to_duration (g_date_time_get_utc_offset (datetime) /
696 					       G_USEC_PER_SEC);
697 		sqlite3_result_text (context, g_strdup (duration), -1, g_free);
698 		g_date_time_unref (datetime);
699 	} else {
700 		result_context_function_error (context, fn, "Invalid argument type");
701 	}
702 }
703 
704 static void
function_sparql_cartesian_distance(sqlite3_context * context,int argc,sqlite3_value * argv[])705 function_sparql_cartesian_distance (sqlite3_context *context,
706                                     int              argc,
707                                     sqlite3_value   *argv[])
708 {
709 	const gchar *fn = "tracker:cartesian-distance";
710 
711 	gdouble lat1;
712 	gdouble lat2;
713 	gdouble lon1;
714 	gdouble lon2;
715 
716 	gdouble R;
717 	gdouble a;
718 	gdouble b;
719 	gdouble c;
720 	gdouble d;
721 
722 	if (argc != 4) {
723 		result_context_function_error (context, fn, "Invalid argument count");
724 		return;
725 	}
726 
727 	lat1 = sqlite3_value_double (argv[0])*M_PI/180;
728 	lat2 = sqlite3_value_double (argv[1])*M_PI/180;
729 	lon1 = sqlite3_value_double (argv[2])*M_PI/180;
730 	lon2 = sqlite3_value_double (argv[3])*M_PI/180;
731 
732 	R = 6371000;
733 	a = M_PI/2 - lat1;
734 	b = M_PI/2 - lat2;
735 	c = sqrt(a*a + b*b - 2*a*b*cos(lon2 - lon1));
736 	d = R*c;
737 
738 	sqlite3_result_double (context, d);
739 }
740 
741 static void
function_sparql_haversine_distance(sqlite3_context * context,int argc,sqlite3_value * argv[])742 function_sparql_haversine_distance (sqlite3_context *context,
743                                     int              argc,
744                                     sqlite3_value   *argv[])
745 {
746 	const gchar *fn = "tracker:haversine-distance";
747 
748 	gdouble lat1;
749 	gdouble lat2;
750 	gdouble lon1;
751 	gdouble lon2;
752 
753 	gdouble R;
754 	gdouble dLat;
755 	gdouble dLon;
756 	gdouble a;
757 	gdouble c;
758 	gdouble d;
759 
760 	if (argc != 4) {
761 		result_context_function_error (context, fn, "Invalid argument count");
762 		return;
763 	}
764 
765 	lat1 = sqlite3_value_double (argv[0])*M_PI/180;
766 	lat2 = sqlite3_value_double (argv[1])*M_PI/180;
767 	lon1 = sqlite3_value_double (argv[2])*M_PI/180;
768 	lon2 = sqlite3_value_double (argv[3])*M_PI/180;
769 
770 	R = 6371000;
771 	dLat = (lat2-lat1);
772 	dLon = (lon2-lon1);
773 	a = sin(dLat/2) * sin(dLat/2) + cos(lat1) * cos(lat2) *  sin(dLon/2) * sin(dLon/2);
774 	c = 2 * atan2(sqrt(a), sqrt(1-a));
775 	d = R * c;
776 
777 	sqlite3_result_double (context, d);
778 }
779 
780 static void
function_sparql_regex(sqlite3_context * context,int argc,sqlite3_value * argv[])781 function_sparql_regex (sqlite3_context *context,
782                        int              argc,
783                        sqlite3_value   *argv[])
784 {
785 	const gchar *fn = "fn:matches";
786 	gboolean ret;
787 	const gchar *text, *pattern, *flags = "";
788 	GRegexCompileFlags regex_flags;
789 	GRegex *regex;
790 
791 	if (argc != 2 && argc != 3) {
792 		result_context_function_error (context, fn, "Invalid argument count");
793 		return;
794 	}
795 
796 	regex = sqlite3_get_auxdata (context, 1);
797 
798 	text = (gchar *)sqlite3_value_text (argv[0]);
799 
800 	if (argc == 3)
801 		flags = (gchar *)sqlite3_value_text (argv[2]);
802 
803 	if (regex == NULL) {
804 		gchar *err_str;
805 		GError *error = NULL;
806 
807 		pattern = (gchar *)sqlite3_value_text (argv[1]);
808 
809 		regex_flags = 0;
810 		while (*flags) {
811 			switch (*flags) {
812 			case 's':
813 				regex_flags |= G_REGEX_DOTALL;
814 				break;
815 			case 'm':
816 				regex_flags |= G_REGEX_MULTILINE;
817 				break;
818 			case 'i':
819 				regex_flags |= G_REGEX_CASELESS;
820 				break;
821 			case 'x':
822 				regex_flags |= G_REGEX_EXTENDED;
823 				break;
824 			default:
825 				err_str = g_strdup_printf ("Invalid SPARQL regex flag '%c'", *flags);
826 				result_context_function_error (context, fn, err_str);
827 				g_free (err_str);
828 				return;
829 			}
830 			flags++;
831 		}
832 
833 		regex = g_regex_new (pattern, regex_flags, 0, &error);
834 
835 		if (error) {
836 			result_context_function_error (context, fn, error->message);
837 			g_clear_error (&error);
838 			return;
839 		}
840 
841 		sqlite3_set_auxdata (context, 1, regex, (void (*) (void*)) g_regex_unref);
842 	}
843 
844 	if (text != NULL) {
845 		ret = g_regex_match (regex, text, 0, NULL);
846 	} else {
847 		ret = FALSE;
848 	}
849 
850 	sqlite3_result_int (context, ret);
851 }
852 
853 static void
ensure_replace_checks(TrackerDBInterface * db_interface)854 ensure_replace_checks (TrackerDBInterface *db_interface)
855 {
856 	if (db_interface->replace_func_checks.syntax_check != NULL)
857 		return;
858 
859 	db_interface->replace_func_checks.syntax_check =
860 		g_regex_new ("(?<!\\\\)\\$\\D", G_REGEX_OPTIMIZE, 0, NULL);
861 	db_interface->replace_func_checks.replacement =
862 		g_regex_new("(?<!\\\\)\\$(\\d)", G_REGEX_OPTIMIZE, 0, NULL);
863 	db_interface->replace_func_checks.unescape =
864 		g_regex_new("\\\\\\$", G_REGEX_OPTIMIZE, 0, NULL);
865 }
866 
867 static void
function_sparql_replace(sqlite3_context * context,int argc,sqlite3_value * argv[])868 function_sparql_replace (sqlite3_context *context,
869                          int              argc,
870                          sqlite3_value   *argv[])
871 {
872 	const gchar *fn = "fn:replace";
873 	TrackerDBInterface *db_interface = sqlite3_user_data (context);
874 	TrackerDBReplaceFuncChecks *checks = &db_interface->replace_func_checks;
875 	gboolean store_regex = FALSE, store_replace_regex = FALSE;
876 	const gchar *input, *pattern, *replacement, *flags;
877 	gchar *err_str, *output = NULL, *replaced = NULL, *unescaped = NULL;
878 	GError *error = NULL;
879 	GRegexCompileFlags regex_flags = 0;
880 	GRegex *regex, *replace_regex;
881 	gint capture_count, i;
882 
883 	ensure_replace_checks (db_interface);
884 
885 	if (argc == 3) {
886 		flags = "";
887 	} else if (argc == 4) {
888 		flags = (gchar *)sqlite3_value_text (argv[3]);
889 	} else {
890 		result_context_function_error (context, fn, "Invalid argument count");
891 		return;
892 	}
893 
894 	input = (gchar *)sqlite3_value_text (argv[0]);
895 	regex = sqlite3_get_auxdata (context, 1);
896 	replacement = (gchar *)sqlite3_value_text (argv[2]);
897 
898 	if (regex == NULL) {
899 		pattern = (gchar *)sqlite3_value_text (argv[1]);
900 
901 		for (i = 0; flags[i]; i++) {
902 			switch (flags[i]) {
903 			case 's':
904 				regex_flags |= G_REGEX_DOTALL;
905 				break;
906 			case 'm':
907 				regex_flags |= G_REGEX_MULTILINE;
908 				break;
909 			case 'i':
910 				regex_flags |= G_REGEX_CASELESS;
911 				break;
912 			case 'x':
913 				regex_flags |= G_REGEX_EXTENDED;
914 				break;
915 			default:
916 				err_str = g_strdup_printf ("Invalid SPARQL regex flag '%c'", flags[i]);
917 				result_context_function_error (context, fn, err_str);
918 				g_free (err_str);
919 				return;
920 			}
921 		}
922 
923 		regex = g_regex_new (pattern, regex_flags, 0, &error);
924 
925 		if (error) {
926 			result_context_function_error (context, fn, error->message);
927 			g_clear_error (&error);
928 			return;
929 		}
930 
931 		/* According to the XPath 2.0 standard, an error shall be raised, if the given
932 		 * pattern matches a zero-length string.
933 		 */
934 		if (g_regex_match (regex, "", 0, NULL)) {
935 			err_str = g_strdup_printf ("The given pattern '%s' matches a zero-length string.",
936 			                           pattern);
937 			result_context_function_error (context, fn, err_str);
938 			g_regex_unref (regex);
939 			g_free (err_str);
940 			return;
941 		}
942 
943 		store_regex = TRUE;
944 	}
945 
946 	/* According to the XPath 2.0 standard, an error shall be raised, if all dollar
947 	 * signs ($) of the given replacement string are not immediately followed by
948 	 * a digit 0-9 or not immediately preceded by a \.
949 	 */
950 	if (g_regex_match (checks->syntax_check, replacement, 0, NULL)) {
951 		err_str = g_strdup_printf ("The replacement string '%s' contains a \"$\" character "
952 		                           "that is not immediately followed by a digit 0-9 and "
953 		                           "not immediately preceded by a \"\\\".",
954 		                           replacement);
955 		result_context_function_error (context, fn, err_str);
956 		g_free (err_str);
957 		return;
958 	}
959 
960 	/* According to the XPath 2.0 standard, the dollar sign ($) followed by a number
961 	 * indicates backreferences. GRegex uses the backslash (\) for this purpose.
962 	 * So the ($) backreferences in the given replacement string are replaced by (\)
963 	 * backreferences to support the standard.
964 	 */
965 	capture_count = g_regex_get_capture_count (regex);
966 	replace_regex = sqlite3_get_auxdata (context, 2);
967 
968 	if (capture_count > 9 && !replace_regex) {
969 		gint i;
970 		GString *backref_range;
971 		gchar *regex_interpret;
972 
973 		/* S ... capture_count, N ... the given decimal number.
974 		 * If N>S and N>9, The last digit of N is taken to be a literal character
975 		 * to be included "as is" in the replacement string, and the rules are
976 		 * reapplied using the number N formed by stripping off this last digit.
977 		 */
978 		backref_range = g_string_new ("(");
979 		for (i = 10; i <= capture_count; i++) {
980 			g_string_append_printf (backref_range, "%d|", i);
981 		}
982 
983 		g_string_append (backref_range, "\\d)");
984 		regex_interpret = g_strdup_printf ("(?<!\\\\)\\$%s",
985 		                                   backref_range->str);
986 
987 		replace_regex = g_regex_new (regex_interpret, 0, 0, NULL);
988 
989 		g_string_free (backref_range, TRUE);
990 		g_free (regex_interpret);
991 
992 		store_replace_regex = TRUE;
993 	} else if (capture_count <= 9) {
994 		replace_regex = checks->replacement;
995 	}
996 
997 	replaced = g_regex_replace (replace_regex,
998 	                            replacement, -1, 0, "\\\\g<\\1>", 0, &error);
999 
1000 	if (!error) {
1001 		/* All '\$' pairs are replaced by '$' */
1002 		unescaped = g_regex_replace (checks->unescape,
1003 		                             replaced, -1, 0, "$", 0, &error);
1004 	}
1005 
1006 	if (!error) {
1007 		output = g_regex_replace (regex, input, -1, 0, unescaped, 0, &error);
1008 	}
1009 
1010 	if (error) {
1011 		result_context_function_error (context, fn, error->message);
1012 		g_clear_error (&error);
1013 		return;
1014 	}
1015 
1016 	sqlite3_result_text (context, output, -1, g_free);
1017 
1018 	if (store_replace_regex)
1019 		sqlite3_set_auxdata (context, 2, replace_regex, (GDestroyNotify) g_regex_unref);
1020 	if (store_regex)
1021 		sqlite3_set_auxdata (context, 1, regex, (GDestroyNotify) g_regex_unref);
1022 
1023 	g_free (replaced);
1024 	g_free (unescaped);
1025 }
1026 
1027 #ifdef HAVE_LIBUNISTRING
1028 
1029 static void
function_sparql_lower_case(sqlite3_context * context,int argc,sqlite3_value * argv[])1030 function_sparql_lower_case (sqlite3_context *context,
1031                             int              argc,
1032                             sqlite3_value   *argv[])
1033 {
1034 	const uint16_t *zInput;
1035 	uint16_t *zOutput;
1036 	size_t written = 0;
1037 	int nInput;
1038 
1039 	g_assert (argc == 1);
1040 
1041 	zInput = sqlite3_value_text16 (argv[0]);
1042 
1043 	if (!zInput) {
1044 		return;
1045 	}
1046 
1047 	nInput = sqlite3_value_bytes16 (argv[0]);
1048 
1049 	zOutput = u16_tolower (zInput, nInput/2, NULL, NULL, NULL, &written);
1050 
1051 	sqlite3_result_text16 (context, zOutput, written * 2, free);
1052 }
1053 
1054 static void
function_sparql_upper_case(sqlite3_context * context,int argc,sqlite3_value * argv[])1055 function_sparql_upper_case (sqlite3_context *context,
1056                             int              argc,
1057                             sqlite3_value   *argv[])
1058 {
1059 	const uint16_t *zInput;
1060 	uint16_t *zOutput;
1061 	size_t written = 0;
1062 	int nInput;
1063 
1064 	g_assert (argc == 1);
1065 
1066 	zInput = sqlite3_value_text16 (argv[0]);
1067 
1068 	if (!zInput) {
1069 		return;
1070 	}
1071 
1072 	nInput = sqlite3_value_bytes16 (argv[0]);
1073 
1074 	zOutput = u16_toupper (zInput, nInput / 2, NULL, NULL, NULL, &written);
1075 
1076 	sqlite3_result_text16 (context, zOutput, written * 2, free);
1077 }
1078 
1079 static void
function_sparql_case_fold(sqlite3_context * context,int argc,sqlite3_value * argv[])1080 function_sparql_case_fold (sqlite3_context *context,
1081                            int              argc,
1082                            sqlite3_value   *argv[])
1083 {
1084 	const uint16_t *zInput;
1085 	uint16_t *zOutput;
1086 	size_t written = 0;
1087 	int nInput;
1088 
1089 	g_assert (argc == 1);
1090 
1091 	zInput = sqlite3_value_text16 (argv[0]);
1092 
1093 	if (!zInput) {
1094 		return;
1095 	}
1096 
1097 	nInput = sqlite3_value_bytes16 (argv[0]);
1098 
1099 	zOutput = u16_casefold (zInput, nInput/2, NULL, NULL, NULL, &written);
1100 
1101 	sqlite3_result_text16 (context, zOutput, written * 2, free);
1102 }
1103 
1104 static void
function_sparql_normalize(sqlite3_context * context,int argc,sqlite3_value * argv[])1105 function_sparql_normalize (sqlite3_context *context,
1106                            int              argc,
1107                            sqlite3_value   *argv[])
1108 {
1109 	const gchar *fn = "tracker:normalize";
1110 	const gchar *nfstr;
1111 	const uint16_t *zInput;
1112 	uint16_t *zOutput;
1113 	size_t written = 0;
1114 	int nInput;
1115 	uninorm_t nf;
1116 
1117 	if (argc != 2) {
1118 		result_context_function_error (context, fn, "Invalid argument count");
1119 		return;
1120 	}
1121 
1122 	zInput = sqlite3_value_text16 (argv[0]);
1123 
1124 	if (!zInput) {
1125 		return;
1126 	}
1127 
1128 	nfstr = sqlite3_value_text (argv[1]);
1129 	if (g_ascii_strcasecmp (nfstr, "nfc") == 0)
1130 		nf = UNINORM_NFC;
1131 	else if (g_ascii_strcasecmp (nfstr, "nfd") == 0)
1132 		nf = UNINORM_NFD;
1133 	else if (g_ascii_strcasecmp (nfstr, "nfkc") == 0)
1134 		nf = UNINORM_NFKC;
1135 	else if (g_ascii_strcasecmp (nfstr, "nfkd") == 0)
1136 		nf = UNINORM_NFKD;
1137 	else {
1138 		result_context_function_error (context, fn, "Invalid normalization specified, options are 'nfc', 'nfd', 'nfkc' or 'nfkd'");
1139 		return;
1140 	}
1141 
1142 	nInput = sqlite3_value_bytes16 (argv[0]);
1143 
1144 	zOutput = u16_normalize (nf, zInput, nInput/2, NULL, &written);
1145 
1146 	sqlite3_result_text16 (context, zOutput, written * 2, free);
1147 }
1148 
1149 static void
function_sparql_unaccent(sqlite3_context * context,int argc,sqlite3_value * argv[])1150 function_sparql_unaccent (sqlite3_context *context,
1151                           int              argc,
1152                           sqlite3_value   *argv[])
1153 {
1154 	const gchar *zInput;
1155 	gchar *zOutput;
1156 	gsize written = 0;
1157 	int nInput;
1158 
1159 	g_assert (argc == 1);
1160 
1161 	zInput = sqlite3_value_text (argv[0]);
1162 
1163 	if (!zInput) {
1164 		return;
1165 	}
1166 
1167 	nInput = sqlite3_value_bytes (argv[0]);
1168 
1169 	zOutput = u8_normalize (UNINORM_NFKD, zInput, nInput, NULL, &written);
1170 
1171 	/* Unaccenting is done in place */
1172 	tracker_parser_unaccent_nfkd_string (zOutput, &written);
1173 
1174 	sqlite3_result_text (context, zOutput, written, free);
1175 }
1176 
1177 #elif defined(HAVE_LIBICU)
1178 
1179 static void
function_sparql_lower_case(sqlite3_context * context,int argc,sqlite3_value * argv[])1180 function_sparql_lower_case (sqlite3_context *context,
1181                             int              argc,
1182                             sqlite3_value   *argv[])
1183 {
1184 	const gchar *fn = "fn:lower-case";
1185 	const UChar *zInput;
1186 	UChar *zOutput;
1187 	int nInput;
1188 	int nOutput;
1189 	UErrorCode status = U_ZERO_ERROR;
1190 
1191 	g_assert (argc == 1);
1192 
1193 	zInput = sqlite3_value_text16 (argv[0]);
1194 
1195 	if (!zInput) {
1196 		return;
1197 	}
1198 
1199 	nInput = sqlite3_value_bytes16 (argv[0]);
1200 
1201 	nOutput = nInput * 2 + 2;
1202 	zOutput = sqlite3_malloc (nOutput);
1203 
1204 	if (!zOutput) {
1205 		return;
1206 	}
1207 
1208 	u_strToLower (zOutput, nOutput/2, zInput, nInput/2, NULL, &status);
1209 
1210 	if (!U_SUCCESS (status)){
1211 		char zBuf[128];
1212 		sqlite3_snprintf (128, zBuf, "ICU error: u_strToLower(): %s", u_errorName (status));
1213 		zBuf[127] = '\0';
1214 		sqlite3_free (zOutput);
1215 		result_context_function_error (context, fn, zBuf);
1216 		return;
1217 	}
1218 
1219 	sqlite3_result_text16 (context, zOutput, -1, sqlite3_free);
1220 }
1221 
1222 static void
function_sparql_upper_case(sqlite3_context * context,int argc,sqlite3_value * argv[])1223 function_sparql_upper_case (sqlite3_context *context,
1224                             int              argc,
1225                             sqlite3_value   *argv[])
1226 {
1227 	const gchar *fn = "fn:upper-case";
1228 	const UChar *zInput;
1229 	UChar *zOutput;
1230 	int nInput;
1231 	int nOutput;
1232 	UErrorCode status = U_ZERO_ERROR;
1233 
1234 	g_assert (argc == 1);
1235 
1236 	zInput = sqlite3_value_text16 (argv[0]);
1237 
1238 	if (!zInput) {
1239 		return;
1240 	}
1241 
1242 	nInput = sqlite3_value_bytes16 (argv[0]);
1243 
1244 	nOutput = nInput * 2 + 2;
1245 	zOutput = sqlite3_malloc (nOutput);
1246 
1247 	if (!zOutput) {
1248 		return;
1249 	}
1250 
1251 	u_strToUpper (zOutput, nOutput / 2, zInput, nInput / 2, NULL, &status);
1252 
1253 	if (!U_SUCCESS (status)){
1254 		char zBuf[128];
1255 		sqlite3_snprintf (128, zBuf, "ICU error: u_strToUpper(): %s", u_errorName (status));
1256 		zBuf[127] = '\0';
1257 		sqlite3_free (zOutput);
1258 		result_context_function_error (context, fn, zBuf);
1259 		return;
1260 	}
1261 
1262 	sqlite3_result_text16 (context, zOutput, -1, sqlite3_free);
1263 }
1264 
1265 static void
function_sparql_case_fold(sqlite3_context * context,int argc,sqlite3_value * argv[])1266 function_sparql_case_fold (sqlite3_context *context,
1267                            int              argc,
1268                            sqlite3_value   *argv[])
1269 {
1270 	const gchar *fn = "tracker:case-fold";
1271 	const UChar *zInput;
1272 	UChar *zOutput;
1273 	int nInput;
1274 	int nOutput;
1275 	UErrorCode status = U_ZERO_ERROR;
1276 
1277 	g_assert (argc == 1);
1278 
1279 	zInput = sqlite3_value_text16 (argv[0]);
1280 
1281 	if (!zInput) {
1282 		return;
1283 	}
1284 
1285 	nInput = sqlite3_value_bytes16 (argv[0]);
1286 
1287 	nOutput = nInput * 2 + 2;
1288 	zOutput = sqlite3_malloc (nOutput);
1289 
1290 	if (!zOutput) {
1291 		return;
1292 	}
1293 
1294 	u_strFoldCase (zOutput, nOutput/2, zInput, nInput/2, U_FOLD_CASE_DEFAULT, &status);
1295 
1296 	if (!U_SUCCESS (status)){
1297 		char zBuf[128];
1298 		sqlite3_snprintf (128, zBuf, "ICU error: u_strFoldCase: %s", u_errorName (status));
1299 		zBuf[127] = '\0';
1300 		sqlite3_free (zOutput);
1301 		result_context_function_error (context, fn, zBuf);
1302 		return;
1303 	}
1304 
1305 	sqlite3_result_text16 (context, zOutput, -1, sqlite3_free);
1306 }
1307 
1308 static void
function_sparql_strip_punctuation(sqlite3_context * context,int argc,sqlite3_value * argv[])1309 function_sparql_strip_punctuation (sqlite3_context *context,
1310                                    int              argc,
1311                                    sqlite3_value   *argv[])
1312 {
1313 	const gchar *fn = "tracker:strip-punctuation";
1314 	gchar *input, *replacement = "", *output = NULL;
1315 	GError *error = NULL;
1316 	GRegex *regex;
1317 	input = (gchar *)sqlite3_value_text (argv[0]);
1318 	const gchar *pattern = "\\p{P}";
1319 
1320 	regex = g_regex_new (pattern, 0, 0, &error);
1321 	if (error)
1322 	{
1323 		result_context_function_error (context, fn, error->message);
1324 		g_clear_error (&error);
1325 		return;
1326 	}
1327 
1328 	output = g_regex_replace (regex, input, -1, 0, replacement, 0, &error);
1329 
1330 	sqlite3_result_text (context, output, -1, g_free);
1331 }
1332 
1333 static gunichar2 *
normalize_string(const gunichar2 * string,gsize string_len,const UNormalizer2 * normalizer,gsize * len_out,UErrorCode * status)1334 normalize_string (const gunichar2    *string,
1335                   gsize               string_len, /* In gunichar2s */
1336                   const UNormalizer2 *normalizer,
1337                   gsize              *len_out,    /* In gunichar2s */
1338                   UErrorCode         *status)
1339 {
1340 	int nOutput;
1341 	gunichar2 *zOutput;
1342 
1343 	nOutput = (string_len * 2) + 1;
1344 	zOutput = g_new0 (gunichar2, nOutput);
1345 
1346 	nOutput = unorm2_normalize (normalizer, string, string_len, zOutput, nOutput, status);
1347 
1348 	if (*status == U_BUFFER_OVERFLOW_ERROR) {
1349 		/* Try again after allocating enough space for the normalization */
1350 		*status = U_ZERO_ERROR;
1351 		zOutput = g_renew (gunichar2, zOutput, nOutput);
1352 		memset (zOutput, 0, nOutput * sizeof (gunichar2));
1353 		nOutput = unorm2_normalize (normalizer, string, string_len, zOutput, nOutput, status);
1354 	}
1355 
1356 	if (!U_SUCCESS (*status)) {
1357 		g_clear_pointer (&zOutput, g_free);
1358 		nOutput = 0;
1359 	}
1360 
1361 	if (len_out)
1362 		*len_out = nOutput;
1363 
1364 	return zOutput;
1365 }
1366 
1367 static void
function_sparql_normalize(sqlite3_context * context,int argc,sqlite3_value * argv[])1368 function_sparql_normalize (sqlite3_context *context,
1369                            int              argc,
1370                            sqlite3_value   *argv[])
1371 {
1372 	const gchar *fn = "tracker:normalize";
1373 	const gchar *nfstr;
1374 	const uint16_t *zInput;
1375 	uint16_t *zOutput = NULL;
1376 	int nInput;
1377 	gsize nOutput;
1378 	const UNormalizer2 *normalizer;
1379 	UErrorCode status = U_ZERO_ERROR;
1380 
1381 	if (argc != 2) {
1382 		result_context_function_error (context, fn, "Invalid argument count");
1383 		return;
1384 	}
1385 
1386 	zInput = sqlite3_value_text16 (argv[0]);
1387 
1388 	if (!zInput) {
1389 		return;
1390 	}
1391 
1392 	nfstr = (gchar *)sqlite3_value_text (argv[1]);
1393 	if (g_ascii_strcasecmp (nfstr, "nfc") == 0)
1394 		normalizer = unorm2_getNFCInstance (&status);
1395 	else if (g_ascii_strcasecmp (nfstr, "nfd") == 0)
1396 		normalizer = unorm2_getNFDInstance (&status);
1397 	else if (g_ascii_strcasecmp (nfstr, "nfkc") == 0)
1398 		normalizer = unorm2_getNFKCInstance (&status);
1399 	else if (g_ascii_strcasecmp (nfstr, "nfkd") == 0)
1400 		normalizer = unorm2_getNFKDInstance (&status);
1401 	else {
1402 		result_context_function_error (context, fn, "Invalid normalization specified");
1403 		return;
1404 	}
1405 
1406 	if (U_SUCCESS (status)) {
1407 		nInput = sqlite3_value_bytes16 (argv[0]);
1408 		zOutput = normalize_string (zInput, nInput / 2, normalizer, &nOutput, &status);
1409 	}
1410 
1411 	if (!U_SUCCESS (status)) {
1412 		char zBuf[128];
1413 		sqlite3_snprintf (128, zBuf, "ICU error: unorm_normalize: %s", u_errorName (status));
1414 		zBuf[127] = '\0';
1415 		g_free (zOutput);
1416 		result_context_function_error (context, fn, zBuf);
1417 		return;
1418 	}
1419 
1420 	sqlite3_result_text16 (context, zOutput, nOutput * sizeof (gunichar2), g_free);
1421 }
1422 
1423 static void
function_sparql_unaccent(sqlite3_context * context,int argc,sqlite3_value * argv[])1424 function_sparql_unaccent (sqlite3_context *context,
1425                           int              argc,
1426                           sqlite3_value   *argv[])
1427 {
1428 	const gchar *fn = "tracker:unaccent";
1429 	const uint16_t *zInput;
1430 	uint16_t *zOutput = NULL;
1431 	int nInput;
1432 	gsize nOutput;
1433 	const UNormalizer2 *normalizer;
1434 	UErrorCode status = U_ZERO_ERROR;
1435 
1436 	g_assert (argc == 1);
1437 
1438 	zInput = sqlite3_value_text16 (argv[0]);
1439 
1440 	if (!zInput) {
1441 		return;
1442 	}
1443 
1444 	normalizer = unorm2_getNFKDInstance (&status);
1445 
1446 	if (U_SUCCESS (status)) {
1447 		nInput = sqlite3_value_bytes16 (argv[0]);
1448 		zOutput = normalize_string (zInput, nInput / 2, normalizer, &nOutput, &status);
1449 	}
1450 
1451 	if (!U_SUCCESS (status)) {
1452 		char zBuf[128];
1453 		sqlite3_snprintf (128, zBuf, "ICU error: unorm_normalize: %s", u_errorName (status));
1454 		zBuf[127] = '\0';
1455 		g_free (zOutput);
1456 		result_context_function_error (context, fn, zBuf);
1457 		return;
1458 	}
1459 
1460 	/* Unaccenting is done in place */
1461 	tracker_parser_unaccent_nfkd_string (zOutput, &nOutput);
1462 
1463 	sqlite3_result_text16 (context, zOutput, nOutput * sizeof (gunichar2), g_free);
1464 }
1465 
1466 #endif
1467 
1468 static void
function_sparql_encode_for_uri(sqlite3_context * context,int argc,sqlite3_value * argv[])1469 function_sparql_encode_for_uri (sqlite3_context *context,
1470                                 int              argc,
1471                                 sqlite3_value   *argv[])
1472 {
1473 	const gchar *fn = "fn:encode-for-uri";
1474 	const gchar *str;
1475 	gchar *encoded;
1476 
1477 	if (argc != 1) {
1478 		result_context_function_error (context, fn, "Invalid argument count");
1479 		return;
1480 	}
1481 
1482 	str = (gchar *)sqlite3_value_text (argv[0]);
1483 	encoded = g_uri_escape_string (str, NULL, FALSE);
1484 	sqlite3_result_text (context, encoded, -1, g_free);
1485 }
1486 
1487 static void
function_sparql_uri(sqlite3_context * context,int argc,sqlite3_value * argv[])1488 function_sparql_uri (sqlite3_context *context,
1489                      int              argc,
1490                      sqlite3_value   *argv[])
1491 {
1492 	const gchar *fn = "tracker:uri";
1493 	const gchar *str;
1494 	gchar *encoded;
1495 
1496 	if (argc != 1) {
1497 		result_context_function_error (context, fn, "Invalid argument count");
1498 		return;
1499 	}
1500 
1501 	str = (gchar *)sqlite3_value_text (argv[0]);
1502 	encoded = g_uri_escape_string (str,
1503 	                               G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
1504 	                               FALSE);
1505 	sqlite3_result_text (context, encoded, -1, g_free);
1506 }
1507 
1508 static void
function_sparql_string_before(sqlite3_context * context,int argc,sqlite3_value * argv[])1509 function_sparql_string_before (sqlite3_context *context,
1510                                int              argc,
1511                                sqlite3_value   *argv[])
1512 {
1513 	const gchar *fn = "fn:substring-before";
1514 	const gchar *str, *substr, *loc;
1515 	gint len;
1516 
1517 	if (argc != 2) {
1518 		result_context_function_error (context, fn, "Invalid argument count");
1519 		return;
1520 	}
1521 
1522 	if (sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
1523 	    sqlite3_value_type (argv[1]) != SQLITE_TEXT) {
1524 		result_context_function_error (context, fn, "Invalid argument types");
1525 		return;
1526 	}
1527 
1528 	str = (gchar *)sqlite3_value_text (argv[0]);
1529 	substr = (gchar *)sqlite3_value_text (argv[1]);
1530 	len = strlen (substr);
1531 
1532 	if (len == 0) {
1533 		sqlite3_result_text (context, "", -1, NULL);
1534 		return;
1535 	}
1536 
1537 	loc = strstr (str, substr);
1538 
1539 	if (!loc) {
1540 		sqlite3_result_text (context, "", -1, NULL);
1541 		return;
1542 	}
1543 
1544 	sqlite3_result_text (context, str, loc - str, NULL);
1545 }
1546 
1547 static void
function_sparql_string_after(sqlite3_context * context,int argc,sqlite3_value * argv[])1548 function_sparql_string_after (sqlite3_context *context,
1549                               int              argc,
1550                               sqlite3_value   *argv[])
1551 {
1552 	const gchar *fn = "fn:substring-after";
1553 	const gchar *str, *substr, *loc;
1554 	gint len;
1555 
1556 	if (argc != 2) {
1557 		result_context_function_error (context, fn, "Invalid argument count");
1558 		return;
1559 	}
1560 
1561 	if (sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
1562 	    sqlite3_value_type (argv[1]) != SQLITE_TEXT) {
1563 		result_context_function_error (context, fn, "Invalid argument types");
1564 		return;
1565 	}
1566 
1567 	str = (gchar *)sqlite3_value_text (argv[0]);
1568 	substr = (gchar *)sqlite3_value_text (argv[1]);
1569 	len = strlen (substr);
1570 
1571 	if (len == 0) {
1572 		sqlite3_result_text (context, g_strdup (str), -1, g_free);
1573 		return;
1574 	}
1575 
1576 	loc = strstr (str, substr);
1577 
1578 	if (!loc) {
1579 		sqlite3_result_text (context, "", -1, NULL);
1580 		return;
1581 	}
1582 
1583 	sqlite3_result_text (context, loc + len, -1, NULL);
1584 }
1585 
1586 static void
function_sparql_ceil(sqlite3_context * context,int argc,sqlite3_value * argv[])1587 function_sparql_ceil (sqlite3_context *context,
1588                       int              argc,
1589                       sqlite3_value   *argv[])
1590 {
1591 	const gchar *fn = "fn:numeric-ceil";
1592 	gdouble value;
1593 
1594 	if (argc != 1) {
1595 		result_context_function_error (context, fn, "Invalid argument count");
1596 		return;
1597 	}
1598 
1599 	value = sqlite3_value_double (argv[0]);
1600 	sqlite3_result_double (context, ceil (value));
1601 }
1602 
1603 static void
function_sparql_floor(sqlite3_context * context,int argc,sqlite3_value * argv[])1604 function_sparql_floor (sqlite3_context *context,
1605                        int              argc,
1606                        sqlite3_value   *argv[])
1607 {
1608 	const gchar *fn = "fn:numeric-floor";
1609 	gdouble value;
1610 
1611 	if (argc != 1) {
1612 		result_context_function_error (context, fn, "Invalid argument count");
1613 		return;
1614 	}
1615 
1616 	value = sqlite3_value_double (argv[0]);
1617 	sqlite3_result_double (context, floor (value));
1618 }
1619 
1620 static void
function_sparql_data_type(sqlite3_context * context,int argc,sqlite3_value * argv[])1621 function_sparql_data_type (sqlite3_context *context,
1622                            int              argc,
1623                            sqlite3_value   *argv[])
1624 {
1625 	const gchar *fn = "SparqlDateType helper";
1626 	TrackerPropertyType prop_type;
1627 	const gchar *type = NULL;
1628 
1629 	if (argc != 1) {
1630 		result_context_function_error (context, fn, "Invalid argument count");
1631 		return;
1632 	}
1633 
1634 	prop_type = sqlite3_value_int (argv[0]);
1635 
1636 	switch (prop_type) {
1637 	case TRACKER_PROPERTY_TYPE_UNKNOWN:
1638 		break;
1639 	case TRACKER_PROPERTY_TYPE_STRING:
1640 		type = "http://www.w3.org/2001/XMLSchema#string";
1641 		break;
1642 	case TRACKER_PROPERTY_TYPE_BOOLEAN:
1643 		type = "http://www.w3.org/2001/XMLSchema#boolean";
1644 		break;
1645 	case TRACKER_PROPERTY_TYPE_INTEGER:
1646 		type = "http://www.w3.org/2001/XMLSchema#integer";
1647 		break;
1648 	case TRACKER_PROPERTY_TYPE_DOUBLE:
1649 		type = "http://www.w3.org/2001/XMLSchema#double";
1650 		break;
1651 	case TRACKER_PROPERTY_TYPE_DATE:
1652 		type = "http://www.w3.org/2001/XMLSchema#date";
1653 		break;
1654 	case TRACKER_PROPERTY_TYPE_DATETIME:
1655 		type = "http://www.w3.org/2001/XMLSchema#dateType";
1656 		break;
1657 	case TRACKER_PROPERTY_TYPE_RESOURCE:
1658 		type = "http://www.w3.org/2000/01/rdf-schema#Resource";
1659 		break;
1660 	case TRACKER_PROPERTY_TYPE_LANGSTRING:
1661 		type = "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString";
1662 		break;
1663 	}
1664 
1665 	if (type)
1666 		sqlite3_result_text (context, type, -1, NULL);
1667 	else
1668 		sqlite3_result_null (context);
1669 }
1670 
1671 static void
function_sparql_rand(sqlite3_context * context,int argc,sqlite3_value * argv[])1672 function_sparql_rand (sqlite3_context *context,
1673                       int              argc,
1674                       sqlite3_value   *argv[])
1675 {
1676 	const gchar *fn = "rand";
1677 
1678 	if (argc != 0) {
1679 		result_context_function_error (context, fn, "Invalid argument count");
1680 		return;
1681 	}
1682 
1683 	sqlite3_result_double (context, g_random_double ());
1684 }
1685 
1686 static void
function_sparql_checksum(sqlite3_context * context,int argc,sqlite3_value * argv[])1687 function_sparql_checksum (sqlite3_context *context,
1688                           int              argc,
1689                           sqlite3_value   *argv[])
1690 {
1691 	const gchar *fn = "SparqlCheckSum helper";
1692 	const gchar *str, *checksumstr;
1693 	GChecksumType checksum;
1694 	gchar *result;
1695 
1696 	if (argc != 2) {
1697 		result_context_function_error (context, fn, "Invalid argument count");
1698 		return;
1699 	}
1700 
1701 	str = (gchar *)sqlite3_value_text (argv[0]);
1702 	checksumstr = (gchar *)sqlite3_value_text (argv[1]);
1703 
1704 	if (!str || !checksumstr) {
1705 		result_context_function_error (context, fn, "Invalid arguments");
1706 		return;
1707 	}
1708 
1709 	if (g_ascii_strcasecmp (checksumstr, "md5") == 0)
1710 		checksum = G_CHECKSUM_MD5;
1711 	else if (g_ascii_strcasecmp (checksumstr, "sha1") == 0)
1712 		checksum = G_CHECKSUM_SHA1;
1713 	else if (g_ascii_strcasecmp (checksumstr, "sha256") == 0)
1714 		checksum = G_CHECKSUM_SHA256;
1715 #if GLIB_CHECK_VERSION (2, 51, 0)
1716 	else if (g_ascii_strcasecmp (checksumstr, "sha384") == 0)
1717 		checksum = G_CHECKSUM_SHA384;
1718 #endif
1719 	else if (g_ascii_strcasecmp (checksumstr, "sha512") == 0)
1720 		checksum = G_CHECKSUM_SHA512;
1721 	else {
1722 		result_context_function_error (context, fn, "Invalid checksum method specified");
1723 		return;
1724 	}
1725 
1726 	result = g_compute_checksum_for_string (checksum, str, -1);
1727 	sqlite3_result_text (context, result, -1, g_free);
1728 }
1729 
1730 static void
function_sparql_langmatches(sqlite3_context * context,int argc,sqlite3_value * argv[])1731 function_sparql_langmatches (sqlite3_context *context,
1732                              int              argc,
1733                              sqlite3_value   *argv[])
1734 {
1735 	const gchar *fn = "langMatches";
1736 	const gchar *str, *langtag;
1737 	gint type;
1738 
1739 	if (argc != 2) {
1740 		result_context_function_error (context, fn, "Invalid argument count");
1741 		return;
1742 	}
1743 
1744 	type = sqlite3_value_type (argv[0]);
1745 
1746 	if (type == SQLITE_TEXT) {
1747 		/* text arguments don't contain any language information */
1748 		sqlite3_result_int (context, FALSE);
1749 	} else if (type == SQLITE_BLOB) {
1750 		gint str_len, len;
1751 
1752 		str = sqlite3_value_blob (argv[0]);
1753 		len = sqlite3_value_bytes (argv[0]);
1754 		langtag = sqlite3_value_text (argv[1]);
1755 		str_len = strlen (str) + 1;
1756 
1757 		if (str_len + strlen (langtag) != len ||
1758 		    g_strcmp0 (&str[str_len], langtag) != 0) {
1759 			sqlite3_result_int (context, FALSE);
1760 		} else {
1761 			sqlite3_result_int (context, TRUE);
1762 		}
1763 	} else {
1764 		sqlite3_result_null (context);
1765 	}
1766 }
1767 
1768 static void
function_sparql_strlang(sqlite3_context * context,int argc,sqlite3_value * argv[])1769 function_sparql_strlang (sqlite3_context *context,
1770                          int              argc,
1771                          sqlite3_value   *argv[])
1772 {
1773 	const gchar *fn = "strlang";
1774 	const gchar *str, *langtag;
1775 	GString *langstr;
1776 
1777 	if (argc != 2) {
1778 		result_context_function_error (context, fn, "Invalid argument count");
1779 		return;
1780 	}
1781 
1782 	str = sqlite3_value_text (argv[0]);
1783 	langtag = sqlite3_value_text (argv[1]);
1784 
1785 	langstr = g_string_new (str);
1786 	g_string_append_c (langstr, '\0');
1787 	g_string_append (langstr, langtag);
1788 
1789 	sqlite3_result_blob64 (context, langstr->str,
1790 	                       langstr->len, g_free);
1791 	g_string_free (langstr, FALSE);
1792 }
1793 
1794 static inline int
stmt_step(sqlite3_stmt * stmt)1795 stmt_step (sqlite3_stmt *stmt)
1796 {
1797 	int result;
1798 
1799 	result = sqlite3_step (stmt);
1800 
1801 	/* If the statement expired between preparing it and executing
1802 	 * sqlite3_step(), we are supposed to get SQLITE_SCHEMA error in
1803 	 * sqlite3_errcode(), BUT there seems to be a bug in sqlite and
1804 	 * SQLITE_ABORT is being returned instead for that case. So, the
1805 	 * only way to see if a given statement was expired is to use
1806 	 * sqlite3_expired(stmt), which is marked as DEPRECATED in sqlite.
1807 	 * If found that the statement is expired, we need to reset it
1808 	 * and retry the sqlite3_step().
1809 	 * NOTE, that this expiration may only happen between preparing
1810 	 * the statement and step-ing it, NOT between steps. */
1811 	if ((result == SQLITE_ABORT || result == SQLITE_SCHEMA) &&
1812 	    sqlite3_expired (stmt)) {
1813 		sqlite3_reset (stmt);
1814 		result = sqlite3_step (stmt);
1815 	}
1816 
1817 	return result;
1818 }
1819 
1820 static void
generate_uuid(sqlite3_context * context,const gchar * fn,const gchar * uri_prefix)1821 generate_uuid (sqlite3_context *context,
1822                const gchar     *fn,
1823                const gchar     *uri_prefix)
1824 {
1825 	gchar *uuid = NULL;
1826 	sqlite3_stmt *stmt;
1827 	gboolean store_auxdata = FALSE;
1828 	sqlite3 *db;
1829 	gint result;
1830 
1831 	stmt = sqlite3_get_auxdata (context, 1);
1832 
1833 	if (stmt == NULL) {
1834 		db = sqlite3_context_db_handle (context);
1835 
1836 		result = sqlite3_prepare_v2 (db, "SELECT ID FROM Resource WHERE Uri=?",
1837 		                             -1, &stmt, NULL);
1838 		if (result != SQLITE_OK) {
1839 			result_context_function_error (context, fn, sqlite3_errstr (result));
1840 			return;
1841 		}
1842 
1843 		store_auxdata = TRUE;
1844 	}
1845 
1846 	do {
1847 		g_clear_pointer (&uuid, g_free);
1848 		uuid = tracker_generate_uuid (uri_prefix);
1849 
1850 		sqlite3_reset (stmt);
1851 		sqlite3_bind_text (stmt, 1, uuid, -1, SQLITE_TRANSIENT);
1852 		result = stmt_step (stmt);
1853 	} while (result == SQLITE_ROW);
1854 
1855 	if (store_auxdata) {
1856 		sqlite3_set_auxdata (context, 1, stmt,
1857 		                     (void (*) (void*)) sqlite3_finalize);
1858 	}
1859 
1860 	if (result != SQLITE_DONE) {
1861 		result_context_function_error (context, fn, sqlite3_errstr (result));
1862 		g_free (uuid);
1863 	} else {
1864 		sqlite3_result_text (context, uuid, -1, g_free);
1865 	}
1866 }
1867 
1868 static void
function_sparql_uuid(sqlite3_context * context,int argc,sqlite3_value * argv[])1869 function_sparql_uuid (sqlite3_context *context,
1870                       int              argc,
1871                       sqlite3_value   *argv[])
1872 {
1873 	const gchar *fn = "SparqlUUID helper";
1874 	const gchar *prefix;
1875 
1876 	if (argc > 1) {
1877 		result_context_function_error (context, fn, "Invalid argument count");
1878 		return;
1879 	}
1880 
1881 	prefix = sqlite3_value_text (argv[0]);
1882 	generate_uuid (context, fn, prefix);
1883 }
1884 
1885 static void
function_sparql_bnode(sqlite3_context * context,int argc,sqlite3_value * argv[])1886 function_sparql_bnode (sqlite3_context *context,
1887                        int              argc,
1888                        sqlite3_value   *argv[])
1889 {
1890 	const gchar *fn = "SparlBNODE helper";
1891 
1892 	if (argc > 1) {
1893 		result_context_function_error (context, fn, "Invalid argument count");
1894 		return;
1895 	}
1896 
1897 	generate_uuid (context, fn, "urn:bnode");
1898 }
1899 
1900 static void
function_sparql_print_iri(sqlite3_context * context,int argc,sqlite3_value * argv[])1901 function_sparql_print_iri (sqlite3_context *context,
1902                            int              argc,
1903                            sqlite3_value   *argv[])
1904 {
1905 	const gchar *fn = "PrintIRI helper";
1906 
1907 	if (argc > 1) {
1908 		result_context_function_error (context, fn, "Invalid argument count");
1909 		return;
1910 	}
1911 
1912 	if (sqlite3_value_type (argv[0]) == SQLITE_INTEGER) {
1913 		sqlite3_stmt *stmt;
1914 		gboolean store_auxdata = FALSE;
1915 		sqlite3 *db;
1916 		gint result;
1917 
1918 		stmt = sqlite3_get_auxdata (context, 1);
1919 
1920 		if (stmt == NULL) {
1921 			store_auxdata = TRUE;
1922 			db = sqlite3_context_db_handle (context);
1923 
1924 			result = sqlite3_prepare_v2 (db, "SELECT Uri FROM Resource WHERE ID = ?",
1925 			                             -1, &stmt, NULL);
1926 			if (result != SQLITE_OK) {
1927 				result_context_function_error (context, fn, sqlite3_errstr (result));
1928 				return;
1929 			}
1930 		}
1931 
1932 		sqlite3_reset (stmt);
1933 		sqlite3_bind_value (stmt, 1, argv[0]);
1934 		result = stmt_step (stmt);
1935 
1936 		if (result == SQLITE_DONE) {
1937 			sqlite3_result_null (context);
1938 		} else if (result == SQLITE_ROW) {
1939 			sqlite3_result_value (context, sqlite3_column_value (stmt, 0));
1940 		} else {
1941 			result_context_function_error (context, fn, sqlite3_errstr (result));
1942 		}
1943 
1944 		if (store_auxdata) {
1945 			sqlite3_set_auxdata (context, 1, stmt,
1946 			                     (void (*) (void*)) sqlite3_finalize);
1947 		}
1948 	} else {
1949 		sqlite3_result_value (context, argv[0]);
1950 	}
1951 }
1952 
1953 static int
check_interrupt(void * user_data)1954 check_interrupt (void *user_data)
1955 {
1956 	TrackerDBInterface *db_interface = user_data;
1957 
1958 	return g_cancellable_is_cancelled (db_interface->cancellable) ? 1 : 0;
1959 }
1960 
1961 static void
initialize_functions(TrackerDBInterface * db_interface)1962 initialize_functions (TrackerDBInterface *db_interface)
1963 {
1964 	gint i;
1965 	struct {
1966 		gchar *name;
1967 		int n_args;
1968 		int mods;
1969 		void (*func) (sqlite3_context *, int, sqlite3_value**);
1970 	} functions[] = {
1971 		/* Geolocation */
1972 		{ "SparqlHaversineDistance", 4, SQLITE_ANY | SQLITE_DETERMINISTIC,
1973 		  function_sparql_haversine_distance },
1974 		{ "SparqlCartesianDistance", 4, SQLITE_ANY | SQLITE_DETERMINISTIC,
1975 		  function_sparql_cartesian_distance },
1976 		/* Date/time */
1977 		{ "SparqlFormatTime", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1978 		  function_sparql_format_time },
1979 		{ "SparqlTimestamp", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1980 		  function_sparql_timestamp },
1981 		{ "SparqlTimeSort", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1982 		  function_sparql_time_sort },
1983 		{ "SparqlTimezoneDuration", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1984 		  function_sparql_time_zone_duration },
1985 		{ "SparqlTimezoneString", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1986 		  function_sparql_time_zone_substr },
1987 		{ "SparqlTimezone", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1988 		  function_sparql_time_zone },
1989 		/* Paths and filenames */
1990 		{ "SparqlStringFromFilename", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1991 		  function_sparql_string_from_filename },
1992 		{ "SparqlUriIsParent", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
1993 		  function_sparql_uri_is_parent },
1994 		{ "SparqlUriIsDescendant", -1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1995 		  function_sparql_uri_is_descendant },
1996 		{ "SparqlEncodeForUri", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1997 		  function_sparql_encode_for_uri },
1998 		{ "SparqlUri", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
1999 		  function_sparql_uri },
2000 		/* Strings */
2001 		{ "SparqlRegex", -1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2002 		  function_sparql_regex },
2003 		{ "SparqlStringJoin", -1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2004 		  function_sparql_string_join },
2005 		{ "SparqlLowerCase", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2006 		  function_sparql_lower_case },
2007 		{ "SparqlUpperCase", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2008 		  function_sparql_upper_case },
2009 		{ "SparqlCaseFold", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2010 		  function_sparql_case_fold },
2011 		{"SparqlStripPunctuation", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2012 		 function_sparql_strip_punctuation },
2013 		{ "SparqlNormalize", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2014 		  function_sparql_normalize },
2015 		{ "SparqlUnaccent", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2016 		  function_sparql_unaccent },
2017 		{ "SparqlStringBefore", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2018 		  function_sparql_string_before },
2019 		{ "SparqlStringAfter", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2020 		  function_sparql_string_after },
2021 		{ "SparqlReplace", -1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2022 		  function_sparql_replace },
2023 		{ "SparqlChecksum", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2024 		  function_sparql_checksum },
2025 		{ "SparqlLangMatches", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2026 		  function_sparql_langmatches },
2027 		{ "SparqlStrLang", 2, SQLITE_ANY | SQLITE_DETERMINISTIC,
2028 		  function_sparql_strlang },
2029 		{ "SparqlPrintIRI", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2030 		  function_sparql_print_iri },
2031 		/* Numbers */
2032 		{ "SparqlCeil", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2033 		  function_sparql_ceil },
2034 		{ "SparqlFloor", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2035 		  function_sparql_floor },
2036 		{ "SparqlRand", 0, SQLITE_ANY, function_sparql_rand },
2037 		/* Types */
2038 		{ "SparqlDataType", 1, SQLITE_ANY | SQLITE_DETERMINISTIC,
2039 		  function_sparql_data_type },
2040 		/* UUID */
2041 		{ "SparqlUUID", 1, SQLITE_ANY, function_sparql_uuid },
2042 		{ "SparqlBNODE", -1, SQLITE_ANY | SQLITE_DETERMINISTIC, function_sparql_bnode },
2043 	};
2044 
2045 	for (i = 0; i < G_N_ELEMENTS (functions); i++) {
2046 		sqlite3_create_function (db_interface->db,
2047 		                         functions[i].name, functions[i].n_args,
2048 		                         functions[i].mods, db_interface,
2049 		                         functions[i].func, NULL, NULL);
2050 	}
2051 }
2052 
2053 static inline void
tracker_db_interface_lock(TrackerDBInterface * iface)2054 tracker_db_interface_lock (TrackerDBInterface *iface)
2055 {
2056 	if (iface->flags & TRACKER_DB_INTERFACE_USE_MUTEX)
2057 		g_mutex_lock (&iface->mutex);
2058 }
2059 
2060 static inline void
tracker_db_interface_unlock(TrackerDBInterface * iface)2061 tracker_db_interface_unlock (TrackerDBInterface *iface)
2062 {
2063 	if (iface->flags & TRACKER_DB_INTERFACE_USE_MUTEX)
2064 		g_mutex_unlock (&iface->mutex);
2065 }
2066 
2067 static void
open_database(TrackerDBInterface * db_interface,GError ** error)2068 open_database (TrackerDBInterface  *db_interface,
2069                GError             **error)
2070 {
2071 	int mode;
2072 	int result;
2073 	gchar *uri;
2074 
2075 	g_assert (db_interface->filename != NULL || db_interface->shared_cache_key != NULL);
2076 
2077 	if ((db_interface->flags & TRACKER_DB_INTERFACE_READONLY) == 0) {
2078 		mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
2079 	} else {
2080 		mode = SQLITE_OPEN_READONLY;
2081 	}
2082 
2083 	if ((db_interface->flags & TRACKER_DB_INTERFACE_IN_MEMORY) != 0) {
2084 		mode |= SQLITE_OPEN_MEMORY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_URI;
2085 		uri = g_strdup_printf ("file:%s", db_interface->shared_cache_key);
2086 	} else {
2087 		uri = g_strdup (db_interface->filename);
2088 	}
2089 
2090 	result = sqlite3_open_v2 (uri, &db_interface->db, mode | SQLITE_OPEN_NOMUTEX, NULL);
2091 	g_free (uri);
2092 
2093 	if (result != SQLITE_OK) {
2094 		const gchar *str;
2095 
2096 		str = sqlite3_errstr (result);
2097 		g_set_error (error,
2098 		             TRACKER_DB_INTERFACE_ERROR,
2099 		             TRACKER_DB_OPEN_ERROR,
2100 		             "Could not open sqlite3 database:'%s': %s",
2101 		             db_interface->filename ? db_interface->filename : "memory",
2102 		             str);
2103 		return;
2104 	} else {
2105 		TRACKER_NOTE (SQLITE,
2106 		              g_message ("Opened sqlite3 database:'%s'",
2107 		                         db_interface->filename? db_interface->filename : "memory"));
2108 	}
2109 
2110 	/* Set our unicode collation function */
2111 	tracker_db_interface_sqlite_reset_collator (db_interface);
2112 
2113 	sqlite3_progress_handler (db_interface->db, 100,
2114 	                          check_interrupt, db_interface);
2115 
2116 	initialize_functions (db_interface);
2117 
2118 	sqlite3_extended_result_codes (db_interface->db, 0);
2119 	sqlite3_busy_timeout (db_interface->db, 100000);
2120 
2121 #ifndef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
2122 #warning Using sqlite3_enable_load_extension instead of SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, this is unsafe
2123 	sqlite3_enable_load_extension (db_interface->db, 1);
2124 #else
2125 	sqlite3_db_config (db_interface->db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
2126 #endif
2127 }
2128 
2129 static gboolean
tracker_db_interface_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)2130 tracker_db_interface_initable_init (GInitable     *initable,
2131                                     GCancellable  *cancellable,
2132                                     GError       **error)
2133 {
2134 	TrackerDBInterface *db_iface;
2135 	GError *internal_error = NULL;
2136 
2137 	db_iface = TRACKER_DB_INTERFACE (initable);
2138 
2139 	open_database (db_iface, &internal_error);
2140 
2141 	if (internal_error) {
2142 		g_propagate_error (error, internal_error);
2143 		return FALSE;
2144 	}
2145 
2146 	return TRUE;
2147 }
2148 
2149 static void
tracker_db_interface_initable_iface_init(GInitableIface * iface)2150 tracker_db_interface_initable_iface_init (GInitableIface *iface)
2151 {
2152 	iface->init = tracker_db_interface_initable_init;
2153 }
2154 
2155 static void
tracker_db_interface_sqlite_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2156 tracker_db_interface_sqlite_set_property (GObject       *object,
2157                                           guint          prop_id,
2158                                           const GValue  *value,
2159                                           GParamSpec    *pspec)
2160 {
2161 	TrackerDBInterface *db_iface;
2162 
2163 	db_iface = TRACKER_DB_INTERFACE (object);
2164 
2165 	switch (prop_id) {
2166 	case PROP_FLAGS:
2167 		db_iface->flags = g_value_get_flags (value);
2168 		break;
2169 	case PROP_FILENAME:
2170 		db_iface->filename = g_value_dup_string (value);
2171 		break;
2172 	case PROP_SHARED_CACHE_KEY:
2173 		db_iface->shared_cache_key = g_value_dup_string (value);
2174 		break;
2175 	default:
2176 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2177 	}
2178 }
2179 
2180 static void
tracker_db_interface_sqlite_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2181 tracker_db_interface_sqlite_get_property (GObject    *object,
2182                                           guint       prop_id,
2183                                           GValue     *value,
2184                                           GParamSpec *pspec)
2185 {
2186 	TrackerDBInterface *db_iface;
2187 
2188 	db_iface = TRACKER_DB_INTERFACE (object);
2189 
2190 	switch (prop_id) {
2191 	case PROP_FLAGS:
2192 		g_value_set_flags (value, db_iface->flags);
2193 		break;
2194 	case PROP_FILENAME:
2195 		g_value_set_string (value, db_iface->filename);
2196 		break;
2197 	case PROP_SHARED_CACHE_KEY:
2198 		g_value_set_string (value, db_iface->shared_cache_key);
2199 		break;
2200 	default:
2201 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2202 	}
2203 }
2204 
2205 static void
close_database(TrackerDBInterface * db_interface)2206 close_database (TrackerDBInterface *db_interface)
2207 {
2208 	gint rc;
2209 
2210 	if (db_interface->dynamic_statements) {
2211 		g_hash_table_unref (db_interface->dynamic_statements);
2212 		db_interface->dynamic_statements = NULL;
2213 	}
2214 
2215 	if (db_interface->replace_func_checks.syntax_check)
2216 		g_regex_unref (db_interface->replace_func_checks.syntax_check);
2217 	if (db_interface->replace_func_checks.replacement)
2218 		g_regex_unref (db_interface->replace_func_checks.replacement);
2219 	if (db_interface->replace_func_checks.unescape)
2220 		g_regex_unref (db_interface->replace_func_checks.unescape);
2221 
2222 	if (db_interface->db) {
2223 		rc = sqlite3_close (db_interface->db);
2224 		if (rc != SQLITE_OK) {
2225 			g_warning ("Database closed uncleanly: %s",
2226 				   sqlite3_errstr (rc));
2227 		}
2228 	}
2229 }
2230 
2231 static gchar **
_fts_create_properties(GHashTable * properties)2232 _fts_create_properties (GHashTable *properties)
2233 {
2234 	GHashTableIter iter;
2235 	GPtrArray *cols;
2236 	GList *columns;
2237 	gchar *table;
2238 
2239 	if (g_hash_table_size (properties) == 0) {
2240 		return NULL;
2241 	}
2242 
2243 	g_hash_table_iter_init (&iter, properties);
2244 	cols = g_ptr_array_new ();
2245 
2246 	while (g_hash_table_iter_next (&iter, (gpointer *) &table,
2247 				       (gpointer *) &columns)) {
2248 		while (columns) {
2249 			g_ptr_array_add (cols, g_strdup (columns->data));
2250 			columns = columns->next;
2251 		}
2252 	}
2253 
2254 	g_ptr_array_add (cols, NULL);
2255 
2256 	return (gchar **) g_ptr_array_free (cols, FALSE);
2257 }
2258 
2259 gboolean
tracker_db_interface_sqlite_fts_init(TrackerDBInterface * db_interface,const gchar * database,GHashTable * properties,GHashTable * multivalued,gboolean create,GError ** error)2260 tracker_db_interface_sqlite_fts_init (TrackerDBInterface  *db_interface,
2261                                       const gchar         *database,
2262                                       GHashTable          *properties,
2263                                       GHashTable          *multivalued,
2264                                       gboolean             create,
2265                                       GError             **error)
2266 {
2267 	GError *inner_error = NULL;
2268 	GStrv fts_columns;
2269 
2270 	if (!tracker_fts_init_db (db_interface->db, db_interface,
2271 	                          db_interface->flags, properties, error))
2272 		return FALSE;
2273 
2274 	if (create &&
2275 	    !tracker_fts_create_table (db_interface->db, database, "fts5",
2276 	                               properties, multivalued,
2277 	                               &inner_error)) {
2278 		g_propagate_prefixed_error (error,
2279 		                            inner_error,
2280 		                            "FTS tables creation failed: ");
2281 		return FALSE;
2282 	}
2283 
2284 	fts_columns = _fts_create_properties (properties);
2285 
2286 	if (fts_columns) {
2287 		GString *fts_properties;
2288 		gint i;
2289 
2290 		fts_properties = g_string_new (NULL);
2291 
2292 		for (i = 0; fts_columns[i] != NULL; i++) {
2293 			g_string_append_printf (fts_properties, ", \"%s\"",
2294 			                        fts_columns[i]);
2295 		}
2296 
2297 		g_free (db_interface->fts_properties);
2298 		db_interface->fts_properties = g_string_free (fts_properties,
2299 		                                              FALSE);
2300 		g_strfreev (fts_columns);
2301 	}
2302 
2303 	return TRUE;
2304 }
2305 
2306 gboolean
tracker_db_interface_sqlite_fts_delete_table(TrackerDBInterface * db_interface,const gchar * database,GError ** error)2307 tracker_db_interface_sqlite_fts_delete_table (TrackerDBInterface  *db_interface,
2308                                               const gchar         *database,
2309                                               GError             **error)
2310 {
2311 	return tracker_fts_delete_table (db_interface->db, database, "fts5", error);
2312 }
2313 
2314 gboolean
tracker_db_interface_sqlite_fts_alter_table(TrackerDBInterface * db_interface,const gchar * database,GHashTable * properties,GHashTable * multivalued,GError ** error)2315 tracker_db_interface_sqlite_fts_alter_table (TrackerDBInterface  *db_interface,
2316                                              const gchar         *database,
2317                                              GHashTable          *properties,
2318                                              GHashTable          *multivalued,
2319                                              GError             **error)
2320 {
2321 	return tracker_fts_alter_table (db_interface->db, database, "fts5",
2322 	                                properties, multivalued, error);
2323 }
2324 
2325 static gchar *
tracker_db_interface_sqlite_fts_create_query(TrackerDBInterface * db_interface,const gchar * database,gboolean delete,const gchar ** properties)2326 tracker_db_interface_sqlite_fts_create_query (TrackerDBInterface  *db_interface,
2327                                               const gchar         *database,
2328                                               gboolean             delete,
2329                                               const gchar        **properties)
2330 {
2331 	GString *insert_str, *values_str;
2332 	gint i;
2333 
2334 	insert_str = g_string_new (NULL);
2335 	g_string_append_printf (insert_str, "INSERT INTO \"%s\".fts5 (", database);
2336 	values_str = g_string_new (NULL);
2337 
2338 	if (delete) {
2339 		g_string_append (insert_str, "fts5,");
2340 		g_string_append (values_str, "'delete',");
2341 	}
2342 
2343 	g_string_append (insert_str, "rowid");
2344 	g_string_append (values_str, "?");
2345 
2346 	for (i = 0; properties[i] != NULL; i++) {
2347 		g_string_append_printf (insert_str, ",\"%s\"", properties[i]);
2348 		g_string_append (values_str, ",?");
2349 	}
2350 
2351 	g_string_append_printf (insert_str, ") VALUES (%s)", values_str->str);
2352 	g_string_free (values_str, TRUE);
2353 
2354 	return g_string_free (insert_str, FALSE);
2355 }
2356 
2357 static gchar *
tracker_db_interface_sqlite_fts_create_delete_all_query(TrackerDBInterface * db_interface,const gchar * database)2358 tracker_db_interface_sqlite_fts_create_delete_all_query (TrackerDBInterface *db_interface,
2359                                                          const gchar        *database)
2360 {
2361 	GString *insert_str;
2362 
2363 	insert_str = g_string_new (NULL);
2364 	g_string_append_printf (insert_str,
2365 	                        "INSERT INTO \"%s\".fts5 (fts5, rowid %s) "
2366 	                        "SELECT 'delete', rowid %s FROM \"%s\".fts_view "
2367 	                        "WHERE rowid = ? AND COALESCE(NULL %s) IS NOT NULL",
2368 				database,
2369 	                        db_interface->fts_properties,
2370 	                        db_interface->fts_properties,
2371 	                        database,
2372 				db_interface->fts_properties);
2373 	return g_string_free (insert_str, FALSE);
2374 }
2375 
2376 gboolean
tracker_db_interface_sqlite_fts_update_text(TrackerDBInterface * db_interface,const gchar * database,int id,const gchar ** properties,const gchar ** text)2377 tracker_db_interface_sqlite_fts_update_text (TrackerDBInterface  *db_interface,
2378                                              const gchar         *database,
2379                                              int                  id,
2380                                              const gchar        **properties,
2381                                              const gchar        **text)
2382 {
2383 	TrackerDBStatement *stmt;
2384 	GError *error = NULL;
2385 	gchar *query;
2386 	gint i;
2387 
2388 	query = tracker_db_interface_sqlite_fts_create_query (db_interface,
2389 							      database,
2390 	                                                      FALSE, properties);
2391 	stmt = tracker_db_interface_create_statement (db_interface,
2392 	                                              TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE,
2393 	                                              &error,
2394 	                                              query);
2395 	g_free (query);
2396 
2397         if (!stmt || error) {
2398                 if (error) {
2399                         g_warning ("Could not create FTS insert statement: %s\n",
2400                                    error->message);
2401                         g_error_free (error);
2402                 }
2403                 return FALSE;
2404         }
2405 
2406         tracker_db_statement_bind_int (stmt, 0, id);
2407         for (i = 0; text[i] != NULL; i++) {
2408 	        tracker_db_statement_bind_text (stmt, i + 1, text[i]);
2409         }
2410 
2411         tracker_db_statement_execute (stmt, &error);
2412         g_object_unref (stmt);
2413 
2414         if (error) {
2415                 g_warning ("Could not insert FTS text: %s", error->message);
2416                 g_error_free (error);
2417                 return FALSE;
2418         }
2419 
2420         return TRUE;
2421 }
2422 
2423 gboolean
tracker_db_interface_sqlite_fts_delete_text(TrackerDBInterface * db_interface,const gchar * database,int rowid,const gchar ** properties,const gchar ** old_text)2424 tracker_db_interface_sqlite_fts_delete_text (TrackerDBInterface  *db_interface,
2425                                              const gchar         *database,
2426                                              int                  rowid,
2427                                              const gchar        **properties,
2428                                              const gchar        **old_text)
2429 {
2430 	TrackerDBStatement *stmt;
2431 	GError *error = NULL;
2432 	gchar *query;
2433 	gboolean has_text = FALSE;
2434 	gint i;
2435 
2436 	for (i = 0; old_text[i] != NULL; i++)
2437 		has_text |= old_text[i] && *old_text[i];
2438 
2439 	if (!has_text)
2440 		return TRUE;
2441 
2442 	query = tracker_db_interface_sqlite_fts_create_query (db_interface,
2443 							      database,
2444 	                                                      TRUE, properties);
2445 	stmt = tracker_db_interface_create_statement (db_interface,
2446 	                                              TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE,
2447 	                                              &error,
2448 	                                              query);
2449 	g_free (query);
2450 
2451 	if (!stmt || error) {
2452 		g_warning ("Could not create FTS delete statement: %s",
2453 		           error ? error->message : "No error given");
2454 		g_clear_error (&error);
2455 		return FALSE;
2456 	}
2457 
2458 	tracker_db_statement_bind_int (stmt, 0, rowid);
2459 	for (i = 0; old_text[i] != NULL; i++)
2460 		tracker_db_statement_bind_text (stmt, i + 1, old_text[i]);
2461 
2462 	tracker_db_statement_execute (stmt, &error);
2463 	g_object_unref (stmt);
2464 
2465 	if (error) {
2466 		g_warning ("Could not delete FTS text: %s", error->message);
2467 		g_error_free (error);
2468 		return FALSE;
2469 	}
2470 
2471 	return TRUE;
2472 }
2473 
2474 gboolean
tracker_db_interface_sqlite_fts_delete_id(TrackerDBInterface * db_interface,const gchar * database,int id)2475 tracker_db_interface_sqlite_fts_delete_id (TrackerDBInterface *db_interface,
2476                                            const gchar        *database,
2477                                            int                 id)
2478 {
2479 	TrackerDBStatement *stmt;
2480 	GError *error = NULL;
2481 	gchar *query;
2482 
2483 	query = tracker_db_interface_sqlite_fts_create_delete_all_query (db_interface, database);
2484 	stmt = tracker_db_interface_create_statement (db_interface,
2485 	                                              TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE,
2486 	                                              &error,
2487 	                                              query);
2488 	g_free (query);
2489 
2490 	if (!stmt || error) {
2491 		if (error) {
2492 			g_warning ("Could not create FTS delete statement: %s",
2493 			           error->message);
2494 			g_error_free (error);
2495 		}
2496 		return FALSE;
2497 	}
2498 
2499 	tracker_db_statement_bind_int (stmt, 0, id);
2500 	tracker_db_statement_execute (stmt, &error);
2501 	g_object_unref (stmt);
2502 
2503 	if (error) {
2504 		g_warning ("Could not delete FTS content: %s", error->message);
2505 		g_error_free (error);
2506 		return FALSE;
2507 	}
2508 
2509 	return TRUE;
2510 }
2511 
2512 gboolean
tracker_db_interface_sqlite_fts_rebuild_tokens(TrackerDBInterface * interface,const gchar * database,GError ** error)2513 tracker_db_interface_sqlite_fts_rebuild_tokens (TrackerDBInterface  *interface,
2514                                                 const gchar         *database,
2515                                                 GError             **error)
2516 {
2517 	return tracker_fts_rebuild_tokens (interface->db, database, "fts5", error);
2518 }
2519 
2520 void
tracker_db_interface_sqlite_reset_collator(TrackerDBInterface * db_interface)2521 tracker_db_interface_sqlite_reset_collator (TrackerDBInterface *db_interface)
2522 {
2523 	TRACKER_NOTE (SQLITE, g_message ("Resetting collator in db interface %p", db_interface));
2524 
2525 	/* This will overwrite any other collation set before, if any */
2526 	if (sqlite3_create_collation_v2 (db_interface->db,
2527 	                                 TRACKER_COLLATION_NAME,
2528 	                                 SQLITE_UTF8,
2529 	                                 tracker_collation_init (),
2530 	                                 tracker_collation_utf8,
2531 	                                 tracker_collation_shutdown) != SQLITE_OK)
2532 	{
2533 		g_critical ("Couldn't set collation function: %s",
2534 		            sqlite3_errmsg (db_interface->db));
2535 	}
2536 
2537 	if (sqlite3_create_collation_v2 (db_interface->db,
2538 	                                 TRACKER_TITLE_COLLATION_NAME,
2539 	                                 SQLITE_UTF8,
2540 	                                 tracker_collation_init (),
2541 	                                 tracker_collation_utf8_title,
2542 	                                 tracker_collation_shutdown) != SQLITE_OK) {
2543 		g_critical ("Couldn't set title collation function: %s",
2544 		            sqlite3_errmsg (db_interface->db));
2545 	}
2546 }
2547 
2548 gboolean
tracker_db_interface_sqlite_wal_checkpoint(TrackerDBInterface * interface,gboolean blocking,GError ** error)2549 tracker_db_interface_sqlite_wal_checkpoint (TrackerDBInterface  *interface,
2550                                             gboolean             blocking,
2551                                             GError             **error)
2552 {
2553 	int return_val;
2554 
2555 	TRACKER_NOTE (SQLITE, g_message ("Checkpointing database (%s)...", blocking ? "blocking" : "non-blocking"));
2556 
2557 	return_val = sqlite3_wal_checkpoint_v2 (interface->db, NULL,
2558 	                                        blocking ? SQLITE_CHECKPOINT_FULL : SQLITE_CHECKPOINT_PASSIVE,
2559 	                                        NULL, NULL);
2560 
2561 	if (return_val != SQLITE_OK) {
2562 		g_set_error (error,
2563 		             TRACKER_DB_INTERFACE_ERROR,
2564 		             TRACKER_DB_QUERY_ERROR,
2565 		             "%s", sqlite3_errstr (return_val));
2566 		return FALSE;
2567 	}
2568 
2569 	TRACKER_NOTE (SQLITE, g_message ("Checkpointing complete"));
2570 	return TRUE;
2571 }
2572 
2573 static void
tracker_db_interface_sqlite_finalize(GObject * object)2574 tracker_db_interface_sqlite_finalize (GObject *object)
2575 {
2576 	TrackerDBInterface *db_interface;
2577 
2578 	db_interface = TRACKER_DB_INTERFACE (object);
2579 
2580 	close_database (db_interface);
2581 	g_free (db_interface->fts_properties);
2582 
2583 	TRACKER_NOTE (SQLITE, g_message ("Closed sqlite3 database:'%s'", db_interface->filename));
2584 
2585 	g_free (db_interface->filename);
2586 	g_free (db_interface->shared_cache_key);
2587 
2588 	if (db_interface->user_data && db_interface->user_data_destroy_notify)
2589 		db_interface->user_data_destroy_notify (db_interface->user_data);
2590 
2591 	G_OBJECT_CLASS (tracker_db_interface_parent_class)->finalize (object);
2592 }
2593 
2594 static void
tracker_db_interface_class_init(TrackerDBInterfaceClass * class)2595 tracker_db_interface_class_init (TrackerDBInterfaceClass *class)
2596 {
2597 	GObjectClass *object_class = G_OBJECT_CLASS (class);
2598 
2599 	object_class->set_property = tracker_db_interface_sqlite_set_property;
2600 	object_class->get_property = tracker_db_interface_sqlite_get_property;
2601 	object_class->finalize = tracker_db_interface_sqlite_finalize;
2602 
2603 	g_object_class_install_property (object_class,
2604 	                                 PROP_FILENAME,
2605 	                                 g_param_spec_string ("filename",
2606 	                                                      "DB filename",
2607 	                                                      "DB filename",
2608 	                                                      NULL,
2609 	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
2610 
2611 	g_object_class_install_property (object_class,
2612 	                                 PROP_FLAGS,
2613 	                                 g_param_spec_flags ("flags",
2614 	                                                     "Flags",
2615 	                                                     "Interface flags",
2616 	                                                     TRACKER_TYPE_DB_INTERFACE_FLAGS, 0,
2617 	                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
2618 
2619 	g_object_class_install_property (object_class,
2620 	                                 PROP_SHARED_CACHE_KEY,
2621 	                                 g_param_spec_string ("shared-cache-key",
2622 	                                                      "Shared cache key",
2623 	                                                      "Shared cache key",
2624 	                                                      NULL,
2625 	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
2626 }
2627 
2628 static void
tracker_db_interface_init(TrackerDBInterface * db_interface)2629 tracker_db_interface_init (TrackerDBInterface *db_interface)
2630 {
2631 	db_interface->dynamic_statements = g_hash_table_new_full (g_str_hash, g_str_equal,
2632 	                                                          NULL,
2633 	                                                          (GDestroyNotify) g_object_unref);
2634 }
2635 
2636 void
tracker_db_interface_set_max_stmt_cache_size(TrackerDBInterface * db_interface,TrackerDBStatementCacheType cache_type,guint max_size)2637 tracker_db_interface_set_max_stmt_cache_size (TrackerDBInterface         *db_interface,
2638                                               TrackerDBStatementCacheType cache_type,
2639                                               guint                       max_size)
2640 {
2641 	TrackerDBStatementLru *stmt_lru;
2642 
2643 	if (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE) {
2644 		stmt_lru = &db_interface->update_stmt_lru;
2645 	} else if (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT) {
2646 		stmt_lru = &db_interface->select_stmt_lru;
2647 	} else {
2648 		return;
2649 	}
2650 
2651 	/* Must be larger than 2 to make sense (to have a tail and head) */
2652 	if (max_size > 2) {
2653 		stmt_lru->max = max_size;
2654 	} else {
2655 		stmt_lru->max = 3;
2656 	}
2657 }
2658 
2659 static sqlite3_stmt *
tracker_db_interface_prepare_stmt(TrackerDBInterface * db_interface,const gchar * full_query,GError ** error)2660 tracker_db_interface_prepare_stmt (TrackerDBInterface  *db_interface,
2661                                    const gchar         *full_query,
2662                                    GError             **error)
2663 {
2664 	sqlite3_stmt *sqlite_stmt;
2665 	int retval;
2666 
2667 	retval = sqlite3_prepare_v2 (db_interface->db, full_query, -1, &sqlite_stmt, NULL);
2668 
2669 	if (retval != SQLITE_OK) {
2670 		sqlite_stmt = NULL;
2671 
2672 		if (retval == SQLITE_INTERRUPT) {
2673 			g_set_error (error,
2674 			             TRACKER_DB_INTERFACE_ERROR,
2675 			             TRACKER_DB_INTERRUPTED,
2676 			             "Interrupted");
2677 		} else {
2678 			g_set_error (error,
2679 			             TRACKER_DB_INTERFACE_ERROR,
2680 			             TRACKER_DB_QUERY_ERROR,
2681 			             "%s",
2682 			             sqlite3_errmsg (db_interface->db));
2683 		}
2684 	}
2685 
2686 	return sqlite_stmt;
2687 }
2688 
2689 static TrackerDBStatement *
tracker_db_interface_lru_lookup(TrackerDBInterface * db_interface,TrackerDBStatementCacheType * cache_type,const gchar * full_query)2690 tracker_db_interface_lru_lookup (TrackerDBInterface          *db_interface,
2691                                  TrackerDBStatementCacheType *cache_type,
2692                                  const gchar                 *full_query)
2693 {
2694 	TrackerDBStatement *stmt;
2695 
2696 	g_return_val_if_fail (*cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE ||
2697 	                      *cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT,
2698 	                      NULL);
2699 
2700 	/* There are three kinds of queries:
2701 	 * a) Cached queries: SELECT and UPDATE ones (cache_type)
2702 	 * b) Non-Cached queries: NONE ones (cache_type)
2703 	 * c) Forced Non-Cached: in case of a stmt being already in use, we can't
2704 	 *    reuse it (you can't use two different loops on a sqlite3_stmt, of
2705 	 *    course). This happens with recursive uses of a cursor, for example.
2706 	 */
2707 
2708 	stmt = g_hash_table_lookup (db_interface->dynamic_statements,
2709 	                            full_query);
2710 	if (!stmt) {
2711 		/* Query not in LRU */
2712 		return NULL;
2713 	}
2714 
2715 	/* a) Cached */
2716 
2717 	if (stmt && stmt->stmt_is_owned) {
2718 		/* c) Forced non-cached
2719 		 * prepared statement is owned somewhere else, create new uncached one
2720 		 */
2721 		stmt = NULL;
2722 		/* Make sure to set cache_type here, to avoid replacing
2723 		 * the current statement.
2724 		 */
2725 		*cache_type = TRACKER_DB_STATEMENT_CACHE_TYPE_NONE;
2726 	}
2727 
2728 	return stmt;
2729 }
2730 
2731 static void
tracker_db_interface_lru_insert_unchecked(TrackerDBInterface * db_interface,TrackerDBStatementCacheType cache_type,TrackerDBStatement * stmt)2732 tracker_db_interface_lru_insert_unchecked (TrackerDBInterface          *db_interface,
2733                                            TrackerDBStatementCacheType  cache_type,
2734                                            TrackerDBStatement          *stmt)
2735 {
2736 	TrackerDBStatementLru *stmt_lru;
2737 
2738 	g_return_if_fail (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE ||
2739 	                  cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT);
2740 
2741 	/* LRU holds a reference to the stmt */
2742 	stmt_lru = cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE ?
2743 		&db_interface->update_stmt_lru : &db_interface->select_stmt_lru;
2744 
2745 	/* use replace instead of insert to make sure we store the string that
2746 	 * belongs to the right sqlite statement to ensure the lifetime of the string
2747 	 * matches the statement
2748 	 */
2749 	g_hash_table_replace (db_interface->dynamic_statements,
2750 	                      (gpointer) sqlite3_sql (stmt->stmt),
2751 	                      g_object_ref_sink (stmt));
2752 
2753 	/* So the ring looks a bit like this: *
2754 	 *                                    *
2755 	 *    .--tail  .--head                *
2756 	 *    |        |                      *
2757 	 *  [p-n] -> [p-n] -> [p-n] -> [p-n]  *
2758 	 *    ^                          |    *
2759 	 *    `- [n-p] <- [n-p] <--------'    *
2760 	 *                                    */
2761 
2762 	if (stmt_lru->size == 0) {
2763 		stmt_lru->head = stmt;
2764 		stmt_lru->tail = stmt;
2765 	} else if (stmt_lru->size >= stmt_lru->max) {
2766 		TrackerDBStatement *new_head;
2767 
2768 		/* We reached max-size of the LRU stmt cache. Destroy current
2769 		 * least recently used (stmt_lru.head) and fix the ring. For
2770 		 * that we take out the current head, and close the ring.
2771 		 * Then we assign head->next as new head.
2772 		 */
2773 		new_head = stmt_lru->head->next;
2774 		g_hash_table_remove (db_interface->dynamic_statements,
2775 		                     (gpointer) sqlite3_sql (stmt_lru->head->stmt));
2776 		stmt_lru->size--;
2777 		stmt_lru->head = new_head;
2778 	}
2779 
2780 	/* Set the current stmt (which is always new here) as the new tail
2781 	 * (new most recent used). We insert current stmt between head and
2782 	 * current tail, and we set tail to current stmt.
2783 	 */
2784 	stmt_lru->size++;
2785 	stmt->next = stmt_lru->head;
2786 	stmt_lru->head->prev = stmt;
2787 
2788 	stmt_lru->tail->next = stmt;
2789 	stmt->prev = stmt_lru->tail;
2790 	stmt_lru->tail = stmt;
2791 }
2792 
2793 static void
tracker_db_interface_lru_update(TrackerDBInterface * db_interface,TrackerDBStatementCacheType cache_type,TrackerDBStatement * stmt)2794 tracker_db_interface_lru_update (TrackerDBInterface          *db_interface,
2795                                  TrackerDBStatementCacheType  cache_type,
2796                                  TrackerDBStatement          *stmt)
2797 {
2798 	TrackerDBStatementLru *stmt_lru;
2799 
2800 	g_return_if_fail (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE ||
2801 	                  cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT);
2802 
2803 	stmt_lru = cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE ?
2804 		&db_interface->update_stmt_lru : &db_interface->select_stmt_lru;
2805 
2806 	tracker_db_statement_sqlite_reset (stmt);
2807 
2808 	if (stmt == stmt_lru->head) {
2809 		/* Current stmt is least recently used, shift head and tail
2810 		 * of the ring to efficiently make it most recently used.
2811 		 */
2812 		stmt_lru->head = stmt_lru->head->next;
2813 		stmt_lru->tail = stmt_lru->tail->next;
2814 	} else if (stmt != stmt_lru->tail) {
2815 		/* Current statement isn't most recently used, make it most
2816 		 * recently used now (less efficient way than above).
2817 		 */
2818 
2819 		/* Take stmt out of the list and close the ring */
2820 		stmt->prev->next = stmt->next;
2821 		stmt->next->prev = stmt->prev;
2822 
2823 		/* Put stmt as tail (most recent used) */
2824 		stmt->next = stmt_lru->head;
2825 		stmt_lru->head->prev = stmt;
2826 		stmt->prev = stmt_lru->tail;
2827 		stmt_lru->tail->next = stmt;
2828 		stmt_lru->tail = stmt;
2829 	}
2830 
2831 	/* if (stmt == tail), it's already the most recently used in the
2832 	 * ring, so in this case we do nothing of course */
2833 }
2834 
2835 TrackerDBStatement *
tracker_db_interface_create_statement(TrackerDBInterface * db_interface,TrackerDBStatementCacheType cache_type,GError ** error,const gchar * query)2836 tracker_db_interface_create_statement (TrackerDBInterface           *db_interface,
2837                                        TrackerDBStatementCacheType   cache_type,
2838                                        GError                      **error,
2839                                        const gchar                  *query)
2840 {
2841 	TrackerDBStatement *stmt = NULL;
2842 
2843 	g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (db_interface), NULL);
2844 
2845 	tracker_db_interface_lock (db_interface);
2846 
2847 	if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) {
2848 		stmt = tracker_db_interface_lru_lookup (db_interface, &cache_type,
2849 		                                        query);
2850 	}
2851 
2852 	if (!stmt) {
2853 		sqlite3_stmt *sqlite_stmt;
2854 
2855 		sqlite_stmt = tracker_db_interface_prepare_stmt (db_interface,
2856 		                                                 query,
2857 		                                                 error);
2858 		if (!sqlite_stmt) {
2859 			tracker_db_interface_unlock (db_interface);
2860 			return NULL;
2861 		}
2862 
2863 		stmt = tracker_db_statement_sqlite_new (db_interface,
2864 		                                        sqlite_stmt);
2865 
2866 		if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) {
2867 			tracker_db_interface_lru_insert_unchecked (db_interface,
2868 			                                           cache_type,
2869 			                                           stmt);
2870 		}
2871 	} else if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) {
2872 		tracker_db_interface_lru_update (db_interface, cache_type,
2873 		                                 stmt);
2874 	}
2875 
2876 	stmt->stmt_is_owned = TRUE;
2877 
2878 	tracker_db_interface_unlock (db_interface);
2879 
2880 	return g_object_ref_sink (stmt);
2881 }
2882 
2883 TrackerDBStatement *
tracker_db_interface_create_vstatement(TrackerDBInterface * db_interface,TrackerDBStatementCacheType cache_type,GError ** error,const gchar * query,...)2884 tracker_db_interface_create_vstatement (TrackerDBInterface           *db_interface,
2885                                         TrackerDBStatementCacheType   cache_type,
2886                                         GError                      **error,
2887                                         const gchar                  *query,
2888                                         ...)
2889 {
2890 	TrackerDBStatement *stmt;
2891 	va_list args;
2892 	gchar *full_query;
2893 
2894 	g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (db_interface), NULL);
2895 
2896 	va_start (args, query);
2897 	full_query = g_strdup_vprintf (query, args);
2898 	va_end (args);
2899 
2900 	stmt = tracker_db_interface_create_statement (db_interface, cache_type,
2901 	                                              error, full_query);
2902 	g_free (full_query);
2903 
2904 	return stmt;
2905 }
2906 
2907 static gboolean
execute_stmt(TrackerDBInterface * interface,sqlite3_stmt * stmt,GCancellable * cancellable,GError ** error)2908 execute_stmt (TrackerDBInterface  *interface,
2909               sqlite3_stmt        *stmt,
2910               GCancellable        *cancellable,
2911               GError             **error)
2912 {
2913 	gint result;
2914 
2915 	result = SQLITE_OK;
2916 
2917 	tracker_db_interface_ref_use (interface);
2918 
2919 #ifdef G_ENABLE_DEBUG
2920         if (TRACKER_DEBUG_CHECK (SQL_STATEMENTS)) {
2921 	        gchar *full_query;
2922 
2923 	        full_query = sqlite3_expanded_sql (stmt);
2924 
2925 	        if (full_query) {
2926 		        g_message ("Executing update: '%s'", full_query);
2927 		        sqlite3_free (full_query);
2928 	        } else {
2929 		        g_message ("Executing update: '%s'",
2930 		                   sqlite3_sql (stmt));
2931 	        }
2932         }
2933 #endif
2934 
2935 	while (result == SQLITE_OK  ||
2936 	       result == SQLITE_ROW) {
2937 
2938 		if (g_cancellable_is_cancelled (cancellable)) {
2939 			result = SQLITE_INTERRUPT;
2940 			sqlite3_reset (stmt);
2941 		} else {
2942 			/* only one statement can be active at the same time per interface */
2943 			interface->cancellable = cancellable;
2944 			result = stmt_step (stmt);
2945 
2946 			interface->cancellable = NULL;
2947 		}
2948 
2949 		switch (result) {
2950 		case SQLITE_ERROR:
2951 			sqlite3_reset (stmt);
2952 			break;
2953 		case SQLITE_ROW:
2954 			break;
2955 		default:
2956 			break;
2957 		}
2958 	}
2959 
2960 	tracker_db_interface_unref_use (interface);
2961 
2962 	if (result != SQLITE_DONE) {
2963 		/* This is rather fatal */
2964 		if (errno != ENOSPC &&
2965 		    (sqlite3_errcode (interface->db) == SQLITE_IOERR ||
2966 		     sqlite3_errcode (interface->db) == SQLITE_CORRUPT ||
2967 		     sqlite3_errcode (interface->db) == SQLITE_NOTADB)) {
2968 
2969 			g_critical ("SQLite error: %s (errno: %s)",
2970 			            sqlite3_errmsg (interface->db),
2971 			            g_strerror (errno));
2972 			return FALSE;
2973 		}
2974 
2975 		if (!error) {
2976 			g_warning ("Could not perform SQLite operation, error:%d->'%s'",
2977 			           sqlite3_errcode (interface->db),
2978 			           sqlite3_errmsg (interface->db));
2979 		} else {
2980 			if (result == SQLITE_INTERRUPT) {
2981 				g_set_error (error,
2982 				             TRACKER_DB_INTERFACE_ERROR,
2983 				             TRACKER_DB_INTERRUPTED,
2984 				             "Interrupted");
2985 			} else if (result == SQLITE_CONSTRAINT) {
2986 				g_set_error (error,
2987 				             TRACKER_DB_INTERFACE_ERROR,
2988 				             TRACKER_DB_CONSTRAINT,
2989 				             "Constraint would be broken");
2990 			} else {
2991 				g_set_error (error,
2992 				             TRACKER_DB_INTERFACE_ERROR,
2993 				             errno != ENOSPC ? TRACKER_DB_QUERY_ERROR : TRACKER_DB_NO_SPACE,
2994 				             "%s%s%s%s",
2995 				             sqlite3_errmsg (interface->db),
2996 				             errno != 0 ? " (strerror of errno (not necessarily related): " : "",
2997 				             errno != 0 ? g_strerror (errno) : "",
2998 				             errno != 0 ? ")" : "");
2999 			}
3000 		}
3001 	}
3002 
3003 	return result == SQLITE_DONE;
3004 }
3005 
3006 void
tracker_db_interface_execute_vquery(TrackerDBInterface * db_interface,GError ** error,const gchar * query,va_list args)3007 tracker_db_interface_execute_vquery (TrackerDBInterface  *db_interface,
3008                                      GError             **error,
3009                                      const gchar         *query,
3010                                      va_list              args)
3011 {
3012 	gchar *full_query;
3013 	sqlite3_stmt *stmt;
3014 
3015 	tracker_db_interface_lock (db_interface);
3016 
3017 	full_query = g_strdup_vprintf (query, args);
3018 	stmt = tracker_db_interface_prepare_stmt (db_interface,
3019 	                                          full_query,
3020 	                                          error);
3021 	g_free (full_query);
3022 	if (stmt) {
3023 		execute_stmt (db_interface, stmt, NULL, error);
3024 		sqlite3_finalize (stmt);
3025 	}
3026 
3027 	tracker_db_interface_unlock (db_interface);
3028 }
3029 
3030 TrackerDBInterface *
tracker_db_interface_sqlite_new(const gchar * filename,const gchar * shared_cache_key,TrackerDBInterfaceFlags flags,GError ** error)3031 tracker_db_interface_sqlite_new (const gchar              *filename,
3032                                  const gchar              *shared_cache_key,
3033                                  TrackerDBInterfaceFlags   flags,
3034                                  GError                  **error)
3035 {
3036 	TrackerDBInterface *object;
3037 	GError *internal_error = NULL;
3038 
3039 	object = g_initable_new (TRACKER_TYPE_DB_INTERFACE,
3040 	                         NULL,
3041 	                         &internal_error,
3042 	                         "filename", filename,
3043 	                         "flags", flags,
3044 	                         "shared-cache-key", shared_cache_key,
3045 	                         NULL);
3046 
3047 	if (internal_error) {
3048 		g_propagate_error (error, internal_error);
3049 		return NULL;
3050 	}
3051 
3052 	return object;
3053 }
3054 
3055 gint64
tracker_db_interface_sqlite_get_last_insert_id(TrackerDBInterface * interface)3056 tracker_db_interface_sqlite_get_last_insert_id (TrackerDBInterface *interface)
3057 {
3058 	g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (interface), 0);
3059 
3060 	return (gint64) sqlite3_last_insert_rowid (interface->db);
3061 }
3062 
3063 static void
tracker_db_statement_finalize(GObject * object)3064 tracker_db_statement_finalize (GObject *object)
3065 {
3066 	TrackerDBStatement *stmt;
3067 
3068 	stmt = TRACKER_DB_STATEMENT (object);
3069 
3070 	/* A cursor was still open while we're being finalized, because a cursor
3071 	 * holds its own reference, this means that somebody is unreffing a stmt
3072 	 * too often. We mustn't sqlite3_finalize the priv->stmt in this case,
3073 	 * though. It would crash&burn the cursor. */
3074 
3075 	g_assert (!stmt->stmt_is_used);
3076 
3077 	sqlite3_finalize (stmt->stmt);
3078 
3079 	G_OBJECT_CLASS (tracker_db_statement_parent_class)->finalize (object);
3080 }
3081 
3082 static void
tracker_db_statement_class_init(TrackerDBStatementClass * class)3083 tracker_db_statement_class_init (TrackerDBStatementClass *class)
3084 {
3085 	GObjectClass *object_class = G_OBJECT_CLASS (class);
3086 
3087 	object_class->finalize = tracker_db_statement_finalize;
3088 }
3089 
3090 static TrackerDBStatement *
tracker_db_statement_sqlite_new(TrackerDBInterface * db_interface,sqlite3_stmt * sqlite_stmt)3091 tracker_db_statement_sqlite_new (TrackerDBInterface *db_interface,
3092                                  sqlite3_stmt       *sqlite_stmt)
3093 {
3094 	TrackerDBStatement *stmt;
3095 
3096 	stmt = g_object_new (TRACKER_TYPE_DB_STATEMENT, NULL);
3097 
3098 	stmt->db_interface = db_interface;
3099 	stmt->stmt = sqlite_stmt;
3100 	stmt->stmt_is_used = FALSE;
3101 
3102 	return stmt;
3103 }
3104 
3105 static TrackerDBStatement *
tracker_db_statement_sqlite_grab(TrackerDBStatement * stmt)3106 tracker_db_statement_sqlite_grab (TrackerDBStatement *stmt)
3107 {
3108 	g_assert (!stmt->stmt_is_used);
3109 	g_assert (stmt->stmt_is_owned);
3110 	stmt->stmt_is_used = TRUE;
3111 	g_object_ref (stmt->db_interface);
3112 	return g_object_ref (stmt);
3113 }
3114 
3115 static void
tracker_db_statement_sqlite_release(TrackerDBStatement * stmt)3116 tracker_db_statement_sqlite_release (TrackerDBStatement *stmt)
3117 {
3118 	TrackerDBInterface *iface = stmt->db_interface;
3119 
3120 	g_assert (stmt->stmt_is_owned);
3121 
3122 	stmt->stmt_is_owned = FALSE;
3123 
3124 	if (stmt->stmt_is_used) {
3125 		stmt->stmt_is_used = FALSE;
3126 		tracker_db_statement_sqlite_reset (stmt);
3127 		g_object_unref (stmt);
3128 		g_object_unref (iface);
3129 	}
3130 }
3131 
3132 static void
tracker_db_cursor_close(TrackerDBCursor * cursor)3133 tracker_db_cursor_close (TrackerDBCursor *cursor)
3134 {
3135 	TrackerDBInterface *iface;
3136 
3137 	g_return_if_fail (TRACKER_IS_DB_CURSOR (cursor));
3138 
3139 	if (cursor->ref_stmt == NULL) {
3140 		/* already closed */
3141 		return;
3142 	}
3143 
3144 	iface = cursor->ref_stmt->db_interface;
3145 
3146 	g_object_ref (iface);
3147 
3148 	tracker_db_interface_lock (iface);
3149 	g_clear_pointer (&cursor->ref_stmt, tracker_db_statement_sqlite_release);
3150 	tracker_db_interface_unlock (iface);
3151 
3152 	tracker_db_interface_unref_use (iface);
3153 
3154 	g_object_unref (iface);
3155 }
3156 
3157 static void
tracker_db_cursor_finalize(GObject * object)3158 tracker_db_cursor_finalize (GObject *object)
3159 {
3160 	TrackerDBCursor *cursor;
3161 	int i;
3162 
3163 	cursor = TRACKER_DB_CURSOR (object);
3164 
3165 	tracker_db_cursor_close (cursor);
3166 
3167 	g_free (cursor->types);
3168 
3169 	for (i = 0; i < cursor->n_variable_names; i++) {
3170 		g_free (cursor->variable_names[i]);
3171 	}
3172 	g_free (cursor->variable_names);
3173 
3174 	G_OBJECT_CLASS (tracker_db_cursor_parent_class)->finalize (object);
3175 }
3176 
3177 static void
tracker_db_cursor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)3178 tracker_db_cursor_get_property (GObject    *object,
3179                                 guint       prop_id,
3180                                 GValue     *value,
3181                                 GParamSpec *pspec)
3182 {
3183 	TrackerDBCursor *cursor = TRACKER_DB_CURSOR (object);
3184 	switch (prop_id) {
3185 	case TRACKER_DB_CURSOR_PROP_N_COLUMNS:
3186 		g_value_set_int (value, tracker_db_cursor_get_n_columns (cursor));
3187 		break;
3188 	default:
3189 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3190 	}
3191 }
3192 
3193 static void
tracker_db_cursor_iter_next_thread(GTask * task,gpointer object,gpointer task_data,GCancellable * cancellable)3194 tracker_db_cursor_iter_next_thread (GTask        *task,
3195                                     gpointer      object,
3196                                     gpointer      task_data,
3197                                     GCancellable *cancellable)
3198 {
3199 	/* run in thread */
3200 
3201 	TrackerDBCursor *cursor = object;
3202 	GError *error = NULL;
3203 	gboolean result;
3204 
3205 	result = db_cursor_iter_next (cursor, cancellable, &error);
3206 	if (error) {
3207 		g_task_return_error (task, error);
3208 	} else {
3209 		g_task_return_boolean (task, result);
3210 	}
3211 }
3212 
3213 static void
tracker_db_cursor_iter_next_async(TrackerDBCursor * cursor,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3214 tracker_db_cursor_iter_next_async (TrackerDBCursor     *cursor,
3215                                    GCancellable        *cancellable,
3216                                    GAsyncReadyCallback  callback,
3217                                    gpointer             user_data)
3218 {
3219 	GTask *task;
3220 
3221 	task = g_task_new (G_OBJECT (cursor), cancellable, callback, user_data);
3222 	g_task_run_in_thread (task, tracker_db_cursor_iter_next_thread);
3223 	g_object_unref (task);
3224 }
3225 
3226 static gboolean
tracker_db_cursor_iter_next_finish(TrackerDBCursor * cursor,GAsyncResult * res,GError ** error)3227 tracker_db_cursor_iter_next_finish (TrackerDBCursor  *cursor,
3228                                     GAsyncResult     *res,
3229                                     GError          **error)
3230 {
3231 	return g_task_propagate_boolean (G_TASK (res), error);
3232 }
3233 
3234 static void
tracker_db_cursor_class_init(TrackerDBCursorClass * class)3235 tracker_db_cursor_class_init (TrackerDBCursorClass *class)
3236 {
3237 	GObjectClass *object_class = G_OBJECT_CLASS (class);
3238 	TrackerSparqlCursorClass *sparql_cursor_class = TRACKER_SPARQL_CURSOR_CLASS (class);
3239 
3240 	object_class->finalize = tracker_db_cursor_finalize;
3241 	object_class->get_property = tracker_db_cursor_get_property;
3242 
3243 	sparql_cursor_class->get_value_type = (TrackerSparqlValueType (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_value_type;
3244 	sparql_cursor_class->get_variable_name = (const gchar * (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_variable_name;
3245 	sparql_cursor_class->get_n_columns = (gint (*) (TrackerSparqlCursor *)) tracker_db_cursor_get_n_columns;
3246 	sparql_cursor_class->get_string = (const gchar * (*) (TrackerSparqlCursor *, gint, glong*)) tracker_db_cursor_get_string;
3247 	sparql_cursor_class->next = (gboolean (*) (TrackerSparqlCursor *, GCancellable *, GError **)) tracker_db_cursor_iter_next;
3248 	sparql_cursor_class->next_async = (void (*) (TrackerSparqlCursor *, GCancellable *, GAsyncReadyCallback, gpointer)) tracker_db_cursor_iter_next_async;
3249 	sparql_cursor_class->next_finish = (gboolean (*) (TrackerSparqlCursor *, GAsyncResult *, GError **)) tracker_db_cursor_iter_next_finish;
3250 	sparql_cursor_class->rewind = (void (*) (TrackerSparqlCursor *)) tracker_db_cursor_rewind;
3251 	sparql_cursor_class->close = (void (*) (TrackerSparqlCursor *)) tracker_db_cursor_close;
3252 
3253 	sparql_cursor_class->get_integer = (gint64 (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_int;
3254 	sparql_cursor_class->get_double = (gdouble (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_double;
3255 	sparql_cursor_class->get_boolean = (gboolean (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_boolean;
3256 
3257 	g_object_class_override_property (object_class, TRACKER_DB_CURSOR_PROP_N_COLUMNS, "n-columns");
3258 }
3259 
3260 static TrackerDBCursor *
tracker_db_cursor_sqlite_new(TrackerDBStatement * ref_stmt,TrackerPropertyType * types,gint n_types,const gchar * const * variable_names,gint n_variable_names)3261 tracker_db_cursor_sqlite_new (TrackerDBStatement  *ref_stmt,
3262                               TrackerPropertyType *types,
3263                               gint                 n_types,
3264                               const gchar * const *variable_names,
3265                               gint                 n_variable_names)
3266 {
3267 	TrackerDBCursor *cursor;
3268 	TrackerDBInterface *iface;
3269 
3270 	iface = ref_stmt->db_interface;
3271 	tracker_db_interface_ref_use (iface);
3272 
3273 #ifdef G_ENABLE_DEBUG
3274         if (TRACKER_DEBUG_CHECK (SQL_STATEMENTS)) {
3275 	        gchar *full_query;
3276 
3277 	        full_query = sqlite3_expanded_sql (ref_stmt->stmt);
3278 
3279 	        if (full_query) {
3280 		        g_message ("Executing query: '%s'", full_query);
3281 		        sqlite3_free (full_query);
3282 	        } else {
3283 		        g_message ("Executing query: '%s'",
3284 		                   sqlite3_sql (ref_stmt->stmt));
3285 	        }
3286         }
3287 #endif
3288 
3289 	cursor = g_object_new (TRACKER_TYPE_DB_CURSOR, NULL);
3290 
3291 	cursor->finished = FALSE;
3292 
3293 	cursor->stmt = ref_stmt->stmt;
3294 	cursor->ref_stmt = tracker_db_statement_sqlite_grab (ref_stmt);
3295 
3296 	if (types) {
3297 		gint i;
3298 
3299 		cursor->types = g_new (TrackerPropertyType, n_types);
3300 		cursor->n_types = n_types;
3301 		for (i = 0; i < n_types; i++) {
3302 			cursor->types[i] = types[i];
3303 		}
3304 	}
3305 
3306 	if (variable_names) {
3307 		gint i;
3308 
3309 		cursor->variable_names = g_new (gchar *, n_variable_names);
3310 		cursor->n_variable_names = n_variable_names;
3311 		for (i = 0; i < n_variable_names; i++) {
3312 			cursor->variable_names[i] = g_strdup (variable_names[i]);
3313 		}
3314 	}
3315 
3316 	return cursor;
3317 }
3318 
3319 void
tracker_db_statement_bind_double(TrackerDBStatement * stmt,int index,double value)3320 tracker_db_statement_bind_double (TrackerDBStatement *stmt,
3321                                   int                 index,
3322                                   double              value)
3323 {
3324 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3325 
3326 	g_assert (!stmt->stmt_is_used);
3327 
3328 	tracker_db_interface_lock (stmt->db_interface);
3329 	sqlite3_bind_double (stmt->stmt, index + 1, value);
3330 	tracker_db_interface_unlock (stmt->db_interface);
3331 }
3332 
3333 void
tracker_db_statement_bind_int(TrackerDBStatement * stmt,int index,gint64 value)3334 tracker_db_statement_bind_int (TrackerDBStatement *stmt,
3335                                int                 index,
3336                                gint64              value)
3337 {
3338 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3339 
3340 	g_assert (!stmt->stmt_is_used);
3341 
3342 	tracker_db_interface_lock (stmt->db_interface);
3343 	sqlite3_bind_int64 (stmt->stmt, index + 1, value);
3344 	tracker_db_interface_unlock (stmt->db_interface);
3345 }
3346 
3347 void
tracker_db_statement_bind_null(TrackerDBStatement * stmt,int index)3348 tracker_db_statement_bind_null (TrackerDBStatement *stmt,
3349                                 int                 index)
3350 {
3351 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3352 
3353 	g_assert (!stmt->stmt_is_used);
3354 
3355 	tracker_db_interface_lock (stmt->db_interface);
3356 	sqlite3_bind_null (stmt->stmt, index + 1);
3357 	tracker_db_interface_unlock (stmt->db_interface);
3358 }
3359 
3360 void
tracker_db_statement_bind_text(TrackerDBStatement * stmt,int index,const gchar * value)3361 tracker_db_statement_bind_text (TrackerDBStatement *stmt,
3362                                 int                 index,
3363                                 const gchar        *value)
3364 {
3365 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3366 
3367 	g_assert (!stmt->stmt_is_used);
3368 
3369 	tracker_db_interface_lock (stmt->db_interface);
3370 	sqlite3_bind_text (stmt->stmt, index + 1, value, -1, SQLITE_TRANSIENT);
3371 	tracker_db_interface_unlock (stmt->db_interface);
3372 }
3373 
3374 void
tracker_db_statement_bind_bytes(TrackerDBStatement * stmt,int index,GBytes * value)3375 tracker_db_statement_bind_bytes (TrackerDBStatement         *stmt,
3376                                  int                         index,
3377                                  GBytes                     *value)
3378 {
3379 	gconstpointer data;
3380 	gsize len;
3381 
3382 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3383 
3384 	g_assert (!stmt->stmt_is_used);
3385 
3386 	data = g_bytes_get_data (value, &len);
3387 
3388 	tracker_db_interface_lock (stmt->db_interface);
3389 	sqlite3_bind_blob (stmt->stmt, index + 1, data, len - 1, SQLITE_TRANSIENT);
3390 	tracker_db_interface_unlock (stmt->db_interface);
3391 }
3392 
3393 void
tracker_db_statement_bind_value(TrackerDBStatement * stmt,int index,const GValue * value)3394 tracker_db_statement_bind_value (TrackerDBStatement *stmt,
3395 				 int                 index,
3396 				 const GValue       *value)
3397 {
3398 	GType type;
3399 
3400 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3401 
3402 	g_assert (!stmt->stmt_is_used);
3403 
3404 	tracker_db_interface_lock (stmt->db_interface);
3405 
3406 	type = G_VALUE_TYPE (value);
3407 
3408 	if (type == G_TYPE_INT) {
3409 		sqlite3_bind_int64 (stmt->stmt, index + 1, g_value_get_int (value));
3410 	} else if (type == G_TYPE_INT64) {
3411 		sqlite3_bind_int64 (stmt->stmt, index + 1, g_value_get_int64 (value));
3412 	} else if (type == G_TYPE_DOUBLE) {
3413 		sqlite3_bind_double (stmt->stmt, index + 1, g_value_get_double (value));
3414 	} else if (type == G_TYPE_FLOAT) {
3415 		sqlite3_bind_double (stmt->stmt, index + 1, g_value_get_float (value));
3416 	} else if (type == G_TYPE_STRING) {
3417 		sqlite3_bind_text (stmt->stmt, index + 1,
3418 				   g_value_get_string (value), -1, SQLITE_TRANSIENT);
3419 	} else if (type == G_TYPE_BYTES) {
3420 		GBytes *bytes;
3421 		gconstpointer data;
3422 		gsize len;
3423 
3424 		bytes = g_value_get_boxed (value);
3425 		data = g_bytes_get_data (bytes, &len);
3426 		sqlite3_bind_text (stmt->stmt, index + 1,
3427 		                   data, len, SQLITE_TRANSIENT);
3428 	} else {
3429 		GValue dest = G_VALUE_INIT;
3430 
3431 		g_value_init (&dest, G_TYPE_STRING);
3432 
3433 		if (g_value_transform (value, &dest)) {
3434 			sqlite3_bind_text (stmt->stmt, index + 1,
3435 					   g_value_get_string (&dest), -1, SQLITE_TRANSIENT);
3436 			g_value_unset (&dest);
3437 		} else {
3438 			g_assert_not_reached ();
3439 		}
3440 	}
3441 
3442 	tracker_db_interface_unlock (stmt->db_interface);
3443 }
3444 
3445 void
tracker_db_cursor_rewind(TrackerDBCursor * cursor)3446 tracker_db_cursor_rewind (TrackerDBCursor *cursor)
3447 {
3448 	TrackerDBInterface *iface;
3449 
3450 	g_return_if_fail (TRACKER_IS_DB_CURSOR (cursor));
3451 
3452 	iface = cursor->ref_stmt->db_interface;
3453 
3454 	tracker_db_interface_lock (iface);
3455 
3456 	sqlite3_reset (cursor->stmt);
3457 	cursor->finished = FALSE;
3458 
3459 	tracker_db_interface_unlock (iface);
3460 }
3461 
3462 gboolean
tracker_db_cursor_iter_next(TrackerDBCursor * cursor,GCancellable * cancellable,GError ** error)3463 tracker_db_cursor_iter_next (TrackerDBCursor *cursor,
3464                              GCancellable    *cancellable,
3465                              GError         **error)
3466 {
3467 	if (!cursor) {
3468 		return FALSE;
3469 	}
3470 
3471 	return db_cursor_iter_next (cursor, cancellable, error);
3472 }
3473 
3474 
3475 static gboolean
db_cursor_iter_next(TrackerDBCursor * cursor,GCancellable * cancellable,GError ** error)3476 db_cursor_iter_next (TrackerDBCursor *cursor,
3477                      GCancellable    *cancellable,
3478                      GError         **error)
3479 {
3480 	TrackerDBStatement *stmt = cursor->ref_stmt;
3481 	TrackerDBInterface *iface = stmt->db_interface;
3482 
3483 	if (!cursor->finished) {
3484 		guint result;
3485 
3486 		tracker_db_interface_lock (iface);
3487 
3488 		if (g_cancellable_is_cancelled (cancellable)) {
3489 			result = SQLITE_INTERRUPT;
3490 			sqlite3_reset (cursor->stmt);
3491 		} else {
3492 			/* only one statement can be active at the same time per interface */
3493 			iface->cancellable = cancellable;
3494 			result = stmt_step (cursor->stmt);
3495 			iface->cancellable = NULL;
3496 		}
3497 
3498 		if (result == SQLITE_INTERRUPT) {
3499 			g_set_error (error,
3500 			             TRACKER_DB_INTERFACE_ERROR,
3501 			             TRACKER_DB_INTERRUPTED,
3502 			             "Interrupted");
3503 		} else if (result != SQLITE_ROW && result != SQLITE_DONE) {
3504 			g_set_error (error,
3505 			             TRACKER_DB_INTERFACE_ERROR,
3506 			             TRACKER_DB_QUERY_ERROR,
3507 			             "%s", sqlite3_errmsg (iface->db));
3508 		}
3509 
3510 		cursor->finished = (result != SQLITE_ROW);
3511 
3512 		tracker_db_interface_unlock (iface);
3513 	}
3514 
3515 	return (!cursor->finished);
3516 }
3517 
3518 guint
tracker_db_cursor_get_n_columns(TrackerDBCursor * cursor)3519 tracker_db_cursor_get_n_columns (TrackerDBCursor *cursor)
3520 {
3521 	return sqlite3_column_count (cursor->stmt);
3522 }
3523 
3524 void
tracker_db_cursor_get_value(TrackerDBCursor * cursor,guint column,GValue * value)3525 tracker_db_cursor_get_value (TrackerDBCursor *cursor,
3526                              guint            column,
3527                              GValue          *value)
3528 {
3529 	gint col_type;
3530 
3531 	col_type = sqlite3_column_type (cursor->stmt, column);
3532 
3533 	switch (col_type) {
3534 	case SQLITE_TEXT:
3535 		g_value_init (value, G_TYPE_STRING);
3536 		g_value_set_string (value, (gchar *) sqlite3_column_text (cursor->stmt, column));
3537 		break;
3538 	case SQLITE_INTEGER:
3539 		g_value_init (value, G_TYPE_INT64);
3540 		g_value_set_int64 (value, sqlite3_column_int64 (cursor->stmt, column));
3541 		break;
3542 	case SQLITE_FLOAT:
3543 		g_value_init (value, G_TYPE_DOUBLE);
3544 		g_value_set_double (value, sqlite3_column_double (cursor->stmt, column));
3545 		break;
3546 	case SQLITE_NULL:
3547 		/* just ignore NULLs */
3548 		break;
3549 	default:
3550 		g_critical ("Unknown sqlite3 database column type:%d", col_type);
3551 	}
3552 
3553 }
3554 
3555 gint64
tracker_db_cursor_get_int(TrackerDBCursor * cursor,guint column)3556 tracker_db_cursor_get_int (TrackerDBCursor *cursor,
3557                            guint            column)
3558 {
3559 	TrackerDBInterface *iface;
3560 	gint64 result;
3561 
3562 	iface = cursor->ref_stmt->db_interface;
3563 
3564 	tracker_db_interface_lock (iface);
3565 
3566 	result = (gint64) sqlite3_column_int64 (cursor->stmt, column);
3567 
3568 	tracker_db_interface_unlock (iface);
3569 
3570 	return result;
3571 }
3572 
3573 gdouble
tracker_db_cursor_get_double(TrackerDBCursor * cursor,guint column)3574 tracker_db_cursor_get_double (TrackerDBCursor *cursor,
3575                               guint            column)
3576 {
3577 	TrackerDBInterface *iface;
3578 	gdouble result;
3579 
3580 	iface = cursor->ref_stmt->db_interface;
3581 
3582 	tracker_db_interface_lock (iface);
3583 
3584 	result = (gdouble) sqlite3_column_double (cursor->stmt, column);
3585 
3586 	tracker_db_interface_unlock (iface);
3587 
3588 	return result;
3589 }
3590 
3591 static gboolean
tracker_db_cursor_get_boolean(TrackerSparqlCursor * sparql_cursor,guint column)3592 tracker_db_cursor_get_boolean (TrackerSparqlCursor *sparql_cursor,
3593                                guint                column)
3594 {
3595 	TrackerDBCursor *cursor = (TrackerDBCursor *) sparql_cursor;
3596 	return (g_strcmp0 (tracker_db_cursor_get_string (cursor, column, NULL), "true") == 0);
3597 }
3598 
3599 TrackerSparqlValueType
tracker_db_cursor_get_value_type(TrackerDBCursor * cursor,guint column)3600 tracker_db_cursor_get_value_type (TrackerDBCursor *cursor,
3601                                   guint            column)
3602 {
3603 	TrackerDBInterface *iface;
3604 	gint column_type;
3605 	gint n_columns = sqlite3_column_count (cursor->stmt);
3606 
3607 	g_return_val_if_fail (column < n_columns, TRACKER_SPARQL_VALUE_TYPE_UNBOUND);
3608 
3609 	iface = cursor->ref_stmt->db_interface;
3610 
3611 	tracker_db_interface_lock (iface);
3612 
3613 	column_type = sqlite3_column_type (cursor->stmt, column);
3614 
3615 	tracker_db_interface_unlock (iface);
3616 
3617 	if (column_type == SQLITE_NULL) {
3618 		return TRACKER_SPARQL_VALUE_TYPE_UNBOUND;
3619 	} else if (column < cursor->n_types) {
3620 		switch (cursor->types[column]) {
3621 		case TRACKER_PROPERTY_TYPE_RESOURCE:
3622 			return TRACKER_SPARQL_VALUE_TYPE_URI;
3623 		case TRACKER_PROPERTY_TYPE_INTEGER:
3624 			return TRACKER_SPARQL_VALUE_TYPE_INTEGER;
3625 		case TRACKER_PROPERTY_TYPE_DOUBLE:
3626 			return TRACKER_SPARQL_VALUE_TYPE_DOUBLE;
3627 		case TRACKER_PROPERTY_TYPE_DATETIME:
3628 			return TRACKER_SPARQL_VALUE_TYPE_DATETIME;
3629 		case TRACKER_PROPERTY_TYPE_BOOLEAN:
3630 			return TRACKER_SPARQL_VALUE_TYPE_BOOLEAN;
3631 		default:
3632 			return TRACKER_SPARQL_VALUE_TYPE_STRING;
3633 		}
3634 	} else {
3635 		return TRACKER_SPARQL_VALUE_TYPE_STRING;
3636 	}
3637 }
3638 
3639 const gchar*
tracker_db_cursor_get_variable_name(TrackerDBCursor * cursor,guint column)3640 tracker_db_cursor_get_variable_name (TrackerDBCursor *cursor,
3641                                      guint            column)
3642 {
3643 	TrackerDBInterface *iface;
3644 	const gchar *result;
3645 
3646 	iface = cursor->ref_stmt->db_interface;
3647 
3648 	tracker_db_interface_lock (iface);
3649 
3650 	if (column < cursor->n_variable_names) {
3651 		result = cursor->variable_names[column];
3652 	} else {
3653 		result = sqlite3_column_name (cursor->stmt, column);
3654 	}
3655 
3656 	tracker_db_interface_unlock (iface);
3657 
3658 	return result;
3659 }
3660 
3661 const gchar*
tracker_db_cursor_get_string(TrackerDBCursor * cursor,guint column,glong * length)3662 tracker_db_cursor_get_string (TrackerDBCursor *cursor,
3663                               guint            column,
3664                               glong           *length)
3665 {
3666 	TrackerDBInterface *iface;
3667 	const gchar *result;
3668 
3669 	iface = cursor->ref_stmt->db_interface;
3670 
3671 	tracker_db_interface_lock (iface);
3672 
3673 	if (length) {
3674 		sqlite3_value *val = sqlite3_column_value (cursor->stmt, column);
3675 
3676 		*length = sqlite3_value_bytes (val);
3677 		result = (const gchar *) sqlite3_value_text (val);
3678 	} else {
3679 		result = (const gchar *) sqlite3_column_text (cursor->stmt, column);
3680 	}
3681 
3682 	tracker_db_interface_unlock (iface);
3683 
3684 	return result;
3685 }
3686 
3687 void
tracker_db_statement_execute(TrackerDBStatement * stmt,GError ** error)3688 tracker_db_statement_execute (TrackerDBStatement  *stmt,
3689                               GError             **error)
3690 {
3691 	g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
3692 	g_return_if_fail (!stmt->stmt_is_used);
3693 
3694 	execute_stmt (stmt->db_interface, stmt->stmt, NULL, error);
3695 	tracker_db_statement_sqlite_release (stmt);
3696 }
3697 
3698 TrackerDBCursor *
tracker_db_statement_start_cursor(TrackerDBStatement * stmt,GError ** error)3699 tracker_db_statement_start_cursor (TrackerDBStatement  *stmt,
3700                                    GError             **error)
3701 {
3702 	g_return_val_if_fail (TRACKER_IS_DB_STATEMENT (stmt), NULL);
3703 	g_return_val_if_fail (!stmt->stmt_is_used, NULL);
3704 
3705 	return tracker_db_cursor_sqlite_new (stmt, NULL, 0, NULL, 0);
3706 }
3707 
3708 TrackerDBCursor *
tracker_db_statement_start_sparql_cursor(TrackerDBStatement * stmt,TrackerPropertyType * types,gint n_types,const gchar * const * variable_names,gint n_variable_names,GError ** error)3709 tracker_db_statement_start_sparql_cursor (TrackerDBStatement   *stmt,
3710                                           TrackerPropertyType  *types,
3711                                           gint                  n_types,
3712                                           const gchar * const  *variable_names,
3713                                           gint                  n_variable_names,
3714                                           GError              **error)
3715 {
3716 	g_return_val_if_fail (TRACKER_IS_DB_STATEMENT (stmt), NULL);
3717 	g_return_val_if_fail (!stmt->stmt_is_used, NULL);
3718 
3719 	return tracker_db_cursor_sqlite_new (stmt, types, n_types, variable_names, n_variable_names);
3720 }
3721 
3722 static void
tracker_db_statement_init(TrackerDBStatement * stmt)3723 tracker_db_statement_init (TrackerDBStatement *stmt)
3724 {
3725 }
3726 
3727 static void
tracker_db_cursor_init(TrackerDBCursor * cursor)3728 tracker_db_cursor_init (TrackerDBCursor *cursor)
3729 {
3730 }
3731 
3732 static void
tracker_db_statement_sqlite_reset(TrackerDBStatement * stmt)3733 tracker_db_statement_sqlite_reset (TrackerDBStatement *stmt)
3734 {
3735 	g_assert (!stmt->stmt_is_used);
3736 
3737 	sqlite3_reset (stmt->stmt);
3738 	sqlite3_clear_bindings (stmt->stmt);
3739 }
3740 
3741 
3742 void
tracker_db_interface_set_user_data(TrackerDBInterface * db_interface,gpointer user_data,GDestroyNotify destroy_notify)3743 tracker_db_interface_set_user_data (TrackerDBInterface *db_interface,
3744                                     gpointer            user_data,
3745                                     GDestroyNotify      destroy_notify)
3746 {
3747 	if (db_interface->user_data && db_interface->user_data_destroy_notify)
3748 		db_interface->user_data_destroy_notify (db_interface->user_data);
3749 
3750 	db_interface->user_data = user_data;
3751 	db_interface->user_data_destroy_notify = destroy_notify;
3752 }
3753 
3754 gpointer
tracker_db_interface_get_user_data(TrackerDBInterface * db_interface)3755 tracker_db_interface_get_user_data (TrackerDBInterface *db_interface)
3756 {
3757 	return db_interface->user_data;
3758 }
3759 
3760 void
tracker_db_interface_ref_use(TrackerDBInterface * db_interface)3761 tracker_db_interface_ref_use (TrackerDBInterface *db_interface)
3762 {
3763 	g_atomic_int_inc (&db_interface->n_users);
3764 }
3765 
3766 gboolean
tracker_db_interface_unref_use(TrackerDBInterface * db_interface)3767 tracker_db_interface_unref_use (TrackerDBInterface *db_interface)
3768 {
3769 	return g_atomic_int_dec_and_test (&db_interface->n_users);
3770 }
3771 
3772 gboolean
tracker_db_interface_get_is_used(TrackerDBInterface * db_interface)3773 tracker_db_interface_get_is_used (TrackerDBInterface *db_interface)
3774 {
3775 	return g_atomic_int_get (&db_interface->n_users) > 0;
3776 }
3777 
3778 gboolean
tracker_db_interface_init_vtabs(TrackerDBInterface * db_interface,gpointer vtab_data)3779 tracker_db_interface_init_vtabs (TrackerDBInterface *db_interface,
3780                                  gpointer            vtab_data)
3781 {
3782 	tracker_vtab_triples_init (db_interface->db, vtab_data);
3783 	tracker_vtab_service_init (db_interface->db, vtab_data);
3784 	return TRUE;
3785 }
3786 
3787 gboolean
tracker_db_interface_attach_database(TrackerDBInterface * db_interface,GFile * file,const gchar * name,GError ** error)3788 tracker_db_interface_attach_database (TrackerDBInterface  *db_interface,
3789                                       GFile               *file,
3790                                       const gchar         *name,
3791                                       GError             **error)
3792 {
3793 	gchar *sql, *uri = NULL;
3794 	sqlite3_stmt *stmt;
3795 	gboolean retval;
3796 
3797 	g_return_val_if_fail (file || db_interface->shared_cache_key, FALSE);
3798 
3799 	if (file) {
3800 		uri = g_file_get_path (file);
3801 	} else if (db_interface->shared_cache_key &&
3802 	           (db_interface->flags & TRACKER_DB_INTERFACE_IN_MEMORY) != 0) {
3803 		gchar *md5;
3804 
3805 		md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, name, -1);
3806 		uri = g_strdup_printf ("file:%s-%s?mode=memory&cache=shared",
3807 		                       db_interface->shared_cache_key, md5);
3808 		g_free (md5);
3809 	}
3810 
3811 	sql = g_strdup_printf ("ATTACH DATABASE \"%s\" AS \"%s\"",
3812 	                       uri, name);
3813 	g_free (uri);
3814 
3815 	stmt = tracker_db_interface_prepare_stmt (db_interface, sql, error);
3816 	g_free (sql);
3817 	if (!stmt)
3818 		return FALSE;
3819 
3820 	retval = execute_stmt (db_interface, stmt, NULL, error);
3821 	sqlite3_finalize (stmt);
3822 	return retval;
3823 }
3824 
3825 gboolean
tracker_db_interface_detach_database(TrackerDBInterface * db_interface,const gchar * name,GError ** error)3826 tracker_db_interface_detach_database (TrackerDBInterface  *db_interface,
3827                                       const gchar         *name,
3828                                       GError             **error)
3829 {
3830 	sqlite3_stmt *stmt;
3831 	gboolean retval;
3832 	gchar *sql;
3833 
3834 	sql = g_strdup_printf ("DETACH DATABASE \"%s\"", name);
3835 	stmt = tracker_db_interface_prepare_stmt (db_interface, sql, error);
3836 	g_free (sql);
3837 
3838 	if (!stmt)
3839 		return FALSE;
3840 
3841 	retval = execute_stmt (db_interface, stmt, NULL, error);
3842 	sqlite3_finalize (stmt);
3843 	return retval;
3844 }
3845 
3846 gssize
tracker_db_interface_sqlite_release_memory(TrackerDBInterface * db_interface)3847 tracker_db_interface_sqlite_release_memory (TrackerDBInterface *db_interface)
3848 {
3849 	db_interface->select_stmt_lru.head = db_interface->select_stmt_lru.tail = NULL;
3850 	db_interface->select_stmt_lru.size = 0;
3851 	db_interface->update_stmt_lru.head = db_interface->update_stmt_lru.tail = NULL;
3852 	db_interface->update_stmt_lru.size = 0;
3853 	g_hash_table_remove_all (db_interface->dynamic_statements);
3854 
3855 	return (gssize) sqlite3_db_release_memory (db_interface->db);
3856 }
3857