X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fdatabase.cc;h=4ff748f6360c494775370c516c1c95a52c3266e6;hp=f33f0af6a7145a603a7ed9eb42bed44c442deba4;hb=f25fc8e2115fc0fa6fa2a6d1cf3ed2747e163886;hpb=6b0cf9b21a8fe8b9a3cd9479e46835bb0eef024b diff --git a/lib/database.cc b/lib/database.cc index f33f0af6..4ff748f6 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -32,10 +32,10 @@ #include #include -#include /* g_free, GPtrArray, GHashTable */ -#include /* g_type_init */ +#include /* g_free, GPtrArray, GHashTable */ +#include /* g_type_init */ -#include /* g_mime_init */ +#include /* g_mime_init */ using namespace std; @@ -49,7 +49,7 @@ typedef struct { #define NOTMUCH_DATABASE_VERSION 3 -#define STRINGIFY(s) _SUB_STRINGIFY(s) +#define STRINGIFY(s) _SUB_STRINGIFY (s) #define _SUB_STRINGIFY(s) #s #if HAVE_XAPIAN_DB_RETRY_LOCK @@ -58,6 +58,17 @@ typedef struct { #define DB_ACTION Xapian::DB_CREATE_OR_OPEN #endif +#define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error) + +static void +_log_xapian_exception (const char *where, notmuch_database_t *notmuch, const Xapian::Error error) { + _notmuch_database_log (notmuch, + "A Xapian exception occurred at %s: %s\n", + where, + error.get_msg ().c_str ()); + notmuch->exception_reported = true; +} + /* Here's the current schema for our database (for NOTMUCH_DATABASE_VERSION): * * We currently have three different types of documents (mail, ghost, @@ -122,11 +133,16 @@ typedef struct { * LAST_MOD: The revision number as of the last tag or * filename change. * - * In addition, terms from the content of the message are added with - * "from", "to", "attachment", and "subject" prefixes for use by the - * user in searching. Similarly, terms from the path of the mail - * message are added with "folder" and "path" prefixes. But the - * database doesn't really care itself about any of these. + * The prefixed terms described above are also searchable without an + * explicit field name, but as of notmuch 0.29 this is due to + * query-parser setup, not extra terms in the database. In addition, + * terms from the content of the message are added without a prefix + * for use by the user in searching. Note that the prefix name "body" + * is used to refer to the empty prefix string in the database. + * + * The path of the containing folder is added with the "folder" prefix + * (see _notmuch_message_add_folder_terms). Sub-paths of the the path + * of the mail message are added with the "path" prefix. * * The data portion of a mail document is empty. * @@ -258,62 +274,121 @@ typedef struct { static const prefix_t prefix_table[] = { /* name term prefix flags */ - { "type", "T", NOTMUCH_FIELD_NO_FLAGS }, - { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS }, - { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS }, - { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS }, - { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, - { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, - { "thread", "G", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, - { "tag", "K", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, - { "is", "K", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, - { "id", "Q", NOTMUCH_FIELD_EXTERNAL }, - { "mid", "Q", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, - { "path", "P", NOTMUCH_FIELD_EXTERNAL| - NOTMUCH_FIELD_PROCESSOR }, - { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL }, + { "type", "T", NOTMUCH_FIELD_NO_FLAGS }, + { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS }, + { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS }, + { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS }, + { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, + { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, + { "body", "", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC }, + { "thread", "G", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "tag", "K", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "is", "K", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "id", "Q", NOTMUCH_FIELD_EXTERNAL }, + { "mid", "Q", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "path", "P", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL }, /* * Unconditionally add ':' to reduce potential ambiguity with * overlapping prefixes and/or terms that start with capital * letters. See Xapian document termprefixes.html for related * discussion. */ - { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, -#if HAVE_XAPIAN_FIELD_PROCESSOR - { "date", NULL, NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, - { "query", NULL, NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROCESSOR }, -#endif - { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROBABILISTIC | - NOTMUCH_FIELD_PROCESSOR }, - { "to", "XTO", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROBABILISTIC }, - { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROBABILISTIC }, - { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROBABILISTIC }, - { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL | - NOTMUCH_FIELD_PROBABILISTIC | - NOTMUCH_FIELD_PROCESSOR}, + { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "date", NULL, NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "query", NULL, NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC | + NOTMUCH_FIELD_PROCESSOR }, + { "to", "XTO", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC }, + { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC }, + { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC }, + { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROBABILISTIC | + NOTMUCH_FIELD_PROCESSOR }, }; static void _setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch) { + if (prefix->prefix) + notmuch->query_parser->add_prefix ("", prefix->prefix); if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC) notmuch->query_parser->add_prefix (prefix->name, prefix->prefix); else notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix); } -#if HAVE_XAPIAN_FIELD_PROCESSOR +notmuch_string_map_iterator_t * +_notmuch_database_user_headers (notmuch_database_t *notmuch) +{ + return _notmuch_string_map_iterator_create (notmuch->user_header, "", false); +} + +const char * +_user_prefix (void *ctx, const char *name) +{ + return talloc_asprintf (ctx, "XU%s:", name); +} + +static notmuch_status_t +_setup_user_query_fields (notmuch_database_t *notmuch) +{ + notmuch_config_list_t *list; + notmuch_status_t status; + + notmuch->user_prefix = _notmuch_string_map_create (notmuch); + if (notmuch->user_prefix == NULL) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + + notmuch->user_header = _notmuch_string_map_create (notmuch); + if (notmuch->user_header == NULL) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + + status = notmuch_database_get_config_list (notmuch, CONFIG_HEADER_PREFIX, &list); + if (status) + return status; + + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { + + prefix_t query_field; + + const char *key = notmuch_config_list_key (list) + + sizeof (CONFIG_HEADER_PREFIX) - 1; + + _notmuch_string_map_append (notmuch->user_prefix, + key, + _user_prefix (notmuch, key)); + + _notmuch_string_map_append (notmuch->user_header, + key, + notmuch_config_list_value (list)); + + query_field.name = talloc_strdup (notmuch, key); + query_field.prefix = _user_prefix (notmuch, key); + query_field.flags = NOTMUCH_FIELD_PROBABILISTIC + | NOTMUCH_FIELD_EXTERNAL; + + _setup_query_field_default (&query_field, notmuch); + } + + notmuch_config_list_destroy (list); + + return NOTMUCH_STATUS_SUCCESS; +} + static void _setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch) { @@ -321,28 +396,23 @@ _setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch) Xapian::FieldProcessor *fp; if (STRNCMP_LITERAL (prefix->name, "date") == 0) - fp = (new DateFieldProcessor())->release (); + fp = (new DateFieldProcessor(NOTMUCH_VALUE_TIMESTAMP))->release (); else if (STRNCMP_LITERAL(prefix->name, "query") == 0) fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release (); - else if (STRNCMP_LITERAL(prefix->name, "thread") == 0) + else if (STRNCMP_LITERAL (prefix->name, "thread") == 0) fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release (); else fp = (new RegexpFieldProcessor (prefix->name, prefix->flags, *notmuch->query_parser, notmuch))->release (); /* we treat all field-processor fields as boolean in order to get the raw input */ + if (prefix->prefix) + notmuch->query_parser->add_prefix ("", prefix->prefix); notmuch->query_parser->add_boolean_prefix (prefix->name, fp); } else { _setup_query_field_default (prefix, notmuch); } } -#else -static inline void -_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch) -{ - _setup_query_field_default (prefix, notmuch); -} -#endif const char * _find_prefix (const char *name) @@ -359,6 +429,26 @@ _find_prefix (const char *name) return ""; } +/* Like find prefix, but include the possibility of user defined + * prefixes specific to this database */ + +const char * +_notmuch_database_prefix (notmuch_database_t *notmuch, const char *name) +{ + unsigned int i; + + /*XXX TODO: reduce code duplication */ + for (i = 0; i < ARRAY_SIZE (prefix_table); i++) { + if (strcmp (name, prefix_table[i].name) == 0) + return prefix_table[i].prefix; + } + + if (notmuch->user_prefix) + return _notmuch_string_map_get (notmuch->user_prefix, name); + + return NULL; +} + static const struct { /* NOTMUCH_FEATURE_* value. */ _notmuch_features value; @@ -380,14 +470,18 @@ static const struct { { NOTMUCH_FEATURE_BOOL_FOLDER, "exact folder:/path: search", "rw" }, { NOTMUCH_FEATURE_GHOSTS, - "mail documents for missing messages", "w"}, + "mail documents for missing messages", "w" }, /* Knowledge of the index mime-types are not required for reading * a database because a reader will just be unable to query * them. */ { NOTMUCH_FEATURE_INDEXED_MIMETYPES, - "indexed MIME types", "w"}, + "indexed MIME types", "w" }, { NOTMUCH_FEATURE_LAST_MOD, - "modification tracking", "w"}, + "modification tracking", "w" }, + /* Existing databases will work fine for all queries not involving + * 'body:' */ + { NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY, + "index body and headers separately", "w" }, }; const char * @@ -436,8 +530,8 @@ notmuch_status_to_string (notmuch_status_t status) void _notmuch_database_log (notmuch_database_t *notmuch, - const char *format, - ...) + const char *format, + ...) { va_list va_args; @@ -452,8 +546,8 @@ _notmuch_database_log (notmuch_database_t *notmuch, void _notmuch_database_log_append (notmuch_database_t *notmuch, - const char *format, - ...) + const char *format, + ...) { va_list va_args; @@ -576,7 +670,7 @@ notmuch_database_find_message (notmuch_database_t *notmuch, return NOTMUCH_STATUS_SUCCESS; } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "A Xapian exception occurred finding message: %s.\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); notmuch->exception_reported = true; *message_ret = NULL; return NOTMUCH_STATUS_XAPIAN_EXCEPTION; @@ -627,7 +721,7 @@ notmuch_database_create_verbose (const char *path, err = stat (path, &st); if (err) { IGNORE_RESULT (asprintf (&message, "Error: Cannot create database at %s: %s.\n", - path, strerror (errno))); + path, strerror (errno))); status = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } @@ -661,10 +755,11 @@ notmuch_database_create_verbose (const char *path, * new databases have them. */ notmuch->features |= NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES; notmuch->features |= NOTMUCH_FEATURE_INDEXED_MIMETYPES; + notmuch->features |= NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY; status = notmuch_database_upgrade (notmuch, NULL, NULL); if (status) { - notmuch_database_close(notmuch); + notmuch_database_close (notmuch); notmuch = NULL; } @@ -799,7 +894,7 @@ notmuch_database_open (const char *path, notmuch_status_t status; status = notmuch_database_open_verbose (path, mode, database, - &status_string); + &status_string); if (status_string) { fputs (status_string, stderr); @@ -858,13 +953,13 @@ notmuch_database_open_verbose (const char *path, } /* Initialize the GLib type system and threads */ -#if !GLIB_CHECK_VERSION(2, 35, 1) +#if ! GLIB_CHECK_VERSION (2, 35, 1) g_type_init (); #endif /* Initialize gmime */ if (! initialized) { - g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS); + g_mime_init (); initialized = 1; } @@ -873,7 +968,7 @@ notmuch_database_open_verbose (const char *path, notmuch->status_string = NULL; notmuch->path = talloc_strdup (notmuch, path); - strip_trailing(notmuch->path, '/'); + strip_trailing (notmuch->path, '/'); notmuch->mode = mode; notmuch->atomic_nesting = 0; @@ -895,9 +990,9 @@ notmuch_database_open_verbose (const char *path, version = notmuch_database_get_version (notmuch); if (version > NOTMUCH_DATABASE_VERSION) { IGNORE_RESULT (asprintf (&message, - "Error: Notmuch database at %s\n" - " has a newer database format version (%u) than supported by this\n" - " version of notmuch (%u).\n", + "Error: Notmuch database at %s\n" + " has a newer database format version (%u) than supported by this\n" + " version of notmuch (%u).\n", notmuch_path, version, NOTMUCH_DATABASE_VERSION)); notmuch->mode = NOTMUCH_DATABASE_MODE_READ_ONLY; notmuch_database_destroy (notmuch); @@ -914,9 +1009,9 @@ notmuch_database_open_verbose (const char *path, &incompat_features); if (incompat_features) { IGNORE_RESULT (asprintf (&message, - "Error: Notmuch database at %s\n" - " requires features (%s)\n" - " not supported by this version of notmuch.\n", + "Error: Notmuch database at %s\n" + " requires features (%s)\n" + " not supported by this version of notmuch.\n", notmuch_path, incompat_features)); notmuch->mode = NOTMUCH_DATABASE_MODE_READ_ONLY; notmuch_database_destroy (notmuch); @@ -952,17 +1047,16 @@ notmuch_database_open_verbose (const char *path, notmuch->query_parser = new Xapian::QueryParser; notmuch->term_gen = new Xapian::TermGenerator; notmuch->term_gen->set_stemmer (Xapian::Stem ("english")); - notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); - notmuch->date_range_processor = new ParseTimeValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); - notmuch->last_mod_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:"); - + notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); + notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP, "date:"); + notmuch->last_mod_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:"); notmuch->query_parser->set_default_op (Xapian::Query::OP_AND); notmuch->query_parser->set_database (*notmuch->xapian_db); notmuch->query_parser->set_stemmer (Xapian::Stem ("english")); notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME); - notmuch->query_parser->add_valuerangeprocessor (notmuch->value_range_processor); - notmuch->query_parser->add_valuerangeprocessor (notmuch->date_range_processor); - notmuch->query_parser->add_valuerangeprocessor (notmuch->last_mod_range_processor); + notmuch->query_parser->add_rangeprocessor (notmuch->value_range_processor); + notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor); + notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor); for (i = 0; i < ARRAY_SIZE (prefix_table); i++) { const prefix_t *prefix = &prefix_table[i]; @@ -970,9 +1064,10 @@ notmuch_database_open_verbose (const char *path, _setup_query_field (prefix, notmuch); } } + status = _setup_user_query_fields (notmuch); } catch (const Xapian::Error &error) { IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n", - error.get_msg().c_str())); + error.get_msg ().c_str ())); notmuch_database_destroy (notmuch); notmuch = NULL; status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; @@ -992,6 +1087,10 @@ notmuch_database_open_verbose (const char *path, *database = notmuch; else talloc_free (notmuch); + + if (notmuch) + notmuch->open = true; + return status; } @@ -1003,7 +1102,7 @@ notmuch_database_close (notmuch_database_t *notmuch) /* Many Xapian objects (and thus notmuch objects) hold references to * the database, so merely deleting the database may not suffice to * close it. Thus, we explicitly close it here. */ - if (notmuch->xapian_db != NULL) { + if (notmuch->open) { try { /* If there's an outstanding transaction, it's unclear if * closing the Xapian database commits everything up to @@ -1013,33 +1112,20 @@ notmuch_database_close (notmuch_database_t *notmuch) if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE && notmuch->atomic_nesting) (static_cast (notmuch->xapian_db)) - ->cancel_transaction (); + ->cancel_transaction (); /* Close the database. This implicitly flushes * outstanding changes. */ - notmuch->xapian_db->close(); + notmuch->xapian_db->close (); } catch (const Xapian::Error &error) { status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; if (! notmuch->exception_reported) { _notmuch_database_log (notmuch, "Error: A Xapian exception occurred closing database: %s\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); } } } - - delete notmuch->term_gen; - notmuch->term_gen = NULL; - delete notmuch->query_parser; - notmuch->query_parser = NULL; - delete notmuch->xapian_db; - notmuch->xapian_db = NULL; - delete notmuch->value_range_processor; - notmuch->value_range_processor = NULL; - delete notmuch->date_range_processor; - notmuch->date_range_processor = NULL; - delete notmuch->last_mod_range_processor; - notmuch->last_mod_range_processor = NULL; - + notmuch->open = false; return status; } @@ -1087,7 +1173,9 @@ class NotmuchCompactor : public Xapian::Compactor public: NotmuchCompactor(notmuch_compact_status_cb_t cb, void *closure) : - status_cb (cb), status_closure (closure) { } + status_cb (cb), status_closure (closure) + { + } virtual void set_status (const std::string &table, const std::string &status) @@ -1098,9 +1186,9 @@ public: return; if (status.length () == 0) - msg = talloc_asprintf (NULL, "compacting table %s", table.c_str()); + msg = talloc_asprintf (NULL, "compacting table %s", table.c_str ()); else - msg = talloc_asprintf (NULL, " %s", status.c_str()); + msg = talloc_asprintf (NULL, " %s", status.c_str ()); if (msg == NULL) { return; @@ -1170,8 +1258,7 @@ notmuch_database_compact (const char *path, goto DONE; } keep_backup = false; - } - else { + } else { keep_backup = true; } @@ -1182,7 +1269,7 @@ notmuch_database_compact (const char *path, } if (errno != ENOENT) { _notmuch_database_log (notmuch, "Unknown error while stat()ing path: %s\n", - strerror (errno)); + strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } @@ -1195,27 +1282,23 @@ notmuch_database_compact (const char *path, try { NotmuchCompactor compactor (status_cb, closure); - - compactor.set_renumber (false); - compactor.add_source (xapian_path); - compactor.set_destdir (compact_xapian_path); - compactor.compact (); + notmuch->xapian_db->compact (compact_xapian_path, Xapian::DBCOMPACT_NO_RENUMBER, 0, compactor); } catch (const Xapian::Error &error) { - _notmuch_database_log (notmuch, "Error while compacting: %s\n", error.get_msg().c_str()); + _notmuch_database_log (notmuch, "Error while compacting: %s\n", error.get_msg ().c_str ()); ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION; goto DONE; } if (rename (xapian_path, backup_path)) { _notmuch_database_log (notmuch, "Error moving %s to %s: %s\n", - xapian_path, backup_path, strerror (errno)); + xapian_path, backup_path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } if (rename (compact_xapian_path, xapian_path)) { _notmuch_database_log (notmuch, "Error moving %s to %s: %s\n", - compact_xapian_path, xapian_path, strerror (errno)); + compact_xapian_path, xapian_path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } @@ -1223,7 +1306,7 @@ notmuch_database_compact (const char *path, if (! keep_backup) { if (rmtree (backup_path)) { _notmuch_database_log (notmuch, "Error removing old database %s: %s\n", - backup_path, strerror (errno)); + backup_path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } @@ -1255,6 +1338,20 @@ notmuch_database_destroy (notmuch_database_t *notmuch) notmuch_status_t status; status = notmuch_database_close (notmuch); + + delete notmuch->term_gen; + notmuch->term_gen = NULL; + delete notmuch->query_parser; + notmuch->query_parser = NULL; + delete notmuch->xapian_db; + notmuch->xapian_db = NULL; + delete notmuch->value_range_processor; + notmuch->value_range_processor = NULL; + delete notmuch->date_range_processor; + notmuch->date_range_processor = NULL; + delete notmuch->last_mod_range_processor; + notmuch->last_mod_range_processor = NULL; + talloc_free (notmuch); return status; @@ -1274,7 +1371,13 @@ notmuch_database_get_version (notmuch_database_t *notmuch) const char *str; char *end; - version_string = notmuch->xapian_db->get_metadata ("version"); + try { + version_string = notmuch->xapian_db->get_metadata ("version"); + } catch (const Xapian::Error &error) { + LOG_XAPIAN_EXCEPTION (notmuch, error); + return 0; + } + if (version_string.empty ()) return 0; @@ -1292,9 +1395,17 @@ notmuch_database_get_version (notmuch_database_t *notmuch) notmuch_bool_t notmuch_database_needs_upgrade (notmuch_database_t *notmuch) { - return notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE && - ((NOTMUCH_FEATURES_CURRENT & ~notmuch->features) || - (notmuch_database_get_version (notmuch) < NOTMUCH_DATABASE_VERSION)); + unsigned int version; + + if (notmuch->mode != NOTMUCH_DATABASE_MODE_READ_WRITE) + return FALSE; + + if (NOTMUCH_FEATURES_CURRENT & ~notmuch->features) + return TRUE; + + version = notmuch_database_get_version (notmuch); + + return (version > 0 && version < NOTMUCH_DATABASE_VERSION); } static volatile sig_atomic_t do_progress_notify = 0; @@ -1415,8 +1526,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, goto DONE; for (; notmuch_messages_valid (messages); - notmuch_messages_move_to_next (messages)) - { + notmuch_messages_move_to_next (messages)) { if (do_progress_notify) { progress_notify (closure, (double) count / total); do_progress_notify = 0; @@ -1473,8 +1583,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, for (t = notmuch->xapian_db->allterms_begin ("XTIMESTAMP"); t != t_end; - t++) - { + t++) { Xapian::PostingIterator p, p_end; std::string term = *t; @@ -1482,8 +1591,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, for (p = notmuch->xapian_db->postlist_begin (term); p != p_end; - p++) - { + p++) { Xapian::Document document; time_t mtime; notmuch_directory_t *directory; @@ -1497,7 +1605,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, mtime = Xapian::sortable_unserialise ( document.get_value (NOTMUCH_VALUE_TIMESTAMP)); - directory = _notmuch_directory_create (notmuch, term.c_str() + 10, + directory = _notmuch_directory_create (notmuch, term.c_str () + 10, NOTMUCH_FIND_CREATE, &status); notmuch_directory_set_mtime (directory, mtime); notmuch_directory_destroy (directory); @@ -1546,7 +1654,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, if (private_status) { _notmuch_database_log (notmuch, - "Upgrade failed while creating ghost messages.\n"); + "Upgrade failed while creating ghost messages.\n"); status = COERCE_STATUS (private_status, "Unexpected status from _notmuch_message_initialize_ghost"); goto DONE; } @@ -1562,7 +1670,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, db->set_metadata ("features", _print_features (local, notmuch->features)); db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION)); - DONE: + DONE: if (status == NOTMUCH_STATUS_SUCCESS) db->commit_transaction (); else @@ -1602,12 +1710,12 @@ notmuch_database_begin_atomic (notmuch_database_t *notmuch) (static_cast (notmuch->xapian_db))->begin_transaction (false); } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "A Xapian exception occurred beginning transaction: %s.\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); notmuch->exception_reported = true; return NOTMUCH_STATUS_XAPIAN_EXCEPTION; } -DONE: + DONE: notmuch->atomic_nesting++; return NOTMUCH_STATUS_SUCCESS; } @@ -1636,7 +1744,7 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch) db->commit (); } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "A Xapian exception occurred committing transaction: %s.\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); notmuch->exception_reported = true; return NOTMUCH_STATUS_XAPIAN_EXCEPTION; } @@ -1646,14 +1754,14 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch) notmuch->atomic_dirty = false; } -DONE: + DONE: notmuch->atomic_nesting--; return NOTMUCH_STATUS_SUCCESS; } unsigned long notmuch_database_get_revision (notmuch_database_t *notmuch, - const char **uuid) + const char **uuid) { if (uuid) *uuid = notmuch->uuid; @@ -1771,7 +1879,7 @@ _notmuch_database_find_directory_id (notmuch_database_t *notmuch, } directory = _notmuch_directory_create (notmuch, path, flags, &status); - if (status || !directory) { + if (status || ! directory) { *directory_id = -1; return status; } @@ -1825,7 +1933,7 @@ _notmuch_database_filename_to_direntry (void *ctx, status = _notmuch_database_find_directory_id (notmuch, directory, flags, &directory_id); - if (status || directory_id == (unsigned int)-1) { + if (status || directory_id == (unsigned int) -1) { *direntry = NULL; return status; } @@ -1855,11 +1963,10 @@ _notmuch_database_relative_path (notmuch_database_t *notmuch, relative = path; if (*relative == '/') { - while (*relative == '/' && *(relative+1) == '/') + while (*relative == '/' && *(relative + 1) == '/') relative++; - if (strncmp (relative, db_path, db_path_len) == 0) - { + if (strncmp (relative, db_path, db_path_len) == 0) { relative += db_path_len; while (*relative == '/') relative++; @@ -1885,7 +1992,7 @@ notmuch_database_get_directory (notmuch_database_t *notmuch, NOTMUCH_FIND_LOOKUP, &status); } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "A Xapian exception occurred getting directory: %s.\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); notmuch->exception_reported = true; status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; } @@ -1928,13 +2035,13 @@ notmuch_database_remove_message (notmuch_database_t *notmuch, &message); if (status == NOTMUCH_STATUS_SUCCESS && message) { - status = _notmuch_message_remove_filename (message, filename); - if (status == NOTMUCH_STATUS_SUCCESS) - _notmuch_message_delete (message); - else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) - _notmuch_message_sync (message); + status = _notmuch_message_remove_filename (message, filename); + if (status == NOTMUCH_STATUS_SUCCESS) + _notmuch_message_delete (message); + else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) + _notmuch_message_sync (message); - notmuch_message_destroy (message); + notmuch_message_destroy (message); } return status; @@ -1965,7 +2072,7 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch, try { status = _notmuch_database_filename_to_direntry ( local, notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry); - if (status || !direntry) + if (status || ! direntry) goto DONE; term = talloc_asprintf (local, "%s%s", prefix, direntry); @@ -1982,7 +2089,7 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch, } } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "Error: A Xapian exception occurred finding message by filename: %s\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); notmuch->exception_reported = true; status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; } @@ -2027,15 +2134,15 @@ notmuch_database_get_all_tags (notmuch_database_t *db) notmuch_string_list_t *tags; try { - i = db->xapian_db->allterms_begin(); - end = db->xapian_db->allterms_end(); + i = db->xapian_db->allterms_begin (); + end = db->xapian_db->allterms_end (); tags = _notmuch_database_get_terms_with_prefix (db, i, end, _find_prefix ("tag")); _notmuch_string_list_sort (tags); return _notmuch_tags_create (db, tags); } catch (const Xapian::Error &error) { _notmuch_database_log (db, "A Xapian exception occurred getting tags: %s.\n", - error.get_msg().c_str()); + error.get_msg ().c_str ()); db->exception_reported = true; return NULL; }