Switch to side-by-side view

--- a/src/rcldb/rcldb.cpp
+++ b/src/rcldb/rcldb.cpp
@@ -1,5 +1,5 @@
 #ifndef lint
-static char rcsid[] = "@(#$Id: rcldb.cpp,v 1.120 2007-07-10 09:23:28 dockes Exp $ (C) 2004 J.F.Dockes";
+static char rcsid[] = "@(#$Id: rcldb.cpp,v 1.121 2007-07-12 08:34:51 dockes Exp $ (C) 2004 J.F.Dockes";
 #endif
 /*
  *   This program is free software; you can redistribute it and/or modify
@@ -525,6 +525,22 @@
     return res;
 }
 
+// Generic Xapian exception catching code. We do this quite often,
+// and I have no idea how to do this except for a macro
+#define XCATCHERROR(MSG) \
+ catch (const Xapian::Error &e) {		   \
+    MSG = e.get_msg();				   \
+    if (MSG.empty()) MSG = "Empty error message";  \
+ } catch (const string &s) {			   \
+    MSG = s;					   \
+    if (MSG.empty()) MSG = "Empty error message";  \
+ } catch (const char *s) {			   \
+    MSG = s;					   \
+    if (MSG.empty()) MSG = "Empty error message";  \
+ } catch (...) {				   \
+    MSG = "Caught unknown xapian exception";	   \
+ } 
+
 
 bool Db::open(const string& dir, const string &stops, OpenMode mode, int qops)
 {
@@ -544,7 +560,7 @@
     if (!stops.empty())
 	m_stops.setFile(stops);
 
-    const char *ermsg = "Unknown";
+    string ermsg;
     try {
 	switch (mode) {
 	case DbUpd:
@@ -581,15 +597,7 @@
 		try {
 		    // Make this non-fatal
 		    m_ndb->db.add_database(Xapian::Database(*it));
-		} catch (const Xapian::Error &e) {
-		    aerr = e.get_msg().c_str();
-		} catch (const string &s) {
-		    aerr = s.c_str();
-		} catch (const char *s) {
-		    aerr = s;
-		} catch (...) {
-		    aerr = "Caught unknown exception";
-		}
+		} XCATCHERROR(aerr);
 		if (!aerr.empty())
 		    LOGERR(("Db::Open: error while trying to add database "
 			    "from [%s]: %s\n", it->c_str(), aerr.c_str()));
@@ -600,17 +608,9 @@
 	m_ndb->m_isopen = true;
 	m_basedir = dir;
 	return true;
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg().c_str();
-    } catch (const string &s) {
-	ermsg = s.c_str();
-    } catch (const char *s) {
-	ermsg = s;
-    } catch (...) {
-	ermsg = "Caught unknown exception";
-    }
+    } XCATCHERROR(ermsg);
     LOGERR(("Db::open: exception while opening [%s]: %s\n", 
-	    dir.c_str(), ermsg));
+	    dir.c_str(), ermsg.c_str()));
     return false;
 }
 
@@ -634,7 +634,7 @@
     if (m_ndb->m_isopen == false && !final) 
 	return true;
 
-    const char *ermsg = "Unknown";
+    string ermsg;
     try {
 	bool w = m_ndb->m_iswritable;
 	if (w)
@@ -653,16 +653,8 @@
 	}
 	LOGERR(("Rcl::Db::close(): cant recreate db object\n"));
 	return false;
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg().c_str();
-    } catch (const string &s) {
-	ermsg = s.c_str();
-    } catch (const char *s) {
-	ermsg = s;
-    } catch (...) {
-	ermsg = "Caught unknown exception";
-    }
-    LOGERR(("Db:close: exception while deleting db: %s\n", ermsg));
+    } XCATCHERROR(ermsg);
+    LOGERR(("Db:close: exception while deleting db: %s\n", ermsg.c_str()));
     return false;
 }
 
@@ -680,11 +672,22 @@
 
 int Db::docCnt()
 {
+    int res = -1;
+    string ermsg;
     if (m_ndb && m_ndb->m_isopen) {
-	return m_ndb->m_iswritable ? m_ndb->wdb.get_doccount() : 
-	    m_ndb->db.get_doccount();
-    }
-    return -1;
+	try {
+	    res = m_ndb->m_iswritable ? m_ndb->wdb.get_doccount() : 
+		m_ndb->db.get_doccount();
+	} catch (const Xapian::DatabaseModifiedError &e) {
+	    LOGDEB(("Db::docCnt: got modified error. reopen/retry\n"));
+	    reOpen();
+	    res = m_ndb->m_iswritable ? m_ndb->wdb.get_doccount() : 
+		m_ndb->db.get_doccount();
+	} XCATCHERROR(ermsg);
+	if (!ermsg.empty())
+	    LOGERR(("Db::docCnt: got error: %s\n", ermsg.c_str()));
+    }
+    return res;
 }
 
 bool Db::addQueryDb(const string &dir) 
@@ -718,21 +721,14 @@
     }
     return reOpen();
 }
+
 bool Db::testDbDir(const string &dir)
 {
     string aerr;
     LOGDEB(("Db::testDbDir: [%s]\n", dir.c_str()));
     try {
 	Xapian::Database db(dir);
-    } catch (const Xapian::Error &e) {
-	aerr = e.get_msg().c_str();
-    } catch (const string &s) {
-	aerr = s.c_str();
-    } catch (const char *s) {
-	aerr = s;
-    } catch (...) {
-	aerr = "Caught unknown exception";
-    }
+    } XCATCHERROR(aerr);
     if (!aerr.empty()) {
 	LOGERR(("Db::Open: error while trying to open database "
 		"from [%s]: %s\n", dir.c_str(), aerr.c_str()));
@@ -823,7 +819,7 @@
     }
 #endif
 
-    const char *ermsg;
+    string ermsg;
     try {
 	if (stops.hasStops() && stops.isStop(term)) {
 	    LOGDEB1(("Db: takeword [%s] in stop list\n", term.c_str()));
@@ -839,12 +835,8 @@
 	    doc.add_posting(prefix + term, pos, 1);
 	}
 	return true;
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg().c_str();
-    } catch (...) {
-	ermsg= "Unknown error";
-    }
-    LOGERR(("Db: xapian add_posting error %s\n", ermsg));
+    } XCATCHERROR(ermsg);
+    LOGERR(("Db: xapian add_posting error %s\n", ermsg.c_str()));
     return false;
 }
 
@@ -1102,13 +1094,7 @@
 	    LOGDEB(("Db::add: docid %d added [%s , %s]\n", did, fnc, 
 		    doc.ipath.c_str()));
 	}
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg();
-	if (ermsg.empty()) 
-	    ermsg = "Empty error message";
-    } catch (...) {
-	ermsg= "Unknown error";
-    }
+    } XCATCHERROR(ermsg);
 
     if (!ermsg.empty()) {
 	LOGERR(("Db::add: replace_document failed: %s\n", ermsg.c_str()));
@@ -1118,13 +1104,7 @@
 	    m_ndb->wdb.add_document(newdocument);
 	    LOGDEB(("Db::add: %s added (failed re-seek for duplicate)\n", 
 		    fnc));
-	} catch (const Xapian::Error &e) {
-	    ermsg = e.get_msg();
-	    if (ermsg.empty()) 
-		ermsg = "Empty error message";
-	} catch (...) {
-	    ermsg= "Unknown error";
-	}
+	} XCATCHERROR(ermsg);
 	if (!ermsg.empty()) {
 	    LOGERR(("Db::add: add_document failed: %s\n", ermsg.c_str()));
 	    return false;
@@ -1139,13 +1119,7 @@
 	    LOGDEB(("Db::add: text size >= %d Mb, flushing\n", m_flushMb));
 	    try {
 		m_ndb->wdb.flush();
-	    } catch (const Xapian::Error &e) {
-		ermsg = e.get_msg();
-		if (ermsg.empty()) 
-		    ermsg = "Empty error message";
-	    } catch (...) {
-		ermsg= "Unknown error";
-	    }
+	    } XCATCHERROR(ermsg);
 	    if (!ermsg.empty()) {
 		LOGERR(("Db::add: flush() failed: %s\n", ermsg.c_str()));
 		return false;
@@ -1245,13 +1219,7 @@
 	} catch (const Xapian::DatabaseModifiedError &e) {
 	    LOGDEB(("Db::needUpdate: got modified error. reopen/retry\n"));
 	    reOpen();
-	} catch (const Xapian::Error &e) {
-	    ermsg = e.get_msg();
-	    break;
-	} catch (...) {
-	    ermsg= "Unknown error";
-	    break;
-	}
+	} XCATCHERROR(ermsg);
     }
     LOGERR(("Db::needUpdate: error while checking existence: %s\n", 
 	    ermsg.c_str()));
@@ -1293,7 +1261,7 @@
     if (m_ndb == 0 || m_ndb->m_isopen == false)
 	return false;
 
-    return StemDb:: createDb(m_ndb->m_iswritable ? m_ndb->wdb : m_ndb->db, 
+    return StemDb::createDb(m_ndb->m_iswritable ? m_ndb->wdb : m_ndb->db, 
 			     m_basedir, lang);
 }
 
@@ -1361,7 +1329,7 @@
     string hash;
     pathHash(fn, hash, PATHHASHLEN);
     string pterm  = "P" + hash;
-    const char *ermsg = "";
+    string ermsg;
     try {
 	Xapian::PostingIterator docid = db.postlist_begin(pterm);
 	if (docid == db.postlist_end(pterm))
@@ -1377,17 +1345,9 @@
 	    db.delete_document(*it);
 	}
 	return true;
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg().c_str();
-    } catch (const string &s) {
-	ermsg = s.c_str();
-    } catch (const char *s) {
-	ermsg = s;
-    } catch (...) {
-	ermsg = "Caught unknown exception";
-    }
-    if (*ermsg) {
-	LOGERR(("Db::purgeFile: %s\n", ermsg));
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("Db::purgeFile: %s\n", ermsg.c_str()));
     }
     return false;
 }
@@ -1412,22 +1372,30 @@
     LOGDEB((" pattern: [%s]\n", pattern.c_str()));
 
     // Match pattern against all file names in the db
-    Xapian::TermIterator it = m_ndb->db.allterms_begin(); 
-    it.skip_to("XSFN");
-    for (;it != m_ndb->db.allterms_end(); it++) {
-	if ((*it).find("XSFN") != 0)
-	    break;
-	string fn = (*it).substr(4);
-	LOGDEB2(("Matching [%s] and [%s]\n", pattern.c_str(), fn.c_str()));
-	if (fnmatch(pattern.c_str(), fn.c_str(), 0) != FNM_NOMATCH) {
-	    names.push_back((*it).c_str());
-	}
-	// Limit the match count
-	if (names.size() > 1000) {
-	    LOGERR(("Db::filenameWildExp: too many matched file names\n"));
-	    break;
-	}
-    }
+    string ermsg;
+    try {
+	Xapian::TermIterator it = m_ndb->db.allterms_begin(); 
+	it.skip_to("XSFN");
+	for (;it != m_ndb->db.allterms_end(); it++) {
+	    if ((*it).find("XSFN") != 0)
+		break;
+	    string fn = (*it).substr(4);
+	    LOGDEB2(("Matching [%s] and [%s]\n", pattern.c_str(), fn.c_str()));
+	    if (fnmatch(pattern.c_str(), fn.c_str(), 0) != FNM_NOMATCH) {
+		names.push_back((*it).c_str());
+	    }
+	    // Limit the match count
+	    if (names.size() > 1000) {
+		LOGERR(("Db::filenameWildExp: too many matched file names\n"));
+		break;
+	    }
+	}
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("filenameWildExp: xapian error: %s\n", ermsg.c_str()));
+	return false;
+    }
+
     if (names.empty()) {
 	// Build an impossible query: we know its impossible because we
 	// control the prefixes!
@@ -1459,12 +1427,21 @@
 	return false;
     }
     m_ndb->query = xq;
-    delete m_ndb->enquire;
-    m_ndb->enquire = new Xapian::Enquire(m_ndb->db);
-    m_ndb->enquire->set_query(m_ndb->query);
-    m_ndb->mset = Xapian::MSet();
-    // Get the query description and trim the "Xapian::Query"
-    string d = m_ndb->query.get_description();
+    string ermsg;
+    string d;
+    try {
+	delete m_ndb->enquire;
+	m_ndb->enquire = new Xapian::Enquire(m_ndb->db);
+	m_ndb->enquire->set_query(m_ndb->query);
+	m_ndb->mset = Xapian::MSet();
+	// Get the query description and trim the "Xapian::Query"
+	d = m_ndb->query.get_description();
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGDEB(("Db::SetQuery: xapian error %s\n", ermsg.c_str()));
+	return false;
+    }
+	
     if (d.find("Xapian::Query") == 0)
 	d.erase(0, strlen("Xapian::Query"));
     sdata->setDescription(d);
@@ -1620,32 +1597,52 @@
     TermIter *tit = new TermIter;
     if (tit) {
 	tit->db = m_ndb->m_iswritable ? m_ndb->wdb: m_ndb->db;
-	tit->it = tit->db.allterms_begin();
+	string ermsg;
+	try {
+	    tit->it = tit->db.allterms_begin();
+	} XCATCHERROR(ermsg);
+	if (!ermsg.empty()) {
+	    LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
+	    return 0;
+	}
     }
     return tit;
 }
 bool Db::termWalkNext(TermIter *tit, string &term)
 {
-    
-    if (tit && tit->it != tit->db.allterms_end()) {
-	term = *(tit->it)++;
-	return true;
+    string ermsg;
+    try {
+	if (tit && tit->it != tit->db.allterms_end()) {
+	    term = *(tit->it)++;
+	    return true;
+	}
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
     }
     return false;
 }
 void Db::termWalkClose(TermIter *tit)
 {
-    delete tit;
-}
-
+    try {
+	delete tit;
+    } catch (...) {}
+}
 
 bool Db::termExists(const string& word)
 {
     if (!m_ndb || !m_ndb->m_isopen)
 	return 0;
     Xapian::Database db = m_ndb->m_iswritable ? m_ndb->wdb: m_ndb->db;
-    if (!db.term_exists(word))
-	return false;
+    string ermsg;
+    try {
+	if (!db.term_exists(word))
+	    return false;
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
+	return false;
+    }
     return true;
 }
 
@@ -1669,12 +1666,15 @@
 
     terms.clear();
     Xapian::TermIterator it;
+    string ermsg;
     try {
 	for (it = m_ndb->query.get_terms_begin(); 
 	     it != m_ndb->query.get_terms_end(); it++) {
 	    terms.push_back(*it);
 	}
-    } catch (...) {
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("getQueryTerms: xapian error: %s\n", ermsg.c_str()));
 	return false;
     }
     return true;
@@ -1690,14 +1690,18 @@
     terms.clear();
     Xapian::TermIterator it;
     Xapian::docid id = Xapian::docid(doc.xdocid);
+    string ermsg;
     try {
 	for (it=m_ndb->enquire->get_matching_terms_begin(id);
 	     it != m_ndb->enquire->get_matching_terms_end(id); it++) {
 	    terms.push_back(*it);
 	}
-    } catch (...) {
-	return false;
-    }
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("getQueryTerms: xapian error: %s\n", ermsg.c_str()));
+	return false;
+    }
+
     return true;
 }
 
@@ -1710,20 +1714,24 @@
 	LOGERR(("Db::getResCnt: no query opened\n"));
 	return -1;
     }
+    string ermsg;
     if (m_ndb->mset.size() <= 0) {
 	try {
 	    m_ndb->mset = m_ndb->enquire->get_mset(0, qquantum);
 	} catch (const Xapian::DatabaseModifiedError &error) {
 	    m_ndb->db.reopen();
 	    m_ndb->mset = m_ndb->enquire->get_mset(0, qquantum);
-	} catch (const Xapian::Error & error) {
-	    LOGERR(("enquire->get_mset: exception: %s\n", 
-		    error.get_msg().c_str()));
+	} XCATCHERROR(ermsg);
+	if (!ermsg.empty()) {
+	    LOGERR(("enquire->get_mset: exception: %s\n", ermsg.c_str()));
 	    return -1;
 	}
     }
-
-    return m_ndb->mset.get_matches_lower_bound();
+    int ret = -1;
+    try {
+    ret = m_ndb->mset.get_matches_lower_bound();
+    } catch (...) {}
+    return ret;
 }
 
 
@@ -1861,7 +1869,7 @@
     string hash;
     pathHash(fn, hash, PATHHASHLEN);
     string pqterm  = ipath.empty() ? "P" + hash : "Q" + hash + "|" + ipath;
-    const char *ermsg = "";
+    string ermsg;
     try {
 	if (!m_ndb->db.term_exists(pqterm)) {
 	    // Document found in history no longer in the database.
@@ -1878,17 +1886,9 @@
 	string data = xdoc.get_data();
 	list<string> terms;
 	return m_ndb->dbDataToRclDoc(*docid, data, doc);
-    } catch (const Xapian::Error &e) {
-	ermsg = e.get_msg().c_str();
-    } catch (const string &s) {
-	ermsg = s.c_str();
-    } catch (const char *s) {
-	ermsg = s;
-    } catch (...) {
-	ermsg = "Caught unknown exception";
-    }
-    if (*ermsg) {
-	LOGERR(("Db::getDoc: %s\n", ermsg));
+    } XCATCHERROR(ermsg);
+    if (!ermsg.empty()) {
+	LOGERR(("Db::getDoc: %s\n", ermsg.c_str()));
     }
     return false;
 }
@@ -1900,20 +1900,34 @@
 	LOGERR(("Db::expand: no query opened\n"));
 	return res;
     }
-    Xapian::RSet rset;
-    rset.add_document(Xapian::docid(doc.xdocid));
-    // We don't exclude the original query terms.
-    Xapian::ESet eset = m_ndb->enquire->get_eset(20, rset, false);
-    LOGDEB(("ESet terms:\n"));
-    // We filter out the special terms
-    for (Xapian::ESetIterator it = eset.begin(); it != eset.end(); it++) {
-	LOGDEB((" [%s]\n", (*it).c_str()));
-	if ((*it).empty() || ((*it).at(0)>='A' && (*it).at(0)<='Z'))
+    string ermsg;
+    for (int tries = 0; tries < 2; tries++) {
+	try {
+	    Xapian::RSet rset;
+	    rset.add_document(Xapian::docid(doc.xdocid));
+	    // We don't exclude the original query terms.
+	    Xapian::ESet eset = m_ndb->enquire->get_eset(20, rset, false);
+	    LOGDEB(("ESet terms:\n"));
+	    // We filter out the special terms
+	    for (Xapian::ESetIterator it = eset.begin(); 
+		 it != eset.end(); it++) {
+		LOGDEB((" [%s]\n", (*it).c_str()));
+		if ((*it).empty() || ((*it).at(0)>='A' && (*it).at(0)<='Z'))
+		    continue;
+		res.push_back(*it);
+		if (res.size() >= 10)
+		    break;
+	    }
+	} catch (const Xapian::DatabaseModifiedError &error) {
 	    continue;
-	res.push_back(*it);
-	if (res.size() >= 10)
-	    break;
-    }
+	} XCATCHERROR(ermsg);
+	if (!ermsg.empty()) {
+	    LOGERR(("Db::expand: xapian error %s\n", ermsg.c_str()));
+	    res.clear();
+	}
+	break;
+    }
+
     return res;
 }