]> git.notmuchmail.org Git - notmuch/blob - lib/database-private.h
emacs: Add new option notmuch-search-hide-excluded
[notmuch] / lib / database-private.h
1 /* database-private.h - For peeking into the internals of notmuch_database_t
2  *
3  * Copyright © 2009 Carl Worth
4  *
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.
9  *
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.
14  *
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/ .
17  *
18  * Author: Carl Worth <cworth@cworth.org>
19  */
20
21 #ifndef NOTMUCH_DATABASE_PRIVATE_H
22 #define NOTMUCH_DATABASE_PRIVATE_H
23
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,
28  * but there it is.
29  */
30 #define __STDC_FORMAT_MACROS
31 #include <inttypes.h>
32
33 #include "notmuch-private.h"
34
35 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
36
37 #ifdef SILENCE_XAPIAN_DEPRECATION_WARNINGS
38 #define XAPIAN_DEPRECATED(D) D
39 #endif
40
41 #include <xapian.h>
42
43 #if HAVE_SFSEXP
44 #include <sexp.h>
45 #endif
46
47 /* Bit masks for _notmuch_database::features.  Features are named,
48  * independent aspects of the database schema.
49  *
50  * A database stores the set of features that it "uses" (implicitly
51  * before database version 3 and explicitly as of version 3).
52  *
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.
61  *
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.
65  */
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.
69      *
70      * Introduced: version 1. */
71     NOTMUCH_FEATURE_FILE_TERMS                  = 1 << 0,
72
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
76      * absolute paths.
77      *
78      * Introduced: version 1. */
79     NOTMUCH_FEATURE_DIRECTORY_DOCS              = 1 << 1,
80
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.
85      *
86      * Introduced: optional in version 1, required as of version 3.
87      */
88     NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES      = 1 << 2,
89
90     /* If set, folder terms are boolean and path terms exist.  If
91      * unset, folder terms are probabilistic and stemmed and path
92      * terms do not exist.
93      *
94      * Introduced: version 2. */
95     NOTMUCH_FEATURE_BOOL_FOLDER                 = 1 << 3,
96
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.
100      *
101      * Introduced: version 3. */
102     NOTMUCH_FEATURE_GHOSTS                      = 1 << 4,
103
104
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.
108      *
109      * Introduced: version 3. */
110     NOTMUCH_FEATURE_INDEXED_MIMETYPES           = 1 << 5,
111
112     /* If set, messages store the revision number of the last
113      * modification in NOTMUCH_VALUE_LAST_MOD.
114      *
115      * Introduced: version 3. */
116     NOTMUCH_FEATURE_LAST_MOD                    = 1 << 6,
117
118     /* If set, unprefixed terms are stored only for the message body,
119      * not for headers.
120      *
121      * Introduced: version 3. */
122     NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY          = 1 << 7,
123 };
124
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)
129 {
130     return static_cast<_notmuch_features>(
131         static_cast<unsigned>(a) | static_cast<unsigned>(b));
132 }
133
134 inline _notmuch_features
135 operator& (_notmuch_features a, _notmuch_features b)
136 {
137     return static_cast<_notmuch_features>(
138         static_cast<unsigned>(a) & static_cast<unsigned>(b));
139 }
140
141 inline _notmuch_features
142 operator~ (_notmuch_features a)
143 {
144     return static_cast<_notmuch_features>(~static_cast<unsigned>(a));
145 }
146
147 inline _notmuch_features&
148 operator|= (_notmuch_features &a, _notmuch_features b)
149 {
150     a = a | b;
151     return a;
152 }
153
154 inline _notmuch_features&
155 operator&= (_notmuch_features &a, _notmuch_features b)
156 {
157     a = a & b;
158     return a;
159 }
160
161 /*
162  * Configuration options for xapian database fields */
163 typedef enum {
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;
170
171 /*
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)
175 {
176     return static_cast<notmuch_field_flag_t>(
177         static_cast<unsigned>(a) | static_cast<unsigned>(b));
178 }
179
180 inline notmuch_field_flag_t
181 operator& (notmuch_field_flag_t a, notmuch_field_flag_t b)
182 {
183     return static_cast<notmuch_field_flag_t>(
184         static_cast<unsigned>(a) & static_cast<unsigned>(b));
185 }
186
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)
193
194 /*
195  * explicit and implied parameters to open */
196 typedef enum {
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;
207
208 /*
209  * define bitwise operators to hide casts */
210
211 inline notmuch_open_param_t
212 operator| (notmuch_open_param_t a, notmuch_open_param_t b)
213 {
214     return static_cast<notmuch_open_param_t>(
215         static_cast<unsigned>(a) | static_cast<unsigned>(b));
216 }
217
218 inline notmuch_open_param_t&
219 operator|= (notmuch_open_param_t &a, notmuch_open_param_t b)
220 {
221     a = a | b;
222     return a;
223 }
224
225 inline notmuch_open_param_t
226 operator& (notmuch_open_param_t a, notmuch_open_param_t b)
227 {
228     return static_cast<notmuch_open_param_t>(
229         static_cast<unsigned>(a) & static_cast<unsigned>(b));
230 }
231
232 struct _notmuch_database {
233     bool exception_reported;
234
235     /* Path to actual database */
236     const char *xapian_path;
237
238     /* Path to config loaded, if any */
239     const char *config_path;
240
241     int atomic_nesting;
242     /* true if changes have been made in this atomic section */
243     bool atomic_dirty;
244     Xapian::Database *xapian_db;
245     Xapian::WritableDatabase *writable_xapian_db;
246     bool open;
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;
250
251     unsigned int last_doc_id;
252
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;
257
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;
262
263     /* error reporting; this value persists only until the
264      * next library call. May be NULL */
265     char *status_string;
266
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;
271     const char *uuid;
272
273     /* Keep track of the number of times the database has been re-opened
274      * (or other global invalidations of notmuch's caching)
275      */
276     unsigned long view;
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;
283
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;
288
289     /* Cached and possibly overridden configuration */
290     notmuch_string_map_t *config;
291
292     /* Track what parameters were specified when opening */
293     notmuch_open_param_t params;
294 };
295
296 /* Prior to database version 3, features were implied by the database
297  * version number, so hard-code them for earlier versions. */
298 #define NOTMUCH_FEATURES_V0 ((enum _notmuch_features) 0)
299 #define NOTMUCH_FEATURES_V1 (NOTMUCH_FEATURES_V0 | NOTMUCH_FEATURE_FILE_TERMS | \
300                              NOTMUCH_FEATURE_DIRECTORY_DOCS)
301 #define NOTMUCH_FEATURES_V2 (NOTMUCH_FEATURES_V1 | NOTMUCH_FEATURE_BOOL_FOLDER)
302
303 /* Current database features.  If any of these are missing from a
304  * database, request an upgrade.
305  * NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES and
306  * NOTMUCH_FEATURE_INDEXED_MIMETYPES are not included because upgrade
307  * doesn't currently introduce the features (though brand new databases
308  * will have it). */
309 #define NOTMUCH_FEATURES_CURRENT \
310     (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_DIRECTORY_DOCS | \
311      NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS | \
312      NOTMUCH_FEATURE_LAST_MOD)
313
314 /* Return the list of terms from the given iterator matching a prefix.
315  * The prefix will be stripped from the strings in the returned list.
316  * The list will be allocated using ctx as the talloc context.
317  *
318  * The function returns NULL on failure.
319  */
320 notmuch_string_list_t *
321 _notmuch_database_get_terms_with_prefix (void *ctx, Xapian::TermIterator &i,
322                                          Xapian::TermIterator &end,
323                                          const char *prefix);
324
325 void
326 _notmuch_database_find_doc_ids (notmuch_database_t *notmuch,
327                                 const char *prefix_name,
328                                 const char *value,
329                                 Xapian::PostingIterator *begin,
330                                 Xapian::PostingIterator *end);
331
332 #define NOTMUCH_DATABASE_VERSION 3
333
334 /* features.cc */
335
336 _notmuch_features
337 _notmuch_database_parse_features (const void *ctx, const char *features, unsigned int version,
338                                   char mode, char **incompat_out);
339
340 char *
341 _notmuch_database_print_features (const void *ctx, unsigned int features);
342
343 /* prefix.cc */
344 notmuch_status_t
345 _notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch);
346
347 notmuch_status_t
348 _notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch);
349
350 #if __cplusplus
351 /* query.cc */
352 notmuch_status_t
353 _notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch,
354                                        std::string query_string,
355                                        Xapian::Query &output,
356                                        std::string &msg);
357
358 notmuch_status_t
359 _notmuch_query_expand (notmuch_database_t *notmuch, const char *field, Xapian::Query subquery,
360                        Xapian::Query &output, std::string &msg);
361
362 /* regexp-fields.cc */
363 notmuch_status_t
364 _notmuch_regexp_to_query (notmuch_database_t *notmuch, Xapian::valueno slot, std::string field,
365                           std::string regexp_str,
366                           Xapian::Query &output, std::string &msg);
367
368 /* thread-fp.cc */
369 notmuch_status_t
370 _notmuch_query_name_to_query (notmuch_database_t *notmuch, const std::string name,
371                               Xapian::Query &output);
372
373 #if HAVE_SFSEXP
374 /* parse-sexp.cc */
375 notmuch_status_t
376 _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr,
377                                       Xapian::Query &output);
378 #endif
379
380 /* parse-time-vrp.h */
381 notmuch_status_t
382 _notmuch_date_strings_to_query (Xapian::valueno slot, const std::string &from, const std::string &to,
383                                 Xapian::Query &output, std::string &msg);
384
385 /* lastmod-fp.h */
386 notmuch_status_t
387 _notmuch_lastmod_strings_to_query (notmuch_database_t *notmuch,
388                                    const std::string &from, const std::string &to,
389                                    Xapian::Query &output, std::string &msg);
390 #endif
391 #endif