* use GError to convey error info in MuQuery; update users

This commit is contained in:
Dirk-Jan C. Binnema 2010-11-24 00:47:36 +02:00
parent 21c01f156d
commit b87b5d25fd
5 changed files with 69 additions and 47 deletions

View File

@ -36,6 +36,7 @@
#include "mu-util.h" #include "mu-util.h"
#include "mu-util-db.h" #include "mu-util-db.h"
#include "mu-str.h" #include "mu-str.h"
#include "mu-result.h"
/* /*
* custom parser for date ranges * custom parser for date ranges
@ -179,23 +180,26 @@ uninit_mu_query (MuQuery *mqx)
} }
static Xapian::Query static bool
get_query (MuQuery * mqx, const char* searchexpr, int *err = 0) { set_query (MuQuery *mqx, Xapian::Query& q, const char* searchexpr,
GError **err) {
try { try {
return mqx->_qparser->parse_query q = mqx->_qparser->parse_query
(searchexpr, (searchexpr,
Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_BOOLEAN |
Xapian::QueryParser::FLAG_PURE_NOT | Xapian::QueryParser::FLAG_PURE_NOT |
Xapian::QueryParser::FLAG_AUTO_SYNONYMS | Xapian::QueryParser::FLAG_AUTO_SYNONYMS |
Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE); Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE);
return true;
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
if (err) /* some error occured */
*err = 1; g_set_error (err, 0, MU_ERROR_QUERY, "parse error in query '%s'",
searchexpr);
return Xapian::Query(); return false;
} }
static void static void
@ -231,32 +235,34 @@ add_prefix (MuMsgFieldId mfid, Xapian::QueryParser* qparser)
} }
MuQuery* MuQuery*
mu_query_new (const char* xpath) mu_query_new (const char* xpath, GError **err)
{ {
MuQuery *mqx; MuQuery *mqx;
g_return_val_if_fail (xpath, NULL); g_return_val_if_fail (xpath, NULL);
if (!mu_util_check_dir (xpath, TRUE, FALSE)) { if (!mu_util_check_dir (xpath, TRUE, FALSE)) {
g_warning ("'%s' is not a readable xapian dir", xpath); g_set_error (err, 0, MU_ERROR_XAPIAN_DIR,
"'%s' is not a readable xapian dir", xpath);
return NULL; return NULL;
} }
if (mu_util_db_is_empty (xpath)) {
g_warning ("database %s is empty; nothing to do", xpath);
return NULL;
}
if (!mu_util_db_version_up_to_date (xpath)) { if (!mu_util_db_version_up_to_date (xpath)) {
g_warning ("%s is not up-to-date, needs a full update", g_set_error (err, 0, MU_ERROR_XAPIAN_NOT_UPTODATE,
xpath); "%s is not up-to-date, needs a full update",
xpath);
return NULL; return NULL;
} }
if (mu_util_db_is_empty (xpath))
g_warning ("database %s is empty; nothing to do", xpath);
mqx = g_new (MuQuery, 1); mqx = g_new (MuQuery, 1);
if (!init_mu_query (mqx, xpath)) { if (!init_mu_query (mqx, xpath)) {
g_critical ("failed to initialize the Xapian query object"); g_set_error (err, 0, MU_ERROR_INTERNAL,
"failed to initialize the Xapian query object");
g_free (mqx); g_free (mqx);
return NULL; return NULL;
} }
@ -373,7 +379,7 @@ mu_query_preprocess (const char *query)
MuMsgIter* MuMsgIter*
mu_query_run (MuQuery *self, const char* searchexpr, mu_query_run (MuQuery *self, const char* searchexpr,
MuMsgFieldId sortfieldid, gboolean ascending, MuMsgFieldId sortfieldid, gboolean ascending,
size_t batchsize) size_t batchsize, GError **err)
{ {
g_return_val_if_fail (self, NULL); g_return_val_if_fail (self, NULL);
g_return_val_if_fail (searchexpr, NULL); g_return_val_if_fail (searchexpr, NULL);
@ -381,14 +387,12 @@ mu_query_run (MuQuery *self, const char* searchexpr,
sortfieldid == MU_MSG_FIELD_ID_NONE, sortfieldid == MU_MSG_FIELD_ID_NONE,
NULL); NULL);
try { try {
Xapian::Query query;
char *preprocessed; char *preprocessed;
int err (0);
preprocessed = mu_query_preprocess (searchexpr); preprocessed = mu_query_preprocess (searchexpr);
Xapian::Query q(get_query(self, preprocessed, &err)); if (!set_query(self, query, preprocessed, err)) {
if (err) {
g_warning ("Error in query '%s'", preprocessed);
g_free (preprocessed); g_free (preprocessed);
return NULL; return NULL;
} }
@ -402,9 +406,8 @@ mu_query_run (MuQuery *self, const char* searchexpr,
if (sortfieldid != MU_MSG_FIELD_ID_NONE) if (sortfieldid != MU_MSG_FIELD_ID_NONE)
enq.set_sort_by_value ((Xapian::valueno)sortfieldid, enq.set_sort_by_value ((Xapian::valueno)sortfieldid,
ascending ? true : false); ascending ? true : false);
enq.set_query(q); enq.set_query(query);
enq.set_cutoff(0,0); enq.set_cutoff(0,0);
return mu_msg_iter_new (enq, batchsize); return mu_msg_iter_new (enq, batchsize);
@ -412,24 +415,24 @@ mu_query_run (MuQuery *self, const char* searchexpr,
} }
char* char*
mu_query_as_string (MuQuery *self, const char *searchexpr) mu_query_as_string (MuQuery *self, const char *searchexpr, GError **err)
{ {
g_return_val_if_fail (self, NULL); g_return_val_if_fail (self, NULL);
g_return_val_if_fail (searchexpr, NULL); g_return_val_if_fail (searchexpr, NULL);
try { try {
Xapian::Query query;
char *preprocessed; char *preprocessed;
int err (0);
preprocessed = mu_query_preprocess (searchexpr); preprocessed = mu_query_preprocess (searchexpr);
Xapian::Query q(get_query(self, preprocessed, &err)); if (!set_query(self, query, preprocessed, err)) {
if (err) g_free (preprocessed);
g_warning ("Error in query '%s'", preprocessed); return NULL;
}
g_free (preprocessed); g_free (preprocessed);
return err ? NULL : g_strdup(q.get_description().c_str()); return g_strdup(query.get_description().c_str());
} MU_XAPIAN_CATCH_BLOCK_RETURN(NULL); } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL);
} }

View File

@ -31,14 +31,15 @@ typedef struct _MuQuery MuQuery;
/** /**
* create a new MuQuery instance. * create a new MuQuery instance.
* *
* @param path path to the xapian db to search * @param path path to the xapian db to search
* @param err receives error information (if there is any) * @param err receives error information (if there is any); if
* * function returns non-NULL, err will _not_be set. err can be NULL
*
* @return a new MuQuery instance, or NULL in case of error. * @return a new MuQuery instance, or NULL in case of error.
* when the instance is no longer needed, use mu_query_destroy * when the instance is no longer needed, use mu_query_destroy
* to free it * to free it
*/ */
MuQuery *mu_query_new (const char* path) G_GNUC_WARN_UNUSED_RESULT; MuQuery *mu_query_new (const char* path, GError **err) G_GNUC_WARN_UNUSED_RESULT;
/** /**
* destroy the MuQuery instance * destroy the MuQuery instance
@ -71,6 +72,8 @@ char* mu_query_version (MuQuery *store) G_GNUC_WARN_UNUSED_RESULT;
* reasons - it's best to get the size one wants to show the user at once. * reasons - it's best to get the size one wants to show the user at once.
* If you pass '0' as the batchsize, mu will use the maximum size (the count * If you pass '0' as the batchsize, mu will use the maximum size (the count
* of documents in the database) * of documents in the database)
* @param err receives error information (if there is any); if
* function returns non-NULL, err will _not_be set. err can be NULL
* *
* @return a MuMsgIter instance you can iterate over, or NULL in * @return a MuMsgIter instance you can iterate over, or NULL in
* case of error * case of error
@ -79,19 +82,22 @@ MuMsgIter* mu_query_run (MuQuery *self,
const char* expr, const char* expr,
MuMsgFieldId sortfieldid, MuMsgFieldId sortfieldid,
gboolean ascending, gboolean ascending,
size_t batchsize) G_GNUC_WARN_UNUSED_RESULT; size_t batchsize,
GError **err) G_GNUC_WARN_UNUSED_RESULT;
/** /**
* get a string representation of the Xapian search query * get a string representation of the Xapian search query
* *
* @param self a MuQuery instance * @param self a MuQuery instance
* @param searchexpr a xapian search expression * @param searchexpr a xapian search expression
* @param err receives error information (if there is any); if
* function returns non-NULL, err will _not_be set. err can be NULL
* *
* @return the string representation of the xapian query, or NULL in case of * @return the string representation of the xapian query, or NULL in case of
* error; free the returned value with g_free * error; free the returned value with g_free
*/ */
char* mu_query_as_string (MuQuery *self, char* mu_query_as_string (MuQuery *self,
const char* searchexpr) G_GNUC_WARN_UNUSED_RESULT; const char* searchexpr, GError **err) G_GNUC_WARN_UNUSED_RESULT;
/** /**
* pre-process the query; this function is useful mainly for debugging mu * pre-process the query; this function is useful mainly for debugging mu

View File

@ -23,7 +23,16 @@
enum _MuResult { enum _MuResult {
MU_OK, /* all went ok */ MU_OK, /* all went ok */
MU_STOP, /* user wants to stop */ MU_STOP, /* user wants to stop */
MU_ERROR_XAPIAN_DIR,
MU_ERROR_XAPIAN_NOT_UPTODATE,
MU_ERROR_QUERY,
MU_ERROR_INTERNAL,
MU_ERROR /* some error occured */ MU_ERROR /* some error occured */
}; };
typedef enum _MuResult MuResult; typedef enum _MuResult MuResult;

View File

@ -64,11 +64,11 @@ run_and_count_matches (const char *xpath, const char *query)
MuMsgIter *iter; MuMsgIter *iter;
guint count; guint count;
mquery = mu_query_new (xpath); mquery = mu_query_new (xpath, NULL);
g_assert (query); g_assert (query);
iter = mu_query_run (mquery, query, MU_MSG_FIELD_ID_NONE, iter = mu_query_run (mquery, query, MU_MSG_FIELD_ID_NONE,
FALSE, 1); FALSE, 1, NULL);
mu_query_destroy (mquery); mu_query_destroy (mquery);
g_assert (iter); g_assert (iter);
@ -213,11 +213,11 @@ test_mu_query_05 (void)
xpath = fill_database (); xpath = fill_database ();
g_assert (xpath != NULL); g_assert (xpath != NULL);
query = mu_query_new (xpath); query = mu_query_new (xpath, NULL);
iter = mu_query_run (query, "fünkÿ", MU_MSG_FIELD_ID_NONE, iter = mu_query_run (query, "fünkÿ", MU_MSG_FIELD_ID_NONE,
FALSE, 1); FALSE, 1, NULL);
msg = mu_msg_iter_get_msg (iter); msg = mu_msg_iter_get_msg (iter);
g_assert_cmpstr (mu_msg_get_subject(msg),==, g_assert_cmpstr (mu_msg_get_subject(msg),==,
"Greetings from Lothlórien"); "Greetings from Lothlórien");
g_assert_cmpstr (mu_msg_get_summary(msg,5),==, g_assert_cmpstr (mu_msg_get_summary(msg,5),==,

View File

@ -311,21 +311,25 @@ empty_or_display_contact (const gchar* str)
static MuMsgIter * static MuMsgIter *
run_query (const char *xpath, const char *query) run_query (const char *xpath, const char *query)
{ {
GError *err;
MuQuery *xapian; MuQuery *xapian;
MuMsgIter *iter; MuMsgIter *iter;
xapian = mu_query_new (xpath); err = NULL;
xapian = mu_query_new (xpath, &err);
if (!xapian) { if (!xapian) {
g_printerr ("Failed to create a Xapian query\n"); g_warning ("Error: %s", err->message);
g_error_free (err);
return NULL; return NULL;
} }
iter = mu_query_run (xapian, query, iter = mu_query_run (xapian, query,
MU_MSG_FIELD_ID_DATE, MU_MSG_FIELD_ID_DATE,
TRUE, 0); TRUE, 0, &err);
mu_query_destroy (xapian); mu_query_destroy (xapian);
if (!iter) { if (!iter) {
g_warning ("error: running query failed\n"); g_warning ("Error: %s", err->message);
g_error_free (err);
return NULL; return NULL;
} }