1 /* database-private.h - For peeking into the internals of notmuch_database_t
3 * Copyright © 2009 Carl Worth
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see https://www.gnu.org/licenses/ .
18 * Author: Carl Worth <cworth@cworth.org>
21 #ifndef NOTMUCH_DATABASE_PRIVATE_H
22 #define NOTMUCH_DATABASE_PRIVATE_H
24 /* According to WG14/N1124, a C++ implementation won't provide us a
25 * macro like PRIx64 (which gives a printf format string for
26 * formatting a uint64_t as hexadecimal) unless we define
27 * __STDC_FORMAT_MACROS before including inttypes.h. That's annoying,
30 #define __STDC_FORMAT_MACROS
33 #include "notmuch-private.h"
35 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
37 #ifdef SILENCE_XAPIAN_DEPRECATION_WARNINGS
38 #define XAPIAN_DEPRECATED(D) D
47 /* Bit masks for _notmuch_database::features. Features are named,
48 * independent aspects of the database schema.
50 * A database stores the set of features that it "uses" (implicitly
51 * before database version 3 and explicitly as of version 3).
53 * A given library version will "recognize" a particular set of
54 * features; if a database uses a feature that the library does not
55 * recognize, the library will refuse to open it. It is assumed the
56 * set of recognized features grows monotonically over time. A
57 * library version will "implement" some subset of the recognized
58 * features: some operations may require that the database use (or not
59 * use) some feature, while other operations may support both
60 * databases that use and that don't use some feature.
62 * On disk, the database stores string names for these features (see
63 * the feature_names array). These enum bit values are never
64 * persisted to disk and may change freely.
66 enum _notmuch_features {
67 /* If set, file names are stored in "file-direntry" terms. If
68 * unset, file names are stored in document data.
70 * Introduced: version 1. */
71 NOTMUCH_FEATURE_FILE_TERMS = 1 << 0,
73 /* If set, directory timestamps are stored in documents with
74 * XDIRECTORY terms and relative paths. If unset, directory
75 * timestamps are stored in documents with XTIMESTAMP terms and
78 * Introduced: version 1. */
79 NOTMUCH_FEATURE_DIRECTORY_DOCS = 1 << 1,
81 /* If set, the from, subject, and message-id headers are stored in
82 * message document values. If unset, message documents *may*
83 * have these values, but if the value is empty, it must be
84 * retrieved from the message file.
86 * Introduced: optional in version 1, required as of version 3.
88 NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES = 1 << 2,
90 /* If set, folder terms are boolean and path terms exist. If
91 * unset, folder terms are probabilistic and stemmed and path
94 * Introduced: version 2. */
95 NOTMUCH_FEATURE_BOOL_FOLDER = 1 << 3,
97 /* If set, missing messages are stored in ghost mail documents.
98 * If unset, thread IDs of ghost messages are stored as database
99 * metadata instead of in ghost documents.
101 * Introduced: version 3. */
102 NOTMUCH_FEATURE_GHOSTS = 1 << 4,
105 /* If set, then the database was created after the introduction of
106 * indexed mime types. If unset, then the database may contain a
107 * mixture of messages with indexed and non-indexed mime types.
109 * Introduced: version 3. */
110 NOTMUCH_FEATURE_INDEXED_MIMETYPES = 1 << 5,
112 /* If set, messages store the revision number of the last
113 * modification in NOTMUCH_VALUE_LAST_MOD.
115 * Introduced: version 3. */
116 NOTMUCH_FEATURE_LAST_MOD = 1 << 6,
118 /* If set, unprefixed terms are stored only for the message body,
121 * Introduced: version 3. */
122 NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY = 1 << 7,
125 /* In C++, a named enum is its own type, so define bitwise operators
126 * on _notmuch_features. */
127 inline _notmuch_features
128 operator| (_notmuch_features a, _notmuch_features b)
130 return static_cast<_notmuch_features>(
131 static_cast<unsigned>(a) | static_cast<unsigned>(b));
134 inline _notmuch_features
135 operator& (_notmuch_features a, _notmuch_features b)
137 return static_cast<_notmuch_features>(
138 static_cast<unsigned>(a) & static_cast<unsigned>(b));
141 inline _notmuch_features
142 operator~ (_notmuch_features a)
144 return static_cast<_notmuch_features>(~static_cast<unsigned>(a));
147 inline _notmuch_features&
148 operator|= (_notmuch_features &a, _notmuch_features b)
154 inline _notmuch_features&
155 operator&= (_notmuch_features &a, _notmuch_features b)
162 * Configuration options for xapian database fields */
164 NOTMUCH_FIELD_NO_FLAGS = 0,
165 NOTMUCH_FIELD_EXTERNAL = 1 << 0,
166 NOTMUCH_FIELD_PROBABILISTIC = 1 << 1,
167 NOTMUCH_FIELD_PROCESSOR = 1 << 2,
168 NOTMUCH_FIELD_STRIP_TRAILING_SLASH = 1 << 3,
169 } notmuch_field_flag_t;
172 * define bitwise operators to hide casts */
173 inline notmuch_field_flag_t
174 operator| (notmuch_field_flag_t a, notmuch_field_flag_t b)
176 return static_cast<notmuch_field_flag_t>(
177 static_cast<unsigned>(a) | static_cast<unsigned>(b));
180 inline notmuch_field_flag_t
181 operator& (notmuch_field_flag_t a, notmuch_field_flag_t b)
183 return static_cast<notmuch_field_flag_t>(
184 static_cast<unsigned>(a) & static_cast<unsigned>(b));
187 #define NOTMUCH_QUERY_PARSER_FLAGS (Xapian::QueryParser::FLAG_BOOLEAN | \
188 Xapian::QueryParser::FLAG_PHRASE | \
189 Xapian::QueryParser::FLAG_LOVEHATE | \
190 Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE | \
191 Xapian::QueryParser::FLAG_WILDCARD | \
192 Xapian::QueryParser::FLAG_PURE_NOT)
195 * explicit and implied parameters to open */
197 NOTMUCH_PARAM_NONE = 0,
198 /* database passed explicitely */
199 NOTMUCH_PARAM_DATABASE = 1 << 0,
200 /* config file passed explicitely */
201 NOTMUCH_PARAM_CONFIG = 1 << 1,
202 /* profile name passed explicitely */
203 NOTMUCH_PARAM_PROFILE = 1 << 2,
204 /* split (e.g. XDG) configuration */
205 NOTMUCH_PARAM_SPLIT = 1 << 3,
206 } notmuch_open_param_t;
209 * define bitwise operators to hide casts */
211 inline notmuch_open_param_t
212 operator| (notmuch_open_param_t a, notmuch_open_param_t b)
214 return static_cast<notmuch_open_param_t>(
215 static_cast<unsigned>(a) | static_cast<unsigned>(b));
218 inline notmuch_open_param_t&
219 operator|= (notmuch_open_param_t &a, notmuch_open_param_t b)
225 inline notmuch_open_param_t
226 operator& (notmuch_open_param_t a, notmuch_open_param_t b)
228 return static_cast<notmuch_open_param_t>(
229 static_cast<unsigned>(a) & static_cast<unsigned>(b));
232 struct _notmuch_database {
233 bool exception_reported;
235 /* Path to actual database */
236 const char *xapian_path;
238 /* Path to config loaded, if any */
239 const char *config_path;
242 /* true if changes have been made in this atomic section */
244 Xapian::Database *xapian_db;
245 Xapian::WritableDatabase *writable_xapian_db;
247 /* Bit mask of features used by this database. This is a
248 * bitwise-OR of NOTMUCH_FEATURE_* values (above). */
249 enum _notmuch_features features;
251 unsigned int last_doc_id;
253 /* 16 bytes (+ terminator) for hexadecimal representation of
254 * a 64-bit integer. */
255 char thread_id_str[17];
256 uint64_t last_thread_id;
258 /* How many transactions have successfully completed since we last committed */
259 int transaction_count;
260 /* when to commit and reset the counter */
261 int transaction_threshold;
263 /* error reporting; this value persists only until the
264 * next library call. May be NULL */
267 /* Highest committed revision number. Modifications are recorded
268 * under a higher revision number, which can be generated with
269 * notmuch_database_new_revision. */
270 unsigned long revision;
273 /* Keep track of the number of times the database has been re-opened
274 * (or other global invalidations of notmuch's caching)
277 Xapian::QueryParser *query_parser;
278 Xapian::Stem *stemmer;
279 Xapian::TermGenerator *term_gen;
280 Xapian::RangeProcessor *value_range_processor;
281 Xapian::RangeProcessor *date_range_processor;
282 Xapian::RangeProcessor *last_mod_range_processor;
284 /* XXX it's slightly gross to use two parallel string->string maps
285 * here, but at least they are small */
286 notmuch_string_map_t *user_prefix;
287 notmuch_string_map_t *user_header;
289 /* Cached and possibly overridden configuration */
290 notmuch_string_map_t *config;
292 /* Track what parameters were specified when opening */
293 notmuch_open_param_t params;
295 /* list of regular expressions to check for text indexing */
296 regex_t *index_as_text;
297 size_t index_as_text_length;
300 /* Prior to database version 3, features were implied by the database
301 * version number, so hard-code them for earlier versions. */
302 #define NOTMUCH_FEATURES_V0 ((enum _notmuch_features) 0)
303 #define NOTMUCH_FEATURES_V1 (NOTMUCH_FEATURES_V0 | NOTMUCH_FEATURE_FILE_TERMS | \
304 NOTMUCH_FEATURE_DIRECTORY_DOCS)
305 #define NOTMUCH_FEATURES_V2 (NOTMUCH_FEATURES_V1 | NOTMUCH_FEATURE_BOOL_FOLDER)
307 /* Current database features. If any of these are missing from a
308 * database, request an upgrade.
309 * NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES and
310 * NOTMUCH_FEATURE_INDEXED_MIMETYPES are not included because upgrade
311 * doesn't currently introduce the features (though brand new databases
313 #define NOTMUCH_FEATURES_CURRENT \
314 (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_DIRECTORY_DOCS | \
315 NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS | \
316 NOTMUCH_FEATURE_LAST_MOD)
318 /* Return the list of terms from the given iterator matching a prefix.
319 * The prefix will be stripped from the strings in the returned list.
320 * The list will be allocated using ctx as the talloc context.
322 * The function returns NULL on failure.
324 notmuch_string_list_t *
325 _notmuch_database_get_terms_with_prefix (void *ctx, Xapian::TermIterator &i,
326 Xapian::TermIterator &end,
330 _notmuch_database_find_doc_ids (notmuch_database_t *notmuch,
331 const char *prefix_name,
333 Xapian::PostingIterator *begin,
334 Xapian::PostingIterator *end);
336 #define NOTMUCH_DATABASE_VERSION 3
341 _notmuch_database_parse_features (const void *ctx, const char *features, unsigned int version,
342 char mode, char **incompat_out);
345 _notmuch_database_print_features (const void *ctx, unsigned int features);
349 _notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch);
352 _notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch);
357 _notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch,
358 std::string query_string,
359 Xapian::Query &output,
363 _notmuch_query_expand (notmuch_database_t *notmuch, const char *field, Xapian::Query subquery,
364 Xapian::Query &output, std::string &msg);
366 /* regexp-fields.cc */
368 _notmuch_regexp_to_query (notmuch_database_t *notmuch, Xapian::valueno slot, std::string field,
369 std::string regexp_str,
370 Xapian::Query &output, std::string &msg);
374 _notmuch_query_name_to_query (notmuch_database_t *notmuch, const std::string name,
375 Xapian::Query &output);
380 _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr,
381 Xapian::Query &output);
384 /* parse-time-vrp.h */
386 _notmuch_date_strings_to_query (Xapian::valueno slot, const std::string &from, const std::string &to,
387 Xapian::Query &output, std::string &msg);
391 _notmuch_lastmod_strings_to_query (notmuch_database_t *notmuch,
392 const std::string &from, const std::string &to,
393 Xapian::Query &output, std::string &msg);