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 notmuch_field_flags { 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_flag_t; 169 170 /* 171 * define bitwise operators to hide casts */ 172 inline notmuch_field_flag_t 173 operator| (notmuch_field_flag_t a, notmuch_field_flag_t b) 174 { 175 return static_cast<notmuch_field_flag_t>( 176 static_cast<unsigned>(a) | static_cast<unsigned>(b)); 177 } 178 179 inline notmuch_field_flag_t 180 operator& (notmuch_field_flag_t a, notmuch_field_flag_t b) 181 { 182 return static_cast<notmuch_field_flag_t>( 183 static_cast<unsigned>(a) & static_cast<unsigned>(b)); 184 } 185 186 #define NOTMUCH_QUERY_PARSER_FLAGS (Xapian::QueryParser::FLAG_BOOLEAN | \ 187 Xapian::QueryParser::FLAG_PHRASE | \ 188 Xapian::QueryParser::FLAG_LOVEHATE | \ 189 Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE | \ 190 Xapian::QueryParser::FLAG_WILDCARD | \ 191 Xapian::QueryParser::FLAG_PURE_NOT) 192 193 /* 194 * Which parameters were explicit when the database was opened */ 195 typedef enum { 196 NOTMUCH_PARAM_NONE = 0, 197 NOTMUCH_PARAM_DATABASE = 1 << 0, 198 NOTMUCH_PARAM_CONFIG = 1 << 1, 199 NOTMUCH_PARAM_PROFILE = 1 << 2, 200 } notmuch_open_param_t; 201 202 /* 203 * define bitwise operators to hide casts */ 204 205 inline notmuch_open_param_t 206 operator| (notmuch_open_param_t a, notmuch_open_param_t b) 207 { 208 return static_cast<notmuch_open_param_t>( 209 static_cast<unsigned>(a) | static_cast<unsigned>(b)); 210 } 211 212 inline notmuch_open_param_t& 213 operator|= (notmuch_open_param_t &a, notmuch_open_param_t b) 214 { 215 a = a | b; 216 return a; 217 } 218 219 inline notmuch_open_param_t 220 operator& (notmuch_open_param_t a, notmuch_open_param_t b) 221 { 222 return static_cast<notmuch_open_param_t>( 223 static_cast<unsigned>(a) & static_cast<unsigned>(b)); 224 } 225 226 struct _notmuch_database { 227 bool exception_reported; 228 229 /* Path to actual database */ 230 const char *xapian_path; 231 232 /* Path to config loaded, if any */ 233 const char *config_path; 234 235 int atomic_nesting; 236 /* true if changes have been made in this atomic section */ 237 bool atomic_dirty; 238 Xapian::Database *xapian_db; 239 Xapian::WritableDatabase *writable_xapian_db; 240 bool open; 241 /* Bit mask of features used by this database. This is a 242 * bitwise-OR of NOTMUCH_FEATURE_* values (above). */ 243 enum _notmuch_features features; 244 245 unsigned int last_doc_id; 246 247 /* 16 bytes (+ terminator) for hexadecimal representation of 248 * a 64-bit integer. */ 249 char thread_id_str[17]; 250 uint64_t last_thread_id; 251 252 /* How many transactions have successfully completed since we last committed */ 253 int transaction_count; 254 /* when to commit and reset the counter */ 255 int transaction_threshold; 256 257 /* error reporting; this value persists only until the 258 * next library call. May be NULL */ 259 char *status_string; 260 261 /* Highest committed revision number. Modifications are recorded 262 * under a higher revision number, which can be generated with 263 * notmuch_database_new_revision. */ 264 unsigned long revision; 265 const char *uuid; 266 267 /* Keep track of the number of times the database has been re-opened 268 * (or other global invalidations of notmuch's caching) 269 */ 270 unsigned long view; 271 Xapian::QueryParser *query_parser; 272 Xapian::Stem *stemmer; 273 Xapian::TermGenerator *term_gen; 274 Xapian::RangeProcessor *value_range_processor; 275 Xapian::RangeProcessor *date_range_processor; 276 Xapian::RangeProcessor *last_mod_range_processor; 277 278 /* XXX it's slightly gross to use two parallel string->string maps 279 * here, but at least they are small */ 280 notmuch_string_map_t *user_prefix; 281 notmuch_string_map_t *user_header; 282 283 /* Cached and possibly overridden configuration */ 284 notmuch_string_map_t *config; 285 286 /* Track what parameters were specified when opening */ 287 notmuch_open_param_t params; 288 }; 289 290 /* Prior to database version 3, features were implied by the database 291 * version number, so hard-code them for earlier versions. */ 292 #define NOTMUCH_FEATURES_V0 ((enum _notmuch_features) 0) 293 #define NOTMUCH_FEATURES_V1 (NOTMUCH_FEATURES_V0 | NOTMUCH_FEATURE_FILE_TERMS | \ 294 NOTMUCH_FEATURE_DIRECTORY_DOCS) 295 #define NOTMUCH_FEATURES_V2 (NOTMUCH_FEATURES_V1 | NOTMUCH_FEATURE_BOOL_FOLDER) 296 297 /* Current database features. If any of these are missing from a 298 * database, request an upgrade. 299 * NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES and 300 * NOTMUCH_FEATURE_INDEXED_MIMETYPES are not included because upgrade 301 * doesn't currently introduce the features (though brand new databases 302 * will have it). */ 303 #define NOTMUCH_FEATURES_CURRENT \ 304 (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_DIRECTORY_DOCS | \ 305 NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS | \ 306 NOTMUCH_FEATURE_LAST_MOD) 307 308 /* Return the list of terms from the given iterator matching a prefix. 309 * The prefix will be stripped from the strings in the returned list. 310 * The list will be allocated using ctx as the talloc context. 311 * 312 * The function returns NULL on failure. 313 */ 314 notmuch_string_list_t * 315 _notmuch_database_get_terms_with_prefix (void *ctx, Xapian::TermIterator &i, 316 Xapian::TermIterator &end, 317 const char *prefix); 318 319 void 320 _notmuch_database_find_doc_ids (notmuch_database_t *notmuch, 321 const char *prefix_name, 322 const char *value, 323 Xapian::PostingIterator *begin, 324 Xapian::PostingIterator *end); 325 326 #define NOTMUCH_DATABASE_VERSION 3 327 328 /* features.cc */ 329 330 _notmuch_features 331 _notmuch_database_parse_features (const void *ctx, const char *features, unsigned int version, 332 char mode, char **incompat_out); 333 334 char * 335 _notmuch_database_print_features (const void *ctx, unsigned int features); 336 337 /* prefix.cc */ 338 notmuch_status_t 339 _notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch); 340 341 notmuch_status_t 342 _notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch); 343 344 #if __cplusplus 345 /* query.cc */ 346 notmuch_status_t 347 _notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch, 348 std::string query_string, 349 Xapian::Query &output, 350 std::string &msg); 351 /* parse-sexp.cc */ 352 notmuch_status_t 353 _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr, 354 Xapian::Query &output); 355 356 notmuch_status_t 357 _notmuch_query_expand (notmuch_database_t *notmuch, const char *field, Xapian::Query subquery, 358 Xapian::Query &output, std::string &msg); 359 360 /* regexp-fields.cc */ 361 notmuch_status_t 362 _notmuch_regexp_to_query (notmuch_database_t *notmuch, Xapian::valueno slot, std::string field, 363 std::string regexp_str, 364 Xapian::Query &output, std::string &msg); 365 366 /* thread-fp.cc */ 367 notmuch_status_t 368 _notmuch_query_name_to_query (notmuch_database_t *notmuch, const std::string name, 369 Xapian::Query &output); 370 371 #if HAVE_SFSEXP 372 /* parse-sexp.cc */ 373 notmuch_status_t 374 _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr, 375 Xapian::Query &output); 376 #endif 377 #endif 378 #endif 379