* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/ .
+ * along with this program. If not, see https://www.gnu.org/licenses/ .
*
* Author: Carl Worth <cworth@cworth.org>
*/
const char *query_string;
notmuch_sort_t sort;
notmuch_string_list_t *exclude_terms;
- notmuch_bool_t omit_excluded_messages;
+ notmuch_exclude_t omit_excluded;
};
typedef struct _notmuch_mset_messages {
} notmuch_mset_messages_t;
struct _notmuch_doc_id_set {
- unsigned int *bitmap;
+ unsigned char *bitmap;
unsigned int bound;
};
-#define DOCIDSET_WORD(bit) ((bit) / sizeof (unsigned int))
-#define DOCIDSET_BIT(bit) ((bit) % sizeof (unsigned int))
+#define DOCIDSET_WORD(bit) ((bit) / CHAR_BIT)
+#define DOCIDSET_BIT(bit) ((bit) % CHAR_BIT)
struct visible _notmuch_threads {
notmuch_query_t *query;
notmuch_doc_id_set_t *doc_ids,
GArray *arr);
+static notmuch_bool_t
+_debug_query (void)
+{
+ char *env = getenv ("NOTMUCH_DEBUG_QUERY");
+ return (env && strcmp (env, "") != 0);
+}
+
notmuch_query_t *
notmuch_query_create (notmuch_database_t *notmuch,
const char *query_string)
{
notmuch_query_t *query;
-#ifdef DEBUG_QUERY
- fprintf (stderr, "Query string is:\n%s\n", query_string);
-#endif
+ if (_debug_query ())
+ fprintf (stderr, "Query string is:\n%s\n", query_string);
- query = talloc (NULL, notmuch_query_t);
+ query = talloc (notmuch, notmuch_query_t);
if (unlikely (query == NULL))
return NULL;
query->exclude_terms = _notmuch_string_list_create (query);
- query->omit_excluded_messages = FALSE;
+ query->omit_excluded = NOTMUCH_EXCLUDE_TRUE;
return query;
}
const char *
-notmuch_query_get_query_string (notmuch_query_t *query)
+notmuch_query_get_query_string (const notmuch_query_t *query)
{
return query->query_string;
}
void
-notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, notmuch_bool_t omit)
+notmuch_query_set_omit_excluded (notmuch_query_t *query,
+ notmuch_exclude_t omit_excluded)
{
- query->omit_excluded_messages = omit;
+ query->omit_excluded = omit_excluded;
}
void
}
notmuch_sort_t
-notmuch_query_get_sort (notmuch_query_t *query)
+notmuch_query_get_sort (const notmuch_query_t *query)
{
return query->sort;
}
notmuch_messages_t *
notmuch_query_search_messages (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+ notmuch_messages_t *messages;
+ status = notmuch_query_search_messages_st (query, &messages);
+ if (status)
+ return NULL;
+ else
+ return messages;
+}
+
+notmuch_status_t
+notmuch_query_search_messages_st (notmuch_query_t *query,
+ notmuch_messages_t **out)
+{
+ return _notmuch_query_search_documents (query, "mail", out);
+}
+
+notmuch_status_t
+_notmuch_query_search_documents (notmuch_query_t *query,
+ const char *type,
+ notmuch_messages_t **out)
{
notmuch_database_t *notmuch = query->notmuch;
const char *query_string = query->query_string;
messages = talloc (query, notmuch_mset_messages_t);
if (unlikely (messages == NULL))
- return NULL;
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
try {
Xapian::Enquire enquire (*notmuch->xapian_db);
Xapian::Query mail_query (talloc_asprintf (query, "%s%s",
_find_prefix ("type"),
- "mail"));
+ type));
Xapian::Query string_query, final_query, exclude_query;
Xapian::MSet mset;
Xapian::MSetIterator iterator;
- unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN |
- Xapian::QueryParser::FLAG_PHRASE |
- Xapian::QueryParser::FLAG_LOVEHATE |
- Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE |
- Xapian::QueryParser::FLAG_WILDCARD |
- Xapian::QueryParser::FLAG_PURE_NOT);
if (strcmp (query_string, "") == 0 ||
strcmp (query_string, "*") == 0)
final_query = mail_query;
} else {
string_query = notmuch->query_parser->
- parse_query (query_string, flags);
+ parse_query (query_string, NOTMUCH_QUERY_PARSER_FLAGS);
final_query = Xapian::Query (Xapian::Query::OP_AND,
mail_query, string_query);
}
messages->base.excluded_doc_ids = NULL;
- if (query->exclude_terms) {
+ if ((query->omit_excluded != NOTMUCH_EXCLUDE_FALSE) && (query->exclude_terms)) {
exclude_query = _notmuch_exclude_tags (query, final_query);
- exclude_query = Xapian::Query (Xapian::Query::OP_AND,
- exclude_query, final_query);
- if (query->omit_excluded_messages)
+ if (query->omit_excluded == NOTMUCH_EXCLUDE_TRUE ||
+ query->omit_excluded == NOTMUCH_EXCLUDE_ALL)
+ {
final_query = Xapian::Query (Xapian::Query::OP_AND_NOT,
final_query, exclude_query);
- else {
+ } else { /* NOTMUCH_EXCLUDE_FLAG */
+ exclude_query = Xapian::Query (Xapian::Query::OP_AND,
+ exclude_query, final_query);
+
enquire.set_weighting_scheme (Xapian::BoolWeight());
enquire.set_query (exclude_query);
case NOTMUCH_SORT_MESSAGE_ID:
enquire.set_sort_by_value (NOTMUCH_VALUE_MESSAGE_ID, FALSE);
break;
- case NOTMUCH_SORT_UNSORTED:
+ case NOTMUCH_SORT_UNSORTED:
break;
}
-#if DEBUG_QUERY
- fprintf (stderr, "Final query is:\n%s\n", final_query.get_description().c_str());
-#endif
+ if (_debug_query ()) {
+ fprintf (stderr, "Exclude query is:\n%s\n",
+ exclude_query.get_description ().c_str ());
+ fprintf (stderr, "Final query is:\n%s\n",
+ final_query.get_description ().c_str ());
+ }
enquire.set_query (final_query);
messages->iterator = mset.begin ();
messages->iterator_end = mset.end ();
- return &messages->base;
+ *out = &messages->base;
+ return NOTMUCH_STATUS_SUCCESS;
} catch (const Xapian::Error &error) {
- fprintf (stderr, "A Xapian exception occurred performing query: %s\n",
- error.get_msg().c_str());
- fprintf (stderr, "Query string was: %s\n", query->query_string);
+ _notmuch_database_log (notmuch,
+ "A Xapian exception occurred performing query: %s\n"
+ "Query string was: %s\n",
+ error.get_msg().c_str(),
+ query->query_string);
+
notmuch->exception_reported = TRUE;
talloc_free (messages);
- return NULL;
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
}
GArray *arr)
{
unsigned int max = 0;
- unsigned int *bitmap;
+ unsigned char *bitmap;
for (unsigned int i = 0; i < arr->len; i++)
max = MAX(max, g_array_index (arr, unsigned int, i));
- bitmap = talloc_zero_array (ctx, unsigned int, 1 + max / sizeof (*bitmap));
+ bitmap = talloc_zero_array (ctx, unsigned char, DOCIDSET_WORD(max) + 1);
if (bitmap == NULL)
return FALSE;
void
_notmuch_doc_id_set_remove (notmuch_doc_id_set_t *doc_ids,
- unsigned int doc_id)
+ unsigned int doc_id)
{
if (doc_id < doc_ids->bound)
doc_ids->bitmap[DOCIDSET_WORD(doc_id)] &= ~(1 << DOCIDSET_BIT(doc_id));
return 0;
}
+
notmuch_threads_t *
notmuch_query_search_threads (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+ notmuch_threads_t *threads;
+ status = notmuch_query_search_threads_st (query, &threads);
+ if (status)
+ return NULL;
+ else
+ return threads;
+}
+
+notmuch_status_t
+notmuch_query_search_threads_st (notmuch_query_t *query,
+ notmuch_threads_t **out)
{
notmuch_threads_t *threads;
notmuch_messages_t *messages;
+ notmuch_status_t status;
threads = talloc (query, notmuch_threads_t);
if (threads == NULL)
- return NULL;
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
threads->doc_ids = NULL;
talloc_set_destructor (threads, _notmuch_threads_destructor);
threads->query = query;
- messages = notmuch_query_search_messages (query);
- if (messages == NULL) {
- talloc_free (threads);
- return NULL;
+ status = notmuch_query_search_messages_st (query, &messages);
+ if (status) {
+ talloc_free (threads);
+ return status;
}
threads->doc_ids = g_array_new (FALSE, FALSE, sizeof (unsigned int));
if (! _notmuch_doc_id_set_init (threads, &threads->match_set,
threads->doc_ids)) {
talloc_free (threads);
- return NULL;
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
}
- return threads;
+ *out = threads;
+ return NOTMUCH_STATUS_SUCCESS;
}
void
{
unsigned int doc_id;
+ if (! threads)
+ return FALSE;
+
while (threads->doc_id_pos < threads->doc_ids->len) {
doc_id = g_array_index (threads->doc_ids, unsigned int,
threads->doc_id_pos);
doc_id,
&threads->match_set,
threads->query->exclude_terms,
+ threads->query->omit_excluded,
threads->query->sort);
}
talloc_free (threads);
}
-unsigned
+unsigned int
notmuch_query_count_messages (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+ unsigned int count;
+
+ status = notmuch_query_count_messages_st (query, &count);
+ return status ? 0 : count;
+}
+
+notmuch_status_t
+notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
+{
+ return _notmuch_query_count_documents (query, "mail", count_out);
+}
+
+notmuch_status_t
+_notmuch_query_count_documents (notmuch_query_t *query, const char *type, unsigned *count_out)
{
notmuch_database_t *notmuch = query->notmuch;
const char *query_string = query->query_string;
Xapian::Enquire enquire (*notmuch->xapian_db);
Xapian::Query mail_query (talloc_asprintf (query, "%s%s",
_find_prefix ("type"),
- "mail"));
+ type));
Xapian::Query string_query, final_query, exclude_query;
Xapian::MSet mset;
- unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN |
- Xapian::QueryParser::FLAG_PHRASE |
- Xapian::QueryParser::FLAG_LOVEHATE |
- Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE |
- Xapian::QueryParser::FLAG_WILDCARD |
- Xapian::QueryParser::FLAG_PURE_NOT);
if (strcmp (query_string, "") == 0 ||
strcmp (query_string, "*") == 0)
final_query = mail_query;
} else {
string_query = notmuch->query_parser->
- parse_query (query_string, flags);
+ parse_query (query_string, NOTMUCH_QUERY_PARSER_FLAGS);
final_query = Xapian::Query (Xapian::Query::OP_AND,
mail_query, string_query);
}
enquire.set_weighting_scheme(Xapian::BoolWeight());
enquire.set_docid_order(Xapian::Enquire::ASCENDING);
-#if DEBUG_QUERY
- fprintf (stderr, "Final query is:\n%s\n", final_query.get_description().c_str());
-#endif
+ if (_debug_query ()) {
+ fprintf (stderr, "Exclude query is:\n%s\n",
+ exclude_query.get_description ().c_str ());
+ fprintf (stderr, "Final query is:\n%s\n",
+ final_query.get_description ().c_str ());
+ }
enquire.set_query (final_query);
- mset = enquire.get_mset (0, notmuch->xapian_db->get_doccount ());
+ /*
+ * Set the checkatleast parameter to the number of documents
+ * in the database to make get_matches_estimated() exact.
+ */
+ mset = enquire.get_mset (0, notmuch->xapian_db->get_doccount (),
+ notmuch->xapian_db->get_doccount ());
count = mset.get_matches_estimated();
} catch (const Xapian::Error &error) {
- fprintf (stderr, "A Xapian exception occurred: %s\n",
- error.get_msg().c_str());
- fprintf (stderr, "Query string was: %s\n", query->query_string);
+ _notmuch_database_log (notmuch,
+ "A Xapian exception occurred performing query: %s\n"
+ "Query string was: %s\n",
+ error.get_msg().c_str(),
+ query->query_string);
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
- return count;
+ *count_out = count;
+ return NOTMUCH_STATUS_SUCCESS;
}
unsigned
notmuch_query_count_threads (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+ unsigned int count;
+
+ status = notmuch_query_count_threads_st (query, &count);
+ return status ? 0 : count;
+}
+
+notmuch_status_t
+notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count)
{
notmuch_messages_t *messages;
GHashTable *hash;
- unsigned int count;
notmuch_sort_t sort;
+ notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
sort = query->sort;
query->sort = NOTMUCH_SORT_UNSORTED;
- messages = notmuch_query_search_messages (query);
+ ret = notmuch_query_search_messages_st (query, &messages);
+ if (ret)
+ return ret;
query->sort = sort;
if (messages == NULL)
- return 0;
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
if (hash == NULL) {
talloc_free (messages);
- return 0;
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
}
while (notmuch_messages_valid (messages)) {
char *thread_id_copy = talloc_strdup (messages, thread_id);
if (unlikely (thread_id_copy == NULL)) {
notmuch_message_destroy (message);
- count = 0;
+ ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
goto DONE;
}
g_hash_table_insert (hash, thread_id_copy, NULL);
notmuch_messages_move_to_next (messages);
}
- count = g_hash_table_size (hash);
+ *count = g_hash_table_size (hash);
DONE:
g_hash_table_unref (hash);
talloc_free (messages);
- return count;
+ return ret;
+}
+
+notmuch_database_t *
+notmuch_query_get_database (const notmuch_query_t *query)
+{
+ return query->notmuch;
}