1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Copyright (C) 2013 Intel Corporation
7 * Tristan Van Berkom <tristanvb@openismus.com>
9 * This library is free software you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 * SECTION: e-book-sqlite
24 * @include: libedata-book/libedata-book.h
25 * @short_description: An SQLite storage facility for addressbooks
27 * The #EBookSqlite is an API for storing and looking up #EContacts
28 * in an SQLite database. It also supports a lean index mode via
29 * the #EbSqlVCardCallback, if you are in a situation where it is
30 * not convenient to store the vCards directly in the SQLite. It is
31 * however recommended to avoid storing contacts in separate storage
32 * if at all possible, as this will decrease performance of searches
33 * an also contribute to flash wear.
35 * The API is thread safe, with special considerations to be made
36 * around e_book_sqlite_lock() and e_book_sqlite_unlock() for
37 * the sake of isolating transactions across threads.
39 * Any operations which can take a lot of time to complete (depending
40 * on the size of your addressbook) can be cancelled using a #GCancellable.
42 * Depending on your summary configuration, your mileage will vary. Refer
43 * to the #ESourceBackendSummarySetup for configuring your addressbook
44 * for the type of usage you mean to make of it.
47 #include "e-book-sqlite.h"
53 #include <glib/gi18n.h>
54 #include <glib/gstdio.h>
58 /* For e_sqlite3_vfs_init() */
59 #include <libebackend/libebackend.h>
61 #include "e-book-backend-sexp.h"
63 #define E_BOOK_SQLITE_GET_PRIVATE(obj) \
64 (G_TYPE_INSTANCE_GET_PRIVATE \
65 ((obj), E_TYPE_BOOK_SQLITE, EBookSqlitePrivate))
67 /******************************************************
69 ******************************************************
70 * Run EDS with EBSQL_DEBUG=statements:explain to print
71 * all statements and explain query plans.
73 * Use any of the values below to select which debug
76 #define EBSQL_ENV_DEBUG "EBSQL_DEBUG"
79 EBSQL_DEBUG_STATEMENTS = 1 << 0, /* Output all executed statements */
80 EBSQL_DEBUG_EXPLAIN = 1 << 1, /* Output SQLite's query plan for SELECT statements */
81 EBSQL_DEBUG_LOCKS = 1 << 2, /* Print which function locks and unlocks the mutex */
82 EBSQL_DEBUG_ERRORS = 1 << 3, /* Print all errors which are set */
83 EBSQL_DEBUG_SCHEMA = 1 << 4, /* Debugging the schema building / upgrading */
84 EBSQL_DEBUG_INSERT = 1 << 5, /* Debugging contact insertions */
85 EBSQL_DEBUG_FETCH_VCARD = 1 << 6, /* Print invocations of the EbSqlVCardCallback fallback */
86 EBSQL_DEBUG_CURSOR = 1 << 7, /* Print information about EbSqlCursor operations */
87 EBSQL_DEBUG_CONVERT_E164 = 1 << 8, /* Print information e164 phone number conversions in vcards */
88 EBSQL_DEBUG_REF_COUNTS = 1 << 9, /* Print about shared EBookSqlite instances, print when finalized */
89 EBSQL_DEBUG_CANCEL = 1 << 10, /* Print information about GCancellable cancellations */
90 EBSQL_DEBUG_PREFLIGHT = 1 << 11, /* Print information about query preflighting */
93 static const GDebugKey ebsql_debug_keys[] = {
94 { "statements", EBSQL_DEBUG_STATEMENTS },
95 { "explain", EBSQL_DEBUG_EXPLAIN },
96 { "locks", EBSQL_DEBUG_LOCKS },
97 { "errors", EBSQL_DEBUG_ERRORS },
98 { "schema", EBSQL_DEBUG_SCHEMA },
99 { "insert", EBSQL_DEBUG_INSERT },
100 { "fetch-vcard", EBSQL_DEBUG_FETCH_VCARD },
101 { "cursor", EBSQL_DEBUG_CURSOR },
102 { "e164", EBSQL_DEBUG_CONVERT_E164 },
103 { "ref-counts", EBSQL_DEBUG_REF_COUNTS },
104 { "cancel", EBSQL_DEBUG_CANCEL },
105 { "preflight", EBSQL_DEBUG_PREFLIGHT },
108 static EbSqlDebugFlag ebsql_debug_flags = 0;
111 ebsql_init_debug (void)
113 static gboolean initialized = FALSE;
115 if (G_UNLIKELY (!initialized)) {
116 const gchar *env_string;
118 env_string = g_getenv (EBSQL_ENV_DEBUG);
120 if (env_string != NULL)
122 g_parse_debug_string (
125 G_N_ELEMENTS (ebsql_debug_keys));
129 #define EBSQL_NOTE(type,action) \
131 if (ebsql_debug_flags & EBSQL_DEBUG_##type) \
135 #define EBSQL_ERROR_STR(code) \
136 ((code) == E_BOOK_SQLITE_ERROR_ENGINE ? "engine" : \
137 (code) == E_BOOK_SQLITE_ERROR_CONSTRAINT ? "constraint" : \
138 (code) == E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND ? "contact not found" : \
139 (code) == E_BOOK_SQLITE_ERROR_INVALID_QUERY ? "invalid query" : \
140 (code) == E_BOOK_SQLITE_ERROR_UNSUPPORTED_QUERY ? "unsupported query" : \
141 (code) == E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD ? "unsupported field" : \
142 (code) == E_BOOK_SQLITE_ERROR_END_OF_LIST ? "end of list" : \
143 (code) == E_BOOK_SQLITE_ERROR_LOAD ? "load" : "(unknown)")
145 #define EBSQL_ORIGIN_STR(origin) \
146 ((origin) == EBSQL_CURSOR_ORIGIN_CURRENT ? "current" : \
147 (origin) == EBSQL_CURSOR_ORIGIN_BEGIN ? "begin" : \
148 (origin) == EBSQL_CURSOR_ORIGIN_END ? "end" : "(invalid)")
150 #define EBSQL_LOCK_MUTEX(mutex) \
152 if (ebsql_debug_flags & EBSQL_DEBUG_LOCKS) { \
153 g_printerr ("%s: Locking %s\n", G_STRFUNC, #mutex); \
154 g_mutex_lock (mutex); \
155 g_printerr ("%s: Locked %s\n", G_STRFUNC, #mutex); \
157 g_mutex_lock (mutex); \
161 #define EBSQL_UNLOCK_MUTEX(mutex) \
163 if (ebsql_debug_flags & EBSQL_DEBUG_LOCKS) { \
164 g_printerr ("%s: Unlocking %s\n", G_STRFUNC, #mutex); \
165 g_mutex_unlock (mutex); \
166 g_printerr ("%s: Unlocked %s\n", G_STRFUNC, #mutex); \
168 g_mutex_unlock (mutex); \
172 /* Format strings are passed through dgettext(), need to be reformatted */
173 #define EBSQL_SET_ERROR(error, code, fmt, args...) \
175 if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
176 gchar *format = g_strdup_printf ( \
177 "ERR [%%s]: Set error code '%%s': %s\n", fmt); \
178 g_printerr (format, G_STRFUNC, \
179 EBSQL_ERROR_STR (code), ## args); \
182 g_set_error (error, E_BOOK_SQLITE_ERROR, code, fmt, ## args); \
185 #define EBSQL_SET_ERROR_LITERAL(error, code, detail) \
187 if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
188 g_printerr ("ERR [%s]: " \
189 "Set error code %s: %s\n", \
191 EBSQL_ERROR_STR (code), detail); \
193 g_set_error_literal (error, E_BOOK_SQLITE_ERROR, code, detail); \
196 /* EBSQL_LOCK_OR_RETURN:
197 * @ebsql: The #EBookSqlite
198 * @cancellable: A #GCancellable passed into an API
199 * @val: Value to return if this check fails
201 * This will first lock the mutex and then check if
202 * the passed cancellable is valid or invalid, it can
203 * be invalid if it differs from a cancellable passed
204 * to a toplevel transaction via e_book_sqlite_lock().
206 * If the check fails, the lock is released and then
209 #define EBSQL_LOCK_OR_RETURN(ebsql, cancellable, val) \
211 EBSQL_LOCK_MUTEX (&(ebsql)->priv->lock); \
212 if (cancellable != NULL && \
213 (ebsql)->priv->cancel != cancellable) { \
214 g_warning ("The GCancellable passed to `%s' " \
215 "is not the same as the cancel object " \
216 "passed to e_book_sqlite_lock()", \
218 EBSQL_UNLOCK_MUTEX (&(ebsql)->priv->lock); \
223 /* Set an error code from an sqlite_exec() or sqlite_step() return value & error message */
224 #define EBSQL_SET_ERROR_FROM_SQLITE(error, code, message) \
226 if (code == SQLITE_CONSTRAINT) { \
227 EBSQL_SET_ERROR_LITERAL (error, \
228 E_BOOK_SQLITE_ERROR_CONSTRAINT, \
230 } else if (code == SQLITE_ABORT) { \
231 if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
232 g_printerr ("ERR [%s]: Set cancelled error\n", \
235 g_set_error (error, \
237 G_IO_ERROR_CANCELLED, \
238 "Operation cancelled: %s", errmsg); \
240 EBSQL_SET_ERROR (error, \
241 E_BOOK_SQLITE_ERROR_ENGINE, \
242 "SQLite error code `%d': %s", \
247 #define FOLDER_VERSION 8
248 #define INSERT_MULTI_STMT_BYTES 128
249 #define COLUMN_DEFINITION_BYTES 32
250 #define GENERATED_QUERY_BYTES 1024
252 #define DEFAULT_FOLDER_ID "folder_id"
254 /* We use a 64 bitmask to track which auxiliary tables
255 * are needed to satisfy a query, it's doubtful that
256 * anyone will need an addressbook with 64 fields configured
259 #define EBSQL_MAX_SUMMARY_FIELDS 64
261 /* The number of SQLite virtual machine instructions that are
262 * evaluated at a time, the user passed GCancellable is
263 * checked between each batch of evaluated instructions.
265 #define EBSQL_CANCEL_BATCH_SIZE 200
267 /* Number of contacts to relocalize at a time
268 * while relocalizing the whole database
270 #define EBSQL_UPGRADE_BATCH_SIZE 20
272 #define EBSQL_ESCAPE_SEQUENCE "ESCAPE '^'"
274 /* Names for custom functions */
275 #define EBSQL_FUNC_COMPARE_VCARD "compare_vcard"
276 #define EBSQL_FUNC_FETCH_VCARD "fetch_vcard"
277 #define EBSQL_FUNC_EQPHONE_EXACT "eqphone_exact"
278 #define EBSQL_FUNC_EQPHONE_NATIONAL "eqphone_national"
279 #define EBSQL_FUNC_EQPHONE_SHORT "eqphone_short"
281 /* Fallback collations are generated as with a prefix and an EContactField name */
282 #define EBSQL_COLLATE_PREFIX "ebsql_"
284 /* A special vcard attribute that we use only for private vcards */
285 #define EBSQL_VCARD_SORT_KEY "X-EVOLUTION-SORT-KEY"
287 /* Suffixes for column names used to store specialized data */
288 #define EBSQL_SUFFIX_REVERSE "reverse"
289 #define EBSQL_SUFFIX_SORT_KEY "localized"
290 #define EBSQL_SUFFIX_PHONE "phone"
291 #define EBSQL_SUFFIX_COUNTRY "country"
292 #define EBSQL_SUFFIX_TRANSLIT "translit"
294 /* Track EBookIndexType's in a bit mask */
295 #define INDEX_FLAG(type) (1 << E_BOOK_INDEX_##type)
297 /* This macro is used to reffer to vcards in statements */
298 #define EBSQL_VCARD_FRAGMENT(ebsql) \
299 ((ebsql)->priv->vcard_callback ? \
300 EBSQL_FUNC_FETCH_VCARD " (summary.uid, summary.bdata)" : \
303 /* Signatures for some of the SQLite callbacks which we pass around */
304 typedef void (*EbSqlCustomFunc) (sqlite3_context *context,
306 sqlite3_value **argv);
307 typedef gint (*EbSqlRowFunc) (gpointer ref,
312 /* Some forward declarations */
313 static gboolean ebsql_init_statements (EBookSqlite *ebsql,
315 static gboolean ebsql_insert_contact (EBookSqlite *ebsql,
316 EbSqlChangeType change_type,
318 const gchar *original_vcard,
322 static gboolean ebsql_exec (EBookSqlite *ebsql,
324 EbSqlRowFunc callback,
326 GCancellable *cancellable,
330 EContactField field_id; /* The EContact field */
331 GType type; /* The GType (only support string or gboolean) */
332 const gchar *dbname; /* The key for this field in the sqlite3 table */
333 gint index; /* Types of searches this field should support (see EBookIndexType) */
334 gchar *aux_table; /* Name of auxiliary table for this field, for multivalued fields only */
335 gchar *aux_table_symbolic; /* Symolic name of auxiliary table used in queries */
338 struct _EBookSqlitePrivate {
340 /* Parameters and settings */
341 gchar *path; /* Full file name of the file we're operating on (used for hash table entries) */
342 gchar *locale; /* The current locale */
343 gchar *region_code; /* Region code (for phone number parsing) */
344 gchar *folderid; /* The summary table name (configurable, for support of legacy
345 * databases created by EBookSqliteDB) */
347 EbSqlVCardCallback vcard_callback; /* User callback to fetch vcards instead of storing them */
348 EbSqlChangeCallback change_callback; /* User callback to catch change notifications */
349 gpointer user_data; /* Data & Destroy notifier for the above callbacks */
350 GDestroyNotify user_data_destroy;
352 /* Summary configuration */
353 SummaryField *summary_fields;
354 gint n_summary_fields;
356 GMutex lock; /* Main API lock */
357 GMutex updates_lock; /* Lock used for calls to e_book_sqlite_lock_updates () */
358 guint32 in_transaction; /* Nested transaction counter */
359 EbSqlLockType lock_type; /* The lock type acquired for the current transaction */
360 GCancellable *cancel; /* User passed GCancellable, we abort an operation if cancelled */
362 ECollator *collator; /* The ECollator to create sort keys for any sortable fields */
363 ETransliterator *transliterator; /* For transliterated queries */
365 /* SQLite resources */
367 sqlite3_stmt *insert_stmt; /* Insert statement for main summary table */
368 sqlite3_stmt *replace_stmt; /* Replace statement for main summary table */
369 GHashTable *multi_deletes; /* Delete statement for each auxiliary table */
370 GHashTable *multi_inserts; /* Insert statement for each auxiliary table */
376 BEFORE_INSERT_CONTACT,
377 BEFORE_REMOVE_CONTACT,
381 static guint signals[LAST_SIGNAL];
383 G_DEFINE_TYPE_WITH_CODE (EBookSqlite, e_book_sqlite, G_TYPE_OBJECT,
384 G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
385 G_DEFINE_QUARK (e-book-backend-sqlite-error-quark,
388 /* The ColumnInfo struct is used to constant data
389 * and dynamically allocated data, the 'type' and
390 * 'extra' members are however always constant.
399 static ColumnInfo main_table_columns[] = {
400 { (gchar *) "folder_id", "TEXT", "PRIMARY KEY", NULL },
401 { (gchar *) "version", "INTEGER", NULL, NULL },
402 { (gchar *) "multivalues", "TEXT", NULL, NULL },
403 { (gchar *) "lc_collate", "TEXT", NULL, NULL },
404 { (gchar *) "countrycode", "VARCHAR(2)", NULL, NULL },
407 /* Default summary configuration */
408 static EContactField default_summary_fields[] = {
414 E_CONTACT_GIVEN_NAME,
415 E_CONTACT_FAMILY_NAME,
419 E_CONTACT_LIST_SHOW_ADDRESSES,
423 /* Create indexes on full_name and email fields as autocompletion
424 * queries would mainly rely on this.
426 * Add sort keys for name fields as those are likely targets for
429 static EContactField default_indexed_fields[] = {
433 E_CONTACT_FAMILY_NAME,
437 static EBookIndexType default_index_types[] = {
440 E_BOOK_INDEX_SORT_KEY,
441 E_BOOK_INDEX_SORT_KEY,
442 E_BOOK_INDEX_SORT_KEY
445 /******************************************************
447 ******************************************************/
449 column_info_new (SummaryField *field,
450 const gchar *folderid,
451 const gchar *column_suffix,
452 const gchar *column_type,
453 const gchar *column_extra,
454 const gchar *idx_prefix)
458 info = g_slice_new0 (ColumnInfo);
459 info->type = column_type;
460 info->extra = column_extra;
463 if (field->type == G_TYPE_STRING)
465 else if (field->type == G_TYPE_BOOLEAN)
466 info->type = "INTEGER";
467 else if (field->type == E_TYPE_CONTACT_ATTR_LIST)
470 g_warn_if_reached ();
473 if (field->type == E_TYPE_CONTACT_ATTR_LIST)
474 /* Attribute lists are on their own table */
475 info->name = g_strconcat (
477 column_suffix ? "_" : NULL,
481 /* Regular fields are named by their 'dbname' */
482 info->name = g_strconcat (
484 column_suffix ? "_" : NULL,
489 info->index = g_strconcat (
499 column_info_free (ColumnInfo *info)
503 g_free (info->index);
504 g_slice_free (ColumnInfo, info);
509 summary_field_array_index (GArray *array,
514 for (i = 0; i < array->len; i++) {
515 SummaryField *iter = &g_array_index (array, SummaryField, i);
516 if (field == iter->field_id)
523 static SummaryField *
524 summary_field_append (GArray *array,
525 const gchar *folderid,
526 EContactField field_id,
529 const gchar *dbname = NULL;
530 GType type = G_TYPE_INVALID;
532 SummaryField new_field = { 0, };
534 if (field_id < 1 || field_id >= E_CONTACT_FIELD_LAST) {
536 error, E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
537 _("Unsupported contact field '%d' specified in summary"),
542 /* Avoid including the same field twice in the summary */
543 idx = summary_field_array_index (array, field_id);
545 return &g_array_index (array, SummaryField, idx);
547 /* Resolve some exceptions, we store these
548 * specific contact fields with different names
549 * than those found in the EContactField table
555 case E_CONTACT_IS_LIST:
559 dbname = e_contact_field_name (field_id);
563 type = e_contact_field_type (field_id);
565 if (type != G_TYPE_STRING &&
566 type != G_TYPE_BOOLEAN &&
567 type != E_TYPE_CONTACT_ATTR_LIST) {
569 error, E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
570 _("Contact field '%s' of type '%s' specified in summary, "
571 "but only boolean, string and string list field types are supported"),
572 e_contact_pretty_name (field_id), g_type_name (type));
576 if (type == E_TYPE_CONTACT_ATTR_LIST) {
577 new_field.aux_table = g_strconcat (folderid, "_", dbname, "_list", NULL);
578 new_field.aux_table_symbolic = g_strconcat (dbname, "_list", NULL);
581 new_field.field_id = field_id;
582 new_field.dbname = dbname;
583 new_field.type = type;
585 g_array_append_val (array, new_field);
587 return &g_array_index (array, SummaryField, array->len - 1);
591 summary_field_remove (GArray *array,
596 idx = summary_field_array_index (array, field);
600 g_array_remove_index_fast (array, idx);
605 summary_fields_add_indexes (GArray *array,
606 EContactField *indexes,
607 EBookIndexType *index_types,
612 for (i = 0; i < array->len; i++) {
613 SummaryField *sfield = &g_array_index (array, SummaryField, i);
615 for (j = 0; j < n_indexes; j++) {
616 if (sfield->field_id == indexes[j])
617 sfield->index |= (1 << index_types[j]);
624 summary_field_get_index (EBookSqlite *ebsql,
625 EContactField field_id)
629 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
630 if (ebsql->priv->summary_fields[i].field_id == field_id)
637 static inline SummaryField *
638 summary_field_get (EBookSqlite *ebsql,
639 EContactField field_id)
643 index = summary_field_get_index (ebsql, field_id);
645 return &(ebsql->priv->summary_fields[index]);
651 summary_field_list_columns (SummaryField *field,
652 const gchar *folderid)
654 GSList *columns = NULL;
657 /* Doesn't hurt to verify a bit more here, this shouldn't happen though */
658 g_return_val_if_fail (
659 field->type == G_TYPE_STRING ||
660 field->type == G_TYPE_BOOLEAN ||
661 field->type == E_TYPE_CONTACT_ATTR_LIST,
664 /* Normal / default column */
665 info = column_info_new (
666 field, folderid, NULL, NULL,
667 (field->field_id == E_CONTACT_UID) ? "PRIMARY KEY" : NULL,
668 (field->index & INDEX_FLAG (PREFIX)) != 0 ? "INDEX" : NULL);
669 columns = g_slist_prepend (columns, info);
671 /* Localized column, for storing sort keys */
672 if (field->type == G_TYPE_STRING && (field->index & INDEX_FLAG (SORT_KEY))) {
673 info = column_info_new (field, folderid, EBSQL_SUFFIX_SORT_KEY, "TEXT", NULL, "SINDEX");
674 columns = g_slist_prepend (columns, info);
677 /* Suffix match column */
678 if (field->type != G_TYPE_BOOLEAN && (field->index & INDEX_FLAG (SUFFIX)) != 0) {
679 info = column_info_new (field, folderid, EBSQL_SUFFIX_REVERSE, "TEXT", NULL, "RINDEX");
680 columns = g_slist_prepend (columns, info);
683 /* Phone match columns */
684 if (field->type != G_TYPE_BOOLEAN && (field->index & INDEX_FLAG (PHONE)) != 0) {
686 /* One indexed column for storing the national number */
687 info = column_info_new (field, folderid, EBSQL_SUFFIX_PHONE, "TEXT", NULL, "PINDEX");
688 columns = g_slist_prepend (columns, info);
690 /* One integer column for storing the country code */
691 info = column_info_new (field, folderid, EBSQL_SUFFIX_COUNTRY, "INTEGER", "DEFAULT 0", NULL);
692 columns = g_slist_prepend (columns, info);
695 /* Transliterated value column */
696 if (field->type != G_TYPE_BOOLEAN && (field->index & INDEX_FLAG (TRANSLIT)) != 0) {
697 info = column_info_new (field, folderid, EBSQL_SUFFIX_TRANSLIT, "TEXT", NULL, "TINDEX");
698 columns = g_slist_prepend (columns, info);
701 return g_slist_reverse (columns);
705 summary_fields_array_free (SummaryField *fields,
710 for (i = 0; i < n_fields; i++) {
711 g_free (fields[i].aux_table);
712 g_free (fields[i].aux_table_symbolic);
718 /******************************************************
719 * Sharing EBookSqlite instances *
720 ******************************************************/
721 static GHashTable *db_connections = NULL;
722 static GMutex dbcon_lock;
725 ebsql_ref_from_hash (const gchar *path)
727 EBookSqlite *ebsql = NULL;
729 if (db_connections != NULL) {
730 ebsql = g_hash_table_lookup (db_connections, path);
734 EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite ref count increased from hash table reference\n"));
735 g_object_ref (ebsql);
742 ebsql_register_to_hash (EBookSqlite *ebsql,
745 if (db_connections == NULL)
746 db_connections = g_hash_table_new_full (
747 (GHashFunc) g_str_hash,
748 (GEqualFunc) g_str_equal,
749 (GDestroyNotify) g_free,
750 (GDestroyNotify) NULL);
751 g_hash_table_insert (db_connections, g_strdup (path), ebsql);
755 ebsql_unregister_from_hash (EBookSqlite *ebsql)
757 EBookSqlitePrivate *priv = ebsql->priv;
759 EBSQL_LOCK_MUTEX (&dbcon_lock);
760 if (db_connections != NULL) {
761 if (priv->path != NULL) {
762 g_hash_table_remove (db_connections, priv->path);
764 if (g_hash_table_size (db_connections) == 0) {
765 g_hash_table_destroy (db_connections);
766 db_connections = NULL;
771 EBSQL_UNLOCK_MUTEX (&dbcon_lock);
774 /************************************************************
775 * SQLite helper functions *
776 ************************************************************/
778 /* For EBSQL_DEBUG_EXPLAIN */
780 ebsql_debug_query_plan_cb (gpointer ref,
787 for (i = 0; i < n_cols; i++) {
788 if (strcmp (name[i], "detail") == 0) {
789 g_printerr (" PLAN: %s\n", cols[i]);
797 /* Collect a GList of column names in the main summary table */
799 get_columns_cb (gpointer ref,
804 GSList **columns = (GSList **) ref;
807 for (i = 0; i < col; i++) {
808 if (strcmp (name[i], "name") == 0) {
810 /* Keep comparing for the legacy 'bdata' column */
811 if (strcmp (cols[i], "vcard") != 0 &&
812 strcmp (cols[i], "bdata") != 0) {
813 gchar *column = g_strdup (cols[i]);
815 *columns = g_slist_prepend (*columns, column);
823 /* Collect the first string result */
825 get_string_cb (gpointer ref,
832 *ret = g_strdup (cols [0]);
837 /* Collect the first integer result */
839 get_int_cb (gpointer ref,
846 *ret = cols [0] ? g_ascii_strtoll (cols[0], NULL, 10) : 0;
851 /* Collect the result of a SELECT count(*) statement */
853 get_count_cb (gpointer ref,
862 for (i = 0; i < n_cols; i++) {
863 if (name[i] && strncmp (name[i], "count", 5) == 0) {
864 count = g_ascii_strtoll (cols[i], NULL, 10);
875 /* Report if there was at least one result */
877 get_exists_cb (gpointer ref,
882 gboolean *exists = ref;
889 static EbSqlSearchData *
890 search_data_from_results (gint ncol,
894 EbSqlSearchData *data = g_slice_new0 (EbSqlSearchData);
897 for (i = 0; i < ncol; i++) {
899 if (!names[i] || !cols[i])
902 /* These come through differently depending on the configuration,
903 * search within text is good enough
905 if (!g_ascii_strcasecmp (names[i], "uid")) {
906 data->uid = g_strdup (cols[i]);
907 } else if (!g_ascii_strcasecmp (names[i], "vcard") ||
908 !g_ascii_strncasecmp (names[i], "fetch_vcard", 11)) {
909 data->vcard = g_strdup (cols[i]);
910 } else if (!g_ascii_strcasecmp (names[i], "bdata")) {
911 data->extra = g_strdup (cols[i]);
919 collect_full_results_cb (gpointer ref,
924 EbSqlSearchData *data;
925 GSList **vcard_data = ref;
927 data = search_data_from_results (ncol, cols, names);
929 *vcard_data = g_slist_prepend (*vcard_data, data);
935 collect_uid_results_cb (gpointer ref,
943 *uids = g_slist_prepend (*uids, g_strdup (cols [0]));
949 collect_lean_results_cb (gpointer ref,
954 GSList **vcard_data = ref;
955 EbSqlSearchData *search_data = g_slice_new0 (EbSqlSearchData);
956 EContact *contact = e_contact_new ();
960 /* parse through cols, this will be useful if the api starts supporting field restrictions */
961 for (i = 0; i < ncol; i++) {
962 if (!names[i] || !cols[i])
965 /* Only UID & REV can be used to create contacts from the summary columns */
966 if (!g_ascii_strcasecmp (names[i], "uid")) {
967 e_contact_set (contact, E_CONTACT_UID, cols[i]);
968 search_data->uid = g_strdup (cols[i]);
969 } else if (!g_ascii_strcasecmp (names[i], "Rev")) {
970 e_contact_set (contact, E_CONTACT_REV, cols[i]);
971 } else if (!g_ascii_strcasecmp (names[i], "bdata")) {
972 search_data->extra = g_strdup (cols[i]);
976 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
977 search_data->vcard = vcard;
978 *vcard_data = g_slist_prepend (*vcard_data, search_data);
980 g_object_unref (contact);
985 ebsql_string_append_vprintf (GString *string,
991 /* Unfortunately, sqlite3_vsnprintf() doesnt tell us
992 * how many bytes it would have needed if it doesnt fit
993 * into the target buffer, so we can't avoid this
994 * really disgusting memory dup.
996 stmt = sqlite3_vmprintf (fmt, args);
997 g_string_append (string, stmt);
1002 ebsql_string_append_printf (GString *string,
1008 va_start (args, fmt);
1009 ebsql_string_append_vprintf (string, fmt, args);
1013 /* Appends an identifier suitable to identify the
1014 * column to test in the context of a query.
1016 * The suffix is for special indexed columns (such as
1017 * reverse values, sort keys, phone numbers, etc).
1020 ebsql_string_append_column (GString *string,
1021 SummaryField *field,
1022 const gchar *suffix)
1024 if (field->aux_table) {
1025 g_string_append (string, field->aux_table_symbolic);
1026 g_string_append (string, ".value");
1028 g_string_append (string, "summary.");
1029 g_string_append (string, field->dbname);
1033 g_string_append_c (string, '_');
1034 g_string_append (string, suffix);
1039 ebsql_exec_vprintf (EBookSqlite *ebsql,
1041 EbSqlRowFunc callback,
1043 GCancellable *cancellable,
1050 stmt = sqlite3_vmprintf (fmt, args);
1051 success = ebsql_exec (ebsql, stmt, callback, data, cancellable, error);
1052 sqlite3_free (stmt);
1058 ebsql_exec_printf (EBookSqlite *ebsql,
1060 EbSqlRowFunc callback,
1062 GCancellable *cancellable,
1069 va_start (args, error);
1070 success = ebsql_exec_vprintf (ebsql, fmt, callback, data, cancellable, error, args);
1077 ebsql_exec_maybe_debug (EBookSqlite *ebsql,
1080 if (ebsql_debug_flags & EBSQL_DEBUG_EXPLAIN &&
1081 strncmp (stmt, "SELECT", 6) == 0) {
1082 g_printerr ("EXPLAIN BEGIN\n STMT: %s\n", stmt);
1083 ebsql_exec_printf (ebsql, "EXPLAIN QUERY PLAN %s",
1084 ebsql_debug_query_plan_cb,
1085 NULL, NULL, NULL, stmt);
1086 g_printerr ("EXPLAIN END\n");
1088 EBSQL_NOTE (STATEMENTS, g_printerr ("STMT: %s\n", stmt));
1093 ebsql_exec (EBookSqlite *ebsql,
1095 EbSqlRowFunc callback,
1097 GCancellable *cancellable,
1100 gboolean had_cancel;
1101 gchar *errmsg = NULL;
1104 /* Debug output for statements and query plans */
1105 ebsql_exec_maybe_debug (ebsql, stmt);
1107 /* Just convenience to set the cancellable on an execution
1108 * without a transaction, error checking on the cancellable
1109 * is done with EBSQL_LOCK_OR_RETURN()
1111 if (ebsql->priv->cancel) {
1114 ebsql->priv->cancel = cancellable;
1118 ret = sqlite3_exec (ebsql->priv->db, stmt, callback, data, &errmsg);
1120 while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
1122 sqlite3_free (errmsg);
1126 ret = sqlite3_exec (ebsql->priv->db, stmt, callback, data, &errmsg);
1130 ebsql->priv->cancel = NULL;
1132 if (ret != SQLITE_OK) {
1133 EBSQL_SET_ERROR_FROM_SQLITE (error, ret, errmsg);
1134 sqlite3_free (errmsg);
1139 sqlite3_free (errmsg);
1145 ebsql_start_transaction (EBookSqlite *ebsql,
1146 EbSqlLockType lock_type,
1147 GCancellable *cancel,
1150 gboolean success = TRUE;
1152 g_return_val_if_fail (ebsql != NULL, FALSE);
1153 g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1154 g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1156 ebsql->priv->in_transaction++;
1157 g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1159 if (ebsql->priv->in_transaction == 1) {
1161 /* No cancellable should be set at transaction start time */
1162 if (ebsql->priv->cancel) {
1164 "Starting a transaction with a cancellable already set. "
1165 "Clearing previously set cancellable");
1166 g_clear_object (&ebsql->priv->cancel);
1169 /* Hold on to the cancel object until the end of the transaction */
1171 ebsql->priv->cancel = g_object_ref (cancel);
1173 /* It's important to make the distinction between a
1174 * transaction which will read or one which will write.
1176 * While it's not well documented, when receiving the SQLITE_BUSY
1177 * error status, one can only safely retry at the beginning of
1180 * If a transaction is 'upgraded' to require a writer lock
1181 * half way through the transaction and SQLITE_BUSY is returned,
1182 * the whole transaction would need to be retried from the beginning.
1184 ebsql->priv->lock_type = lock_type;
1186 switch (lock_type) {
1187 case EBSQL_LOCK_READ:
1188 success = ebsql_exec (ebsql, "BEGIN", NULL, NULL, NULL, error);
1190 case EBSQL_LOCK_WRITE:
1191 success = ebsql_exec (ebsql, "BEGIN IMMEDIATE", NULL, NULL, NULL, error);
1197 /* Warn about cases where where a read transaction might be upgraded */
1198 if (lock_type == EBSQL_LOCK_WRITE && ebsql->priv->lock_type == EBSQL_LOCK_READ)
1200 "A nested transaction wants to write, "
1201 "but the outermost transaction was started "
1202 "without a writer lock.");
1209 ebsql_commit_transaction (EBookSqlite *ebsql,
1212 gboolean success = TRUE;
1214 g_return_val_if_fail (ebsql != NULL, FALSE);
1215 g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1216 g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1218 g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1220 ebsql->priv->in_transaction--;
1222 if (ebsql->priv->in_transaction == 0) {
1223 success = ebsql_exec (ebsql, "COMMIT", NULL, NULL, NULL, error);
1225 /* The outermost transaction is finished, let's release
1226 * our reference to the user's cancel object here */
1227 g_clear_object (&ebsql->priv->cancel);
1234 ebsql_rollback_transaction (EBookSqlite *ebsql,
1237 gboolean success = TRUE;
1239 g_return_val_if_fail (ebsql != NULL, FALSE);
1240 g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1241 g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1243 g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1245 ebsql->priv->in_transaction--;
1247 if (ebsql->priv->in_transaction == 0) {
1248 success = ebsql_exec (ebsql, "ROLLBACK", NULL, NULL, NULL, error);
1250 /* The outermost transaction is finished, let's release
1251 * our reference to the user's cancel object here */
1252 g_clear_object (&ebsql->priv->cancel);
1257 static sqlite3_stmt *
1258 ebsql_prepare_statement (EBookSqlite *ebsql,
1259 const gchar *stmt_str,
1263 const gchar *stmt_tail = NULL;
1266 ret = sqlite3_prepare_v2 (ebsql->priv->db, stmt_str, strlen (stmt_str), &stmt, &stmt_tail);
1268 if (ret != SQLITE_OK) {
1269 const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1270 EBSQL_SET_ERROR_LITERAL (
1272 E_BOOK_SQLITE_ERROR_ENGINE,
1274 } else if (stmt == NULL) {
1275 EBSQL_SET_ERROR_LITERAL (
1277 E_BOOK_SQLITE_ERROR_ENGINE,
1278 "Unknown error preparing SQL statement");
1281 if (stmt_tail && stmt_tail[0])
1282 g_warning ("Part of this statement was not parsed: %s", stmt_tail);
1287 /* Convenience for running statements. After successfully
1288 * binding all parameters, just return with this.
1291 ebsql_complete_statement (EBookSqlite *ebsql,
1296 if (ret == SQLITE_OK)
1297 ret = sqlite3_step (stmt);
1299 if (ret != SQLITE_OK && ret != SQLITE_DONE) {
1300 const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1301 EBSQL_SET_ERROR_FROM_SQLITE (error, ret, errmsg);
1304 /* Reset / Clear at the end, regardless of error state */
1305 sqlite3_reset (stmt);
1306 sqlite3_clear_bindings (stmt);
1308 return (ret == SQLITE_OK || ret == SQLITE_DONE);
1311 /******************************************************
1312 * Functions installed into the SQLite *
1313 ******************************************************/
1315 /* Implementation for REGEXP keyword */
1317 ebsql_regexp (sqlite3_context *context,
1319 sqlite3_value **argv)
1322 const gchar *expression;
1325 /* Reuse the same GRegex for all REGEXP queries with the same expression */
1326 regex = sqlite3_get_auxdata (context, 0);
1328 GError *error = NULL;
1330 expression = (const gchar *) sqlite3_value_text (argv[0]);
1332 regex = g_regex_new (expression, 0, 0, &error);
1335 sqlite3_result_error (
1337 error ? error->message :
1338 _("Error parsing regular expression"),
1340 g_clear_error (&error);
1344 /* SQLite will take care of freeing the GRegex when we're done with the query */
1345 sqlite3_set_auxdata (context, 0, regex, (GDestroyNotify) g_regex_unref);
1348 /* Now perform the comparison */
1349 text = (const gchar *) sqlite3_value_text (argv[1]);
1353 match = g_regex_match (regex, text, 0, NULL);
1354 sqlite3_result_int (context, match ? 1 : 0);
1358 /* Implementation of EBSQL_FUNC_COMPARE_VCARD (fallback for non-summary queries) */
1360 ebsql_compare_vcard (sqlite3_context *context,
1362 sqlite3_value **argv)
1364 EBookBackendSExp *sexp = NULL;
1368 /* Reuse the same sexp for all queries with the same search expression */
1369 sexp = sqlite3_get_auxdata (context, 0);
1372 /* The first argument will be reused for many rows */
1373 text = (const gchar *) sqlite3_value_text (argv[0]);
1375 sexp = e_book_backend_sexp_new (text);
1376 sqlite3_set_auxdata (
1382 /* This shouldn't happen, catch invalid sexp in preflight */
1384 sqlite3_result_int (context, 0);
1390 /* Reuse the same vcard as much as possible (it can be referred to more than
1391 * once in the query, so it can be reused for multiple comparisons on the same row)
1393 * This may look extensive, but as the vcard might be resolved by calling a
1394 * EbSqlVCardCallback, it's important to reuse this string as much as possible.
1396 * See ebsql_fetch_vcard() for details.
1398 vcard = sqlite3_get_auxdata (context, 1);
1400 vcard = (const gchar *) sqlite3_value_text (argv[1]);
1403 sqlite3_set_auxdata (context, 1, g_strdup (vcard), g_free);
1406 /* A NULL vcard can never match */
1407 if (vcard == NULL || *vcard == '\0') {
1408 sqlite3_result_int (context, 0);
1412 /* Compare this vcard */
1413 if (e_book_backend_sexp_match_vcard (sexp, vcard))
1414 sqlite3_result_int (context, 1);
1416 sqlite3_result_int (context, 0);
1420 ebsql_eqphone (sqlite3_context *context,
1422 sqlite3_value **argv,
1423 EPhoneNumberMatch requested_match)
1425 EBookSqlite *ebsql = sqlite3_user_data (context);
1426 EPhoneNumber *input_phone = NULL, *row_phone = NULL;
1427 EPhoneNumberMatch match = E_PHONE_NUMBER_MATCH_NONE;
1430 /* Reuse the same phone number for all queries with the same phone number argument */
1431 input_phone = sqlite3_get_auxdata (context, 0);
1434 /* The first argument will be reused for many rows */
1435 text = (const gchar *) sqlite3_value_text (argv[0]);
1438 /* Ignore errors, they are fine for phone numbers */
1439 input_phone = e_phone_number_from_string (text, ebsql->priv->region_code, NULL);
1441 /* SQLite will take care of freeing the EPhoneNumber when we're done with the expression */
1443 sqlite3_set_auxdata (
1446 (GDestroyNotify) e_phone_number_free);
1450 /* This shouldn't happen, as we catch invalid phone number queries in preflight
1453 sqlite3_result_int (context, 0);
1457 /* Parse the phone number for this row */
1458 text = (const gchar *) sqlite3_value_text (argv[1]);
1460 row_phone = e_phone_number_from_string (text, ebsql->priv->region_code, NULL);
1462 /* And perform the comparison */
1464 match = e_phone_number_compare (input_phone, row_phone);
1466 e_phone_number_free (row_phone);
1470 /* Now report the result */
1471 if (match != E_PHONE_NUMBER_MATCH_NONE &&
1472 match <= requested_match)
1473 sqlite3_result_int (context, 1);
1475 sqlite3_result_int (context, 0);
1478 /* Exact phone number match function: EBSQL_FUNC_EQPHONE_EXACT */
1480 ebsql_eqphone_exact (sqlite3_context *context,
1482 sqlite3_value **argv)
1484 ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_EXACT);
1487 /* National phone number match function: EBSQL_FUNC_EQPHONE_NATIONAL */
1489 ebsql_eqphone_national (sqlite3_context *context,
1491 sqlite3_value **argv)
1493 ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_NATIONAL);
1496 /* Short phone number match function: EBSQL_FUNC_EQPHONE_SHORT */
1498 ebsql_eqphone_short (sqlite3_context *context,
1500 sqlite3_value **argv)
1502 ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_SHORT);
1505 /* Implementation of EBSQL_FUNC_FETCH_VCARD (fallback for shallow addressbooks) */
1507 ebsql_fetch_vcard (sqlite3_context *context,
1509 sqlite3_value **argv)
1511 EBookSqlite *ebsql = sqlite3_user_data (context);
1514 gchar *vcard = NULL;
1516 uid = (const gchar *) sqlite3_value_text (argv[0]);
1517 extra = (const gchar *) sqlite3_value_text (argv[1]);
1519 /* Call our delegate to generate the vcard */
1520 if (ebsql->priv->vcard_callback)
1521 vcard = ebsql->priv->vcard_callback (
1522 uid, extra, ebsql->priv->user_data);
1527 "fetch_vcard (%s, %s) %s",
1528 uid, extra, vcard ? "Got VCard" : "No VCard"));
1530 sqlite3_result_text (context, vcard, -1, g_free);
1535 EbSqlCustomFunc func;
1537 } EbSqlCustomFuncTab;
1539 static EbSqlCustomFuncTab ebsql_custom_functions[] = {
1540 { "regexp", ebsql_regexp, 2 }, /* regexp (expression, column_data) */
1541 { EBSQL_FUNC_COMPARE_VCARD, ebsql_compare_vcard, 2 }, /* compare_vcard (sexp, vcard) */
1542 { EBSQL_FUNC_FETCH_VCARD, ebsql_fetch_vcard, 2 }, /* fetch_vcard (uid, extra) */
1543 { EBSQL_FUNC_EQPHONE_EXACT, ebsql_eqphone_exact, 2 }, /* eqphone_exact (search_input, column_data) */
1544 { EBSQL_FUNC_EQPHONE_NATIONAL, ebsql_eqphone_national, 2 }, /* eqphone_national (search_input, column_data) */
1545 { EBSQL_FUNC_EQPHONE_SHORT, ebsql_eqphone_short, 2 }, /* eqphone_national (search_input, column_data) */
1548 /******************************************************
1549 * Fallback Collation Sequences *
1550 ******************************************************
1552 * The fallback simply compares vcards, vcards which have been
1553 * stored on the cursor will have a preencoded key (these
1554 * utilities encode & decode that key).
1557 ebsql_encode_vcard_sort_key (const gchar *sort_key)
1559 EVCard *vcard = e_vcard_new ();
1563 /* Encode this otherwise e-vcard messes it up */
1564 base64 = g_base64_encode ((const guchar *) sort_key, strlen (sort_key));
1565 e_vcard_append_attribute_with_value (
1567 e_vcard_attribute_new (NULL, EBSQL_VCARD_SORT_KEY),
1569 encoded = e_vcard_to_string (vcard, EVC_FORMAT_VCARD_30);
1572 g_object_unref (vcard);
1578 ebsql_decode_vcard_sort_key_from_vcard (EVCard *vcard)
1580 EVCardAttribute *attr;
1581 GList *values = NULL;
1582 gchar *sort_key = NULL;
1583 gchar *base64 = NULL;
1585 attr = e_vcard_get_attribute (vcard, EBSQL_VCARD_SORT_KEY);
1587 values = e_vcard_attribute_get_values (attr);
1589 if (values && values->data) {
1592 base64 = g_strdup (values->data);
1594 sort_key = (gchar *) g_base64_decode (base64, &len);
1602 ebsql_decode_vcard_sort_key (const gchar *encoded)
1607 vcard = e_vcard_new_from_string (encoded);
1608 sort_key = ebsql_decode_vcard_sort_key_from_vcard (vcard);
1609 g_object_unref (vcard);
1616 EContactField field;
1620 ebsql_fallback_collator (gpointer ref,
1622 gconstpointer data1,
1624 gconstpointer data2)
1626 EbSqlCollData *data = (EbSqlCollData *) ref;
1627 EBookSqlitePrivate *priv;
1628 EContact *contact1, *contact2;
1629 const gchar *str1, *str2;
1634 priv = data->ebsql->priv;
1636 str1 = (const gchar *) data1;
1637 str2 = (const gchar *) data2;
1639 /* Construct 2 contacts (we're comparing vcards) */
1640 contact1 = e_contact_new ();
1641 contact2 = e_contact_new ();
1642 e_vcard_construct_full (E_VCARD (contact1), str1, len1, NULL);
1643 e_vcard_construct_full (E_VCARD (contact2), str2, len2, NULL);
1645 /* Extract first key */
1646 key1 = ebsql_decode_vcard_sort_key_from_vcard (E_VCARD (contact1));
1648 tmp = e_contact_get (contact1, data->field);
1650 key1 = e_collator_generate_key (priv->collator, tmp, NULL);
1654 key1 = g_strdup ("");
1656 /* Extract second key */
1657 key2 = ebsql_decode_vcard_sort_key_from_vcard (E_VCARD (contact2));
1659 tmp = e_contact_get (contact2, data->field);
1661 key2 = e_collator_generate_key (priv->collator, tmp, NULL);
1665 key2 = g_strdup ("");
1667 result = strcmp (key1, key2);
1671 g_object_unref (contact1);
1672 g_object_unref (contact2);
1677 static EbSqlCollData *
1678 ebsql_coll_data_new (EBookSqlite *ebsql,
1679 EContactField field)
1681 EbSqlCollData *data = g_slice_new (EbSqlCollData);
1683 data->ebsql = ebsql;
1684 data->field = field;
1690 ebsql_coll_data_free (EbSqlCollData *data)
1693 g_slice_free (EbSqlCollData, data);
1696 /* COLLATE functions are generated on demand only */
1698 ebsql_generate_collator (gpointer ref,
1701 const gchar *coll_name)
1703 EBookSqlite *ebsql = (EBookSqlite *) ref;
1704 EbSqlCollData *data;
1705 EContactField field;
1706 const gchar *field_name;
1708 field_name = coll_name + strlen (EBSQL_COLLATE_PREFIX);
1709 field = e_contact_field_id (field_name);
1711 /* This should be caught before reaching here, just an extra check */
1712 if (field == 0 || field >= E_CONTACT_FIELD_LAST ||
1713 e_contact_field_type (field) != G_TYPE_STRING) {
1714 g_warning ("Specified collation on invalid contact field");
1718 data = ebsql_coll_data_new (ebsql, field);
1719 sqlite3_create_collation_v2 (
1720 db, coll_name, SQLITE_UTF8,
1721 data, ebsql_fallback_collator,
1722 (GDestroyNotify) ebsql_coll_data_free);
1725 /**********************************************************
1726 * Cancel long operations with GCancellable *
1727 **********************************************************/
1729 ebsql_check_cancel (gpointer ref)
1731 EBookSqlite *ebsql = (EBookSqlite *) ref;
1733 if (ebsql->priv->cancel &&
1734 g_cancellable_is_cancelled (ebsql->priv->cancel)) {
1737 g_printerr ("CANCEL: An operation was canceled\n"));
1744 /**********************************************************
1745 * Database Initialization *
1746 **********************************************************/
1748 main_table_index_by_name (const gchar *name)
1752 for (i = 0; i < G_N_ELEMENTS (main_table_columns); i++) {
1753 if (g_strcmp0 (name, main_table_columns[i].name) == 0)
1761 check_main_table_columns (gpointer data,
1766 guint *columns_mask = (guint *) data;
1769 for (i = 0; i < n_cols; i++) {
1771 if (g_strcmp0 (name[i], "name") == 0) {
1772 gint idx = main_table_index_by_name (cols[i]);
1775 *columns_mask |= (1 << idx);
1785 ebsql_init_sqlite (EBookSqlite *ebsql,
1786 const gchar *filename,
1791 e_sqlite3_vfs_init ();
1793 ret = sqlite3_open (filename, &ebsql->priv->db);
1795 /* Handle GCancellable */
1796 sqlite3_progress_handler (
1798 EBSQL_CANCEL_BATCH_SIZE,
1802 /* Install our custom functions */
1803 for (i = 0; ret == SQLITE_OK && i < G_N_ELEMENTS (ebsql_custom_functions); i++)
1804 ret = sqlite3_create_function (
1806 ebsql_custom_functions[i].name,
1807 ebsql_custom_functions[i].arguments,
1809 ebsql_custom_functions[i].func,
1812 /* Fallback COLLATE implementations generated on demand */
1813 if (ret == SQLITE_OK)
1814 ret = sqlite3_collation_needed (
1815 ebsql->priv->db, ebsql, ebsql_generate_collator);
1817 if (ret != SQLITE_OK) {
1818 if (!ebsql->priv->db) {
1819 EBSQL_SET_ERROR_LITERAL (
1821 E_BOOK_SQLITE_ERROR_LOAD,
1822 _("Insufficient memory"));
1824 const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1828 E_BOOK_SQLITE_ERROR_ENGINE,
1829 "Can't open database %s: %s\n",
1831 sqlite3_close (ebsql->priv->db);
1836 ebsql_exec (ebsql, "ATTACH DATABASE ':memory:' AS mem", NULL, NULL, NULL, NULL);
1837 ebsql_exec (ebsql, "PRAGMA foreign_keys = ON", NULL, NULL, NULL, NULL);
1838 ebsql_exec (ebsql, "PRAGMA case_sensitive_like = ON", NULL, NULL, NULL, NULL);
1844 format_column_declaration (GString *string,
1847 g_string_append (string, info->name);
1848 g_string_append_c (string, ' ');
1850 g_string_append (string, info->type);
1853 g_string_append_c (string, ' ');
1854 g_string_append (string, info->extra);
1858 static inline gboolean
1859 ensure_column_index (EBookSqlite *ebsql,
1867 return ebsql_exec_printf (
1869 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)",
1870 NULL, NULL, NULL, error,
1871 info->index, table, info->name);
1874 /* Called with the lock held and inside a transaction */
1876 ebsql_resolve_folderid (EBookSqlite *ebsql,
1877 gint *previous_schema,
1878 gint *already_exists,
1883 gchar *loaded_folder_id = NULL;
1886 success = ebsql_exec (
1887 ebsql, "SELECT count(*) FROM sqlite_master "
1888 "WHERE type='table' AND name='folders';",
1889 get_count_cb, &n_folders, NULL, error);
1891 if (success && n_folders > 1) {
1892 EBSQL_SET_ERROR_LITERAL (
1894 E_BOOK_SQLITE_ERROR_LOAD,
1895 _("Cannot upgrade contacts database from a legacy "
1896 "database with more than one addressbook. "
1897 "Delete one of the entries in the 'folders' table first."));
1901 if (success && n_folders == 1)
1902 success = ebsql_exec (
1903 ebsql, "SELECT folder_id FROM folders LIMIT 1",
1904 get_string_cb, &loaded_folder_id, NULL, error);
1906 if (success && n_folders == 1)
1907 success = ebsql_exec (
1908 ebsql, "SELECT version FROM folders LIMIT 1",
1909 get_int_cb, &version, NULL, error);
1911 if (success && n_folders == 1) {
1912 g_free (ebsql->priv->folderid);
1913 ebsql->priv->folderid = loaded_folder_id;
1915 g_free (loaded_folder_id);
1919 *already_exists = TRUE;
1921 *already_exists = FALSE;
1926 "SCHEMA: main folder id resolved as '%s', "
1927 "already existing tables: %d loaded version: %d (%s)\n",
1928 ebsql->priv->folderid, n_folders, version,
1929 success ? "success" : "failed"));
1931 *previous_schema = version;
1936 /* Called with the lock held and inside a transaction */
1938 ebsql_init_folders (EBookSqlite *ebsql,
1939 gint previous_schema,
1943 guint existing_columns_mask = 0, i;
1946 string = g_string_sized_new (COLUMN_DEFINITION_BYTES * G_N_ELEMENTS (main_table_columns));
1947 g_string_append (string, "CREATE TABLE IF NOT EXISTS folders (");
1948 for (i = 0; i < G_N_ELEMENTS (main_table_columns); i++) {
1951 g_string_append (string, ", ");
1953 format_column_declaration (string, &(main_table_columns[i]));
1955 g_string_append_c (string, ')');
1957 /* Create main folders table */
1958 success = ebsql_exec (ebsql, string->str, NULL, NULL, NULL, error);
1959 g_string_free (string, TRUE);
1961 /* Check which columns in the main table already exist */
1963 success = ebsql_exec (
1964 ebsql, "PRAGMA table_info (folders)",
1965 check_main_table_columns, &existing_columns_mask,
1968 /* Add columns which may be missing */
1969 for (i = 0; success && i < G_N_ELEMENTS (main_table_columns); i++) {
1970 ColumnInfo *info = &(main_table_columns[i]);
1972 if ((existing_columns_mask & (1 << i)) != 0)
1975 success = ebsql_exec_printf (
1976 ebsql, "ALTER TABLE folders ADD COLUMN %s %s %s",
1977 NULL, NULL, NULL, error, info->name, info->type,
1978 info->extra ? info->extra : "");
1981 /* Special case upgrade for schema versions 3 & 4.
1983 * Drops the reverse_multivalues column.
1985 if (success && previous_schema >= 3 && previous_schema < 5) {
1987 success = ebsql_exec (
1989 "UPDATE folders SET "
1990 "multivalues = REPLACE(RTRIM(REPLACE("
1991 "multivalues || ':', ':', "
1992 "CASE reverse_multivalues "
1993 "WHEN 0 THEN ';prefix ' "
1994 "ELSE ';prefix;suffix ' "
1995 "END)), ' ', ':'), "
1996 "reverse_multivalues = NULL",
1997 NULL, NULL, NULL, error);
2000 /* Finish the eventual upgrade by storing the current schema version.
2002 if (success && previous_schema >= 1 && previous_schema < FOLDER_VERSION)
2003 success = ebsql_exec_printf (
2004 ebsql, "UPDATE folders SET version = %d",
2005 NULL, NULL, NULL, error, FOLDER_VERSION);
2010 "SCHEMA: Initialized main folders table (%s)\n",
2011 success ? "success" : "failed"));
2016 /* Called with the lock held and inside a transaction */
2018 ebsql_init_keys (EBookSqlite *ebsql,
2023 /* Create a child table to store key/value pairs for a folder. */
2024 success = ebsql_exec (
2026 "CREATE TABLE IF NOT EXISTS keys ("
2027 " key TEXT PRIMARY KEY,"
2029 " folder_id TEXT REFERENCES folders)",
2030 NULL, NULL, NULL, error);
2032 /* Add an index on the keys */
2034 success = ebsql_exec (
2036 "CREATE INDEX IF NOT EXISTS keysindex ON keys (folder_id)",
2037 NULL, NULL, NULL, error);
2042 "SCHEMA: Initialized keys table (%s)\n",
2043 success ? "success" : "failed"));
2049 format_multivalues (EBookSqlite *ebsql)
2053 gboolean first = TRUE;
2055 string = g_string_new (NULL);
2057 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
2058 if (ebsql->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
2062 g_string_append_c (string, ':');
2064 g_string_append (string, ebsql->priv->summary_fields[i].dbname);
2066 /* E_BOOK_INDEX_SORT_KEY is not supported in the multivalue fields */
2067 if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (PREFIX)) != 0)
2068 g_string_append (string, ";prefix");
2069 if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (SUFFIX)) != 0)
2070 g_string_append (string, ";suffix");
2071 if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (PHONE)) != 0)
2072 g_string_append (string, ";phone");
2073 if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (TRANSLIT)) != 0)
2074 g_string_append (string, ";translit");
2078 return g_string_free (string, FALSE);
2081 /* Called with the lock held and inside a transaction */
2083 ebsql_add_folder (EBookSqlite *ebsql,
2088 const gchar *lc_collate;
2090 multivalues = format_multivalues (ebsql);
2091 lc_collate = setlocale (LC_COLLATE, NULL);
2093 success = ebsql_exec_printf (
2095 "INSERT OR IGNORE INTO folders"
2096 " ( folder_id, version, multivalues, lc_collate ) "
2097 "VALUES ( %Q, %d, %Q, %Q ) ",
2098 NULL, NULL, NULL, error,
2099 ebsql->priv->folderid, FOLDER_VERSION, multivalues, lc_collate);
2101 g_free (multivalues);
2106 "SCHEMA: Added '%s' entry to main folder (%s)\n",
2107 ebsql->priv->folderid, success ? "success" : "failed"));
2112 /* Called with the lock held and inside a transaction */
2114 ebsql_introspect_summary (EBookSqlite *ebsql,
2115 gint previous_schema,
2116 GSList **introspected_columns,
2120 GSList *summary_columns = NULL, *l;
2121 GArray *summary_fields = NULL;
2122 gchar *multivalues = NULL;
2125 success = ebsql_exec_printf (
2126 ebsql, "PRAGMA table_info (%Q);",
2127 get_columns_cb, &summary_columns, NULL, error,
2128 ebsql->priv->folderid);
2131 goto introspect_summary_finish;
2133 summary_columns = g_slist_reverse (summary_columns);
2134 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
2136 /* Introspect the normal summary fields */
2137 for (l = summary_columns; l; l = l->next) {
2138 EContactField field_id;
2139 const gchar *col = l->data;
2142 gchar *freeme = NULL;
2144 /* Note that we don't have any way to introspect
2145 * E_BOOK_INDEX_PREFIX, this is not important because if
2146 * the prefix index is specified, it will be created
2147 * the first time the SQLite tables are created, so
2148 * it's not important to ensure prefix indexes after
2149 * introspecting the summary.
2152 /* Check if we're parsing a reverse field */
2153 if ((p = strstr (col, "_" EBSQL_SUFFIX_REVERSE)) != NULL) {
2154 computed = INDEX_FLAG (SUFFIX);
2155 freeme = g_strndup (col, p - col);
2157 } else if ((p = strstr (col, "_" EBSQL_SUFFIX_PHONE)) != NULL) {
2158 computed = INDEX_FLAG (PHONE);
2159 freeme = g_strndup (col, p - col);
2161 } else if ((p = strstr (col, "_" EBSQL_SUFFIX_COUNTRY)) != NULL) {
2162 computed = INDEX_FLAG (PHONE);
2163 freeme = g_strndup (col, p - col);
2165 } else if ((p = strstr (col, "_" EBSQL_SUFFIX_SORT_KEY)) != NULL) {
2166 computed = INDEX_FLAG (SORT_KEY);
2167 freeme = g_strndup (col, p - col);
2169 } else if ((p = strstr (col, "_" EBSQL_SUFFIX_TRANSLIT)) != NULL) {
2170 computed = INDEX_FLAG (TRANSLIT);
2171 freeme = g_strndup (col, p - col);
2175 /* First check exception fields */
2176 if (g_ascii_strcasecmp (col, "uid") == 0)
2177 field_id = E_CONTACT_UID;
2178 else if (g_ascii_strcasecmp (col, "is_list") == 0)
2179 field_id = E_CONTACT_IS_LIST;
2181 field_id = e_contact_field_id (col);
2183 /* Check for parse error */
2184 if (field_id == 0) {
2187 E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
2188 _("Error introspecting unknown summary field '%s'"),
2195 /* Computed columns are always declared after the normal columns,
2196 * if a reverse field is encountered we need to set the suffix
2197 * index on the coresponding summary field
2203 field_idx = summary_field_array_index (summary_fields, field_id);
2204 if (field_idx >= 0) {
2205 iter = &g_array_index (summary_fields, SummaryField, field_idx);
2206 iter->index |= computed;
2210 summary_field_append (
2211 summary_fields, ebsql->priv->folderid,
2219 goto introspect_summary_finish;
2221 /* Introspect the multivalied summary fields */
2222 success = ebsql_exec_printf (
2224 "SELECT multivalues FROM folders "
2225 "WHERE folder_id = %Q",
2226 get_string_cb, &multivalues, NULL, error,
2227 ebsql->priv->folderid);
2230 goto introspect_summary_finish;
2233 gchar **fields = g_strsplit (multivalues, ":", 0);
2235 for (i = 0; fields[i] != NULL; i++) {
2236 EContactField field_id;
2240 params = g_strsplit (fields[i], ";", 0);
2241 field_id = e_contact_field_id (params[0]);
2242 iter = summary_field_append (
2244 ebsql->priv->folderid,
2248 for (j = 1; params[j]; ++j) {
2249 /* Sort keys not supported for multivalued fields */
2250 if (strcmp (params[j], "prefix") == 0) {
2251 iter->index |= INDEX_FLAG (PREFIX);
2252 } else if (strcmp (params[j], "suffix") == 0) {
2253 iter->index |= INDEX_FLAG (SUFFIX);
2254 } else if (strcmp (params[j], "phone") == 0) {
2255 iter->index |= INDEX_FLAG (PHONE);
2256 } else if (strcmp (params[j], "translit") == 0) {
2257 iter->index |= INDEX_FLAG (TRANSLIT);
2262 g_strfreev (params);
2265 g_strfreev (fields);
2268 /* HARD CODE UP AHEAD
2270 * Now we're finished introspecting, if the summary is from a previous version,
2271 * we need to add any summary fields which we're added to the default summary
2272 * since the schema version which was introduced here
2274 if (previous_schema >= 1) {
2275 SummaryField *summary_field;
2277 if (previous_schema < 8) {
2279 /* We used to keep 4 email fields in the summary, before we supported
2280 * the multivaliued E_CONTACT_EMAIL... convert the old summary to use
2281 * the multivaliued field instead.
2283 if (summary_field_array_index (summary_fields, E_CONTACT_EMAIL_1) >= 0 &&
2284 summary_field_array_index (summary_fields, E_CONTACT_EMAIL_2) >= 0 &&
2285 summary_field_array_index (summary_fields, E_CONTACT_EMAIL_3) >= 0 &&
2286 summary_field_array_index (summary_fields, E_CONTACT_EMAIL_4) >= 0) {
2288 summary_field_remove (summary_fields, E_CONTACT_EMAIL_1);
2289 summary_field_remove (summary_fields, E_CONTACT_EMAIL_2);
2290 summary_field_remove (summary_fields, E_CONTACT_EMAIL_3);
2291 summary_field_remove (summary_fields, E_CONTACT_EMAIL_4);
2293 summary_field = summary_field_append (
2295 ebsql->priv->folderid,
2296 E_CONTACT_EMAIL, NULL);
2297 summary_field->index |= INDEX_FLAG (PREFIX);
2300 /* Regardless of whether it was a default summary or not, add the sort
2301 * keys to anything less than Schema 8 (as long as those fields are at least
2304 if ((i = summary_field_array_index (summary_fields, E_CONTACT_FILE_AS)) >= 0) {
2305 summary_field = &g_array_index (summary_fields, SummaryField, i);
2306 summary_field->index |= INDEX_FLAG (SORT_KEY);
2309 if ((i = summary_field_array_index (summary_fields, E_CONTACT_GIVEN_NAME)) >= 0) {
2310 summary_field = &g_array_index (summary_fields, SummaryField, i);
2311 summary_field->index |= INDEX_FLAG (SORT_KEY);
2314 if ((i = summary_field_array_index (summary_fields, E_CONTACT_FAMILY_NAME)) >= 0) {
2315 summary_field = &g_array_index (summary_fields, SummaryField, i);
2316 summary_field->index |= INDEX_FLAG (SORT_KEY);
2321 introspect_summary_finish:
2323 /* Apply the introspected summary fields */
2325 summary_fields_array_free (
2326 ebsql->priv->summary_fields,
2327 ebsql->priv->n_summary_fields);
2329 ebsql->priv->n_summary_fields = summary_fields->len;
2330 ebsql->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
2332 *introspected_columns = summary_columns;
2333 } else if (summary_fields) {
2335 SummaryField *fields;
2337 /* Properly free the array */
2338 n_fields = summary_fields->len;
2339 fields = (SummaryField *) g_array_free (summary_fields, FALSE);
2340 summary_fields_array_free (fields, n_fields);
2342 g_slist_free_full (summary_columns, (GDestroyNotify) g_free);
2345 g_free (multivalues);
2350 "SCHEMA: Introspected summary (%s)\n",
2351 success ? "success" : "failed"));
2356 /* Called with the lock held and inside a transaction */
2358 ebsql_init_contacts (EBookSqlite *ebsql,
2359 GSList *introspected_columns,
2363 gboolean success = TRUE;
2365 GSList *summary_columns = NULL, *l;
2367 /* Get a list of all columns and indexes which should be present
2368 * in the main summary table */
2369 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
2370 SummaryField *field = &(ebsql->priv->summary_fields[i]);
2372 if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
2373 l = summary_field_list_columns (field, ebsql->priv->folderid);
2374 summary_columns = g_slist_concat (summary_columns, l);
2378 /* Create the main contacts table for this folder
2380 string = g_string_sized_new (32 * g_slist_length (summary_columns));
2381 g_string_append (string, "CREATE TABLE IF NOT EXISTS %Q (");
2383 for (l = summary_columns; l; l = l->next) {
2384 ColumnInfo *info = l->data;
2386 if (l != summary_columns)
2387 g_string_append (string, ", ");
2389 format_column_declaration (string, info);
2391 g_string_append (string, ", vcard TEXT, bdata TEXT)");
2393 success = ebsql_exec_printf (
2395 NULL, NULL, NULL, error,
2396 ebsql->priv->folderid);
2398 g_string_free (string, TRUE);
2400 /* If we introspected something, let's first adjust the contacts table
2401 * so that it includes the right columns */
2402 if (introspected_columns) {
2404 /* Add any missing columns which are in the summary fields but
2405 * not found in the contacts table
2407 for (l = summary_columns; success && l; l = l->next) {
2408 ColumnInfo *info = l->data;
2410 if (g_slist_find_custom (introspected_columns,
2411 info->name, (GCompareFunc) g_ascii_strcasecmp))
2414 success = ebsql_exec_printf (
2416 "ALTER TABLE %Q ADD COLUMN %s %s %s",
2417 NULL, NULL, NULL, error,
2418 ebsql->priv->folderid,
2419 info->name, info->type,
2420 info->extra ? info->extra : "");
2424 /* Add indexes to columns in the main contacts table
2426 for (l = summary_columns; success && l; l = l->next) {
2427 ColumnInfo *info = l->data;
2429 success = ensure_column_index (ebsql, ebsql->priv->folderid, info, error);
2432 g_slist_free_full (summary_columns, (GDestroyNotify) column_info_free);
2437 "SCHEMA: Initialized summary table '%s' (%s)\n",
2438 ebsql->priv->folderid, success ? "success" : "failed"));
2443 /* Called with the lock held and inside a transaction */
2445 ebsql_init_aux_tables (EBookSqlite *ebsql,
2446 gint previous_schema,
2450 gboolean success = TRUE;
2451 GSList *aux_columns = NULL, *l;
2455 /* Drop the general 'folder_id_lists' table which was used prior to
2456 * version 8 of the schema
2458 if (previous_schema >= 1 && previous_schema < 8) {
2459 tmp = g_strconcat (ebsql->priv->folderid, "_lists", NULL);
2460 success = ebsql_exec_printf (
2461 ebsql, "DROP TABLE IF EXISTS %Q",
2462 NULL, NULL, NULL, error, tmp);
2466 for (i = 0; success && i < ebsql->priv->n_summary_fields; i++) {
2467 SummaryField *field = &(ebsql->priv->summary_fields[i]);
2469 if (field->type != E_TYPE_CONTACT_ATTR_LIST)
2472 aux_columns = summary_field_list_columns (field, ebsql->priv->folderid);
2474 /* Create the auxiliary table for this multi valued field */
2475 string = g_string_sized_new (
2476 COLUMN_DEFINITION_BYTES * 3 +
2477 COLUMN_DEFINITION_BYTES * g_slist_length (aux_columns));
2479 g_string_append (string, "CREATE TABLE IF NOT EXISTS %Q (uid TEXT NOT NULL REFERENCES %Q (uid)");
2480 for (l = aux_columns; l; l = l->next) {
2481 ColumnInfo *info = l->data;
2483 g_string_append (string, ", ");
2484 format_column_declaration (string, info);
2486 g_string_append_c (string, ')');
2488 success = ebsql_exec_printf (
2489 ebsql, string->str, NULL, NULL, NULL, error,
2490 field->aux_table, ebsql->priv->folderid);
2491 g_string_free (string, TRUE);
2495 /* Create an index on the implied 'uid' column, this is important
2496 * when replacing (modifying) contacts, since we need to remove
2497 * all rows in an auxiliary table which matches a given UID.
2499 * This index speeds up the constraint in a statement such as:
2501 * DELETE from email_list WHERE email_list.uid = 'contact uid'
2506 "_", ebsql->priv->folderid,
2510 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)",
2511 NULL, NULL, NULL, error,
2512 tmp, field->aux_table, "uid");
2516 /* Add indexes to columns in this auxiliary table
2518 for (l = aux_columns; success && l; l = l->next) {
2519 ColumnInfo *info = l->data;
2521 success = ensure_column_index (ebsql, field->aux_table, info, error);
2524 g_slist_free_full (aux_columns, (GDestroyNotify) column_info_free);
2529 "SCHEMA: Initialized auxiliary table '%s'\n",
2536 "SCHEMA: Initialized auxiliary tables (%s)\n",
2537 success ? "success" : "failed"));
2543 ebsql_upgrade_one (EBookSqlite *ebsql,
2544 EbSqlChangeType change_type,
2545 EbSqlSearchData *result,
2548 EContact *contact = NULL;
2551 /* It can be we're opening a light summary which was created without
2552 * storing the vcards, such as was used in EDS versions 3.2 to 3.6.
2554 * In this case we just want to skip the contacts we can't load
2555 * and leave them as is in the SQLite, they will be added from
2556 * the old BDB in the case of a migration anyway.
2559 contact = e_contact_new_from_vcard_with_uid (result->vcard, result->uid);
2561 if (contact == NULL)
2564 success = ebsql_insert_contact (
2565 ebsql, change_type, contact,
2566 result->vcard, result->extra,
2569 g_object_unref (contact);
2574 /* Called with the lock held and inside a transaction */
2576 ebsql_upgrade (EBookSqlite *ebsql,
2577 EbSqlChangeType change_type,
2582 gboolean success = TRUE;
2585 GSList *batch = NULL, *l;
2586 EbSqlSearchData *result = NULL;
2589 success = ebsql_exec_printf (
2591 "SELECT summary.uid, %s, summary.bdata FROM %Q AS summary "
2592 "ORDER BY summary.uid ASC LIMIT %d",
2593 collect_full_results_cb, &batch, NULL, error,
2594 EBSQL_VCARD_FRAGMENT (ebsql),
2595 ebsql->priv->folderid, EBSQL_UPGRADE_BATCH_SIZE);
2597 success = ebsql_exec_printf (
2599 "SELECT summary.uid, %s, summary.bdata FROM %Q AS summary "
2600 "WHERE summary.uid > %Q "
2601 "ORDER BY summary.uid ASC LIMIT %d",
2602 collect_full_results_cb, &batch, NULL, error,
2603 EBSQL_VCARD_FRAGMENT (ebsql),
2604 ebsql->priv->folderid, uid, EBSQL_UPGRADE_BATCH_SIZE);
2607 /* Reverse the list, we want to walk through it forwards */
2608 batch = g_slist_reverse (batch);
2609 for (l = batch; success && l; l = l->next) {
2611 success = ebsql_upgrade_one (
2618 /* result is now the last one in the list */
2625 n_results = g_slist_length (batch);
2626 g_slist_free_full (batch, (GDestroyNotify) e_book_sqlite_search_data_free);
2628 } while (success && n_results == EBSQL_UPGRADE_BATCH_SIZE);
2632 /* Store the new locale & country code */
2634 success = ebsql_exec_printf (
2635 ebsql, "UPDATE folders SET countrycode = %Q WHERE folder_id = %Q",
2636 NULL, NULL, NULL, error,
2637 ebsql->priv->region_code, ebsql->priv->folderid);
2640 success = ebsql_exec_printf (
2641 ebsql, "UPDATE folders SET lc_collate = %Q WHERE folder_id = %Q",
2642 NULL, NULL, NULL, error,
2643 ebsql->priv->locale, ebsql->priv->folderid);
2649 ebsql_set_locale_internal (EBookSqlite *ebsql,
2650 const gchar *locale,
2653 EBookSqlitePrivate *priv = ebsql->priv;
2654 ECollator *collator;
2656 g_return_val_if_fail (locale && locale[0], FALSE);
2658 if (g_strcmp0 (priv->locale, locale) != 0) {
2659 gchar *country_code = NULL;
2661 collator = e_collator_new_interpret_country (
2662 locale, &country_code, error);
2663 if (collator == NULL)
2666 /* Assign region code parsed from the locale by ICU */
2667 g_free (priv->region_code);
2668 priv->region_code = country_code;
2671 g_free (priv->locale);
2672 priv->locale = g_strdup (locale);
2674 /* Assign collator */
2675 if (ebsql->priv->collator)
2676 e_collator_unref (ebsql->priv->collator);
2677 ebsql->priv->collator = collator;
2683 /* Called with the lock held and inside a transaction */
2685 ebsql_init_is_populated (EBookSqlite *ebsql,
2686 gint previous_schema,
2689 gboolean success = TRUE;
2691 /* Schema 8 is when we moved from EBookSqlite */
2692 if (previous_schema >= 1 && previous_schema < 8) {
2693 gint is_populated = 0;
2695 /* We need to hold on to the value of any previously set 'is_populated' flag */
2696 success = ebsql_exec_printf (
2697 ebsql, "SELECT is_populated FROM folders WHERE folder_id = %Q",
2698 get_int_cb, &is_populated, NULL, error, ebsql->priv->folderid);
2701 /* We can't use e_book_sqlite_set_key_value_int() at this
2702 * point as that would hold the access locks
2704 success = ebsql_exec_printf (
2705 ebsql, "INSERT or REPLACE INTO keys (key, value, folder_id) values (%Q, %Q, %Q)",
2706 NULL, NULL, NULL, error,
2707 E_BOOK_SQL_IS_POPULATED_KEY,
2708 is_populated ? "1" : "0",
2709 ebsql->priv->folderid);
2716 /* Called with the lock held and inside a transaction */
2718 ebsql_init_locale (EBookSqlite *ebsql,
2719 gint previous_schema,
2720 gboolean already_exists,
2723 gchar *stored_lc_collate = NULL;
2724 gchar *stored_region_code = NULL;
2725 const gchar *lc_collate = NULL;
2726 gboolean success = TRUE;
2727 gboolean relocalize_needed = FALSE;
2729 /* Get the locale setting for this addressbook */
2730 if (already_exists) {
2731 success = ebsql_exec_printf (
2732 ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
2733 get_string_cb, &stored_lc_collate, NULL, error, ebsql->priv->folderid);
2736 success = ebsql_exec_printf (
2737 ebsql, "SELECT countrycode FROM folders WHERE folder_id = %Q",
2738 get_string_cb, &stored_region_code, NULL, error, ebsql->priv->folderid);
2740 lc_collate = stored_lc_collate;
2743 /* When creating a new addressbook, or upgrading from a version
2744 * where we did not have any locale setting; default to system locale,
2745 * we must absolutely always have a locale set.
2747 if (!lc_collate || !lc_collate[0])
2748 lc_collate = setlocale (LC_COLLATE, NULL);
2749 if (!lc_collate || !lc_collate[0])
2750 lc_collate = setlocale (LC_ALL, NULL);
2751 if (!lc_collate || !lc_collate[0])
2752 lc_collate = "en_US.utf8";
2754 /* Before touching any data, make sure we have a valid ECollator,
2755 * this will also resolve our region code
2758 success = ebsql_set_locale_internal (ebsql, lc_collate, error);
2760 /* Check if we need to relocalize */
2762 /* Need to relocalize the whole thing if the schema has been upgraded to version 7 */
2763 if (previous_schema >= 1 && previous_schema < 7)
2764 relocalize_needed = TRUE;
2766 /* We may need to relocalize for a country code change */
2767 else if (g_strcmp0 (ebsql->priv->region_code, stored_region_code) != 0)
2768 relocalize_needed = TRUE;
2771 /* Reinsert all contacts with new locale & country code */
2772 if (success && relocalize_needed)
2773 success = ebsql_upgrade (ebsql, EBSQL_CHANGE_LAST, error);
2778 "SCHEMA: Initialized locale as '%s' (%s)\n",
2779 ebsql->priv->locale, success ? "success" : "failed"));
2781 g_free (stored_region_code);
2782 g_free (stored_lc_collate);
2787 static EBookSqlite *
2788 ebsql_new_internal (const gchar *path,
2790 EbSqlVCardCallback vcard_callback,
2791 EbSqlChangeCallback change_callback,
2793 GDestroyNotify user_data_destroy,
2794 SummaryField *fields,
2796 GCancellable *cancellable,
2800 gchar *dirname = NULL;
2801 gint previous_schema = 0;
2802 gboolean already_exists = FALSE;
2803 gboolean success = TRUE;
2804 GSList *introspected_columns = NULL;
2806 g_return_val_if_fail (path != NULL, NULL);
2808 EBSQL_LOCK_MUTEX (&dbcon_lock);
2812 g_printerr ("SCHEMA: Creating new EBookSqlite at path '%s'\n", path));
2814 ebsql = ebsql_ref_from_hash (path);
2816 EBSQL_NOTE (SCHEMA, g_printerr ("SCHEMA: An EBookSqlite already existed\n"));
2820 ebsql = g_object_new (E_TYPE_BOOK_SQLITE, NULL);
2821 ebsql->priv->path = g_strdup (path);
2822 ebsql->priv->folderid = g_strdup (DEFAULT_FOLDER_ID);
2823 ebsql->priv->summary_fields = fields;
2824 ebsql->priv->n_summary_fields = n_fields;
2825 ebsql->priv->vcard_callback = vcard_callback;
2826 ebsql->priv->change_callback = change_callback;
2827 ebsql->priv->user_data = user_data;
2828 ebsql->priv->user_data_destroy = user_data_destroy;
2830 ebsql->priv->source = g_object_ref (source);
2832 ebsql->priv->source = NULL;
2834 EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite initially created\n"));
2836 /* Ensure existance of the directories leading up to 'path' */
2837 dirname = g_path_get_dirname (path);
2838 if (g_mkdir_with_parents (dirname, 0777) < 0) {
2841 E_BOOK_SQLITE_ERROR_LOAD,
2842 "Can not make parent directory: %s",
2843 g_strerror (errno));
2848 /* The additional instance lock is unneccesarry because of the global
2849 * lock held here, but let's keep it locked because we hold it while
2850 * executing any SQLite code throughout this code
2852 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
2854 /* Initialize the SQLite (set some parameters and add some custom hooks) */
2855 if (!ebsql_init_sqlite (ebsql, path, error)) {
2856 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
2861 /* Lets do it all atomically inside a single transaction */
2862 if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
2863 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
2868 /* When loading addressbooks created by EBookBackendSqlite, we
2869 * need to fetch the 'folderid' which was in use for that existing
2870 * addressbook before introspecting it's summary and upgrading
2874 success = ebsql_resolve_folderid (
2880 /* Initialize main folders table, also retrieve the current
2881 * schema version if the table already exists
2884 success = ebsql_init_folders (ebsql, previous_schema, error);
2886 /* Initialize the key/value table */
2888 success = ebsql_init_keys (ebsql, error);
2890 /* Determine if the addressbook already existed, and fill out
2891 * some information in the main folder table
2893 if (success && !already_exists)
2894 success = ebsql_add_folder (ebsql, error);
2896 /* If the addressbook did exist, then check how it's configured.
2898 * Let the existing summary information override the current
2899 * one asked for by our callers.
2901 * Some summary fields are also adjusted for schema upgrades
2903 if (success && already_exists)
2904 success = ebsql_introspect_summary (
2907 &introspected_columns,
2910 /* Add the contacts table, ensure the right columns are defined
2911 * to handle our summary configuration
2914 success = ebsql_init_contacts (
2916 introspected_columns,
2919 /* Add any auxiliary tables which we might need to support our
2920 * summary configuration.
2922 * Any fields which represent a 'list-of-strings' require an
2923 * auxiliary table to store them in.
2926 success = ebsql_init_aux_tables (ebsql, previous_schema, error);
2928 /* At this point we have resolved our schema, let's build our
2929 * precompiled statements, we might use them to re-insert contacts
2933 success = ebsql_init_statements (ebsql, error);
2935 /* When porting from older schemas, we need to port the old 'is-populated' flag */
2937 success = ebsql_init_is_populated (ebsql, previous_schema, error);
2939 /* Load / resolve the current locale setting
2941 * Also perform the overall upgrade in this step
2942 * in the case that an upgrade happened, or a locale
2943 * change is detected... all rows need to be renormalized
2947 success = ebsql_init_locale (
2948 ebsql, previous_schema,
2949 already_exists, error);
2952 success = ebsql_commit_transaction (ebsql, error);
2954 /* The GError is already set. */
2955 ebsql_rollback_transaction (ebsql, NULL);
2957 /* Release the instance lock and register to the global hash */
2958 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
2961 ebsql_register_to_hash (ebsql, path);
2965 /* Cleanup and exit */
2966 EBSQL_UNLOCK_MUTEX (&dbcon_lock);
2968 /* If we failed somewhere, give up on creating the 'ebsql',
2969 * otherwise add it to the hash table
2972 g_clear_object (&ebsql);
2977 "SCHEMA: %s the new EBookSqlite\n",
2978 success ? "Successfully created" : "Failed to create"));
2980 g_slist_free_full (introspected_columns, (GDestroyNotify) g_free);
2986 /**********************************************************
2987 * Inserting Contacts *
2988 **********************************************************/
2990 convert_phone (const gchar *normal,
2991 const gchar *region_code,
2992 gint *out_country_code)
2994 EPhoneNumber *number = NULL;
2995 gchar *national_number = NULL;
2996 gint country_code = 0;
2998 /* Don't warn about erronous phone number strings, it's a perfectly normal
2999 * use case for users to enter notes instead of phone numbers in the phone
3000 * number contact fields, such as "Ask Jenny for Lisa's phone number"
3002 if (normal && e_phone_number_is_supported ())
3003 number = e_phone_number_from_string (normal, region_code, NULL);
3006 EPhoneNumberCountrySource source;
3008 national_number = e_phone_number_get_national_number (number);
3009 country_code = e_phone_number_get_country_code (number, &source);
3010 e_phone_number_free (number);
3012 if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
3016 if (out_country_code)
3017 *out_country_code = country_code;
3019 return national_number;
3028 ebsql_e164_number_new (gint country_code,
3031 E164Number *number = g_slice_new (E164Number);
3033 number->country_code = country_code;
3034 number->national = g_strdup (national);
3040 ebsql_e164_number_free (E164Number *number)
3043 g_free (number->national);
3044 g_slice_free (E164Number, number);
3049 ebsql_e164_number_find (E164Number *number_a,
3050 E164Number *number_b)
3054 ret = number_a->country_code - number_b->country_code;
3059 number_b->national);
3065 extract_e164_attribute_params (EContact *contact)
3067 EVCard *vcard = E_VCARD (contact);
3068 GList *extracted = NULL;
3071 for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
3072 EVCardAttribute *const attr = attr_list->data;
3073 EVCardAttributeParam *param = NULL;
3074 GList *param_list, *values, *l;
3075 gchar *this_national = NULL;
3076 gint this_country = 0;
3078 /* We only attach E164 parameters to TEL attributes. */
3079 if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
3082 /* Find already exisiting parameter, so that we can reuse it. */
3083 for (param_list = e_vcard_attribute_get_params (attr); param_list; param_list = param_list->next) {
3084 if (strcmp (e_vcard_attribute_param_get_name (param_list->data), EVC_X_E164) == 0) {
3085 param = param_list->data;
3093 values = e_vcard_attribute_param_get_values (param);
3094 for (l = values; l; l = l->next) {
3095 const gchar *value = l->data;
3097 if (value[0] == '+')
3098 this_country = g_ascii_strtoll (&value[1], NULL, 10);
3099 else if (this_national == NULL)
3100 this_national = g_strdup (value);
3103 if (this_national) {
3109 "Extracted e164 number from '%s' with "
3110 "country = %d national = %s\n",
3111 (gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3112 this_country, this_national));
3114 number = ebsql_e164_number_new (
3115 this_country, this_national);
3116 extracted = g_list_prepend (extracted, number);
3119 g_free (this_national);
3121 /* Clear the values, we'll insert new ones */
3122 e_vcard_attribute_param_remove_values (param);
3123 e_vcard_attribute_remove_param (attr, EVC_X_E164);
3129 "Extracted %d numbers from '%s'\n",
3130 g_list_length (extracted),
3131 (gchar *) e_contact_get_const (contact, E_CONTACT_UID)));
3137 update_e164_attribute_params (EBookSqlite *ebsql,
3139 const gchar *default_region)
3141 GList *original_numbers = NULL;
3143 gboolean changed = FALSE;
3145 EVCard *vcard = E_VCARD (contact);
3147 original_numbers = extract_e164_attribute_params (contact);
3149 for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
3150 EVCardAttribute *const attr = attr_list->data;
3151 EVCardAttributeParam *param = NULL;
3152 const gchar *original_number = NULL;
3153 gchar *country_string;
3155 E164Number number = { 0, NULL };
3157 /* We only attach E164 parameters to TEL attributes. */
3158 if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
3161 /* Fetch the TEL value */
3162 values = e_vcard_attribute_get_values (attr);
3164 /* Compute E164 number based on the TEL value */
3165 if (values && values->data) {
3166 original_number = (const gchar *) values->data;
3167 number.national = convert_phone (
3169 ebsql->priv->region_code,
3170 &(number.country_code));
3173 if (number.national == NULL)
3176 /* Count how many we successfully parsed in this region code */
3179 /* Check if we have a differing e164 number, if there is no match
3180 * in the old existing values then the vcard changed
3182 if (!g_list_find_custom (original_numbers, &number,
3183 (GCompareFunc) ebsql_e164_number_find))
3186 if (number.country_code != 0)
3187 country_string = g_strdup_printf ("+%d", number.country_code);
3189 country_string = g_strdup ("");
3191 param = e_vcard_attribute_param_new (EVC_X_E164);
3192 e_vcard_attribute_add_param (attr, param);
3194 /* Assign the parameter values. It seems odd that we revert
3195 * the order of NN and CC, but at least EVCard's parser doesn't
3196 * permit an empty first param value. Which of course could be
3197 * fixed - in order to create a nice potential IOP problem with
3198 ** other vCard parsers. */
3199 e_vcard_attribute_param_add_values (param, number.national, country_string, NULL);
3204 "Converted '%s' to e164 number with country = %d "
3205 "national = %s for '%s' (changed %s)\n",
3206 original_number, number.country_code, number.national,
3207 (gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3208 changed ? "yes" : "no"));
3210 g_free (number.national);
3211 g_free (country_string);
3215 n_numbers != g_list_length (original_numbers))
3221 "Converted %d e164 numbers for '%s' which previously had %d e164 numbers\n",
3223 (gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3224 g_list_length (original_numbers)));
3226 g_list_free_full (original_numbers, (GDestroyNotify) ebsql_e164_number_free);
3231 static sqlite3_stmt *
3232 ebsql_prepare_multi_delete (EBookSqlite *ebsql,
3233 SummaryField *field,
3236 sqlite3_stmt *stmt = NULL;
3239 stmt_str = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = :uid", field->aux_table);
3240 stmt = ebsql_prepare_statement (ebsql, stmt_str, error);
3241 sqlite3_free (stmt_str);
3247 ebsql_run_multi_delete (EBookSqlite *ebsql,
3248 SummaryField *field,
3255 stmt = g_hash_table_lookup (ebsql->priv->multi_deletes, GUINT_TO_POINTER (field->field_id));
3257 /* This can return an error if a previous call to sqlite3_step() had errors,
3258 * so let's just ignore any error in this case
3260 sqlite3_reset (stmt);
3262 /* Clear all previously set values */
3263 ret = sqlite3_clear_bindings (stmt);
3265 /* Set the UID host parameter statically */
3266 if (ret == SQLITE_OK)
3267 ret = sqlite3_bind_text (stmt, 1, uid, -1, SQLITE_STATIC);
3269 /* Run the statement */
3270 return ebsql_complete_statement (ebsql, stmt, ret, error);
3273 static sqlite3_stmt *
3274 ebsql_prepare_multi_insert (EBookSqlite *ebsql,
3275 SummaryField *field,
3278 sqlite3_stmt *stmt = NULL;
3281 string = g_string_sized_new (INSERT_MULTI_STMT_BYTES);
3282 ebsql_string_append_printf (string, "INSERT INTO %Q (uid, value", field->aux_table);
3284 if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3285 g_string_append (string, ", value_" EBSQL_SUFFIX_REVERSE);
3287 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3288 g_string_append (string, ", value_" EBSQL_SUFFIX_PHONE);
3289 g_string_append (string, ", value_" EBSQL_SUFFIX_COUNTRY);
3292 if ((field->index & INDEX_FLAG (TRANSLIT)) != 0)
3293 g_string_append (string, ", value_" EBSQL_SUFFIX_TRANSLIT);
3295 g_string_append (string, ") VALUES (:uid, :value");
3297 if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3298 g_string_append (string, ", :value_" EBSQL_SUFFIX_REVERSE);
3300 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3301 g_string_append (string, ", :value_" EBSQL_SUFFIX_PHONE);
3302 g_string_append (string, ", :value_" EBSQL_SUFFIX_COUNTRY);
3305 if ((field->index & INDEX_FLAG (TRANSLIT)) != 0)
3306 g_string_append (string, ", :value_" EBSQL_SUFFIX_TRANSLIT);
3308 g_string_append_c (string, ')');
3310 stmt = ebsql_prepare_statement (ebsql, string->str, error);
3311 g_string_free (string, TRUE);
3317 ebsql_run_multi_insert_one (EBookSqlite *ebsql,
3319 SummaryField *field,
3324 gchar *normal = e_util_utf8_normalize (value);
3326 gint ret, param_idx = 1;
3329 ret = sqlite3_bind_text (stmt, param_idx++, uid, -1, SQLITE_STATIC);
3331 if (ret == SQLITE_OK) /* :value */
3332 ret = sqlite3_bind_text (stmt, param_idx++, normal, -1, g_free);
3334 if (ret == SQLITE_OK && (field->index & INDEX_FLAG (SUFFIX)) != 0) {
3336 str = g_utf8_strreverse (normal, -1);
3340 /* :value_reverse */
3341 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3344 if (ret == SQLITE_OK && (field->index & INDEX_FLAG (PHONE)) != 0) {
3347 str = convert_phone (
3348 normal, ebsql->priv->region_code,
3352 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3354 /* :value_country */
3355 if (ret == SQLITE_OK)
3356 sqlite3_bind_int (stmt, param_idx++, country_code);
3360 if (ret == SQLITE_OK && (field->index & INDEX_FLAG (TRANSLIT)) != 0) {
3363 tmp = e_transliterator_transliterate (ebsql->priv->transliterator, value);
3364 str = e_util_utf8_normalize (tmp);
3370 /* :value_translit */
3371 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3374 /* Run the statement */
3375 return ebsql_complete_statement (ebsql, stmt, ret, error);
3379 ebsql_run_multi_insert (EBookSqlite *ebsql,
3380 SummaryField *field,
3387 gboolean success = TRUE;
3389 stmt = g_hash_table_lookup (ebsql->priv->multi_inserts, GUINT_TO_POINTER (field->field_id));
3390 values = e_contact_get (contact, field->field_id);
3392 for (l = values; success && l != NULL; l = l->next) {
3393 gchar *value = (gchar *) l->data;
3395 success = ebsql_run_multi_insert_one (
3396 ebsql, stmt, field, uid, value, error);
3399 /* Free the list of allocated strings */
3400 e_contact_attr_list_free (values);
3405 static sqlite3_stmt *
3406 ebsql_prepare_insert (EBookSqlite *ebsql,
3407 gboolean replace_existing,
3414 string = g_string_new ("");
3415 if (replace_existing)
3416 ebsql_string_append_printf (
3417 string, "INSERT or REPLACE INTO %Q (",
3418 ebsql->priv->folderid);
3420 ebsql_string_append_printf (
3421 string, "INSERT or FAIL INTO %Q (",
3422 ebsql->priv->folderid);
3425 * First specify the column names for the insert, since it's possible we
3426 * upgraded the DB and cannot be sure the order of the columns are ordered
3427 * just how we like them to be.
3429 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3430 SummaryField *field = &(ebsql->priv->summary_fields[i]);
3432 /* Multi values go into a separate table/statement */
3433 if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
3435 /* Only add a ", " before every field except the first,
3436 * this will not break because the first 2 fields (UID & REV)
3437 * are string fields.
3440 g_string_append (string, ", ");
3442 g_string_append (string, field->dbname);
3445 if (field->type == G_TYPE_STRING) {
3447 if ((field->index & INDEX_FLAG (SORT_KEY)) != 0) {
3448 g_string_append (string, ", ");
3449 g_string_append (string, field->dbname);
3450 g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY);
3453 if ((field->index & INDEX_FLAG (SUFFIX)) != 0) {
3454 g_string_append (string, ", ");
3455 g_string_append (string, field->dbname);
3456 g_string_append (string, "_" EBSQL_SUFFIX_REVERSE);
3459 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3461 g_string_append (string, ", ");
3462 g_string_append (string, field->dbname);
3463 g_string_append (string, "_" EBSQL_SUFFIX_PHONE);
3465 g_string_append (string, ", ");
3466 g_string_append (string, field->dbname);
3467 g_string_append (string, "_" EBSQL_SUFFIX_COUNTRY);
3470 if ((field->index & INDEX_FLAG (TRANSLIT)) != 0) {
3471 g_string_append (string, ", ");
3472 g_string_append (string, field->dbname);
3473 g_string_append (string, "_" EBSQL_SUFFIX_TRANSLIT);
3477 g_string_append (string, ", vcard, bdata)");
3480 * Now specify values for all of the column names we specified.
3482 g_string_append (string, " VALUES (");
3483 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3484 SummaryField *field = &(ebsql->priv->summary_fields[i]);
3486 if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
3487 /* Only add a ", " before every field except the first,
3488 * this will not break because the first 2 fields (UID & REV)
3489 * are string fields.
3492 g_string_append (string, ", ");
3495 if (field->type == G_TYPE_STRING || field->type == G_TYPE_BOOLEAN) {
3497 g_string_append_c (string, ':');
3498 g_string_append (string, field->dbname);
3500 if ((field->index & INDEX_FLAG (SORT_KEY)) != 0)
3501 g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_SORT_KEY, field->dbname);
3503 if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3504 g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_REVERSE, field->dbname);
3506 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3507 g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_PHONE, field->dbname);
3508 g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_COUNTRY, field->dbname);
3511 if ((field->index & INDEX_FLAG (TRANSLIT)) != 0)
3512 g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_TRANSLIT, field->dbname);
3514 } else if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3515 g_warn_if_reached ();
3518 g_string_append (string, ", :vcard, :bdata)");
3520 stmt = ebsql_prepare_statement (ebsql, string->str, error);
3521 g_string_free (string, TRUE);
3527 ebsql_init_statements (EBookSqlite *ebsql,
3533 ebsql->priv->insert_stmt = ebsql_prepare_insert (ebsql, FALSE, error);
3534 if (!ebsql->priv->insert_stmt)
3535 goto preparation_failed;
3537 ebsql->priv->replace_stmt = ebsql_prepare_insert (ebsql, TRUE, error);
3538 if (!ebsql->priv->replace_stmt)
3539 goto preparation_failed;
3541 ebsql->priv->multi_deletes =
3542 g_hash_table_new_full (
3543 g_direct_hash, g_direct_equal,
3545 (GDestroyNotify) sqlite3_finalize);
3546 ebsql->priv->multi_inserts =
3547 g_hash_table_new_full (
3548 g_direct_hash, g_direct_equal,
3550 (GDestroyNotify) sqlite3_finalize);
3552 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3553 SummaryField *field = &(ebsql->priv->summary_fields[i]);
3555 if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3558 stmt = ebsql_prepare_multi_insert (ebsql, field, error);
3560 goto preparation_failed;
3562 g_hash_table_insert (
3563 ebsql->priv->multi_inserts,
3564 GUINT_TO_POINTER (field->field_id),
3567 stmt = ebsql_prepare_multi_delete (ebsql, field, error);
3569 goto preparation_failed;
3571 g_hash_table_insert (
3572 ebsql->priv->multi_deletes,
3573 GUINT_TO_POINTER (field->field_id),
3585 ebsql_run_insert (EBookSqlite *ebsql,
3592 EBookSqlitePrivate *priv;
3597 GError *local_error = NULL;
3602 stmt = ebsql->priv->replace_stmt;
3604 stmt = ebsql->priv->insert_stmt;
3606 /* This can return an error if a previous call to sqlite3_step() had errors,
3607 * so let's just ignore any error in this case
3609 sqlite3_reset (stmt);
3611 /* Clear all previously set values */
3612 ret = sqlite3_clear_bindings (stmt);
3614 for (i = 0, param_idx = 1; ret == SQLITE_OK && i < ebsql->priv->n_summary_fields; i++) {
3615 SummaryField *field = &(ebsql->priv->summary_fields[i]);
3617 if (field->type == G_TYPE_STRING) {
3622 val = e_contact_get (contact, field->field_id);
3624 /* Special exception, never normalize/localize the UID or REV string */
3625 if (field->field_id != E_CONTACT_UID &&
3626 field->field_id != E_CONTACT_REV) {
3627 normal = e_util_utf8_normalize (val);
3629 normal = g_strdup (val);
3631 /* Takes ownership of 'normal' */
3632 ret = sqlite3_bind_text (stmt, param_idx++, normal, -1, g_free);
3634 if (ret == SQLITE_OK &&
3635 (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
3637 str = e_collator_generate_key (ebsql->priv->collator, val, NULL);
3639 str = g_strdup ("");
3641 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3644 if (ret == SQLITE_OK &&
3645 (field->index & INDEX_FLAG (SUFFIX)) != 0) {
3647 str = g_utf8_strreverse (normal, -1);
3651 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3654 if (ret == SQLITE_OK &&
3655 (field->index & INDEX_FLAG (PHONE)) != 0) {
3658 str = convert_phone (
3659 normal, ebsql->priv->region_code,
3662 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3663 if (ret == SQLITE_OK)
3664 sqlite3_bind_int (stmt, param_idx++, country_code);
3667 if (ret == SQLITE_OK &&
3668 (field->index & INDEX_FLAG (TRANSLIT)) != 0) {
3671 gchar *tmp = e_transliterator_transliterate (ebsql->priv->transliterator, val);
3672 str = e_util_utf8_normalize (tmp);
3678 ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3682 } else if (field->type == G_TYPE_BOOLEAN) {
3685 val = e_contact_get (contact, field->field_id) ? TRUE : FALSE;
3687 ret = sqlite3_bind_int (stmt, param_idx++, val ? 1 : 0);
3688 } else if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3689 g_warn_if_reached ();
3692 if (ret == SQLITE_OK) {
3697 "Inserting vcard for contact with UID '%s'\n%s\n",
3698 (gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3699 vcard ? vcard : "(no vcard)"));
3701 /* If we have a priv->vcard_callback, then it's a shallow addressbook
3702 * and we don't populate the vcard column, need to free it anyway
3704 if (priv->vcard_callback != NULL) {
3709 ret = sqlite3_bind_text (stmt, param_idx++, vcard, -1, g_free);
3712 /* The extra data */
3713 if (ret == SQLITE_OK)
3714 ret = sqlite3_bind_text (stmt, param_idx++, g_strdup (extra), -1, g_free);
3716 /* Run the statement */
3717 success = ebsql_complete_statement (ebsql, stmt, ret, &local_error);
3722 "%s contact with UID '%s' and extra data '%s' vcard: %s (error: %s)\n",
3723 success ? "Succesfully inserted" : "Failed to insert",
3724 (gchar *) e_contact_get_const (contact, E_CONTACT_UID), extra,
3725 vcard ? "yes" : "no",
3726 local_error ? local_error->message : "(none)"));
3729 g_propagate_error (error, local_error);
3735 ebsql_insert_contact (EBookSqlite *ebsql,
3736 EbSqlChangeType change_type,
3738 const gchar *original_vcard,
3743 EBookSqlitePrivate *priv;
3744 gboolean e164_changed = FALSE;
3746 gchar *uid, *vcard = NULL;
3749 uid = e_contact_get (contact, E_CONTACT_UID);
3751 /* Update E.164 parameters in vcard if needed */
3752 e164_changed = update_e164_attribute_params (
3753 ebsql, contact, priv->region_code);
3755 if (e164_changed || original_vcard == NULL) {
3757 /* Generate a new one if it changed (or if we don't have one) */
3758 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
3761 change_type != EBSQL_CHANGE_LAST &&
3762 ebsql->priv->change_callback)
3763 ebsql->priv->change_callback (change_type,
3765 ebsql->priv->user_data);
3768 vcard = g_strdup (original_vcard);
3771 /* This actually consumes 'vcard' */
3772 success = ebsql_run_insert (ebsql, replace, contact, vcard, extra, error);
3774 /* Update attribute list table */
3778 for (i = 0; success && i < priv->n_summary_fields; i++) {
3779 SummaryField *field = &(ebsql->priv->summary_fields[i]);
3781 if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3784 success = ebsql_run_multi_delete (
3785 ebsql, field, uid, error);
3788 success = ebsql_run_multi_insert (
3789 ebsql, field, uid, contact, error);
3798 /***************************************************************
3799 * Structures and utilities for preflight and query generation *
3800 ***************************************************************/
3802 /* This enumeration is ordered by severity, higher values
3803 * of PreflightStatus take precedence in error reporting.
3808 PREFLIGHT_NOT_SUMMARIZED,
3810 PREFLIGHT_UNSUPPORTED,
3813 #define EBSQL_STATUS_STR(status) \
3814 ((status) == PREFLIGHT_OK ? "Ok" : \
3815 (status) == PREFLIGHT_LIST_ALL ? "List all" : \
3816 (status) == PREFLIGHT_NOT_SUMMARIZED ? "Not Summarized" : \
3817 (status) == PREFLIGHT_INVALID ? "Invalid" : \
3818 (status) == PREFLIGHT_UNSUPPORTED ? "Unsupported" : "(unknown status)")
3820 /* Whether we can satisfy the constraints or whether we
3821 * need to do a fallback, we still need to call
3822 * ebsql_generate_constraints()
3824 #define EBSQL_STATUS_GEN_CONSTRAINTS(status) \
3825 ((status) == PREFLIGHT_OK || \
3826 (status) == PREFLIGHT_NOT_SUMMARIZED)
3828 /* Internal extension of the EBookQueryTest enumeration */
3830 /* 'exists' is a supported query on a field, but not part of EBookQueryTest */
3831 BOOK_QUERY_EXISTS = E_BOOK_QUERY_LAST,
3833 /* From here the compound types start */
3839 BOOK_QUERY_SUB_FIRST = BOOK_QUERY_SUB_AND,
3842 #define EBSQL_QUERY_TYPE_STR(query) \
3843 ((query) == BOOK_QUERY_EXISTS ? "exists" : \
3844 (query) == BOOK_QUERY_SUB_AND ? "AND" : \
3845 (query) == BOOK_QUERY_SUB_OR ? "OR" : \
3846 (query) == BOOK_QUERY_SUB_NOT ? "NOT" : \
3847 (query) == BOOK_QUERY_SUB_END ? "END" : \
3848 (query) == E_BOOK_QUERY_IS ? "is" : \
3849 (query) == E_BOOK_QUERY_CONTAINS ? "contains" : \
3850 (query) == E_BOOK_QUERY_BEGINS_WITH ? "begins-with" : \
3851 (query) == E_BOOK_QUERY_ENDS_WITH ? "ends-with" : \
3852 (query) == E_BOOK_QUERY_EQUALS_PHONE_NUMBER ? "eqphone" : \
3853 (query) == E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER ? "eqphone-national" : \
3854 (query) == E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER ? "eqphone-short" : \
3855 (query) == E_BOOK_QUERY_REGEX_NORMAL ? "regex-normal" : \
3856 (query) == E_BOOK_QUERY_REGEX_RAW ? "regex-raw" : \
3857 (query) == E_BOOK_QUERY_TRANSLIT_IS ? "translit-is" : \
3858 (query) == E_BOOK_QUERY_TRANSLIT_CONTAINS ? "translit-contains" : \
3859 (query) == E_BOOK_QUERY_TRANSLIT_BEGINS_WITH ? "translit-begins-with" : \
3860 (query) == E_BOOK_QUERY_TRANSLIT_ENDS_WITH ? "translit-ends-with" : "unknown")
3862 #define EBSQL_FIELD_ID_STR(field_id) \
3863 ((field_id) == E_CONTACT_FIELD_LAST ? "x-evolution-any-field" : \
3864 (field_id) == 0 ? "(not an EContactField)" : \
3865 e_contact_field_name (field_id))
3867 #define IS_QUERY_PHONE(query) \
3868 ((query) == E_BOOK_QUERY_EQUALS_PHONE_NUMBER || \
3869 (query) == E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER || \
3870 (query) == E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER)
3873 guint query; /* EBookQueryTest (extended) */
3877 guint query; /* EBookQueryTest (extended) */
3881 guint query; /* EBookQueryTest (extended) */
3883 EContactField field_id; /* The EContactField to compare */
3884 SummaryField *field; /* The summary field for 'field' */
3885 gchar *value; /* The value to compare with */
3890 guint query; /* EBookQueryTest (extended) */
3892 /* Common fields from QueryFieldTest */
3893 EContactField field_id; /* The EContactField to compare */
3894 SummaryField *field; /* The summary field for 'field' */
3895 gchar *value; /* The value to compare with */
3898 gchar *region; /* Region code from the query input */
3899 gchar *national; /* Parsed national number */
3900 gint country; /* Parsed country code */
3903 /* Stack initializer for the PreflightContext struct below */
3904 #define PREFLIGHT_CONTEXT_INIT { PREFLIGHT_OK, NULL, 0 }
3907 PreflightStatus status; /* result status */
3908 GPtrArray *constraints; /* main query */
3909 guint64 aux_mask; /* Bitmask of which auxiliary tables are needed in the query */
3912 static QueryElement *
3913 query_delimiter_new (guint query)
3915 QueryDelimiter *delim;
3917 g_return_val_if_fail (query >= BOOK_QUERY_SUB_FIRST, NULL);
3919 delim = g_slice_new (QueryDelimiter);
3920 delim->query = query;
3922 return (QueryElement *) delim;
3925 static QueryFieldTest *
3926 query_field_test_new (guint query,
3927 EContactField field)
3929 QueryFieldTest *test;
3931 g_return_val_if_fail (query < BOOK_QUERY_SUB_FIRST, NULL);
3932 g_return_val_if_fail (IS_QUERY_PHONE (query) == FALSE, NULL);
3934 test = g_slice_new (QueryFieldTest);
3935 test->query = query;
3936 test->field_id = field;
3938 /* Instead of g_slice_new0, NULL them out manually */
3945 static QueryPhoneTest *
3946 query_phone_test_new (guint query,
3947 EContactField field)
3949 QueryPhoneTest *test;
3951 g_return_val_if_fail (IS_QUERY_PHONE (query), NULL);
3953 test = g_slice_new (QueryPhoneTest);
3954 test->query = query;
3955 test->field_id = field;
3957 /* Instead of g_slice_new0, NULL them out manually */
3961 /* Extra QueryPhoneTest fields */
3962 test->region = NULL;
3963 test->national = NULL;
3970 query_element_free (QueryElement *element)
3974 if (element->query >= BOOK_QUERY_SUB_FIRST) {
3975 QueryDelimiter *delim = (QueryDelimiter *) element;
3977 g_slice_free (QueryDelimiter, delim);
3978 } else if (IS_QUERY_PHONE (element->query)) {
3979 QueryPhoneTest *test = (QueryPhoneTest *) element;
3981 g_free (test->value);
3982 g_free (test->region);
3983 g_free (test->national);
3984 g_slice_free (QueryPhoneTest, test);
3986 QueryFieldTest *test = (QueryFieldTest *) element;
3988 g_free (test->value);
3989 g_slice_free (QueryFieldTest, test);
3994 /* We use ptr arrays for the QueryElement vectors */
3996 constraints_insert (GPtrArray *array,
4001 g_ptr_array_insert (array, idx, data);
4003 g_return_if_fail ((idx >= -1) && (idx < (gint) array->len + 1));
4008 g_ptr_array_add (array, NULL);
4010 if (idx != (array->len - 1))
4012 &(array->pdata[idx + 1]),
4013 &(array->pdata[idx]),
4014 ((array->len - 1) - idx) * sizeof (gpointer));
4016 array->pdata[idx] = data;
4020 static inline QueryElement *
4021 constraints_take (GPtrArray *array,
4024 QueryElement *element;
4026 g_return_val_if_fail (idx >= 0 && idx < (gint) array->len, NULL);
4028 element = array->pdata[idx];
4029 array->pdata[idx] = NULL;
4030 g_ptr_array_remove_index (array, idx);
4036 constraints_insert_delimiter (GPtrArray *array,
4040 QueryElement *delim;
4042 delim = query_delimiter_new (query);
4043 constraints_insert (array, idx, delim);
4047 constraints_insert_field_test (GPtrArray *array,
4049 SummaryField *field,
4053 QueryFieldTest *test;
4055 test = query_field_test_new (query, field->field_id);
4056 test->field = field;
4057 test->value = g_strdup (value);
4059 constraints_insert (array, idx, test);
4063 preflight_context_clear (PreflightContext *context)
4066 /* Free any allocated data, but leave the context values in place */
4067 if (context->constraints)
4068 g_ptr_array_free (context->constraints, TRUE);
4069 context->constraints = NULL;
4073 /* A small API to track the current sub-query context.
4075 * I.e. sub contexts can be OR, AND, or NOT, in which
4076 * field tests or other sub contexts are nested.
4078 typedef GQueue SubQueryContext;
4081 guint sub_type; /* The type of this sub context */
4082 guint count; /* The number of field tests so far in this context */
4085 #define sub_query_context_new g_queue_new
4086 #define sub_query_context_free(ctx) g_queue_free (ctx)
4089 sub_query_context_push (SubQueryContext *ctx,
4094 data = g_slice_new (SubQueryData);
4095 data->sub_type = sub_type;
4098 g_queue_push_tail (ctx, data);
4102 sub_query_context_pop (SubQueryContext *ctx)
4106 data = g_queue_pop_tail (ctx);
4107 g_slice_free (SubQueryData, data);
4111 sub_query_context_peek_type (SubQueryContext *ctx)
4115 data = g_queue_peek_tail (ctx);
4117 return data->sub_type;
4120 /* Returns the context field test count before incrementing */
4122 sub_query_context_increment (SubQueryContext *ctx)
4126 data = g_queue_peek_tail (ctx);
4131 return (data->count - 1);
4134 /* If we're not in a sub context, just return 0 */
4138 /**********************************************************
4139 * Querying preflighting *
4140 **********************************************************
4142 * The preflight checks are performed before a query might
4143 * take place in order to evaluate whether the given query
4144 * can be performed with the current summary configuration.
4146 * After preflighting, all relevant data has been extracted
4147 * from the search expression and the search expression need
4148 * not be parsed again.
4151 /* The PreflightSubCallback is expected to return TRUE
4152 * to keep iterating and FALSE to abort iteration.
4154 * The sub_level is the counter of how deep the 'element'
4155 * is nested in sub elements, the offset is the real offset
4156 * of 'element' in the array passed to query_preflight_foreach_sub().
4158 typedef gboolean (* PreflightSubCallback) (QueryElement *element,
4161 gpointer user_data);
4164 query_preflight_foreach_sub (QueryElement **elements,
4167 gboolean include_delim,
4168 PreflightSubCallback callback,
4171 gint sub_counter = 1, i;
4173 g_return_if_fail (offset >= 0 && offset < n_elements);
4174 g_return_if_fail (elements[offset]->query >= BOOK_QUERY_SUB_FIRST);
4175 g_return_if_fail (callback != NULL);
4177 if (include_delim && !callback (elements[offset], 0, offset, user_data))
4180 for (i = (offset + 1); sub_counter > 0 && i < n_elements; i++) {
4182 if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
4184 if (elements[i]->query == BOOK_QUERY_SUB_END)
4189 if (include_delim &&
4190 !callback (elements[i], sub_counter, i, user_data))
4194 if (!callback (elements[i], sub_counter, i, user_data))
4200 /* Table used in ESExp parsing below */
4201 static const struct {
4202 const gchar *name; /* Name of the symbol to match for this parse phase */
4203 gboolean subset; /* TRUE for the subset ESExpIFunc, otherwise the field check ESExpFunc */
4204 guint test; /* Extended EBookQueryTest value */
4205 } check_symbols[] = {
4206 { "and", TRUE, BOOK_QUERY_SUB_AND },
4207 { "or", TRUE, BOOK_QUERY_SUB_OR },
4208 { "not", TRUE, BOOK_QUERY_SUB_NOT },
4209 { "contains", FALSE, E_BOOK_QUERY_CONTAINS },
4210 { "is", FALSE, E_BOOK_QUERY_IS },
4211 { "beginswith", FALSE, E_BOOK_QUERY_BEGINS_WITH },
4212 { "endswith", FALSE, E_BOOK_QUERY_ENDS_WITH },
4213 { "eqphone", FALSE, E_BOOK_QUERY_EQUALS_PHONE_NUMBER },
4214 { "eqphone_national", FALSE, E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER },
4215 { "eqphone_short", FALSE, E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER },
4216 { "regex_normal", FALSE, E_BOOK_QUERY_REGEX_NORMAL },
4217 { "regex_raw", FALSE, E_BOOK_QUERY_REGEX_RAW },
4218 { "translit_is", FALSE, E_BOOK_QUERY_TRANSLIT_IS },
4219 { "translit_contains", FALSE, E_BOOK_QUERY_TRANSLIT_CONTAINS },
4220 { "translit_beginswith", FALSE, E_BOOK_QUERY_TRANSLIT_BEGINS_WITH },
4221 { "translit_endswith", FALSE, E_BOOK_QUERY_TRANSLIT_ENDS_WITH },
4222 { "exists", FALSE, BOOK_QUERY_EXISTS },
4225 /* Cheat our way into passing mode data to these funcs */
4226 static ESExpResult *
4227 func_check_subset (ESExp *f,
4229 struct _ESExpTerm **argv,
4232 ESExpResult *result, *sub_result;
4233 GPtrArray *result_array;
4234 QueryElement *element, **sub_elements;
4238 query_type = GPOINTER_TO_UINT (data);
4240 /* The compound query delimiter is the first element in this return array */
4241 result_array = g_ptr_array_new_with_free_func ((GDestroyNotify) query_element_free);
4242 element = query_delimiter_new (query_type);
4243 g_ptr_array_add (result_array, element);
4248 "PREFLIGHT INIT: Open sub: %s\n",
4249 EBSQL_QUERY_TYPE_STR (query_type)));
4251 for (i = 0; i < argc; i++) {
4252 sub_result = e_sexp_term_eval (f, argv[i]);
4254 if (sub_result->type == ESEXP_RES_ARRAY_PTR) {
4255 /* Steal the elements directly from the sub result */
4256 sub_elements = (QueryElement **) sub_result->value.ptrarray->pdata;
4257 len = sub_result->value.ptrarray->len;
4259 for (j = 0; j < len; j++) {
4260 element = sub_elements[j];
4261 sub_elements[j] = NULL;
4263 g_ptr_array_add (result_array, element);
4266 e_sexp_result_free (f, sub_result);
4272 "PREFLIGHT INIT: Close sub: %s\n",
4273 EBSQL_QUERY_TYPE_STR (query_type)));
4275 /* The last element in this return array is the sub end delimiter */
4276 element = query_delimiter_new (BOOK_QUERY_SUB_END);
4277 g_ptr_array_add (result_array, element);
4279 result = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
4280 result->value.ptrarray = result_array;
4285 static ESExpResult *
4286 func_check (struct _ESExp *f,
4288 struct _ESExpResult **argv,
4291 ESExpResult *result;
4292 GPtrArray *result_array;
4293 QueryElement *element = NULL;
4294 EContactField field_id = 0;
4295 const gchar *query_name = NULL;
4296 const gchar *query_value = NULL;
4297 const gchar *query_extra = NULL;
4300 query_type = GPOINTER_TO_UINT (data);
4303 argv[0]->type == ESEXP_RES_STRING &&
4304 argv[1]->type == ESEXP_RES_STRING) {
4305 query_name = argv[0]->value.string;
4306 query_value = argv[1]->value.string;
4308 /* We use E_CONTACT_FIELD_LAST to hold the special case of "x-evolution-any-field" */
4309 if (g_strcmp0 (query_name, "x-evolution-any-field") == 0)
4310 field_id = E_CONTACT_FIELD_LAST;
4312 field_id = e_contact_field_id (query_name);
4314 } else if (argc == 3 &&
4315 argv[0]->type == ESEXP_RES_STRING &&
4316 argv[1]->type == ESEXP_RES_STRING &&
4317 argv[2]->type == ESEXP_RES_STRING) {
4318 query_name = argv[0]->value.string;
4319 query_value = argv[1]->value.string;
4320 query_extra = argv[2]->value.string;
4322 field_id = e_contact_field_id (query_name);
4325 if (IS_QUERY_PHONE (query_type)) {
4326 QueryPhoneTest *test;
4328 /* Collect data from this field test */
4329 test = query_phone_test_new (query_type, field_id);
4330 test->value = g_strdup (query_value);
4331 test->region = g_strdup (query_extra);
4333 element = (QueryElement *) test;
4335 QueryFieldTest *test;
4337 /* Collect data from this field test */
4338 test = query_field_test_new (query_type, field_id);
4339 test->value = g_strdup (query_value);
4341 element = (QueryElement *) test;
4347 "PREFLIGHT INIT: Adding field test: `%s' on field `%s' "
4348 "(field name: %s query value: %s query extra: %s)\n",
4349 EBSQL_QUERY_TYPE_STR (query_type),
4350 EBSQL_FIELD_ID_STR (field_id),
4351 query_name, query_value, query_extra));
4353 /* Return an array with only one element, for lack of a pointer type ESExpResult */
4354 result_array = g_ptr_array_new_with_free_func ((GDestroyNotify) query_element_free);
4355 g_ptr_array_add (result_array, element);
4357 result = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
4358 result->value.ptrarray = result_array;
4363 /* Initial stage of preflighting:
4365 * o Parse the search expression and generate our array of QueryElements
4366 * o Collect lengths of query terms
4369 query_preflight_initialize (PreflightContext *context,
4373 ESExpResult *result;
4374 gint esexp_error, i;
4376 if (sexp == NULL || *sexp == '\0') {
4377 context->status = PREFLIGHT_LIST_ALL;
4381 sexp_parser = e_sexp_new ();
4383 for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
4384 if (check_symbols[i].subset) {
4385 e_sexp_add_ifunction (
4386 sexp_parser, 0, check_symbols[i].name,
4388 GUINT_TO_POINTER (check_symbols[i].test));
4390 e_sexp_add_function (
4391 sexp_parser, 0, check_symbols[i].name,
4393 GUINT_TO_POINTER (check_symbols[i].test));
4397 e_sexp_input_text (sexp_parser, sexp, strlen (sexp));
4398 esexp_error = e_sexp_parse (sexp_parser);
4400 if (esexp_error == -1) {
4401 context->status = PREFLIGHT_INVALID;
4405 g_printerr ("PREFLIGHT INIT: Sexp parse error\n"));
4408 result = e_sexp_eval (sexp_parser);
4411 if (result->type == ESEXP_RES_ARRAY_PTR) {
4413 /* Just steal the array away from the ESexpResult */
4414 context->constraints = result->value.ptrarray;
4415 result->value.ptrarray = NULL;
4418 context->status = PREFLIGHT_INVALID;
4422 g_printerr ("PREFLIGHT INIT: ERROR, Did not get GPtrArray\n"));
4426 e_sexp_result_free (sexp_parser, result);
4429 e_sexp_unref (sexp_parser);
4434 "PREFLIGHT INIT: Completed with status %s\n",
4435 EBSQL_STATUS_STR (context->status)));
4440 gboolean has_attr_list;
4441 } AttrListCheckData;
4444 check_has_attr_list_cb (QueryElement *element,
4449 QueryFieldTest *test = (QueryFieldTest *) element;
4450 AttrListCheckData *data = (AttrListCheckData *) user_data;
4452 /* We havent resolved all the fields at this stage yet */
4454 test->field = summary_field_get (data->ebsql, test->field_id);
4456 if (test->field && test->field->type == E_TYPE_CONTACT_ATTR_LIST)
4457 data->has_attr_list = TRUE;
4459 /* Keep looping until we find one */
4460 return (data->has_attr_list == FALSE);
4463 /* What is done in this pass:
4464 * o Viability of the query is analyzed, i.e. can it be done with the summary columns.
4465 * o Phone numbers are parsed and loaded onto QueryPhoneTests
4466 * o Bitmask of auxiliary tables is collected
4469 query_preflight_check (PreflightContext *context,
4473 QueryElement **elements;
4475 context->status = PREFLIGHT_OK;
4477 elements = (QueryElement **) context->constraints->pdata;
4478 n_elements = context->constraints->len;
4480 for (i = 0; i < n_elements; i++) {
4481 QueryFieldTest *test;
4487 "PREFLIGHT CHECK: Encountered: %s\n",
4488 EBSQL_QUERY_TYPE_STR (elements[i]->query)));
4490 if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
4491 /* It's too complicated to properly perform
4492 * the unary NOT operator on a constraint which
4493 * accesses attribute lists.
4495 * Hint, if the contact has a "%.com" email address
4496 * and a "%.org" email address, what do we return
4497 * for (not (endswith "email" ".com") ?
4499 * Currently we rely on DISTINCT to sort out
4500 * muliple results from the attribute list tables,
4501 * this breaks down with NOT.
4503 if (elements[i]->query == BOOK_QUERY_SUB_NOT) {
4504 AttrListCheckData data = { ebsql, FALSE };
4506 query_preflight_foreach_sub (elements,
4509 check_has_attr_list_cb,
4512 if (data.has_attr_list) {
4513 context->status = MAX (
4515 PREFLIGHT_NOT_SUMMARIZED);
4520 "Setting invalid for NOT (mutli-attribute), "
4522 EBSQL_STATUS_STR (context->status)));
4528 test = (QueryFieldTest *) elements[i];
4529 field_test = (EBookQueryTest) test->query;
4532 test->field = summary_field_get (ebsql, test->field_id);
4534 /* Even if the field is not in the summary, we need to
4535 * retport unsupported errors if phone number queries are
4536 * issued while libphonenumber is unavailable
4540 /* Special case for e_book_query_any_field_contains().
4542 * We interpret 'x-evolution-any-field' as E_CONTACT_FIELD_LAST
4544 if (test->field_id == E_CONTACT_FIELD_LAST) {
4546 /* If we search for a NULL or zero length string, it
4547 * means 'get all contacts', that is considered a summary
4548 * query but is handled differently (i.e. we just drop the
4549 * field tests and run a regular query).
4551 * This is only true if the 'any field contains' query is
4552 * the only test in the constraints, however.
4554 if (n_elements == 1 && (!test->value || !test->value[0])) {
4556 context->status = MAX (context->status, PREFLIGHT_LIST_ALL);
4561 "Encountered lonesome 'x-evolution-any-field' with empty value, "
4563 EBSQL_STATUS_STR (context->status)));
4566 /* Searching for a value with 'x-evolution-any-field' is
4567 * not a summary query.
4569 context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4574 "Encountered 'x-evolution-any-field', "
4576 EBSQL_STATUS_STR (context->status)));
4581 /* Couldnt resolve the field, it's not a summary query */
4582 context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4587 "Field `%s' not in the summary, new status: %s\n",
4588 EBSQL_FIELD_ID_STR (test->field_id),
4589 EBSQL_STATUS_STR (context->status)));
4593 switch (field_test) {
4594 case E_BOOK_QUERY_IS:
4597 case BOOK_QUERY_EXISTS:
4598 case E_BOOK_QUERY_CONTAINS:
4599 case E_BOOK_QUERY_BEGINS_WITH:
4600 case E_BOOK_QUERY_ENDS_WITH:
4601 case E_BOOK_QUERY_REGEX_NORMAL:
4603 /* All of these queries can only apply to string fields,
4604 * or fields which hold multiple strings
4607 if (test->field->type != G_TYPE_STRING &&
4608 test->field->type != E_TYPE_CONTACT_ATTR_LIST) {
4609 context->status = MAX (context->status, PREFLIGHT_INVALID);
4614 "Refusing pattern match on boolean field `%s', new status: %s\n",
4615 EBSQL_FIELD_ID_STR (test->field_id),
4616 EBSQL_STATUS_STR (context->status)));
4622 case E_BOOK_QUERY_REGEX_RAW:
4623 /* Raw regex queries only supported in the fallback */
4624 context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4629 "Raw regexp requires full data, new status: %s\n",
4630 EBSQL_STATUS_STR (context->status)));
4633 case E_BOOK_QUERY_EQUALS_PHONE_NUMBER:
4634 case E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER:
4635 case E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER:
4637 /* Phone number queries are supported so long as they are in the summary,
4638 * libphonenumber is available, and the phone number string is a valid one
4640 if (!e_phone_number_is_supported ()) {
4642 context->status = MAX (context->status, PREFLIGHT_UNSUPPORTED);
4647 "Usupported phone number query, new status: %s\n",
4648 EBSQL_STATUS_STR (context->status)));
4650 QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
4651 EPhoneNumberCountrySource source;
4652 EPhoneNumber *number;
4653 const gchar *region_code;
4655 if (phone_test->region)
4656 region_code = phone_test->region;
4658 region_code = ebsql->priv->region_code;
4660 number = e_phone_number_from_string (
4664 if (number == NULL) {
4666 context->status = MAX (context->status, PREFLIGHT_INVALID);
4671 "Invalid phone number `%s', new status: %s\n",
4673 EBSQL_STATUS_STR (context->status)));
4675 /* Collect values we'll need later while generating field
4676 * tests, no need to parse the phone number more than once
4678 phone_test->national = e_phone_number_get_national_number (number);
4679 phone_test->country = e_phone_number_get_country_code (number, &source);
4681 if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
4682 phone_test->country = 0;
4684 e_phone_number_free (number);
4689 case E_BOOK_QUERY_TRANSLIT_IS:
4690 case E_BOOK_QUERY_TRANSLIT_CONTAINS:
4691 case E_BOOK_QUERY_TRANSLIT_BEGINS_WITH:
4692 case E_BOOK_QUERY_TRANSLIT_ENDS_WITH:
4694 /* These only only searchable in the summary with the E_BOOK_INDEX_TRANSLIT index */
4695 if (test->field == NULL ||
4696 (test->field->index & INDEX_FLAG (TRANSLIT)) == 0) {
4698 context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4699 EBSQL_NOTE (PREFLIGHT,
4700 g_printerr ("PREFLIGHT CHECK: "
4701 "Query `%s' needs fallback search, new status: %s\n",
4702 EBSQL_QUERY_TYPE_STR (field_test),
4703 EBSQL_STATUS_STR (context->status)));
4709 test->field->type == E_TYPE_CONTACT_ATTR_LIST) {
4710 gint aux_index = summary_field_get_index (ebsql, test->field_id);
4712 /* It's really improbable that we ever get 64 fields in the summary
4713 * In any case we warn about this in e_book_sqlite_new_full().
4715 g_warn_if_fail (aux_index < EBSQL_MAX_SUMMARY_FIELDS);
4716 context->aux_mask |= (1 << aux_index);
4721 "Adding auxiliary field `%s' to the mask\n",
4722 EBSQL_FIELD_ID_STR (test->field_id)));
4727 /* Handle special case of E_CONTACT_FULL_NAME
4729 * For any query which accesses the full name field,
4730 * we need to also OR it with any of the related name
4731 * fields, IF those are found in the summary as well.
4734 query_preflight_substitute_full_name (PreflightContext *context,
4739 for (i = 0; i < context->constraints->len; i++) {
4740 SummaryField *family_name, *given_name, *nickname;
4741 QueryElement *element;
4742 QueryFieldTest *test;
4743 gboolean need_translit = FALSE;
4745 element = g_ptr_array_index (context->constraints, i);
4747 if (element->query >= BOOK_QUERY_SUB_FIRST)
4750 test = (QueryFieldTest *) element;
4751 if (test->field_id != E_CONTACT_FULL_NAME)
4754 /* If it's transliterated, we won't do this */
4755 if (element->query >= E_BOOK_QUERY_TRANSLIT_IS &&
4756 element->query <= E_BOOK_QUERY_TRANSLIT_ENDS_WITH)
4757 need_translit = TRUE;
4759 family_name = summary_field_get (ebsql, E_CONTACT_FAMILY_NAME);
4760 given_name = summary_field_get (ebsql, E_CONTACT_GIVEN_NAME);
4761 nickname = summary_field_get (ebsql, E_CONTACT_NICKNAME);
4763 /* Only OR them in if they are also indexed for transliteration */
4764 if (need_translit) {
4766 (family_name->index & INDEX_FLAG (TRANSLIT)) == 0)
4770 (given_name->index & INDEX_FLAG (TRANSLIT)) == 0)
4774 (nickname->index & INDEX_FLAG (TRANSLIT)) == 0)
4778 /* If any of these are in the summary, then we'll construct
4779 * a grouped OR statment for this E_CONTACT_FULL_NAME test */
4780 if (family_name || given_name || nickname) {
4781 /* Add the OR directly before the E_CONTACT_FULL_NAME test */
4782 constraints_insert_delimiter (context->constraints, i, BOOK_QUERY_SUB_OR);
4787 constraints_insert_field_test (
4788 context->constraints, j++,
4789 family_name, test->query,
4793 constraints_insert_field_test (
4794 context->constraints, j++,
4795 given_name, test->query,
4799 constraints_insert_field_test (
4800 context->constraints, j++,
4801 nickname, test->query,
4804 constraints_insert_delimiter (context->constraints, j, BOOK_QUERY_SUB_END);
4812 query_preflight (PreflightContext *context,
4816 EBSQL_NOTE (PREFLIGHT, g_printerr ("PREFLIGHT BEGIN\n"));
4817 query_preflight_initialize (context, sexp);
4819 if (context->status == PREFLIGHT_OK) {
4821 query_preflight_check (context, ebsql);
4823 /* No need to change the constraints if we're not
4824 * going to generate statements with it
4826 if (context->status == PREFLIGHT_OK) {
4829 g_printerr ("PREFLIGHT: Substituting full name\n"));
4831 /* Handle E_CONTACT_FULL_NAME substitutions */
4832 query_preflight_substitute_full_name (context, ebsql);
4835 EBSQL_NOTE (PREFLIGHT, g_printerr ("PREFLIGHT: Clearing context\n"));
4837 /* We might use this context to perform a fallback query,
4838 * so let's clear out all the constraints now
4840 preflight_context_clear (context);
4847 "PREFLIGHT END (status: %s)\n",
4848 EBSQL_STATUS_STR (context->status)));
4851 /**********************************************************
4852 * Field Test Generators *
4853 **********************************************************
4855 * This section contains the field test generators for
4856 * various EBookQueryTest types. When implementing new
4857 * query types, a new GenerateFieldTest needs to be created
4858 * and added to the table below.
4861 typedef void (* GenerateFieldTest) (EBookSqlite *ebsql,
4863 QueryFieldTest *test);
4865 /* This function escapes characters which need escaping
4866 * for LIKE statements as well as the single quotes.
4868 * The return value is not suitable to be formatted
4872 ebsql_normalize_for_like (EBookSqlite *ebsql,
4873 QueryFieldTest *test,
4874 gboolean reverse_string,
4875 gboolean *escape_needed)
4880 gboolean escape_modifier_needed = FALSE;
4881 const gchar *normal = NULL;
4883 const gchar *str_to_escape;
4884 gchar *reverse = NULL;
4885 gchar *freeme = NULL;
4887 if (test->field_id == E_CONTACT_UID ||
4888 test->field_id == E_CONTACT_REV) {
4889 normal = test->value;
4890 } else if (test->query >= E_BOOK_QUERY_TRANSLIT_CONTAINS &&
4891 test->query <= E_BOOK_QUERY_TRANSLIT_ENDS_WITH) {
4892 gchar *tmp = e_transliterator_transliterate (ebsql->priv->transliterator, test->value);
4893 freeme = e_util_utf8_normalize (tmp);
4898 freeme = e_util_utf8_normalize (test->value);
4902 if (reverse_string) {
4903 reverse = g_utf8_strreverse (normal, -1);
4904 str_to_escape = reverse;
4906 str_to_escape = normal;
4908 /* Just assume each character must be escaped. The result of this function
4909 * is discarded shortly after calling this function. Therefore it's
4910 * acceptable to possibly allocate twice the memory needed.
4912 len = strlen (str_to_escape);
4913 str = g_string_sized_new (2 * len + 4 + strlen (EBSQL_ESCAPE_SEQUENCE) - 1);
4915 ptr = str_to_escape;
4916 while ((c = *ptr++)) {
4918 g_string_append_c (str, '\'');
4919 } else if (c == '%' || c == '_' || c == '^') {
4920 g_string_append_c (str, '^');
4921 escape_modifier_needed = TRUE;
4924 g_string_append_c (str, c);
4928 *escape_needed = escape_modifier_needed;
4933 return g_string_free (str, FALSE);
4937 field_test_query_is (EBookSqlite *ebsql,
4939 QueryFieldTest *test)
4941 SummaryField *field = test->field;
4944 ebsql_string_append_column (string, field, NULL);
4946 if (test->field_id == E_CONTACT_UID ||
4947 test->field_id == E_CONTACT_REV) {
4948 /* UID & REV fields are not normalized in the summary */
4949 ebsql_string_append_printf (string, " = %Q", test->value);
4951 normal = e_util_utf8_normalize (test->value);
4952 ebsql_string_append_printf (string, " = %Q", normal);
4958 field_test_query_contains (EBookSqlite *ebsql,
4960 QueryFieldTest *test)
4962 SummaryField *field = test->field;
4963 gboolean need_escape;
4966 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
4968 g_string_append_c (string, '(');
4970 ebsql_string_append_column (string, field, NULL);
4971 g_string_append (string, " IS NOT NULL AND ");
4972 ebsql_string_append_column (string, field, NULL);
4973 g_string_append (string, " LIKE '%");
4974 g_string_append (string, escaped);
4975 g_string_append (string, "%'");
4978 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
4980 g_string_append_c (string, ')');
4986 field_test_query_begins_with (EBookSqlite *ebsql,
4988 QueryFieldTest *test)
4990 SummaryField *field = test->field;
4991 gboolean need_escape;
4994 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
4996 g_string_append_c (string, '(');
4997 ebsql_string_append_column (string, field, NULL);
4998 g_string_append (string, " IS NOT NULL AND ");
5000 ebsql_string_append_column (string, field, NULL);
5001 g_string_append (string, " LIKE \'");
5002 g_string_append (string, escaped);
5003 g_string_append (string, "%\'");
5006 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5007 g_string_append_c (string, ')');
5013 field_test_query_ends_with (EBookSqlite *ebsql,
5015 QueryFieldTest *test)
5017 SummaryField *field = test->field;
5018 gboolean need_escape;
5021 if ((field->index & INDEX_FLAG (SUFFIX)) != 0) {
5023 escaped = ebsql_normalize_for_like (ebsql, test, TRUE, &need_escape);
5025 g_string_append_c (string, '(');
5026 ebsql_string_append_column (string, field, EBSQL_SUFFIX_REVERSE);
5027 g_string_append (string, " IS NOT NULL AND ");
5029 ebsql_string_append_column (string, field, EBSQL_SUFFIX_REVERSE);
5030 g_string_append (string, " LIKE \'");
5031 g_string_append (string, escaped);
5032 g_string_append (string, "%\'");
5036 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
5037 g_string_append_c (string, '(');
5039 ebsql_string_append_column (string, field, NULL);
5040 g_string_append (string, " IS NOT NULL AND ");
5042 ebsql_string_append_column (string, field, NULL);
5043 g_string_append (string, " LIKE \'%");
5044 g_string_append (string, escaped);
5045 g_string_append (string, "\'");
5049 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5051 g_string_append_c (string, ')');
5056 field_test_query_eqphone (EBookSqlite *ebsql,
5058 QueryFieldTest *test)
5060 SummaryField *field = test->field;
5061 QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
5063 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
5065 g_string_append_c (string, '(');
5066 ebsql_string_append_column (string, field, EBSQL_SUFFIX_PHONE);
5067 ebsql_string_append_printf (string, " = %Q AND ", phone_test->national);
5069 /* For exact matches, a country code qualifier is required by both
5070 * query input and row input
5072 ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5073 g_string_append (string, " != 0 AND ");
5075 ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5076 ebsql_string_append_printf (string, " = %d", phone_test->country);
5077 g_string_append_c (string, ')');
5081 /* No indexed columns available, perform the fallback */
5082 g_string_append (string, EBSQL_FUNC_EQPHONE_EXACT " (");
5083 ebsql_string_append_column (string, field, NULL);
5084 ebsql_string_append_printf (string, ", %Q)", test->value);
5089 field_test_query_eqphone_national (EBookSqlite *ebsql,
5091 QueryFieldTest *test)
5094 SummaryField *field = test->field;
5095 QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
5097 if ((field->index & INDEX_FLAG (PHONE)) != 0) {
5099 /* Only a compound expression if there is a country code */
5100 if (phone_test->country)
5101 g_string_append_c (string, '(');
5103 /* Generate: phone = %Q */
5104 ebsql_string_append_column (string, field, EBSQL_SUFFIX_PHONE);
5105 ebsql_string_append_printf (string, " = %Q", phone_test->national);
5107 /* When doing a national search, no need to check country
5108 * code unless the query number also has a country code
5110 if (phone_test->country) {
5111 /* Generate: (phone = %Q AND (country = 0 OR country = %d)) */
5112 g_string_append (string, " AND (");
5113 ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5114 g_string_append (string, " = 0 OR ");
5115 ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5116 ebsql_string_append_printf (string, " = %d))", phone_test->country);
5122 /* No indexed columns available, perform the fallback */
5123 g_string_append (string, EBSQL_FUNC_EQPHONE_NATIONAL " (");
5124 ebsql_string_append_column (string, field, NULL);
5125 ebsql_string_append_printf (string, ", %Q)", test->value);
5130 field_test_query_eqphone_short (EBookSqlite *ebsql,
5132 QueryFieldTest *test)
5134 SummaryField *field = test->field;
5136 /* No quick way to do the short match */
5137 g_string_append (string, EBSQL_FUNC_EQPHONE_SHORT " (");
5138 ebsql_string_append_column (string, field, NULL);
5139 ebsql_string_append_printf (string, ", %Q)", test->value);
5143 field_test_query_regex_normal (EBookSqlite *ebsql,
5145 QueryFieldTest *test)
5147 SummaryField *field = test->field;
5150 normal = e_util_utf8_normalize (test->value);
5152 if (field->aux_table)
5153 ebsql_string_append_printf (
5154 string, "%s.value REGEXP %Q",
5155 field->aux_table_symbolic,
5158 ebsql_string_append_printf (
5159 string, "summary.%s REGEXP %Q",
5167 field_test_query_translit_is (EBookSqlite *ebsql,
5169 QueryFieldTest *test)
5171 SummaryField *field = test->field;
5172 gchar *normal, *translit;
5174 translit = e_transliterator_transliterate (ebsql->priv->transliterator, test->value);
5175 normal = e_util_utf8_normalize (translit);
5177 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5178 ebsql_string_append_printf (string, " = %Q", normal);
5185 field_test_query_translit_contains (EBookSqlite *ebsql,
5187 QueryFieldTest *test)
5189 SummaryField *field = test->field;
5190 gboolean need_escape;
5193 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
5195 g_string_append_c (string, '(');
5197 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5198 g_string_append (string, " IS NOT NULL AND ");
5199 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5200 g_string_append (string, " LIKE '%");
5201 g_string_append (string, escaped);
5202 g_string_append (string, "%'");
5205 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5207 g_string_append_c (string, ')');
5213 field_test_query_translit_begins_with (EBookSqlite *ebsql,
5215 QueryFieldTest *test)
5217 SummaryField *field = test->field;
5218 gboolean need_escape;
5221 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
5223 g_string_append_c (string, '(');
5224 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5225 g_string_append (string, " IS NOT NULL AND ");
5227 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5228 g_string_append (string, " LIKE \'");
5229 g_string_append (string, escaped);
5230 g_string_append (string, "%\'");
5233 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5234 g_string_append_c (string, ')');
5240 field_test_query_translit_ends_with (EBookSqlite *ebsql,
5242 QueryFieldTest *test)
5244 SummaryField *field = test->field;
5245 gboolean need_escape;
5248 escaped = ebsql_normalize_for_like (ebsql, test, FALSE, &need_escape);
5249 g_string_append_c (string, '(');
5251 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5252 g_string_append (string, " IS NOT NULL AND ");
5254 ebsql_string_append_column (string, field, EBSQL_SUFFIX_TRANSLIT);
5255 g_string_append (string, " LIKE \'%");
5256 g_string_append (string, escaped);
5257 g_string_append (string, "\'");
5260 g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5262 g_string_append_c (string, ')');
5267 field_test_query_exists (EBookSqlite *ebsql,
5269 QueryFieldTest *test)
5271 SummaryField *field = test->field;
5273 ebsql_string_append_column (string, field, NULL);
5274 ebsql_string_append_printf (string, " IS NOT NULL");
5277 /* Lookup table for field test generators per EBookQueryTest,
5279 * WARNING: This must stay in line with the EBookQueryTest definition.
5281 static const GenerateFieldTest field_test_func_table[] = {
5282 field_test_query_is, /* E_BOOK_QUERY_IS */
5283 field_test_query_contains, /* E_BOOK_QUERY_CONTAINS */
5284 field_test_query_begins_with, /* E_BOOK_QUERY_BEGINS_WITH */
5285 field_test_query_ends_with, /* E_BOOK_QUERY_ENDS_WITH */
5286 field_test_query_eqphone, /* E_BOOK_QUERY_EQUALS_PHONE_NUMBER */
5287 field_test_query_eqphone_national, /* E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER */
5288 field_test_query_eqphone_short, /* E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER */
5289 field_test_query_regex_normal, /* E_BOOK_QUERY_REGEX_NORMAL */
5290 NULL /* Requires fallback */, /* E_BOOK_QUERY_REGEX_RAW */
5291 field_test_query_translit_is, /* E_BOOK_QUERY_TRANSLIT_IS */
5292 field_test_query_translit_contains,/* E_BOOK_QUERY_TRANSLIT_CONTAINS */
5293 field_test_query_translit_begins_with,/* E_BOOK_QUERY_TRANSLIT_BEGINS_WITH */
5294 field_test_query_translit_ends_with,/* E_BOOK_QUERY_TRANSLIT_ENDS_WITH */
5295 field_test_query_exists, /* BOOK_QUERY_EXISTS */
5298 /**********************************************************
5299 * Querying Contacts *
5300 **********************************************************/
5302 /* The various search types indicate what should be fetched
5305 SEARCH_FULL, /* Get a list of EbSqlSearchData */
5306 SEARCH_UID_AND_REV, /* Get a list of EbSqlSearchData, with shallow vcards only containing UID & REV */
5307 SEARCH_UID, /* Get a list of UID strings */
5308 SEARCH_COUNT, /* Get the number of matching rows */
5312 ebsql_generate_constraints (EBookSqlite *ebsql,
5314 GPtrArray *constraints,
5317 SubQueryContext *ctx;
5318 QueryDelimiter *delim;
5319 QueryFieldTest *test;
5320 QueryElement **elements;
5323 /* If there are no constraints, we generate the fallback constraint for 'sexp' */
5324 if (constraints == NULL) {
5325 ebsql_string_append_printf (
5327 EBSQL_FUNC_COMPARE_VCARD " (%Q, %s)",
5328 sexp, EBSQL_VCARD_FRAGMENT (ebsql));
5332 elements = (QueryElement **) constraints->pdata;
5333 n_elements = constraints->len;
5335 ctx = sub_query_context_new ();
5337 for (i = 0; i < n_elements; i++) {
5338 GenerateFieldTest generate_test_func = NULL;
5340 /* Seperate field tests with the appropriate grouping */
5341 if (elements[i]->query != BOOK_QUERY_SUB_END &&
5342 sub_query_context_increment (ctx) > 0) {
5343 guint delim_type = sub_query_context_peek_type (ctx);
5345 switch (delim_type) {
5346 case BOOK_QUERY_SUB_AND:
5348 g_string_append (string, " AND ");
5351 case BOOK_QUERY_SUB_OR:
5353 g_string_append (string, " OR ");
5356 case BOOK_QUERY_SUB_NOT:
5358 /* Nothing to do between children of NOT,
5359 * there should only ever be one child of NOT anyway
5363 case BOOK_QUERY_SUB_END:
5365 g_warn_if_reached ();
5369 if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
5370 delim = (QueryDelimiter *) elements[i];
5372 switch (delim->query) {
5374 case BOOK_QUERY_SUB_NOT:
5376 /* NOT is a unary operator and as such
5377 * comes before the opening parenthesis
5379 g_string_append (string, "NOT ");
5383 case BOOK_QUERY_SUB_AND:
5384 case BOOK_QUERY_SUB_OR:
5386 /* Open a grouped statement and push the context */
5387 sub_query_context_push (ctx, delim->query);
5388 g_string_append_c (string, '(');
5391 case BOOK_QUERY_SUB_END:
5392 /* Close a grouped statement and pop the context */
5393 g_string_append_c (string, ')');
5394 sub_query_context_pop (ctx);
5397 g_warn_if_reached ();
5403 /* Find the appropriate field test generator */
5404 test = (QueryFieldTest *) elements[i];
5405 if (test->query < G_N_ELEMENTS (field_test_func_table))
5406 generate_test_func = field_test_func_table[test->query];
5408 /* These should never happen, if it does it should be
5409 * fixed in the preflight checks
5411 g_warn_if_fail (generate_test_func != NULL);
5412 g_warn_if_fail (test->field != NULL);
5414 /* Generate the field test */
5415 generate_test_func (ebsql, string, test);
5418 sub_query_context_free (ctx);
5421 /* Generates the SELECT portion of the query, this will take care of
5422 * preparing the context of the query, and add the needed JOIN statements
5423 * based on which fields are referenced in the query expression.
5425 * This also handles getting the correct callback and asking for the
5426 * right data depending on the 'search_type'
5429 ebsql_generate_select (EBookSqlite *ebsql,
5431 SearchType search_type,
5432 PreflightContext *context,
5435 EbSqlRowFunc callback = NULL;
5436 gboolean add_auxiliary_tables = FALSE;
5439 if (context->status == PREFLIGHT_OK &&
5440 context->aux_mask != 0)
5441 add_auxiliary_tables = TRUE;
5443 g_string_append (string, "SELECT ");
5444 if (add_auxiliary_tables)
5445 g_string_append (string, "DISTINCT ");
5447 switch (search_type) {
5449 callback = collect_full_results_cb;
5450 g_string_append (string, "summary.uid, ");
5451 g_string_append (string, EBSQL_VCARD_FRAGMENT (ebsql));
5452 g_string_append (string, ", summary.bdata ");
5454 case SEARCH_UID_AND_REV:
5455 callback = collect_lean_results_cb;
5456 g_string_append (string, "summary.uid, summary.Rev, summary.bdata ");
5459 callback = collect_uid_results_cb;
5460 g_string_append (string, "summary.uid ");
5463 callback = get_count_cb;
5464 if (context->aux_mask != 0)
5465 g_string_append (string, "count (DISTINCT summary.uid) ");
5467 g_string_append (string, "count (*) ");
5471 ebsql_string_append_printf (string, "FROM %Q AS summary", ebsql->priv->folderid);
5473 /* Add any required auxiliary tables into the query context */
5474 if (add_auxiliary_tables) {
5475 for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
5477 /* We cap this at EBSQL_MAX_SUMMARY_FIELDS (64 bits) at creation time */
5478 if ((context->aux_mask & (1 << i)) != 0) {
5479 SummaryField *field = &(ebsql->priv->summary_fields[i]);
5481 /* Note the '+' in the JOIN statement.
5483 * This plus makes the uid's index ineligable to participate
5486 * Without this, the indexes which we prefer for prefix or
5487 * suffix matching in the auxiliary tables are ignored and
5488 * only considered on exact matches.
5490 * This is crucial to ensure that the uid index does not
5491 * compete with the value index in constraints such as:
5493 * WHERE email_list.value LIKE "boogieman%"
5495 ebsql_string_append_printf (
5496 string, " JOIN %Q AS %s ON +%s.uid = summary.uid",
5498 field->aux_table_symbolic,
5499 field->aux_table_symbolic);
5508 ebsql_do_search_query (EBookSqlite *ebsql,
5509 PreflightContext *context,
5511 SearchType search_type,
5512 GSList **return_data,
5513 GCancellable *cancellable,
5517 EbSqlRowFunc callback = NULL;
5518 gboolean success = FALSE;
5520 /* We might calculate a reasonable estimation of bytes
5521 * during the preflight checks */
5522 string = g_string_sized_new (GENERATED_QUERY_BYTES);
5524 /* Generate the leading SELECT statement */
5525 callback = ebsql_generate_select (
5526 ebsql, string, search_type, context, error);
5529 EBSQL_STATUS_GEN_CONSTRAINTS (context->status)) {
5531 * Now generate the search expression on the main contacts table
5533 g_string_append (string, " WHERE ");
5534 ebsql_generate_constraints (
5535 ebsql, string, context->constraints, sexp);
5539 success = ebsql_exec (
5541 callback, return_data,
5542 cancellable, error);
5544 g_string_free (string, TRUE);
5549 /* ebsql_search_query:
5550 * @ebsql: An EBookSqlite
5551 * @sexp: The search expression, or NULL for all contacts
5552 * @search_type: Indicates what kind of data should be returned
5553 * @return_data: A list of data fetched from the DB, as specified by 'search_type'
5554 * @error: Location to store any error which may have occurred
5556 * This is the main common entry point for querying contacts.
5558 * If the query cannot be satisfied with the summary, then
5559 * a fallback will automatically be used.
5562 ebsql_search_query (EBookSqlite *ebsql,
5564 SearchType search_type,
5565 GSList **return_data,
5566 GCancellable *cancellable,
5569 PreflightContext context = PREFLIGHT_CONTEXT_INIT;
5570 gboolean success = FALSE;
5572 /* Now start with the query preflighting */
5573 query_preflight (&context, ebsql, sexp);
5575 switch (context.status) {
5577 case PREFLIGHT_LIST_ALL:
5578 case PREFLIGHT_NOT_SUMMARIZED:
5579 /* No errors, let's really search */
5580 success = ebsql_do_search_query (
5581 ebsql, &context, sexp,
5582 search_type, return_data,
5583 cancellable, error);
5586 case PREFLIGHT_INVALID:
5589 E_BOOK_SQLITE_ERROR_INVALID_QUERY,
5590 _("Invalid query: %s"), sexp);
5593 case PREFLIGHT_UNSUPPORTED:
5594 EBSQL_SET_ERROR_LITERAL (
5596 E_BOOK_SQLITE_ERROR_UNSUPPORTED_QUERY,
5597 _("Query contained unsupported elements"));
5601 preflight_context_clear (&context);
5606 /******************************************************************
5607 * EbSqlCursor Implementation *
5608 ******************************************************************/
5609 typedef struct _CursorState CursorState;
5611 struct _CursorState {
5612 gchar **values; /* The current cursor position, results will be returned after this position */
5613 gchar *last_uid; /* The current cursor contact UID position, used as a tie breaker */
5614 EbSqlCursorOrigin position; /* The position is updated with the cursor state and is used to distinguish
5615 * between the beginning and the ending of the cursor's contact list.
5616 * While the cursor is in a non-null state, the position will be
5617 * EBSQL_CURSOR_ORIGIN_CURRENT.
5621 struct _EbSqlCursor {
5622 EBookBackendSExp *sexp; /* An EBookBackendSExp based on the query, used by e_book_sqlite_cursor_compare () */
5623 gchar *select_vcards; /* The first fragment when querying results */
5624 gchar *select_count; /* The first fragment when querying contact counts */
5625 gchar *query; /* The SQL query expression derived from the passed search expression */
5626 gchar *order; /* The normal order SQL query fragment to append at the end, containing ORDER BY etc */
5627 gchar *reverse_order; /* The reverse order SQL query fragment to append at the end, containing ORDER BY etc */
5629 EContactField *sort_fields; /* The fields to sort in a query in the order or sort priority */
5630 EBookCursorSortType *sort_types; /* The sort method to use for each field */
5631 gint n_sort_fields; /* The amound of sort fields */
5636 static CursorState *cursor_state_copy (EbSqlCursor *cursor,
5637 CursorState *state);
5638 static void cursor_state_free (EbSqlCursor *cursor,
5639 CursorState *state);
5640 static void cursor_state_clear (EbSqlCursor *cursor,
5642 EbSqlCursorOrigin position);
5643 static void cursor_state_set_from_contact (EBookSqlite *ebsql,
5644 EbSqlCursor *cursor,
5647 static void cursor_state_set_from_vcard (EBookSqlite *ebsql,
5648 EbSqlCursor *cursor,
5650 const gchar *vcard);
5652 static CursorState *
5653 cursor_state_copy (EbSqlCursor *cursor,
5659 copy = g_slice_new0 (CursorState);
5660 copy->values = g_new0 (gchar *, cursor->n_sort_fields);
5662 for (i = 0; i < cursor->n_sort_fields; i++)
5663 copy->values[i] = g_strdup (state->values[i]);
5665 copy->last_uid = g_strdup (state->last_uid);
5666 copy->position = state->position;
5672 cursor_state_free (EbSqlCursor *cursor,
5676 cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
5677 g_free (state->values);
5678 g_slice_free (CursorState, state);
5683 cursor_state_clear (EbSqlCursor *cursor,
5685 EbSqlCursorOrigin position)
5689 for (i = 0; i < cursor->n_sort_fields; i++) {
5690 g_free (state->values[i]);
5691 state->values[i] = NULL;
5694 g_free (state->last_uid);
5695 state->last_uid = NULL;
5696 state->position = position;
5700 cursor_state_set_from_contact (EBookSqlite *ebsql,
5701 EbSqlCursor *cursor,
5707 cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
5709 for (i = 0; i < cursor->n_sort_fields; i++) {
5710 const gchar *string = e_contact_get_const (contact, cursor->sort_fields[i]);
5711 SummaryField *field;
5715 sort_key = e_collator_generate_key (
5716 ebsql->priv->collator,
5719 sort_key = g_strdup ("");
5721 field = summary_field_get (ebsql, cursor->sort_fields[i]);
5723 if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
5724 state->values[i] = sort_key;
5726 state->values[i] = ebsql_encode_vcard_sort_key (sort_key);
5731 state->last_uid = e_contact_get (contact, E_CONTACT_UID);
5732 state->position = EBSQL_CURSOR_ORIGIN_CURRENT;
5736 cursor_state_set_from_vcard (EBookSqlite *ebsql,
5737 EbSqlCursor *cursor,
5743 contact = e_contact_new_from_vcard (vcard);
5744 cursor_state_set_from_contact (ebsql, cursor, state, contact);
5745 g_object_unref (contact);
5749 ebsql_cursor_setup_query (EBookSqlite *ebsql,
5750 EbSqlCursor *cursor,
5754 PreflightContext context = PREFLIGHT_CONTEXT_INIT;
5757 /* Preflighting and error checking */
5759 query_preflight (&context, ebsql, sexp);
5761 if (context.status > PREFLIGHT_NOT_SUMMARIZED) {
5762 EBSQL_SET_ERROR_LITERAL (
5764 E_BOOK_SQLITE_ERROR_INVALID_QUERY,
5765 _("Invalid query for EbSqlCursor"));
5767 preflight_context_clear (&context);
5773 /* Now we caught the errors, let's generate our queries and get out of here ... */
5774 g_free (cursor->select_vcards);
5775 g_free (cursor->select_count);
5776 g_free (cursor->query);
5777 g_clear_object (&(cursor->sexp));
5779 /* Generate the leading SELECT portions that we need */
5780 string = g_string_new ("");
5781 ebsql_generate_select (ebsql, string, SEARCH_FULL, &context, NULL);
5782 cursor->select_vcards = g_string_free (string, FALSE);
5784 string = g_string_new ("");
5785 ebsql_generate_select (ebsql, string, SEARCH_COUNT, &context, NULL);
5786 cursor->select_count = g_string_free (string, FALSE);
5788 if (sexp == NULL || context.status == PREFLIGHT_LIST_ALL) {
5789 cursor->query = NULL;
5790 cursor->sexp = NULL;
5792 /* Generate the constraints for our queries
5794 string = g_string_new (NULL);
5795 ebsql_generate_constraints (
5796 ebsql, string, context.constraints, sexp);
5797 cursor->query = g_string_free (string, FALSE);
5798 cursor->sexp = e_book_backend_sexp_new (sexp);
5801 preflight_context_clear (&context);
5807 ebsql_cursor_order_by_fragment (EBookSqlite *ebsql,
5808 const EContactField *sort_fields,
5809 const EBookCursorSortType *sort_types,
5810 guint n_sort_fields,
5816 string = g_string_new ("ORDER BY ");
5818 for (i = 0; i < n_sort_fields; i++) {
5819 SummaryField *field = summary_field_get (ebsql, sort_fields[i]);
5822 g_string_append (string, ", ");
5825 (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
5826 g_string_append (string, "summary.");
5827 g_string_append (string, field->dbname);
5828 g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY " ");
5830 g_string_append (string, EBSQL_VCARD_FRAGMENT (ebsql));
5831 g_string_append (string, " COLLATE ");
5832 g_string_append (string, EBSQL_COLLATE_PREFIX);
5833 g_string_append (string, e_contact_field_name (sort_fields[i]));
5834 g_string_append_c (string, ' ');
5838 g_string_append (string, (sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ? "DESC" : "ASC"));
5840 g_string_append (string, (sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ? "ASC" : "DESC"));
5843 /* Also order the UID, since it's our tie breaker */
5844 if (n_sort_fields > 0)
5845 g_string_append (string, ", ");
5847 g_string_append (string, "summary.uid ");
5848 g_string_append (string, reverse ? "DESC" : "ASC");
5850 return g_string_free (string, FALSE);
5853 static EbSqlCursor *
5854 ebsql_cursor_new (EBookSqlite *ebsql,
5856 const EContactField *sort_fields,
5857 const EBookCursorSortType *sort_types,
5858 guint n_sort_fields)
5860 EbSqlCursor *cursor = g_slice_new0 (EbSqlCursor);
5862 cursor->order = ebsql_cursor_order_by_fragment (
5863 ebsql, sort_fields, sort_types, n_sort_fields, FALSE);
5864 cursor->reverse_order = ebsql_cursor_order_by_fragment (
5865 ebsql, sort_fields, sort_types, n_sort_fields, TRUE);
5867 /* Sort parameters */
5868 cursor->n_sort_fields = n_sort_fields;
5869 cursor->sort_fields = g_memdup (sort_fields, sizeof (EContactField) * n_sort_fields);
5870 cursor->sort_types = g_memdup (sort_types, sizeof (EBookCursorSortType) * n_sort_fields);
5873 cursor->state.values = g_new0 (gchar *, n_sort_fields);
5874 cursor->state.last_uid = NULL;
5875 cursor->state.position = EBSQL_CURSOR_ORIGIN_BEGIN;
5881 ebsql_cursor_free (EbSqlCursor *cursor)
5884 cursor_state_clear (cursor, &(cursor->state), EBSQL_CURSOR_ORIGIN_BEGIN);
5885 g_free (cursor->state.values);
5887 g_clear_object (&(cursor->sexp));
5888 g_free (cursor->select_vcards);
5889 g_free (cursor->select_count);
5890 g_free (cursor->query);
5891 g_free (cursor->order);
5892 g_free (cursor->reverse_order);
5893 g_free (cursor->sort_fields);
5894 g_free (cursor->sort_types);
5896 g_slice_free (EbSqlCursor, cursor);
5900 #define GREATER_OR_LESS(cursor, idx, reverse) \
5902 (((EbSqlCursor *) cursor)->sort_types[idx] == E_BOOK_CURSOR_SORT_ASCENDING ? '<' : '>') : \
5903 (((EbSqlCursor *) cursor)->sort_types[idx] == E_BOOK_CURSOR_SORT_ASCENDING ? '>' : '<'))
5906 ebsql_cursor_format_equality (EBookSqlite *ebsql,
5908 EContactField field_id,
5912 SummaryField *field = summary_field_get (ebsql, field_id);
5915 (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
5917 g_string_append (string, "summary.");
5918 g_string_append (string, field->dbname);
5919 g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY " ");
5921 ebsql_string_append_printf (string, "%c %Q", equality, value);
5924 ebsql_string_append_printf (
5925 string, "(%s %c %Q ",
5926 EBSQL_VCARD_FRAGMENT (ebsql),
5929 g_string_append (string, "COLLATE " EBSQL_COLLATE_PREFIX);
5930 g_string_append (string, e_contact_field_name (field_id));
5931 g_string_append_c (string, ')');
5936 ebsql_cursor_constraints (EBookSqlite *ebsql,
5937 EbSqlCursor *cursor,
5940 gboolean include_current_uid)
5946 * ORDER BY family_name ASC, given_name DESC
5948 * Where current cursor values are:
5949 * family_name = Jackson
5950 * given_name = Micheal
5952 * With reverse = FALSE
5954 * (summary.family_name > 'Jackson') OR
5955 * (summary.family_name = 'Jackson' AND summary.given_name < 'Micheal') OR
5956 * (summary.family_name = 'Jackson' AND summary.given_name = 'Micheal' AND summary.uid > 'last-uid')
5958 * With reverse = TRUE (needed for moving the cursor backwards through results)
5960 * (summary.family_name < 'Jackson') OR
5961 * (summary.family_name = 'Jackson' AND summary.given_name > 'Micheal') OR
5962 * (summary.family_name = 'Jackson' AND summary.given_name = 'Micheal' AND summary.uid < 'last-uid')
5965 string = g_string_new (NULL);
5967 for (i = 0; i <= cursor->n_sort_fields; i++) {
5969 /* Break once we hit a NULL value */
5970 if ((i < cursor->n_sort_fields && state->values[i] == NULL) ||
5971 (i == cursor->n_sort_fields && state->last_uid == NULL))
5974 /* Between each qualifier, add an 'OR' */
5976 g_string_append (string, " OR ");
5978 /* Begin qualifier */
5979 g_string_append_c (string, '(');
5981 /* Create the '=' statements leading up to the current tie breaker */
5982 for (j = 0; j < i; j++) {
5983 ebsql_cursor_format_equality (ebsql, string,
5984 cursor->sort_fields[j],
5985 state->values[j], '=');
5986 g_string_append (string, " AND ");
5989 if (i == cursor->n_sort_fields) {
5991 /* The 'include_current_uid' clause is used for calculating
5992 * the current position of the cursor, inclusive of the
5995 if (include_current_uid)
5996 g_string_append_c (string, '(');
5998 /* Append the UID tie breaker */
5999 ebsql_string_append_printf (
6001 "summary.uid %c %Q",
6002 reverse ? '<' : '>',
6005 if (include_current_uid)
6006 ebsql_string_append_printf (
6008 " OR summary.uid = %Q)",
6013 /* SPECIAL CASE: If we have a parially set cursor state, then we must
6014 * report next results that are inclusive of the final qualifier.
6016 * This allows one to set the cursor with the family name set to 'J'
6017 * and include the results for contact's Mr & Miss 'J'.
6019 gboolean include_exact_match =
6020 (reverse == FALSE &&
6021 ((i + 1 < cursor->n_sort_fields && state->values[i + 1] == NULL) ||
6022 (i + 1 == cursor->n_sort_fields && state->last_uid == NULL)));
6024 if (include_exact_match)
6025 g_string_append_c (string, '(');
6027 /* Append the final qualifier for this field */
6028 ebsql_cursor_format_equality (ebsql, string,
6029 cursor->sort_fields[i],
6031 GREATER_OR_LESS (cursor, i, reverse));
6033 if (include_exact_match) {
6034 g_string_append (string, " OR ");
6035 ebsql_cursor_format_equality (ebsql, string,
6036 cursor->sort_fields[i],
6037 state->values[i], '=');
6038 g_string_append_c (string, ')');
6043 g_string_append_c (string, ')');
6046 return g_string_free (string, FALSE);
6050 cursor_count_total_locked (EBookSqlite *ebsql,
6051 EbSqlCursor *cursor,
6058 query = g_string_new (cursor->select_count);
6060 /* Add the filter constraints (if any) */
6061 if (cursor->query) {
6062 g_string_append (query, " WHERE ");
6064 g_string_append_c (query, '(');
6065 g_string_append (query, cursor->query);
6066 g_string_append_c (query, ')');
6069 /* Execute the query */
6070 success = ebsql_exec (ebsql, query->str, get_count_cb, total, NULL, error);
6072 g_string_free (query, TRUE);
6078 cursor_count_position_locked (EBookSqlite *ebsql,
6079 EbSqlCursor *cursor,
6086 query = g_string_new (cursor->select_count);
6088 /* Add the filter constraints (if any) */
6089 if (cursor->query) {
6090 g_string_append (query, " WHERE ");
6092 g_string_append_c (query, '(');
6093 g_string_append (query, cursor->query);
6094 g_string_append_c (query, ')');
6097 /* Add the cursor constraints (if any) */
6098 if (cursor->state.values[0] != NULL) {
6099 gchar *constraints = NULL;
6102 g_string_append (query, " WHERE ");
6104 g_string_append (query, " AND ");
6106 /* Here we do a reverse query, we're looking for all the
6107 * results leading up to the current cursor value, including
6110 constraints = ebsql_cursor_constraints (
6111 ebsql, cursor, &(cursor->state), TRUE, TRUE);
6113 g_string_append_c (query, '(');
6114 g_string_append (query, constraints);
6115 g_string_append_c (query, ')');
6117 g_free (constraints);
6120 /* Execute the query */
6121 success = ebsql_exec (ebsql, query->str, get_count_cb, position, NULL, error);
6123 g_string_free (query, TRUE);
6128 /**********************************************************
6130 **********************************************************/
6132 e_book_sqlite_dispose (GObject *object)
6134 EBookSqlite *ebsql = E_BOOK_SQLITE (object);
6136 ebsql_unregister_from_hash (ebsql);
6138 /* Chain up to parent's dispose() method. */
6139 G_OBJECT_CLASS (e_book_sqlite_parent_class)->dispose (object);
6143 e_book_sqlite_finalize (GObject *object)
6145 EBookSqlite *ebsql = E_BOOK_SQLITE (object);
6146 EBookSqlitePrivate *priv = ebsql->priv;
6148 summary_fields_array_free (
6149 priv->summary_fields,
6150 priv->n_summary_fields);
6152 g_free (priv->folderid);
6153 g_free (priv->path);
6154 g_free (priv->locale);
6155 g_free (priv->region_code);
6158 e_collator_unref (priv->collator);
6160 if (ebsql->priv->transliterator)
6161 e_transliterator_unref (ebsql->priv->transliterator);
6163 g_clear_object (&priv->source);
6165 g_mutex_clear (&priv->lock);
6166 g_mutex_clear (&priv->updates_lock);
6168 if (priv->multi_deletes)
6169 g_hash_table_destroy (priv->multi_deletes);
6171 if (priv->multi_inserts)
6172 g_hash_table_destroy (priv->multi_inserts);
6174 if (priv->user_data && priv->user_data_destroy)
6175 priv->user_data_destroy (priv->user_data);
6177 sqlite3_finalize (priv->insert_stmt);
6178 sqlite3_finalize (priv->replace_stmt);
6179 sqlite3_close (priv->db);
6181 EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite finalized\n"));
6183 /* Chain up to parent's finalize() method. */
6184 G_OBJECT_CLASS (e_book_sqlite_parent_class)->finalize (object);
6188 e_book_sqlite_constructed (GObject *object)
6190 /* Chain up to parent's constructed() method. */
6191 G_OBJECT_CLASS (e_book_sqlite_parent_class)->constructed (object);
6193 e_extensible_load_extensions (E_EXTENSIBLE (object));
6197 ebsql_signals_accumulator (GSignalInvocationHint *ihint,
6198 GValue *return_accu,
6199 const GValue *handler_return,
6202 gboolean handler_result;
6204 handler_result = g_value_get_boolean (handler_return);
6205 g_value_set_boolean (return_accu, handler_result);
6207 return handler_result;
6211 ebsql_before_insert_contact_default (EBookSqlite *ebsql,
6216 GCancellable *cancellable,
6223 ebsql_before_remove_contact_default (EBookSqlite *ebsql,
6225 const gchar *contact_uid,
6226 GCancellable *cancellable,
6233 e_book_sqlite_class_init (EBookSqliteClass *class)
6235 GObjectClass *object_class;
6237 g_type_class_add_private (class, sizeof (EBookSqlitePrivate));
6239 object_class = G_OBJECT_CLASS (class);
6240 object_class->dispose = e_book_sqlite_dispose;
6241 object_class->finalize = e_book_sqlite_finalize;
6242 object_class->constructed = e_book_sqlite_constructed;
6244 class->before_insert_contact = ebsql_before_insert_contact_default;
6245 class->before_remove_contact = ebsql_before_remove_contact_default;
6247 /* Parse the EBSQL_DEBUG environment variable */
6248 ebsql_init_debug ();
6250 signals[BEFORE_INSERT_CONTACT] = g_signal_new (
6251 "before-insert-contact",
6252 G_OBJECT_CLASS_TYPE (class),
6254 G_STRUCT_OFFSET (EBookSqliteClass, before_insert_contact),
6255 ebsql_signals_accumulator,
6257 g_cclosure_marshal_generic,
6266 signals[BEFORE_REMOVE_CONTACT] = g_signal_new (
6267 "before-remove-contact",
6268 G_OBJECT_CLASS_TYPE (class),
6270 G_STRUCT_OFFSET (EBookSqliteClass, before_remove_contact),
6271 ebsql_signals_accumulator,
6273 g_cclosure_marshal_generic,
6282 e_book_sqlite_init (EBookSqlite *ebsql)
6284 ebsql->priv = E_BOOK_SQLITE_GET_PRIVATE (ebsql);
6286 g_mutex_init (&ebsql->priv->lock);
6287 g_mutex_init (&ebsql->priv->updates_lock);
6289 ebsql->priv->transliterator = e_transliterator_new ("Any-Latin");
6292 /**********************************************************
6294 **********************************************************/
6295 static EBookSqlite *
6296 ebsql_new_default (const gchar *path,
6298 EbSqlVCardCallback vcard_callback,
6299 EbSqlChangeCallback change_callback,
6301 GDestroyNotify user_data_destroy,
6302 GCancellable *cancellable,
6306 GArray *summary_fields;
6309 /* Create the default summary structs */
6310 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
6311 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
6312 summary_field_append (summary_fields, DEFAULT_FOLDER_ID, default_summary_fields[i], NULL);
6314 /* Add the default index flags */
6315 summary_fields_add_indexes (
6317 default_indexed_fields,
6318 default_index_types,
6319 G_N_ELEMENTS (default_indexed_fields));
6321 ebsql = ebsql_new_internal (
6323 vcard_callback, change_callback,
6324 user_data, user_data_destroy,
6325 (SummaryField *) summary_fields->data,
6326 summary_fields->len,
6327 cancellable, error);
6329 g_array_free (summary_fields, FALSE);
6335 * e_book_sqlite_new:
6336 * @path: location to load or create the new database
6337 * @cancellable: (allow-none): A #GCancellable
6338 * @error: (allow-none): A location to store any error that may have occurred.
6340 * Creates a new #EBookSqlite with the default summary configuration.
6342 * Aside from the manditory fields %E_CONTACT_UID, %E_CONTACT_REV,
6343 * the default configuration stores the following fields for quick
6344 * performance of searches: %E_CONTACT_FILE_AS, %E_CONTACT_NICKNAME,
6345 * %E_CONTACT_FULL_NAME, %E_CONTACT_GIVEN_NAME, %E_CONTACT_FAMILY_NAME,
6346 * %E_CONTACT_EMAIL, %E_CONTACT_TEL, %E_CONTACT_IS_LIST, %E_CONTACT_LIST_SHOW_ADDRESSES,
6347 * and %E_CONTACT_WANTS_HTML.
6349 * The fields %E_CONTACT_FULL_NAME and %E_CONTACT_EMAIL are configured
6350 * to respond extra quickly with the %E_BOOK_INDEX_PREFIX index flag.
6352 * The fields %E_CONTACT_FILE_AS, %E_CONTACT_FAMILY_NAME and
6353 * %E_CONTACT_GIVEN_NAME are configured to perform well with
6354 * the #EbSqlCursor interface, using the %E_BOOK_INDEX_SORT_KEY
6357 * Returns: (transfer full): A reference to a #EBookSqlite
6362 e_book_sqlite_new (const gchar *path,
6364 GCancellable *cancellable,
6367 g_return_val_if_fail (path && path[0], NULL);
6369 return ebsql_new_default (path, source, NULL, NULL, NULL, NULL, cancellable, error);
6373 * e_book_sqlite_new_full:
6374 * @path: location to load or create the new database
6375 * @setup: (allow-none): an #ESourceBackendSummarySetup describing how the summary should be setup, or %NULL to use the default
6376 * @vcard_callback: (allow-none) (scope async) (closure user_data): A function to resolve vcards
6377 * @change_callback: (allow-none) (scope async) (closure user_data): A function to catch notifications of vcard changes
6378 * @user_data: (allow-none): callback user data
6379 * @user_data_destroy: (allow-none): A function to free @user_data automatically when the created #EBookSqlite is destroyed.
6380 * @cancellable: (allow-none): A #GCancellable
6381 * @error: (allow-none): A location to store any error that may have occurred.
6383 * Opens or creates a new addressbook at @path.
6385 * Like e_book_sqlite_new(), but allows configuration of which contact fields
6386 * will be stored for quick reference in the summary. The configuration indicated by
6387 * @setup will only be taken into account when initially creating the underlying table,
6388 * further configurations will be ignored.
6390 * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
6391 * they will be stored in the summary regardless of this function's parameters.
6392 * Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
6393 * #E_TYPE_CONTACT_ATTR_LIST are currently supported.
6395 * If @vcard_callback is specified, then vcards will not be stored by functions
6396 * such as e_book_sqlitedb_add_contact(). Instead @vcard_callback will be invoked
6397 * at any time the created #EBookSqlite requires a vcard, either as a fallback
6398 * for querying search expressions which cannot be satisfied with the summary
6399 * fields, or when reporting results from searches.
6401 * If any error occurs and %NULL is returned, then the passed @user_data will
6402 * be automatically freed using the @user_data_destroy function, if specified.
6404 * It is recommended to store all contact vcards in the #EBookSqlite addressbook
6405 * if at all possible, however in some cases the vcards must be stored in some
6408 * Returns: (transfer full): The newly created #EBookSqlite, or %NULL if opening or creating the addressbook failed.
6413 e_book_sqlite_new_full (const gchar *path,
6415 ESourceBackendSummarySetup *setup,
6416 EbSqlVCardCallback vcard_callback,
6417 EbSqlChangeCallback change_callback,
6419 GDestroyNotify user_data_destroy,
6420 GCancellable *cancellable,
6423 EBookSqlite *ebsql = NULL;
6424 EContactField *fields;
6425 EContactField *indexed_fields;
6426 EBookIndexType *index_types = NULL;
6427 gboolean had_error = FALSE;
6428 GArray *summary_fields;
6429 gint n_fields = 0, n_indexed_fields = 0, i;
6431 g_return_val_if_fail (path && path[0], NULL);
6432 g_return_val_if_fail (setup == NULL || E_IS_SOURCE_BACKEND_SUMMARY_SETUP (setup), NULL);
6435 return ebsql_new_default (
6442 cancellable, error);
6444 fields = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
6445 indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
6447 /* No specified summary fields indicates the default summary configuration should be used */
6448 if (n_fields <= 0 || n_fields >= EBSQL_MAX_SUMMARY_FIELDS) {
6452 "EBookSqlite refused to create addressbook with over %d summary fields",
6453 EBSQL_MAX_SUMMARY_FIELDS);
6455 ebsql = ebsql_new_default (
6462 cancellable, error);
6464 g_free (index_types);
6465 g_free (indexed_fields);
6470 summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
6472 /* Ensure the non-optional fields first */
6473 summary_field_append (summary_fields, DEFAULT_FOLDER_ID, E_CONTACT_UID, error);
6474 summary_field_append (summary_fields, DEFAULT_FOLDER_ID, E_CONTACT_REV, error);
6476 for (i = 0; i < n_fields; i++) {
6477 if (!summary_field_append (summary_fields, DEFAULT_FOLDER_ID, fields[i], error)) {
6485 SummaryField *sfields;
6487 /* Properly free the array */
6488 n_sfields = summary_fields->len;
6489 sfields = (SummaryField *) g_array_free (summary_fields, FALSE);
6490 summary_fields_array_free (sfields, n_sfields);
6493 g_free (index_types);
6494 g_free (indexed_fields);
6496 if (user_data && user_data_destroy)
6497 user_data_destroy (user_data);
6502 /* Add the 'indexed' flag to the SummaryField structs */
6503 summary_fields_add_indexes (
6504 summary_fields, indexed_fields, index_types, n_indexed_fields);
6506 ebsql = ebsql_new_internal (
6508 vcard_callback, change_callback,
6509 user_data, user_data_destroy,
6510 (SummaryField *) summary_fields->data,
6511 summary_fields->len,
6512 cancellable, error);
6515 g_free (index_types);
6516 g_free (indexed_fields);
6517 g_array_free (summary_fields, FALSE);
6523 * e_book_sqlite_lock:
6524 * @ebsql: An #EBookSqlite
6525 * @lock_type: The #EbSqlLockType to acquire
6526 * @cancellable: (allow-none): A #GCancellable
6527 * @error: (allow-none): A location to store any error that may have occurred.
6529 * Obtains an exclusive lock on @ebsql and starts a transaction.
6531 * This should be called if you need to access @ebsql multiple times while
6532 * ensuring an atomic transaction. End this transaction with e_book_sqlite_unlock().
6534 * If @cancellable is specified, then @ebsql will retain a reference to it until
6535 * e_book_sqlite_unlock() is called. Any accesses to @ebsql with the lock held
6536 * are expected to have the same @cancellable specified, or %NULL.
6538 * <note><para>Aside from ensuring atomicity of transactions, this function will hold a mutex
6539 * which will cause further calls to e_book_sqlite_lock() to block. If you are accessing
6540 * @ebsql from multiple threads, then any interactions with @ebsql should be nested in calls
6541 * to e_book_sqlite_lock() and e_book_sqlite_unlock().</para></note>
6543 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6548 e_book_sqlite_lock (EBookSqlite *ebsql,
6549 EbSqlLockType lock_type,
6550 GCancellable *cancellable,
6555 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6557 EBSQL_LOCK_MUTEX (&ebsql->priv->updates_lock);
6559 /* Here, after obtaining the outer facing transaction lock, we need
6560 * to assert that there is no cancellable already set */
6561 if (ebsql->priv->cancel != NULL) {
6562 /* This should never happen, if it does it's a bug
6563 * in this code, not the calling code
6565 g_warn_if_reached ();
6566 EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6570 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6572 /* Here, after obtaining the regular lock, we need to assert that we are
6573 * the toplevel transaction */
6574 if (ebsql->priv->in_transaction != 0) {
6575 g_warn_if_reached ();
6576 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6577 EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6581 success = ebsql_start_transaction (ebsql, lock_type, cancellable, error);
6582 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6584 /* If we failed to start the transaction, we don't hold the lock */
6586 EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6592 * e_book_sqlite_unlock:
6593 * @ebsql: An #EBookSqlite
6594 * @action: Which #EbSqlUnlockAction to take while unlocking
6595 * @error: (allow-none): A location to store any error that may have occurred.
6597 * Releases an exclusive on @ebsql and finishes a transaction previously
6598 * started with e_book_sqlite_lock_updates().
6600 * <note><para>If this fails, the lock on @ebsql is still released and @error will
6601 * be set to indicate why the transaction or rollback failed.</para></note>
6603 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6608 e_book_sqlite_unlock (EBookSqlite *ebsql,
6609 EbSqlUnlockAction action,
6612 gboolean success = FALSE;
6614 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6616 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6619 case EBSQL_UNLOCK_NONE:
6620 case EBSQL_UNLOCK_COMMIT:
6621 success = ebsql_commit_transaction (ebsql, error);
6623 case EBSQL_UNLOCK_ROLLBACK:
6624 success = ebsql_rollback_transaction (ebsql, error);
6628 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6630 EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6636 * e_book_sqlite_ref_collator:
6637 * @ebsql: An #EBookSqlite
6639 * References the currently active #ECollator for @ebsql,
6640 * use e_collator_unref() when finished using the returned collator.
6642 * Note that the active collator will change with the active locale setting.
6644 * Returns: (transfer full): A reference to the active collator.
6649 e_book_sqlite_ref_collator (EBookSqlite *ebsql)
6651 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
6653 return e_collator_ref (ebsql->priv->collator);
6657 * e_book_sqlite_ref_source:
6658 * @ebsql: An #EBookSqlite
6660 * References the #ESource to which @ebsql is paired,
6661 * use g_object_unref() when finished using the source.
6662 * It can be %NULL in some cases, like when running tests.
6664 * Returns: (transfer-full): A reference to the #ESource to which @ebsql
6665 * is paired, or %NULL.
6670 e_book_sqlite_ref_source (EBookSqlite *ebsql)
6672 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
6674 if (!ebsql->priv->source)
6677 return g_object_ref (ebsql->priv->source);
6681 * e_book_sqlitedb_add_contact:
6682 * @ebsql: An #EBookSqlite
6683 * @contact: EContact to be added
6684 * @extra: Extra data to store in association with this contact
6685 * @replace: Whether this contact should replace another contact with the same UID.
6686 * @cancellable: (allow-none): A #GCancellable
6687 * @error: (allow-none): A location to store any error that may have occurred.
6689 * This is a convenience wrapper for e_book_sqlite_add_contacts(),
6690 * which is the preferred means to add or modify multiple contacts when possible.
6692 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6697 e_book_sqlite_add_contact (EBookSqlite *ebsql,
6701 GCancellable *cancellable,
6707 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6708 g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
6713 el.data = (gpointer) extra;
6716 return e_book_sqlite_add_contacts (ebsql, &l, &el, replace, cancellable, error);
6720 * e_book_sqlite_new_contacts:
6721 * @ebsql: An #EBookSqlite
6722 * @contacts: (element-type EContact): A list of contacts to add to @ebsql
6723 * @extra: (allow-none) (element-type utf8): A list of extra data to store in association with this contact
6724 * @replace: Whether this contact should replace another contact with the same UID.
6725 * @cancellable: (allow-none): A #GCancellable
6726 * @error: (allow-none): A location to store any error that may have occurred.
6728 * Adds or replaces contacts in @ebsql. If @replace_existing is specified then existing
6729 * contacts with the same UID will be replaced, otherwise adding an existing contact
6730 * will return an error.
6732 * If @extra is specified, it must have an equal length as the @contacts list. Each element
6733 * from the @extra list will be stored in association with it's corresponding contact
6734 * in the @contacts list.
6736 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6741 e_book_sqlite_add_contacts (EBookSqlite *ebsql,
6745 GCancellable *cancellable,
6749 gboolean success = TRUE;
6751 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6752 g_return_val_if_fail (contacts != NULL, FALSE);
6753 g_return_val_if_fail (extra == NULL ||
6754 g_slist_length (extra) == g_slist_length (contacts), FALSE);
6756 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
6758 if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
6759 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6763 for (l = contacts, ll = extra;
6764 success && l != NULL;
6765 l = l->next, ll = ll ? ll->next : NULL) {
6766 EContact *contact = (EContact *) l->data;
6767 const gchar *extra_data = NULL;
6770 extra_data = (const gchar *) ll->data;
6772 g_signal_emit (ebsql,
6773 signals[BEFORE_INSERT_CONTACT],
6776 contact, extra_data,
6783 success = ebsql_insert_contact (
6785 EBSQL_CHANGE_CONTACT_ADDED,
6786 contact, NULL, extra_data,
6791 success = ebsql_commit_transaction (ebsql, error);
6793 /* The GError is already set. */
6794 ebsql_rollback_transaction (ebsql, NULL);
6796 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6802 * e_book_sqlite_remove_contact:
6803 * @ebsql: An #EBookSqlite
6804 * @uid: the uid of the contact to remove
6805 * @cancellable: (allow-none): A #GCancellable
6806 * @error: (allow-none): A location to store any error that may have occurred.
6808 * Removes the contact indicated by @uid from @ebsql.
6810 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6815 e_book_sqlite_remove_contact (EBookSqlite *ebsql,
6817 GCancellable *cancellable,
6822 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6823 g_return_val_if_fail (uid != NULL, FALSE);
6825 l.data = (gchar *) uid; /* Won't modify it, I promise :) */
6828 return e_book_sqlite_remove_contacts (
6829 ebsql, &l, cancellable, error);
6833 generate_delete_stmt (const gchar *table,
6836 GString *str = g_string_new (NULL);
6839 ebsql_string_append_printf (str, "DELETE FROM %Q WHERE uid IN (", table);
6841 for (l = uids; l; l = l->next) {
6842 const gchar *uid = (const gchar *) l->data;
6844 /* First uid with no comma */
6846 g_string_append_printf (str, ", ");
6848 ebsql_string_append_printf (str, "%Q", uid);
6851 g_string_append_c (str, ')');
6853 return g_string_free (str, FALSE);
6857 * e_book_sqlite_remove_contacts:
6858 * @ebsql: An #EBookSqlite
6859 * @uids: a #GSList of uids indicating which contacts to remove
6860 * @cancellable: (allow-none): A #GCancellable
6861 * @error: (allow-none): A location to store any error that may have occurred.
6863 * Removes the contacts indicated by @uids from @ebsql.
6865 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6870 e_book_sqlite_remove_contacts (EBookSqlite *ebsql,
6872 GCancellable *cancellable,
6875 gboolean success = TRUE;
6878 const gchar *contact_uid;
6881 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6882 g_return_val_if_fail (uids != NULL, FALSE);
6884 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
6886 if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
6887 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6891 for (l = uids; success && l; l = l->next) {
6892 contact_uid = (const gchar *) l->data;
6893 g_signal_emit (ebsql,
6894 signals[BEFORE_REMOVE_CONTACT],
6902 /* Delete data from the auxiliary tables first */
6903 for (i = 0; success && i < ebsql->priv->n_summary_fields; i++) {
6904 SummaryField *field = &(ebsql->priv->summary_fields[i]);
6906 if (field->type != E_TYPE_CONTACT_ATTR_LIST)
6909 stmt = generate_delete_stmt (field->aux_table, uids);
6910 success = ebsql_exec (ebsql, stmt, NULL, NULL, NULL, error);
6914 /* Now delete the entry from the main contacts */
6916 stmt = generate_delete_stmt (ebsql->priv->folderid, uids);
6917 success = ebsql_exec (ebsql, stmt, NULL, NULL, NULL, error);
6922 success = ebsql_commit_transaction (ebsql, error);
6924 /* The GError is already set. */
6925 ebsql_rollback_transaction (ebsql, NULL);
6927 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6933 * e_book_sqlite_has_contact:
6934 * @ebsql: An #EBookSqlite
6935 * @uid: The uid of the contact to check for
6936 * @exists: (out): Return location to store whether the contact exists.
6937 * @error: (allow-none): A location to store any error that may have occurred.
6939 * Checks if a contact bearing the UID indicated by @uid is stored in @ebsql.
6941 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6946 e_book_sqlite_has_contact (EBookSqlite *ebsql,
6951 gboolean local_exists = FALSE;
6954 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6955 g_return_val_if_fail (uid != NULL, FALSE);
6956 g_return_val_if_fail (exists != NULL, FALSE);
6958 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6959 success = ebsql_exec_printf (
6961 "SELECT uid FROM %Q WHERE uid = %Q",
6962 get_exists_cb, &local_exists, NULL, error,
6963 ebsql->priv->folderid, uid);
6964 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6966 *exists = local_exists;
6972 * e_book_sqlite_get_contact:
6973 * @ebsql: An #EBookSqlite
6974 * @uid: The uid of the contact to fetch
6975 * @meta_contact: Whether an entire contact is desired, or only the metadata
6976 * @ret_contact: (out) (transfer full): Return location to store the fetched contact
6977 * @error: (allow-none): A location to store any error that may have occurred.
6979 * Fetch the #EContact specified by @uid in @ebsql.
6981 * If @meta_contact is specified, then a shallow #EContact will be created
6982 * holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
6984 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6989 e_book_sqlite_get_contact (EBookSqlite *ebsql,
6991 gboolean meta_contact,
6992 EContact **ret_contact,
6995 gboolean success = FALSE;
6996 gchar *vcard = NULL;
6998 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6999 g_return_val_if_fail (uid != NULL, FALSE);
7000 g_return_val_if_fail (ret_contact != NULL && *ret_contact == NULL, FALSE);
7002 success = e_book_sqlite_get_vcard (
7003 ebsql, uid, meta_contact, &vcard, error);
7005 if (success && vcard) {
7006 *ret_contact = e_contact_new_from_vcard_with_uid (vcard, uid);
7014 * ebsql_get_contact_unlocked:
7015 * @ebsql: An #EBookSqlite
7016 * @uid: The uid of the contact to fetch
7017 * @meta_contact: Whether an entire contact is desired, or only the metadata
7018 * @contact: (out) (transfer full): Return location to store the fetched contact
7019 * @error: (allow-none): A location to store any error that may have occurred.
7021 * Fetch the #EContact specified by @uid in @ebsql without locking internal mutex.
7023 * If @meta_contact is specified, then a shallow #EContact will be created
7024 * holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7026 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7031 ebsql_get_contact_unlocked (EBookSqlite *ebsql,
7033 gboolean meta_contact,
7037 gboolean success = FALSE;
7038 gchar *vcard = NULL;
7040 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7041 g_return_val_if_fail (uid != NULL, FALSE);
7042 g_return_val_if_fail (contact != NULL && *contact == NULL, FALSE);
7044 success = ebsql_get_vcard_unlocked (ebsql,
7050 if (success && vcard) {
7051 *contact = e_contact_new_from_vcard_with_uid (vcard, uid);
7059 * e_book_sqlite_get_vcard:
7060 * @ebsql: An #EBookSqlite
7061 * @uid: The uid of the contact to fetch
7062 * @meta_contact: Whether an entire contact is desired, or only the metadata
7063 * @ret_vcard: (out) (transfer full): Return location to store the fetched vcard string
7064 * @error: (allow-none): A location to store any error that may have occurred.
7066 * Fetch a vcard string for @uid in @ebsql.
7068 * If @meta_contact is specified, then a shallow vcard representation will be
7069 * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7071 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7076 e_book_sqlite_get_vcard (EBookSqlite *ebsql,
7078 gboolean meta_contact,
7082 gboolean success = FALSE;
7083 gchar *vcard = NULL;
7085 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7086 g_return_val_if_fail (uid != NULL, FALSE);
7087 g_return_val_if_fail (ret_vcard != NULL && *ret_vcard == NULL, FALSE);
7089 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7091 /* Try constructing contacts from only UID/REV first if that's requested */
7093 GSList *vcards = NULL;
7095 success = ebsql_exec_printf (
7096 ebsql, "SELECT summary.uid, summary.Rev FROM %Q AS summary WHERE uid = %Q",
7097 collect_lean_results_cb, &vcards, NULL, error,
7098 ebsql->priv->folderid, uid);
7101 EbSqlSearchData *search_data = (EbSqlSearchData *) vcards->data;
7103 vcard = search_data->vcard;
7104 search_data->vcard = NULL;
7106 g_slist_free_full (vcards, (GDestroyNotify) e_book_sqlite_search_data_free);
7111 success = ebsql_exec_printf (
7112 ebsql, "SELECT %s FROM %Q AS summary WHERE summary.uid = %Q",
7113 get_string_cb, &vcard, NULL, error,
7114 EBSQL_VCARD_FRAGMENT (ebsql), ebsql->priv->folderid, uid);
7117 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7121 if (success && !vcard) {
7124 E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND,
7125 _("Contact '%s' not found"), uid);
7133 * ebsql_get_vcard_unlocked:
7134 * @ebsql: An #EBookSqlite
7135 * @uid: The uid of the contact to fetch
7136 * @meta_contact: Whether an entire contact is desired, or only the metadata
7137 * @ret_vcard: (out) (transfer full): Return location to store the fetched vcard string
7138 * @error: (allow-none): A location to store any error that may have occurred.
7140 * Fetch a vcard string for @uid in @ebsql without locking internal mutex.
7142 * If @meta_contact is specified, then a shallow vcard representation will be
7143 * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7145 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7150 ebsql_get_vcard_unlocked (EBookSqlite *ebsql,
7152 gboolean meta_contact,
7156 gboolean success = FALSE;
7157 gchar *vcard = NULL;
7159 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7160 g_return_val_if_fail (uid != NULL, FALSE);
7161 g_return_val_if_fail (ret_vcard != NULL && *ret_vcard == NULL, FALSE);
7163 /* Try constructing contacts from only UID/REV first if that's requested */
7165 GSList *vcards = NULL;
7167 success = ebsql_exec_printf (
7168 ebsql, "SELECT summary.uid, summary.Rev FROM %Q AS summary WHERE uid = %Q",
7169 collect_lean_results_cb, &vcards, NULL, error,
7170 ebsql->priv->folderid, uid);
7173 EbSqlSearchData *search_data = (EbSqlSearchData *) vcards->data;
7175 vcard = search_data->vcard;
7176 search_data->vcard = NULL;
7178 g_slist_free_full (vcards, (GDestroyNotify) e_book_sqlite_search_data_free);
7183 success = ebsql_exec_printf (
7184 ebsql, "SELECT %s FROM %Q AS summary WHERE summary.uid = %Q",
7185 get_string_cb, &vcard, NULL, error,
7186 EBSQL_VCARD_FRAGMENT (ebsql), ebsql->priv->folderid, uid);
7191 if (success && !vcard) {
7192 EBSQL_SET_ERROR (error,
7193 E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND,
7194 _("Contact '%s' not found"), uid);
7202 * e_book_sqlite_set_contact_extra:
7203 * @ebsql: An #EBookSqlite
7204 * @uid: The uid of the contact to set the extra data for
7205 * @extra: (allow-none): The extra data to set
7206 * @error: (allow-none): A location to store any error that may have occurred.
7208 * Sets or replaces the extra data associated with @uid.
7210 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7215 e_book_sqlite_set_contact_extra (EBookSqlite *ebsql,
7222 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7223 g_return_val_if_fail (uid != NULL, FALSE);
7225 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7226 success = ebsql_exec_printf (
7227 ebsql, "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
7228 NULL, NULL, NULL, error,
7229 ebsql->priv->folderid, uid);
7230 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7236 * e_book_sqlite_get_contact_extra:
7237 * @ebsql: An #EBookSqlite
7238 * @uid: The uid of the contact to fetch the extra data for
7239 * @ret_extra: (out) (transfer full): Return location to store the extra data
7240 * @error: (allow-none): A location to store any error that may have occurred.
7242 * Fetches the extra data previously set for @uid, either with
7243 * e_book_sqlite_set_contact_extra() or when adding contacts.
7245 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7250 e_book_sqlite_get_contact_extra (EBookSqlite *ebsql,
7257 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7258 g_return_val_if_fail (uid != NULL, FALSE);
7259 g_return_val_if_fail (ret_extra != NULL && *ret_extra == NULL, FALSE);
7261 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7262 success = ebsql_exec_printf (
7263 ebsql, "SELECT bdata FROM %Q WHERE uid = %Q",
7264 get_string_cb, ret_extra, NULL, error,
7265 ebsql->priv->folderid, uid);
7266 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7272 * ebsql_get_contact_extra_unlocked:
7273 * @ebsql: An #EBookSqlite
7274 * @uid: The uid of the contact to fetch the extra data for
7275 * @ret_extra: (out) (transfer full): Return location to store the extra data
7276 * @error: (allow-none): A location to store any error that may have occurred.
7278 * Fetches the extra data previously set for @uid, either with
7279 * e_book_sqlite_set_contact_extra() or when adding contacts,
7280 * without locking internal mutex.
7282 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7287 ebsql_get_contact_extra_unlocked (EBookSqlite *ebsql,
7294 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7295 g_return_val_if_fail (uid != NULL, FALSE);
7296 g_return_val_if_fail (ret_extra != NULL && *ret_extra == NULL, FALSE);
7298 success = ebsql_exec_printf (
7299 ebsql, "SELECT bdata FROM %Q WHERE uid = %Q",
7300 get_string_cb, ret_extra, NULL, error,
7301 ebsql->priv->folderid, uid);
7307 * e_book_sqlite_search:
7308 * @ebsql: An #EBookSqlite
7309 * @sexp: (allow-none): search expression; use %NULL or an empty string to list all stored contacts.
7310 * @meta_contacts: Whether entire contacts are desired, or only the metadata
7311 * @ret_list: (out) (transfer full) (element-type EbSqlSearchData): Return location
7312 * to store a #GSList of #EbSqlSearchData structures
7313 * @cancellable: (allow-none): A #GCancellable
7314 * @error: (allow-none): A location to store any error that may have occurred.
7316 * Searches @ebsql for contacts matching the search expression indicated by @sexp.
7318 * When @sexp refers only to #EContactFields configured in the summary of @ebsql,
7319 * the search should always be quick, when searching for other #EContactFields
7320 * a fallback will be used, possibly invoking any #EbSqlVCardCallback which
7321 * may have been passed to e_book_sqlite_new_full().
7323 * The returned @ret_list list should be freed with g_slist_free()
7324 * and all elements freed with e_book_sqlite_search_data_free().
7326 * If @meta_contact is specified, then shallow vcard representations will be
7327 * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7329 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7334 e_book_sqlite_search (EBookSqlite *ebsql,
7336 gboolean meta_contacts,
7338 GCancellable *cancellable,
7343 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7344 g_return_val_if_fail (ret_list != NULL && *ret_list == NULL, FALSE);
7346 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7347 success = ebsql_search_query (
7350 SEARCH_UID_AND_REV : SEARCH_FULL,
7354 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7360 * e_book_sqlite_search_uids:
7361 * @ebsql: An #EBookSqlite
7362 * @sexp: (allow-none): search expression; use %NULL or an empty string to get all stored contacts.
7363 * @ret_list: (out) (transfer full): Return location to store a #GSList of contact uids
7364 * @cancellable: (allow-none): A #GCancellable
7365 * @error: (allow-none): A location to store any error that may have occurred.
7367 * Similar to e_book_sqlitedb_search(), but fetches only a list of contact UIDs.
7369 * The returned @ret_list list should be freed with g_slist_free() and all
7370 * elements freed with g_free().
7372 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7377 e_book_sqlite_search_uids (EBookSqlite *ebsql,
7380 GCancellable *cancellable,
7385 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7386 g_return_val_if_fail (ret_list != NULL && *ret_list == NULL, FALSE);
7388 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7389 success = ebsql_search_query (ebsql, sexp, SEARCH_UID, ret_list, cancellable, error);
7390 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7396 * e_book_sqlite_get_key_value:
7397 * @ebsql: An #EBookSqlite
7398 * @key: The key to fetch a value for
7399 * @value: (out) (transfer full): A return location to store the value for @key
7400 * @error: (allow-none): A location to store any error that may have occurred.
7402 * Fetches the value for @key and stores it in @value
7404 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7409 e_book_sqlite_get_key_value (EBookSqlite *ebsql,
7416 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7417 g_return_val_if_fail (key != NULL, FALSE);
7418 g_return_val_if_fail (value != NULL && *value == NULL, FALSE);
7420 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7421 success = ebsql_exec_printf (
7423 "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
7424 get_string_cb, value, NULL, error,
7425 ebsql->priv->folderid, key);
7426 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7432 * e_book_sqlite_set_key_value:
7433 * @ebsql: An #EBookSqlite
7434 * @key: The key to fetch a value for
7435 * @value: The new value for @key
7436 * @error: (allow-none): A location to store any error that may have occurred.
7438 * Sets the value for @key to be @value
7440 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7445 e_book_sqlite_set_key_value (EBookSqlite *ebsql,
7452 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7453 g_return_val_if_fail (key != NULL, FALSE);
7454 g_return_val_if_fail (value != NULL, FALSE);
7456 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7457 success = ebsql_exec_printf (
7458 ebsql, "INSERT or REPLACE INTO keys (key, value, folder_id) values (%Q, %Q, %Q)",
7459 NULL, NULL, NULL, error,
7460 key, value, ebsql->priv->folderid);
7461 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7467 * e_book_sqlite_get_key_value_int:
7468 * @ebsql: An #EBookSqlite
7469 * @key: The key to fetch a value for
7470 * @value: (out): A return location to store the value for @key
7471 * @error: (allow-none): A location to store any error that may have occurred.
7473 * A convenience function to fetch the value of @key as an integer.
7475 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7480 e_book_sqlite_get_key_value_int (EBookSqlite *ebsql,
7486 gchar *str_value = NULL;
7488 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7489 g_return_val_if_fail (key != NULL, FALSE);
7490 g_return_val_if_fail (value != NULL, FALSE);
7492 success = e_book_sqlite_get_key_value (ebsql, key, &str_value, error);
7497 *value = g_ascii_strtoll (str_value, NULL, 10);
7508 * e_book_sqlite_set_key_value_int:
7509 * @ebsql: An #EBookSqlite
7510 * @key: The key to fetch a value for
7511 * @value: The new value for @key
7512 * @error: (allow-none): A location to store any error that may have occurred.
7514 * A convenience function to set the value of @key as an integer.
7516 * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7521 e_book_sqlite_set_key_value_int (EBookSqlite *ebsql,
7527 gchar *str_value = NULL;
7529 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7530 g_return_val_if_fail (key != NULL, FALSE);
7532 str_value = g_strdup_printf ("%d", value);
7533 success = e_book_sqlite_set_key_value (
7534 ebsql, key, str_value, error);
7541 * e_book_sqlite_search_data_free:
7542 * @data: An #EbSqlSearchData
7544 * Frees an #EbSqlSearchData
7549 e_book_sqlite_search_data_free (EbSqlSearchData *data)
7553 g_free (data->vcard);
7554 g_free (data->extra);
7555 g_slice_free (EbSqlSearchData, data);
7560 * e_book_sqlite_set_locale:
7561 * @ebsql: An #EBookSqlite
7562 * @lc_collate: The new locale for the addressbook
7563 * @cancellable: (allow-none): A #GCancellable
7564 * @error: A location to store any error that may have occurred
7566 * Relocalizes any locale specific data in the specified
7567 * new @lc_collate locale.
7569 * The @lc_collate locale setting is stored and remembered on
7570 * subsequent accesses of the addressbook, changing the locale
7571 * will store the new locale and will modify sort keys and any
7572 * locale specific data in the addressbook.
7574 * As a side effect, it's possible that changing the locale
7575 * will cause stored vcards to change. Notifications for
7576 * these changes can be caught with the #EbSqlVCardCallback
7577 * provided to e_book_sqlite_new_full().
7579 * Returns: Whether the new locale was successfully set.
7584 e_book_sqlite_set_locale (EBookSqlite *ebsql,
7585 const gchar *lc_collate,
7586 GCancellable *cancellable,
7590 gchar *stored_lc_collate = NULL;
7592 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7594 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7596 if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
7597 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7601 success = ebsql_set_locale_internal (ebsql, lc_collate, error);
7604 success = ebsql_exec_printf (
7605 ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
7606 get_string_cb, &stored_lc_collate, NULL, error,
7607 ebsql->priv->folderid);
7609 if (success && g_strcmp0 (stored_lc_collate, lc_collate) != 0)
7610 success = ebsql_upgrade (ebsql, EBSQL_CHANGE_LOCALE_CHANGED, error);
7612 /* If for some reason we failed, then reset the collator to use the old locale */
7613 if (!success && stored_lc_collate && stored_lc_collate[0])
7614 ebsql_set_locale_internal (ebsql, stored_lc_collate, NULL);
7617 success = ebsql_commit_transaction (ebsql, error);
7619 /* The GError is already set. */
7620 ebsql_rollback_transaction (ebsql, NULL);
7622 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7624 g_free (stored_lc_collate);
7630 * e_book_sqlite_get_locale:
7631 * @ebsql: An #EBookSqlite
7632 * @locale_out: (out) (transfer full): The location to return the current locale
7633 * @error: A location to store any error that may have occurred
7635 * Fetches the current locale setting for the address-book.
7637 * Upon success, @lc_collate_out will hold the returned locale setting,
7638 * otherwise %FALSE will be returned and @error will be updated accordingly.
7640 * Returns: Whether the locale was successfully fetched.
7645 e_book_sqlite_get_locale (EBookSqlite *ebsql,
7650 GError *local_error = NULL;
7652 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7653 g_return_val_if_fail (locale_out != NULL && *locale_out == NULL, FALSE);
7655 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7657 success = ebsql_exec_printf (
7658 ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
7659 get_string_cb, locale_out, NULL, error,
7660 ebsql->priv->folderid);
7662 if (*locale_out == NULL) {
7664 /* This can't realistically happen, if it does we
7665 * should warn about it in stdout */
7666 g_warning ("EBookSqlite has no active locale in the database");
7668 *locale_out = g_strdup (ebsql->priv->locale);
7671 if (success && !ebsql_set_locale_internal (ebsql, *locale_out, &local_error)) {
7672 g_warning ("Error loading new locale: %s", local_error->message);
7673 g_clear_error (&local_error);
7676 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7682 * e_book_sqlite_cursor_new:
7683 * @ebsql: An #EBookSqlite
7684 * @sexp: search expression; use NULL or an empty string to get all stored contacts.
7685 * @sort_fields: (array length=n_sort_fields): An array of #EContactFields as sort keys in order of priority
7686 * @sort_types: (array length=n_sort_fields): An array of #EBookCursorSortTypes, one for each field in @sort_fields
7687 * @n_sort_fields: The number of fields to sort results by.
7688 * @error: A return location to store any error that might be reported.
7690 * Creates a new #EbSqlCursor.
7692 * The cursor should be freed with e_book_sqlite_cursor_free().
7694 * Returns: (transfer full): A newly created #EbSqlCursor
7699 e_book_sqlite_cursor_new (EBookSqlite *ebsql,
7701 const EContactField *sort_fields,
7702 const EBookCursorSortType *sort_types,
7703 guint n_sort_fields,
7706 EbSqlCursor *cursor;
7709 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
7711 /* We don't like '\0' sexps, prefer NULL */
7712 if (sexp && !sexp[0])
7715 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7717 /* Need one sort key ... */
7718 if (n_sort_fields == 0) {
7719 EBSQL_SET_ERROR_LITERAL (
7720 error, E_BOOK_SQLITE_ERROR_INVALID_QUERY,
7721 _("At least one sort field must be specified to use an EbSqlCursor"));
7722 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7726 /* We only support string fields to sort the cursor */
7727 for (i = 0; i < n_sort_fields; i++) {
7731 "Building cursor to sort '%s' in '%s' order\n",
7732 e_contact_field_name (sort_fields[i]),
7733 sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ?
7734 "ascending" : "descending"));
7736 if (e_contact_field_type (sort_fields[i]) != G_TYPE_STRING) {
7737 EBSQL_SET_ERROR_LITERAL (
7738 error, E_BOOK_SQLITE_ERROR_INVALID_QUERY,
7739 _("Cannot sort by a field that is not a string type"));
7740 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7745 /* Now we need to create the cursor instance before setting up the query
7746 * (not really true, but more convenient that way).
7748 cursor = ebsql_cursor_new (ebsql, sexp, sort_fields, sort_types, n_sort_fields);
7750 /* Setup the cursor's query expression which might fail */
7751 if (!ebsql_cursor_setup_query (ebsql, cursor, sexp, error)) {
7752 ebsql_cursor_free (cursor);
7756 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7761 "%s cursor with search expression '%s'\n",
7762 cursor ? "Successfully created" : "Failed to create",
7769 * e_book_sqlite_cursor_free:
7770 * @ebsql: An #EBookSqlite
7771 * @cursor: The #EbSqlCursor to free
7778 e_book_sqlite_cursor_free (EBookSqlite *ebsql,
7779 EbSqlCursor *cursor)
7781 g_return_if_fail (E_IS_BOOK_SQLITE (ebsql));
7783 ebsql_cursor_free (cursor);
7789 const gchar *last_vcard;
7791 gboolean collect_results;
7793 } CursorCollectData;
7796 collect_results_for_cursor_cb (gpointer ref,
7801 CursorCollectData *data = ref;
7803 if (data->collect_results) {
7804 EbSqlSearchData *search_data;
7806 search_data = search_data_from_results (ncol, cols, names);
7808 data->results = g_slist_prepend (data->results, search_data);
7810 data->last_vcard = search_data->vcard;
7812 g_free (data->alloc_vcard);
7813 data->alloc_vcard = g_strdup (cols[1]);
7815 data->last_vcard = data->alloc_vcard;
7824 * e_book_sqlite_cursor_step:
7825 * @ebsql: An #EBookSqlite
7826 * @cursor: The #EbSqlCursor to use
7827 * @flags: The #EbSqlCursorStepFlags for this step
7828 * @origin: The #EbSqlCursorOrigin from whence to step
7829 * @count: A positive or negative amount of contacts to try and fetch
7830 * @results: (out) (allow-none) (element-type EbSqlSearchData) (transfer full):
7831 * A return location to store the results, or %NULL if %EBSQL_CURSOR_STEP_FETCH is not specified in %flags.
7832 * @cancellable: (allow-none): A #GCancellable
7833 * @error: A return location to store any error that might be reported.
7835 * Steps @cursor through it's sorted query by a maximum of @count contacts
7836 * starting from @origin.
7838 * If @count is negative, then the cursor will move through the list in reverse.
7840 * If @cursor reaches the beginning or end of the query results, then the
7841 * returned list might not contain the amount of desired contacts, or might
7842 * return no results if the cursor currently points to the last contact.
7843 * Reaching the end of the list is not considered an error condition. Attempts
7844 * to step beyond the end of the list after having reached the end of the list
7845 * will however trigger an %E_BOOK_SQLITE_ERROR_END_OF_LIST error.
7847 * If %EBSQL_CURSOR_STEP_FETCH is specified in %flags, a pointer to
7848 * a %NULL #GSList pointer should be provided for the @results parameter.
7850 * The result list will be stored to @results and should be freed with g_slist_free()
7851 * and all elements freed with e_book_sqlite_search_data_free().
7853 * Returns: The number of contacts traversed if successful, otherwise -1 is
7854 * returned and @error is set.
7859 e_book_sqlite_cursor_step (EBookSqlite *ebsql,
7860 EbSqlCursor *cursor,
7861 EbSqlCursorStepFlags flags,
7862 EbSqlCursorOrigin origin,
7865 GCancellable *cancellable,
7868 CursorCollectData data = { NULL, NULL, NULL, FALSE, 0 };
7872 EbSqlCursorOrigin try_position;
7874 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), -1);
7875 g_return_val_if_fail (cursor != NULL, -1);
7876 g_return_val_if_fail ((flags & EBSQL_CURSOR_STEP_FETCH) == 0 ||
7877 (results != NULL && *results == NULL), -1);
7879 /* Lock and check cancellable early */
7880 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, -1);
7885 "Cursor requested to step by %d with origin %s will move: %s will fetch: %s\n",
7886 count, EBSQL_ORIGIN_STR (origin),
7887 (flags & EBSQL_CURSOR_STEP_MOVE) ? "yes" : "no",
7888 (flags & EBSQL_CURSOR_STEP_FETCH) ? "yes" : "no"));
7890 /* Check if this step should result in an end of list error first */
7891 try_position = cursor->state.position;
7892 if (origin != EBSQL_CURSOR_ORIGIN_CURRENT)
7893 try_position = origin;
7895 /* Report errors for requests to run off the end of the list */
7896 if (try_position == EBSQL_CURSOR_ORIGIN_BEGIN && count < 0) {
7897 EBSQL_SET_ERROR_LITERAL (
7898 error, E_BOOK_SQLITE_ERROR_END_OF_LIST,
7899 _("Tried to step a cursor in reverse, "
7900 "but cursor is already at the beginning of the contact list"));
7902 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7904 } else if (try_position == EBSQL_CURSOR_ORIGIN_END && count > 0) {
7905 EBSQL_SET_ERROR_LITERAL (
7906 error, E_BOOK_SQLITE_ERROR_END_OF_LIST,
7907 _("Tried to step a cursor forwards, "
7908 "but cursor is already at the end of the contact list"));
7910 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7914 /* Nothing to do, silently return */
7915 if (count == 0 && try_position == EBSQL_CURSOR_ORIGIN_CURRENT) {
7916 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7920 /* If we're not going to modify the position, just use
7921 * a copy of the current cursor state.
7923 if ((flags & EBSQL_CURSOR_STEP_MOVE) != 0)
7924 state = &(cursor->state);
7926 state = cursor_state_copy (cursor, &(cursor->state));
7928 /* Every query starts with the STATE_CURRENT position, first
7929 * fix up the cursor state according to 'origin'
7932 case EBSQL_CURSOR_ORIGIN_CURRENT:
7933 /* Do nothing, normal operation */
7936 case EBSQL_CURSOR_ORIGIN_BEGIN:
7937 case EBSQL_CURSOR_ORIGIN_END:
7939 /* Prepare the state before executing the query */
7940 cursor_state_clear (cursor, state, origin);
7944 /* If count is 0 then there is no need to run any
7945 * query, however it can be useful if you just want
7946 * to move the cursor to the beginning or ending of
7951 /* Free the state copy if need be */
7952 if ((flags & EBSQL_CURSOR_STEP_MOVE) == 0)
7953 cursor_state_free (cursor, state);
7955 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7959 query = g_string_new (cursor->select_vcards);
7961 /* Add the filter constraints (if any) */
7962 if (cursor->query) {
7963 g_string_append (query, " WHERE ");
7965 g_string_append_c (query, '(');
7966 g_string_append (query, cursor->query);
7967 g_string_append_c (query, ')');
7970 /* Add the cursor constraints (if any) */
7971 if (state->values[0] != NULL) {
7972 gchar *constraints = NULL;
7975 g_string_append (query, " WHERE ");
7977 g_string_append (query, " AND ");
7979 constraints = ebsql_cursor_constraints (
7980 ebsql, cursor, state, count < 0, FALSE);
7982 g_string_append_c (query, '(');
7983 g_string_append (query, constraints);
7984 g_string_append_c (query, ')');
7986 g_free (constraints);
7989 /* Add the sort order */
7990 g_string_append_c (query, ' ');
7992 g_string_append (query, cursor->order);
7994 g_string_append (query, cursor->reverse_order);
7997 g_string_append_printf (query, " LIMIT %d", ABS (count));
7999 /* Specify whether we really want results or not */
8000 data.collect_results = (flags & EBSQL_CURSOR_STEP_FETCH) != 0;
8002 /* Execute the query */
8003 success = ebsql_exec (
8005 collect_results_for_cursor_cb, &data,
8006 cancellable, error);
8008 /* Lock was obtained above */
8009 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8011 g_string_free (query, TRUE);
8013 /* If there was no error, update the internal cursor state */
8016 if (data.n_results < ABS (count)) {
8018 /* We've reached the end, clear the current state */
8020 cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
8022 cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_END);
8024 } else if (data.last_vcard) {
8026 /* Set the cursor state to the last result */
8027 cursor_state_set_from_vcard (ebsql, cursor, state, data.last_vcard);
8029 /* Should never get here */
8030 g_warn_if_reached ();
8032 /* Assign the results to return (if any) */
8034 /* Correct the order of results at the last minute */
8035 *results = g_slist_reverse (data.results);
8036 data.results = NULL;
8040 /* Cleanup what was allocated by collect_results_for_cursor_cb() */
8044 (GDestroyNotify) e_book_sqlite_search_data_free);
8045 g_free (data.alloc_vcard);
8047 /* Free the copy state if we were working with a copy */
8048 if ((flags & EBSQL_CURSOR_STEP_MOVE) == 0)
8049 cursor_state_free (cursor, state);
8052 return data.n_results;
8058 * e_book_sqlite_cursor_set_target_alphabetic_index:
8059 * @ebsql: An #EBookSqlite
8060 * @cursor: The #EbSqlCursor to modify
8061 * @idx: The alphabetic index
8063 * Sets the @cursor position to an
8064 * <link linkend="cursor-alphabet">Alphabetic Index</link>
8065 * into the alphabet active in @ebsql's locale.
8067 * After setting the target to an alphabetic index, for example the
8068 * index for letter 'E', then further calls to e_book_sqlite_cursor_step()
8069 * will return results starting with the letter 'E' (or results starting
8070 * with the last result in 'D', if moving in a negative direction).
8072 * The passed index must be a valid index in the active locale, knowledge
8073 * on the currently active alphabet index must be obtained using #ECollator
8076 * Use e_book_sqlite_ref_collator() to obtain the active collator for @ebsql.
8081 e_book_sqlite_cursor_set_target_alphabetic_index (EBookSqlite *ebsql,
8082 EbSqlCursor *cursor,
8087 g_return_if_fail (E_IS_BOOK_SQLITE (ebsql));
8088 g_return_if_fail (cursor != NULL);
8089 g_return_if_fail (idx >= 0);
8091 e_collator_get_index_labels (
8092 ebsql->priv->collator, &n_labels,
8094 g_return_if_fail (idx < n_labels);
8096 cursor_state_clear (cursor, &(cursor->state), EBSQL_CURSOR_ORIGIN_CURRENT);
8097 if (cursor->n_sort_fields > 0) {
8098 SummaryField *field;
8101 index_key = e_collator_generate_key_for_index (ebsql->priv->collator, idx);
8102 field = summary_field_get (ebsql, cursor->sort_fields[0]);
8104 if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
8105 cursor->state.values[0] = index_key;
8107 cursor->state.values[0] =
8108 ebsql_encode_vcard_sort_key (index_key);
8115 * e_book_sqlite_cursor_set_sexp:
8116 * @ebsql: An #EBookSqlite
8117 * @cursor: The #EbSqlCursor
8118 * @sexp: The new query expression for @cursor
8119 * @error: A return location to store any error that might be reported.
8121 * Modifies the current query expression for @cursor. This will not
8122 * modify @cursor's state, but will change the outcome of any further
8123 * calls to e_book_sqlite_cursor_calculate() or
8124 * e_book_sqlite_cursor_step().
8126 * Returns: %TRUE if the expression was valid and accepted by @ebsql
8131 e_book_sqlite_cursor_set_sexp (EBookSqlite *ebsql,
8132 EbSqlCursor *cursor,
8138 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
8139 g_return_val_if_fail (cursor != NULL, FALSE);
8141 /* We don't like '\0' sexps, prefer NULL */
8142 if (sexp && !sexp[0])
8145 EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
8146 success = ebsql_cursor_setup_query (ebsql, cursor, sexp, error);
8147 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8153 * e_book_sqlite_cursor_calculate:
8154 * @ebsql: An #EBookSqlite
8155 * @cursor: The #EbSqlCursor
8156 * @total: (out) (allow-none): A return location to store the total result set for this cursor
8157 * @position: (out) (allow-none): A return location to store the total results before the cursor value
8158 * @cancellable: (allow-none): A #GCancellable
8159 * @error: (allow-none): A return location to store any error that might be reported.
8161 * Calculates the @total amount of results for the @cursor's query expression,
8162 * as well as the current @position of @cursor in the results. @position is
8163 * represented as the amount of results which lead up to the current value
8164 * of @cursor, if @cursor currently points to an exact contact, the position
8165 * also includes the cursor contact.
8167 * Returns: Whether @total and @position were successfully calculated.
8172 e_book_sqlite_cursor_calculate (EBookSqlite *ebsql,
8173 EbSqlCursor *cursor,
8176 GCancellable *cancellable,
8179 gboolean success = TRUE;
8180 gint local_total = 0;
8182 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
8183 g_return_val_if_fail (cursor != NULL, FALSE);
8185 /* If we're in a clear cursor state, then the position is 0 */
8186 if (position && cursor->state.values[0] == NULL) {
8188 if (cursor->state.position == EBSQL_CURSOR_ORIGIN_BEGIN) {
8189 /* Mark the local pointer NULL, no need to calculate this anymore */
8192 } else if (cursor->state.position == EBSQL_CURSOR_ORIGIN_END) {
8194 /* Make sure that we look up the total so we can
8195 * set the position to 'total + 1'
8198 total = &local_total;
8202 /* Early return if there is nothing to do */
8203 if (!total && !position)
8206 EBSQL_LOCK_OR_RETURN (ebsql, cancellable, -1);
8208 /* Start a read transaction, it's important our two queries are atomic */
8209 if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_READ, cancellable, error)) {
8210 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8215 success = cursor_count_total_locked (ebsql, cursor, total, error);
8217 if (success && position)
8218 success = cursor_count_position_locked (ebsql, cursor, position, error);
8221 success = ebsql_commit_transaction (ebsql, error);
8223 /* The GError is already set. */
8224 ebsql_rollback_transaction (ebsql, NULL);
8226 EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8228 /* In the case we're at the end, we just set the position
8229 * to be the total + 1
8231 if (success && position && total &&
8232 cursor->state.position == EBSQL_CURSOR_ORIGIN_END)
8233 *position = *total + 1;
8239 * e_book_sqlite_cursor_compare_contact:
8240 * @ebsql: An #EBookSqlite
8241 * @cursor: The #EbSqlCursor
8242 * @contact: The #EContact to compare
8243 * @matches_sexp: (out) (allow-none): Whether the contact matches the cursor's search expression
8245 * Compares @contact with @cursor and returns whether @contact is less than, equal to, or greater
8248 * Returns: A value that is less than, equal to, or greater than zero if @contact is found,
8249 * respectively, to be less than, to match, or be greater than the current value of @cursor.
8254 e_book_sqlite_cursor_compare_contact (EBookSqlite *ebsql,
8255 EbSqlCursor *cursor,
8257 gboolean *matches_sexp)
8259 EBookSqlitePrivate *priv;
8261 gint comparison = 0;
8263 g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), -1);
8264 g_return_val_if_fail (E_IS_CONTACT (contact), -1);
8265 g_return_val_if_fail (cursor != NULL, -1);
8270 if (cursor->sexp == NULL)
8271 *matches_sexp = TRUE;
8274 e_book_backend_sexp_match_contact (cursor->sexp, contact);
8277 for (i = 0; i < cursor->n_sort_fields && comparison == 0; i++) {
8278 SummaryField *field;
8279 gchar *contact_key = NULL;
8280 const gchar *cursor_key = NULL;
8281 const gchar *field_value;
8282 gchar *freeme = NULL;
8284 field_value = (const gchar *) e_contact_get_const (contact, cursor->sort_fields[i]);
8286 contact_key = e_collator_generate_key (priv->collator, field_value, NULL);
8288 field = summary_field_get (ebsql, cursor->sort_fields[i]);
8290 if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
8291 cursor_key = cursor->state.values[i];
8294 if (cursor->state.values[i])
8295 freeme = ebsql_decode_vcard_sort_key (cursor->state.values[i]);
8297 cursor_key = freeme;
8300 /* Empty state sorts below any contact value, which means the contact sorts above cursor */
8301 if (cursor_key == NULL)
8304 /* Check if contact sorts below, equal to, or above the cursor */
8305 comparison = g_strcmp0 (contact_key, cursor_key);
8307 g_free (contact_key);
8311 /* UID tie-breaker */
8312 if (comparison == 0) {
8315 uid = (const gchar *) e_contact_get_const (contact, E_CONTACT_UID);
8317 if (cursor->state.last_uid == NULL)
8319 else if (uid == NULL)
8322 comparison = strcmp (uid, cursor->state.last_uid);