Ticket #295: remotepostsource2.patch

File remotepostsource2.patch, 29.8 KB (added by Richard Boulton, 16 years ago)

Latest version of patch

  • xapian-core/matcher/externalpostlist.cc

     
    2929
    3030using namespace std;
    3131
    32 ExternalPostList::ExternalPostList(Xapian::PostingSource *source_,
     32ExternalPostList::ExternalPostList(const Xapian::Database & db,
     33                                   Xapian::PostingSource *source_,
    3334                                   double factor_)
    34     : source(source_), current(0), factor(factor_)
     35    : source(source_), source_is_owned(false), current(0), factor(factor_)
    3536{
    3637    Assert(source);
    37     source->reset();
     38    Xapian::PostingSource * newsource = source->clone();
     39    if (newsource != NULL) {
     40        source = newsource;
     41        source_is_owned = true;
     42    }
     43    source->reset(db);
    3844}
    3945
     46ExternalPostList::~ExternalPostList()
     47{
     48    if (source_is_owned) {
     49        delete source;
     50    }
     51}
     52
    4053Xapian::doccount
    4154ExternalPostList::get_termfreq_min() const
    4255{
  • xapian-core/matcher/queryoptimiser.cc

     
    6464
    6565        case Xapian::Query::Internal::OP_EXTERNAL_SOURCE:
    6666            Assert(query->external_source);
    67             RETURN(new ExternalPostList(query->external_source, factor));
     67            RETURN(new ExternalPostList(
     68                Xapian::Database(const_cast<Xapian::Database::Internal *>(&db)),
     69                query->external_source, factor));
    6870
    6971        case Xapian::Query::OP_AND:
    7072        case Xapian::Query::OP_FILTER:
  • xapian-core/matcher/externalpostlist.h

     
    2929
    3030class ExternalPostList : public PostList {
    3131    Xapian::PostingSource * source;
     32    bool source_is_owned;
    3233
    3334    Xapian::docid current;
    3435
     
    4344    PostList * update_after_advance();
    4445
    4546  public:
    46     ExternalPostList(Xapian::PostingSource *source_, double factor_);
     47    ExternalPostList(const Xapian::Database & db,
     48                     Xapian::PostingSource *source_,
     49                     double factor_);
     50    ~ExternalPostList();
    4751
    4852    Xapian::doccount get_termfreq_min() const;
    4953
  • xapian-core/tests/internaltest.cc

     
    452452        Xapian::Query::Internal * qint;
    453453
    454454        s = query->internal->serialise();
    455         qint = Xapian::Query::Internal::unserialise(s);
     455        map<string, Xapian::PostingSource *> m;
     456        qint = Xapian::Query::Internal::unserialise(s, m);
    456457
    457458        TEST(qint->serialise() == s);
    458459        delete qint;
  • xapian-core/tests/api_db.cc

     
    18941894        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    18951895    { }
    18961896
    1897     void reset() { did = 0; }
     1897    MyOddPostingSource(Xapian::doccount num_docs_,
     1898                       Xapian::doccount last_docid_)
     1899        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     1900    { }
    18981901
     1902    PostingSource * clone() const { return new MyOddPostingSource(num_docs, last_docid); }
     1903
     1904    void reset(const Xapian::Database &) { did = 0; }
     1905
    18991906    // These bounds could be better, but that's not important here.
    19001907    Xapian::doccount get_termfreq_min() const { return 0; }
    19011908
     
    19321939    Xapian::Enquire enq(db);
    19331940    MyOddPostingSource src(db);
    19341941
    1935     // Check that passing NULL is rejected as intended.
    1936     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(NULL));
    1937     Xapian::PostingSource * nullsrc = NULL;
    1938     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(nullsrc));
    1939                
    19401942    enq.set_query(Xapian::Query(&src));
    19411943
    19421944    Xapian::MSet mset = enq.get_mset(0, 10);
     
    19881990        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    19891991    { }
    19901992
    1991     void reset() { did = 0; }
     1993    MyOddWeightingPostingSource(Xapian::doccount num_docs_,
     1994                                Xapian::doccount last_docid_)
     1995        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     1996    { }
    19921997
     1998    PostingSource * clone() const { return new MyOddWeightingPostingSource(num_docs, last_docid); }
     1999
     2000    void reset(const Xapian::Database &) { did = 0; }
     2001
    19932002    Xapian::weight get_weight() const {
    19942003        return (did % 2) ? 1000 : 0.001;
    19952004    }
     
    20852094        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    20862095    { }
    20872096
    2088     void reset() { did = 0; }
     2097    MyDontAskWeightPostingSource(Xapian::doccount num_docs_,
     2098                                 Xapian::doccount last_docid_)
     2099        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     2100    { }
    20892101
     2102    PostingSource * clone() const { return new MyDontAskWeightPostingSource(num_docs, last_docid); }
     2103
     2104    void reset(const Xapian::Database &) { did = 0; }
     2105
    20902106    Xapian::weight get_weight() const {
    20912107        FAIL_TEST("MyDontAskWeightPostingSource::get_weight() called");
    20922108    }
     
    21582174}
    21592175
    21602176// Check that valueweightsource works correctly.
    2161 DEFINE_TESTCASE(valueweightsource1, backend && !remote) {
    2162     // FIXME: PostingSource doesn't currently work well with multi databases
    2163     // but we should try to resolve that issue.
    2164     SKIP_TEST_FOR_BACKEND("multi");
     2177DEFINE_TESTCASE(valueweightsource1, backend) {
    21652178    Xapian::Database db(get_database("apitest_phrase"));
    21662179    Xapian::Enquire enq(db);
    2167     Xapian::ValueWeightPostingSource src(db, 11);
     2180    Xapian::ValueWeightPostingSource src(11);
    21682181
    21692182    // Should be in descending order of length
    21702183    tout << "RAW" << endl;
     
    21962209// Check that valueweightsource gives the correct bounds for those databases
    21972210// which support value statistics.
    21982211DEFINE_TESTCASE(valueweightsource2, backend && valuestats) {
    2199     // FIXME: PostingSource doesn't currently work well with multi databases
    2200     // but we should try to resolve that issue.
    2201     SKIP_TEST_FOR_BACKEND("multi");
    22022212    Xapian::Database db(get_database("apitest_phrase"));
    2203     Xapian::ValueWeightPostingSource src(db, 11);
     2213    Xapian::ValueWeightPostingSource src(11);
     2214    src.reset(db);
    22042215    TEST_EQUAL(src.get_termfreq_min(), 17);
    22052216    TEST_EQUAL(src.get_termfreq_est(), 17);
    22062217    TEST_EQUAL(src.get_termfreq_max(), 17);
     
    22112222
    22122223// Check that valueweightsource skip_to() can stay in the same position.
    22132224DEFINE_TESTCASE(valueweightsource3, backend && valuestats) {
    2214     // FIXME: PostingSource doesn't currently work well with multi databases
    2215     // but we should try to resolve that issue.
    2216     SKIP_TEST_FOR_BACKEND("multi");
    22172225    Xapian::Database db(get_database("apitest_phrase"));
    2218     Xapian::ValueWeightPostingSource src(db, 11);
     2226    Xapian::ValueWeightPostingSource src(11);
     2227    src.reset(db);
    22192228    TEST(!src.at_end());
    22202229    src.skip_to(8, 0.0);
    22212230    TEST(!src.at_end());
  • xapian-core/tests/api_percentages.cc

     
    4545        : maxwt(0.0), started(false)
    4646    {}
    4747
     48    MyPostingSource(const std::vector<std::pair<Xapian::docid, Xapian::weight> > &weights_,
     49                    Xapian::weight maxwt_)
     50        : weights(weights_), maxwt(maxwt_), started(false)
     51    {}
     52
     53
     54    PostingSource * clone() const
     55    {
     56        return new MyPostingSource(weights, maxwt);
     57    }
     58
    4859    void append_docweight(Xapian::docid did, Xapian::weight wt)
    4960    {
    5061        weights.push_back(make_pair(did, wt));
     
    5566        if (wt > maxwt) maxwt = wt;
    5667    }
    5768
    58     void reset() { started = false; }
     69    void reset(const Xapian::Database &) { started = false; }
    5970
    6071    Xapian::weight get_weight() const {
    6172        return i->second;
  • xapian-core/include/xapian/postingsource.h

     
    137137    /// Return the current docid.
    138138    virtual Xapian::docid get_docid() const = 0;
    139139
     140    /** Clone the posting source.
     141     *
     142     *  The clone should inherit the configuration of the parent, but need not
     143     *  inherit the state.  ie, the clone does not need to be in the same
     144     *  iteration position as the original: the matcher will always call
     145     *  reset() on the clone before attempting to move the iterator, or read
     146     *  the information about the current position of the iterator.
     147     *
     148     *  This may return NULL to indicate that cloning is not supported.  In
     149     *  this case, the PostingSource may only be used with a single-database
     150     *  search.
     151     *
     152     *  The default implementation returns NULL.
     153     */
     154    virtual PostingSource * clone() const;
     155
     156    /** Name of the posting source, for performing remote searches.
     157     *
     158     *  If the subclass is called FooPostingSource, this should return "Foo".
     159     *
     160     *  This should only be implemented if serialise() and unserialise() are
     161     *  also implemented.
     162     *
     163     *  The default implmenentation returns an empty string, to indicate that
     164     *  serialise() and unserialise() are not implemented.
     165     */
     166    virtual std::string name() const;
     167
     168    /** Serialise object parameters into a string.
     169     *
     170     *  The serialised parameters should represent the configuration of the
     171     *  posting source, but need not (indeed, should not) represent the current
     172     *  iteration state.
     173     */
     174    virtual std::string serialise() const;
     175
     176    /** Create object given string serialisation returned by serialise().
     177     *
     178     *  @param s A serialised instance of this PostingSource subclass.
     179     */
     180    virtual PostingSource * unserialise(const std::string &s) const;
     181
    140182    /** Reset this PostingSource to its freshly constructed state.
    141183     *
    142184     *  This is called automatically by the matcher prior to each query being
    143185     *  processed.
     186     *
     187     *  FIXME - document the db parameter.
    144188     */
    145     virtual void reset() = 0;
     189    virtual void reset(const Database & db) = 0;
    146190
    147191    /** Return a string describing this object.
    148192     *
     
    196240    /// An upper bound on the value returned.
    197241    double max_value;
    198242
     243    /// Upper bound on the value returned specified in constructor.
     244    double specified_max_value;
     245
    199246  public:
    200247    /** Construct a ValueWeightPostingSource.
    201248     *
    202249     *  @param db_ The database to read values from.
    203250     *  @param valno_ The value slot to read values from.
    204251     */
    205     ValueWeightPostingSource(Xapian::Database db_, Xapian::valueno valno_);
     252    ValueWeightPostingSource(Xapian::valueno valno_);
    206253
    207254    /** Construct a ValueWeightPostingSource.
    208255     *
     
    214261     *  constructor need only be used if more accurate information is
    215262     *  available.
    216263     */
    217     ValueWeightPostingSource(Xapian::Database db_, Xapian::valueno valno_,
    218                              double max_weight_);
     264    ValueWeightPostingSource(Xapian::valueno valno_, double max_weight_);
    219265
    220266    Xapian::doccount get_termfreq_min() const;
    221267    Xapian::doccount get_termfreq_est() const;
     
    232278
    233279    Xapian::docid get_docid() const;
    234280
    235     void reset();
     281    ValueWeightPostingSource * clone() const;
     282    std::string name() const;
     283    std::string serialise() const;
     284    PostingSource * unserialise(const std::string &s) const;
    236285
     286    void reset(const Database & db_);
     287
    237288    std::string get_description() const;
    238289};
    239290
  • xapian-core/include/xapian/query.h

     
    2525#ifndef XAPIAN_INCLUDED_QUERY_H
    2626#define XAPIAN_INCLUDED_QUERY_H
    2727
     28#include <map>
    2829#include <string>
    2930#include <vector>
    3031
     
    204205         */
    205206        Query(Query::op op_, Xapian::valueno valno, const std::string &value);
    206207
    207         /// Construct an external source query.
     208        /** Construct an external source query.
     209         *
     210         *  The posting source will be cloned immediately, so the source
     211         *  supplied may be safely deallocated after this call.
     212         *
     213         *  @param external_source The source to use in the query.
     214         */
    208215        explicit Query(Xapian::PostingSource * external_source);
    209216
    210217        /** A query which matches all documents in the database. */
     
    325332        /// External posting source.
    326333        Xapian::PostingSource * external_source;
    327334
     335        /// Flag, indicating whether the external source is owned by the query.
     336        bool external_source_owned;
     337
    328338        /** swap the contents of this with another Xapian::Query::Internal,
    329339         *  in a way which is guaranteed not to throw.  This is
    330340         *  used with the assignment operator to make it exception
     
    400410        Internal(op_t op_, Xapian::valueno valno, const std::string &value);
    401411
    402412        /// Construct an external source query.
    403         explicit Internal(Xapian::PostingSource * external_source_);
     413        explicit Internal(Xapian::PostingSource * external_source_, bool owned);
    404414
    405415        /** Destructor. */
    406416        ~Internal();
    407417
    408         static Xapian::Query::Internal * unserialise(const std::string &s);
     418        static Xapian::Query::Internal * unserialise(const std::string &s,
     419                const std::map<std::string, Xapian::PostingSource *> &sources);
    409420
    410421        /** Add a subquery.
    411422         */
  • xapian-core/net/remoteserver.cc

     
    114114    wtschemes[weight->name()] = weight;
    115115    weight = new Xapian::TradWeight;
    116116    wtschemes[weight->name()] = weight;
     117
     118    Xapian::PostingSource * source;
     119    source = new Xapian::ValueWeightPostingSource(0);
     120    postingsources[source->name()] = source;
    117121}
    118122
    119123RemoteServer::~RemoteServer()
     
    121125    delete db;
    122126    // wdb is either NULL or equal to db, so we shouldn't delete it too!
    123127
    124     map<string, Xapian::Weight*>::const_iterator i;
    125     for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
    126         delete i->second;
     128    {
     129        map<string, Xapian::Weight*>::const_iterator i;
     130        for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
     131            delete i->second;
     132        }
    127133    }
     134
     135    {
     136        map<string, Xapian::PostingSource *>::const_iterator i;
     137        for (i = postingsources.begin(); i != postingsources.end(); ++i) {
     138            delete i->second;
     139        }
     140    }
    128141}
    129142
    130143message_type
     
    365378
    366379    // Unserialise the Query.
    367380    len = decode_length(&p, p_end, true);
    368     AutoPtr<Xapian::Query::Internal> query(Xapian::Query::Internal::unserialise(string(p, len)));
     381    AutoPtr<Xapian::Query::Internal> query(Xapian::Query::Internal::unserialise(string(p, len), postingsources));
    369382    p += len;
    370383
    371384    // Unserialise assorted Enquire settings.
     
    610623
    611624    send_message(REPLY_ADDDOCUMENT, encode_length(did));
    612625}
     626
     627
     628void
     629RemoteServer::register_posting_source(const Xapian::PostingSource &source)
     630{
     631    if (source.name().empty()) {
     632        throw Xapian::InvalidOperationError("Unable to register posting source - name() method returns empty string.");
     633    }
     634    Xapian::PostingSource * sourceclone = source.clone();
     635    if (!sourceclone) {
     636        throw Xapian::InvalidOperationError("Unable to register posting source - clone() method returns NULL.");
     637    }
     638    try {
     639        postingsources[source.name()] = sourceclone;
     640    } catch(...) {
     641        delete sourceclone;
     642        throw;
     643    }
     644}
  • xapian-core/common/remoteserver.h

     
    2424
    2525#include "xapian/database.h"
    2626#include "xapian/enquire.h"
     27#include "xapian/postingsource.h"
    2728#include "xapian/visibility.h"
    2829
    2930#include "remoteconnection.h"
     
    3132#include <map>
    3233#include <string>
    3334
    34 // Forward declaration
    35 namespace Xapian { class Weight; }
    36 
    3735using namespace std;
    3836
    3937/** Remote backend server base class. */
     
    7068    /// Registered weighting schemes.
    7169    map<string, Xapian::Weight *> wtschemes;
    7270
     71    /// Registered external posting sources.
     72    map<string, Xapian::PostingSource *> postingsources;
     73
    7374    /// Accept a message from the client.
    7475    message_type get_message(Xapian::timeout timeout, string & result,
    7576                             message_type required_type = MSG_MAX);
     
    173174    void register_weighting_scheme(const Xapian::Weight &wt) {
    174175        wtschemes[wt.name()] = wt.clone();
    175176    }
     177
     178    /** Register a user-defined posting source class.
     179     */
     180    void register_posting_source(const Xapian::PostingSource &source);
    176181};
    177182
    178183#endif // XAPIAN_INCLUDED_REMOTESERVER_H
  • xapian-core/api/omqueryinternal.cc

     
    4242#include <cfloat>
    4343#include <climits>
    4444#include <cmath>
     45#include <map>
    4546#include <set>
    4647#include <vector>
    4748
     
    142143        result += '[';
    143144        result += encode_length(tname.length());
    144145        result += tname;
    145         if (term_pos != curpos) result += '@' + om_tostring(term_pos);
    146         if (wqf != 1) result += '#' + om_tostring(wqf);
     146        if (term_pos != curpos) result += '@' + om_tostring(term_pos); // FIXME - should this use encode_length()?
     147        if (wqf != 1) result += '#' + om_tostring(wqf); // FIXME - should this use encode_length()?
    147148        ++curpos;
    148149    } else if (op == Xapian::Query::Internal::OP_EXTERNAL_SOURCE) {
    149         throw Xapian::UnimplementedError("Remote backend doesn't support PostingSource");
     150        string sourcename = external_source->name();
     151        if (sourcename.empty())
     152            throw Xapian::UnimplementedError("This PostingSource doesn't support remote use.");
     153        result += '!';
     154        result += encode_length(sourcename.length());
     155        result += sourcename;
     156        string sourcedata = external_source->serialise();
     157        result += encode_length(sourcedata.length());
     158        result += sourcedata;
    150159    } else {
    151160        result += "(";
    152161        for (subquery_list::const_iterator i = subqs.begin();
     
    158167            case Xapian::Query::Internal::OP_LEAF:
    159168                Assert(false);
    160169                break;
     170            case Xapian::Query::Internal::OP_EXTERNAL_SOURCE:
     171                Assert(false);
     172                break;
    161173            case Xapian::Query::OP_AND:
    162174                result += "&";
    163175                break;
     
    380392    const char *p;
    381393    const char *end;
    382394    Xapian::termpos curpos;
     395    const map<string, Xapian::PostingSource *> & sources;
    383396
    384397    Xapian::Query::Internal * readquery();
     398    Xapian::Query::Internal * readexternal();
    385399    Xapian::Query::Internal * readcompound();
    386400
    387401  public:
    388     QUnserial(const string & s) : p(s.c_str()), end(p + s.size()), curpos(1) { }
     402    QUnserial(const string & s,
     403              const map<string, Xapian::PostingSource *> & sources_)
     404            : p(s.c_str()), end(p + s.size()), curpos(1), sources(sources_) { }
    389405    Xapian::Query::Internal * decode();
    390406};
    391407
     
    424440            ++curpos;
    425441            return new Xapian::Query::Internal(tname, wqf, term_pos);
    426442        }
     443        case '!':
     444            return readexternal();
    427445        case '(':
    428446            return readcompound();
    429447        default:
     
    432450    }
    433451}
    434452
     453Xapian::Query::Internal *
     454QUnserial::readexternal()
     455{
     456    if (p == end)
     457        throw Xapian::InvalidArgumentError("Bad serialised query");
     458
     459    size_t length = decode_length(&p, end, true);
     460    string sourcename(p, length);
     461    map<string, Xapian::PostingSource *>::const_iterator i;
     462    i = sources.find(string(p, length));
     463    if (i == sources.end()) {
     464        throw Xapian::InvalidArgumentError("PostingSource " + string(p, length) + " not registered");
     465    }
     466
     467    p += length;
     468    length = decode_length(&p, end, true);
     469    string sourcedata(p, length);
     470    p += length;
     471
     472    return new Xapian::Query::Internal(i->second->unserialise(sourcedata), true);
     473}
     474
    435475static Xapian::Query::Internal *
    436476qint_from_vector(Xapian::Query::op op,
    437477                 const vector<Xapian::Query::Internal *> & vec,
     
    476516                    --p;
    477517                    subqs.push_back(readquery());
    478518                    break;
     519                case '!':
     520                    subqs.push_back(readexternal());
     521                    break;
    479522                case '(': {
    480523                    subqs.push_back(readcompound());
    481524                    break;
     
    563606}
    564607
    565608Xapian::Query::Internal *
    566 Xapian::Query::Internal::unserialise(const string &s)
     609Xapian::Query::Internal::unserialise(const string &s,
     610                        const map<string, Xapian::PostingSource *> & sources)
    567611{
    568612    Assert(s.length() > 1);
    569     QUnserial u(s);
     613    QUnserial u(s, sources);
    570614    Xapian::Query::Internal * qint = u.decode();
    571615    AssertEq(s, qint->serialise());
    572616    return qint;
    573617}
    574618#else
    575619Xapian::Query::Internal *
    576 Xapian::Query::Internal::unserialise(const string &)
     620Xapian::Query::Internal::unserialise(const string &,
     621                        const map<string, Xapian::PostingSource *> & sources)
    577622{
    578623    throw Xapian::InternalError("query serialisation not compiled in");
    579624}
     
    597642    std::swap(term_pos, other.term_pos);
    598643    std::swap(wqf, other.wqf);
    599644    std::swap(external_source, other.external_source);
     645    std::swap(external_source_owned, other.external_source_owned);
    600646}
    601647
    602648Xapian::Query::Internal::Internal(const Xapian::Query::Internal &copyme)
     
    608654          str_parameter(copyme.str_parameter),
    609655          term_pos(copyme.term_pos),
    610656          wqf(copyme.wqf),
    611           external_source(copyme.external_source)
     657          external_source(NULL),
     658          external_source_owned(false)
    612659{
    613660    for (subquery_list::const_iterator i = copyme.subqs.begin();
    614661         i != copyme.subqs.end();
    615662         ++i) {
    616663        subqs.push_back(new Xapian::Query::Internal(**i));
    617664    }
     665    if (copyme.external_source) {
     666        external_source = copyme.external_source->clone();
     667        if (external_source == NULL) {
     668            external_source = copyme.external_source;
     669            external_source_owned = false;
     670        } else {
     671            external_source_owned = true;
     672        }
     673    }
    618674}
    619675
    620676//////////////////////////////////////////
     
    627683          parameter(0),
    628684          tname(tname_),
    629685          term_pos(term_pos_),
    630           wqf(wqf_)
     686          wqf(wqf_),
     687          external_source(NULL),
     688          external_source_owned(false)
    631689{
    632690    validate_query();
    633691}
     
    638696          parameter(parameter_),
    639697          tname(),
    640698          term_pos(0),
    641           wqf(0)
     699          wqf(0),
     700          external_source(NULL),
     701          external_source_owned(false)
    642702{
    643703    if (parameter != 0 && op != OP_PHRASE && op != OP_NEAR && op != OP_ELITE_SET)
    644704        throw Xapian::InvalidArgumentError("parameter is only meaningful for OP_NEAR, OP_PHRASE, or OP_ELITE_SET");
     
    649709        : op(op_),
    650710          parameter(Xapian::termcount(valno)),
    651711          tname(begin),
    652           str_parameter(end)
     712          str_parameter(end),
     713          external_source(NULL),
     714          external_source_owned(false)
    653715{
    654716    if (op != OP_VALUE_RANGE)
    655717        throw Xapian::InvalidArgumentError("This constructor is only meaningful for OP_VALUE_RANGE");
     
    660722                                  const std::string &value)
    661723        : op(op_),
    662724          parameter(Xapian::termcount(valno)),
    663           tname(value)
     725          tname(value),
     726          external_source(NULL),
     727          external_source_owned(false)
    664728{
    665729    if (op != OP_VALUE_GE && op != OP_VALUE_LE)
    666730        throw Xapian::InvalidArgumentError("This constructor is only meaningful for OP_VALUE_GE or OP_VALUE_LE");
     
    674738    validate_query();
    675739}
    676740
    677 Xapian::Query::Internal::Internal(PostingSource * external_source_)
    678     : op(OP_EXTERNAL_SOURCE), external_source(external_source_)
     741Xapian::Query::Internal::Internal(PostingSource * external_source_, bool owned)
     742        : op(OP_EXTERNAL_SOURCE), external_source(external_source_),
     743          external_source_owned(owned)
    679744{
    680     if (!external_source)
    681         throw Xapian::InvalidArgumentError("The external_source parameter can not be NULL");
     745    Assert(external_source);
    682746}
    683747
    684748Xapian::Query::Internal::~Internal()
     
    687751    for (i = subqs.begin(); i != subqs.end(); i++) {
    688752        delete *i;
    689753    }
     754    if (external_source_owned) {
     755        delete external_source;
     756    }
    690757}
    691758
    692759Xapian::Query::Internal *
  • xapian-core/api/omquery.cc

     
    3030
    3131#include <xapian/error.h>
    3232#include <xapian/enquire.h>
    33 
     33#include <xapian/postingsource.h>
    3434#include <xapian/termiterator.h>
    3535
    3636#include <vector>
     
    162162}
    163163
    164164Query::Query(PostingSource * external_source)
    165         : internal(new Query::Internal(external_source))
     165        : internal(NULL)
    166166{
    167167    DEBUGAPICALL(void, "Xapian::Query::Query", external_source);
     168    PostingSource * clone = external_source->clone();
     169    if (clone) {
     170        internal = new Query::Internal(clone, true);
     171    } else {
     172        internal = new Query::Internal(external_source, false);
     173    }
    168174}
    169175
    170176// Copy constructor
  • xapian-core/api/postingsource.cc

     
    3232#include "xapian/queryparser.h" // For sortable_unserialise
    3333
    3434#include "omassert.h"
     35#include "serialise.h"
     36#include "serialise-double.h"
    3537#include "utils.h"
    3638
    3739#include <cfloat>
     
    6769    return true;
    6870}
    6971
     72PostingSource *
     73PostingSource::clone() const
     74{
     75    return NULL;
     76}
     77
    7078std::string
     79PostingSource::name() const
     80{
     81    return std::string();
     82}
     83
     84std::string
     85PostingSource::serialise() const
     86{
     87    throw Xapian::InvalidOperationError("serialise() not supported for this PostingSource");
     88}
     89
     90PostingSource *
     91PostingSource::unserialise(const std::string &) const
     92{
     93    throw Xapian::InvalidOperationError("unserialise() not supported for this PostingSource");
     94}
     95
     96std::string
    7197PostingSource::get_description() const
    7298{
    7399    return "Xapian::PostingSource subclass";
    74100}
    75101
    76102
    77 ValueWeightPostingSource::ValueWeightPostingSource(Xapian::Database db_,
    78                                                    Xapian::valueno valno_)
    79         : db(db_),
    80           valno(valno_),
    81           current_docid(0),
    82           last_docid(db.get_lastdocid()),
    83           current_value(0.0)
     103ValueWeightPostingSource::ValueWeightPostingSource(Xapian::valueno valno_)
     104        : valno(valno_),
     105          specified_max_value(DBL_MAX)
    84106{
    85     try {
    86         termfreq_max = db.get_value_freq(valno);
    87         termfreq_est = termfreq_max;
    88         termfreq_min = termfreq_max;
    89         max_value = sortable_unserialise(db.get_value_upper_bound(valno));
    90     } catch (const Xapian::UnimplementedError &) {
    91         termfreq_max = db.get_doccount();
    92         termfreq_est = termfreq_max / 2;
    93         termfreq_min = 0;
    94         max_value = DBL_MAX;
    95     }
    96107}
    97108
    98 ValueWeightPostingSource::ValueWeightPostingSource(Xapian::Database db_,
    99                                                    Xapian::valueno valno_,
     109ValueWeightPostingSource::ValueWeightPostingSource(Xapian::valueno valno_,
    100110                                                   double max_weight_)
    101         : db(db_),
    102           valno(valno_),
    103           current_docid(0),
    104           last_docid(db.get_lastdocid()),
    105           current_value(0.0),
    106           max_value(max_weight_)
     111        : valno(valno_),
     112          specified_max_value(max_weight_)
    107113{
    108     try {
    109         termfreq_max = db.get_value_freq(valno);
    110         termfreq_est = termfreq_max;
    111         termfreq_min = termfreq_max;
    112         max_value = std::min(max_value,
    113                              sortable_unserialise(db.get_value_upper_bound(valno)));
    114     } catch (const Xapian::UnimplementedError &) {
    115         termfreq_max = db.get_doccount();
    116         termfreq_est = termfreq_max / 2;
    117         termfreq_min = 0;
    118     }
    119114}
    120115
    121116Xapian::doccount
     
    232227    return current_docid;
    233228}
    234229
     230ValueWeightPostingSource *
     231ValueWeightPostingSource::clone() const
     232{
     233    return new ValueWeightPostingSource(valno, specified_max_value);
     234}
     235
     236std::string
     237ValueWeightPostingSource::name() const
     238{
     239    return std::string("ValueWeight");
     240}
     241
     242std::string
     243ValueWeightPostingSource::serialise() const
     244{
     245    return encode_length(valno) + serialise_double(specified_max_value);
     246}
     247
     248PostingSource *
     249ValueWeightPostingSource::unserialise(const std::string &s) const
     250{
     251    const char * p = s.data();
     252    const char * end = p + s.size();
     253
     254    Xapian::valueno new_valno = decode_length(&p, end, false);
     255    double new_spec_max = unserialise_double(&p, end);
     256
     257    return new ValueWeightPostingSource(new_valno, new_spec_max);
     258}
     259
    235260void
    236 ValueWeightPostingSource::reset()
     261ValueWeightPostingSource::reset(const Database & db_)
    237262{
     263    db = db_;
    238264    current_docid = 0;
     265    current_value = 0.0;
     266    last_docid = db.get_lastdocid();
     267    try {
     268        termfreq_max = db.get_value_freq(valno);
     269        termfreq_est = termfreq_max;
     270        termfreq_min = termfreq_max;
     271        max_value = std::min(specified_max_value,
     272                        sortable_unserialise(db.get_value_upper_bound(valno)));
     273    } catch (const Xapian::UnimplementedError &) {
     274        termfreq_max = db.get_doccount();
     275        termfreq_est = termfreq_max / 2;
     276        termfreq_min = 0;
     277        max_value = specified_max_value;
     278    }
    239279}
    240280
    241281std::string
  • xapian-bindings/python/pythontest2.py

     
    913913            xapian.PostingSource.__init__(self)
    914914            self.max = max
    915915
    916         def reset(self):
     916        def reset(self, db):
    917917            self.current = -1
    918918
    919919        def get_termfreq_min(self): return 0
     
    954954        doc.add_value(1, xapian.sortable_serialise(vals[id]))
    955955        db.add_document(doc)
    956956
    957     source = xapian.ValueWeightPostingSource(db, 1)
     957    source = xapian.ValueWeightPostingSource(1)
    958958    query = xapian.Query(source)
    959959    # del source # Check that query keeps a reference to it.
    960960
  • xapian-bindings/python/generate-python-exceptions.in

     
    4343    get_docid
    4444    get_description
    4545    reset
     46    name
     47    serialise
    4648);
    4749
    4850open FD, ">except.i" or die $!;
  • xapian-bindings/xapian.i

     
    194194
    195195#ifdef XAPIAN_SWIG_DIRECTORS
    196196%feature("director") Xapian::PostingSource;
     197%ignore Xapian::PostingSource::clone;
     198%ignore Xapian::PostingSource::unserialise;
    197199%include <xapian/postingsource.h>
    198200#else
    199201%ignore Xapian::Query(Xapian::PostingSource *);