--- a/src/rcldb/searchdata.cpp
+++ b/src/rcldb/searchdata.cpp
@@ -46,32 +46,106 @@
static const int original_term_wqf_booster = 10;
+/* The dates-to-query routine is is lifted quasi-verbatim but
+ * modified from xapian-omega:date.cc. Copyright info:
+ *
+ * Copyright 1999,2000,2001 BrightStation PLC
+ * Copyright 2001 James Aylett
+ * Copyright 2001,2002 Ananova Ltd
+ * Copyright 2002 Intercede 1749 Ltd
+ * Copyright 2002,2003,2006 Olly Betts
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+static Xapian::Query
+date_range_filter(int y1, int m1, int d1, int y2, int m2, int d2)
+{
+ // Xapian uses a smallbuf and snprintf. Can't be bothered, we're
+ // only doing %d's !
+ char buf[200];
+ sprintf(buf, "D%04d%02d", y1, m1);
+ vector<Xapian::Query> v;
+
+ int d_last = monthdays(m1, y1);
+ int d_end = d_last;
+ if (y1 == y2 && m1 == m2 && d2 < d_last) {
+ d_end = d2;
+ }
+ // Deal with any initial partial month
+ if (d1 > 1 || d_end < d_last) {
+ for ( ; d1 <= d_end ; d1++) {
+ sprintf(buf + 7, "%02d", d1);
+ v.push_back(Xapian::Query(buf));
+ }
+ } else {
+ buf[0] = 'M';
+ v.push_back(Xapian::Query(buf));
+ }
+
+ if (y1 == y2 && m1 == m2) {
+ return Xapian::Query(Xapian::Query::OP_OR, v.begin(), v.end());
+ }
+
+ int m_last = (y1 < y2) ? 12 : m2 - 1;
+ while (++m1 <= m_last) {
+ sprintf(buf + 5, "%02d", m1);
+ buf[0] = 'M';
+ v.push_back(Xapian::Query(buf));
+ }
+
+ if (y1 < y2) {
+ while (++y1 < y2) {
+ sprintf(buf + 1, "%04d", y1);
+ buf[0] = 'Y';
+ v.push_back(Xapian::Query(buf));
+ }
+ sprintf(buf + 1, "%04d", y2);
+ buf[0] = 'M';
+ for (m1 = 1; m1 < m2; m1++) {
+ sprintf(buf + 5, "%02d", m1);
+ v.push_back(Xapian::Query(buf));
+ }
+ }
+
+ sprintf(buf + 5, "%02d", m2);
+
+ // Deal with any final partial month
+ if (d2 < monthdays(m2, y2)) {
+ buf[0] = 'D';
+ for (d1 = 1 ; d1 <= d2; d1++) {
+ sprintf(buf + 7, "%02d", d1);
+ v.push_back(Xapian::Query(buf));
+ }
+ } else {
+ buf[0] = 'M';
+ v.push_back(Xapian::Query(buf));
+ }
+
+ return Xapian::Query(Xapian::Query::OP_OR, v.begin(), v.end());
+}
+
bool SearchData::toNativeQuery(Rcl::Db &db, void *d)
{
Xapian::Query xq;
m_reason.erase();
- if (m_query.size() < 1) {
+ if (!m_query.size() && !m_haveDates) {
m_reason = "empty query";
return false;
}
-
- // It's not allowed to have a pure negative query and also it
- // seems that Xapian doesn't like the first element to be AND_NOT
- qlist_it_t itnotneg = m_query.end();
- for (qlist_it_t it = m_query.begin(); it != m_query.end(); it++) {
- if ((*it)->m_tp != SCLT_EXCL) {
- itnotneg = it;
- break;
- }
- }
- if (itnotneg == m_query.end()) {
- LOGERR(("SearchData::toNativeQuery: can't have all negative clauses"));
- m_reason = "Can't have only negative clauses";
- return false;
- }
- if ((*m_query.begin())->m_tp == SCLT_EXCL)
- iter_swap(m_query.begin(), itnotneg);
// Walk the clause list translating each in turn and building the
// Xapian query tree
@@ -91,12 +165,59 @@
// addClause())
Xapian::Query::op op;
if (m_tp == SCLT_AND) {
- op = (*it)->m_tp == SCLT_EXCL ?
- Xapian::Query::OP_AND_NOT: Xapian::Query::OP_AND;
+ if ((*it)->m_tp == SCLT_EXCL) {
+ op = Xapian::Query::OP_AND_NOT;
+ } else {
+ op = Xapian::Query::OP_AND;
+ }
} else {
op = Xapian::Query::OP_OR;
}
- xq = xq.empty() ? nq : Xapian::Query(op, xq, nq);
+ if (xq.empty()) {
+ if (op == Xapian::Query::OP_AND_NOT)
+ xq = Xapian::Query(op, Xapian::Query::MatchAll, nq);
+ else
+ xq = nq;
+ } else {
+ xq = Xapian::Query(op, xq, nq);
+ }
+ }
+
+ if (m_haveDates) {
+ // If one of the extremities is unset, compute db extremas
+ if (m_dates.y1 == 0 || m_dates.y2 == 0) {
+ int minyear = 1970, maxyear = 2100;
+ if (!db.maxYearSpan(&minyear, &maxyear)) {
+ LOGERR(("Can't retrieve index min/max dates\n"));
+ //whatever, go on.
+ }
+ if (m_dates.y1 == 0) {
+ m_dates.y1 = minyear;
+ m_dates.m1 = 1;
+ m_dates.d1 = 1;
+ }
+ if (m_dates.y2 == 0) {
+ m_dates.y2 = maxyear;
+ m_dates.m2 = 12;
+ m_dates.d2 = 31;
+ }
+ }
+ LOGDEB(("Db::toNativeQuery: date interval: %d-%d-%d/%d-%d-%d\n",
+ m_dates.y1, m_dates.m1, m_dates.d1,
+ m_dates.y2, m_dates.m2, m_dates.d2));
+ Xapian::Query dq = date_range_filter(m_dates.y1, m_dates.m1, m_dates.d1,
+ m_dates.y2, m_dates.m2, m_dates.d2);
+ if (dq.empty()) {
+ LOGINFO(("Db::toNativeQuery: date filter is empty\n"));
+ }
+ // If no probabilistic query is provided then promote the daterange
+ // filter to be THE query instead of filtering an empty query.
+ if (xq.empty()) {
+ LOGINFO(("Db::toNativeQuery: proba query is empty\n"));
+ xq = dq;
+ } else {
+ xq = Xapian::Query(Xapian::Query::OP_FILTER, xq, dq);
+ }
}
// Add the file type filtering clause if any
@@ -116,7 +237,6 @@
}
}
- list<Xapian::Query> pqueries;
Xapian::Query tq;
for (vector<string>::iterator it = exptps.begin();
it != exptps.end(); it++) {
@@ -157,6 +277,7 @@
m_topdir.erase();
m_description.erase();
m_reason.erase();
+ m_haveDates = false;
}
// Am I a file name only search ? This is to turn off term highlighting