Xapian::ValueRangeProcessor *value_range_processor;
     Xapian::ValueRangeProcessor *date_range_processor;
     Xapian::ValueRangeProcessor *last_mod_range_processor;
+
+    /* XXX it's slightly gross to use two parallel string->string maps
+     * here, but at least they are small */
+    notmuch_string_map_t *user_prefix;
+    notmuch_string_map_t *user_header;
 };
 
 /* Prior to database version 3, features were implied by the database
 
     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;
        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
 
 #define THREAD_DEBUG(format, ...) do {} while (0) /* ignored */
 #endif
 
-#define EMPTY_STRING(s) ((s)[0] == '\0')
-
 struct _notmuch_thread {
     notmuch_database_t *notmuch;
     char *thread_id;