+notmuch_status_t
+notmuch_query_create_with_syntax (notmuch_database_t *notmuch,
+ const char *query_string,
+ notmuch_query_syntax_t syntax,
+ notmuch_query_t **output)
+{
+
+ notmuch_query_t *query;
+
+ if (! output)
+ return NOTMUCH_STATUS_NULL_POINTER;
+
+ query = _notmuch_query_constructor (notmuch, query_string);
+ if (! query)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ if (syntax == NOTMUCH_QUERY_SYNTAX_SEXP && ! HAVE_SFSEXP) {
+ _notmuch_database_log (notmuch, "sexp query parser not available");
+ return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
+ }
+
+ query->syntax = syntax;
+
+ *output = query;
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+static void
+_notmuch_query_cache_terms (notmuch_query_t *query)
+{
+ /* Xapian doesn't support skip_to on terms from a query since
+ * they are unordered, so cache a copy of all terms in
+ * something searchable.
+ */
+
+ for (Xapian::TermIterator t = query->xapian_query.get_terms_begin ();
+ t != query->xapian_query.get_terms_end (); ++t)
+ query->terms.insert (*t);
+}
+
+notmuch_status_t
+_notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch,
+ std::string query_string,
+ Xapian::Query &output,
+ std::string &msg)
+{
+ try {
+ if (query_string == "" || query_string == "*") {
+ output = xapian_query_match_all ();
+ } else {
+ output =
+ notmuch->query_parser->
+ parse_query (query_string, NOTMUCH_QUERY_PARSER_FLAGS);
+ }
+ } catch (const Xapian::Error &error) {
+ if (! notmuch->exception_reported) {
+ _notmuch_database_log (notmuch,
+ "A Xapian exception occurred parsing query: %s\n",
+ error.get_msg ().c_str ());
+ _notmuch_database_log_append (notmuch,
+ "Query string was: %s\n",
+ query_string.c_str ());
+ notmuch->exception_reported = true;
+ }
+
+ msg = error.get_msg ();
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_notmuch_query_ensure_parsed_xapian (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+ std::string msg; /* ignored */
+
+ status = _notmuch_query_string_to_xapian_query (query->notmuch, query->query_string,
+ query->xapian_query, msg);
+ if (status)
+ return status;
+
+ query->parsed = true;
+
+ _notmuch_query_cache_terms (query);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+#if HAVE_SFSEXP
+static notmuch_status_t
+_notmuch_query_ensure_parsed_sexpr (notmuch_query_t *query)
+{
+ notmuch_status_t status;
+
+ if (query->parsed)
+ return NOTMUCH_STATUS_SUCCESS;
+
+ status = _notmuch_sexp_string_to_xapian_query (query->notmuch, query->query_string,
+ query->xapian_query);
+ if (status)
+ return status;
+
+ _notmuch_query_cache_terms (query);
+ return NOTMUCH_STATUS_SUCCESS;
+}
+#endif
+
+static notmuch_status_t
+_notmuch_query_ensure_parsed (notmuch_query_t *query)
+{
+ if (query->parsed)
+ return NOTMUCH_STATUS_SUCCESS;
+
+#if HAVE_SFSEXP
+ if (query->syntax == NOTMUCH_QUERY_SYNTAX_SEXP)
+ return _notmuch_query_ensure_parsed_sexpr (query);
+#endif
+
+ return _notmuch_query_ensure_parsed_xapian (query);
+}
+