* <many>: update for mu-msg-field change

This commit is contained in:
Dirk-Jan C. Binnema 2010-11-20 14:43:04 +02:00
parent 7f617e32f0
commit b69cf8f589
12 changed files with 306 additions and 224 deletions

View File

@ -70,20 +70,23 @@ print_xapian_query (MuQuery *xapian, const gchar *query)
}
/* returns NULL if there is an error */
const MuMsgField*
static MuMsgFieldId
sort_field_from_string (const char* fieldstr)
{
const MuMsgField *field;
MuMsgFieldId mfid;
field = mu_msg_field_from_name (fieldstr);
mfid = mu_msg_field_id_from_name (fieldstr, FALSE);
if (!field && strlen(fieldstr) == 1)
field = mu_msg_field_from_shortcut(fieldstr[0]);
if (!field)
g_printerr ("not a valid sort field: '%s'\n",
fieldstr);
return field;
/* not found? try a shortcut */
if (mfid == MU_MSG_FIELD_ID_NONE &&
strlen(fieldstr) == 1)
mfid = mu_msg_field_id_from_shortcut(fieldstr[0],
FALSE);
if (mfid == MU_MSG_FIELD_ID_NONE)
g_warning ("Not a valid sort field: '%s'\n",
fieldstr);
return mfid;
}
@ -133,26 +136,28 @@ static gboolean
run_query (MuQuery *xapian, const gchar *query, MuConfigOptions *opts)
{
MuMsgIter *iter;
const MuMsgField *sortfield;
MuMsgFieldId sortid;
size_t matches;
sortfield = NULL;
sortid = MU_MSG_FIELD_ID_NONE;
if (opts->sortfield) {
sortfield = sort_field_from_string (opts->sortfield);
if (!sortfield) /* error occured? */
sortid = sort_field_from_string (opts->sortfield);
if (sortid == MU_MSG_FIELD_ID_NONE) /* error occured? */
return FALSE;
}
iter = mu_query_run (xapian, query, sortfield, !opts->descending, 0);
iter = mu_query_run (xapian, query, sortid, !opts->descending, 0);
if (!iter) {
g_printerr ("error: running query failed\n");
return FALSE;
}
if (opts->linksdir)
matches = make_links (iter, opts->linksdir, opts->clearlinks);
matches = make_links (iter, opts->linksdir,
opts->clearlinks);
else
matches = print_rows (iter, opts->fields, opts->summary_len);
matches = print_rows (iter, opts->fields,
opts->summary_len);
if (matches == 0)
g_printerr ("No matches found\n");

View File

@ -181,54 +181,50 @@ mu_msg_iter_is_done (MuMsgIter *iter)
const gchar*
mu_msg_iter_get_field (MuMsgIter *iter, const MuMsgField *field)
mu_msg_iter_get_field (MuMsgIter *iter, MuMsgFieldId mfid)
{
g_return_val_if_fail (field, NULL);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL);
try {
MuMsgFieldId id;
id = mu_msg_field_id (field);
if (!iter->_str[id]) { /* cache the value */
if (!iter->_str[mfid]) { /* cache the value */
Xapian::Document doc (iter->_cursor.get_document());
iter->_str[id] = g_strdup (doc.get_value(id).c_str());
iter->_str[mfid] =
g_strdup (doc.get_value(mfid).c_str());
}
return iter->_str[id];
return iter->_str[mfid];
} MU_XAPIAN_CATCH_BLOCK_RETURN(NULL);
}
gint64
mu_msg_iter_get_field_numeric (MuMsgIter *iter,
const MuMsgField *field)
mu_msg_iter_get_field_numeric (MuMsgIter *iter, MuMsgFieldId mfid)
{
g_return_val_if_fail (field, -1);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), -1);
g_return_val_if_fail (mu_msg_field_is_numeric(field), -1);
g_return_val_if_fail (mu_msg_field_is_numeric(mfid), -1);
try {
return static_cast<gint64>(
Xapian::sortable_unserialise(
mu_msg_iter_get_field(iter, field)));
mu_msg_iter_get_field(iter, mfid)));
} MU_XAPIAN_CATCH_BLOCK_RETURN(static_cast<gint64>(-1));
}
static const gchar*
get_field (MuMsgIter *iter, MuMsgFieldId id)
{
return mu_msg_iter_get_field(iter, mu_msg_field_from_id (id));
}
// static const gchar*
// get_field (MuMsgIter *iter, MuMsgFieldId mfid)
// {
// return mu_msg_iter_get_field(iter, mfid);
// }
static long
get_field_number (MuMsgIter *iter, MuMsgFieldId id)
get_field_number (MuMsgIter *iter, MuMsgFieldId mfid)
{
const char* str = get_field (iter, id);
const char* str = mu_msg_iter_get_field(iter, mfid);
return str ? atol (str) : 0;
}
@ -250,14 +246,14 @@ const char*
mu_msg_iter_get_path (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_PATH);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_PATH);
}
const char*
mu_msg_iter_get_maildir (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_MAILDIR);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_MAILDIR);
}
@ -266,14 +262,14 @@ const char*
mu_msg_iter_get_from (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_FROM);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_FROM);
}
const char*
mu_msg_iter_get_to (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_TO);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_TO);
}
@ -281,7 +277,7 @@ const char*
mu_msg_iter_get_cc (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_CC);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_CC);
}
@ -289,7 +285,7 @@ const char*
mu_msg_iter_get_subject (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_SUBJECT);
return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_SUBJECT);
}
@ -297,45 +293,39 @@ size_t
mu_msg_iter_get_size (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0);
return static_cast<size_t>(get_field_number (iter, MU_MSG_FIELD_ID_SIZE));
return static_cast<size_t>(get_field_number
(iter, MU_MSG_FIELD_ID_SIZE));
}
time_t
mu_msg_iter_get_date (MuMsgIter *iter)
{
static const MuMsgField *date_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_DATE);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0);
try {
return static_cast<time_t>(
Xapian::sortable_unserialise(
mu_msg_iter_get_field(iter, date_field)));
mu_msg_iter_get_field
(iter,MU_MSG_FIELD_ID_DATE)));
} MU_XAPIAN_CATCH_BLOCK_RETURN(0);
}
MuMsgFlags
mu_msg_iter_get_flags (MuMsgIter *iter)
{
static const MuMsgField *flags_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_FLAGS);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_FLAG_NONE);
return static_cast<MuMsgFlags>(mu_msg_iter_get_field_numeric
(iter, flags_field));
(iter, MU_MSG_FIELD_ID_FLAGS));
}
MuMsgPrio
mu_msg_iter_get_prio (MuMsgIter *iter)
{
static const MuMsgField *prio_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_PRIO);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_PRIO_NONE);
return static_cast<MuMsgPrio>(mu_msg_iter_get_field_numeric
(iter, prio_field));
(iter, MU_MSG_FIELD_ID_PRIO));
}

View File

@ -198,7 +198,7 @@ MuMsgPrio mu_msg_iter_get_prio (MuMsgIter *iter);
* @return the field value, or NULL
*/
const gchar* mu_msg_iter_get_field (MuMsgIter *iter,
const MuMsgField *field);
MuMsgFieldId mfid);
/**
* get some numeric message field
@ -209,7 +209,7 @@ const gchar* mu_msg_iter_get_field (MuMsgIter *iter,
* @return the field value, or -1 in case of error
*/
gint64 mu_msg_iter_get_field_numeric (MuMsgIter *iter,
const MuMsgField *field);
MuMsgFieldId mfid);
G_END_DECLS
#endif /*__MU_MSG_ITER_H__*/

View File

@ -751,15 +751,11 @@ mu_msg_get_summary (MuMsg *msg, size_t max_lines)
const char*
mu_msg_get_field_string (MuMsg *msg, const MuMsgField* field)
mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid)
{
MuMsgFieldId id;
g_return_val_if_fail (msg, NULL);
id = mu_msg_field_id (field);
g_return_val_if_fail (id != MU_MSG_FIELD_ID_NONE, NULL);
switch (id) {
switch (mfid) {
case MU_MSG_FIELD_ID_BODY_TEXT: return mu_msg_get_body_text (msg);
case MU_MSG_FIELD_ID_BODY_HTML: return mu_msg_get_body_html (msg);
case MU_MSG_FIELD_ID_CC: return mu_msg_get_cc (msg);
@ -775,15 +771,11 @@ mu_msg_get_field_string (MuMsg *msg, const MuMsgField* field)
}
gint64
mu_msg_get_field_numeric (MuMsg *msg, const MuMsgField* field)
mu_msg_get_field_numeric (MuMsg *msg, const MuMsgFieldId mfid)
{
MuMsgFieldId id;
g_return_val_if_fail (msg, 0);
id = mu_msg_field_id (field);
g_return_val_if_fail (id != MU_MSG_FIELD_ID_NONE, 0);
switch (id) {
switch (mfid) {
case MU_MSG_FIELD_ID_DATE:
return mu_msg_get_date(msg);
case MU_MSG_FIELD_ID_FLAGS:
@ -793,7 +785,7 @@ mu_msg_get_field_numeric (MuMsg *msg, const MuMsgField* field)
case MU_MSG_FIELD_ID_SIZE:
return mu_msg_get_size(msg);
default:
g_warning ("%s: %u", __FUNCTION__, (guint)id);
g_warning ("%s: %u", __FUNCTION__, mfid);
g_return_val_if_reached (0);
}
}

View File

@ -238,8 +238,8 @@ size_t mu_msg_get_size (MuMsg *msg);
*
* @return a string that should not be freed
*/
const char* mu_msg_get_field_string (MuMsg *msg,
const MuMsgField* field);
const char* mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid);
/**
* get some field value as string
@ -249,8 +249,7 @@ const char* mu_msg_get_field_string (MuMsg *msg,
*
* @return a string that should not be freed
*/
gint64 mu_msg_get_field_numeric (MuMsg *msg,
const MuMsgField* field);
gint64 mu_msg_get_field_numeric (MuMsg *msg, MuMsgFieldId mfid);
/**
* get the message priority for this message (MU_MSG_PRIO_LOW,

View File

@ -57,15 +57,12 @@ gboolean
mu_output_link_row (MuMsgIter *iter, const char* linksdir)
{
const char *path;
const MuMsgField *pathfield;
g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (linksdir, FALSE);
g_return_val_if_fail (!mu_msg_iter_is_done (iter), FALSE);
pathfield = mu_msg_field_from_id (MU_MSG_FIELD_ID_PATH);
path = mu_msg_iter_get_field (iter, pathfield);
path = mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_PATH);
if (!path)
return FALSE;

View File

@ -40,34 +40,31 @@
static const gchar*
display_field (MuMsgIter *iter, const MuMsgField* field)
display_field (MuMsgIter *iter, MuMsgFieldId mfid)
{
gint64 val;
switch (mu_msg_field_type(field)) {
switch (mu_msg_field_type(mfid)) {
case MU_MSG_FIELD_TYPE_STRING:
return mu_msg_iter_get_field (iter, field);
return mu_msg_iter_get_field (iter, mfid);
case MU_MSG_FIELD_TYPE_INT:
if (mu_msg_field_id(field) == MU_MSG_FIELD_ID_PRIO) {
val = mu_msg_iter_get_field_numeric (iter, field);
if (mfid == MU_MSG_FIELD_ID_PRIO) {
val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_prio ((MuMsgPrio)val);
}
if (mu_msg_field_id(field) == MU_MSG_FIELD_ID_FLAGS) {
val = mu_msg_iter_get_field_numeric (iter, field);
return mu_msg_str_flags_s ((MuMsgPrio)val);
}
return mu_msg_iter_get_field (iter, field); /* as string */
} else if (mfid == MU_MSG_FIELD_ID_FLAGS) {
val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_flags_s ((MuMsgFlags)val);
} else /* as string */
return mu_msg_iter_get_field (iter, mfid);
case MU_MSG_FIELD_TYPE_TIME_T:
val = mu_msg_iter_get_field_numeric (iter, field);
val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_date_s ("%c", (time_t)val);
case MU_MSG_FIELD_TYPE_BYTESIZE:
val = mu_msg_iter_get_field_numeric (iter, field);
val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_size_s ((unsigned)val);
default:
g_return_val_if_reached (NULL);
@ -107,14 +104,15 @@ mu_output_plain_row (MuMsgIter *iter, const char *fields, size_t summary_len)
myfields = fields;
while (*myfields) {
const MuMsgField* field;
field = mu_msg_field_from_shortcut (*myfields);
if (!field || ( !mu_msg_field_xapian_value (field) &&
!mu_msg_field_xapian_contact (field)))
MuMsgFieldId mfid;
mfid = mu_msg_field_id_from_shortcut (*myfields, FALSE);
if (mfid == MU_MSG_FIELD_ID_NONE ||
( !mu_msg_field_xapian_value (mfid) &&
!mu_msg_field_xapian_contact (mfid)))
len += printf ("%c", *myfields);
else
len += printf ("%s",
display_field(iter, field));
display_field(iter, mfid));
++myfields;
}

View File

@ -32,8 +32,7 @@
#include "mu-util-db.h"
#include "mu-msg-str.h"
static void add_prefix (const MuMsgField* field,
Xapian::QueryParser* qparser);
static void add_prefix (MuMsgFieldId field, Xapian::QueryParser* qparser);
struct _MuQuery {
Xapian::Database* _db;
@ -51,14 +50,23 @@ init_mu_query (MuQuery *mqx, const char* dbpath)
mqx->_db = new Xapian::Database(dbpath);
mqx->_qparser = new Xapian::QueryParser;
mqx->_qparser->set_database(*mqx->_db);
mqx->_qparser->set_default_op(Xapian::Query::OP_AND);
mqx->_qparser->set_stemming_strategy
(Xapian::QueryParser::STEM_ALL);
mqx->_qparser->set_database (*mqx->_db);
mqx->_qparser->set_default_op (Xapian::Query::OP_AND);
//mqx->_qparser->set_stemming_strategy (Xapian::QueryParser::STEM_NONE);
memset (mqx->_sorters, 0, sizeof(mqx->_sorters));
mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix,
(gpointer)mqx->_qparser);
////// FIXME
// g_print ("synonyms:");
// for (Xapian::TermIterator iter = mqx->_db->synonym_keys_begin();
// iter != mqx->_db->synonym_keys_end(); ++iter) {
// for (Xapian::TermIterator jter = mqx->_db->synonyms_begin(*iter);
// jter != mqx->_db->synonyms_end(*iter); ++jter) {
// g_print ("%s => %s\n", (*iter).c_str(), (*jter).c_str());
// }
// }
return TRUE;
} MU_XAPIAN_CATCH_BLOCK;
@ -95,8 +103,9 @@ get_query (MuQuery * mqx, const char* searchexpr, int *err = 0) {
(searchexpr,
Xapian::QueryParser::FLAG_BOOLEAN |
Xapian::QueryParser::FLAG_PHRASE |
Xapian::QueryParser::FLAG_AUTO_SYNONYMS |
Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE);
} MU_XAPIAN_CATCH_BLOCK;
if (err)
@ -106,22 +115,43 @@ get_query (MuQuery * mqx, const char* searchexpr, int *err = 0) {
}
static void
add_prefix (const MuMsgField* field, Xapian::QueryParser* qparser)
add_prefix (MuMsgFieldId mfid, Xapian::QueryParser* qparser)
{
if (!mu_msg_field_xapian_index(field) &&
!mu_msg_field_xapian_term(field) &&
!mu_msg_field_xapian_contact(field))
static char pfx[] = "\0\0";
static char shortcut[] = "\0\0";
if (!mu_msg_field_xapian_index(mfid) &&
!mu_msg_field_xapian_term(mfid) &&
!mu_msg_field_xapian_contact(mfid))
return;
const std::string prefix (mu_msg_field_xapian_prefix(field));
pfx[0] = mu_msg_field_xapian_prefix (mfid);
shortcut[0] = mu_msg_field_shortcut (mfid);
qparser->add_boolean_prefix
(std::string(mu_msg_field_name(field)), prefix);
qparser->add_boolean_prefix
(std::string(mu_msg_field_shortcut(field)), prefix);
try {
/* make the empty string match this field too*/
qparser->add_prefix ("", prefix);
if (mfid == MU_MSG_FIELD_ID_MSGID ||
mfid == MU_MSG_FIELD_ID_MAILDIR ||
mu_msg_field_type (mfid) != MU_MSG_FIELD_TYPE_STRING ||
mu_msg_field_xapian_contact(mfid)) {
qparser->add_boolean_prefix
(mu_msg_field_name(mfid), pfx);
qparser->add_boolean_prefix (shortcut, pfx);
/* make the empty string match this field too*/
qparser->add_prefix ("", pfx);
} else {
qparser->add_boolean_prefix
(mu_msg_field_name(mfid), pfx);
qparser->add_prefix (shortcut, pfx);
/* make the empty string match this field too*/
qparser->add_prefix ("", pfx);
}
} MU_XAPIAN_CATCH_BLOCK;
}
MuQuery*
@ -162,10 +192,11 @@ mu_query_new (const char* xpath)
void
mu_query_destroy (MuQuery *self)
{
if (self) {
uninit_mu_query (self);
g_free (self);
}
if (!self)
return;
uninit_mu_query (self);
g_free (self);
}
struct _CheckPrefix {
@ -176,21 +207,21 @@ struct _CheckPrefix {
typedef struct _CheckPrefix CheckPrefix;
static void
each_check_prefix (const MuMsgField *field, CheckPrefix *cpfx)
each_check_prefix (MuMsgFieldId mfid, CheckPrefix *cpfx)
{
const char *field_name, *field_shortcut;
const char *field_name;
char field_shortcut;
if (cpfx->match)
if (!cpfx || cpfx->match)
return;
field_shortcut = mu_msg_field_shortcut (field);
if (field_shortcut &&
strncmp (cpfx->pfx, field_shortcut, cpfx->len) == 0) {
field_shortcut = mu_msg_field_shortcut (mfid);
if (field_shortcut == cpfx->pfx[0]) {
cpfx->match = TRUE;
return;
}
field_name = mu_msg_field_name (field);
field_name = mu_msg_field_name (mfid);
if (field_name &&
strncmp (cpfx->pfx, field_name, cpfx->len) == 0) {
cpfx->match = TRUE;
@ -265,11 +296,13 @@ mu_query_preprocess (const char *query)
MuMsgIter*
mu_query_run (MuQuery *self, const char* searchexpr,
const MuMsgField* sortfield, gboolean ascending,
MuMsgFieldId sortfieldid, gboolean ascending,
size_t batchsize)
{
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (searchexpr, NULL);
g_return_val_if_fail (mu_msg_field_id_is_valid (sortfieldid) ||
sortfieldid == MU_MSG_FIELD_ID_NONE, NULL);
try {
char *preprocessed;
@ -290,9 +323,9 @@ mu_query_run (MuQuery *self, const char* searchexpr,
if (batchsize == 0)
batchsize = self->_db->get_doccount();
if (sortfield)
if (sortfieldid != MU_MSG_FIELD_ID_NONE)
enq.set_sort_by_value (
(Xapian::valueno)mu_msg_field_id(sortfield),
(Xapian::valueno)sortfieldid,
ascending);
enq.set_query(q);
@ -312,7 +345,7 @@ mu_query_as_string (MuQuery *self, const char *searchexpr)
try {
char *preprocessed;
int err (0);
preprocessed = mu_query_preprocess (searchexpr);
Xapian::Query q(get_query(self, preprocessed, &err));

View File

@ -63,7 +63,8 @@ char* mu_query_version (MuQuery *store) G_GNUC_WARN_UNUSED_RESULT;
*
* @param self a valid MuQuery instance
* @param expr the search expression
* @param sortfield the field to sort by or NULL
* @param sortfield the field id to sort by or MU_MSG_FIELD_ID_NONE if
* sorting is not desired
* @param ascending if TRUE sort in ascending (A-Z) order, otherwise,
* sort in descending (Z-A) order
* @param batchsize the size of batches to receive; this is mainly for
@ -76,7 +77,7 @@ char* mu_query_version (MuQuery *store) G_GNUC_WARN_UNUSED_RESULT;
*/
MuMsgIter* mu_query_run (MuQuery *self,
const char* expr,
const MuMsgField* sortfield,
MuMsgFieldId sortfieldid,
gboolean ascending,
size_t batchsize) G_GNUC_WARN_UNUSED_RESULT;

View File

@ -40,12 +40,60 @@
struct _MuStore {
Xapian::WritableDatabase *_db;
char *_version;
/* transaction handling */
bool _in_transaction;
int _processed;
size_t _trx_size;
};
static void
add_synonyms (MuStore *store)
{
std::string pfx (1, mu_msg_field_xapian_prefix
(MU_MSG_FIELD_ID_FLAGS));
store->_db->add_synonym (pfx + "n", pfx + "new");
store->_db->add_synonym (pfx + "unread", pfx + "n");
store->_db->add_synonym (pfx + "attach", pfx + "a");
store->_db->add_synonym (pfx + "attachment", pfx + "a");
store->_db->add_synonym ("Bfoo", "Bbar");
store->_db->add_synonym ("Gnew", "Gn");
}
static gboolean
check_version (MuStore *store)
{
/* FIXME clear up versioning semantics */
const gchar *version;
version = mu_store_version (store);
/* no version yet? it must be a new db then; we'll set the version */
if (!version) {
if (!mu_store_set_version (store, MU_XAPIAN_DB_VERSION)) {
g_warning ("failed to set database version");
return FALSE;
}
return TRUE; /* ok, done. */
}
/* we have a version, but is it the right one? */
if (std::strcmp (version, MU_XAPIAN_DB_VERSION) != 0) {
g_warning ("expected db version %s, but got %s",
MU_XAPIAN_DB_VERSION, version);
return FALSE;
}
return TRUE;
}
MuStore*
mu_store_new (const char* xpath)
{
@ -55,15 +103,22 @@ mu_store_new (const char* xpath)
try {
store = g_new0(MuStore,1);
store->_db = new Xapian::WritableDatabase
(xpath, Xapian::DB_CREATE_OR_OPEN);
store->_db = new Xapian::WritableDatabase (xpath,
Xapian::DB_CREATE_OR_OPEN);
if (!check_version (store)) {
mu_store_destroy (store);
return NULL;
}
/* keep count of processed docs */
store->_trx_size = MU_STORE_TRX_SIZE;
store->_in_transaction = false;
store->_processed = 0;
add_synonyms (store);
MU_WRITE_LOG ("%s: opened %s", __FUNCTION__, xpath);
return store;
} MU_XAPIAN_CATCH_BLOCK;
@ -75,6 +130,26 @@ mu_store_new (const char* xpath)
}
void
mu_store_destroy (MuStore *store)
{
if (!store)
return;
try {
mu_store_flush (store);
MU_WRITE_LOG ("closing xapian database with %d documents",
(int)store->_db->get_doccount());
g_free (store->_version);
delete store->_db;
g_free (store);
} MU_XAPIAN_CATCH_BLOCK;
}
unsigned
mu_store_count (MuStore *store)
@ -90,17 +165,18 @@ mu_store_count (MuStore *store)
}
char*
const char*
mu_store_version (MuStore *store)
{
g_return_val_if_fail (store, NULL);
try {
const std::string version (
store->_db->get_metadata (MU_XAPIAN_VERSION_KEY));
return version.empty() ? NULL : g_strdup (version.c_str());
std::string v;
v = store->_db->get_metadata (MU_XAPIAN_VERSION_KEY);
g_free (store->_version);
return store->_version = v.empty() ? NULL : g_strdup (v.c_str());
} MU_XAPIAN_CATCH_BLOCK;
return NULL;
@ -118,7 +194,7 @@ mu_store_set_version (MuStore *store, const char* version)
} MU_XAPIAN_CATCH_BLOCK;
return FALSE;
return FALSE;
}
@ -153,23 +229,6 @@ rollback_trx_if (MuStore *store, gboolean cond)
}
void
mu_store_destroy (MuStore *store)
{
if (!store)
return;
try {
mu_store_flush (store);
MU_WRITE_LOG ("closing xapian database with %d documents",
(int)store->_db->get_doccount());
delete store->_db;
g_free (store);
} MU_XAPIAN_CATCH_BLOCK;
}
void
mu_store_flush (MuStore *store)
@ -178,7 +237,7 @@ mu_store_flush (MuStore *store)
try {
commit_trx_if (store, store->_in_transaction);
store->_db->flush ();
store->_db->flush (); /* => commit, post X 1.1.x */
} MU_XAPIAN_CATCH_BLOCK;
}
@ -186,30 +245,40 @@ mu_store_flush (MuStore *store)
static void
add_terms_values_number (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field)
MuMsgFieldId mfid)
{
const std::string pfx (mu_msg_field_xapian_prefix(field), 1);
gint64 num = mu_msg_get_field_numeric (msg, field);
const std::string pfx (1, mu_msg_field_xapian_prefix(mfid));
gint64 num = mu_msg_get_field_numeric (msg, mfid);
const std::string numstr (Xapian::sortable_serialise((double)num));
doc.add_value ((Xapian::valueno)mu_msg_field_id(field), numstr);
doc.add_term (pfx + numstr);
doc.add_value ((Xapian::valueno)mfid, numstr);
if (mfid == MU_MSG_FIELD_ID_FLAGS) {
const char* flags, *cur;
cur = flags = mu_msg_flags_to_str_s ((MuMsgFlags)num);
while (cur && *cur) {
char kar = tolower (*cur);
doc.add_term (pfx + kar);
++cur;
}
} else
doc.add_term (pfx + numstr);
}
static void
add_terms_values_string (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field)
MuMsgFieldId mfid)
{
const char* str;
str = mu_msg_get_field_string (msg, field);
str = mu_msg_get_field_string (msg, mfid);
if (!str)
return;
const std::string value (str);
const std::string prefix (mu_msg_field_xapian_prefix(field));
const std::string prefix (1, mu_msg_field_xapian_prefix(mfid));
if (mu_msg_field_xapian_index (field)) {
if (mu_msg_field_xapian_index (mfid)) {
Xapian::TermGenerator termgen;
gchar *norm (mu_msg_str_normalize(str, TRUE));
termgen.set_document (doc);
@ -217,28 +286,24 @@ add_terms_values_string (Xapian::Document& doc, MuMsg *msg,
g_free(norm);
}
if (mu_msg_field_xapian_term(field)) {
/* terms can be up to MU_STORE_MAX_TERM_LENGTH (240)
* long; this is a Xapian limit */
// doc.add_term (std::string (prefix + value, 0,
// MU_STORE_MAX_TERM_LENGTH));
/* add a normalized version as well (accents removed,
* lowercase), if it's actually different */
if (mu_msg_field_xapian_term(mfid)) {
/* add a normalized version (accents removed,
* lowercase) */
gchar *norm = mu_msg_str_normalize(str, TRUE);
doc.add_term (std::string (prefix + std::string(norm), 0,
MU_STORE_MAX_TERM_LENGTH));
g_free (norm);
}
if (mu_msg_field_xapian_value(field))
doc.add_value ((Xapian::valueno)mu_msg_field_id (field),
/* the value is what we'll display; the unchanged original */
if (mu_msg_field_xapian_value(mfid))
doc.add_value ((Xapian::valueno)mfid,
value);
}
static void
add_terms_values_body (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field)
MuMsgFieldId mfid)
{
const char *str;
char *norm;
@ -257,7 +322,8 @@ add_terms_values_body (Xapian::Document& doc, MuMsg *msg,
termgen.set_document(doc);
norm = mu_msg_str_normalize (str, TRUE);
termgen.index_text(norm, 1, mu_msg_field_xapian_prefix(field));
termgen.index_text_without_positions
(norm, 1, std::string(1,mu_msg_field_xapian_prefix(mfid)));
g_free (norm);
}
@ -268,33 +334,34 @@ struct _MsgDoc {
typedef struct _MsgDoc MsgDoc;
static void
add_terms_values (const MuMsgField* field, MsgDoc* msgdoc)
add_terms_values (MuMsgFieldId mfid, MsgDoc* msgdoc)
{
MuMsgFieldType type;
/* note: contact-stuff (To/Cc/From) will handled in
* add_contact_info, not here */
if (!mu_msg_field_xapian_index(field) &&
!mu_msg_field_xapian_term(field) &&
!mu_msg_field_xapian_value(field))
if (!mu_msg_field_xapian_index(mfid) &&
!mu_msg_field_xapian_term(mfid) &&
!mu_msg_field_xapian_value(mfid))
return;
type = mu_msg_field_type (field);
type = mu_msg_field_type (mfid);
if (type == MU_MSG_FIELD_TYPE_STRING) {
if (mu_msg_field_id (field) == MU_MSG_FIELD_ID_BODY_TEXT)
if (mfid == MU_MSG_FIELD_ID_BODY_TEXT)
add_terms_values_body (*msgdoc->_doc, msgdoc->_msg,
field);
mfid);
else
add_terms_values_string (*msgdoc->_doc, msgdoc->_msg,
field);
mfid);
return;
}
if (type == MU_MSG_FIELD_TYPE_BYTESIZE ||
type == MU_MSG_FIELD_TYPE_TIME_T ||
type == MU_MSG_FIELD_TYPE_INT) {
add_terms_values_number (*msgdoc->_doc, msgdoc->_msg, field);
add_terms_values_number (*msgdoc->_doc, msgdoc->_msg,
mfid);
return;
}
@ -305,39 +372,38 @@ add_terms_values (const MuMsgField* field, MsgDoc* msgdoc)
static void
each_contact_info (MuMsgContact *contact, MsgDoc *data)
{
std::string pfx;
static const MuMsgField *to_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_TO);
static const MuMsgField *from_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_FROM);
static const MuMsgField *cc_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_CC);
const std::string *pfxp;
static const std::string to_pfx (mu_msg_field_xapian_prefix(to_field));
static const std::string from_pfx (mu_msg_field_xapian_prefix(from_field));
static const std::string cc_pfx (mu_msg_field_xapian_prefix(cc_field));
static const std::string to_pfx (1,
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_TO));
static const std::string from_pfx (1,
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_FROM));
static const std::string cc_pfx (1,
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_CC));
/* use ptr to string to prevent copy... */
switch (contact->type) {
case MU_MSG_CONTACT_TYPE_TO: pfx = to_pfx; break;
case MU_MSG_CONTACT_TYPE_FROM: pfx = from_pfx; break;
case MU_MSG_CONTACT_TYPE_CC: pfx = cc_pfx; break;
default: return; /* other types (like bcc) are ignored */
case MU_MSG_CONTACT_TYPE_TO: pfxp = &to_pfx; break;
case MU_MSG_CONTACT_TYPE_FROM: pfxp = &from_pfx; break;
case MU_MSG_CONTACT_TYPE_CC: pfxp = &cc_pfx; break;
default: return;
/* other types (like bcc) are ignored */
}
if (contact->name && strlen(contact->name) > 0) {
Xapian::TermGenerator termgen;
termgen.set_document (*data->_doc);
char *norm = mu_msg_str_normalize (contact->name, TRUE);
termgen.index_text_without_positions (norm, 1, pfx);
termgen.index_text_without_positions (norm, 1, *pfxp);
g_free (norm);
}
/* don't normalize e-mail address, but do lowercase it */
if (contact->address && strlen (contact->address)) {
char *lower = g_utf8_strdown (contact->address, -1);
data->_doc->add_term (std::string (pfx + lower, 0,
MU_STORE_MAX_TERM_LENGTH));
data->_doc->add_term
(std::string (*pfxp + lower, 0,
MU_STORE_MAX_TERM_LENGTH));
g_free (lower);
}
}
@ -347,10 +413,8 @@ each_contact_info (MuMsgContact *contact, MsgDoc *data)
static std::string
get_message_uid (const char* path)
{
static const MuMsgField* pathfield =
mu_msg_field_from_id(MU_MSG_FIELD_ID_PATH);
static const std::string pathprefix
(mu_msg_field_xapian_prefix(pathfield));
(1, mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_PATH));
return pathprefix + path;
}
@ -377,8 +441,8 @@ mu_store_store (MuStore *store, MuMsg *msg)
/* we must add a unique term, so we can replace
* matching documents */
newdoc.add_term (uid);
mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_terms_values,
&msgdoc);
mu_msg_field_foreach
((MuMsgFieldForEachFunc)add_terms_values, &msgdoc);
/* also store the contact-info as separate terms */
mu_msg_contact_foreach (msg,
(MuMsgContactForeachFunc)each_contact_info,

View File

@ -45,7 +45,7 @@ MuStore* mu_store_new (const char* path);
*
* @param store a valid store, or NULL
*/
void mu_store_destroy (MuStore *store);
void mu_store_destroy (MuStore *store);
/**
@ -59,13 +59,15 @@ void mu_store_destroy (MuStore *store);
unsigned mu_store_count (MuStore *store);
/**
* get a version string for the database
* get a version string for the database; it's a const string, which
* is valid as long MuStore exists and mu_store_version is not called
* again.
*
* @param store a valid MuStore
*
* @return the version string (free with g_free), or NULL in case of error
* @return the version string or NULL in case of error
*/
char* mu_store_version (MuStore *store);
const char* mu_store_version (MuStore *store);
/**
* set the version string for the database

View File

@ -311,7 +311,8 @@ run_query (const char *xpath, const char *query)
return NULL;
}
iter = mu_query_run (xapian, query, NULL, TRUE, 0);
iter = mu_query_run (xapian, query, MU_MSG_FIELD_ID_NONE,
TRUE, 0);
mu_query_destroy (xapian);
if (!iter) {
g_warning ("error: running query failed\n");