]> git.notmuchmail.org Git - notmuch/blobdiff - lib/database.cc
lib: create field processors from prefix table
[notmuch] / lib / database.cc
index f0bfe5667fba4736996583830047d7529cd390fc..fa4c31167407576f4f4c431ad0330868033381bc 100644 (file)
@@ -42,6 +42,7 @@ using namespace std;
 typedef struct {
     const char *name;
     const char *prefix;
+    notmuch_field_flag_t flags;
 } prefix_t;
 
 #define NOTMUCH_DATABASE_VERSION 3
@@ -247,57 +248,91 @@ typedef struct {
  * nearly universal to all mail messages).
  */
 
-static prefix_t BOOLEAN_PREFIX_INTERNAL[] = {
-    { "type",                  "T" },
-    { "reference",             "XREFERENCE" },
-    { "replyto",               "XREPLYTO" },
-    { "directory",             "XDIRECTORY" },
-    { "file-direntry",         "XFDIRENTRY" },
-    { "directory-direntry",    "XDDIRENTRY" },
-};
-
-static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
-    { "thread",                        "G" },
-    { "tag",                   "K" },
-    { "is",                    "K" },
-    { "id",                    "Q" },
-    { "path",                  "P" },
-    { "property",              "XPROPERTY" },
+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 },
+    { "tag",                   "K",            NOTMUCH_FIELD_EXTERNAL },
+    { "is",                    "K",            NOTMUCH_FIELD_EXTERNAL },
+    { "id",                    "Q",            NOTMUCH_FIELD_EXTERNAL },
+    { "path",                  "P",            NOTMUCH_FIELD_EXTERNAL },
+    { "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:" },
+    { "folder",                        "XFOLDER:",     NOTMUCH_FIELD_EXTERNAL },
+#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 },
+    { "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 },
 };
 
-static prefix_t PROBABILISTIC_PREFIX[]= {
-    { "from",                  "XFROM" },
-    { "to",                    "XTO" },
-    { "attachment",            "XATTACHMENT" },
-    { "mimetype",              "XMIMETYPE"},
-    { "subject",               "XSUBJECT"},
-};
+static void
+_setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+    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);
+}
 
-const char *
-_find_prefix (const char *name)
+#if HAVE_XAPIAN_FIELD_PROCESSOR
+static void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
 {
-    unsigned int i;
+    if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
+       Xapian::FieldProcessor *fp;
 
-    for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_INTERNAL); i++) {
-       if (strcmp (name, BOOLEAN_PREFIX_INTERNAL[i].name) == 0)
-           return BOOLEAN_PREFIX_INTERNAL[i].prefix;
-    }
+       if (STRNCMP_LITERAL (prefix->name, "date") == 0)
+           fp = (new DateFieldProcessor())->release ();
+       else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
+           fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
+       else
+           INTERNAL_ERROR("unsupported field processor prefix: %s\n", prefix->name);
 
-    for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) {
-       if (strcmp (name, BOOLEAN_PREFIX_EXTERNAL[i].name) == 0)
-           return BOOLEAN_PREFIX_EXTERNAL[i].prefix;
+       /* we treat all field-processor fields as boolean in order to get the raw input */
+       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)
+{
+    unsigned int i;
 
-    for (i = 0; i < ARRAY_SIZE (PROBABILISTIC_PREFIX); i++) {
-       if (strcmp (name, PROBABILISTIC_PREFIX[i].name) == 0)
-           return PROBABILISTIC_PREFIX[i].prefix;
+    for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
+       if (strcmp (name, prefix_table[i].name) == 0)
+           return prefix_table[i].prefix;
     }
 
     INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
@@ -652,7 +687,7 @@ parse_references (void *ctx,
        ref = _parse_message_id (ctx, refs, &refs);
 
        if (ref && strcmp (ref, message_id)) {
-           g_hash_table_insert (hash, ref, NULL);
+           g_hash_table_add (hash, ref);
            last_ref = ref;
        }
     }
@@ -661,7 +696,7 @@ parse_references (void *ctx,
      * reference to the database.  We should avoid making a message
      * its own parent, thus the above check.
      */
-    return last_ref;
+    return talloc_strdup(ctx, last_ref);
 }
 
 notmuch_status_t
@@ -959,6 +994,7 @@ notmuch_database_open_verbose (const char *path,
 
     notmuch->mode = mode;
     notmuch->atomic_nesting = 0;
+    notmuch->view = 1;
     try {
        string last_thread_id;
        string last_mod;
@@ -1035,14 +1071,6 @@ notmuch_database_open_verbose (const char *path,
        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);
-#if HAVE_XAPIAN_FIELD_PROCESSOR
-       /* This currently relies on the query parser to pass anything
-        * with a .. to the range processor */
-       notmuch->date_field_processor = new DateFieldProcessor();
-       notmuch->query_parser->add_boolean_prefix("date", notmuch->date_field_processor);
-       notmuch->query_field_processor = new QueryFieldProcessor (*notmuch->query_parser, notmuch);
-       notmuch->query_parser->add_boolean_prefix("query", notmuch->query_field_processor);
-#endif
        notmuch->last_mod_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
 
        notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
@@ -1053,15 +1081,11 @@ notmuch_database_open_verbose (const char *path,
        notmuch->query_parser->add_valuerangeprocessor (notmuch->date_range_processor);
        notmuch->query_parser->add_valuerangeprocessor (notmuch->last_mod_range_processor);
 
-       for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) {
-           prefix_t *prefix = &BOOLEAN_PREFIX_EXTERNAL[i];
-           notmuch->query_parser->add_boolean_prefix (prefix->name,
-                                                      prefix->prefix);
-       }
-
-       for (i = 0; i < ARRAY_SIZE (PROBABILISTIC_PREFIX); i++) {
-           prefix_t *prefix = &PROBABILISTIC_PREFIX[i];
-           notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
+       for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
+           const prefix_t *prefix = &prefix_table[i];
+           if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
+               _setup_query_field (prefix, notmuch);
+           }
        }
     } catch (const Xapian::Error &error) {
        IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
@@ -1133,16 +1157,31 @@ notmuch_database_close (notmuch_database_t *notmuch)
     delete notmuch->last_mod_range_processor;
     notmuch->last_mod_range_processor = NULL;
 
-#if HAVE_XAPIAN_FIELD_PROCESSOR
-    delete notmuch->date_field_processor;
-    notmuch->date_field_processor = NULL;
-    delete notmuch->query_field_processor;
-    notmuch->query_field_processor = NULL;
-#endif
-
     return status;
 }
 
+notmuch_status_t
+_notmuch_database_reopen (notmuch_database_t *notmuch)
+{
+    if (notmuch->mode != NOTMUCH_DATABASE_MODE_READ_ONLY)
+       return NOTMUCH_STATUS_UNSUPPORTED_OPERATION;
+
+    try {
+       notmuch->xapian_db->reopen ();
+    } catch (const Xapian::Error &error) {
+       if (! notmuch->exception_reported) {
+           _notmuch_database_log (notmuch, "Error: A Xapian exception reopening database: %s\n",
+                                  error.get_msg ().c_str ());
+           notmuch->exception_reported = TRUE;
+       }
+       return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+    }
+
+    notmuch->view++;
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
 static int
 unlink_cb (const char *path,
           unused (const struct stat *sb),
@@ -1711,7 +1750,7 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch)
         * However, we rely on flushing to test atomicity. */
        const char *thresh = getenv ("XAPIAN_FLUSH_THRESHOLD");
        if (thresh && atoi (thresh) == 1)
-           db->flush ();
+           db->commit ();
     } catch (const Xapian::Error &error) {
        _notmuch_database_log (notmuch, "A Xapian exception occurred committing transaction: %s.\n",
                 error.get_msg().c_str());