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.
22 #include "e-book-backend-sqlitedb.h"
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
32 #include <libebackend/libebackend.h>
34 #include "e-book-backend-sexp.h"
36 #define E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_BOOK_BACKEND_SQLITEDB, EBookBackendSqliteDBPrivate))
43 # define LOCK_MUTEX(mutex) \
45 g_message ("%s: DB Locking ", G_STRFUNC); \
46 g_mutex_lock (mutex); \
47 g_message ("%s: DB Locked ", G_STRFUNC); \
50 # define UNLOCK_MUTEX(mutex) \
52 g_message ("%s: Unlocking ", G_STRFUNC); \
53 g_mutex_unlock (mutex); \
54 g_message ("%s: DB Unlocked ", G_STRFUNC); \
57 # define LOCK_MUTEX(mutex) g_mutex_lock (mutex)
58 # define UNLOCK_MUTEX(mutex) g_mutex_unlock (mutex)
61 #define DB_FILENAME "contacts.db"
62 #define FOLDER_VERSION 6
65 INDEX_PREFIX = (1 << 0),
66 INDEX_SUFFIX = (1 << 1),
67 INDEX_PHONE = (1 << 2)
71 EContactField field; /* The EContact field */
72 GType type; /* The GType (only support string or gboolean) */
73 const gchar *dbname; /* The key for this field in the sqlite3 table */
74 IndexFlags index; /* Whether this summary field should have an index in the SQLite DB */
77 struct _EBookBackendSqliteDBPrivate {
83 GMutex updates_lock; /* This is for deprecated e_book_backend_sqlitedb_lock_updates () */
86 guint32 in_transaction;
88 SummaryField *summary_fields;
89 gint n_summary_fields;
90 guint have_attr_list : 1;
91 IndexFlags attr_list_indexes;
94 G_DEFINE_TYPE (EBookBackendSqliteDB, e_book_backend_sqlitedb, G_TYPE_OBJECT)
96 static GHashTable *db_connections = NULL;
97 static GMutex dbcon_lock;
99 static EContactField default_summary_fields[] = {
105 E_CONTACT_GIVEN_NAME,
106 E_CONTACT_FAMILY_NAME,
109 E_CONTACT_LIST_SHOW_ADDRESSES,
113 /* Create indexes on full_name and email fields as autocompletion queries would mainly
116 static EContactField default_indexed_fields[] = {
121 static EBookIndexType default_index_types[] = {
126 static SummaryField * append_summary_field (GArray *array,
128 gboolean *have_attr_list,
131 static gboolean upgrade_contacts_table (EBookBackendSqliteDB *ebsdb,
132 const gchar *folderid,
136 summary_dbname_from_field (EBookBackendSqliteDB *ebsdb,
141 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
142 if (ebsdb->priv->summary_fields[i].field == field)
143 return ebsdb->priv->summary_fields[i].dbname;
150 summary_index_from_field_name (EBookBackendSqliteDB *ebsdb,
151 const gchar *field_name)
156 field = e_contact_field_id (field_name);
158 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
159 if (ebsdb->priv->summary_fields[i].field == field)
167 EBookBackendSqliteDB *ebsdb;
172 e-book-backend-sqlitedb-error-quark,
173 e_book_backend_sqlitedb_error)
176 e_book_backend_sqlitedb_dispose (GObject *object)
178 EBookBackendSqliteDBPrivate *priv;
180 priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
182 g_mutex_lock (&dbcon_lock);
183 if (db_connections != NULL) {
184 if (priv->hash_key != NULL) {
185 g_hash_table_remove (db_connections, priv->hash_key);
187 if (g_hash_table_size (db_connections) == 0) {
188 g_hash_table_destroy (db_connections);
189 db_connections = NULL;
192 g_free (priv->hash_key);
193 priv->hash_key = NULL;
196 g_mutex_unlock (&dbcon_lock);
198 /* Chain up to parent's dispose() method. */
199 G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->dispose (object);
203 e_book_backend_sqlitedb_finalize (GObject *object)
205 EBookBackendSqliteDBPrivate *priv;
207 priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
209 sqlite3_close (priv->db);
212 g_free (priv->summary_fields);
214 g_mutex_clear (&priv->lock);
215 g_mutex_clear (&priv->updates_lock);
217 /* Chain up to parent's finalize() method. */
218 G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->finalize (object);
222 e_book_backend_sqlitedb_class_init (EBookBackendSqliteDBClass *class)
224 GObjectClass *object_class;
226 g_type_class_add_private (class, sizeof (EBookBackendSqliteDBPrivate));
228 object_class = G_OBJECT_CLASS (class);
229 object_class->dispose = e_book_backend_sqlitedb_dispose;
230 object_class->finalize = e_book_backend_sqlitedb_finalize;
234 e_book_backend_sqlitedb_init (EBookBackendSqliteDB *ebsdb)
236 ebsdb->priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (ebsdb);
238 ebsdb->priv->store_vcard = TRUE;
240 ebsdb->priv->in_transaction = 0;
241 g_mutex_init (&ebsdb->priv->lock);
242 g_mutex_init (&ebsdb->priv->updates_lock);
246 get_string_cb (gpointer ref,
253 *ret = g_strdup (cols [0]);
259 get_bool_cb (gpointer ref,
266 *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
279 * Callers should hold the rw lock depending on read or write operation
283 book_backend_sql_exec_real (sqlite3 *db,
285 gint (*callback)(gpointer ,gint,gchar **,gchar **),
289 gchar *errmsg = NULL;
292 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
293 while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
295 sqlite3_free (errmsg);
299 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
302 if (ret != SQLITE_OK) {
303 d (g_printerr ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
304 g_set_error_literal (
305 error, E_BOOK_SDB_ERROR,
306 ret == SQLITE_CONSTRAINT ?
307 E_BOOK_SDB_ERROR_CONSTRAINT : E_BOOK_SDB_ERROR_OTHER,
309 sqlite3_free (errmsg);
315 sqlite3_free (errmsg);
323 print_debug_cb (gpointer ref,
330 g_printerr (" DEBUG BEGIN:\n");
332 for (i = 0; i < n_cols; i++)
333 g_printerr (" NAME: '%s' VALUE: %s\n", name[i], cols[i]);
335 g_printerr (" DEBUG END\n");
340 static gint G_GNUC_CONST
343 static gint booksql_debug = -1;
345 if (booksql_debug == -1) {
346 const gchar *const tmp = g_getenv ("BOOKSQL_DEBUG");
347 booksql_debug = (tmp != NULL ? MAX (0, atoi (tmp)) : 0);
350 return booksql_debug;
354 book_backend_sql_debug (sqlite3 *db,
356 gint (*callback)(gpointer ,gint,gchar **,gchar **),
360 GError *local_error = NULL;
362 g_printerr ("DEBUG STATEMENT: %s\n", stmt);
364 if (booksql_debug () > 1) {
365 gchar *debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
366 book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
371 g_printerr ("DEBUG STATEMENT END: Error: %s\n", local_error->message);
372 } else if (booksql_debug () > 1) {
373 g_printerr ("DEBUG STATEMENT END: Success\n");
376 g_clear_error (&local_error);
380 book_backend_sql_exec (sqlite3 *db,
382 gint (*callback)(gpointer ,gint,gchar **,gchar **),
386 if (booksql_debug ())
387 book_backend_sql_debug (db, stmt, callback, data, error);
389 return book_backend_sql_exec_real (db, stmt, callback, data, error);
392 /* This function must always be called with the priv->lock held */
394 book_backend_sqlitedb_start_transaction (EBookBackendSqliteDB *ebsdb,
397 gboolean success = TRUE;
399 g_return_val_if_fail (ebsdb != NULL, FALSE);
400 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
401 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
403 ebsdb->priv->in_transaction++;
404 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
406 if (ebsdb->priv->in_transaction == 1) {
408 success = book_backend_sql_exec (
409 ebsdb->priv->db, "BEGIN", NULL, NULL, error);
415 /* This function must always be called with the priv->lock held */
417 book_backend_sqlitedb_commit_transaction (EBookBackendSqliteDB *ebsdb,
420 gboolean success = TRUE;
422 g_return_val_if_fail (ebsdb != NULL, FALSE);
423 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
424 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
426 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
428 ebsdb->priv->in_transaction--;
430 if (ebsdb->priv->in_transaction == 0) {
431 success = book_backend_sql_exec (
432 ebsdb->priv->db, "COMMIT", NULL, NULL, error);
438 /* This function must always be called with the priv->lock held */
440 book_backend_sqlitedb_rollback_transaction (EBookBackendSqliteDB *ebsdb,
443 gboolean success = TRUE;
445 g_return_val_if_fail (ebsdb != NULL, FALSE);
446 g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
447 g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
449 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
451 ebsdb->priv->in_transaction--;
453 if (ebsdb->priv->in_transaction == 0) {
454 success = book_backend_sql_exec (
455 ebsdb->priv->db, "ROLLBACK", NULL, NULL, error);
462 collect_versions_cb (gpointer ref,
469 /* Just collect the first result, all folders
470 * should always have the same DB version. */
471 *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
477 create_folders_table (EBookBackendSqliteDB *ebsdb,
478 gint *previous_schema,
484 /* sync_data points to syncronization data, it could be last_modified
485 * time or a sequence number or some text depending on the backend.
487 * partial_content says whether the contents are partially downloaded
488 * for auto-completion or if it has the complete content.
490 * Have not included a bdata here since the keys table should suffice
491 * any additional need that arises.
494 "CREATE TABLE IF NOT EXISTS folders"
495 "( folder_id TEXT PRIMARY KEY,"
498 " is_populated INTEGER DEFAULT 0,"
499 " partial_content INTEGER DEFAULT 0,"
502 " multivalues TEXT )";
504 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
507 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
510 /* Create a child table to store key/value pairs for a folder. */
511 stmt = "CREATE TABLE IF NOT EXISTS keys"
512 "( key TEXT PRIMARY KEY, value TEXT,"
513 " folder_id TEXT REFERENCES folders)";
514 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
517 stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
518 if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
521 /* Fetch the version, it should be the
522 * same for all folders (hence the LIMIT). */
523 stmt = "SELECT version FROM folders LIMIT 1";
524 success = book_backend_sql_exec (
525 ebsdb->priv->db, stmt, collect_versions_cb, &version, error);
530 /* Upgrade DB to version 2, add revision column
532 * (version = 0 indicates that it did not exist and we just
535 if (version >= 1 && version < 2) {
536 stmt = "ALTER TABLE folders ADD COLUMN revision TEXT";
537 success = book_backend_sql_exec (
538 ebsdb->priv->db, stmt, NULL, NULL, error);
544 /* Upgrade DB to version 3, add multivalues introspection columns
546 if (version >= 1 && version < 3) {
547 stmt = "ALTER TABLE folders ADD COLUMN multivalues TEXT";
548 success = book_backend_sql_exec (
549 ebsdb->priv->db, stmt, NULL, NULL, error);
555 /* Upgrade DB to version 4: Nothing to do. The country-code column it
556 * added got redundant already.
559 /* Upgrade DB to version 5: Drop the reverse_multivalues column, but
560 * wait with converting phone summary values to new format until
561 * create_contacts_table() as we need introspection details for doing
564 if (version >= 3 && version < 5) {
565 stmt = "UPDATE folders SET "
566 "multivalues = REPLACE(RTRIM(REPLACE("
567 "multivalues || ':', ':', "
568 "CASE reverse_multivalues "
569 "WHEN 0 THEN ';prefix ' "
570 "ELSE ';prefix;suffix ' "
572 "reverse_multivalues = NULL";
574 success = book_backend_sql_exec (
575 ebsdb->priv->db, stmt, NULL, NULL, error);
581 /* Finish the eventual upgrade by storing the current schema version.
583 if (version >= 1 && version < FOLDER_VERSION) {
584 gchar *version_update_stmt =
585 sqlite3_mprintf ("UPDATE folders SET version = %d", FOLDER_VERSION);
587 success = book_backend_sql_exec (
588 ebsdb->priv->db, version_update_stmt, NULL, NULL, error);
590 sqlite3_free (version_update_stmt);
596 *previous_schema = version;
597 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
600 /* The GError is already set. */
601 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
603 *previous_schema = 0;
608 format_multivalues (EBookBackendSqliteDB *ebsdb)
612 gboolean first = TRUE;
614 string = g_string_new (NULL);
616 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
617 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
621 g_string_append_c (string, ':');
623 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
625 if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0)
626 g_string_append (string, ";prefix");
627 if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
628 g_string_append (string, ";suffix");
629 if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0)
630 g_string_append (string, ";phone");
634 return g_string_free (string, FALSE);
638 add_folder_into_db (EBookBackendSqliteDB *ebsdb,
639 const gchar *folderid,
640 const gchar *folder_name,
647 if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
650 multivalues = format_multivalues (ebsdb);
652 stmt = sqlite3_mprintf (
653 "INSERT OR IGNORE INTO "
654 "folders ( folder_id, folder_name, version, multivalues ) "
655 "VALUES ( %Q, %Q, %d, %Q ) ",
656 folderid, folder_name, FOLDER_VERSION, multivalues);
657 success = book_backend_sql_exec (
658 ebsdb->priv->db, stmt, NULL, NULL, error);
660 g_free (multivalues);
665 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
668 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
674 collect_columns_cb (gpointer ref,
679 GList **columns = (GList **) ref;
682 for (i = 0; i < col; i++) {
684 if (strcmp (name[i], "name") == 0) {
686 if (strcmp (cols[i], "vcard") != 0 &&
687 strcmp (cols[i], "bdata") != 0) {
689 gchar *column = g_strdup (cols[i]);
691 *columns = g_list_prepend (*columns, column);
702 introspect_summary (EBookBackendSqliteDB *ebsdb,
703 const gchar *folderid,
708 GList *summary_columns = NULL, *l;
709 GArray *summary_fields = NULL;
710 gchar *multivalues = NULL;
713 stmt = sqlite3_mprintf ("PRAGMA table_info (%Q);", folderid);
714 success = book_backend_sql_exec (
715 ebsdb->priv->db, stmt, collect_columns_cb, &summary_columns, error);
719 goto introspect_summary_finish;
721 summary_columns = g_list_reverse (summary_columns);
722 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
724 /* Introspect the normal summary fields */
725 for (l = summary_columns; l; l = l->next) {
727 gchar *col = l->data;
729 IndexFlags computed = 0;
731 /* Check if we're parsing a reverse field */
732 if ((p = strstr (col, "_reverse")) != NULL) {
733 computed = INDEX_SUFFIX;
735 } else if ((p = strstr (col, "_phone")) != NULL) {
736 computed = INDEX_PHONE;
740 /* First check exception fields */
741 if (g_ascii_strcasecmp (col, "uid") == 0)
742 field = E_CONTACT_UID;
743 else if (g_ascii_strcasecmp (col, "is_list") == 0)
744 field = E_CONTACT_IS_LIST;
746 field = e_contact_field_id (col);
748 /* Check for parse error */
751 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
752 _("Error introspecting unknown summary field '%s'"), col);
757 /* Computed columns are always declared after the normal columns,
758 * if a reverse field is encountered we need to set the suffix
759 * index on the coresponding summary field
762 for (i = 0; i < summary_fields->len; i++) {
763 SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
765 if (iter->field == field) {
766 iter->index |= computed;
771 append_summary_field (summary_fields, field, NULL, NULL);
776 goto introspect_summary_finish;
778 /* Introspect the multivalied summary fields */
779 stmt = sqlite3_mprintf (
780 "SELECT multivalues FROM folders WHERE folder_id = %Q", folderid);
781 success = book_backend_sql_exec (
782 ebsdb->priv->db, stmt, get_string_cb, &multivalues, error);
786 goto introspect_summary_finish;
788 ebsdb->priv->attr_list_indexes = 0;
791 gchar **fields = g_strsplit (multivalues, ":", 0);
793 for (i = 0; fields[i] != NULL; i++) {
798 params = g_strsplit (fields[i], ";", 0);
799 field = e_contact_field_id (params[0]);
800 iter = append_summary_field (summary_fields, field, NULL, NULL);
803 for (j = 1; params[j]; ++j) {
804 if (strcmp (params[j], "prefix") == 0) {
805 iter->index |= INDEX_PREFIX;
806 } else if (strcmp (params[j], "suffix") == 0) {
807 iter->index |= INDEX_SUFFIX;
808 } else if (strcmp (params[j], "phone") == 0) {
809 iter->index |= INDEX_PHONE;
813 ebsdb->priv->attr_list_indexes |= iter->index;
822 introspect_summary_finish:
824 g_list_free_full (summary_columns, (GDestroyNotify) g_free);
825 g_free (multivalues);
827 /* Apply the introspected summary fields */
829 g_free (ebsdb->priv->summary_fields);
830 ebsdb->priv->n_summary_fields = summary_fields->len;
831 ebsdb->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
832 } else if (summary_fields) {
833 g_array_free (summary_fields, TRUE);
839 /* The column names match the fields used in book-backend-sexp */
841 create_contacts_table (EBookBackendSqliteDB *ebsdb,
842 const gchar *folderid,
843 gint previous_schema,
851 /* Construct the create statement from the summary fields table */
852 string = g_string_new (
853 "CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
855 for (i = 1; i < ebsdb->priv->n_summary_fields; i++) {
856 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
857 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
858 g_string_append (string, " TEXT, ");
859 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
860 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
861 g_string_append (string, " INTEGER, ");
862 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
863 g_warn_if_reached ();
865 /* Additional columns holding normalized reverse values for suffix matching */
866 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
867 if (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) {
868 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
869 g_string_append (string, "_reverse TEXT, ");
872 if (ebsdb->priv->summary_fields[i].index & INDEX_PHONE) {
873 g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
874 g_string_append (string, "_phone TEXT, ");
878 g_string_append (string, "vcard TEXT, bdata TEXT)");
880 stmt = sqlite3_mprintf (string->str, folderid);
881 g_string_free (string, TRUE);
883 success = book_backend_sql_exec (
884 ebsdb->priv->db, stmt, NULL, NULL , error);
888 /* Construct the create statement from the attribute list summary table */
889 if (success && ebsdb->priv->have_attr_list) {
890 string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT NOT NULL REFERENCES %Q(uid), "
891 "field TEXT, value TEXT");
893 if ((ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0)
894 g_string_append (string, ", value_reverse TEXT");
895 if ((ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0)
896 g_string_append (string, ", value_phone TEXT");
898 g_string_append_c (string, ')');
900 tmp = g_strdup_printf ("%s_lists", folderid);
901 stmt = sqlite3_mprintf (string->str, tmp, folderid);
902 g_string_free (string, TRUE);
904 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
907 /* Give the UID an index in this table, always */
908 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS LISTINDEX ON %Q (uid)", tmp);
909 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
912 /* Create indexes if specified */
913 if (success && (ebsdb->priv->attr_list_indexes & INDEX_PREFIX) != 0) {
914 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS VALINDEX ON %Q (value)", tmp);
915 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
919 if (success && (ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0) {
920 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS RVALINDEX ON %Q (value_reverse)", tmp);
921 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
925 if (success && (ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0) {
926 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS PVALINDEX ON %Q (value_phone)", tmp);
927 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
935 success = introspect_summary (ebsdb, folderid, error);
937 /* Create indexes on the summary fields configured for indexing */
938 for (i = 0; success && i < ebsdb->priv->n_summary_fields; i++) {
939 if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0 &&
940 ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
941 /* Derive index name from field & folder */
942 tmp = g_strdup_printf (
944 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
946 stmt = sqlite3_mprintf (
947 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
948 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
949 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
955 (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
956 ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
957 /* Derive index name from field & folder */
958 tmp = g_strdup_printf (
960 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
962 stmt = sqlite3_mprintf (
963 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, folderid,
964 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
965 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
970 if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0 &&
971 ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
972 /* Derive index name from field & folder */
973 tmp = g_strdup_printf ("PINDEX_%s_%s",
974 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
976 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_phone)", tmp, folderid,
977 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
978 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
984 /* Until version 6, the whole contacts table requires a re-normalization of the data */
985 if (success && previous_schema < 6)
986 success = upgrade_contacts_table (ebsdb, folderid, error);
993 const gchar *collation;
998 create_phone_indexes_for_columns (gpointer data,
1003 const gchar *column_name = cols[1];
1004 CollationInfo *info = data;
1006 if (g_str_has_suffix (column_name, "_phone")) {
1007 gchar *index_name, *stmt;
1008 GError *error = NULL;
1010 index_name = g_strdup_printf (
1011 "PINDEX_%s_ON_%s_WITH_%s", column_name, info->table, info->collation);
1012 stmt = sqlite3_mprintf (
1013 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s COLLATE %Q)",
1014 index_name, info->table, column_name, info->collation);
1016 if (!book_backend_sql_exec (info->db, stmt, NULL, NULL, &error)) {
1017 g_warning ("%s: %s", G_STRFUNC, error->message);
1018 g_error_free (error);
1021 sqlite3_free (stmt);
1022 g_free (index_name);
1029 create_phone_indexes_for_tables (gpointer data,
1034 CollationInfo *info = data;
1035 GError *error = NULL;
1038 info->table = cols[0];
1039 stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
1041 if (!book_backend_sql_exec (
1042 info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
1043 g_warning ("%s: %s", G_STRFUNC, error->message);
1044 g_clear_error (&error);
1047 sqlite3_free (stmt);
1049 info->table = tmp = g_strconcat (info->table, "_lists", NULL);
1050 stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
1052 if (!book_backend_sql_exec (
1053 info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
1054 g_warning ("%s: %s", G_STRFUNC, error->message);
1055 g_clear_error (&error);
1058 sqlite3_free (stmt);
1065 ixphone_str (gint country_code,
1066 const gchar *const national_str,
1069 GString *const str = g_string_sized_new (6 + national_len);
1070 g_string_append_printf (str, "+%d|", country_code);
1071 g_string_append_len (str, national_str, national_len);
1076 e_strcmp2n (const gchar *str1,
1081 const gint cmp = memcmp (str1, str2, MIN (len1, len2));
1083 return (cmp != 0 ? cmp :
1085 len1 < len2 ? -1 : 1);
1089 ixphone_compare_for_country (gpointer data,
1095 const gchar *const str1 = arg1;
1096 const gchar *const str2 = arg2;
1097 const gchar *const sep1 = memchr (str1, '|', len1);
1098 const gchar *const sep2 = memchr (str2, '|', len2);
1099 const gint country_code = GPOINTER_TO_INT (data);
1101 g_return_val_if_fail (sep1 != NULL, 0);
1102 g_return_val_if_fail (sep2 != NULL, 0);
1104 if ((str1 == sep1) == (str2 == sep2))
1105 return e_strcmp2n (str1, len1, str2, len2);
1108 GString *const tmp = ixphone_str (country_code, str1, len1);
1109 const gint cmp = e_strcmp2n (tmp->str, tmp->len, str2, len2);
1110 g_string_free (tmp, TRUE);
1113 GString *const tmp = ixphone_str (country_code, str2, len2);
1114 const gint cmp = e_strcmp2n (str1, len1, tmp->str, tmp->len);
1115 g_string_free (tmp, TRUE);
1121 ixphone_compare_national (gpointer data,
1127 const gchar *const country_code = data;
1128 const gchar *const str1 = arg1;
1129 const gchar *const str2 = arg2;
1130 const gchar *sep1 = memchr (str1, '|', len1);
1131 const gchar *sep2 = memchr (str2, '|', len2);
1135 g_return_val_if_fail (sep1 != NULL, 0);
1136 g_return_val_if_fail (sep2 != NULL, 0);
1138 /* First only check national portions */
1140 sep1 + 1, len1 - (sep1 + 1 - str1),
1141 sep2 + 1, len2 - (sep2 + 1 - str2));
1143 /* On match we also have to check for potential country codes.
1144 * Note that we can't just compare the full phone number string
1145 * in the case that both numbers have a country code, because
1146 * this would break the collations sorting order. As a result
1147 * the binary search performed on the index would miss matches.
1148 * Consider the index contains "|2215423789" and "+31|2215423789"
1149 * while we look for "+1|2215423789". By performing full string
1150 * compares in case of fully qualified numbers, we might check
1151 * "+31|2215423789" first and then miss "|2215423789" because
1152 * we traverse the binary tree in wrong direction.
1157 cmp = e_strcmp2n (country_code, strlen (country_code), str2, sep2 - str2);
1158 } else if (sep2 == str2) {
1159 cmp = e_strcmp2n (str1, sep1 - str1, country_code, 2);
1161 /* Also compare the country code if the national number
1162 * matches and both numbers have a country code. */
1163 cmp = e_strcmp2n (str1, sep1 - str1, str2, sep2 - str2);
1167 if (booksql_debug ()) {
1168 gchar *const tmp1 = g_strndup (str1, len1);
1169 gchar *const tmp2 = g_strndup (str2, len2);
1172 (" DEBUG %s('%s', '%s') = %d\n",
1173 G_STRFUNC, tmp1, tmp2, cmp);
1183 create_collation (gpointer data,
1188 gint ret = SQLITE_DONE;
1191 g_warn_if_fail (encoding == SQLITE_UTF8);
1193 if (1 == sscanf (name, "ixphone_%d", &country_code)) {
1194 ret = sqlite3_create_collation (
1195 db, name, SQLITE_UTF8, GINT_TO_POINTER (country_code),
1196 ixphone_compare_for_country);
1197 } else if (strcmp (name, "ixphone_national") == 0) {
1198 country_code = e_phone_number_get_country_code_for_region (NULL, NULL);
1200 ret = sqlite3_create_collation_v2 (
1201 db, name, SQLITE_UTF8,
1202 g_strdup_printf ("+%d", country_code),
1203 ixphone_compare_national, g_free);
1206 if (ret == SQLITE_OK) {
1207 CollationInfo info = { db, name };
1208 GError *error = NULL;
1210 if (!book_backend_sql_exec (
1211 db, "SELECT folder_id FROM folders",
1212 create_phone_indexes_for_tables, &info, &error)) {
1213 g_warning ("%s(%s): %s", G_STRFUNC, name, error->message);
1214 g_error_free (error);
1216 } else if (ret != SQLITE_DONE) {
1217 g_warning ("%s(%s): %s", G_STRFUNC, name, sqlite3_errmsg (db));
1222 book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb,
1223 const gchar *filename,
1224 gint *previous_schema,
1229 e_sqlite3_vfs_init ();
1231 ret = sqlite3_open (filename, &ebsdb->priv->db);
1233 if (ret == SQLITE_OK)
1234 ret = sqlite3_collation_needed (ebsdb->priv->db, ebsdb, create_collation);
1236 if (ret != SQLITE_OK) {
1237 if (!ebsdb->priv->db) {
1239 error, E_BOOK_SDB_ERROR,
1240 E_BOOK_SDB_ERROR_OTHER,
1241 _("Insufficient memory"));
1243 const gchar *errmsg;
1244 errmsg = sqlite3_errmsg (ebsdb->priv->db);
1245 d (g_printerr ("Can't open database %s: %s\n", path, errmsg));
1246 g_set_error_literal (
1247 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER, errmsg);
1248 sqlite3_close (ebsdb->priv->db);
1253 book_backend_sql_exec (
1255 "ATTACH DATABASE ':memory:' AS mem",
1257 book_backend_sql_exec (
1259 "PRAGMA foreign_keys = ON",
1261 book_backend_sql_exec (
1263 "PRAGMA case_sensitive_like = ON",
1266 return create_folders_table (ebsdb, previous_schema, error);
1269 static EBookBackendSqliteDB *
1270 e_book_backend_sqlitedb_new_internal (const gchar *path,
1271 const gchar *emailid,
1272 const gchar *folderid,
1273 const gchar *folder_name,
1274 gboolean store_vcard,
1275 SummaryField *fields,
1277 gboolean have_attr_list,
1278 IndexFlags attr_list_indexes,
1281 EBookBackendSqliteDB *ebsdb;
1282 gchar *hash_key, *filename;
1283 gint previous_schema = 0;
1285 g_return_val_if_fail (path != NULL, NULL);
1286 g_return_val_if_fail (emailid != NULL, NULL);
1287 g_return_val_if_fail (folderid != NULL, NULL);
1288 g_return_val_if_fail (folder_name != NULL, NULL);
1290 g_mutex_lock (&dbcon_lock);
1292 hash_key = g_strdup_printf ("%s@%s", emailid, path);
1293 if (db_connections != NULL) {
1294 ebsdb = g_hash_table_lookup (db_connections, hash_key);
1297 g_object_ref (ebsdb);
1303 ebsdb = g_object_new (E_TYPE_BOOK_BACKEND_SQLITEDB, NULL);
1304 ebsdb->priv->path = g_strdup (path);
1305 ebsdb->priv->summary_fields = fields;
1306 ebsdb->priv->n_summary_fields = n_fields;
1307 ebsdb->priv->have_attr_list = have_attr_list;
1308 ebsdb->priv->attr_list_indexes = attr_list_indexes;
1309 ebsdb->priv->store_vcard = store_vcard;
1310 if (g_mkdir_with_parents (path, 0777) < 0) {
1311 g_mutex_unlock (&dbcon_lock);
1313 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1314 "Can not make parent directory: errno %d", errno);
1317 filename = g_build_filename (path, DB_FILENAME, NULL);
1319 if (!book_backend_sqlitedb_load (ebsdb, filename, &previous_schema, error)) {
1320 g_mutex_unlock (&dbcon_lock);
1321 g_object_unref (ebsdb);
1327 if (db_connections == NULL)
1328 db_connections = g_hash_table_new_full (
1329 (GHashFunc) g_str_hash,
1330 (GEqualFunc) g_str_equal,
1331 (GDestroyNotify) g_free,
1332 (GDestroyNotify) NULL);
1333 g_hash_table_insert (db_connections, hash_key, ebsdb);
1334 ebsdb->priv->hash_key = g_strdup (hash_key);
1337 /* While the global dbcon_lock is held, hold the ebsdb specific lock and
1338 * prolong the locking on that instance until the folders are all set up
1340 LOCK_MUTEX (&ebsdb->priv->lock);
1341 g_mutex_unlock (&dbcon_lock);
1343 if (!add_folder_into_db (ebsdb, folderid, folder_name, error)) {
1344 UNLOCK_MUTEX (&ebsdb->priv->lock);
1345 g_object_unref (ebsdb);
1349 if (!create_contacts_table (ebsdb, folderid, previous_schema, error)) {
1350 UNLOCK_MUTEX (&ebsdb->priv->lock);
1351 g_object_unref (ebsdb);
1355 UNLOCK_MUTEX (&ebsdb->priv->lock);
1360 static SummaryField *
1361 append_summary_field (GArray *array,
1362 EContactField field,
1363 gboolean *have_attr_list,
1366 const gchar *dbname = NULL;
1367 GType type = G_TYPE_INVALID;
1369 SummaryField new_field = { 0, };
1371 if (field < 1 || field >= E_CONTACT_FIELD_LAST) {
1373 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1374 _("Invalid contact field '%d' specified in summary"), field);
1378 /* Avoid including the same field twice in the summary */
1379 for (i = 0; i < array->len; i++) {
1380 SummaryField *iter = &g_array_index (array, SummaryField, i);
1381 if (field == iter->field)
1385 /* Resolve some exceptions, we store these
1386 * specific contact fields with different names
1387 * than those found in the EContactField table
1393 case E_CONTACT_IS_LIST:
1397 dbname = e_contact_field_name (field);
1401 type = e_contact_field_type (field);
1403 if (type != G_TYPE_STRING &&
1404 type != G_TYPE_BOOLEAN &&
1405 type != E_TYPE_CONTACT_ATTR_LIST) {
1407 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1408 _("Contact field '%s' of type '%s' specified in summary, "
1409 "but only boolean, string and string list field types are supported"),
1410 e_contact_pretty_name (field), g_type_name (type));
1414 if (type == E_TYPE_CONTACT_ATTR_LIST && have_attr_list)
1415 *have_attr_list = TRUE;
1417 new_field.field = field;
1418 new_field.dbname = dbname;
1419 new_field.type = type;
1420 new_field.index = 0;
1421 g_array_append_val (array, new_field);
1423 return &g_array_index (array, SummaryField, array->len - 1);
1427 summary_fields_add_indexes (GArray *array,
1428 EContactField *indexes,
1429 EBookIndexType *index_types,
1431 IndexFlags *attr_list_indexes)
1435 for (i = 0; i < array->len; i++) {
1436 SummaryField *sfield = &g_array_index (array, SummaryField, i);
1438 for (j = 0; j < n_indexes; j++) {
1439 if (sfield->field == indexes[j]) {
1440 switch (index_types[j]) {
1441 case E_BOOK_INDEX_PREFIX:
1442 sfield->index |= INDEX_PREFIX;
1444 if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1445 *attr_list_indexes |= INDEX_PREFIX;
1447 case E_BOOK_INDEX_SUFFIX:
1448 sfield->index |= INDEX_SUFFIX;
1450 if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1451 *attr_list_indexes |= INDEX_SUFFIX;
1453 case E_BOOK_INDEX_PHONE:
1454 sfield->index |= INDEX_PHONE;
1456 if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1457 *attr_list_indexes |= INDEX_PHONE;
1460 g_warn_if_reached ();
1469 * e_book_backend_sqlitedb_new_full:
1470 * @path: location where the db would be created
1471 * @emailid: email id of the user
1472 * @folderid: folder id of the address-book
1473 * @folder_name: name of the address-book
1474 * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1475 * @setup: an #ESourceBackendSummarySetup describing how the summary should be setup
1476 * @error: A location to store any error that may have occurred
1478 * Like e_book_backend_sqlitedb_new(), but allows configuration of which contact fields
1479 * will be stored for quick reference in the summary. The configuration indicated by
1480 * @setup will only be taken into account when initially creating the underlying table,
1481 * further configurations will be ignored.
1483 * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
1484 * they will be stored in the summary regardless of this function's parameters
1486 * <note><para>Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
1487 * #E_TYPE_CONTACT_ATTR_LIST are currently supported.</para></note>
1489 * Returns: (transfer full): The newly created #EBookBackendSqliteDB
1493 EBookBackendSqliteDB *
1494 e_book_backend_sqlitedb_new_full (const gchar *path,
1495 const gchar *emailid,
1496 const gchar *folderid,
1497 const gchar *folder_name,
1498 gboolean store_vcard,
1499 ESourceBackendSummarySetup *setup,
1502 EBookBackendSqliteDB *ebsdb = NULL;
1503 EContactField *fields;
1504 EContactField *indexed_fields;
1505 EBookIndexType *index_types = NULL;
1506 gboolean have_attr_list = FALSE;
1507 IndexFlags attr_list_indexes = 0;
1508 gboolean had_error = FALSE;
1509 GArray *summary_fields;
1510 gint n_fields = 0, n_indexed_fields = 0, i;
1512 fields = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
1513 indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
1515 /* No specified summary fields indicates the default summary configuration should be used */
1516 if (n_fields <= 0) {
1517 ebsdb = e_book_backend_sqlitedb_new (path, emailid, folderid, folder_name, store_vcard, error);
1519 g_free (index_types);
1520 g_free (indexed_fields);
1525 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1527 /* Ensure the non-optional fields first */
1528 append_summary_field (summary_fields, E_CONTACT_UID, &have_attr_list, error);
1529 append_summary_field (summary_fields, E_CONTACT_REV, &have_attr_list, error);
1531 for (i = 0; i < n_fields; i++) {
1532 if (!append_summary_field (summary_fields, fields[i], &have_attr_list, error)) {
1539 g_array_free (summary_fields, TRUE);
1541 g_free (index_types);
1542 g_free (indexed_fields);
1546 /* Add the 'indexed' flag to the SummaryField structs */
1547 summary_fields_add_indexes (
1548 summary_fields, indexed_fields, index_types, n_indexed_fields,
1549 &attr_list_indexes);
1551 ebsdb = e_book_backend_sqlitedb_new_internal (
1552 path, emailid, folderid, folder_name,
1554 (SummaryField *) summary_fields->data,
1555 summary_fields->len,
1561 g_free (index_types);
1562 g_free (indexed_fields);
1563 g_array_free (summary_fields, FALSE);
1569 * e_book_backend_sqlitedb_new
1570 * @path: location where the db would be created
1571 * @emailid: email id of the user
1572 * @folderid: folder id of the address-book
1573 * @folder_name: name of the address-book
1574 * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1577 * If the path for multiple addressbooks are same, the contacts from all addressbooks
1578 * would be stored in same db in different tables.
1584 EBookBackendSqliteDB *
1585 e_book_backend_sqlitedb_new (const gchar *path,
1586 const gchar *emailid,
1587 const gchar *folderid,
1588 const gchar *folder_name,
1589 gboolean store_vcard,
1592 EBookBackendSqliteDB *ebsdb;
1593 GArray *summary_fields;
1594 gboolean have_attr_list = FALSE;
1595 IndexFlags attr_list_indexes = 0;
1598 /* Create the default summary structs */
1599 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1600 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
1601 append_summary_field (summary_fields, default_summary_fields[i], &have_attr_list, NULL);
1603 /* Add the default index flags */
1604 summary_fields_add_indexes (
1606 default_indexed_fields,
1607 default_index_types,
1608 G_N_ELEMENTS (default_indexed_fields),
1609 &attr_list_indexes);
1611 ebsdb = e_book_backend_sqlitedb_new_internal (
1612 path, emailid, folderid, folder_name,
1614 (SummaryField *) summary_fields->data,
1615 summary_fields->len,
1620 g_array_free (summary_fields, FALSE);
1626 e_book_backend_sqlitedb_lock_updates (EBookBackendSqliteDB *ebsdb,
1631 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1633 LOCK_MUTEX (&ebsdb->priv->updates_lock);
1635 LOCK_MUTEX (&ebsdb->priv->lock);
1636 success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1637 UNLOCK_MUTEX (&ebsdb->priv->lock);
1643 e_book_backend_sqlitedb_unlock_updates (EBookBackendSqliteDB *ebsdb,
1649 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1651 LOCK_MUTEX (&ebsdb->priv->lock);
1652 success = do_commit ?
1653 book_backend_sqlitedb_commit_transaction (ebsdb, error) :
1654 book_backend_sqlitedb_rollback_transaction (ebsdb, error);
1655 UNLOCK_MUTEX (&ebsdb->priv->lock);
1657 UNLOCK_MUTEX (&ebsdb->priv->updates_lock);
1663 mprintf_suffix (const gchar *normal)
1665 gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1666 gchar *stmt = sqlite3_mprintf ("%Q", reverse);
1672 static EPhoneNumber *
1673 phone_number_from_string (const gchar *normal,
1674 const gchar *default_region)
1676 EPhoneNumber *number = NULL;
1678 /* Don't warn about erronous phone number strings, it's a perfectly normal
1679 * use case for users to enter notes instead of phone numbers in the phone
1680 * number contact fields, such as "Ask Jenny for Lisa's phone number"
1682 if (normal && e_phone_number_is_supported ())
1683 number = e_phone_number_from_string (normal, default_region, NULL);
1689 convert_phone (const gchar *normal,
1690 const gchar *default_region)
1692 EPhoneNumber *number = phone_number_from_string (normal, default_region);
1693 gchar *indexed_phone_number = NULL;
1694 gchar *national_number = NULL;
1695 gint country_code = 0;
1698 EPhoneNumberCountrySource source;
1700 national_number = e_phone_number_get_national_number (number);
1701 country_code = e_phone_number_get_country_code (number, &source);
1702 e_phone_number_free (number);
1704 if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
1708 if (national_number) {
1709 indexed_phone_number = country_code
1710 ? g_strdup_printf ("+%d|%s", country_code, national_number)
1711 : g_strconcat ("|", national_number, NULL);
1713 g_free (national_number);
1716 return indexed_phone_number;
1720 mprintf_phone (const gchar *normal,
1721 const gchar *default_region)
1723 gchar *phone = convert_phone (normal, default_region);
1727 stmt = sqlite3_mprintf ("%Q", phone);
1734 /* Add Contact (free the result with g_free() ) */
1736 insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
1738 const gchar *folderid,
1739 gboolean store_vcard,
1740 gboolean replace_existing,
1741 const gchar *default_region)
1744 gchar *str, *vcard_str;
1747 str = sqlite3_mprintf (
1748 "INSERT or %s INTO %Q VALUES (",
1749 replace_existing ? "REPLACE" : "FAIL", folderid);
1750 string = g_string_new (str);
1753 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
1754 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
1759 g_string_append (string, ", ");
1761 val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field);
1763 /* Special exception, never normalize the UID or REV string */
1764 if (ebsdb->priv->summary_fields[i].field != E_CONTACT_UID &&
1765 ebsdb->priv->summary_fields[i].field != E_CONTACT_REV)
1766 normal = e_util_utf8_normalize (val);
1768 normal = g_strdup (val);
1770 str = sqlite3_mprintf ("%Q", normal);
1771 g_string_append (string, str);
1774 if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
1775 str = mprintf_suffix (normal);
1776 g_string_append (string, ", ");
1777 g_string_append (string, str);
1781 if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0) {
1782 str = mprintf_phone (normal, default_region);
1783 g_string_append (string, ", ");
1784 g_string_append (string, str ? str : "NULL");
1790 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
1794 g_string_append (string, ", ");
1796 val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field) ? TRUE : FALSE;
1797 g_string_append_printf (string, "%d", val ? 1 : 0);
1799 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1800 g_warn_if_reached ();
1803 vcard_str = store_vcard ? e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30) : NULL;
1804 str = sqlite3_mprintf (", %Q, %Q)", vcard_str, NULL);
1806 g_string_append (string, str);
1811 return g_string_free (string, FALSE);
1815 update_e164_attribute_params (EVCard *vcard,
1816 const gchar *default_region)
1820 for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
1821 EVCardAttribute *const attr = attr_list->data;
1822 EVCardAttributeParam *param = NULL;
1823 gchar *e164 = NULL, *cc, *nn;
1824 GList *param_list, *values;
1826 /* We only attach E164 parameters to TEL attributes. */
1827 if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
1830 /* Compute E164 number. */
1831 values = e_vcard_attribute_get_values (attr);
1833 e164 = values && values->data
1834 ? convert_phone (values->data, default_region)
1838 e_vcard_attribute_remove_param (attr, EVC_X_E164);
1842 /* Find already exisiting parameter, so that we can reuse it. */
1843 for (param_list = e_vcard_attribute_get_params (attr); param_list; param_list = param_list->next) {
1844 if (strcmp (e_vcard_attribute_param_get_name (param_list->data), EVC_X_E164) == 0) {
1845 param = param_list->data;
1850 /* Create a new parameter instance if needed. Otherwise clean
1851 * the existing parameter's values: This is much cheaper than
1852 * checking for modifications. */
1853 if (param == NULL) {
1854 param = e_vcard_attribute_param_new (EVC_X_E164);
1855 e_vcard_attribute_add_param (attr, param);
1857 e_vcard_attribute_param_remove_values (param);
1860 /* Split the phone number into country calling code and
1861 * national number code. */
1862 nn = strchr (e164, '|');
1865 g_warn_if_reached ();
1872 /* Assign the parameter values. It seems odd that we revert
1873 * the order of NN and CC, but at least EVCard's parser doesn't
1874 * permit an empty first param value. Which of course could be
1875 * fixed - in order to create a nice potential IOP problem with
1876 ** other vCard parsers. */
1877 e_vcard_attribute_param_add_values (param, nn, cc, NULL);
1884 insert_contact (EBookBackendSqliteDB *ebsdb,
1886 const gchar *folderid,
1887 gboolean replace_existing,
1888 const gchar *default_region,
1891 EBookBackendSqliteDBPrivate *priv;
1897 /* Update E.164 parameters in vcard if needed */
1898 if (priv->store_vcard)
1899 update_e164_attribute_params (E_VCARD (contact), default_region);
1901 /* Update main summary table */
1902 stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing, default_region);
1903 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1906 /* Update attribute list table */
1907 if (success && priv->have_attr_list) {
1908 gchar *list_folder = g_strdup_printf ("%s_lists", folderid);
1913 /* First remove all entries for this UID */
1914 uid = e_contact_get (contact, E_CONTACT_UID);
1915 stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", list_folder, uid);
1916 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1917 sqlite3_free (stmt);
1919 for (i = 0; success && i < priv->n_summary_fields; i++) {
1920 if (priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1923 values = e_contact_get (contact, priv->summary_fields[i].field);
1925 for (l = values; success && l != NULL; l = l->next) {
1926 gchar *value = (gchar *) l->data;
1927 gchar *normal = e_util_utf8_normalize (value);
1928 gchar *stmt_suffix = NULL;
1929 gchar *stmt_phone = NULL;
1931 if ((priv->attr_list_indexes & INDEX_SUFFIX) != 0
1932 && (priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
1933 stmt_suffix = mprintf_suffix (normal);
1935 if ((priv->attr_list_indexes & INDEX_PHONE) != 0
1936 && (priv->summary_fields[i].index & INDEX_PHONE) != 0)
1937 stmt_phone = mprintf_phone (normal, default_region);
1939 stmt = sqlite3_mprintf (
1940 "INSERT INTO %Q (uid, field, value%s%s) "
1941 "VALUES (%Q, %Q, %Q%s%s%s%s)",
1943 stmt_suffix ? ", value_reverse" : "",
1944 stmt_phone ? ", value_phone" : "",
1945 uid, priv->summary_fields[i].dbname, normal,
1946 stmt_suffix ? ", " : "",
1947 stmt_suffix ? stmt_suffix : "",
1948 stmt_phone ? ", " : "",
1949 stmt_phone ? stmt_phone : "");
1952 sqlite3_free (stmt_suffix);
1954 sqlite3_free (stmt_phone);
1956 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1957 sqlite3_free (stmt);
1961 /* Free the list of allocated strings */
1962 e_contact_attr_list_free (values);
1965 g_free (list_folder);
1973 * e_book_backend_sqlitedb_new_contact
1974 * @ebsdb: An #EBookBackendSqliteDB
1975 * @folderid: folder id
1976 * @contact: EContact to be added
1977 * @replace_existing: Whether this contact should replace another contact with the same UID.
1978 * @error: A location to store any error that may have occurred.
1980 * This is a convenience wrapper for e_book_backend_sqlitedb_new_contacts,
1981 * which is the preferred means to add or modify multiple contacts when possible.
1983 * Returns: TRUE on success.
1988 e_book_backend_sqlitedb_new_contact (EBookBackendSqliteDB *ebsdb,
1989 const gchar *folderid,
1991 gboolean replace_existing,
1996 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1997 g_return_val_if_fail (folderid != NULL, FALSE);
1998 g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
2003 return e_book_backend_sqlitedb_new_contacts (
2004 ebsdb, folderid, &l,
2005 replace_existing, error);
2009 * e_book_backend_sqlitedb_new_contacts
2010 * @ebsdb: An #EBookBackendSqliteDB
2011 * @folderid: folder id
2012 * @contacts: list of EContacts
2013 * @replace_existing: Whether this contact should replace another contact with the same UID.
2014 * @error: A location to store any error that may have occurred.
2016 * Adds or replaces contacts in @ebsdb. If @replace_existing is specified then existing
2017 * contacts with the same UID will be replaced, otherwise adding an existing contact
2018 * will return an error.
2020 * Returns: TRUE on success.
2025 e_book_backend_sqlitedb_new_contacts (EBookBackendSqliteDB *ebsdb,
2026 const gchar *folderid,
2028 gboolean replace_existing,
2032 gboolean success = TRUE;
2033 gchar *default_region = NULL;
2035 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2036 g_return_val_if_fail (folderid != NULL, FALSE);
2037 g_return_val_if_fail (contacts != NULL, FALSE);
2039 LOCK_MUTEX (&ebsdb->priv->lock);
2041 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
2042 UNLOCK_MUTEX (&ebsdb->priv->lock);
2046 if (e_phone_number_is_supported ()) {
2047 default_region = e_phone_number_get_default_region (error);
2049 if (default_region == NULL)
2053 for (l = contacts; success && l != NULL; l = g_slist_next (l)) {
2054 EContact *contact = (EContact *) l->data;
2056 success = insert_contact (
2057 ebsdb, contact, folderid, replace_existing,
2058 default_region, error);
2061 g_free (default_region);
2064 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
2066 /* The GError is already set. */
2067 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
2069 UNLOCK_MUTEX (&ebsdb->priv->lock);
2075 * e_book_backend_sqlitedb_add_contact
2077 * @folderid: folder id
2078 * @contact: EContact to be added
2079 * @partial_content: contact does not contain full information. Used when
2080 * the backend cache's partial information for auto-completion.
2083 * This is a convenience wrapper for e_book_backend_sqlitedb_add_contacts,
2084 * which is the preferred means to add multiple contacts when possible.
2086 * Returns: TRUE on success.
2090 * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contact() instead.
2093 e_book_backend_sqlitedb_add_contact (EBookBackendSqliteDB *ebsdb,
2094 const gchar *folderid,
2096 gboolean partial_content,
2099 return e_book_backend_sqlitedb_new_contact (ebsdb, folderid, contact, TRUE, error);
2103 * e_book_backend_sqlitedb_add_contacts
2105 * @folderid: folder id
2106 * @contacts: list of EContacts
2107 * @partial_content: contact does not contain full information. Used when
2108 * the backend cache's partial information for auto-completion.
2112 * Returns: TRUE on success.
2116 * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contacts() instead.
2119 e_book_backend_sqlitedb_add_contacts (EBookBackendSqliteDB *ebsdb,
2120 const gchar *folderid,
2122 gboolean partial_content,
2125 return e_book_backend_sqlitedb_new_contacts (ebsdb, folderid, contacts, TRUE, error);
2129 * e_book_backend_sqlitedb_remove_contact:
2131 * FIXME: Document me.
2136 e_book_backend_sqlitedb_remove_contact (EBookBackendSqliteDB *ebsdb,
2137 const gchar *folderid,
2143 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2144 g_return_val_if_fail (folderid != NULL, FALSE);
2145 g_return_val_if_fail (uid != NULL, FALSE);
2147 l.data = (gchar *) uid; /* Won't modify it, I promise :) */
2150 return e_book_backend_sqlitedb_remove_contacts (
2151 ebsdb, folderid, &l, error);
2155 generate_uid_list_for_stmt (GSList *uids)
2157 GString *str = g_string_new (NULL);
2159 gboolean first = TRUE;
2161 for (l = uids; l; l = l->next) {
2162 gchar *uid = (gchar *) l->data;
2165 /* First uid with no comma */
2167 g_string_append_printf (str, ", ");
2171 tmp = sqlite3_mprintf ("%Q", uid);
2172 g_string_append (str, tmp);
2176 return g_string_free (str, FALSE);
2180 generate_delete_stmt (const gchar *table,
2183 GString *str = g_string_new (NULL);
2186 tmp = sqlite3_mprintf ("DELETE FROM %Q WHERE uid IN (", table);
2187 g_string_append (str, tmp);
2190 tmp = generate_uid_list_for_stmt (uids);
2191 g_string_append (str, tmp);
2193 g_string_append_c (str, ')');
2195 return g_string_free (str, FALSE);
2199 * e_book_backend_sqlitedb_remove_contacts:
2201 * FIXME: Document me.
2206 e_book_backend_sqlitedb_remove_contacts (EBookBackendSqliteDB *ebsdb,
2207 const gchar *folderid,
2211 gboolean success = TRUE;
2214 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2215 g_return_val_if_fail (folderid != NULL, FALSE);
2216 g_return_val_if_fail (uids != NULL, FALSE);
2218 LOCK_MUTEX (&ebsdb->priv->lock);
2220 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
2221 UNLOCK_MUTEX (&ebsdb->priv->lock);
2225 /* Delete the auxillary contact infos first */
2226 if (success && ebsdb->priv->have_attr_list) {
2227 gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
2229 stmt = generate_delete_stmt (lists_folder, uids);
2230 g_free (lists_folder);
2232 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
2237 stmt = generate_delete_stmt (folderid, uids);
2238 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
2243 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
2245 /* The GError is already set. */
2246 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
2248 UNLOCK_MUTEX (&ebsdb->priv->lock);
2253 struct _contact_info {
2255 gboolean partial_content;
2259 contact_found_cb (gpointer ref,
2264 struct _contact_info *cinfo = ref;
2266 cinfo->exists = TRUE;
2267 cinfo->partial_content = cols[0] ? strtoul (cols[0], NULL, 10) : 0;
2273 * e_book_backend_sqlitedb_has_contact:
2275 * FIXME: Document me.
2280 e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
2281 const gchar *folderid,
2283 gboolean *partial_content,
2286 struct _contact_info cinfo;
2290 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2291 g_return_val_if_fail (folderid != NULL, FALSE);
2292 g_return_val_if_fail (uid != NULL, FALSE);
2294 cinfo.exists = FALSE;
2295 cinfo.partial_content = FALSE;
2297 LOCK_MUTEX (&ebsdb->priv->lock);
2299 stmt = sqlite3_mprintf (
2300 "SELECT partial_content FROM %Q WHERE uid = %Q",
2302 success = book_backend_sql_exec (
2303 ebsdb->priv->db, stmt, contact_found_cb , &cinfo, error);
2304 sqlite3_free (stmt);
2307 *partial_content = cinfo.partial_content;
2309 UNLOCK_MUTEX (&ebsdb->priv->lock);
2311 /* FIXME Returning FALSE can mean either "contact not found" or
2312 * "error occurred". Add a boolean (out) "exists" parameter. */
2313 return success && cinfo.exists;
2317 get_vcard_cb (gpointer ref,
2322 gchar **vcard_str = ref;
2325 *vcard_str = g_strdup (cols [0]);
2331 * e_book_backend_sqlitedb_get_contact:
2333 * FIXME: Document me.
2338 e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
2339 const gchar *folderid,
2341 GHashTable *fields_of_interest,
2342 gboolean *with_all_required_fields,
2345 EContact *contact = NULL;
2348 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2349 g_return_val_if_fail (folderid != NULL, NULL);
2350 g_return_val_if_fail (uid != NULL, NULL);
2352 vcard = e_book_backend_sqlitedb_get_vcard_string (
2353 ebsdb, folderid, uid,
2354 fields_of_interest, with_all_required_fields, error);
2356 if (vcard != NULL) {
2357 contact = e_contact_new_from_vcard_with_uid (vcard, uid);
2365 uid_rev_fields (GHashTable *fields_of_interest)
2367 GHashTableIter iter;
2368 gpointer key, value;
2370 if (!fields_of_interest || g_hash_table_size (fields_of_interest) > 2)
2373 g_hash_table_iter_init (&iter, fields_of_interest);
2374 while (g_hash_table_iter_next (&iter, &key, &value)) {
2375 const gchar *field_name = key;
2376 EContactField field = e_contact_field_id (field_name);
2378 if (field != E_CONTACT_UID &&
2379 field != E_CONTACT_REV)
2387 * e_book_backend_sqlitedb_is_summary_fields:
2388 * @fields_of_interest: A hash table containing the fields of interest
2390 * This only checks if all the fields are part of the default summary fields,
2391 * not part of the configured summary fields.
2395 * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_fields() instead.
2398 e_book_backend_sqlitedb_is_summary_fields (GHashTable *fields_of_interest)
2400 gboolean summary_fields = TRUE;
2401 GHashTableIter iter;
2402 gpointer key, value;
2405 if (!fields_of_interest)
2408 g_hash_table_iter_init (&iter, fields_of_interest);
2409 while (g_hash_table_iter_next (&iter, &key, &value)) {
2410 const gchar *field_name = key;
2411 EContactField field = e_contact_field_id (field_name);
2412 gboolean found = FALSE;
2414 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2415 if (field == default_summary_fields[i]) {
2422 summary_fields = FALSE;
2427 return summary_fields;
2431 * e_book_backend_sqlitedb_check_summary_fields:
2432 * @ebsdb: An #EBookBackendSqliteDB
2433 * @fields_of_interest: A hash table containing the fields of interest
2435 * Checks if all the specified fields are part of the configured summary
2441 e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
2442 GHashTable *fields_of_interest)
2444 gboolean summary_fields = TRUE;
2445 GHashTableIter iter;
2446 gpointer key, value;
2448 if (!fields_of_interest)
2451 LOCK_MUTEX (&ebsdb->priv->lock);
2453 g_hash_table_iter_init (&iter, fields_of_interest);
2454 while (g_hash_table_iter_next (&iter, &key, &value)) {
2455 const gchar *field_name = key;
2456 EContactField field = e_contact_field_id (field_name);
2458 if (summary_dbname_from_field (ebsdb, field) == NULL) {
2459 summary_fields = FALSE;
2464 UNLOCK_MUTEX (&ebsdb->priv->lock);
2466 return summary_fields;
2469 /* free return value with g_free */
2471 summary_select_stmt (GHashTable *fields_of_interest,
2477 string = g_string_new ("SELECT DISTINCT summary.uid");
2479 string = g_string_new ("SELECT summary.uid");
2481 /* Add the E_CONTACT_REV field if they are both requested */
2482 if (g_hash_table_size (fields_of_interest) == 2)
2483 g_string_append (string, ", Rev");
2485 return g_string_free (string, FALSE);
2489 store_data_to_vcard (gpointer ref,
2494 GSList **vcard_data = ref;
2495 EbSdbSearchData *search_data = g_slice_new0 (EbSdbSearchData);
2496 EContact *contact = e_contact_new ();
2500 /* parse through cols, this will be useful if the api starts supporting field restrictions */
2501 for (i = 0; i < ncol; i++)
2503 if (!name[i] || !cols[i])
2506 /* Only UID & REV can be used to create contacts from the summary columns */
2507 if (!g_ascii_strcasecmp (name[i], "uid")) {
2508 e_contact_set (contact, E_CONTACT_UID, cols[i]);
2509 search_data->uid = g_strdup (cols[i]);
2510 } else if (!g_ascii_strcasecmp (name[i], "Rev")) {
2511 e_contact_set (contact, E_CONTACT_REV, cols[i]);
2512 } else if (!g_ascii_strcasecmp (name[i], "bdata"))
2513 search_data->bdata = g_strdup (cols[i]);
2516 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2517 search_data->vcard = vcard;
2518 *vcard_data = g_slist_prepend (*vcard_data, search_data);
2520 g_object_unref (contact);
2525 * e_book_backend_sqlitedb_get_vcard_string:
2526 * @ebsdb: An #EBookBackendSqliteDB
2527 * @folderid: The folder id
2528 * @uid: The uid to fetch a vcard for
2529 * @fields_of_interest: The required fields for this vcard, or %NULL to require all fields.
2530 * @with_all_required_fields: (allow none) (out): Whether all the required fields are present in the returned vcard.
2531 * @error: A location to store any error that may have occurred.
2533 * Searches @ebsdb in the context of @folderid for @uid.
2535 * If @ebsdb is configured to store the whole vcards, the whole vcard will be returned.
2536 * Otherwise the summary cache will be searched and the virtual vcard will be built
2537 * from the summary cache.
2539 * In either case, @with_all_required_fields if specified, will be updated to reflect whether
2540 * the returned vcard string satisfies the passed 'fields_of_interest' parameter.
2542 * Returns: (transfer full): The vcard string for @uid or %NULL if @uid was not found.
2547 e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
2548 const gchar *folderid,
2550 GHashTable *fields_of_interest,
2551 gboolean *with_all_required_fields,
2555 gchar *vcard_str = NULL;
2556 gboolean local_with_all_required_fields = FALSE;
2558 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2559 g_return_val_if_fail (folderid != NULL, NULL);
2560 g_return_val_if_fail (uid != NULL, NULL);
2562 LOCK_MUTEX (&ebsdb->priv->lock);
2564 /* Try constructing contacts from only UID/REV first if that's requested */
2565 if (uid_rev_fields (fields_of_interest)) {
2566 GSList *vcards = NULL;
2567 gchar *select_portion;
2569 select_portion = summary_select_stmt (fields_of_interest, FALSE);
2571 stmt = sqlite3_mprintf (
2572 "%s FROM %Q AS summary WHERE summary.uid = %Q",
2573 select_portion, folderid, uid);
2574 book_backend_sql_exec (ebsdb->priv->db, stmt, store_data_to_vcard, &vcards, error);
2575 sqlite3_free (stmt);
2576 g_free (select_portion);
2579 EbSdbSearchData *s_data = (EbSdbSearchData *) vcards->data;
2581 vcard_str = s_data->vcard;
2582 s_data->vcard = NULL;
2584 e_book_backend_sqlitedb_search_data_free (s_data);
2586 g_slist_free (vcards);
2590 local_with_all_required_fields = TRUE;
2591 } else if (ebsdb->priv->store_vcard) {
2592 stmt = sqlite3_mprintf (
2593 "SELECT vcard FROM %Q WHERE uid = %Q", folderid, uid);
2594 book_backend_sql_exec (
2595 ebsdb->priv->db, stmt,
2596 get_vcard_cb , &vcard_str, error);
2597 sqlite3_free (stmt);
2599 local_with_all_required_fields = TRUE;
2602 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2603 _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2607 UNLOCK_MUTEX (&ebsdb->priv->lock);
2609 if (with_all_required_fields)
2610 *with_all_required_fields = local_with_all_required_fields;
2612 if (!vcard_str && error && !*error)
2614 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_CONTACT_NOT_FOUND,
2615 _("Contact '%s' not found"), uid ? uid : "NULL");
2621 CHECK_IS_SUMMARY = (1 << 0),
2622 CHECK_IS_LIST_ATTR = (1 << 1),
2623 CHECK_UNSUPPORTED = (1 << 2),
2624 CHECK_INVALID = (1 << 3)
2627 static ESExpResult *
2628 func_check_subset (ESExp *f,
2630 struct _ESExpTerm **argv,
2633 ESExpResult *r, *r1;
2634 gboolean one_non_summary_query = FALSE;
2638 for (i = 0; i < argc; i++) {
2639 r1 = e_sexp_term_eval (f, argv[i]);
2641 if (r1->type != ESEXP_RES_INT) {
2642 e_sexp_result_free (f, r1);
2646 result |= r1->value.number;
2648 if ((r1->value.number & CHECK_IS_SUMMARY) == 0)
2649 one_non_summary_query = TRUE;
2651 e_sexp_result_free (f, r1);
2654 /* If at least one subset is not a summary query,
2655 * then the whole query is not a summary query and
2656 * thus cannot be done with an SQL statement
2658 if (one_non_summary_query)
2659 result &= ~CHECK_IS_SUMMARY;
2661 r = e_sexp_result_new (f, ESEXP_RES_INT);
2662 r->value.number = result;
2668 func_check_field_test (EBookBackendSqliteDB *ebsdb,
2669 const gchar *query_name,
2670 const gchar *query_value)
2676 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
2677 if (!g_ascii_strcasecmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), query_name)) {
2678 ret_val |= CHECK_IS_SUMMARY;
2680 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
2681 ret_val |= CHECK_IS_LIST_ATTR;
2687 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2688 if (!g_ascii_strcasecmp (e_contact_field_name (default_summary_fields[i]), query_name)) {
2689 ret_val |= CHECK_IS_SUMMARY;
2691 if (e_contact_field_type (default_summary_fields[i]) == E_TYPE_CONTACT_ATTR_LIST)
2692 ret_val |= CHECK_IS_LIST_ATTR;
2702 static ESExpResult *
2703 func_check (struct _ESExp *f,
2705 struct _ESExpResult **argv,
2708 EBookBackendSqliteDB *ebsdb = data;
2713 && argv[0]->type == ESEXP_RES_STRING
2714 && argv[1]->type == ESEXP_RES_STRING) {
2715 const gchar *query_name = argv[0]->value.string;
2716 const gchar *query_value = argv[1]->value.string;
2718 /* Special case, when testing the special symbolic 'any field' we can
2719 * consider it a summary query (it's similar to a 'no query'). */
2720 if (g_strcmp0 (query_name, "x-evolution-any-field") == 0 &&
2721 g_strcmp0 (query_value, "") == 0) {
2722 ret_val |= CHECK_IS_SUMMARY;
2726 ret_val |= func_check_field_test (ebsdb, query_name, query_value);
2727 } else if (argc == 3
2728 && argv[0]->type == ESEXP_RES_STRING
2729 && argv[1]->type == ESEXP_RES_STRING
2730 && argv[2]->type == ESEXP_RES_STRING) {
2731 const gchar *query_name = argv[0]->value.string;
2732 const gchar *query_value = argv[1]->value.string;
2733 ret_val |= func_check_field_test (ebsdb, query_name, query_value);
2737 r = e_sexp_result_new (f, ESEXP_RES_INT);
2738 r->value.number = ret_val;
2743 static ESExpResult *
2744 func_check_phone (struct _ESExp *f,
2746 struct _ESExpResult **argv,
2749 ESExpResult *const r = func_check (f, argc, argv, data);
2750 const gchar *const query_value = argv[1]->value.string;
2751 EPhoneNumber *number;
2753 /* Here we need to catch unsupported queries and invalid queries
2754 * so we perform validity checks even if func_check() reports this
2755 * as not a part of the summary.
2757 if (!e_phone_number_is_supported ()) {
2758 r->value.number |= CHECK_UNSUPPORTED;
2762 number = e_phone_number_from_string (query_value, NULL, NULL);
2764 if (number == NULL) {
2765 /* Could not construct a phone number from the query input,
2766 * an invalid query error will be propagated to the client.
2768 r->value.number |= CHECK_INVALID;
2770 e_phone_number_free (number);
2776 /* 'builtin' functions */
2777 static const struct {
2780 gint type; /* set to 1 if a function can perform shortcut evaluation, or
2781 doesn't execute everything, 0 otherwise */
2782 } check_symbols[] = {
2783 { "and", (ESExpFunc *) func_check_subset, 1},
2784 { "or", (ESExpFunc *) func_check_subset, 1},
2786 { "contains", func_check, 0 },
2787 { "is", func_check, 0 },
2788 { "beginswith", func_check, 0 },
2789 { "endswith", func_check, 0 },
2790 { "exists", func_check, 0 },
2791 { "eqphone", func_check_phone, 0 },
2792 { "eqphone_national", func_check_phone, 0 },
2793 { "eqphone_short", func_check_phone, 0 }
2797 e_book_backend_sqlitedb_check_summary_query_locked (EBookBackendSqliteDB *ebsdb,
2799 gboolean *with_list_attrs,
2800 gboolean *unsupported_query,
2801 gboolean *invalid_query)
2805 gboolean retval = FALSE;
2809 g_return_val_if_fail (query != NULL, FALSE);
2810 g_return_val_if_fail (*query != '\0', FALSE);
2812 sexp = e_sexp_new ();
2814 for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
2815 if (check_symbols[i].type == 1) {
2816 e_sexp_add_ifunction (
2817 sexp, 0, check_symbols[i].name,
2818 (ESExpIFunc *) check_symbols[i].func, ebsdb);
2820 e_sexp_add_function (
2821 sexp, 0, check_symbols[i].name,
2822 check_symbols[i].func, ebsdb);
2826 e_sexp_input_text (sexp, query, strlen (query));
2827 esexp_error = e_sexp_parse (sexp);
2829 if (esexp_error == -1) {
2831 *invalid_query = TRUE;
2836 r = e_sexp_eval (sexp);
2837 if (r && r->type == ESEXP_RES_INT) {
2838 retval = (r->value.number & CHECK_IS_SUMMARY) != 0;
2840 if (with_list_attrs)
2841 *with_list_attrs = (r->value.number & CHECK_IS_LIST_ATTR) != 0;
2843 if (unsupported_query)
2844 *unsupported_query = (r->value.number & CHECK_UNSUPPORTED) != 0;
2847 *invalid_query = (r->value.number & CHECK_INVALID) != 0;
2850 e_sexp_result_free (sexp, r);
2851 e_sexp_unref (sexp);
2857 * e_book_backend_sqlitedb_check_summary_query:
2858 * @ebsdb: an #EBookBackendSqliteDB
2859 * @query: the query to check
2860 * @with_list_attrs: Return location to store whether the query touches upon list attributes
2862 * Checks whether @query contains only checks for the summary fields
2863 * configured in @ebsdb
2868 e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
2870 gboolean *with_list_attrs)
2872 gboolean is_summary;
2874 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2876 LOCK_MUTEX (&ebsdb->priv->lock);
2877 is_summary = e_book_backend_sqlitedb_check_summary_query_locked (ebsdb, query, with_list_attrs, NULL, NULL);
2878 UNLOCK_MUTEX (&ebsdb->priv->lock);
2884 * e_book_backend_sqlitedb_is_summary_query:
2886 * Checks whether the query contains only checks for the default summary fields
2890 * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_query() instead
2893 e_book_backend_sqlitedb_is_summary_query (const gchar *query)
2895 return e_book_backend_sqlitedb_check_summary_query_locked (NULL, query, NULL, NULL, NULL);
2898 static ESExpResult *
2901 struct _ESExpTerm **argv,
2904 ESExpResult *r, *r1;
2908 string = g_string_new ("( ");
2909 for (i = 0; i < argc; i++) {
2910 r1 = e_sexp_term_eval (f, argv[i]);
2912 if (r1->type != ESEXP_RES_STRING) {
2913 e_sexp_result_free (f, r1);
2916 if (r1->value.string && *r1->value.string)
2917 g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " AND ":"");
2918 e_sexp_result_free (f, r1);
2920 g_string_append (string, " )");
2921 r = e_sexp_result_new (f, ESEXP_RES_STRING);
2923 if (strlen (string->str) == 4) {
2924 r->value.string = g_strdup ("");
2925 g_string_free (string, TRUE);
2927 r->value.string = g_string_free (string, FALSE);
2933 static ESExpResult *
2936 struct _ESExpTerm **argv,
2939 ESExpResult *r, *r1;
2943 string = g_string_new ("( ");
2944 for (i = 0; i < argc; i++) {
2945 r1 = e_sexp_term_eval (f, argv[i]);
2947 if (r1->type != ESEXP_RES_STRING) {
2948 e_sexp_result_free (f, r1);
2951 if (r1->value.string && *r1->value.string)
2952 g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " OR ":"");
2953 e_sexp_result_free (f, r1);
2955 g_string_append (string, " )");
2957 r = e_sexp_result_new (f, ESEXP_RES_STRING);
2958 if (strlen (string->str) == 4) {
2959 r->value.string = g_strdup ("");
2960 g_string_free (string, TRUE);
2962 r->value.string = g_string_free (string, FALSE);
2974 MATCH_NATIONAL_PHONE_NUMBER,
2975 MATCH_SHORT_PHONE_NUMBER
2979 CONVERT_NOTHING = 0,
2980 CONVERT_NORMALIZE = (1 << 0),
2981 CONVERT_REVERSE = (1 << 1),
2982 CONVERT_PHONE = (1 << 2)
2986 extract_digits (const gchar *normal)
2988 gchar *digits = g_new (char, strlen (normal) + 1);
2989 const gchar *src = normal;
2990 gchar *dst = digits;
2992 /* extract digits also considering eastern arabic numerals */
2993 for (src = normal; *src; src = g_utf8_next_char (src)) {
2994 const gunichar uc = g_utf8_get_char_validated (src, -1);
2995 const gint value = g_unichar_digit_value (uc);
3001 *dst++ = '0' + value;
3010 convert_string_value (EBookBackendSqliteDB *ebsdb,
3012 const gchar *region,
3019 gboolean escape_modifier_needed = FALSE;
3020 const gchar *escape_modifier = " ESCAPE '^'";
3021 gchar *computed = NULL;
3025 g_return_val_if_fail (value != NULL, NULL);
3027 if (flags & CONVERT_NORMALIZE)
3028 normal = e_util_utf8_normalize (value);
3030 normal = g_strdup (value);
3032 /* Just assume each character must be escaped. The result of this function
3033 * is discarded shortly after calling this function. Therefore it's
3034 * acceptable to possibly allocate twice the memory needed.
3036 len = strlen (normal);
3037 str = g_string_sized_new (2 * len + 4 + strlen (escape_modifier) - 1);
3038 g_string_append_c (str, '\'');
3041 case MATCH_CONTAINS:
3042 case MATCH_ENDS_WITH:
3043 case MATCH_SHORT_PHONE_NUMBER:
3044 g_string_append_c (str, '%');
3047 case MATCH_BEGINS_WITH:
3049 case MATCH_PHONE_NUMBER:
3050 case MATCH_NATIONAL_PHONE_NUMBER:
3054 if (flags & CONVERT_REVERSE) {
3055 computed = g_utf8_strreverse (normal, -1);
3057 } else if (flags & CONVERT_PHONE) {
3058 computed = convert_phone (normal, region);
3064 while ((c = *ptr++)) {
3066 g_string_append_c (str, '\'');
3067 } else if (c == '%' || c == '^') {
3068 g_string_append_c (str, '^');
3069 escape_modifier_needed = TRUE;
3072 g_string_append_c (str, c);
3076 case MATCH_CONTAINS:
3077 case MATCH_BEGINS_WITH:
3078 g_string_append_c (str, '%');
3081 case MATCH_ENDS_WITH:
3083 case MATCH_PHONE_NUMBER:
3084 case MATCH_NATIONAL_PHONE_NUMBER:
3085 case MATCH_SHORT_PHONE_NUMBER:
3089 g_string_append_c (str, '\'');
3091 if (escape_modifier_needed)
3092 g_string_append (str, escape_modifier);
3097 return g_string_free (str, FALSE);
3101 field_name_and_query_term (EBookBackendSqliteDB *ebsdb,
3102 const gchar *folderid,
3103 const gchar *field_name_input,
3104 const gchar *query_term_input,
3105 const gchar *region,
3107 gboolean *is_list_attr,
3112 gchar *field_name = NULL;
3113 gchar *value = NULL;
3114 gchar *extra = NULL;
3115 gboolean list_attr = FALSE;
3117 summary_index = summary_index_from_field_name (ebsdb, field_name_input);
3119 if (summary_index < 0) {
3120 g_critical ("Only summary field matches should be converted to sql queries");
3121 field_name = g_strconcat (folderid, ".", field_name_input, NULL);
3122 value = convert_string_value (
3123 ebsdb, query_term_input, region,
3124 CONVERT_NORMALIZE, match);
3126 gboolean suffix_search = FALSE;
3127 gboolean phone_search = FALSE;
3129 /* If its a suffix search and we have reverse data to search... */
3130 if (match == MATCH_ENDS_WITH &&
3131 (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0)
3132 suffix_search = TRUE;
3134 /* If its a phone-number search and we have E.164 data to search... */
3135 else if ((match == MATCH_PHONE_NUMBER ||
3136 match == MATCH_NATIONAL_PHONE_NUMBER ||
3137 match == MATCH_SHORT_PHONE_NUMBER) &&
3138 (ebsdb->priv->summary_fields[summary_index].index & INDEX_PHONE) != 0)
3139 phone_search = TRUE;
3141 /* Or also if its an exact match, and we *only* have reverse data which is indexed,
3142 * then prefer the indexed reverse search. */
3143 else if (match == MATCH_IS &&
3144 (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0 &&
3145 (ebsdb->priv->summary_fields[summary_index].index & INDEX_PREFIX) == 0)
3146 suffix_search = TRUE;
3148 if (suffix_search) {
3149 /* Special case for suffix matching:
3150 * o Reverse the string
3151 * o Check the reversed column instead
3152 * o Make it a prefix search
3154 if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3155 field_name = g_strdup ("multi.value_reverse");
3158 field_name = g_strconcat (
3160 ebsdb->priv->summary_fields[summary_index].dbname,
3163 if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
3164 ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
3165 value = convert_string_value (
3166 ebsdb, query_term_input, region, CONVERT_REVERSE,
3167 (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
3169 value = convert_string_value (
3170 ebsdb, query_term_input, region,
3171 CONVERT_REVERSE | CONVERT_NORMALIZE,
3172 (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
3173 } else if (phone_search) {
3174 /* Special case for E.164 matching:
3175 * o Normalize the string
3176 * o Check the E.164 column instead
3178 const gint country_code = e_phone_number_get_country_code_for_region (region, NULL);
3180 if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3181 field_name = g_strdup ("multi.value_phone");
3184 field_name = g_strdup_printf (
3186 ebsdb->priv->summary_fields[summary_index].dbname);
3189 if (match == MATCH_PHONE_NUMBER) {
3190 value = convert_string_value (
3191 ebsdb, query_term_input, region,
3192 CONVERT_NORMALIZE | CONVERT_PHONE, match);
3194 extra = sqlite3_mprintf (" COLLATE ixphone_%d", country_code);
3196 if (match == MATCH_NATIONAL_PHONE_NUMBER) {
3197 value = convert_string_value (
3198 ebsdb, query_term_input, region,
3199 CONVERT_PHONE, MATCH_NATIONAL_PHONE_NUMBER);
3201 extra = sqlite3_mprintf (" COLLATE ixphone_national");
3203 gchar *const digits = extract_digits (query_term_input);
3204 value = convert_string_value (
3205 ebsdb, digits, region,
3206 CONVERT_NOTHING, MATCH_ENDS_WITH);
3209 extra = sqlite3_mprintf (
3210 " AND (%q LIKE '|%%' OR %q LIKE '+%d|%%')",
3211 field_name, field_name, country_code);
3216 if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3217 field_name = g_strdup ("multi.value");
3220 field_name = g_strconcat (
3222 ebsdb->priv->summary_fields[summary_index].dbname, NULL);
3224 if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
3225 ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV) {
3226 value = convert_string_value (
3227 ebsdb, query_term_input, region,
3228 CONVERT_NOTHING, match);
3230 value = convert_string_value (
3231 ebsdb, query_term_input, region,
3232 CONVERT_NORMALIZE, match);
3238 *is_list_attr = list_attr;
3240 *query_term = value;
3243 *extra_term = extra;
3249 EBookBackendSqliteDB *ebsdb;
3250 const gchar *folderid;
3253 static const gchar *
3254 field_oper (MatchType match)
3258 case MATCH_PHONE_NUMBER:
3259 case MATCH_NATIONAL_PHONE_NUMBER:
3262 case MATCH_CONTAINS:
3263 case MATCH_BEGINS_WITH:
3264 case MATCH_ENDS_WITH:
3265 case MATCH_SHORT_PHONE_NUMBER:
3272 static ESExpResult *
3273 convert_match_exp (struct _ESExp *f,
3275 struct _ESExpResult **argv,
3279 BuildQueryData *qdata = (BuildQueryData *) data;
3280 EBookBackendSqliteDB *ebsdb = qdata->ebsdb;
3284 /* are we inside a match-all? */
3285 if (argc > 1 && argv[0]->type == ESEXP_RES_STRING) {
3288 /* only a subset of headers are supported .. */
3289 field = argv[0]->value.string;
3291 if (argv[1]->type == ESEXP_RES_STRING && argv[1]->value.string[0] != 0) {
3292 const gchar *const oper = field_oper (match);
3293 gchar *field_name, *query_term, *extra_term;
3295 if (!g_ascii_strcasecmp (field, "full_name")) {
3296 GString *names = g_string_new (NULL);
3298 field_name = field_name_and_query_term (
3299 ebsdb, qdata->folderid, "full_name",
3300 argv[1]->value.string, NULL,
3301 match, NULL, &query_term, NULL);
3302 g_string_append_printf (
3303 names, "(%s IS NOT NULL AND %s %s %s)",
3304 field_name, field_name, oper, query_term);
3305 g_free (field_name);
3306 g_free (query_term);
3308 if (summary_dbname_from_field (ebsdb, E_CONTACT_FAMILY_NAME)) {
3309 field_name = field_name_and_query_term (
3310 ebsdb, qdata->folderid, "family_name",
3311 argv[1]->value.string, NULL,
3312 match, NULL, &query_term, NULL);
3313 g_string_append_printf (
3314 names, " OR (%s IS NOT NULL AND %s %s %s)",
3315 field_name, field_name, oper, query_term);
3316 g_free (field_name);
3317 g_free (query_term);
3320 if (summary_dbname_from_field (ebsdb, E_CONTACT_GIVEN_NAME)) {
3321 field_name = field_name_and_query_term (
3322 ebsdb, qdata->folderid, "given_name",
3323 argv[1]->value.string, NULL,
3324 match, NULL, &query_term, NULL);
3325 g_string_append_printf (
3326 names, " OR (%s IS NOT NULL AND %s %s %s)",
3327 field_name, field_name, oper, query_term);
3328 g_free (field_name);
3329 g_free (query_term);
3332 if (summary_dbname_from_field (ebsdb, E_CONTACT_NICKNAME)) {
3333 field_name = field_name_and_query_term (
3334 ebsdb, qdata->folderid, "nickname",
3335 argv[1]->value.string, NULL,
3336 match, NULL, &query_term, NULL);
3337 g_string_append_printf (
3338 names, " OR (%s IS NOT NULL AND %s %s %s)",
3339 field_name, field_name, oper, query_term);
3340 g_free (field_name);
3341 g_free (query_term);
3345 g_string_free (names, FALSE);
3348 const gchar *const region =
3349 argc > 2 && argv[2]->type == ESEXP_RES_STRING ?
3350 argv[2]->value.string : NULL;
3352 gboolean is_list = FALSE;
3354 /* This should ideally be the only valid case from all the above special casing, but oh well... */
3355 field_name = field_name_and_query_term (
3356 ebsdb, qdata->folderid, field,
3357 argv[1]->value.string, region,
3358 match, &is_list, &query_term, &extra_term);
3360 /* User functions like eqphone_national() cannot utilize indexes. Therefore we
3361 * should reduce the result set first before applying any user functions. This
3362 * is done by applying a seemingly redundant suffix match first.
3367 tmp = sqlite3_mprintf ("summary.uid = multi.uid AND multi.field = %Q", field);
3368 str = g_strdup_printf (
3369 "(%s AND (%s %s %s%s))",
3370 tmp, field_name, oper, query_term,
3371 extra_term ? extra_term : "");
3374 str = g_strdup_printf (
3375 "(%s IS NOT NULL AND (%s %s %s%s))",
3376 field_name, field_name, oper, query_term,
3377 extra_term ? extra_term : "");
3379 g_free (field_name);
3380 g_free (query_term);
3382 sqlite3_free (extra_term);
3387 r = e_sexp_result_new (f, ESEXP_RES_STRING);
3388 r->value.string = str;
3393 static ESExpResult *
3394 func_contains (struct _ESExp *f,
3396 struct _ESExpResult **argv,
3399 return convert_match_exp (f, argc, argv, data, MATCH_CONTAINS);
3402 static ESExpResult *
3403 func_is (struct _ESExp *f,
3405 struct _ESExpResult **argv,
3408 return convert_match_exp (f, argc, argv, data, MATCH_IS);
3411 static ESExpResult *
3412 func_beginswith (struct _ESExp *f,
3414 struct _ESExpResult **argv,
3417 return convert_match_exp (f, argc, argv, data, MATCH_BEGINS_WITH);
3420 static ESExpResult *
3421 func_endswith (struct _ESExp *f,
3423 struct _ESExpResult **argv,
3426 return convert_match_exp (f, argc, argv, data, MATCH_ENDS_WITH);
3429 static ESExpResult *
3430 func_eqphone (struct _ESExp *f,
3432 struct _ESExpResult **argv,
3435 return convert_match_exp (f, argc, argv, data, MATCH_PHONE_NUMBER);
3438 static ESExpResult *
3439 func_eqphone_national (struct _ESExp *f,
3441 struct _ESExpResult **argv,
3444 return convert_match_exp (f, argc, argv, data, MATCH_NATIONAL_PHONE_NUMBER);
3447 static ESExpResult *
3448 func_eqphone_short (struct _ESExp *f,
3450 struct _ESExpResult **argv,
3453 return convert_match_exp (f, argc, argv, data, MATCH_SHORT_PHONE_NUMBER);
3456 /* 'builtin' functions */
3462 { "and", (ESExpFunc *) func_and, 1},
3463 { "or", (ESExpFunc *) func_or, 1},
3465 { "contains", func_contains, 0 },
3466 { "is", func_is, 0 },
3467 { "beginswith", func_beginswith, 0 },
3468 { "endswith", func_endswith, 0 },
3469 { "eqphone", func_eqphone, 0 },
3470 { "eqphone_national", func_eqphone_national, 0 },
3471 { "eqphone_short", func_eqphone_short, 0 }
3475 sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
3476 const gchar *folderid,
3479 BuildQueryData data = { ebsdb, folderid };
3485 sexp = e_sexp_new ();
3487 for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
3488 if (symbols[i].immediate)
3489 e_sexp_add_ifunction (
3490 sexp, 0, symbols[i].name,
3491 (ESExpIFunc *) symbols[i].func, &data);
3493 e_sexp_add_function (
3494 sexp, 0, symbols[i].name,
3495 symbols[i].func, &data);
3498 e_sexp_input_text (sexp, query, strlen (query));
3499 e_sexp_parse (sexp);
3501 r = e_sexp_eval (sexp);
3504 if (r->type == ESEXP_RES_STRING) {
3505 if (r->value.string && *r->value.string)
3506 res = g_strdup (r->value.string);
3510 g_warn_if_reached ();
3514 e_sexp_result_free (sexp, r);
3515 e_sexp_unref (sexp);
3521 addto_vcard_list_cb (gpointer ref,
3526 GSList **vcard_data = ref;
3527 EbSdbSearchData *s_data = g_slice_new0 (EbSdbSearchData);
3530 s_data->uid = g_strdup (cols[0]);
3533 s_data->vcard = g_strdup (cols[1]);
3536 s_data->bdata = g_strdup (cols[2]);
3538 *vcard_data = g_slist_prepend (*vcard_data, s_data);
3544 addto_slist_cb (gpointer ref,
3549 GSList **uids = ref;
3552 *uids = g_slist_prepend (*uids, g_strdup (cols [0]));
3558 book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
3560 const gchar *folderid,
3561 GHashTable *fields_of_interest,
3562 gboolean *with_all_required_fields,
3563 gboolean query_with_list_attrs,
3566 GSList *vcard_data = NULL;
3568 gboolean local_with_all_required_fields = FALSE;
3569 gboolean success = TRUE;
3571 /* Try constructing contacts from only UID/REV first if that's requested */
3572 if (uid_rev_fields (fields_of_interest)) {
3573 gchar *select_portion;
3575 select_portion = summary_select_stmt (
3576 fields_of_interest, query_with_list_attrs);
3578 if (sql && sql[0]) {
3580 if (query_with_list_attrs) {
3581 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3583 stmt = sqlite3_mprintf (
3584 "%s FROM %Q AS summary, %Q AS multi WHERE %s",
3585 select_portion, folderid, list_table, sql);
3586 g_free (list_table);
3588 stmt = sqlite3_mprintf (
3589 "%s FROM %Q AS summary WHERE %s",
3590 select_portion, folderid, sql);
3593 success = book_backend_sql_exec (
3594 ebsdb->priv->db, stmt,
3595 store_data_to_vcard, &vcard_data, error);
3597 sqlite3_free (stmt);
3599 stmt = sqlite3_mprintf ("%s FROM %Q AS summary", select_portion, folderid);
3600 success = book_backend_sql_exec (
3601 ebsdb->priv->db, stmt,
3602 store_data_to_vcard, &vcard_data, error);
3603 sqlite3_free (stmt);
3606 local_with_all_required_fields = TRUE;
3607 g_free (select_portion);
3609 } else if (ebsdb->priv->store_vcard) {
3611 if (sql && sql[0]) {
3613 if (query_with_list_attrs) {
3614 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3616 stmt = sqlite3_mprintf (
3617 "SELECT DISTINCT summary.uid, vcard, bdata "
3618 "FROM %Q AS summary, %Q AS multi WHERE %s",
3619 folderid, list_table, sql);
3620 g_free (list_table);
3622 stmt = sqlite3_mprintf (
3623 "SELECT uid, vcard, bdata FROM %Q as summary WHERE %s", folderid, sql);
3626 success = book_backend_sql_exec (
3627 ebsdb->priv->db, stmt,
3628 addto_vcard_list_cb , &vcard_data, error);
3630 sqlite3_free (stmt);
3632 stmt = sqlite3_mprintf (
3633 "SELECT uid, vcard, bdata FROM %Q", folderid);
3634 success = book_backend_sql_exec (
3635 ebsdb->priv->db, stmt,
3636 addto_vcard_list_cb , &vcard_data, error);
3637 sqlite3_free (stmt);
3640 local_with_all_required_fields = TRUE;
3643 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3644 _("Full search_contacts are not stored in cache. vcards cannot be returned."));
3648 g_warn_if_fail (vcard_data == NULL);
3652 if (with_all_required_fields)
3653 *with_all_required_fields = local_with_all_required_fields;
3655 return g_slist_reverse (vcard_data);
3659 book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
3661 const gchar *folderid,
3662 gboolean return_uids,
3665 GSList *r_list = NULL, *all = NULL, *l;
3666 EBookBackendSExp *bsexp = NULL;
3670 stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
3671 success = book_backend_sql_exec (
3672 ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
3673 sqlite3_free (stmt);
3676 g_warn_if_fail (all == NULL);
3680 bsexp = e_book_backend_sexp_new (sexp);
3682 for (l = all; l != NULL; l = g_slist_next (l)) {
3683 EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
3685 if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
3687 r_list = g_slist_prepend (r_list, s_data);
3689 r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
3690 e_book_backend_sqlitedb_search_data_free (s_data);
3693 e_book_backend_sqlitedb_search_data_free (s_data);
3696 g_object_unref (bsexp);
3704 * e_book_backend_sqlitedb_search
3707 * @sexp: search expression; use NULL or an empty string to get all stored
3709 * @fields_of_interest: a #GHashTable containing the names of fields to return,
3710 * or NULL for all. At the moment if this is non-null, the vcard will be
3711 * populated with summary fields, else it would return the whole vcard if
3712 * its stored in the db. [not implemented fully]
3713 * @searched: (allow none) (out): Whether @ebsdb was capable of searching
3714 * for the provided query @sexp.
3715 * @with_all_required_fields: (allow none) (out): Whether all the required
3716 * fields are present in the returned vcards.
3719 * Searching with summary fields is always supported. Search expressions
3720 * containing any other field is supported only if backend chooses to store
3721 * the vcard inside the db.
3723 * Summary fields - uid, rev, nickname, given_name, family_name, file_as
3724 * email_1, email_2, email_3, email_4, is_list, list_show_addresses, wants_html
3726 * If @ebsdb was incapable of returning vcards with results that satisfy
3727 * @fields_of_interest, then @with_all_required_fields will be updated to
3728 * @FALSE and only uid fields will be present in the returned vcards. This
3729 * can be useful when a summary query succeeds and the returned list can be
3730 * used to iterate and fetch for full required data from another persistance.
3732 * Returns: List of EbSdbSearchData.
3737 e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
3738 const gchar *folderid,
3740 GHashTable *fields_of_interest,
3742 gboolean *with_all_required_fields,
3745 GSList *search_contacts = NULL;
3746 gboolean local_searched = FALSE;
3747 gboolean local_with_all_required_fields = FALSE;
3748 gboolean query_with_list_attrs = FALSE;
3749 gboolean query_unsupported = FALSE;
3750 gboolean query_invalid = FALSE;
3751 gboolean summary_query = FALSE;
3753 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3754 g_return_val_if_fail (folderid != NULL, NULL);
3759 LOCK_MUTEX (&ebsdb->priv->lock);
3762 summary_query = e_book_backend_sqlitedb_check_summary_query_locked (
3764 &query_with_list_attrs,
3765 &query_unsupported, &query_invalid);
3767 if (query_unsupported)
3769 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_NOT_SUPPORTED,
3770 _("Query contained unsupported elements"));
3771 else if (query_invalid)
3773 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_INVALID_QUERY,
3774 _("Invalid Query"));
3775 else if (!sexp || summary_query) {
3778 sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3779 search_contacts = book_backend_sqlitedb_search_query (
3780 ebsdb, sql_query, folderid,
3782 &local_with_all_required_fields,
3783 query_with_list_attrs, error);
3786 local_searched = TRUE;
3788 } else if (ebsdb->priv->store_vcard) {
3789 search_contacts = book_backend_sqlitedb_search_full (
3790 ebsdb, sexp, folderid, FALSE, error);
3792 local_searched = TRUE;
3793 local_with_all_required_fields = TRUE;
3797 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3798 _("Full search_contacts are not stored in cache. "
3799 "Hence only summary query is supported."));
3802 UNLOCK_MUTEX (&ebsdb->priv->lock);
3805 *searched = local_searched;
3806 if (with_all_required_fields)
3807 *with_all_required_fields = local_with_all_required_fields;
3809 return search_contacts;
3813 * e_book_backend_sqlitedb_search_uids:
3815 * FIXME: Document me.
3820 e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
3821 const gchar *folderid,
3826 GSList *uids = NULL;
3827 gboolean local_searched = FALSE;
3828 gboolean query_with_list_attrs = FALSE;
3829 gboolean query_unsupported = FALSE;
3830 gboolean summary_query = FALSE;
3831 gboolean query_invalid = FALSE;
3833 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3834 g_return_val_if_fail (folderid != NULL, NULL);
3839 LOCK_MUTEX (&ebsdb->priv->lock);
3842 summary_query = e_book_backend_sqlitedb_check_summary_query_locked (
3844 &query_with_list_attrs,
3848 if (query_unsupported)
3850 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_NOT_SUPPORTED,
3851 _("Query contained unsupported elements"));
3852 else if (query_invalid)
3854 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_INVALID_QUERY,
3855 _("Invalid query"));
3856 else if (!sexp || summary_query) {
3858 gchar *sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3860 if (sql_query && sql_query[0]) {
3862 if (query_with_list_attrs) {
3863 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3865 stmt = sqlite3_mprintf (
3866 "SELECT DISTINCT summary.uid FROM %Q AS summary, %Q AS multi WHERE %s",
3867 folderid, list_table, sql_query);
3869 g_free (list_table);
3871 stmt = sqlite3_mprintf (
3872 "SELECT summary.uid FROM %Q AS summary WHERE %s",
3873 folderid, sql_query);
3875 book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3876 sqlite3_free (stmt);
3879 stmt = sqlite3_mprintf ("SELECT uid FROM %Q", folderid);
3880 book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3881 sqlite3_free (stmt);
3884 local_searched = TRUE;
3888 } else if (ebsdb->priv->store_vcard) {
3889 uids = book_backend_sqlitedb_search_full (
3890 ebsdb, sexp, folderid, TRUE, error);
3892 local_searched = TRUE;
3896 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3897 _("Full vcards are not stored in cache. "
3898 "Hence only summary query is supported."));
3901 UNLOCK_MUTEX (&ebsdb->priv->lock);
3904 *searched = local_searched;
3910 get_uids_and_rev_cb (gpointer user_data,
3915 GHashTable *uids_and_rev = user_data;
3917 if (col == 2 && cols[0])
3918 g_hash_table_insert (uids_and_rev, g_strdup (cols[0]), g_strdup (cols[1] ? cols[1] : ""));
3924 * e_book_backend_sqlitedb_get_uids_and_rev:
3926 * Gets hash table of all uids (key) and rev (value) pairs stored
3927 * for each contact in the cache. The hash table should be freed
3928 * with g_hash_table_destroy(), if not needed anymore. Each key
3929 * and value is a newly allocated string.
3934 e_book_backend_sqlitedb_get_uids_and_rev (EBookBackendSqliteDB *ebsdb,
3935 const gchar *folderid,
3938 GHashTable *uids_and_rev;
3941 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3942 g_return_val_if_fail (folderid != NULL, NULL);
3944 uids_and_rev = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3946 LOCK_MUTEX (&ebsdb->priv->lock);
3948 stmt = sqlite3_mprintf ("SELECT uid,rev FROM %Q", folderid);
3949 book_backend_sql_exec (
3950 ebsdb->priv->db, stmt,
3951 get_uids_and_rev_cb, uids_and_rev, error);
3952 sqlite3_free (stmt);
3954 UNLOCK_MUTEX (&ebsdb->priv->lock);
3956 return uids_and_rev;
3960 * e_book_backend_sqlitedb_get_is_populated:
3962 * FIXME: Document me.
3967 e_book_backend_sqlitedb_get_is_populated (EBookBackendSqliteDB *ebsdb,
3968 const gchar *folderid,
3972 gboolean ret = FALSE;
3974 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3975 g_return_val_if_fail (folderid != NULL, FALSE);
3977 LOCK_MUTEX (&ebsdb->priv->lock);
3979 stmt = sqlite3_mprintf (
3980 "SELECT is_populated FROM folders WHERE folder_id = %Q",
3982 book_backend_sql_exec (
3983 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3984 sqlite3_free (stmt);
3986 UNLOCK_MUTEX (&ebsdb->priv->lock);
3993 * e_book_backend_sqlitedb_set_is_populated:
3995 * FIXME: Document me.
4000 e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
4001 const gchar *folderid,
4008 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4009 g_return_val_if_fail (folderid != NULL, FALSE);
4011 LOCK_MUTEX (&ebsdb->priv->lock);
4013 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4014 UNLOCK_MUTEX (&ebsdb->priv->lock);
4018 stmt = sqlite3_mprintf (
4019 "UPDATE folders SET is_populated = %d "
4020 "WHERE folder_id = %Q", populated, folderid);
4021 success = book_backend_sql_exec (
4022 ebsdb->priv->db, stmt, NULL, NULL, error);
4023 sqlite3_free (stmt);
4026 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4028 /* The GError is already set. */
4029 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4031 UNLOCK_MUTEX (&ebsdb->priv->lock);
4037 * e_book_backend_sqlitedb_get_revision:
4038 * @ebsdb: An #EBookBackendSqliteDB
4039 * @folderid: folder id of the address-book
4040 * @revision_out: (out) (transfer full): The location to return the current
4042 * @error: A location to store any error that may have occurred
4044 * Fetches the current revision for the address-book indicated by @folderid.
4046 * Upon success, @revision_out will hold the returned revision, otherwise
4047 * %FALSE will be returned and @error will be updated accordingly.
4049 * Returns: Whether the revision was successfully fetched.
4054 e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
4055 const gchar *folderid,
4056 gchar **revision_out,
4062 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4063 g_return_val_if_fail (folderid && folderid[0], FALSE);
4064 g_return_val_if_fail (revision_out != NULL && *revision_out == NULL, FALSE);
4066 LOCK_MUTEX (&ebsdb->priv->lock);
4068 stmt = sqlite3_mprintf (
4069 "SELECT revision FROM folders WHERE folder_id = %Q", folderid);
4070 success = book_backend_sql_exec (
4071 ebsdb->priv->db, stmt, get_string_cb, revision_out, error);
4072 sqlite3_free (stmt);
4074 UNLOCK_MUTEX (&ebsdb->priv->lock);
4080 * e_book_backend_sqlitedb_set_revision:
4081 * @ebsdb: An #EBookBackendSqliteDB
4082 * @folderid: folder id of the address-book
4083 * @revision: The new revision
4084 * @error: A location to store any error that may have occurred
4086 * Sets the current revision for the address-book indicated by @folderid to be @revision.
4088 * Returns: Whether the revision was successfully set.
4093 e_book_backend_sqlitedb_set_revision (EBookBackendSqliteDB *ebsdb,
4094 const gchar *folderid,
4095 const gchar *revision,
4101 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4102 g_return_val_if_fail (folderid && folderid[0], FALSE);
4104 LOCK_MUTEX (&ebsdb->priv->lock);
4106 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4107 UNLOCK_MUTEX (&ebsdb->priv->lock);
4111 stmt = sqlite3_mprintf (
4112 "UPDATE folders SET revision = %Q "
4113 "WHERE folder_id = %Q", revision, folderid);
4114 success = book_backend_sql_exec (
4115 ebsdb->priv->db, stmt, NULL, NULL, error);
4116 sqlite3_free (stmt);
4119 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4121 /* The GError is already set. */
4122 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4124 UNLOCK_MUTEX (&ebsdb->priv->lock);
4130 * e_book_backend_sqlitedb_get_has_partial_content
4136 * Returns: TRUE if the vcards stored in the db were downloaded partially. It is to indicate
4137 * the stored vcards does not contain the full data.
4142 e_book_backend_sqlitedb_get_has_partial_content (EBookBackendSqliteDB *ebsdb,
4143 const gchar *folderid,
4147 gboolean ret = FALSE;
4149 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4150 g_return_val_if_fail (folderid != NULL, FALSE);
4152 LOCK_MUTEX (&ebsdb->priv->lock);
4154 stmt = sqlite3_mprintf (
4155 "SELECT partial_content FROM folders "
4156 "WHERE folder_id = %Q", folderid);
4157 book_backend_sql_exec (
4158 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
4159 sqlite3_free (stmt);
4161 UNLOCK_MUTEX (&ebsdb->priv->lock);
4167 * e_book_backend_sqlitedb_set_has_partial_content:
4169 * FIXME: Document me.
4174 e_book_backend_sqlitedb_set_has_partial_content (EBookBackendSqliteDB *ebsdb,
4175 const gchar *folderid,
4176 gboolean partial_content,
4182 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4183 g_return_val_if_fail (folderid != NULL, FALSE);
4185 LOCK_MUTEX (&ebsdb->priv->lock);
4187 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4188 UNLOCK_MUTEX (&ebsdb->priv->lock);
4192 stmt = sqlite3_mprintf (
4193 "UPDATE folders SET partial_content = %d "
4194 "WHERE folder_id = %Q", partial_content, folderid);
4195 success = book_backend_sql_exec (
4196 ebsdb->priv->db, stmt, NULL, NULL, error);
4197 sqlite3_free (stmt);
4200 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4202 /* The GError is already set. */
4203 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4205 UNLOCK_MUTEX (&ebsdb->priv->lock);
4211 * e_book_backend_sqlitedb_get_contact_bdata:
4213 * FIXME: Document me.
4218 e_book_backend_sqlitedb_get_contact_bdata (EBookBackendSqliteDB *ebsdb,
4219 const gchar *folderid,
4223 gchar *stmt, *ret = NULL;
4226 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4227 g_return_val_if_fail (folderid != NULL, NULL);
4228 g_return_val_if_fail (uid != NULL, NULL);
4230 LOCK_MUTEX (&ebsdb->priv->lock);
4232 stmt = sqlite3_mprintf (
4233 "SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
4234 success = book_backend_sql_exec (
4235 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4236 sqlite3_free (stmt);
4238 UNLOCK_MUTEX (&ebsdb->priv->lock);
4241 g_warn_if_fail (ret == NULL);
4249 * e_book_backend_sqlitedb_set_contact_bdata:
4251 * FIXME: Document me.
4256 e_book_backend_sqlitedb_set_contact_bdata (EBookBackendSqliteDB *ebsdb,
4257 const gchar *folderid,
4265 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4266 g_return_val_if_fail (folderid != NULL, FALSE);
4267 g_return_val_if_fail (uid != NULL, FALSE);
4268 g_return_val_if_fail (value != NULL, FALSE);
4270 LOCK_MUTEX (&ebsdb->priv->lock);
4272 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4273 UNLOCK_MUTEX (&ebsdb->priv->lock);
4277 stmt = sqlite3_mprintf (
4278 "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
4279 folderid, value, uid);
4280 success = book_backend_sql_exec (
4281 ebsdb->priv->db, stmt, NULL, NULL, error);
4282 sqlite3_free (stmt);
4285 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4287 /* The GError is already set. */
4288 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4290 UNLOCK_MUTEX (&ebsdb->priv->lock);
4296 * e_book_backend_sqlitedb_get_sync_data:
4298 * FIXME: Document me.
4303 e_book_backend_sqlitedb_get_sync_data (EBookBackendSqliteDB *ebsdb,
4304 const gchar *folderid,
4307 gchar *stmt, *ret = NULL;
4309 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4310 g_return_val_if_fail (folderid != NULL, NULL);
4312 LOCK_MUTEX (&ebsdb->priv->lock);
4314 stmt = sqlite3_mprintf (
4315 "SELECT sync_data FROM folders WHERE folder_id = %Q",
4317 book_backend_sql_exec (
4318 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4319 sqlite3_free (stmt);
4321 UNLOCK_MUTEX (&ebsdb->priv->lock);
4327 * e_book_backend_sqlitedb_set_sync_data:
4329 * FIXME: Document me.
4334 e_book_backend_sqlitedb_set_sync_data (EBookBackendSqliteDB *ebsdb,
4335 const gchar *folderid,
4336 const gchar *sync_data,
4342 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4343 g_return_val_if_fail (folderid != NULL, FALSE);
4344 g_return_val_if_fail (sync_data != NULL, FALSE);
4346 LOCK_MUTEX (&ebsdb->priv->lock);
4348 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4349 UNLOCK_MUTEX (&ebsdb->priv->lock);
4353 stmt = sqlite3_mprintf (
4354 "UPDATE folders SET sync_data = %Q "
4355 "WHERE folder_id = %Q", sync_data, folderid);
4356 success = book_backend_sql_exec (
4357 ebsdb->priv->db, stmt, NULL, NULL, error);
4358 sqlite3_free (stmt);
4361 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4363 /* The GError is already set. */
4364 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4366 UNLOCK_MUTEX (&ebsdb->priv->lock);
4372 * e_book_backend_sqlitedb_get_key_value:
4374 * FIXME: Document me.
4379 e_book_backend_sqlitedb_get_key_value (EBookBackendSqliteDB *ebsdb,
4380 const gchar *folderid,
4384 gchar *stmt, *ret = NULL;
4386 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4387 g_return_val_if_fail (folderid != NULL, NULL);
4388 g_return_val_if_fail (key != NULL, NULL);
4390 LOCK_MUTEX (&ebsdb->priv->lock);
4392 stmt = sqlite3_mprintf (
4393 "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
4395 book_backend_sql_exec (
4396 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4397 sqlite3_free (stmt);
4399 UNLOCK_MUTEX (&ebsdb->priv->lock);
4405 * e_book_backend_sqlitedb_set_key_value:
4407 * FIXME: Document me.
4412 e_book_backend_sqlitedb_set_key_value (EBookBackendSqliteDB *ebsdb,
4413 const gchar *folderid,
4421 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4422 g_return_val_if_fail (folderid != NULL, FALSE);
4423 g_return_val_if_fail (key != NULL, FALSE);
4424 g_return_val_if_fail (value != NULL, FALSE);
4426 LOCK_MUTEX (&ebsdb->priv->lock);
4428 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4429 UNLOCK_MUTEX (&ebsdb->priv->lock);
4433 stmt = sqlite3_mprintf (
4434 "INSERT or REPLACE INTO keys (key, value, folder_id) "
4435 "values (%Q, %Q, %Q)", key, value, folderid);
4436 success = book_backend_sql_exec (
4437 ebsdb->priv->db, stmt, NULL, NULL, error);
4438 sqlite3_free (stmt);
4441 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4443 /* The GError is already set. */
4444 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4446 UNLOCK_MUTEX (&ebsdb->priv->lock);
4452 * e_book_backend_sqlitedb_get_partially_cached_ids:
4454 * FIXME: Document me.
4459 e_book_backend_sqlitedb_get_partially_cached_ids (EBookBackendSqliteDB *ebsdb,
4460 const gchar *folderid,
4464 GSList *uids = NULL;
4466 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4467 g_return_val_if_fail (folderid != NULL, NULL);
4469 LOCK_MUTEX (&ebsdb->priv->lock);
4471 stmt = sqlite3_mprintf (
4472 "SELECT uid FROM %Q WHERE partial_content = 1",
4474 book_backend_sql_exec (
4475 ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
4476 sqlite3_free (stmt);
4478 UNLOCK_MUTEX (&ebsdb->priv->lock);
4484 * e_book_backend_sqlitedb_delete_addressbook:
4486 * FIXME: Document me.
4491 e_book_backend_sqlitedb_delete_addressbook (EBookBackendSqliteDB *ebsdb,
4492 const gchar *folderid,
4498 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4499 g_return_val_if_fail (folderid != NULL, FALSE);
4501 LOCK_MUTEX (&ebsdb->priv->lock);
4503 if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4504 UNLOCK_MUTEX (&ebsdb->priv->lock);
4508 /* delete the contacts table */
4509 stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
4510 success = book_backend_sql_exec (
4511 ebsdb->priv->db, stmt, NULL, NULL, error);
4512 sqlite3_free (stmt);
4517 /* delete the key/value pairs corresponding to this table */
4518 stmt = sqlite3_mprintf (
4519 "DELETE FROM keys WHERE folder_id = %Q", folderid);
4520 success = book_backend_sql_exec (
4521 ebsdb->priv->db, stmt, NULL, NULL, error);
4522 sqlite3_free (stmt);
4527 /* delete the folder from the folders table */
4528 stmt = sqlite3_mprintf (
4529 "DELETE FROM folders WHERE folder_id = %Q", folderid);
4530 success = book_backend_sql_exec (
4531 ebsdb->priv->db, stmt, NULL, NULL, error);
4532 sqlite3_free (stmt);
4537 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4538 UNLOCK_MUTEX (&ebsdb->priv->lock);
4543 /* The GError is already set. */
4544 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4546 UNLOCK_MUTEX (&ebsdb->priv->lock);
4552 * e_book_backend_sqlitedb_search_data_free:
4554 * FIXME: Document me.
4559 e_book_backend_sqlitedb_search_data_free (EbSdbSearchData *s_data)
4562 g_free (s_data->uid);
4563 g_free (s_data->vcard);
4564 g_free (s_data->bdata);
4565 g_slice_free (EbSdbSearchData, s_data);
4570 * e_book_backend_sqlitedb_remove:
4572 * FIXME: Document me.
4577 e_book_backend_sqlitedb_remove (EBookBackendSqliteDB *ebsdb,
4583 g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4585 LOCK_MUTEX (&ebsdb->priv->lock);
4587 sqlite3_close (ebsdb->priv->db);
4589 filename = g_build_filename (ebsdb->priv->path, DB_FILENAME, NULL);
4590 ret = g_unlink (filename);
4593 UNLOCK_MUTEX (&ebsdb->priv->lock);
4597 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
4598 _("Unable to remove the db file: errno %d"), errno);
4606 destroy_search_data (gpointer data)
4608 e_book_backend_sqlitedb_search_data_free (data);
4612 upgrade_contacts_table (EBookBackendSqliteDB *ebsdb,
4613 const gchar *folderid,
4617 gboolean success = FALSE;
4618 GSList *vcard_data = NULL;
4620 gchar *default_region = NULL;
4622 stmt = sqlite3_mprintf ("SELECT uid, vcard, NULL FROM %Q", folderid);
4623 success = book_backend_sql_exec (
4624 ebsdb->priv->db, stmt, addto_vcard_list_cb, &vcard_data, error);
4625 sqlite3_free (stmt);
4627 if (vcard_data == NULL)
4630 if (e_phone_number_is_supported ()) {
4631 default_region = e_phone_number_get_default_region (error);
4633 if (default_region == NULL)
4637 success = book_backend_sqlitedb_start_transaction (ebsdb, error);
4641 for (l = vcard_data; success && l; l = l->next) {
4642 EbSdbSearchData *const s_data = l->data;
4643 EContact *contact = e_contact_new_from_vcard_with_uid (s_data->vcard, s_data->uid);
4645 if (contact == NULL)
4648 success = insert_contact (ebsdb, contact, folderid, TRUE, default_region, error);
4650 g_object_unref (contact);
4654 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4656 /* The GError is already set. */
4657 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4660 g_slist_free_full (vcard_data, destroy_search_data);
4661 g_free (default_region);