1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* e-book-backend-sqlitedb.c
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6 * Authors: Chenthill Palanisamy <pchenthill@novell.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU Lesser General Public
10 * License as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
31 #include <libebackend/libebackend.h>
33 #include "e-book-backend-sexp.h"
34 #include "e-book-backend-sqlitedb.h"
36 #define E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_BOOK_BACKEND_SQLITEDB, EBookBackendSqliteDBPrivate))
42 #define DB_FILENAME "contacts.db"
43 #define FOLDER_VERSION 3
45 #define READER_LOCK(ebsdb) g_rw_lock_reader_lock (&ebsdb->priv->rwlock)
46 #define READER_UNLOCK(ebsdb) g_rw_lock_reader_unlock (&ebsdb->priv->rwlock)
47 #define WRITER_LOCK(ebssdb) g_rw_lock_writer_lock (&ebsdb->priv->rwlock)
48 #define WRITER_UNLOCK(ebssdb) g_rw_lock_writer_unlock (&ebsdb->priv->rwlock)
51 INDEX_PREFIX = (1 << 0),
52 INDEX_SUFFIX = (1 << 1)
56 EContactField field; /* The EContact field */
57 GType type; /* The GType (only support string or gboolean) */
58 const gchar *dbname; /* The key for this field in the sqlite3 table */
59 IndexFlags index; /* Whether this summary field should have an index in the SQLite DB */
62 struct _EBookBackendSqliteDBPrivate {
70 GMutex in_transaction_lock;
71 guint32 in_transaction;
73 SummaryField *summary_fields;
74 gint n_summary_fields;
75 guint have_attr_list : 1;
76 guint have_attr_list_prefix : 1;
77 guint have_attr_list_suffix : 1;
80 G_DEFINE_TYPE (EBookBackendSqliteDB, e_book_backend_sqlitedb, G_TYPE_OBJECT)
83 static GHashTable *db_connections = NULL;
84 static GMutex dbcon_lock;
86 static EContactField default_summary_fields[] = {
93 E_CONTACT_FAMILY_NAME,
96 E_CONTACT_LIST_SHOW_ADDRESSES,
100 /* Create indexes on full_name and email fields as autocompletion queries would mainly
103 static EContactField default_indexed_fields[] = {
108 static EBookIndexType default_index_types[] = {
113 static gboolean append_summary_field (GArray *array,
115 gboolean *have_attr_list,
119 summary_dbname_from_field (EBookBackendSqliteDB *ebsdb,
124 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
125 if (ebsdb->priv->summary_fields[i].field == field)
126 return ebsdb->priv->summary_fields[i].dbname;
133 summary_index_from_field_name (EBookBackendSqliteDB *ebsdb,
134 const gchar *field_name)
139 field = e_contact_field_id (field_name);
141 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
142 if (ebsdb->priv->summary_fields[i].field == field)
150 EBookBackendSqliteDB *ebsdb;
155 e-book-backend-sqlitedb-error-quark,
156 e_book_backend_sqlitedb_error)
159 e_book_backend_sqlitedb_dispose (GObject *object)
161 EBookBackendSqliteDBPrivate *priv;
163 priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
165 g_mutex_lock (&dbcon_lock);
166 if (db_connections != NULL) {
167 if (priv->hash_key != NULL) {
168 g_hash_table_remove (db_connections, priv->hash_key);
170 if (g_hash_table_size (db_connections) == 0) {
171 g_hash_table_destroy (db_connections);
172 db_connections = NULL;
175 g_free (priv->hash_key);
176 priv->hash_key = NULL;
179 g_mutex_unlock (&dbcon_lock);
181 /* Chain up to parent's dispose() method. */
182 G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->dispose (object);
186 e_book_backend_sqlitedb_finalize (GObject *object)
188 EBookBackendSqliteDBPrivate *priv;
190 priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
192 g_rw_lock_clear (&priv->rwlock);
194 sqlite3_close (priv->db);
197 g_free (priv->summary_fields);
199 g_mutex_clear (&priv->in_transaction_lock);
201 /* Chain up to parent's finalize() method. */
202 G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->finalize (object);
206 e_book_backend_sqlitedb_class_init (EBookBackendSqliteDBClass *class)
208 GObjectClass *object_class;
210 g_type_class_add_private (class, sizeof (EBookBackendSqliteDBPrivate));
212 object_class = G_OBJECT_CLASS (class);
213 object_class->dispose = e_book_backend_sqlitedb_dispose;
214 object_class->finalize = e_book_backend_sqlitedb_finalize;
218 e_book_backend_sqlitedb_init (EBookBackendSqliteDB *ebsdb)
220 ebsdb->priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (ebsdb);
222 ebsdb->priv->store_vcard = TRUE;
223 g_rw_lock_init (&ebsdb->priv->rwlock);
225 ebsdb->priv->in_transaction = 0;
226 g_mutex_init (&ebsdb->priv->in_transaction_lock);
230 get_string_cb (gpointer ref,
237 *ret = g_strdup (cols [0]);
243 get_bool_cb (gpointer ref,
250 *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
263 * Callers should hold the rw lock depending on read or write operation
267 book_backend_sql_exec_real (sqlite3 *db,
269 gint (*callback)(gpointer ,gint,gchar **,gchar **),
273 gchar *errmsg = NULL;
276 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
277 while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
279 sqlite3_free (errmsg);
283 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
286 if (ret != SQLITE_OK) {
287 d (g_print ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
288 g_set_error_literal (
289 error, E_BOOK_SDB_ERROR,
290 ret == SQLITE_CONSTRAINT ?
291 E_BOOK_SDB_ERROR_CONSTRAINT : E_BOOK_SDB_ERROR_OTHER,
293 sqlite3_free (errmsg);
299 sqlite3_free (errmsg);
307 print_debug_cb (gpointer ref,
314 g_print (" DEBUG BEGIN: %d results\n", col);
316 for (i = 0; i < col; i++)
317 g_print (" NAME: '%s' COL: %s\n", name[i], cols[i]);
319 g_print (" DEBUG END\n");
325 book_backend_sql_debug (sqlite3 *db,
327 gint (*callback)(gpointer ,gint,gchar **,gchar **),
332 GError *local_error = NULL;
333 debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
335 g_print ("DEBUG STATEMENT: %s\n", stmt);
336 book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
337 g_print ("DEBUG STATEMENT END: %s%s\n", local_error ? "Error: " : "", local_error ? local_error->message : "Success");
340 g_clear_error (&local_error);
344 book_backend_sql_exec (sqlite3 *db,
346 gint (*callback)(gpointer ,gint,gchar **,gchar **),
350 static gint booksql_debug = -1;
352 if (booksql_debug == -1) {
353 booksql_debug = g_getenv ("BOOKSQL_DEBUG") != NULL ? 1 : 0;
357 book_backend_sql_debug (db, stmt, callback, data, error);
359 return book_backend_sql_exec_real (db, stmt, callback, data, error);
362 /* the first caller holds the writer lock too */
364 book_backend_sqlitedb_start_transaction (EBookBackendSqliteDB *ebsdb,
367 gboolean success = TRUE;
369 g_return_val_if_fail (ebsdb != NULL, FALSE);
370 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
371 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
373 g_mutex_lock (&ebsdb->priv->in_transaction_lock);
375 ebsdb->priv->in_transaction++;
376 if (ebsdb->priv->in_transaction == 0) {
377 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
379 g_return_val_if_fail (ebsdb->priv->in_transaction != 0, FALSE);
383 if (ebsdb->priv->in_transaction == 1) {
386 success = book_backend_sql_exec (
387 ebsdb->priv->db, "BEGIN", NULL, NULL, error);
390 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
395 /* the last caller releases the writer lock too */
397 book_backend_sqlitedb_commit_transaction (EBookBackendSqliteDB *ebsdb,
400 gboolean success = TRUE;
402 g_return_val_if_fail (ebsdb != NULL, FALSE);
403 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
404 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
406 g_mutex_lock (&ebsdb->priv->in_transaction_lock);
408 if (ebsdb->priv->in_transaction == 0) {
409 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
411 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
415 ebsdb->priv->in_transaction--;
417 if (ebsdb->priv->in_transaction == 0) {
418 success = book_backend_sql_exec (
419 ebsdb->priv->db, "COMMIT", NULL, NULL, error);
421 WRITER_UNLOCK (ebsdb);
424 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
429 /* the last caller releases the writer lock too */
431 book_backend_sqlitedb_rollback_transaction (EBookBackendSqliteDB *ebsdb,
434 gboolean success = TRUE;
436 g_return_val_if_fail (ebsdb != NULL, FALSE);
437 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
438 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
440 g_mutex_lock (&ebsdb->priv->in_transaction_lock);
442 if (ebsdb->priv->in_transaction == 0) {
443 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
445 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
449 ebsdb->priv->in_transaction--;
451 if (ebsdb->priv->in_transaction == 0) {
452 success = book_backend_sql_exec (
453 ebsdb->priv->db, "ROLLBACK", NULL, NULL, error);
455 WRITER_UNLOCK (ebsdb);
458 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
464 collect_versions_cb (gpointer ref,
471 /* Just collect the first result, all folders
472 * should always have the same DB version. */
473 *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
479 create_folders_table (EBookBackendSqliteDB *ebsdb,
485 /* sync_data points to syncronization data, it could be last_modified
486 * time or a sequence number or some text depending on the backend.
488 * partial_content says whether the contents are partially downloaded
489 * for auto-completion or if it has the complete content.
491 * Have not included a bdata here since the keys table should suffice
492 * any additional need that arises.
495 "CREATE TABLE IF NOT EXISTS folders"
496 "( folder_id TEXT PRIMARY KEY,"
499 " is_populated INTEGER,"
500 " partial_content INTEGER,"
504 " reverse_multivalues INTEGER )";
506 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
509 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
512 /* Create a child table to store key/value pairs for a folder. */
513 stmt = "CREATE TABLE IF NOT EXISTS keys"
514 "( key TEXT PRIMARY KEY, value TEXT,"
515 " folder_id TEXT REFERENCES folders)";
516 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
519 stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
520 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
523 /* Fetch the version, it should be the
524 * same for all folders (hence the LIMIT). */
525 stmt = "SELECT version FROM folders LIMIT 1";
526 success = book_backend_sql_exec (
527 ebsdb->priv->db, stmt, collect_versions_cb, &version, error);
532 /* Upgrade DB to version 2, add revision column
534 * (version = 0 indicates that it did not exist and we just
537 if (version >= 1 && version < 2) {
538 stmt = "ALTER TABLE folders ADD COLUMN revision TEXT";
539 success = book_backend_sql_exec (
540 ebsdb->priv->db, stmt, NULL, NULL, error);
546 /* Upgrade DB to version 3, add multivalues introspection columns
548 if (version >= 1 && version < 3) {
550 stmt = "ALTER TABLE folders ADD COLUMN multivalues TEXT";
551 success = book_backend_sql_exec (
552 ebsdb->priv->db, stmt, NULL, NULL, error);
557 stmt = "ALTER TABLE folders ADD COLUMN reverse_multivalues INTEGER";
558 success = book_backend_sql_exec (
559 ebsdb->priv->db, stmt, NULL, NULL, error);
565 if (version >= 1 && version < FOLDER_VERSION) {
566 gchar *version_update_stmt =
567 sqlite3_mprintf ("UPDATE folders SET version = %d", FOLDER_VERSION);
569 success = book_backend_sql_exec (
570 ebsdb->priv->db, version_update_stmt, NULL, NULL, error);
572 sqlite3_free (version_update_stmt);
578 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
581 /* The GError is already set. */
582 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
588 format_multivalues (EBookBackendSqliteDB *ebsdb,
589 gboolean *reverse_multivalues)
593 gboolean first = TRUE;
594 gboolean has_reverse = FALSE;
596 string = g_string_new (NULL);
598 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
599 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
603 g_string_append_c (string, ':');
605 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
607 if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
612 if (reverse_multivalues)
613 *reverse_multivalues = has_reverse;
615 return g_string_free (string, FALSE);
619 add_folder_into_db (EBookBackendSqliteDB *ebsdb,
620 const gchar *folderid,
621 const gchar *folder_name,
626 gboolean has_reverse = FALSE;
629 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
632 multivalues = format_multivalues (ebsdb, &has_reverse);
634 stmt = sqlite3_mprintf (
635 "INSERT OR IGNORE INTO folders VALUES "
636 "( %Q, %Q, %Q, %d, %d, %d, %Q, %Q, %d ) ",
637 folderid, folder_name, NULL, 0, 0, FOLDER_VERSION,
638 NULL, multivalues, has_reverse);
639 success = book_backend_sql_exec (
640 ebsdb->priv->db, stmt, NULL, NULL, error);
642 g_free (multivalues);
647 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
650 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
656 collect_columns_cb (gpointer ref,
661 GList **columns = (GList **) ref;
664 for (i = 0; i < col; i++) {
666 if (strcmp (name[i], "name") == 0) {
668 if (strcmp (cols[i], "vcard") != 0 &&
669 strcmp (cols[i], "bdata") != 0) {
671 gchar *column = g_strdup (cols[i]);
673 *columns = g_list_prepend (*columns, column);
684 introspect_summary (EBookBackendSqliteDB *ebsdb,
685 const gchar *folderid,
690 GList *summary_columns = NULL, *l;
691 GArray *summary_fields = NULL;
692 gchar *multivalues = NULL;
693 gboolean reverse_multivalues = FALSE;
697 stmt = sqlite3_mprintf ("PRAGMA table_info (%Q);", folderid);
698 success = book_backend_sql_exec (
699 ebsdb->priv->db, stmt, collect_columns_cb, &summary_columns, error);
703 goto introspect_summary_finish;
705 summary_columns = g_list_reverse (summary_columns);
706 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
708 /* Introspect the normal summary fields */
709 for (l = summary_columns; l; l = l->next) {
711 gchar *col = l->data;
713 gboolean reverse = FALSE;
715 /* Check if we're parsing a reverse field */
716 p = strstr (col, "_reverse");
722 /* First check exception fields */
723 if (g_ascii_strcasecmp (col, "uid") == 0)
724 field = E_CONTACT_UID;
725 else if (g_ascii_strcasecmp (col, "is_list") == 0)
726 field = E_CONTACT_IS_LIST;
728 field = e_contact_field_id (col);
730 /* Check for parse error */
733 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
734 _("Error introspecting unknown summary field '%s'"), col);
739 /* Reverse columns are always declared after the normal columns,
740 * if a reverse field is encountered we need to set the suffix
741 * index on the coresponding summary field
744 for (i = 0; i < summary_fields->len; i++) {
745 SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
747 if (iter->field == field) {
748 iter->index |= INDEX_SUFFIX;
753 append_summary_field (summary_fields, field, NULL, NULL);
758 goto introspect_summary_finish;
760 /* Introspect the multivalied summary fields */
761 stmt = sqlite3_mprintf (
762 "SELECT multivalues FROM folders WHERE folder_id = %Q", folderid);
763 success = book_backend_sql_exec (
764 ebsdb->priv->db, stmt, get_string_cb, &multivalues, error);
768 goto introspect_summary_finish;
770 stmt = sqlite3_mprintf (
771 "SELECT reverse_multivalues FROM folders WHERE folder_id = %Q", folderid);
772 success = book_backend_sql_exec (
773 ebsdb->priv->db, stmt, get_bool_cb, &reverse_multivalues, error);
777 goto introspect_summary_finish;
780 split = g_strsplit (multivalues, ":", 0);
782 for (i = 0; split[i] != NULL; i++) {
785 field = e_contact_field_id (split[i]);
786 append_summary_field (summary_fields, field, NULL, NULL);
791 /* If there is a reverse multivalue column, enable lookups for every multivalue field in reverse */
792 if (reverse_multivalues) {
794 for (i = 0; i < summary_fields->len; i++) {
795 SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
797 if (iter->type == E_TYPE_CONTACT_ATTR_LIST)
798 iter->index |= INDEX_SUFFIX;
802 introspect_summary_finish:
804 g_list_free_full (summary_columns, (GDestroyNotify) g_free);
805 g_free (multivalues);
807 /* Apply the introspected summary fields */
809 g_free (ebsdb->priv->summary_fields);
810 ebsdb->priv->n_summary_fields = summary_fields->len;
811 ebsdb->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
812 } else if (summary_fields) {
813 g_array_free (summary_fields, TRUE);
819 /* The column names match the fields used in book-backend-sexp */
821 create_contacts_table (EBookBackendSqliteDB *ebsdb,
822 const gchar *folderid,
830 /* Construct the create statement from the summary fields table */
831 string = g_string_new (
832 "CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
834 for (i = 1; i < ebsdb->priv->n_summary_fields; i++) {
835 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
836 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
837 g_string_append (string, " TEXT, ");
838 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
839 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
840 g_string_append (string, " INTEGER, ");
841 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
842 g_warn_if_reached ();
844 /* Additional columns holding normalized reverse values for suffix matching */
845 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING &&
846 (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
847 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
848 g_string_append (string, "_reverse TEXT, ");
851 g_string_append (string, "vcard TEXT, bdata TEXT)");
853 stmt = sqlite3_mprintf (string->str, folderid);
854 g_string_free (string, TRUE);
858 success = book_backend_sql_exec (
859 ebsdb->priv->db, stmt, NULL, NULL , error);
863 /* Create indexes on the summary fields configured for indexing */
864 for (i = 0; success && i < ebsdb->priv->n_summary_fields; i++) {
865 if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0 &&
866 ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
867 /* Derive index name from field & folder */
868 tmp = g_strdup_printf (
870 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
872 stmt = sqlite3_mprintf (
873 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
874 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
875 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
881 (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
882 ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
883 /* Derive index name from field & folder */
884 tmp = g_strdup_printf (
886 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
888 stmt = sqlite3_mprintf (
889 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, folderid,
890 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
891 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
897 /* Construct the create statement from the attribute list summary table */
898 if (success && ebsdb->priv->have_attr_list) {
899 string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT NOT NULL REFERENCES %Q(uid), "
900 "field TEXT, value TEXT");
902 if (ebsdb->priv->have_attr_list_suffix)
903 g_string_append (string, ", value_reverse TEXT");
905 g_string_append_c (string, ')');
907 tmp = g_strdup_printf ("%s_lists", folderid);
908 stmt = sqlite3_mprintf (string->str, tmp, folderid);
909 g_string_free (string, TRUE);
911 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
914 /* Give the UID an index in this table, always */
915 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS LISTINDEX ON %Q (uid)", tmp);
916 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
919 /* Create indexes if specified */
920 if (success && ebsdb->priv->have_attr_list_prefix) {
921 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS VALINDEX ON %Q (value)", tmp);
922 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
926 if (success && ebsdb->priv->have_attr_list_suffix) {
927 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS RVALINDEX ON %Q (value_reverse)", tmp);
928 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
936 WRITER_UNLOCK (ebsdb);
939 success = introspect_summary (ebsdb, folderid, error);
945 book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb,
946 const gchar *filename,
951 e_sqlite3_vfs_init ();
953 ret = sqlite3_open (filename, &ebsdb->priv->db);
955 if (!ebsdb->priv->db) {
957 error, E_BOOK_SDB_ERROR,
958 E_BOOK_SDB_ERROR_OTHER,
959 _("Insufficient memory"));
962 errmsg = sqlite3_errmsg (ebsdb->priv->db);
963 d (g_print ("Can't open database %s: %s\n", path, errmsg));
964 g_set_error_literal (
965 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER, errmsg);
966 sqlite3_close (ebsdb->priv->db);
973 book_backend_sql_exec (
975 "ATTACH DATABASE ':memory:' AS mem",
977 book_backend_sql_exec (
979 "PRAGMA foreign_keys = ON",
981 book_backend_sql_exec (
983 "PRAGMA case_sensitive_like = ON",
986 WRITER_UNLOCK (ebsdb);
988 return create_folders_table (ebsdb, error);
991 static EBookBackendSqliteDB *
992 e_book_backend_sqlitedb_new_internal (const gchar *path,
993 const gchar *emailid,
994 const gchar *folderid,
995 const gchar *folder_name,
996 gboolean store_vcard,
997 SummaryField *fields,
999 gboolean have_attr_list,
1000 gboolean have_attr_list_prefix,
1001 gboolean have_attr_list_suffix,
1004 EBookBackendSqliteDB *ebsdb;
1005 gchar *hash_key, *filename;
1007 g_return_val_if_fail (path != NULL, NULL);
1008 g_return_val_if_fail (emailid != NULL, NULL);
1009 g_return_val_if_fail (folderid != NULL, NULL);
1010 g_return_val_if_fail (folder_name != NULL, NULL);
1012 g_mutex_lock (&dbcon_lock);
1014 hash_key = g_strdup_printf ("%s@%s", emailid, path);
1015 if (db_connections != NULL) {
1016 ebsdb = g_hash_table_lookup (db_connections, hash_key);
1019 g_object_ref (ebsdb);
1020 g_mutex_unlock (&dbcon_lock);
1026 ebsdb = g_object_new (E_TYPE_BOOK_BACKEND_SQLITEDB, NULL);
1027 ebsdb->priv->path = g_strdup (path);
1028 ebsdb->priv->summary_fields = fields;
1029 ebsdb->priv->n_summary_fields = n_fields;
1030 ebsdb->priv->have_attr_list = have_attr_list;
1031 ebsdb->priv->have_attr_list_prefix = have_attr_list_prefix;
1032 ebsdb->priv->have_attr_list_suffix = have_attr_list_suffix;
1033 ebsdb->priv->store_vcard = store_vcard;
1034 if (g_mkdir_with_parents (path, 0777) < 0) {
1035 g_mutex_unlock (&dbcon_lock);
1037 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1038 "Can not make parent directory: errno %d", errno);
1041 filename = g_build_filename (path, DB_FILENAME, NULL);
1043 if (!book_backend_sqlitedb_load (ebsdb, filename, error)) {
1044 g_mutex_unlock (&dbcon_lock);
1045 g_object_unref (ebsdb);
1051 if (db_connections == NULL)
1052 db_connections = g_hash_table_new_full (
1053 (GHashFunc) g_str_hash,
1054 (GEqualFunc) g_str_equal,
1055 (GDestroyNotify) g_free,
1056 (GDestroyNotify) NULL);
1057 g_hash_table_insert (db_connections, hash_key, ebsdb);
1058 ebsdb->priv->hash_key = g_strdup (hash_key);
1060 g_mutex_unlock (&dbcon_lock);
1063 if (!add_folder_into_db (ebsdb, folderid, folder_name, error)) {
1064 g_object_unref (ebsdb);
1068 if (!create_contacts_table (ebsdb, folderid, error)) {
1069 g_object_unref (ebsdb);
1077 append_summary_field (GArray *array,
1078 EContactField field,
1079 gboolean *have_attr_list,
1082 const gchar *dbname = NULL;
1083 GType type = G_TYPE_INVALID;
1085 SummaryField new_field = { 0, };
1087 if (field < 1 || field >= E_CONTACT_FIELD_LAST) {
1089 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1090 _("Invalid contact field '%d' specified in summary"), field);
1094 /* Avoid including the same field twice in the summary */
1095 for (i = 0; i < array->len; i++) {
1096 SummaryField *iter = &g_array_index (array, SummaryField, i);
1097 if (field == iter->field)
1101 /* Resolve some exceptions, we store these
1102 * specific contact fields with different names
1103 * than those found in the EContactField table
1109 case E_CONTACT_IS_LIST:
1113 dbname = e_contact_field_name (field);
1117 type = e_contact_field_type (field);
1119 if (type != G_TYPE_STRING &&
1120 type != G_TYPE_BOOLEAN &&
1121 type != E_TYPE_CONTACT_ATTR_LIST) {
1123 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1124 _("Contact field '%s' of type '%s' specified in summary, "
1125 "but only boolean, string and string list field types are supported"),
1126 e_contact_pretty_name (field), g_type_name (type));
1130 if (type == E_TYPE_CONTACT_ATTR_LIST && have_attr_list)
1131 *have_attr_list = TRUE;
1133 new_field.field = field;
1134 new_field.dbname = dbname;
1135 new_field.type = type;
1136 g_array_append_val (array, new_field);
1142 summary_fields_add_indexes (GArray *array,
1143 EContactField *indexes,
1144 EBookIndexType *index_types,
1146 gboolean *have_attr_list_prefix,
1147 gboolean *have_attr_list_suffix)
1151 for (i = 0; i < array->len; i++) {
1152 SummaryField *sfield = &g_array_index (array, SummaryField, i);
1154 for (j = 0; j < n_indexes; j++) {
1155 if (sfield->field == indexes[j]) {
1156 switch (index_types[j]) {
1157 case E_BOOK_INDEX_PREFIX:
1158 sfield->index |= INDEX_PREFIX;
1160 if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1161 *have_attr_list_prefix = TRUE;
1163 case E_BOOK_INDEX_SUFFIX:
1164 sfield->index |= INDEX_SUFFIX;
1166 if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1167 *have_attr_list_suffix = TRUE;
1170 g_warn_if_reached ();
1179 * e_book_backend_sqlitedb_new_full:
1180 * @path: location where the db would be created
1181 * @emailid: email id of the user
1182 * @folderid: folder id of the address-book
1183 * @folder_name: name of the address-book
1184 * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1185 * @setup: an #ESourceBackendSummarySetup describing how the summary should be setup
1186 * @error: A location to store any error that may have occurred
1188 * Like e_book_backend_sqlitedb_new(), but allows configuration of which contact fields
1189 * will be stored for quick reference in the summary. The configuration indicated by
1190 * @setup will only be taken into account when initially creating the underlying table,
1191 * further configurations will be ignored.
1193 * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
1194 * they will be stored in the summary regardless of this function's parameters
1196 * <note><para>Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
1197 * #E_TYPE_CONTACT_ATTR_LIST are currently supported.</para></note>
1199 * Returns: (transfer full): The newly created #EBookBackendSqliteDB
1203 EBookBackendSqliteDB *
1204 e_book_backend_sqlitedb_new_full (const gchar *path,
1205 const gchar *emailid,
1206 const gchar *folderid,
1207 const gchar *folder_name,
1208 gboolean store_vcard,
1209 ESourceBackendSummarySetup *setup,
1212 EBookBackendSqliteDB *ebsdb = NULL;
1213 EContactField *fields;
1214 EContactField *indexed_fields;
1215 EBookIndexType *index_types = NULL;
1216 gboolean have_attr_list = FALSE;
1217 gboolean have_attr_list_prefix = FALSE;
1218 gboolean have_attr_list_suffix = FALSE;
1219 gboolean had_error = FALSE;
1220 GArray *summary_fields;
1221 gint n_fields = 0, n_indexed_fields = 0, i;
1223 fields = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
1224 indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
1226 /* No specified summary fields indicates the default summary configuration should be used */
1227 if (n_fields <= 0) {
1228 ebsdb = e_book_backend_sqlitedb_new (path, emailid, folderid, folder_name, store_vcard, error);
1230 g_free (index_types);
1231 g_free (indexed_fields);
1236 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1238 /* Ensure the non-optional fields first */
1239 append_summary_field (summary_fields, E_CONTACT_UID, &have_attr_list, error);
1240 append_summary_field (summary_fields, E_CONTACT_REV, &have_attr_list, error);
1242 for (i = 0; i < n_fields; i++) {
1243 if (!append_summary_field (summary_fields, fields[i], &have_attr_list, error)) {
1250 g_array_free (summary_fields, TRUE);
1252 g_free (index_types);
1253 g_free (indexed_fields);
1257 /* Add the 'indexed' flag to the SummaryField structs */
1258 summary_fields_add_indexes (
1259 summary_fields, indexed_fields, index_types, n_indexed_fields,
1260 &have_attr_list_prefix, &have_attr_list_suffix);
1262 ebsdb = e_book_backend_sqlitedb_new_internal (
1263 path, emailid, folderid, folder_name,
1265 (SummaryField *) summary_fields->data,
1266 summary_fields->len,
1268 have_attr_list_prefix,
1269 have_attr_list_suffix,
1273 g_free (index_types);
1274 g_free (indexed_fields);
1275 g_array_free (summary_fields, FALSE);
1281 * e_book_backend_sqlitedb_new
1282 * @path: location where the db would be created
1283 * @emailid: email id of the user
1284 * @folderid: folder id of the address-book
1285 * @folder_name: name of the address-book
1286 * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1289 * If the path for multiple addressbooks are same, the contacts from all addressbooks
1290 * would be stored in same db in different tables.
1296 EBookBackendSqliteDB *
1297 e_book_backend_sqlitedb_new (const gchar *path,
1298 const gchar *emailid,
1299 const gchar *folderid,
1300 const gchar *folder_name,
1301 gboolean store_vcard,
1304 EBookBackendSqliteDB *ebsdb;
1305 GArray *summary_fields;
1306 gboolean have_attr_list = FALSE;
1307 gboolean have_attr_list_prefix = FALSE;
1308 gboolean have_attr_list_suffix = FALSE;
1311 /* Create the default summary structs */
1312 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1313 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
1314 append_summary_field (summary_fields, default_summary_fields[i], &have_attr_list, NULL);
1316 /* Add the default index flags */
1317 summary_fields_add_indexes (
1319 default_indexed_fields,
1320 default_index_types,
1321 G_N_ELEMENTS (default_indexed_fields),
1322 &have_attr_list_prefix, &have_attr_list_suffix);
1324 ebsdb = e_book_backend_sqlitedb_new_internal (
1325 path, emailid, folderid, folder_name,
1327 (SummaryField *) summary_fields->data,
1328 summary_fields->len,
1330 have_attr_list_prefix,
1331 have_attr_list_suffix,
1333 g_array_free (summary_fields, FALSE);
1339 e_book_backend_sqlitedb_lock_updates (EBookBackendSqliteDB *ebsdb,
1342 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1344 return book_backend_sqlitedb_start_transaction (ebsdb, error);
1348 e_book_backend_sqlitedb_unlock_updates (EBookBackendSqliteDB *ebsdb,
1352 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1355 book_backend_sqlitedb_commit_transaction (ebsdb, error) :
1356 book_backend_sqlitedb_rollback_transaction (ebsdb, error);
1359 /* Add Contact (free the result with g_free() ) */
1361 insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
1363 const gchar *folderid,
1364 gboolean store_vcard,
1365 gboolean replace_existing)
1368 gchar *str, *vcard_str;
1371 str = sqlite3_mprintf ("INSERT or %s INTO %Q VALUES (",
1372 replace_existing ? "REPLACE" : "FAIL", folderid);
1373 string = g_string_new (str);
1376 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
1378 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
1383 g_string_append (string, ", ");
1385 val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field);
1387 /* Special exception, never normalize the UID or REV string */
1388 if (ebsdb->priv->summary_fields[i].field != E_CONTACT_UID &&
1389 ebsdb->priv->summary_fields[i].field != E_CONTACT_REV)
1390 normal = e_util_utf8_normalize (val);
1392 normal = g_strdup (val);
1394 str = sqlite3_mprintf ("%Q", normal);
1395 g_string_append (string, str);
1398 if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
1399 gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1401 str = sqlite3_mprintf ("%Q", reverse);
1402 g_string_append (string, ", ");
1403 g_string_append (string, str);
1411 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
1415 g_string_append (string, ", ");
1417 val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field) ? TRUE : FALSE;
1418 g_string_append_printf (string, "%d", val ? 1 : 0);
1420 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1421 g_warn_if_reached ();
1424 vcard_str = store_vcard ? e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30) : NULL;
1425 str = sqlite3_mprintf (", %Q, %Q)", vcard_str, NULL);
1427 g_string_append (string, str);
1432 return g_string_free (string, FALSE);
1436 insert_contact (EBookBackendSqliteDB *ebsdb,
1438 const gchar *folderid,
1439 gboolean replace_existing,
1442 EBookBackendSqliteDBPrivate *priv;
1448 /* Update main summary table */
1449 stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing);
1450 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1453 /* Update attribute list table */
1454 if (success && priv->have_attr_list) {
1455 gchar *list_folder = g_strdup_printf ("%s_lists", folderid);
1460 /* First remove all entries for this UID */
1461 uid = e_contact_get (contact, E_CONTACT_UID);
1462 stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", list_folder, uid);
1463 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1464 sqlite3_free (stmt);
1466 for (i = 0; success && i < priv->n_summary_fields; i++) {
1468 if (priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1471 values = e_contact_get (contact, priv->summary_fields[i].field);
1473 for (l = values; success && l != NULL; l = l->next) {
1474 gchar *value = (gchar *) l->data;
1475 gchar *normal = e_util_utf8_normalize (value);
1477 if (priv->have_attr_list_suffix) {
1478 gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1480 stmt = sqlite3_mprintf ("INSERT INTO %Q (uid, field, value, value_reverse) "
1481 "VALUES (%Q, %Q, %Q, %Q)",
1483 priv->summary_fields[i].dbname,
1488 stmt = sqlite3_mprintf ("INSERT INTO %Q (uid, field, value) "
1489 "VALUES (%Q, %Q, %Q)",
1491 priv->summary_fields[i].dbname,
1495 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1496 sqlite3_free (stmt);
1500 /* Free the list of allocated strings */
1501 e_contact_attr_list_free (values);
1504 g_free (list_folder);
1512 * e_book_backend_sqlitedb_new_contact
1513 * @ebsdb: An #EBookBackendSqliteDB
1514 * @folderid: folder id
1515 * @contact: EContact to be added
1516 * @replace_existing: Whether this contact should replace another contact with the same UID.
1517 * @error: A location to store any error that may have occurred.
1519 * This is a convenience wrapper for e_book_backend_sqlitedb_new_contacts,
1520 * which is the preferred means to add or modify multiple contacts when possible.
1522 * Returns: TRUE on success.
1527 e_book_backend_sqlitedb_new_contact (EBookBackendSqliteDB *ebsdb,
1528 const gchar *folderid,
1530 gboolean replace_existing,
1535 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1536 g_return_val_if_fail (folderid != NULL, FALSE);
1537 g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
1542 return e_book_backend_sqlitedb_new_contacts (
1543 ebsdb, folderid, &l,
1544 replace_existing, error);
1548 * e_book_backend_sqlitedb_new_contacts
1549 * @ebsdb: An #EBookBackendSqliteDB
1550 * @folderid: folder id
1551 * @contacts: list of EContacts
1552 * @replace_existing: Whether this contact should replace another contact with the same UID.
1553 * @error: A location to store any error that may have occurred.
1555 * Adds or replaces contacts in @ebsdb. If @replace_existing is specified then existing
1556 * contacts with the same UID will be replaced, otherwise adding an existing contact
1557 * will return an error.
1559 * Returns: TRUE on success.
1564 e_book_backend_sqlitedb_new_contacts (EBookBackendSqliteDB *ebsdb,
1565 const gchar *folderid,
1567 gboolean replace_existing,
1573 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1574 g_return_val_if_fail (folderid != NULL, FALSE);
1575 g_return_val_if_fail (contacts != NULL, FALSE);
1577 success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1579 for (l = contacts; success && l != NULL; l = g_slist_next (l)) {
1580 EContact *contact = (EContact *) l->data;
1582 success = insert_contact (ebsdb, contact, folderid, replace_existing, error);
1586 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
1588 /* The GError is already set. */
1589 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
1595 * e_book_backend_sqlitedb_add_contact
1597 * @folderid: folder id
1598 * @contact: EContact to be added
1599 * @partial_content: contact does not contain full information. Used when
1600 * the backend cache's partial information for auto-completion.
1603 * This is a convenience wrapper for e_book_backend_sqlitedb_add_contacts,
1604 * which is the preferred means to add multiple contacts when possible.
1606 * Returns: TRUE on success.
1610 * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contact() instead.
1613 e_book_backend_sqlitedb_add_contact (EBookBackendSqliteDB *ebsdb,
1614 const gchar *folderid,
1616 gboolean partial_content,
1619 return e_book_backend_sqlitedb_new_contact (ebsdb, folderid, contact, TRUE, error);
1623 * e_book_backend_sqlitedb_add_contacts
1625 * @folderid: folder id
1626 * @contacts: list of EContacts
1627 * @partial_content: contact does not contain full information. Used when
1628 * the backend cache's partial information for auto-completion.
1632 * Returns: TRUE on success.
1636 * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contacts() instead.
1639 e_book_backend_sqlitedb_add_contacts (EBookBackendSqliteDB *ebsdb,
1640 const gchar *folderid,
1642 gboolean partial_content,
1645 return e_book_backend_sqlitedb_new_contacts (ebsdb, folderid, contacts, TRUE, error);
1649 * e_book_backend_sqlitedb_remove_contact:
1651 * FIXME: Document me.
1656 e_book_backend_sqlitedb_remove_contact (EBookBackendSqliteDB *ebsdb,
1657 const gchar *folderid,
1663 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1664 g_return_val_if_fail (folderid != NULL, FALSE);
1665 g_return_val_if_fail (uid != NULL, FALSE);
1667 l.data = (gchar *) uid; /* Won't modify it, I promise :) */
1670 return e_book_backend_sqlitedb_remove_contacts (
1671 ebsdb, folderid, &l, error);
1675 generate_uid_list_for_stmt (GSList *uids)
1677 GString *str = g_string_new (NULL);
1679 gboolean first = TRUE;
1681 for (l = uids; l; l = l->next) {
1682 gchar *uid = (gchar *) l->data;
1685 /* First uid with no comma */
1687 g_string_append_printf (str, ", ");
1691 tmp = sqlite3_mprintf ("%Q", uid);
1692 g_string_append (str, tmp);
1696 return g_string_free (str, FALSE);
1700 generate_delete_stmt (const gchar *table,
1703 GString *str = g_string_new (NULL);
1706 tmp = sqlite3_mprintf ("DELETE FROM %Q WHERE uid IN (", table);
1707 g_string_append (str, tmp);
1710 tmp = generate_uid_list_for_stmt (uids);
1711 g_string_append (str, tmp);
1713 g_string_append_c (str, ')');
1715 return g_string_free (str, FALSE);
1719 * e_book_backend_sqlitedb_remove_contacts:
1721 * FIXME: Document me.
1726 e_book_backend_sqlitedb_remove_contacts (EBookBackendSqliteDB *ebsdb,
1727 const gchar *folderid,
1734 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1735 g_return_val_if_fail (folderid != NULL, FALSE);
1736 g_return_val_if_fail (uids != NULL, FALSE);
1738 success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1740 /* Delete the auxillary contact infos first */
1741 if (success && ebsdb->priv->have_attr_list) {
1742 gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
1744 stmt = generate_delete_stmt (lists_folder, uids);
1745 g_free (lists_folder);
1747 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
1752 stmt = generate_delete_stmt (folderid, uids);
1753 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
1758 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
1760 /* The GError is already set. */
1761 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
1766 struct _contact_info {
1768 gboolean partial_content;
1772 contact_found_cb (gpointer ref,
1777 struct _contact_info *cinfo = ref;
1779 cinfo->exists = TRUE;
1780 cinfo->partial_content = cols[0] ? strtoul (cols[0], NULL, 10) : 0;
1786 * e_book_backend_sqlitedb_has_contact:
1788 * FIXME: Document me.
1793 e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
1794 const gchar *folderid,
1796 gboolean *partial_content,
1799 struct _contact_info cinfo;
1803 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1804 g_return_val_if_fail (folderid != NULL, FALSE);
1805 g_return_val_if_fail (uid != NULL, FALSE);
1807 cinfo.exists = FALSE;
1808 cinfo.partial_content = FALSE;
1810 READER_LOCK (ebsdb);
1812 stmt = sqlite3_mprintf (
1813 "SELECT partial_content FROM %Q WHERE uid = %Q",
1815 success = book_backend_sql_exec (
1816 ebsdb->priv->db, stmt, contact_found_cb , &cinfo, error);
1817 sqlite3_free (stmt);
1820 *partial_content = cinfo.partial_content;
1822 READER_UNLOCK (ebsdb);
1824 /* FIXME Returning FALSE can mean either "contact not found" or
1825 * "error occurred". Add a boolean (out) "exists" parameter. */
1826 return success && cinfo.exists;
1830 get_vcard_cb (gpointer ref,
1835 gchar **vcard_str = ref;
1838 *vcard_str = g_strdup (cols [0]);
1844 * e_book_backend_sqlitedb_get_contact:
1846 * FIXME: Document me.
1851 e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
1852 const gchar *folderid,
1854 GHashTable *fields_of_interest,
1855 gboolean *with_all_required_fields,
1858 EContact *contact = NULL;
1861 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
1862 g_return_val_if_fail (folderid != NULL, NULL);
1863 g_return_val_if_fail (uid != NULL, NULL);
1865 vcard = e_book_backend_sqlitedb_get_vcard_string (
1866 ebsdb, folderid, uid,
1867 fields_of_interest, with_all_required_fields, error);
1869 if (vcard != NULL) {
1870 contact = e_contact_new_from_vcard_with_uid (vcard, uid);
1878 uid_rev_fields (GHashTable *fields_of_interest)
1880 GHashTableIter iter;
1881 gpointer key, value;
1883 if (!fields_of_interest || g_hash_table_size (fields_of_interest) > 2)
1886 g_hash_table_iter_init (&iter, fields_of_interest);
1887 while (g_hash_table_iter_next (&iter, &key, &value)) {
1888 const gchar *field_name = key;
1889 EContactField field = e_contact_field_id (field_name);
1891 if (field != E_CONTACT_UID &&
1892 field != E_CONTACT_REV)
1900 * e_book_backend_sqlitedb_is_summary_fields:
1901 * @fields_of_interest: A hash table containing the fields of interest
1903 * This only checks if all the fields are part of the default summary fields,
1904 * not part of the configured summary fields.
1908 * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_fields() instead.
1911 e_book_backend_sqlitedb_is_summary_fields (GHashTable *fields_of_interest)
1913 gboolean summary_fields = TRUE;
1914 GHashTableIter iter;
1915 gpointer key, value;
1918 if (!fields_of_interest)
1921 g_hash_table_iter_init (&iter, fields_of_interest);
1922 while (g_hash_table_iter_next (&iter, &key, &value)) {
1923 const gchar *field_name = key;
1924 EContactField field = e_contact_field_id (field_name);
1925 gboolean found = FALSE;
1927 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
1928 if (field == default_summary_fields[i]) {
1935 summary_fields = FALSE;
1940 return summary_fields;
1944 * e_book_backend_sqlitedb_check_summary_fields:
1945 * @ebsdb: An #EBookBackendSqliteDB
1946 * @fields_of_interest: A hash table containing the fields of interest
1948 * Checks if all the specified fields are part of the configured summary
1954 e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
1955 GHashTable *fields_of_interest)
1957 gboolean summary_fields = TRUE;
1958 GHashTableIter iter;
1959 gpointer key, value;
1961 if (!fields_of_interest)
1964 g_hash_table_iter_init (&iter, fields_of_interest);
1965 while (g_hash_table_iter_next (&iter, &key, &value)) {
1966 const gchar *field_name = key;
1967 EContactField field = e_contact_field_id (field_name);
1969 if (summary_dbname_from_field (ebsdb, field) == NULL) {
1970 summary_fields = FALSE;
1975 return summary_fields;
1978 /* free return value with g_free */
1980 summary_select_stmt (GHashTable *fields_of_interest,
1986 string = g_string_new ("SELECT DISTINCT summary.uid");
1988 string = g_string_new ("SELECT summary.uid");
1990 /* Add the E_CONTACT_REV field if they are both requested */
1991 if (g_hash_table_size (fields_of_interest) == 2)
1992 g_string_append (string, ", Rev");
1994 return g_string_free (string, FALSE);
1998 store_data_to_vcard (gpointer ref,
2003 GSList **vcard_data = ref;
2004 EbSdbSearchData *search_data = g_slice_new0 (EbSdbSearchData);
2005 EContact *contact = e_contact_new ();
2009 /* parse through cols, this will be useful if the api starts supporting field restrictions */
2010 for (i = 0; i < ncol; i++)
2012 if (!name[i] || !cols[i])
2015 /* Only UID & REV can be used to create contacts from the summary columns */
2016 if (!g_ascii_strcasecmp (name[i], "uid")) {
2017 e_contact_set (contact, E_CONTACT_UID, cols[i]);
2019 search_data->uid = g_strdup (cols[i]);
2020 } else if (!g_ascii_strcasecmp (name[i], "Rev")) {
2021 e_contact_set (contact, E_CONTACT_REV, cols[i]);
2022 } else if (!g_ascii_strcasecmp (name[i], "bdata"))
2023 search_data->bdata = g_strdup (cols[i]);
2026 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2027 search_data->vcard = vcard;
2028 *vcard_data = g_slist_prepend (*vcard_data, search_data);
2030 g_object_unref (contact);
2035 * e_book_backend_sqlitedb_get_vcard_string:
2036 * @ebsdb: An #EBookBackendSqliteDB
2037 * @folderid: The folder id
2038 * @uid: The uid to fetch a vcard for
2039 * @fields_of_interest: The required fields for this vcard, or %NULL to require all fields.
2040 * @with_all_required_fields: (allow none) (out): Whether all the required fields are present in the returned vcard.
2041 * @error: A location to store any error that may have occurred.
2043 * Searches @ebsdb in the context of @folderid for @uid.
2045 * If @ebsdb is configured to store the whole vcards, the whole vcard will be returned.
2046 * Otherwise the summary cache will be searched and the virtual vcard will be built
2047 * from the summary cache.
2049 * In either case, @with_all_required_fields if specified, will be updated to reflect whether
2050 * the returned vcard string satisfies the passed 'fields_of_interest' parameter.
2052 * Returns: (transfer full): The vcard string for @uid or %NULL if @uid was not found.
2057 e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
2058 const gchar *folderid,
2060 GHashTable *fields_of_interest,
2061 gboolean *with_all_required_fields,
2065 gchar *vcard_str = NULL;
2066 gboolean local_with_all_required_fields = FALSE;
2068 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2069 g_return_val_if_fail (folderid != NULL, NULL);
2070 g_return_val_if_fail (uid != NULL, NULL);
2072 READER_LOCK (ebsdb);
2074 /* Try constructing contacts from only UID/REV first if that's requested */
2075 if (uid_rev_fields (fields_of_interest)) {
2076 GSList *vcards = NULL;
2077 gchar *select_portion;
2079 select_portion = summary_select_stmt (fields_of_interest, FALSE);
2081 stmt = sqlite3_mprintf (
2082 "%s FROM %Q AS summary WHERE summary.uid = %Q",
2083 select_portion, folderid, uid);
2084 book_backend_sql_exec (ebsdb->priv->db, stmt, store_data_to_vcard, &vcards, error);
2085 sqlite3_free (stmt);
2086 g_free (select_portion);
2089 EbSdbSearchData *s_data = (EbSdbSearchData *) vcards->data;
2091 vcard_str = s_data->vcard;
2092 s_data->vcard = NULL;
2094 e_book_backend_sqlitedb_search_data_free (s_data);
2096 g_slist_free (vcards);
2100 local_with_all_required_fields = TRUE;
2102 } else if (ebsdb->priv->store_vcard) {
2104 stmt = sqlite3_mprintf (
2105 "SELECT vcard FROM %Q WHERE uid = %Q", folderid, uid);
2106 book_backend_sql_exec (
2107 ebsdb->priv->db, stmt,
2108 get_vcard_cb , &vcard_str, error);
2109 sqlite3_free (stmt);
2111 local_with_all_required_fields = TRUE;
2114 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2115 _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2119 READER_UNLOCK (ebsdb);
2121 if (with_all_required_fields)
2122 *with_all_required_fields = local_with_all_required_fields;
2124 if (!vcard_str && error && !*error)
2126 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_CONTACT_NOT_FOUND,
2127 _("Contact '%s' not found"), uid ? uid : "NULL");
2133 CHECK_IS_SUMMARY = (1 << 0),
2134 CHECK_IS_LIST_ATTR = (1 << 1),
2137 static ESExpResult *
2138 func_check_subset (ESExp *f,
2140 struct _ESExpTerm **argv,
2143 ESExpResult *r, *r1;
2144 gboolean one_non_summary_query = FALSE;
2148 for (i = 0; i < argc; i++) {
2149 r1 = e_sexp_term_eval (f, argv[i]);
2151 if (r1->type != ESEXP_RES_INT) {
2152 e_sexp_result_free (f, r1);
2156 result |= r1->value.number;
2158 if ((r1->value.number & CHECK_IS_SUMMARY) == 0)
2159 one_non_summary_query = TRUE;
2161 e_sexp_result_free (f, r1);
2164 /* If at least one subset is not a summary query,
2165 * then the whole query is not a summary query and
2166 * thus cannot be done with an SQL statement
2168 if (one_non_summary_query)
2171 r = e_sexp_result_new (f, ESEXP_RES_INT);
2172 r->value.number = result;
2177 static ESExpResult *
2178 func_check (struct _ESExp *f,
2180 struct _ESExpResult **argv,
2183 EBookBackendSqliteDB *ebsdb = data;
2188 && argv[0]->type == ESEXP_RES_STRING
2189 && argv[1]->type == ESEXP_RES_STRING) {
2190 const gchar *query_name = argv[0]->value.string;
2191 const gchar *query_value = argv[1]->value.string;
2194 /* Special case, when testing the special symbolic 'any field' we can
2195 * consider it a summary query (it's similar to a 'no query'). */
2196 if (g_strcmp0 (query_name, "x-evolution-any-field") == 0 &&
2197 g_strcmp0 (query_value, "") == 0) {
2198 ret_val |= CHECK_IS_SUMMARY;
2203 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
2204 if (!g_ascii_strcasecmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), query_name)) {
2205 ret_val |= CHECK_IS_SUMMARY;
2207 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
2208 ret_val |= CHECK_IS_LIST_ATTR;
2212 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2214 if (!g_ascii_strcasecmp (e_contact_field_name (default_summary_fields[i]), query_name)) {
2215 ret_val |= CHECK_IS_SUMMARY;
2217 if (e_contact_field_type (default_summary_fields[i]) == E_TYPE_CONTACT_ATTR_LIST)
2218 ret_val |= CHECK_IS_LIST_ATTR;
2226 r = e_sexp_result_new (f, ESEXP_RES_INT);
2227 r->value.number = ret_val;
2232 /* 'builtin' functions */
2233 static const struct {
2236 gint type; /* set to 1 if a function can perform shortcut evaluation, or
2237 doesn't execute everything, 0 otherwise */
2238 } check_symbols[] = {
2239 { "and", (ESExpFunc *) func_check_subset, 1},
2240 { "or", (ESExpFunc *) func_check_subset, 1},
2242 { "contains", func_check, 0 },
2243 { "is", func_check, 0 },
2244 { "beginswith", func_check, 0 },
2245 { "endswith", func_check, 0 },
2246 { "exists", func_check, 0 }
2250 * e_book_backend_sqlitedb_check_summary_query:
2251 * @ebsdb: an #EBookBackendSqliteDB
2252 * @query: the query to check
2253 * @with_list_attrs: Return location to store whether the query touches upon list attributes
2255 * Checks whether @query contains only checks for the summary fields
2256 * configured in @ebsdb
2261 e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
2263 gboolean *with_list_attrs)
2267 gboolean retval = FALSE;
2271 g_return_val_if_fail (query != NULL, FALSE);
2272 g_return_val_if_fail (*query != '\0', FALSE);
2274 sexp = e_sexp_new ();
2276 for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
2277 if (check_symbols[i].type == 1) {
2278 e_sexp_add_ifunction (
2279 sexp, 0, check_symbols[i].name,
2280 (ESExpIFunc *) check_symbols[i].func, ebsdb);
2282 e_sexp_add_function (
2283 sexp, 0, check_symbols[i].name,
2284 check_symbols[i].func, ebsdb);
2288 e_sexp_input_text (sexp, query, strlen (query));
2289 esexp_error = e_sexp_parse (sexp);
2291 if (esexp_error == -1) {
2295 r = e_sexp_eval (sexp);
2296 if (r && r->type == ESEXP_RES_INT) {
2297 retval = (r->value.number & CHECK_IS_SUMMARY) != 0;
2299 if ((r->value.number & CHECK_IS_LIST_ATTR) != 0 && with_list_attrs)
2300 *with_list_attrs = TRUE;
2303 e_sexp_result_free (sexp, r);
2304 e_sexp_unref (sexp);
2310 * e_book_backend_sqlitedb_is_summary_query:
2312 * Checks whether the query contains only checks for the default summary fields
2316 * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_query() instead
2319 e_book_backend_sqlitedb_is_summary_query (const gchar *query)
2321 return e_book_backend_sqlitedb_check_summary_query (NULL, query, NULL);
2324 static ESExpResult *
2327 struct _ESExpTerm **argv,
2330 ESExpResult *r, *r1;
2334 string = g_string_new ("( ");
2335 for (i = 0; i < argc; i++) {
2336 r1 = e_sexp_term_eval (f, argv[i]);
2338 if (r1->type != ESEXP_RES_STRING) {
2339 e_sexp_result_free (f, r1);
2342 if (r1->value.string && *r1->value.string)
2343 g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " AND ":"");
2344 e_sexp_result_free (f, r1);
2346 g_string_append (string, " )");
2347 r = e_sexp_result_new (f, ESEXP_RES_STRING);
2349 if (strlen (string->str) == 4) {
2350 r->value.string = g_strdup ("");
2351 g_string_free (string, TRUE);
2353 r->value.string = g_string_free (string, FALSE);
2359 static ESExpResult *
2362 struct _ESExpTerm **argv,
2365 ESExpResult *r, *r1;
2369 string = g_string_new ("( ");
2370 for (i = 0; i < argc; i++) {
2371 r1 = e_sexp_term_eval (f, argv[i]);
2373 if (r1->type != ESEXP_RES_STRING) {
2374 e_sexp_result_free (f, r1);
2377 if (r1->value.string && *r1->value.string)
2378 g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " OR ":"");
2379 e_sexp_result_free (f, r1);
2381 g_string_append (string, " )");
2383 r = e_sexp_result_new (f, ESEXP_RES_STRING);
2384 if (strlen (string->str) == 4) {
2385 r->value.string = g_strdup ("");
2386 g_string_free (string, TRUE);
2388 r->value.string = g_string_free (string, FALSE);
2402 convert_string_value (const gchar *value,
2410 gboolean escape_modifier_needed = FALSE;
2411 const gchar *escape_modifier = " ESCAPE '^'";
2412 gchar *reverse_val = NULL;
2416 g_return_val_if_fail (value != NULL, NULL);
2419 normal = e_util_utf8_normalize (value);
2421 normal = g_strdup (value);
2423 /* Just assume each character must be escaped. The result of this function
2424 * is discarded shortly after calling this function. Therefore it's
2425 * acceptable to possibly allocate twice the memory needed.
2427 len = strlen (normal);
2428 str = g_string_sized_new (2 * len + 4 + strlen (escape_modifier) - 1);
2429 g_string_append_c (str, '\'');
2432 case MATCH_CONTAINS:
2433 case MATCH_ENDS_WITH:
2434 g_string_append_c (str, '%');
2437 case MATCH_BEGINS_WITH:
2443 reverse_val = g_utf8_strreverse (normal, -1);
2449 while ((c = *ptr++)) {
2451 g_string_append_c (str, '\'');
2452 } else if (c == '%' || c == '^') {
2453 g_string_append_c (str, '^');
2454 escape_modifier_needed = TRUE;
2457 g_string_append_c (str, c);
2461 case MATCH_CONTAINS:
2462 case MATCH_BEGINS_WITH:
2463 g_string_append_c (str, '%');
2466 case MATCH_ENDS_WITH:
2471 g_string_append_c (str, '\'');
2473 if (escape_modifier_needed)
2474 g_string_append (str, escape_modifier);
2476 g_free (reverse_val);
2479 return g_string_free (str, FALSE);
2483 field_name_and_query_term (EBookBackendSqliteDB *ebsdb,
2484 const gchar *folderid,
2485 const gchar *field_name_input,
2486 const gchar *query_term_input,
2488 gboolean *is_list_attr,
2492 gchar *field_name = NULL;
2493 gchar *value = NULL;
2494 gboolean list_attr = FALSE;
2496 summary_index = summary_index_from_field_name (ebsdb, field_name_input);
2498 if (summary_index < 0) {
2499 g_critical ("Only summary field matches should be converted to sql queries");
2500 field_name = g_strconcat (folderid, ".", field_name_input, NULL);
2501 value = convert_string_value (query_term_input, TRUE, FALSE, match);
2503 gboolean suffix_search = FALSE;
2505 /* If its a suffix search and we have reverse data to search... */
2506 if (match == MATCH_ENDS_WITH &&
2507 (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0)
2508 suffix_search = TRUE;
2510 /* Or also if its an exact match, and we *only* have reverse data which is indexed,
2511 * then prefer the indexed reverse search. */
2512 else if (match == MATCH_IS &&
2513 (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0 &&
2514 (ebsdb->priv->summary_fields[summary_index].index & INDEX_PREFIX) == 0)
2515 suffix_search = TRUE;
2517 if (suffix_search) {
2518 /* Special case for suffix matching:
2519 * o Reverse the string
2520 * o Check the reversed column instead
2521 * o Make it a prefix search
2523 if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
2524 field_name = g_strdup ("multi.value_reverse");
2527 field_name = g_strconcat (
2529 ebsdb->priv->summary_fields[summary_index].dbname,
2532 if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
2533 ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
2534 value = convert_string_value (
2535 query_term_input, FALSE, TRUE,
2536 (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
2538 value = convert_string_value (
2539 query_term_input, TRUE, TRUE,
2540 (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
2543 if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
2544 field_name = g_strdup ("multi.value");
2547 field_name = g_strconcat (
2549 ebsdb->priv->summary_fields[summary_index].dbname, NULL);
2551 if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
2552 ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
2553 value = convert_string_value (query_term_input, FALSE, FALSE, match);
2555 value = convert_string_value (query_term_input, TRUE, FALSE, match);
2560 *is_list_attr = list_attr;
2562 *query_term = value;
2568 EBookBackendSqliteDB *ebsdb;
2569 const gchar *folderid;
2572 static ESExpResult *
2573 convert_match_exp (struct _ESExp *f,
2575 struct _ESExpResult **argv,
2579 BuildQueryData *qdata = (BuildQueryData *) data;
2580 EBookBackendSqliteDB *ebsdb = qdata->ebsdb;
2584 /* are we inside a match-all? */
2585 if (argc > 1 && argv[0]->type == ESEXP_RES_STRING) {
2588 /* only a subset of headers are supported .. */
2589 field = argv[0]->value.string;
2591 if (argv[1]->type == ESEXP_RES_STRING && argv[1]->value.string[0] != 0) {
2592 const gchar *oper = "LIKE";
2593 gchar *field_name, *query_term;
2595 if (match == MATCH_IS)
2598 if (!g_ascii_strcasecmp (field, "full_name")) {
2599 GString *names = g_string_new (NULL);
2601 field_name = field_name_and_query_term (
2602 ebsdb, qdata->folderid, "full_name",
2603 argv[1]->value.string,
2604 match, NULL, &query_term);
2605 g_string_append_printf (
2606 names, "(%s IS NOT NULL AND %s %s %s)",
2607 field_name, field_name, oper, query_term);
2608 g_free (field_name);
2609 g_free (query_term);
2611 if (summary_dbname_from_field (ebsdb, E_CONTACT_FAMILY_NAME)) {
2613 field_name = field_name_and_query_term (
2614 ebsdb, qdata->folderid, "family_name",
2615 argv[1]->value.string,
2616 match, NULL, &query_term);
2617 g_string_append_printf (
2618 names, " OR (%s IS NOT NULL AND %s %s %s)",
2619 field_name, field_name, oper, query_term);
2620 g_free (field_name);
2621 g_free (query_term);
2624 if (summary_dbname_from_field (ebsdb, E_CONTACT_GIVEN_NAME)) {
2626 field_name = field_name_and_query_term (
2627 ebsdb, qdata->folderid, "given_name",
2628 argv[1]->value.string,
2629 match, NULL, &query_term);
2630 g_string_append_printf (
2631 names, " OR (%s IS NOT NULL AND %s %s %s)",
2632 field_name, field_name, oper, query_term);
2633 g_free (field_name);
2634 g_free (query_term);
2637 if (summary_dbname_from_field (ebsdb, E_CONTACT_NICKNAME)) {
2639 field_name = field_name_and_query_term (
2640 ebsdb, qdata->folderid, "nickname",
2641 argv[1]->value.string,
2642 match, NULL, &query_term);
2643 g_string_append_printf (
2644 names, " OR (%s IS NOT NULL AND %s %s %s)",
2645 field_name, field_name, oper, query_term);
2646 g_free (field_name);
2647 g_free (query_term);
2651 g_string_free (names, FALSE);
2654 gboolean is_list = FALSE;
2656 /* This should ideally be the only valid case from all the above special casing, but oh well... */
2657 field_name = field_name_and_query_term (
2658 ebsdb, qdata->folderid, field,
2659 argv[1]->value.string,
2660 match, &is_list, &query_term);
2665 tmp = sqlite3_mprintf ("summary.uid = multi.uid AND multi.field = %Q", field);
2666 str = g_strdup_printf (
2667 "(%s AND %s %s %s)",
2668 tmp, field_name, oper, query_term);
2671 str = g_strdup_printf (
2672 "(%s IS NOT NULL AND %s %s %s)",
2673 field_name, field_name, oper, query_term);
2675 g_free (field_name);
2676 g_free (query_term);
2681 r = e_sexp_result_new (f, ESEXP_RES_STRING);
2682 r->value.string = str;
2687 static ESExpResult *
2688 func_contains (struct _ESExp *f,
2690 struct _ESExpResult **argv,
2693 return convert_match_exp (f, argc, argv, data, MATCH_CONTAINS);
2696 static ESExpResult *
2697 func_is (struct _ESExp *f,
2699 struct _ESExpResult **argv,
2702 return convert_match_exp (f, argc, argv, data, MATCH_IS);
2705 static ESExpResult *
2706 func_beginswith (struct _ESExp *f,
2708 struct _ESExpResult **argv,
2711 return convert_match_exp (f, argc, argv, data, MATCH_BEGINS_WITH);
2714 static ESExpResult *
2715 func_endswith (struct _ESExp *f,
2717 struct _ESExpResult **argv,
2720 return convert_match_exp (f, argc, argv, data, MATCH_ENDS_WITH);
2723 /* 'builtin' functions */
2729 { "and", (ESExpFunc *) func_and, 1},
2730 { "or", (ESExpFunc *) func_or, 1},
2732 { "contains", func_contains, 0 },
2733 { "is", func_is, 0 },
2734 { "beginswith", func_beginswith, 0 },
2735 { "endswith", func_endswith, 0 },
2739 sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
2740 const gchar *folderid,
2743 BuildQueryData data = { ebsdb, folderid };
2749 sexp = e_sexp_new ();
2751 for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
2752 if (symbols[i].immediate)
2753 e_sexp_add_ifunction (
2754 sexp, 0, symbols[i].name,
2755 (ESExpIFunc *) symbols[i].func, &data);
2757 e_sexp_add_function (
2758 sexp, 0, symbols[i].name,
2759 symbols[i].func, &data);
2762 e_sexp_input_text (sexp, query, strlen (query));
2763 e_sexp_parse (sexp);
2765 r = e_sexp_eval (sexp);
2768 if (r->type == ESEXP_RES_STRING) {
2769 if (r->value.string && *r->value.string)
2770 res = g_strdup (r->value.string);
2774 g_warn_if_reached ();
2778 e_sexp_result_free (sexp, r);
2779 e_sexp_unref (sexp);
2785 addto_vcard_list_cb (gpointer ref,
2790 GSList **vcard_data = ref;
2791 EbSdbSearchData *s_data = g_slice_new0 (EbSdbSearchData);
2794 s_data->uid = g_strdup (cols[0]);
2797 s_data->vcard = g_strdup (cols[1]);
2800 s_data->bdata = g_strdup (cols[2]);
2802 *vcard_data = g_slist_prepend (*vcard_data, s_data);
2808 addto_slist_cb (gpointer ref,
2813 GSList **uids = ref;
2816 *uids = g_slist_prepend (*uids, g_strdup (cols [0]));
2822 book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
2824 const gchar *folderid,
2825 GHashTable *fields_of_interest,
2826 gboolean *with_all_required_fields,
2827 gboolean query_with_list_attrs,
2830 GSList *vcard_data = NULL;
2832 gboolean local_with_all_required_fields = FALSE;
2833 gboolean success = TRUE;
2835 READER_LOCK (ebsdb);
2837 /* Try constructing contacts from only UID/REV first if that's requested */
2838 if (uid_rev_fields (fields_of_interest)) {
2839 gchar *select_portion;
2841 select_portion = summary_select_stmt (
2842 fields_of_interest, query_with_list_attrs);
2844 if (sql && sql[0]) {
2846 if (query_with_list_attrs) {
2847 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
2849 stmt = sqlite3_mprintf (
2850 "%s FROM %Q AS summary, %Q AS multi WHERE %s",
2851 select_portion, folderid, list_table, sql);
2852 g_free (list_table);
2854 stmt = sqlite3_mprintf (
2855 "%s FROM %Q AS summary WHERE %s",
2856 select_portion, folderid, sql);
2859 success = book_backend_sql_exec (
2860 ebsdb->priv->db, stmt,
2861 store_data_to_vcard, &vcard_data, error);
2863 sqlite3_free (stmt);
2865 stmt = sqlite3_mprintf ("%s FROM %Q AS summary", select_portion, folderid);
2866 success = book_backend_sql_exec (
2867 ebsdb->priv->db, stmt,
2868 store_data_to_vcard, &vcard_data, error);
2869 sqlite3_free (stmt);
2872 local_with_all_required_fields = TRUE;
2873 g_free (select_portion);
2875 } else if (ebsdb->priv->store_vcard) {
2877 if (sql && sql[0]) {
2879 if (query_with_list_attrs) {
2880 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
2882 stmt = sqlite3_mprintf (
2883 "SELECT DISTINCT summary.uid, vcard, bdata "
2884 "FROM %Q AS summary, %Q AS multi WHERE %s",
2885 folderid, list_table, sql);
2886 g_free (list_table);
2888 stmt = sqlite3_mprintf (
2889 "SELECT uid, vcard, bdata FROM %Q as summary WHERE %s", folderid, sql);
2892 success = book_backend_sql_exec (
2893 ebsdb->priv->db, stmt,
2894 addto_vcard_list_cb , &vcard_data, error);
2896 sqlite3_free (stmt);
2898 stmt = sqlite3_mprintf (
2899 "SELECT uid, vcard, bdata FROM %Q", folderid);
2900 success = book_backend_sql_exec (
2901 ebsdb->priv->db, stmt,
2902 addto_vcard_list_cb , &vcard_data, error);
2903 sqlite3_free (stmt);
2906 local_with_all_required_fields = TRUE;
2909 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2910 _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2913 READER_UNLOCK (ebsdb);
2916 g_warn_if_fail (vcard_data == NULL);
2920 if (with_all_required_fields)
2921 *with_all_required_fields = local_with_all_required_fields;
2923 return g_slist_reverse (vcard_data);
2927 book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
2929 const gchar *folderid,
2930 gboolean return_uids,
2933 GSList *r_list = NULL, *all = NULL, *l;
2934 EBookBackendSExp *bsexp = NULL;
2938 READER_LOCK (ebsdb);
2940 stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
2941 success = book_backend_sql_exec (
2942 ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
2943 sqlite3_free (stmt);
2945 READER_UNLOCK (ebsdb);
2948 g_warn_if_fail (all == NULL);
2952 bsexp = e_book_backend_sexp_new (sexp);
2954 for (l = all; l != NULL; l = g_slist_next (l)) {
2955 EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
2957 if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
2959 r_list = g_slist_prepend (r_list, s_data);
2961 r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
2962 e_book_backend_sqlitedb_search_data_free (s_data);
2965 e_book_backend_sqlitedb_search_data_free (s_data);
2968 g_object_unref (bsexp);
2976 * e_book_backend_sqlitedb_search
2979 * @sexp: search expression; use NULL or an empty string to get all stored
2981 * @fields_of_interest: a #GHashTable containing the names of fields to return,
2982 * or NULL for all. At the moment if this is non-null, the vcard will be
2983 * populated with summary fields, else it would return the whole vcard if
2984 * its stored in the db. [not implemented fully]
2985 * @searched: (allow none) (out): Whether @ebsdb was capable of searching
2986 * for the provided query @sexp.
2987 * @with_all_required_fields: (allow none) (out): Whether all the required
2988 * fields are present in the returned vcards.
2991 * Searching with summary fields is always supported. Search expressions
2992 * containing any other field is supported only if backend chooses to store
2993 * the vcard inside the db.
2995 * Summary fields - uid, rev, nickname, given_name, family_name, file_as
2996 * email_1, email_2, email_3, email_4, is_list, list_show_addresses, wants_html
2998 * If @ebsdb was incapable of returning vcards with results that satisfy
2999 * @fields_of_interest, then @with_all_required_fields will be updated to
3000 * @FALSE and only uid fields will be present in the returned vcards. This
3001 * can be useful when a summary query succeeds and the returned list can be
3002 * used to iterate and fetch for full required data from another persistance.
3004 * Returns: List of EbSdbSearchData.
3009 e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
3010 const gchar *folderid,
3012 GHashTable *fields_of_interest,
3014 gboolean *with_all_required_fields,
3017 GSList *search_contacts = NULL;
3018 gboolean local_searched = FALSE;
3019 gboolean local_with_all_required_fields = FALSE;
3020 gboolean query_with_list_attrs = FALSE;
3022 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3023 g_return_val_if_fail (folderid != NULL, NULL);
3028 if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp,
3029 &query_with_list_attrs)) {
3032 sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3033 search_contacts = book_backend_sqlitedb_search_query (
3034 ebsdb, sql_query, folderid,
3036 &local_with_all_required_fields,
3037 query_with_list_attrs, error);
3040 local_searched = TRUE;
3042 } else if (ebsdb->priv->store_vcard) {
3043 search_contacts = book_backend_sqlitedb_search_full (
3044 ebsdb, sexp, folderid, FALSE, error);
3046 local_searched = TRUE;
3047 local_with_all_required_fields = TRUE;
3051 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3052 _("Full search_contacts are not stored in cache. "
3053 "Hence only summary query is supported."));
3057 *searched = local_searched;
3058 if (with_all_required_fields)
3059 *with_all_required_fields = local_with_all_required_fields;
3061 return search_contacts;
3065 * e_book_backend_sqlitedb_search_uids:
3067 * FIXME: Document me.
3072 e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
3073 const gchar *folderid,
3078 GSList *uids = NULL;
3079 gboolean local_searched = FALSE;
3080 gboolean query_with_list_attrs = FALSE;
3082 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3083 g_return_val_if_fail (folderid != NULL, NULL);
3088 if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp, &query_with_list_attrs)) {
3090 gchar *sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3092 READER_LOCK (ebsdb);
3094 if (sql_query && sql_query[0]) {
3096 if (query_with_list_attrs) {
3097 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3099 stmt = sqlite3_mprintf (
3100 "SELECT DISTINCT summary.uid FROM %Q AS summary, %Q AS multi WHERE %s",
3101 folderid, list_table, sql_query);
3103 g_free (list_table);
3105 stmt = sqlite3_mprintf (
3106 "SELECT summary.uid FROM %Q AS summary WHERE %s",
3107 folderid, sql_query);
3109 book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3110 sqlite3_free (stmt);
3113 stmt = sqlite3_mprintf ("SELECT uid FROM %Q", folderid);
3114 book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3115 sqlite3_free (stmt);
3118 READER_UNLOCK (ebsdb);
3120 local_searched = TRUE;
3124 } else if (ebsdb->priv->store_vcard) {
3125 uids = book_backend_sqlitedb_search_full (
3126 ebsdb, sexp, folderid, TRUE, error);
3128 local_searched = TRUE;
3132 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3133 _("Full vcards are not stored in cache. "
3134 "Hence only summary query is supported."));
3138 *searched = local_searched;
3144 get_uids_and_rev_cb (gpointer user_data,
3149 GHashTable *uids_and_rev = user_data;
3151 if (col == 2 && cols[0])
3152 g_hash_table_insert (uids_and_rev, g_strdup (cols[0]), g_strdup (cols[1] ? cols[1] : ""));
3158 * e_book_backend_sqlitedb_get_uids_and_rev:
3160 * Gets hash table of all uids (key) and rev (value) pairs stored
3161 * for each contact in the cache. The hash table should be freed
3162 * with g_hash_table_destroy(), if not needed anymore. Each key
3163 * and value is a newly allocated string.
3168 e_book_backend_sqlitedb_get_uids_and_rev (EBookBackendSqliteDB *ebsdb,
3169 const gchar *folderid,
3172 GHashTable *uids_and_rev;
3175 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3176 g_return_val_if_fail (folderid != NULL, NULL);
3178 uids_and_rev = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3180 READER_LOCK (ebsdb);
3182 stmt = sqlite3_mprintf ("SELECT uid,rev FROM %Q", folderid);
3183 book_backend_sql_exec (
3184 ebsdb->priv->db, stmt,
3185 get_uids_and_rev_cb, uids_and_rev, error);
3186 sqlite3_free (stmt);
3188 READER_UNLOCK (ebsdb);
3190 return uids_and_rev;
3194 * e_book_backend_sqlitedb_get_is_populated:
3196 * FIXME: Document me.
3201 e_book_backend_sqlitedb_get_is_populated (EBookBackendSqliteDB *ebsdb,
3202 const gchar *folderid,
3206 gboolean ret = FALSE;
3208 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3209 g_return_val_if_fail (folderid != NULL, FALSE);
3211 READER_LOCK (ebsdb);
3213 stmt = sqlite3_mprintf (
3214 "SELECT is_populated FROM folders WHERE folder_id = %Q",
3216 book_backend_sql_exec (
3217 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3218 sqlite3_free (stmt);
3220 READER_UNLOCK (ebsdb);
3227 * e_book_backend_sqlitedb_set_is_populated:
3229 * FIXME: Document me.
3234 e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
3235 const gchar *folderid,
3242 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3243 g_return_val_if_fail (folderid != NULL, FALSE);
3245 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3248 stmt = sqlite3_mprintf (
3249 "UPDATE folders SET is_populated = %d "
3250 "WHERE folder_id = %Q", populated, folderid);
3251 success =book_backend_sql_exec (
3252 ebsdb->priv->db, stmt, NULL, NULL, error);
3253 sqlite3_free (stmt);
3258 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3261 /* The GError is already set. */
3262 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3268 * e_book_backend_sqlitedb_get_revision:
3269 * @ebsdb: An #EBookBackendSqliteDB
3270 * @folderid: folder id of the address-book
3271 * @revision_out: (out) (transfer full): The location to return the current
3273 * @error: A location to store any error that may have occurred
3275 * Fetches the current revision for the address-book indicated by @folderid.
3277 * Upon success, @revision_out will hold the returned revision, otherwise
3278 * %FALSE will be returned and @error will be updated accordingly.
3280 * Returns: Whether the revision was successfully fetched.
3285 e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
3286 const gchar *folderid,
3287 gchar **revision_out,
3293 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3294 g_return_val_if_fail (folderid && folderid[0], FALSE);
3295 g_return_val_if_fail (revision_out != NULL && *revision_out == NULL, FALSE);
3297 READER_LOCK (ebsdb);
3299 stmt = sqlite3_mprintf (
3300 "SELECT revision FROM folders WHERE folder_id = %Q", folderid);
3301 success = book_backend_sql_exec (
3302 ebsdb->priv->db, stmt, get_string_cb, &revision_out, error);
3303 sqlite3_free (stmt);
3305 READER_UNLOCK (ebsdb);
3311 * e_book_backend_sqlitedb_set_revision:
3312 * @ebsdb: An #EBookBackendSqliteDB
3313 * @folderid: folder id of the address-book
3314 * @revision: The new revision
3315 * @error: A location to store any error that may have occurred
3317 * Sets the current revision for the address-book indicated by @folderid to be @revision.
3319 * Returns: Whether the revision was successfully set.
3324 e_book_backend_sqlitedb_set_revision (EBookBackendSqliteDB *ebsdb,
3325 const gchar *folderid,
3326 const gchar *revision,
3332 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3333 g_return_val_if_fail (folderid && folderid[0], FALSE);
3335 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3338 stmt = sqlite3_mprintf (
3339 "UPDATE folders SET revision = %Q "
3340 "WHERE folder_id = %Q", revision, folderid);
3341 success = book_backend_sql_exec (
3342 ebsdb->priv->db, stmt, NULL, NULL, error);
3343 sqlite3_free (stmt);
3348 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3351 /* The GError is already set. */
3352 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3358 * e_book_backend_sqlitedb_get_has_partial_content
3364 * Returns: TRUE if the vcards stored in the db were downloaded partially. It is to indicate
3365 * the stored vcards does not contain the full data.
3370 e_book_backend_sqlitedb_get_has_partial_content (EBookBackendSqliteDB *ebsdb,
3371 const gchar *folderid,
3375 gboolean ret = FALSE;
3377 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3378 g_return_val_if_fail (folderid != NULL, FALSE);
3380 READER_LOCK (ebsdb);
3382 stmt = sqlite3_mprintf (
3383 "SELECT partial_content FROM folders "
3384 "WHERE folder_id = %Q", folderid);
3385 book_backend_sql_exec (
3386 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3387 sqlite3_free (stmt);
3389 READER_UNLOCK (ebsdb);
3395 * e_book_backend_sqlitedb_set_has_partial_content:
3397 * FIXME: Document me.
3402 e_book_backend_sqlitedb_set_has_partial_content (EBookBackendSqliteDB *ebsdb,
3403 const gchar *folderid,
3404 gboolean partial_content,
3410 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3411 g_return_val_if_fail (folderid != NULL, FALSE);
3413 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3416 stmt = sqlite3_mprintf (
3417 "UPDATE folders SET partial_content = %d "
3418 "WHERE folder_id = %Q", partial_content, folderid);
3419 success = book_backend_sql_exec (
3420 ebsdb->priv->db, stmt, NULL, NULL, error);
3421 sqlite3_free (stmt);
3426 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3429 /* The GError is already set. */
3430 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3436 * e_book_backend_sqlitedb_get_contact_bdata:
3438 * FIXME: Document me.
3443 e_book_backend_sqlitedb_get_contact_bdata (EBookBackendSqliteDB *ebsdb,
3444 const gchar *folderid,
3448 gchar *stmt, *ret = NULL;
3451 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3452 g_return_val_if_fail (folderid != NULL, NULL);
3453 g_return_val_if_fail (uid != NULL, NULL);
3455 READER_LOCK (ebsdb);
3457 stmt = sqlite3_mprintf (
3458 "SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
3459 success = book_backend_sql_exec (
3460 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3461 sqlite3_free (stmt);
3463 READER_UNLOCK (ebsdb);
3466 g_warn_if_fail (ret == NULL);
3474 * e_book_backend_sqlitedb_set_contact_bdata:
3476 * FIXME: Document me.
3481 e_book_backend_sqlitedb_set_contact_bdata (EBookBackendSqliteDB *ebsdb,
3482 const gchar *folderid,
3490 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3491 g_return_val_if_fail (folderid != NULL, FALSE);
3492 g_return_val_if_fail (uid != NULL, FALSE);
3493 g_return_val_if_fail (value != NULL, FALSE);
3495 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3498 stmt = sqlite3_mprintf (
3499 "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
3500 folderid, value, uid);
3501 success = book_backend_sql_exec (
3502 ebsdb->priv->db, stmt, NULL, NULL, error);
3503 sqlite3_free (stmt);
3508 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3511 /* The GError is already set. */
3512 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3518 * e_book_backend_sqlitedb_get_sync_data:
3520 * FIXME: Document me.
3525 e_book_backend_sqlitedb_get_sync_data (EBookBackendSqliteDB *ebsdb,
3526 const gchar *folderid,
3529 gchar *stmt, *ret = NULL;
3531 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3532 g_return_val_if_fail (folderid != NULL, NULL);
3534 READER_LOCK (ebsdb);
3536 stmt = sqlite3_mprintf (
3537 "SELECT sync_data FROM folders WHERE folder_id = %Q",
3539 book_backend_sql_exec (
3540 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3541 sqlite3_free (stmt);
3543 READER_UNLOCK (ebsdb);
3549 * e_book_backend_sqlitedb_set_sync_data:
3551 * FIXME: Document me.
3556 e_book_backend_sqlitedb_set_sync_data (EBookBackendSqliteDB *ebsdb,
3557 const gchar *folderid,
3558 const gchar *sync_data,
3564 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3565 g_return_val_if_fail (folderid != NULL, FALSE);
3566 g_return_val_if_fail (sync_data != NULL, FALSE);
3568 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3571 stmt = sqlite3_mprintf (
3572 "UPDATE folders SET sync_data = %Q "
3573 "WHERE folder_id = %Q", sync_data, folderid);
3574 success = book_backend_sql_exec (
3575 ebsdb->priv->db, stmt, NULL, NULL, error);
3576 sqlite3_free (stmt);
3581 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3584 /* The GError is already set. */
3585 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3591 * e_book_backend_sqlitedb_get_key_value:
3593 * FIXME: Document me.
3598 e_book_backend_sqlitedb_get_key_value (EBookBackendSqliteDB *ebsdb,
3599 const gchar *folderid,
3603 gchar *stmt, *ret = NULL;
3605 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3606 g_return_val_if_fail (folderid != NULL, NULL);
3607 g_return_val_if_fail (key != NULL, NULL);
3609 READER_LOCK (ebsdb);
3611 stmt = sqlite3_mprintf (
3612 "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
3614 book_backend_sql_exec (
3615 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3616 sqlite3_free (stmt);
3618 READER_UNLOCK (ebsdb);
3624 * e_book_backend_sqlitedb_set_key_value:
3626 * FIXME: Document me.
3631 e_book_backend_sqlitedb_set_key_value (EBookBackendSqliteDB *ebsdb,
3632 const gchar *folderid,
3640 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3641 g_return_val_if_fail (folderid != NULL, FALSE);
3642 g_return_val_if_fail (key != NULL, FALSE);
3643 g_return_val_if_fail (value != NULL, FALSE);
3645 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3648 stmt = sqlite3_mprintf (
3649 "INSERT or REPLACE INTO keys (key, value, folder_id) "
3650 "values (%Q, %Q, %Q)", key, value, folderid);
3651 success = book_backend_sql_exec (
3652 ebsdb->priv->db, stmt, NULL, NULL, error);
3653 sqlite3_free (stmt);
3658 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3661 /* The GError is already set. */
3662 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3668 * e_book_backend_sqlitedb_get_partially_cached_ids:
3670 * FIXME: Document me.
3675 e_book_backend_sqlitedb_get_partially_cached_ids (EBookBackendSqliteDB *ebsdb,
3676 const gchar *folderid,
3680 GSList *uids = NULL;
3682 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3683 g_return_val_if_fail (folderid != NULL, NULL);
3685 READER_LOCK (ebsdb);
3687 stmt = sqlite3_mprintf (
3688 "SELECT uid FROM %Q WHERE partial_content = 1",
3690 book_backend_sql_exec (
3691 ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3692 sqlite3_free (stmt);
3694 READER_UNLOCK (ebsdb);
3700 * e_book_backend_sqlitedb_delete_addressbook:
3702 * FIXME: Document me.
3707 e_book_backend_sqlitedb_delete_addressbook (EBookBackendSqliteDB *ebsdb,
3708 const gchar *folderid,
3714 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3715 g_return_val_if_fail (folderid != NULL, FALSE);
3717 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3720 /* delete the contacts table */
3721 stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
3722 success = book_backend_sql_exec (
3723 ebsdb->priv->db, stmt, NULL, NULL, error);
3724 sqlite3_free (stmt);
3729 /* delete the key/value pairs corresponding to this table */
3730 stmt = sqlite3_mprintf (
3731 "DELETE FROM keys WHERE folder_id = %Q", folderid);
3732 success = book_backend_sql_exec (
3733 ebsdb->priv->db, stmt, NULL, NULL, error);
3734 sqlite3_free (stmt);
3739 /* delete the folder from the folders table */
3740 stmt = sqlite3_mprintf (
3741 "DELETE FROM folders WHERE folder_id = %Q", folderid);
3742 success = book_backend_sql_exec (
3743 ebsdb->priv->db, stmt, NULL, NULL, error);
3744 sqlite3_free (stmt);
3749 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3752 /* The GError is already set. */
3753 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3759 * e_book_backend_sqlitedb_search_data_free:
3761 * FIXME: Document me.
3766 e_book_backend_sqlitedb_search_data_free (EbSdbSearchData *s_data)
3769 g_free (s_data->uid);
3770 g_free (s_data->vcard);
3771 g_free (s_data->bdata);
3772 g_slice_free (EbSdbSearchData, s_data);
3777 * e_book_backend_sqlitedb_remove:
3779 * FIXME: Document me.
3784 e_book_backend_sqlitedb_remove (EBookBackendSqliteDB *ebsdb,
3790 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3792 WRITER_LOCK (ebsdb);
3794 sqlite3_close (ebsdb->priv->db);
3796 filename = g_build_filename (ebsdb->priv->path, DB_FILENAME, NULL);
3797 ret = g_unlink (filename);
3800 WRITER_UNLOCK (ebsdb);
3804 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3805 _("Unable to remove the db file: errno %d"), errno);