tracker-0.16.2/src/libtracker-data/tracker-db-interface-sqlite.c

Location Tool Test ID Function Issue
tracker-db-interface-sqlite.c:195:12 gcc pointer-sign function_sparql_string_join pointer targets in assignment differ in signedness
tracker-db-interface-sqlite.c:238:2 gcc pointer-sign function_sparql_string_from_filename pointer targets in passing argument 1 of 'g_filename_display_basename' differ in signedness
tracker-db-interface-sqlite.c:270:9 gcc pointer-sign function_sparql_uri_is_parent pointer targets in assignment differ in signedness
tracker-db-interface-sqlite.c:394:8 gcc pointer-sign function_sparql_uri_is_descendant pointer targets in assignment differ in signedness
tracker-db-interface-sqlite.c:524:7 gcc pointer-sign function_sparql_regex pointer targets in assignment differ in signedness
   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-locale.h>
  31 
  32 #include <libtracker-sparql/tracker-sparql.h>
  33 
  34 #if HAVE_TRACKER_FTS
  35 #include <libtracker-fts/tracker-fts.h>
  36 #endif
  37 
  38 #ifdef HAVE_LIBUNISTRING
  39 /* libunistring versions prior to 9.1.2 need this hack */
  40 #define _UNUSED_PARAMETER_
  41 #include <unistr.h>
  42 #include <unicase.h>
  43 #elif HAVE_LIBICU
  44 #include <unicode/utypes.h>
  45 #include <unicode/uregex.h>
  46 #include <unicode/ustring.h>
  47 #include <unicode/ucol.h>
  48 #endif
  49 
  50 #include "tracker-collation.h"
  51 
  52 #include "tracker-db-interface-sqlite.h"
  53 #include "tracker-db-manager.h"
  54 
  55 /* Since 2.30, g_atomic_int_add() is fully equivalente to g_atomic_int_exchange_and_add() */
  56 #if GLIB_CHECK_VERSION (2,30,0)
  57 #define ATOMIC_EXCHANGE_AND_ADD(a,v) g_atomic_int_add (a,v)
  58 #else
  59 #define ATOMIC_EXCHANGE_AND_ADD(a,v) g_atomic_int_exchange_and_add (a,v)
  60 #endif
  61 
  62 #define UNKNOWN_STATUS 0.5
  63 
  64 typedef struct {
  65 	TrackerDBStatement *head;
  66 	TrackerDBStatement *tail;
  67 	guint size;
  68 	guint max;
  69 } TrackerDBStatementLru;
  70 
  71 struct TrackerDBInterface {
  72 	GObject parent_instance;
  73 
  74 	gchar *filename;
  75 	sqlite3 *db;
  76 
  77 	GHashTable *dynamic_statements;
  78 
  79 	GSList *function_data;
  80 
  81 	/* Collation and locale change */
  82 	gpointer locale_notification_id;
  83 	gint collator_reset_requested;
  84 
  85 	/* Number of active cursors */
  86 	gint n_active_cursors;
  87 
  88 	guint ro : 1;
  89 	GCancellable *cancellable;
  90 
  91 	TrackerDBStatementLru select_stmt_lru;
  92 	TrackerDBStatementLru update_stmt_lru;
  93 
  94 	TrackerBusyCallback busy_callback;
  95 	gpointer busy_user_data;
  96 	gchar *busy_status;
  97 
  98 	gchar *fts_insert_str;
  99 };
 100 
 101 struct TrackerDBInterfaceClass {
 102 	GObjectClass parent_class;
 103 };
 104 
 105 struct TrackerDBCursor {
 106 	TrackerSparqlCursor parent_instance;
 107 	sqlite3_stmt *stmt;
 108 	TrackerDBStatement *ref_stmt;
 109 	gboolean finished;
 110 	TrackerPropertyType *types;
 111 	gint n_types;
 112 	gchar **variable_names;
 113 	gint n_variable_names;
 114 
 115 	/* used for direct access as libtracker-sparql is thread-safe and
 116 	   uses a single shared connection with SQLite mutex disabled */
 117 	gboolean threadsafe;
 118 };
 119 
 120 struct TrackerDBCursorClass {
 121 	TrackerSparqlCursorClass parent_class;
 122 };
 123 
 124 struct TrackerDBStatement {
 125 	GObject parent_instance;
 126 	TrackerDBInterface *db_interface;
 127 	sqlite3_stmt *stmt;
 128 	gboolean stmt_is_sunk;
 129 	TrackerDBStatement *next;
 130 	TrackerDBStatement *prev;
 131 };
 132 
 133 struct TrackerDBStatementClass {
 134 	GObjectClass parent_class;
 135 };
 136 
 137 static void                tracker_db_interface_initable_iface_init (GInitableIface        *iface);
 138 static TrackerDBStatement *tracker_db_statement_sqlite_new          (TrackerDBInterface    *db_interface,
 139                                                                      sqlite3_stmt          *sqlite_stmt);
 140 static void                tracker_db_statement_sqlite_reset        (TrackerDBStatement    *stmt);
 141 static TrackerDBCursor    *tracker_db_cursor_sqlite_new             (sqlite3_stmt          *sqlite_stmt,
 142                                                                      TrackerDBStatement    *ref_stmt,
 143                                                                      TrackerPropertyType   *types,
 144                                                                      gint                   n_types,
 145                                                                      const gchar          **variable_names,
 146                                                                      gint                   n_variable_names,
 147                                                                      gboolean               threadsafe);
 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_RO
 158 };
 159 
 160 enum {
 161 	TRACKER_DB_CURSOR_PROP_0,
 162 	TRACKER_DB_CURSOR_PROP_N_COLUMNS
 163 };
 164 
 165 G_DEFINE_TYPE_WITH_CODE (TrackerDBInterface, tracker_db_interface, G_TYPE_OBJECT,
 166                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
 167                                                 tracker_db_interface_initable_iface_init));
 168 
 169 G_DEFINE_TYPE (TrackerDBStatement, tracker_db_statement, G_TYPE_OBJECT)
 170 
 171 G_DEFINE_TYPE (TrackerDBCursor, tracker_db_cursor, TRACKER_SPARQL_TYPE_CURSOR)
 172 
 173 void
 174 tracker_db_interface_sqlite_enable_shared_cache (void)
 175 {
 176 	sqlite3_enable_shared_cache (1);
 177 }
 178 
 179 static void
 180 function_sparql_string_join (sqlite3_context *context,
 181                              int              argc,
 182                              sqlite3_value   *argv[])
 183 {
 184 	GString *str = NULL;
 185 	const gchar *separator;
 186 	gint i;
 187 
 188 	/* fn:string-join (str1, str2, ..., separator) */
 189 
 190 	if (sqlite3_value_type (argv[argc-1]) != SQLITE_TEXT) {
 191 		sqlite3_result_error (context, "Invalid separator", -1);
 192 		return;
 193 	}
 194 
 195 	separator = sqlite3_value_text (argv[argc-1]);
pointer targets in assignment differ in signedness
(emitted by gcc)
196 197 for (i = 0;i < argc-1; i++) { 198 if (sqlite3_value_type (argv[argc-1]) == SQLITE_TEXT) { 199 const gchar *text = sqlite3_value_text (argv[i]); 200 201 if (text != NULL) { 202 if (!str) { 203 str = g_string_new (text); 204 } else { 205 g_string_append_printf (str, "%s%s", separator, text); 206 } 207 } 208 } 209 } 210 211 if (str) { 212 sqlite3_result_text (context, str->str, str->len, g_free); 213 g_string_free (str, FALSE); 214 } else { 215 sqlite3_result_null (context); 216 } 217 218 return; 219 } 220 221 /* Create a title-type string from the filename for replacing missing ones */ 222 static void 223 function_sparql_string_from_filename (sqlite3_context *context, 224 int argc, 225 sqlite3_value *argv[]) 226 { 227 gchar *name = NULL; 228 gchar *suffix = NULL; 229 230 if (argc != 1) { 231 sqlite3_result_error (context, "Invalid argument count", -1); 232 return; 233 } 234 235 /* "/home/user/path/title_of_the_movie.movie" -> "title of the movie" 236 * Only for local files currently, do we need to change? */ 237 238 name = g_filename_display_basename (sqlite3_value_text (argv[0]));
pointer targets in passing argument 1 of 'g_filename_display_basename' differ in signedness
(emitted by gcc)
239 240 if (!name) { 241 sqlite3_result_null (context); 242 return; 243 } 244 245 suffix = g_strrstr (name, "."); 246 247 if (suffix) { 248 *suffix = '\0'; 249 } 250 251 g_strdelimit (name, "._", ' '); 252 253 sqlite3_result_text (context, name, -1, g_free); 254 } 255 256 static void 257 function_sparql_uri_is_parent (sqlite3_context *context, 258 int argc, 259 sqlite3_value *argv[]) 260 { 261 const gchar *uri, *parent, *remaining; 262 gboolean match = FALSE; 263 guint parent_len; 264 265 if (argc != 2) { 266 sqlite3_result_error (context, "Invalid argument count", -1); 267 return; 268 } 269 270 parent = sqlite3_value_text (argv[0]);
pointer targets in assignment differ in signedness
(emitted by gcc)
271 uri = sqlite3_value_text (argv[1]); 272 273 if (!parent || !uri) { 274 sqlite3_result_error (context, "Invalid arguments", -1); 275 return; 276 } 277 278 parent_len = sqlite3_value_bytes (argv[0]); 279 280 /* Check only one argument, it's going to 281 * be compared with the other anyway. 282 */ 283 284 if (!(parent_len >= 7 && (parent[4] == ':' && parent[5] == '/' && parent[6] == '/'))) { 285 if (strstr (parent, "://") == NULL) { 286 sqlite3_result_int (context, FALSE); 287 return; 288 } 289 } 290 291 /* Remove trailing '/', will 292 * be checked later on uri. 293 */ 294 while (parent[parent_len - 1] == '/') { 295 parent_len--; 296 } 297 298 if (strncmp (uri, parent, parent_len) == 0 && uri[parent_len] == '/') { 299 const gchar *slash; 300 301 while (uri[parent_len] == '/') { 302 parent_len++; 303 } 304 305 remaining = &uri[parent_len]; 306 307 if (*remaining == '\0') { 308 /* Exact match, not a child */ 309 match = FALSE; 310 } else if ((slash = strchr (remaining, '/')) == NULL) { 311 /* Remaining doesn't have uri 312 * separator, it's a direct child. 313 */ 314 match = TRUE; 315 } else { 316 /* Check it's not trailing slashes */ 317 while (*slash == '/') { 318 slash++; 319 } 320 321 match = (*slash == '\0'); 322 } 323 } 324 325 sqlite3_result_int (context, match); 326 } 327 328 static gboolean 329 check_uri_is_descendant (const gchar *parent, 330 guint parent_len, 331 const gchar *uri) 332 { 333 const gchar *remaining; 334 gboolean match = FALSE; 335 336 /* Check only one argument, it's going to 337 * be compared with the other anyway. 338 */ 339 340 if (!(parent_len >= 7 && (parent[4] == ':' && parent[5] == '/' && parent[6] == '/'))) { 341 if (strstr (parent, "://") == NULL) { 342 return FALSE; 343 } 344 } 345 346 /* Remove trailing '/', will 347 * be checked later on uri. 348 */ 349 while (parent[parent_len - 1] == '/') { 350 parent_len--; 351 } 352 353 if (strncmp (uri, parent, parent_len) == 0 && uri[parent_len] == '/') { 354 while (uri[parent_len] == '/') { 355 parent_len++; 356 } 357 358 remaining = &uri[parent_len]; 359 360 if (remaining && *remaining) { 361 match = TRUE; 362 } 363 } 364 365 return match; 366 } 367 368 static void 369 function_sparql_uri_is_descendant (sqlite3_context *context, 370 int argc, 371 sqlite3_value *argv[]) 372 { 373 const gchar *child; 374 gboolean match = FALSE; 375 gint i; 376 377 /* fn:uri-is-descendant (parent1, parent2, ..., parentN, child) */ 378 379 if (argc < 2) { 380 sqlite3_result_error (context, "Invalid argument count", -1); 381 return; 382 } 383 384 if (sqlite3_value_type (argv[argc-1]) != SQLITE_TEXT) { 385 sqlite3_result_error (context, "Invalid child", -1); 386 return; 387 } 388 389 if (sqlite3_value_type (argv[0]) != SQLITE_TEXT) { 390 sqlite3_result_error (context, "Invalid first parent", -1); 391 return; 392 } 393 394 child = sqlite3_value_text (argv[argc-1]);
pointer targets in assignment differ in signedness
(emitted by gcc)
395 396 for (i = 0; i < argc - 1 && !match; i++) { 397 if (sqlite3_value_type (argv[i]) == SQLITE_TEXT) { 398 const gchar *parent = sqlite3_value_text (argv[i]); 399 guint parent_len = sqlite3_value_bytes (argv[i]); 400 401 if (!parent) 402 continue; 403 404 match = check_uri_is_descendant (parent, parent_len, child); 405 } 406 } 407 408 sqlite3_result_int (context, match); 409 } 410 411 static void 412 function_sparql_format_time (sqlite3_context *context, 413 int argc, 414 sqlite3_value *argv[]) 415 { 416 gdouble seconds; 417 gchar *str; 418 419 if (argc != 1) { 420 sqlite3_result_error (context, "Invalid argument count", -1); 421 return; 422 } 423 424 if (sqlite3_value_type (argv[0]) == SQLITE_NULL) { 425 sqlite3_result_null (context); 426 return; 427 } 428 429 seconds = sqlite3_value_double (argv[0]); 430 str = tracker_date_to_string (seconds); 431 432 sqlite3_result_text (context, str, -1, g_free); 433 } 434 435 static void 436 function_sparql_cartesian_distance (sqlite3_context *context, 437 int argc, 438 sqlite3_value *argv[]) 439 { 440 gdouble lat1; 441 gdouble lat2; 442 gdouble lon1; 443 gdouble lon2; 444 445 gdouble R; 446 gdouble a; 447 gdouble b; 448 gdouble c; 449 gdouble d; 450 451 if (argc != 4) { 452 sqlite3_result_error (context, "Invalid argument count", -1); 453 return; 454 } 455 456 lat1 = sqlite3_value_double (argv[0])*M_PI/180; 457 lat2 = sqlite3_value_double (argv[1])*M_PI/180; 458 lon1 = sqlite3_value_double (argv[2])*M_PI/180; 459 lon2 = sqlite3_value_double (argv[3])*M_PI/180; 460 461 R = 6371000; 462 a = M_PI/2 - lat1; 463 b = M_PI/2 - lat2; 464 c = sqrt(a*a + b*b - 2*a*b*cos(lon2 - lon1)); 465 d = R*c; 466 467 sqlite3_result_double (context, d); 468 } 469 470 static void 471 function_sparql_haversine_distance (sqlite3_context *context, 472 int argc, 473 sqlite3_value *argv[]) 474 { 475 gdouble lat1; 476 gdouble lat2; 477 gdouble lon1; 478 gdouble lon2; 479 480 gdouble R; 481 gdouble dLat; 482 gdouble dLon; 483 gdouble a; 484 gdouble c; 485 gdouble d; 486 487 if (argc != 4) { 488 sqlite3_result_error (context, "Invalid argument count", -1); 489 return; 490 } 491 492 lat1 = sqlite3_value_double (argv[0])*M_PI/180; 493 lat2 = sqlite3_value_double (argv[1])*M_PI/180; 494 lon1 = sqlite3_value_double (argv[2])*M_PI/180; 495 lon2 = sqlite3_value_double (argv[3])*M_PI/180; 496 497 R = 6371000; 498 dLat = (lat2-lat1); 499 dLon = (lon2-lon1); 500 a = sin(dLat/2) * sin(dLat/2) + cos(lat1) * cos(lat2) * sin(dLon/2) * sin(dLon/2); 501 c = 2 * atan2(sqrt(a), sqrt(1-a)); 502 d = R * c; 503 504 sqlite3_result_double (context, d); 505 } 506 507 static void 508 function_sparql_regex (sqlite3_context *context, 509 int argc, 510 sqlite3_value *argv[]) 511 { 512 gboolean ret; 513 const gchar *text, *pattern, *flags; 514 GRegexCompileFlags regex_flags; 515 GRegex *regex; 516 517 if (argc != 3) { 518 sqlite3_result_error (context, "Invalid argument count", -1); 519 return; 520 } 521 522 regex = sqlite3_get_auxdata (context, 1); 523 524 text = sqlite3_value_text (argv[0]);
pointer targets in assignment differ in signedness
(emitted by gcc)
525 flags = sqlite3_value_text (argv[2]); 526 527 if (regex == NULL) { 528 gchar *err_str; 529 GError *error = NULL; 530 531 pattern = sqlite3_value_text (argv[1]); 532 533 regex_flags = 0; 534 while (*flags) { 535 switch (*flags) { 536 case 's': 537 regex_flags |= G_REGEX_DOTALL; 538 break; 539 case 'm': 540 regex_flags |= G_REGEX_MULTILINE; 541 break; 542 case 'i': 543 regex_flags |= G_REGEX_CASELESS; 544 break; 545 case 'x': 546 regex_flags |= G_REGEX_EXTENDED; 547 break; 548 default: 549 err_str = g_strdup_printf ("Invalid SPARQL regex flag '%c'", *flags); 550 sqlite3_result_error (context, err_str, -1); 551 g_free (err_str); 552 return; 553 } 554 flags++; 555 } 556 557 regex = g_regex_new (pattern, regex_flags, 0, &error); 558 559 if (error) { 560 sqlite3_result_error (context, error->message, -1); 561 g_clear_error (&error); 562 return; 563 } 564 565 sqlite3_set_auxdata (context, 1, regex, (void (*) (void*)) g_regex_unref); 566 } 567 568 ret = g_regex_match (regex, text, 0, NULL); 569 570 sqlite3_result_int (context, ret); 571 } 572 573 #ifdef HAVE_LIBUNISTRING 574 575 static void 576 function_sparql_lower_case (sqlite3_context *context, 577 int argc, 578 sqlite3_value *argv[]) 579 { 580 const uint16_t *zInput; 581 uint16_t *zOutput; 582 size_t written = 0; 583 int nInput; 584 585 g_assert (argc == 1); 586 587 zInput = sqlite3_value_text16 (argv[0]); 588 589 if (!zInput) { 590 return; 591 } 592 593 nInput = sqlite3_value_bytes16 (argv[0]); 594 595 zOutput = u16_tolower (zInput, nInput/2, NULL, NULL, NULL, &written); 596 597 sqlite3_result_text16 (context, zOutput, written * 2, free); 598 } 599 600 static void 601 function_sparql_case_fold (sqlite3_context *context, 602 int argc, 603 sqlite3_value *argv[]) 604 { 605 const uint16_t *zInput; 606 uint16_t *zOutput; 607 size_t written = 0; 608 int nInput; 609 610 g_assert (argc == 1); 611 612 zInput = sqlite3_value_text16 (argv[0]); 613 614 if (!zInput) { 615 return; 616 } 617 618 nInput = sqlite3_value_bytes16 (argv[0]); 619 620 zOutput = u16_casefold (zInput, nInput/2, NULL, NULL, NULL, &written); 621 622 sqlite3_result_text16 (context, zOutput, written * 2, free); 623 } 624 625 #elif HAVE_LIBICU 626 627 static void 628 function_sparql_lower_case (sqlite3_context *context, 629 int argc, 630 sqlite3_value *argv[]) 631 { 632 const UChar *zInput; 633 UChar *zOutput; 634 int nInput; 635 int nOutput; 636 UErrorCode status = U_ZERO_ERROR; 637 638 g_assert (argc == 1); 639 640 zInput = sqlite3_value_text16 (argv[0]); 641 642 if (!zInput) { 643 return; 644 } 645 646 nInput = sqlite3_value_bytes16 (argv[0]); 647 648 nOutput = nInput * 2 + 2; 649 zOutput = sqlite3_malloc (nOutput); 650 651 if (!zOutput) { 652 return; 653 } 654 655 u_strToLower (zOutput, nOutput/2, zInput, nInput/2, NULL, &status); 656 657 if (!U_SUCCESS (status)){ 658 char zBuf[128]; 659 sqlite3_snprintf (128, zBuf, "ICU error: u_strToLower(): %s", u_errorName (status)); 660 zBuf[127] = '\0'; 661 sqlite3_free (zOutput); 662 sqlite3_result_error (context, zBuf, -1); 663 return; 664 } 665 666 sqlite3_result_text16 (context, zOutput, -1, sqlite3_free); 667 } 668 669 static void 670 function_sparql_case_fold (sqlite3_context *context, 671 int argc, 672 sqlite3_value *argv[]) 673 { 674 const UChar *zInput; 675 UChar *zOutput; 676 int nInput; 677 int nOutput; 678 UErrorCode status = U_ZERO_ERROR; 679 680 g_assert (argc == 1); 681 682 zInput = sqlite3_value_text16 (argv[0]); 683 684 if (!zInput) { 685 return; 686 } 687 688 nInput = sqlite3_value_bytes16 (argv[0]); 689 690 nOutput = nInput * 2 + 2; 691 zOutput = sqlite3_malloc (nOutput); 692 693 if (!zOutput) { 694 return; 695 } 696 697 u_strFoldCase (zOutput, nOutput/2, zInput, nInput/2, U_FOLD_CASE_DEFAULT, &status); 698 699 if (!U_SUCCESS (status)){ 700 char zBuf[128]; 701 sqlite3_snprintf (128, zBuf, "ICU error: u_strFoldCase: %s", u_errorName (status)); 702 zBuf[127] = '\0'; 703 sqlite3_free (zOutput); 704 sqlite3_result_error (context, zBuf, -1); 705 return; 706 } 707 708 sqlite3_result_text16 (context, zOutput, -1, sqlite3_free); 709 } 710 #else /* GLib based */ 711 712 static void 713 function_sparql_lower_case (sqlite3_context *context, 714 int argc, 715 sqlite3_value *argv[]) 716 { 717 const gchar *zInput; 718 gchar *zOutput; 719 int nInput; 720 721 g_assert (argc == 1); 722 723 /* GLib API works with UTF-8, so use the UTF-8 functions of SQLite too */ 724 725 zInput = (const gchar*) sqlite3_value_text (argv[0]); 726 727 if (!zInput) { 728 return; 729 } 730 731 nInput = sqlite3_value_bytes (argv[0]); 732 733 if (!zOutput) { 734 return; 735 } 736 737 zOutput = g_utf8_strdown (zInput, nInput); 738 739 sqlite3_result_text (context, zOutput, -1, g_free); 740 } 741 742 static void 743 function_sparql_case_fold (sqlite3_context *context, 744 int argc, 745 sqlite3_value *argv[]) 746 { 747 const gchar *zInput; 748 gchar *zOutput; 749 int nInput; 750 751 g_assert (argc == 1); 752 753 /* GLib API works with UTF-8, so use the UTF-8 functions of SQLite too */ 754 755 zInput = (const gchar*) sqlite3_value_text (argv[0]); 756 757 if (!zInput) { 758 return; 759 } 760 761 nInput = sqlite3_value_bytes (argv[0]); 762 763 if (!zOutput) { 764 return; 765 } 766 767 zOutput = g_utf8_casefold (zInput, nInput); 768 769 sqlite3_result_text (context, zOutput, -1, g_free); 770 } 771 772 #endif 773 774 static inline int 775 stmt_step (sqlite3_stmt *stmt) 776 { 777 int result; 778 779 result = sqlite3_step (stmt); 780 781 /* If the statement expired between preparing it and executing 782 * sqlite3_step(), we are supposed to get SQLITE_SCHEMA error in 783 * sqlite3_errcode(), BUT there seems to be a bug in sqlite and 784 * SQLITE_ABORT is being returned instead for that case. So, the 785 * only way to see if a given statement was expired is to use 786 * sqlite3_expired(stmt), which is marked as DEPRECATED in sqlite. 787 * If found that the statement is expired, we need to reset it 788 * and retry the sqlite3_step(). 789 * NOTE, that this expiration may only happen between preparing 790 * the statement and step-ing it, NOT between steps. */ 791 if ((result == SQLITE_ABORT || result == SQLITE_SCHEMA) && 792 sqlite3_expired (stmt)) { 793 sqlite3_reset (stmt); 794 result = sqlite3_step (stmt); 795 } 796 797 return result; 798 } 799 800 static int 801 check_interrupt (void *user_data) 802 { 803 TrackerDBInterface *db_interface = user_data; 804 805 if (db_interface->busy_callback) { 806 db_interface->busy_callback (db_interface->busy_status, 807 UNKNOWN_STATUS, /* No idea to get the status from SQLite */ 808 db_interface->busy_user_data); 809 } 810 811 return g_cancellable_is_cancelled (db_interface->cancellable) ? 1 : 0; 812 } 813 814 static void 815 tracker_locale_notify_cb (TrackerLocaleID id, 816 gpointer user_data) 817 { 818 TrackerDBInterface *db_interface = user_data; 819 820 /* Request a collator reset. Use thread-safe methods as this function will get 821 * called from the main thread */ 822 g_atomic_int_compare_and_exchange (&(db_interface->collator_reset_requested), FALSE, TRUE); 823 } 824 825 static void 826 open_database (TrackerDBInterface *db_interface, 827 GError **error) 828 { 829 int mode; 830 831 g_assert (db_interface->filename != NULL); 832 833 if (!db_interface->ro) { 834 mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; 835 } else { 836 mode = SQLITE_OPEN_READONLY; 837 } 838 839 if (sqlite3_open_v2 (db_interface->filename, &db_interface->db, mode | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) { 840 g_set_error (error, 841 TRACKER_DB_INTERFACE_ERROR, 842 TRACKER_DB_OPEN_ERROR, 843 "Could not open sqlite3 database:'%s'", db_interface->filename); 844 return; 845 } else { 846 g_message ("Opened sqlite3 database:'%s'", db_interface->filename); 847 } 848 849 /* Set our unicode collation function */ 850 tracker_db_interface_sqlite_reset_collator (db_interface); 851 /* And register for updates on locale changes */ 852 db_interface->locale_notification_id = tracker_locale_notify_add (TRACKER_LOCALE_COLLATE, 853 tracker_locale_notify_cb, 854 db_interface, 855 NULL); 856 857 sqlite3_progress_handler (db_interface->db, 100, 858 check_interrupt, db_interface); 859 860 sqlite3_create_function (db_interface->db, "SparqlRegex", 3, SQLITE_ANY, 861 db_interface, &function_sparql_regex, 862 NULL, NULL); 863 864 sqlite3_create_function (db_interface->db, "SparqlHaversineDistance", 4, SQLITE_ANY, 865 db_interface, &function_sparql_haversine_distance, 866 NULL, NULL); 867 868 sqlite3_create_function (db_interface->db, "SparqlCartesianDistance", 4, SQLITE_ANY, 869 db_interface, &function_sparql_cartesian_distance, 870 NULL, NULL); 871 872 sqlite3_create_function (db_interface->db, "SparqlStringFromFilename", 1, SQLITE_ANY, 873 db_interface, &function_sparql_string_from_filename, 874 NULL, NULL); 875 876 sqlite3_create_function (db_interface->db, "SparqlStringJoin", -1, SQLITE_ANY, 877 db_interface, &function_sparql_string_join, 878 NULL, NULL); 879 880 sqlite3_create_function (db_interface->db, "SparqlUriIsParent", 2, SQLITE_ANY, 881 db_interface, &function_sparql_uri_is_parent, 882 NULL, NULL); 883 884 sqlite3_create_function (db_interface->db, "SparqlUriIsDescendant", -1, SQLITE_ANY, 885 db_interface, &function_sparql_uri_is_descendant, 886 NULL, NULL); 887 888 sqlite3_create_function (db_interface->db, "SparqlLowerCase", 1, SQLITE_ANY, 889 db_interface, &function_sparql_lower_case, 890 NULL, NULL); 891 892 sqlite3_create_function (db_interface->db, "SparqlCaseFold", 1, SQLITE_ANY, 893 db_interface, &function_sparql_case_fold, 894 NULL, NULL); 895 896 sqlite3_create_function (db_interface->db, "SparqlFormatTime", 1, SQLITE_ANY, 897 db_interface, &function_sparql_format_time, 898 NULL, NULL); 899 900 sqlite3_extended_result_codes (db_interface->db, 0); 901 sqlite3_busy_timeout (db_interface->db, 100000); 902 } 903 904 static gboolean 905 tracker_db_interface_initable_init (GInitable *initable, 906 GCancellable *cancellable, 907 GError **error) 908 { 909 TrackerDBInterface *db_iface; 910 GError *internal_error = NULL; 911 912 db_iface = TRACKER_DB_INTERFACE (initable); 913 914 open_database (db_iface, &internal_error); 915 916 if (internal_error) { 917 g_propagate_error (error, internal_error); 918 return FALSE; 919 } 920 921 return TRUE; 922 } 923 924 static void 925 tracker_db_interface_initable_iface_init (GInitableIface *iface) 926 { 927 iface->init = tracker_db_interface_initable_init; 928 } 929 930 static void 931 tracker_db_interface_sqlite_set_property (GObject *object, 932 guint prop_id, 933 const GValue *value, 934 GParamSpec *pspec) 935 { 936 TrackerDBInterface *db_iface; 937 938 db_iface = TRACKER_DB_INTERFACE (object); 939 940 switch (prop_id) { 941 case PROP_RO: 942 db_iface->ro = g_value_get_boolean (value); 943 break; 944 case PROP_FILENAME: 945 db_iface->filename = g_value_dup_string (value); 946 break; 947 default: 948 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 949 } 950 } 951 952 static void 953 tracker_db_interface_sqlite_get_property (GObject *object, 954 guint prop_id, 955 GValue *value, 956 GParamSpec *pspec) 957 { 958 TrackerDBInterface *db_iface; 959 960 db_iface = TRACKER_DB_INTERFACE (object); 961 962 switch (prop_id) { 963 case PROP_RO: 964 g_value_set_boolean (value, db_iface->ro); 965 break; 966 case PROP_FILENAME: 967 g_value_set_string (value, db_iface->filename); 968 break; 969 default: 970 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 971 } 972 } 973 974 static void 975 close_database (TrackerDBInterface *db_interface) 976 { 977 gint rc; 978 979 if (db_interface->dynamic_statements) { 980 g_hash_table_unref (db_interface->dynamic_statements); 981 db_interface->dynamic_statements = NULL; 982 } 983 984 if (db_interface->function_data) { 985 g_slist_foreach (db_interface->function_data, (GFunc) g_free, NULL); 986 g_slist_free (db_interface->function_data); 987 db_interface->function_data = NULL; 988 } 989 990 if (db_interface->db) { 991 rc = sqlite3_close (db_interface->db); 992 g_warn_if_fail (rc == SQLITE_OK); 993 } 994 } 995 996 static gchar ** 997 _fts_create_properties (GHashTable *properties) 998 { 999 GHashTableIter iter; 1000 GPtrArray *cols; 1001 GList *columns; 1002 gchar *table; 1003 1004 if (g_hash_table_size (properties) == 0) { 1005 return NULL; 1006 } 1007 1008 g_hash_table_iter_init (&iter, properties); 1009 cols = g_ptr_array_new (); 1010 1011 while (g_hash_table_iter_next (&iter, (gpointer *) &table, 1012 (gpointer *) &columns)) { 1013 while (columns) { 1014 g_ptr_array_add (cols, g_strdup (columns->data)); 1015 columns = columns->next; 1016 } 1017 } 1018 1019 g_ptr_array_add (cols, NULL); 1020 1021 return (gchar **) g_ptr_array_free (cols, FALSE); 1022 } 1023 1024 void 1025 tracker_db_interface_sqlite_fts_init (TrackerDBInterface *db_interface, 1026 GHashTable *properties, 1027 GHashTable *multivalued, 1028 gboolean create) 1029 { 1030 #if HAVE_TRACKER_FTS 1031 GStrv fts_columns = NULL; 1032 1033 tracker_fts_init_db (db_interface->db); 1034 1035 if (properties) { 1036 fts_columns = _fts_create_properties (properties); 1037 } 1038 1039 if (create && 1040 !tracker_fts_create_table (db_interface->db, "fts", 1041 properties, multivalued)) { 1042 g_warning ("FTS tables creation failed"); 1043 } 1044 1045 if (fts_columns) { 1046 GString *insert, *select; 1047 gint i = 0; 1048 1049 insert = g_string_new ("INSERT INTO fts (docid"); 1050 select = g_string_new ("SELECT rowid"); 1051 1052 while (fts_columns[i]) { 1053 g_string_append_printf (insert, ", \"%s\"", 1054 fts_columns[i]); 1055 g_string_append_printf (select, ", \"%s\"", 1056 fts_columns[i]); 1057 i++; 1058 } 1059 1060 g_string_append (select, " FROM fts_view WHERE rowid=?"); 1061 g_string_append (insert, ") "); 1062 g_string_append (insert, select->str); 1063 1064 g_string_free (select, TRUE); 1065 db_interface->fts_insert_str = g_string_free (insert, FALSE); 1066 1067 g_strfreev (fts_columns); 1068 } 1069 #endif 1070 } 1071 1072 #if HAVE_TRACKER_FTS 1073 void 1074 tracker_db_interface_sqlite_fts_alter_table (TrackerDBInterface *db_interface, 1075 GHashTable *properties, 1076 GHashTable *multivalued) 1077 { 1078 if (!tracker_fts_alter_table (db_interface->db, "fts", properties, multivalued)) { 1079 g_critical ("Failed to update FTS columns"); 1080 } 1081 } 1082 1083 gboolean 1084 tracker_db_interface_sqlite_fts_update_text (TrackerDBInterface *db_interface, 1085 int id, 1086 const gchar **properties, 1087 const char **text, 1088 gboolean create) 1089 { 1090 TrackerDBStatement *stmt; 1091 GError *error = NULL; 1092 1093 if (!create) { 1094 stmt = tracker_db_interface_create_statement (db_interface, 1095 TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, 1096 &error, 1097 "DELETE FROM fts WHERE docid=?"); 1098 tracker_db_statement_bind_int (stmt, 0, id); 1099 1100 tracker_db_statement_execute (stmt, &error); 1101 g_object_unref (stmt); 1102 1103 if (error) { 1104 g_warning ("Could not update FTS text: %s", error->message); 1105 g_error_free (error); 1106 return FALSE; 1107 } 1108 } 1109 1110 stmt = tracker_db_interface_create_statement (db_interface, 1111 TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, 1112 &error, 1113 "%s", 1114 db_interface->fts_insert_str); 1115 1116 if (!stmt || error) { 1117 if (error) { 1118 g_warning ("Could not create FTS insert statement: %s\n", 1119 error->message); 1120 g_error_free (error); 1121 } 1122 return FALSE; 1123 } 1124 1125 tracker_db_statement_bind_int (stmt, 0, id); 1126 tracker_db_statement_execute (stmt, &error); 1127 g_object_unref (stmt); 1128 1129 if (error) { 1130 g_warning ("Could not insert FTS text: %s", error->message); 1131 g_error_free (error); 1132 return FALSE; 1133 } 1134 1135 return TRUE; 1136 } 1137 1138 gboolean 1139 tracker_db_interface_sqlite_fts_delete_text (TrackerDBInterface *db_interface, 1140 int id, 1141 const gchar *property) 1142 { 1143 TrackerDBStatement *stmt; 1144 GError *error = NULL; 1145 1146 stmt = tracker_db_interface_create_statement (db_interface, 1147 TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, 1148 &error, 1149 "UPDATE fts SET \"%s\" = '' WHERE docid = ?", 1150 property); 1151 1152 if (!stmt || error) { 1153 if (error) { 1154 g_warning ("Could not create FTS update statement: %s\n", 1155 error->message); 1156 g_error_free (error); 1157 } 1158 return FALSE; 1159 } 1160 1161 tracker_db_statement_bind_int (stmt, 0, id); 1162 tracker_db_statement_execute (stmt, &error); 1163 g_object_unref (stmt); 1164 1165 if (error) { 1166 g_warning ("Could not execute FTS update: %s", error->message); 1167 g_error_free (error); 1168 return FALSE; 1169 } 1170 1171 return TRUE; 1172 } 1173 1174 #endif 1175 1176 void 1177 tracker_db_interface_sqlite_reset_collator (TrackerDBInterface *db_interface) 1178 { 1179 g_debug ("Resetting collator in db interface %p", db_interface); 1180 1181 /* This will overwrite any other collation set before, if any */ 1182 if (sqlite3_create_collation_v2 (db_interface->db, 1183 TRACKER_COLLATION_NAME, 1184 SQLITE_UTF8, 1185 tracker_collation_init (), 1186 tracker_collation_utf8, 1187 tracker_collation_shutdown) != SQLITE_OK) 1188 { 1189 g_critical ("Couldn't set collation function: %s", 1190 sqlite3_errmsg (db_interface->db)); 1191 } 1192 } 1193 1194 static gint 1195 wal_hook (gpointer user_data, 1196 sqlite3 *db, 1197 const gchar *db_name, 1198 gint n_pages) 1199 { 1200 ((TrackerDBWalCallback) user_data) (n_pages); 1201 1202 return SQLITE_OK; 1203 } 1204 1205 void 1206 tracker_db_interface_sqlite_wal_hook (TrackerDBInterface *interface, 1207 TrackerDBWalCallback callback) 1208 { 1209 sqlite3_wal_hook (interface->db, wal_hook, callback); 1210 } 1211 1212 1213 static void 1214 tracker_db_interface_sqlite_finalize (GObject *object) 1215 { 1216 TrackerDBInterface *db_interface; 1217 1218 db_interface = TRACKER_DB_INTERFACE (object); 1219 1220 close_database (db_interface); 1221 g_free (db_interface->fts_insert_str); 1222 1223 g_message ("Closed sqlite3 database:'%s'", db_interface->filename); 1224 1225 g_free (db_interface->filename); 1226 g_free (db_interface->busy_status); 1227 1228 if (db_interface->locale_notification_id) { 1229 tracker_locale_notify_remove (db_interface->locale_notification_id); 1230 } 1231 1232 G_OBJECT_CLASS (tracker_db_interface_parent_class)->finalize (object); 1233 } 1234 1235 static void 1236 tracker_db_interface_class_init (TrackerDBInterfaceClass *class) 1237 { 1238 GObjectClass *object_class = G_OBJECT_CLASS (class); 1239 1240 object_class->set_property = tracker_db_interface_sqlite_set_property; 1241 object_class->get_property = tracker_db_interface_sqlite_get_property; 1242 object_class->finalize = tracker_db_interface_sqlite_finalize; 1243 1244 g_object_class_install_property (object_class, 1245 PROP_FILENAME, 1246 g_param_spec_string ("filename", 1247 "DB filename", 1248 "DB filename", 1249 NULL, 1250 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); 1251 1252 g_object_class_install_property (object_class, 1253 PROP_RO, 1254 g_param_spec_boolean ("read-only", 1255 "Read only", 1256 "Whether the connection is read only", 1257 FALSE, 1258 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); 1259 } 1260 1261 static void 1262 prepare_database (TrackerDBInterface *db_interface) 1263 { 1264 db_interface->dynamic_statements = g_hash_table_new_full (g_str_hash, g_str_equal, 1265 NULL, 1266 (GDestroyNotify) g_object_unref); 1267 } 1268 1269 static void 1270 tracker_db_interface_init (TrackerDBInterface *db_interface) 1271 { 1272 db_interface->ro = FALSE; 1273 1274 prepare_database (db_interface); 1275 } 1276 1277 void 1278 tracker_db_interface_set_max_stmt_cache_size (TrackerDBInterface *db_interface, 1279 TrackerDBStatementCacheType cache_type, 1280 guint max_size) 1281 { 1282 TrackerDBStatementLru *stmt_lru; 1283 1284 if (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE) { 1285 stmt_lru = &db_interface->update_stmt_lru; 1286 } else if (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT) { 1287 stmt_lru = &db_interface->select_stmt_lru; 1288 } else { 1289 return; 1290 } 1291 1292 /* Must be larger than 2 to make sense (to have a tail and head) */ 1293 if (max_size > 2) { 1294 stmt_lru->max = max_size; 1295 } else { 1296 stmt_lru->max = 3; 1297 } 1298 } 1299 1300 void 1301 tracker_db_interface_set_busy_handler (TrackerDBInterface *db_interface, 1302 TrackerBusyCallback busy_callback, 1303 const gchar *busy_status, 1304 gpointer busy_user_data) 1305 { 1306 g_return_if_fail (TRACKER_IS_DB_INTERFACE (db_interface)); 1307 db_interface->busy_callback = busy_callback; 1308 db_interface->busy_user_data = busy_user_data; 1309 g_free (db_interface->busy_status); 1310 1311 if (busy_status) { 1312 db_interface->busy_status = g_strdup (busy_status); 1313 } else { 1314 db_interface->busy_status = NULL; 1315 } 1316 } 1317 1318 TrackerDBStatement * 1319 tracker_db_interface_create_statement (TrackerDBInterface *db_interface, 1320 TrackerDBStatementCacheType cache_type, 1321 GError **error, 1322 const gchar *query, 1323 ...) 1324 { 1325 TrackerDBStatementLru *stmt_lru = NULL; 1326 TrackerDBStatement *stmt; 1327 va_list args; 1328 gchar *full_query; 1329 1330 g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (db_interface), NULL); 1331 1332 va_start (args, query); 1333 full_query = g_strdup_vprintf (query, args); 1334 va_end (args); 1335 1336 /* There are three kinds of queries: 1337 * a) Cached queries: SELECT and UPDATE ones (cache_type) 1338 * b) Non-Cached queries: NONE ones (cache_type) 1339 * c) Forced Non-Cached: in case of a stmt being already in use, we can't 1340 * reuse it (you can't use two different loops on a sqlite3_stmt, of 1341 * course). This happens with recursive uses of a cursor, for example */ 1342 1343 if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) { 1344 stmt = g_hash_table_lookup (db_interface->dynamic_statements, full_query); 1345 1346 if (stmt && stmt->stmt_is_sunk) { 1347 /* c) Forced non-cached 1348 * prepared statement is still in use, create new uncached one */ 1349 stmt = NULL; 1350 /* Make sure to set cache_type here, to ensure the right flow in the 1351 * LRU-cache below */ 1352 cache_type = TRACKER_DB_STATEMENT_CACHE_TYPE_NONE; 1353 } 1354 1355 if (cache_type == TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE) { 1356 /* a) Cached */ 1357 stmt_lru = &db_interface->update_stmt_lru; 1358 } else { 1359 /* a) Cached */ 1360 stmt_lru = &db_interface->select_stmt_lru; 1361 } 1362 1363 } else { 1364 /* b) Non-Cached */ 1365 stmt = NULL; 1366 } 1367 1368 if (!stmt) { 1369 sqlite3_stmt *sqlite_stmt; 1370 int retval; 1371 1372 g_debug ("Preparing query: '%s'", full_query); 1373 1374 retval = sqlite3_prepare_v2 (db_interface->db, full_query, -1, &sqlite_stmt, NULL); 1375 1376 if (retval != SQLITE_OK) { 1377 1378 if (retval == SQLITE_INTERRUPT) { 1379 g_set_error (error, 1380 TRACKER_DB_INTERFACE_ERROR, 1381 TRACKER_DB_INTERRUPTED, 1382 "Interrupted"); 1383 } else { 1384 g_set_error (error, 1385 TRACKER_DB_INTERFACE_ERROR, 1386 TRACKER_DB_QUERY_ERROR, 1387 "%s", 1388 sqlite3_errmsg (db_interface->db)); 1389 } 1390 1391 g_free (full_query); 1392 1393 return NULL; 1394 } 1395 1396 stmt = tracker_db_statement_sqlite_new (db_interface, sqlite_stmt); 1397 1398 if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) { 1399 /* use replace instead of insert to make sure we store the string that 1400 belongs to the right sqlite statement to ensure the lifetime of the string 1401 matches the statement */ 1402 g_hash_table_replace (db_interface->dynamic_statements, 1403 (gpointer) sqlite3_sql (sqlite_stmt), 1404 stmt); 1405 1406 /* So the ring looks a bit like this: * 1407 * * 1408 * .--tail .--head * 1409 * | | * 1410 * [p-n] -> [p-n] -> [p-n] -> [p-n] * 1411 * ^ | * 1412 * `- [n-p] <- [n-p] <--------' * 1413 * */ 1414 1415 if (stmt_lru->size >= stmt_lru->max) { 1416 TrackerDBStatement *new_head; 1417 1418 /* We reached max-size of the LRU stmt cache. Destroy current 1419 * least recently used (stmt_lru.head) and fix the ring. For 1420 * that we take out the current head, and close the ring. 1421 * Then we assign head->next as new head. */ 1422 1423 new_head = stmt_lru->head->next; 1424 g_hash_table_remove (db_interface->dynamic_statements, 1425 (gpointer) sqlite3_sql (stmt_lru->head->stmt)); 1426 stmt_lru->size--; 1427 stmt_lru->head = new_head; 1428 } else { 1429 if (stmt_lru->size == 0) { 1430 stmt_lru->head = stmt; 1431 stmt_lru->tail = stmt; 1432 } 1433 } 1434 1435 /* Set the current stmt (which is always new here) as the new tail 1436 * (new most recent used). We insert current stmt between head and 1437 * current tail, and we set tail to current stmt. */ 1438 1439 stmt_lru->size++; 1440 stmt->next = stmt_lru->head; 1441 stmt_lru->head->prev = stmt; 1442 1443 stmt_lru->tail->next = stmt; 1444 stmt->prev = stmt_lru->tail; 1445 stmt_lru->tail = stmt; 1446 } 1447 } else { 1448 tracker_db_statement_sqlite_reset (stmt); 1449 1450 if (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) { 1451 if (stmt == stmt_lru->head) { 1452 1453 /* Current stmt is least recently used, shift head and tail 1454 * of the ring to efficiently make it most recently used. */ 1455 1456 stmt_lru->head = stmt_lru->head->next; 1457 stmt_lru->tail = stmt_lru->tail->next; 1458 } else if (stmt != stmt_lru->tail) { 1459 1460 /* Current statement isn't most recently used, make it most 1461 * recently used now (less efficient way than above). */ 1462 1463 /* Take stmt out of the list and close the ring */ 1464 stmt->prev->next = stmt->next; 1465 stmt->next->prev = stmt->prev; 1466 1467 /* Put stmt as tail (most recent used) */ 1468 stmt->next = stmt_lru->head; 1469 stmt_lru->head->prev = stmt; 1470 stmt->prev = stmt_lru->tail; 1471 stmt_lru->tail->next = stmt; 1472 stmt_lru->tail = stmt; 1473 } 1474 1475 /* if (stmt == tail), it's already the most recently used in the 1476 * ring, so in this case we do nothing of course */ 1477 } 1478 } 1479 1480 g_free (full_query); 1481 1482 return (cache_type != TRACKER_DB_STATEMENT_CACHE_TYPE_NONE) ? g_object_ref (stmt) : stmt; 1483 } 1484 1485 static void 1486 execute_stmt (TrackerDBInterface *interface, 1487 sqlite3_stmt *stmt, 1488 GCancellable *cancellable, 1489 GError **error) 1490 { 1491 gint result; 1492 1493 result = SQLITE_OK; 1494 1495 /* Statement is going to start, check if we got a request to reset the 1496 * collator, and if so, do it. */ 1497 if (ATOMIC_EXCHANGE_AND_ADD (&interface->n_active_cursors, 1) == 0 && 1498 g_atomic_int_compare_and_exchange (&(interface->collator_reset_requested), TRUE, FALSE)) { 1499 tracker_db_interface_sqlite_reset_collator (interface); 1500 } 1501 1502 while (result == SQLITE_OK || 1503 result == SQLITE_ROW) { 1504 1505 if (g_cancellable_is_cancelled (cancellable)) { 1506 result = SQLITE_INTERRUPT; 1507 sqlite3_reset (stmt); 1508 } else { 1509 /* only one statement can be active at the same time per interface */ 1510 interface->cancellable = cancellable; 1511 result = stmt_step (stmt); 1512 1513 interface->cancellable = NULL; 1514 } 1515 1516 switch (result) { 1517 case SQLITE_ERROR: 1518 sqlite3_reset (stmt); 1519 break; 1520 case SQLITE_ROW: 1521 break; 1522 default: 1523 break; 1524 } 1525 } 1526 1527 1528 if (result == SQLITE_DONE) { 1529 /* Statement finished, check if we got a request to reset the 1530 * collator, and if so, do it. 1531 */ 1532 if (g_atomic_int_dec_and_test (&interface->n_active_cursors) && 1533 g_atomic_int_compare_and_exchange (&(interface->collator_reset_requested), TRUE, FALSE)) { 1534 tracker_db_interface_sqlite_reset_collator (interface); 1535 } 1536 } else { 1537 g_atomic_int_add (&interface->n_active_cursors, -1); 1538 1539 /* This is rather fatal */ 1540 if (errno != ENOSPC && 1541 (sqlite3_errcode (interface->db) == SQLITE_IOERR || 1542 sqlite3_errcode (interface->db) == SQLITE_CORRUPT || 1543 sqlite3_errcode (interface->db) == SQLITE_NOTADB)) { 1544 1545 g_critical ("SQLite error: %s (errno: %s)", 1546 sqlite3_errmsg (interface->db), 1547 g_strerror (errno)); 1548 1549 #ifndef DISABLE_JOURNAL 1550 g_unlink (interface->filename); 1551 1552 g_error ("SQLite experienced an error with file:'%s'. " 1553 "It is either NOT a SQLite database or it is " 1554 "corrupt or there was an IO error accessing the data. " 1555 "This file has now been removed and will be recreated on the next start. " 1556 "Shutting down now.", 1557 interface->filename); 1558 1559 return; 1560 #endif /* DISABLE_JOURNAL */ 1561 } 1562 1563 if (!error) { 1564 g_warning ("Could not perform SQLite operation, error:%d->'%s'", 1565 sqlite3_errcode (interface->db), 1566 sqlite3_errmsg (interface->db)); 1567 } else { 1568 if (result == SQLITE_INTERRUPT) { 1569 g_set_error (error, 1570 TRACKER_DB_INTERFACE_ERROR, 1571 TRACKER_DB_INTERRUPTED, 1572 "Interrupted"); 1573 } else { 1574 g_set_error (error, 1575 TRACKER_DB_INTERFACE_ERROR, 1576 errno != ENOSPC ? TRACKER_DB_QUERY_ERROR : TRACKER_DB_NO_SPACE, 1577 "%s%s%s%s", 1578 sqlite3_errmsg (interface->db), 1579 errno != 0 ? " (strerror of errno (not necessarily related): " : "", 1580 errno != 0 ? g_strerror (errno) : "", 1581 errno != 0 ? ")" : ""); 1582 } 1583 } 1584 } 1585 } 1586 1587 void 1588 tracker_db_interface_execute_vquery (TrackerDBInterface *db_interface, 1589 GError **error, 1590 const gchar *query, 1591 va_list args) 1592 { 1593 gchar *full_query; 1594 sqlite3_stmt *stmt; 1595 int retval; 1596 1597 full_query = g_strdup_vprintf (query, args); 1598 1599 /* g_debug ("Running query: '%s'", full_query); */ 1600 retval = sqlite3_prepare_v2 (db_interface->db, full_query, -1, &stmt, NULL); 1601 1602 if (retval != SQLITE_OK) { 1603 g_set_error (error, 1604 TRACKER_DB_INTERFACE_ERROR, 1605 TRACKER_DB_QUERY_ERROR, 1606 "%s", 1607 sqlite3_errmsg (db_interface->db)); 1608 g_free (full_query); 1609 return; 1610 } else if (stmt == NULL) { 1611 g_set_error (error, 1612 TRACKER_DB_INTERFACE_ERROR, 1613 TRACKER_DB_QUERY_ERROR, 1614 "Could not prepare SQL statement:'%s'", 1615 full_query); 1616 1617 g_free (full_query); 1618 return; 1619 } 1620 1621 execute_stmt (db_interface, stmt, NULL, error); 1622 sqlite3_finalize (stmt); 1623 1624 g_free (full_query); 1625 } 1626 1627 TrackerDBInterface * 1628 tracker_db_interface_sqlite_new (const gchar *filename, 1629 GError **error) 1630 { 1631 TrackerDBInterface *object; 1632 GError *internal_error = NULL; 1633 1634 object = g_initable_new (TRACKER_TYPE_DB_INTERFACE, 1635 NULL, 1636 &internal_error, 1637 "filename", filename, 1638 NULL); 1639 1640 if (internal_error) { 1641 g_propagate_error (error, internal_error); 1642 return NULL; 1643 } 1644 1645 return object; 1646 } 1647 1648 TrackerDBInterface * 1649 tracker_db_interface_sqlite_new_ro (const gchar *filename, 1650 GError **error) 1651 { 1652 TrackerDBInterface *object; 1653 GError *internal_error = NULL; 1654 1655 object = g_initable_new (TRACKER_TYPE_DB_INTERFACE, 1656 NULL, 1657 &internal_error, 1658 "filename", filename, 1659 "read-only", TRUE, 1660 NULL); 1661 1662 if (internal_error) { 1663 g_propagate_error (error, internal_error); 1664 return NULL; 1665 } 1666 1667 return object; 1668 } 1669 1670 gint64 1671 tracker_db_interface_sqlite_get_last_insert_id (TrackerDBInterface *interface) 1672 { 1673 g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (interface), 0); 1674 1675 return (gint64) sqlite3_last_insert_rowid (interface->db); 1676 } 1677 1678 static void 1679 tracker_db_statement_finalize (GObject *object) 1680 { 1681 TrackerDBStatement *stmt; 1682 1683 stmt = TRACKER_DB_STATEMENT (object); 1684 1685 /* A cursor was still open while we're being finalized, because a cursor 1686 * holds its own reference, this means that somebody is unreffing a stmt 1687 * too often. We mustn't sqlite3_finalize the priv->stmt in this case, 1688 * though. It would crash&burn the cursor. */ 1689 1690 g_assert (!stmt->stmt_is_sunk); 1691 1692 sqlite3_finalize (stmt->stmt); 1693 1694 G_OBJECT_CLASS (tracker_db_statement_parent_class)->finalize (object); 1695 } 1696 1697 static void 1698 tracker_db_statement_class_init (TrackerDBStatementClass *class) 1699 { 1700 GObjectClass *object_class = G_OBJECT_CLASS (class); 1701 1702 object_class->finalize = tracker_db_statement_finalize; 1703 } 1704 1705 static TrackerDBStatement * 1706 tracker_db_statement_sqlite_new (TrackerDBInterface *db_interface, 1707 sqlite3_stmt *sqlite_stmt) 1708 { 1709 TrackerDBStatement *stmt; 1710 1711 stmt = g_object_new (TRACKER_TYPE_DB_STATEMENT, NULL); 1712 1713 stmt->db_interface = db_interface; 1714 stmt->stmt = sqlite_stmt; 1715 stmt->stmt_is_sunk = FALSE; 1716 1717 return stmt; 1718 } 1719 1720 static void 1721 tracker_db_cursor_close (TrackerDBCursor *cursor) 1722 { 1723 TrackerDBInterface *iface; 1724 1725 g_return_if_fail (TRACKER_IS_DB_CURSOR (cursor)); 1726 1727 if (cursor->ref_stmt == NULL) { 1728 /* already closed */ 1729 return; 1730 } 1731 1732 /* As soon as we finalize the cursor, check if we need a collator reset 1733 * and notify the iface about the removed cursor */ 1734 iface = cursor->ref_stmt->db_interface; 1735 if (g_atomic_int_dec_and_test (&iface->n_active_cursors) && 1736 g_atomic_int_compare_and_exchange (&(iface->collator_reset_requested), TRUE, FALSE)) { 1737 tracker_db_interface_sqlite_reset_collator (iface); 1738 } 1739 1740 if (cursor->threadsafe) { 1741 tracker_db_manager_lock (); 1742 } 1743 1744 cursor->ref_stmt->stmt_is_sunk = FALSE; 1745 tracker_db_statement_sqlite_reset (cursor->ref_stmt); 1746 g_object_unref (cursor->ref_stmt); 1747 cursor->ref_stmt = NULL; 1748 1749 if (cursor->threadsafe) { 1750 tracker_db_manager_unlock (); 1751 } 1752 } 1753 1754 static void 1755 tracker_db_cursor_finalize (GObject *object) 1756 { 1757 TrackerDBCursor *cursor; 1758 int i; 1759 1760 cursor = TRACKER_DB_CURSOR (object); 1761 1762 tracker_db_cursor_close (cursor); 1763 1764 g_free (cursor->types); 1765 1766 for (i = 0; i < cursor->n_variable_names; i++) { 1767 g_free (cursor->variable_names[i]); 1768 } 1769 g_free (cursor->variable_names); 1770 1771 G_OBJECT_CLASS (tracker_db_cursor_parent_class)->finalize (object); 1772 } 1773 1774 static void 1775 tracker_db_cursor_get_property (GObject *object, 1776 guint prop_id, 1777 GValue *value, 1778 GParamSpec *pspec) 1779 { 1780 TrackerDBCursor *cursor = TRACKER_DB_CURSOR (object); 1781 switch (prop_id) { 1782 case TRACKER_DB_CURSOR_PROP_N_COLUMNS: 1783 g_value_set_int (value, tracker_db_cursor_get_n_columns (cursor)); 1784 break; 1785 default: 1786 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 1787 } 1788 } 1789 1790 static void 1791 tracker_db_cursor_iter_next_thread (GSimpleAsyncResult *res, 1792 GObject *object, 1793 GCancellable *cancellable) 1794 { 1795 /* run in thread */ 1796 1797 TrackerDBCursor *cursor = TRACKER_DB_CURSOR (object); 1798 GError *error = NULL; 1799 gboolean result; 1800 1801 result = db_cursor_iter_next (cursor, cancellable, &error); 1802 if (error) { 1803 g_simple_async_result_set_from_error (res, error); 1804 } else { 1805 g_simple_async_result_set_op_res_gboolean (res, result); 1806 } 1807 } 1808 1809 static void 1810 tracker_db_cursor_iter_next_async (TrackerDBCursor *cursor, 1811 GCancellable *cancellable, 1812 GAsyncReadyCallback callback, 1813 gpointer user_data) 1814 { 1815 GSimpleAsyncResult *res; 1816 1817 res = g_simple_async_result_new (G_OBJECT (cursor), callback, user_data, tracker_db_cursor_iter_next_async); 1818 g_simple_async_result_run_in_thread (res, tracker_db_cursor_iter_next_thread, 0, cancellable); 1819 g_object_unref (res); 1820 } 1821 1822 static gboolean 1823 tracker_db_cursor_iter_next_finish (TrackerDBCursor *cursor, 1824 GAsyncResult *res, 1825 GError **error) 1826 { 1827 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { 1828 return FALSE; 1829 } 1830 return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res)); 1831 } 1832 1833 static void 1834 tracker_db_cursor_class_init (TrackerDBCursorClass *class) 1835 { 1836 GObjectClass *object_class = G_OBJECT_CLASS (class); 1837 TrackerSparqlCursorClass *sparql_cursor_class = TRACKER_SPARQL_CURSOR_CLASS (class); 1838 1839 object_class->finalize = tracker_db_cursor_finalize; 1840 object_class->get_property = tracker_db_cursor_get_property; 1841 1842 sparql_cursor_class->get_value_type = (TrackerSparqlValueType (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_value_type; 1843 sparql_cursor_class->get_variable_name = (const gchar * (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_variable_name; 1844 sparql_cursor_class->get_n_columns = (gint (*) (TrackerSparqlCursor *)) tracker_db_cursor_get_n_columns; 1845 sparql_cursor_class->get_string = (const gchar * (*) (TrackerSparqlCursor *, gint, glong*)) tracker_db_cursor_get_string; 1846 sparql_cursor_class->next = (gboolean (*) (TrackerSparqlCursor *, GCancellable *, GError **)) tracker_db_cursor_iter_next; 1847 sparql_cursor_class->next_async = (void (*) (TrackerSparqlCursor *, GCancellable *, GAsyncReadyCallback, gpointer)) tracker_db_cursor_iter_next_async; 1848 sparql_cursor_class->next_finish = (gboolean (*) (TrackerSparqlCursor *, GAsyncResult *, GError **)) tracker_db_cursor_iter_next_finish; 1849 sparql_cursor_class->rewind = (void (*) (TrackerSparqlCursor *)) tracker_db_cursor_rewind; 1850 sparql_cursor_class->close = (void (*) (TrackerSparqlCursor *)) tracker_db_cursor_close; 1851 1852 sparql_cursor_class->get_integer = (gint64 (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_int; 1853 sparql_cursor_class->get_double = (gdouble (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_double; 1854 sparql_cursor_class->get_boolean = (gboolean (*) (TrackerSparqlCursor *, gint)) tracker_db_cursor_get_boolean; 1855 1856 g_object_class_override_property (object_class, TRACKER_DB_CURSOR_PROP_N_COLUMNS, "n-columns"); 1857 } 1858 1859 static TrackerDBCursor * 1860 tracker_db_cursor_sqlite_new (sqlite3_stmt *sqlite_stmt, 1861 TrackerDBStatement *ref_stmt, 1862 TrackerPropertyType *types, 1863 gint n_types, 1864 const gchar **variable_names, 1865 gint n_variable_names, 1866 gboolean threadsafe) 1867 { 1868 TrackerDBCursor *cursor; 1869 TrackerDBInterface *iface; 1870 1871 /* As soon as we create a cursor, check if we need a collator reset 1872 * and notify the iface about the new cursor */ 1873 iface = ref_stmt->db_interface; 1874 if (ATOMIC_EXCHANGE_AND_ADD (&iface->n_active_cursors, 1) == 0 && 1875 g_atomic_int_compare_and_exchange (&(iface->collator_reset_requested), TRUE, FALSE)) { 1876 tracker_db_interface_sqlite_reset_collator (iface); 1877 } 1878 1879 cursor = g_object_new (TRACKER_TYPE_DB_CURSOR, NULL); 1880 1881 cursor->finished = FALSE; 1882 1883 /* used for direct access as libtracker-sparql is thread-safe and 1884 uses a single shared connection with SQLite mutex disabled */ 1885 cursor->threadsafe = threadsafe; 1886 1887 cursor->stmt = sqlite_stmt; 1888 ref_stmt->stmt_is_sunk = TRUE; 1889 cursor->ref_stmt = g_object_ref (ref_stmt); 1890 1891 if (types) { 1892 gint i; 1893 1894 cursor->types = g_new (TrackerPropertyType, n_types); 1895 cursor->n_types = n_types; 1896 for (i = 0; i < n_types; i++) { 1897 cursor->types[i] = types[i]; 1898 } 1899 } 1900 1901 if (variable_names) { 1902 gint i; 1903 1904 cursor->variable_names = g_new (gchar *, n_variable_names); 1905 cursor->n_variable_names = n_variable_names; 1906 for (i = 0; i < n_variable_names; i++) { 1907 cursor->variable_names[i] = g_strdup (variable_names[i]); 1908 } 1909 } 1910 1911 return cursor; 1912 } 1913 1914 void 1915 tracker_db_statement_bind_double (TrackerDBStatement *stmt, 1916 int index, 1917 double value) 1918 { 1919 g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt)); 1920 1921 g_assert (!stmt->stmt_is_sunk); 1922 1923 sqlite3_bind_double (stmt->stmt, index + 1, value); 1924 } 1925 1926 void 1927 tracker_db_statement_bind_int (TrackerDBStatement *stmt, 1928 int index, 1929 gint64 value) 1930 { 1931 g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt)); 1932 1933 g_assert (!stmt->stmt_is_sunk); 1934 1935 sqlite3_bind_int64 (stmt->stmt, index + 1, value); 1936 } 1937 1938 void 1939 tracker_db_statement_bind_null (TrackerDBStatement *stmt, 1940 int index) 1941 { 1942 g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt)); 1943 1944 g_assert (!stmt->stmt_is_sunk); 1945 1946 sqlite3_bind_null (stmt->stmt, index + 1); 1947 } 1948 1949 void 1950 tracker_db_statement_bind_text (TrackerDBStatement *stmt, 1951 int index, 1952 const gchar *value) 1953 { 1954 g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt)); 1955 1956 g_assert (!stmt->stmt_is_sunk); 1957 1958 sqlite3_bind_text (stmt->stmt, index + 1, value, -1, SQLITE_TRANSIENT); 1959 } 1960 1961 void 1962 tracker_db_cursor_rewind (TrackerDBCursor *cursor) 1963 { 1964 g_return_if_fail (TRACKER_IS_DB_CURSOR (cursor)); 1965 1966 if (cursor->threadsafe) { 1967 tracker_db_manager_lock (); 1968 } 1969 1970 sqlite3_reset (cursor->stmt); 1971 cursor->finished = FALSE; 1972 1973 if (cursor->threadsafe) { 1974 tracker_db_manager_unlock (); 1975 } 1976 } 1977 1978 gboolean 1979 tracker_db_cursor_iter_next (TrackerDBCursor *cursor, 1980 GCancellable *cancellable, 1981 GError **error) 1982 { 1983 return db_cursor_iter_next (cursor, cancellable, error); 1984 } 1985 1986 1987 static gboolean 1988 db_cursor_iter_next (TrackerDBCursor *cursor, 1989 GCancellable *cancellable, 1990 GError **error) 1991 { 1992 TrackerDBStatement *stmt = cursor->ref_stmt; 1993 TrackerDBInterface *iface = stmt->db_interface; 1994 1995 if (!cursor->finished) { 1996 guint result; 1997 1998 if (cursor->threadsafe) { 1999 tracker_db_manager_lock (); 2000 } 2001 2002 if (g_cancellable_is_cancelled (cancellable)) { 2003 result = SQLITE_INTERRUPT; 2004 sqlite3_reset (cursor->stmt); 2005 } else { 2006 /* only one statement can be active at the same time per interface */ 2007 iface->cancellable = cancellable; 2008 result = stmt_step (cursor->stmt); 2009 iface->cancellable = NULL; 2010 } 2011 2012 if (result == SQLITE_INTERRUPT) { 2013 g_set_error (error, 2014 TRACKER_DB_INTERFACE_ERROR, 2015 TRACKER_DB_INTERRUPTED, 2016 "Interrupted"); 2017 } else if (result != SQLITE_ROW && result != SQLITE_DONE) { 2018 g_set_error (error, 2019 TRACKER_DB_INTERFACE_ERROR, 2020 TRACKER_DB_QUERY_ERROR, 2021 "%s", sqlite3_errmsg (iface->db)); 2022 } 2023 2024 cursor->finished = (result != SQLITE_ROW); 2025 2026 if (cursor->threadsafe) { 2027 tracker_db_manager_unlock (); 2028 } 2029 } 2030 2031 return (!cursor->finished); 2032 } 2033 2034 guint 2035 tracker_db_cursor_get_n_columns (TrackerDBCursor *cursor) 2036 { 2037 return sqlite3_column_count (cursor->stmt); 2038 } 2039 2040 void 2041 tracker_db_cursor_get_value (TrackerDBCursor *cursor, 2042 guint column, 2043 GValue *value) 2044 { 2045 gint col_type; 2046 2047 col_type = sqlite3_column_type (cursor->stmt, column); 2048 2049 switch (col_type) { 2050 case SQLITE_TEXT: 2051 g_value_init (value, G_TYPE_STRING); 2052 g_value_set_string (value, (gchar *) sqlite3_column_text (cursor->stmt, column)); 2053 break; 2054 case SQLITE_INTEGER: 2055 g_value_init (value, G_TYPE_INT64); 2056 g_value_set_int64 (value, sqlite3_column_int64 (cursor->stmt, column)); 2057 break; 2058 case SQLITE_FLOAT: 2059 g_value_init (value, G_TYPE_DOUBLE); 2060 g_value_set_double (value, sqlite3_column_double (cursor->stmt, column)); 2061 break; 2062 case SQLITE_NULL: 2063 /* just ignore NULLs */ 2064 break; 2065 default: 2066 g_critical ("Unknown sqlite3 database column type:%d", col_type); 2067 } 2068 2069 } 2070 2071 gint64 2072 tracker_db_cursor_get_int (TrackerDBCursor *cursor, 2073 guint column) 2074 { 2075 gint64 result; 2076 2077 if (cursor->threadsafe) { 2078 tracker_db_manager_lock (); 2079 } 2080 2081 result = (gint64) sqlite3_column_int64 (cursor->stmt, column); 2082 2083 if (cursor->threadsafe) { 2084 tracker_db_manager_unlock (); 2085 } 2086 2087 return result; 2088 } 2089 2090 gdouble 2091 tracker_db_cursor_get_double (TrackerDBCursor *cursor, 2092 guint column) 2093 { 2094 gdouble result; 2095 2096 if (cursor->threadsafe) { 2097 tracker_db_manager_lock (); 2098 } 2099 2100 result = (gdouble) sqlite3_column_double (cursor->stmt, column); 2101 2102 if (cursor->threadsafe) { 2103 tracker_db_manager_unlock (); 2104 } 2105 2106 return result; 2107 } 2108 2109 static gboolean 2110 tracker_db_cursor_get_boolean (TrackerSparqlCursor *sparql_cursor, 2111 guint column) 2112 { 2113 TrackerDBCursor *cursor = (TrackerDBCursor *) sparql_cursor; 2114 return (g_strcmp0 (tracker_db_cursor_get_string (cursor, column, NULL), "true") == 0); 2115 } 2116 2117 TrackerSparqlValueType 2118 tracker_db_cursor_get_value_type (TrackerDBCursor *cursor, 2119 guint column) 2120 { 2121 gint column_type; 2122 gint n_columns = sqlite3_column_count (cursor->stmt); 2123 2124 g_return_val_if_fail (column < n_columns, TRACKER_SPARQL_VALUE_TYPE_UNBOUND); 2125 2126 if (cursor->threadsafe) { 2127 tracker_db_manager_lock (); 2128 } 2129 2130 column_type = sqlite3_column_type (cursor->stmt, column); 2131 2132 if (cursor->threadsafe) { 2133 tracker_db_manager_unlock (); 2134 } 2135 2136 if (column_type == SQLITE_NULL) { 2137 return TRACKER_SPARQL_VALUE_TYPE_UNBOUND; 2138 } else if (column < cursor->n_types) { 2139 switch (cursor->types[column]) { 2140 case TRACKER_PROPERTY_TYPE_RESOURCE: 2141 return TRACKER_SPARQL_VALUE_TYPE_URI; 2142 case TRACKER_PROPERTY_TYPE_INTEGER: 2143 return TRACKER_SPARQL_VALUE_TYPE_INTEGER; 2144 case TRACKER_PROPERTY_TYPE_DOUBLE: 2145 return TRACKER_SPARQL_VALUE_TYPE_DOUBLE; 2146 case TRACKER_PROPERTY_TYPE_DATETIME: 2147 return TRACKER_SPARQL_VALUE_TYPE_DATETIME; 2148 case TRACKER_PROPERTY_TYPE_BOOLEAN: 2149 return TRACKER_SPARQL_VALUE_TYPE_BOOLEAN; 2150 default: 2151 return TRACKER_SPARQL_VALUE_TYPE_STRING; 2152 } 2153 } else { 2154 return TRACKER_SPARQL_VALUE_TYPE_STRING; 2155 } 2156 } 2157 2158 const gchar* 2159 tracker_db_cursor_get_variable_name (TrackerDBCursor *cursor, 2160 guint column) 2161 { 2162 const gchar *result; 2163 2164 if (cursor->threadsafe) { 2165 tracker_db_manager_lock (); 2166 } 2167 2168 if (column < cursor->n_variable_names) { 2169 result = cursor->variable_names[column]; 2170 } else { 2171 result = sqlite3_column_name (cursor->stmt, column); 2172 } 2173 2174 if (cursor->threadsafe) { 2175 tracker_db_manager_unlock (); 2176 } 2177 2178 return result; 2179 } 2180 2181 const gchar* 2182 tracker_db_cursor_get_string (TrackerDBCursor *cursor, 2183 guint column, 2184 glong *length) 2185 { 2186 const gchar *result; 2187 2188 if (cursor->threadsafe) { 2189 tracker_db_manager_lock (); 2190 } 2191 2192 if (length) { 2193 sqlite3_value *val = sqlite3_column_value (cursor->stmt, column); 2194 2195 *length = sqlite3_value_bytes (val); 2196 result = (const gchar *) sqlite3_value_text (val); 2197 } else { 2198 result = (const gchar *) sqlite3_column_text (cursor->stmt, column); 2199 } 2200 2201 if (cursor->threadsafe) { 2202 tracker_db_manager_unlock (); 2203 } 2204 2205 return result; 2206 } 2207 2208 void 2209 tracker_db_statement_execute (TrackerDBStatement *stmt, 2210 GError **error) 2211 { 2212 g_return_if_fail (!stmt->stmt_is_sunk); 2213 2214 execute_stmt (stmt->db_interface, stmt->stmt, NULL, error); 2215 } 2216 2217 TrackerDBCursor * 2218 tracker_db_statement_start_cursor (TrackerDBStatement *stmt, 2219 GError **error) 2220 { 2221 g_return_val_if_fail (!stmt->stmt_is_sunk, NULL); 2222 2223 return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, NULL, 0, NULL, 0, FALSE); 2224 } 2225 2226 TrackerDBCursor * 2227 tracker_db_statement_start_sparql_cursor (TrackerDBStatement *stmt, 2228 TrackerPropertyType *types, 2229 gint n_types, 2230 const gchar **variable_names, 2231 gint n_variable_names, 2232 gboolean threadsafe, 2233 GError **error) 2234 { 2235 g_return_val_if_fail (!stmt->stmt_is_sunk, NULL); 2236 2237 return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, types, n_types, variable_names, n_variable_names, threadsafe); 2238 } 2239 2240 static void 2241 tracker_db_statement_init (TrackerDBStatement *stmt) 2242 { 2243 } 2244 2245 static void 2246 tracker_db_cursor_init (TrackerDBCursor *cursor) 2247 { 2248 } 2249 2250 static void 2251 tracker_db_statement_sqlite_reset (TrackerDBStatement *stmt) 2252 { 2253 g_assert (!stmt->stmt_is_sunk); 2254 2255 sqlite3_reset (stmt->stmt); 2256 sqlite3_clear_bindings (stmt->stmt); 2257 }