Ticket #295: remotepostsource3.patch

File remotepostsource3.patch, 45.3 KB (added by Richard Boulton, 15 years ago)

Updated implementation patch (applies to trunk rev 11827)

  • 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/api_db.cc

     
    18991899        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    19001900    { }
    19011901
    1902     void reset() { did = 0; }
     1902    MyOddPostingSource(Xapian::doccount num_docs_,
     1903                       Xapian::doccount last_docid_)
     1904        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     1905    { }
    19031906
     1907    PostingSource * clone() const { return new MyOddPostingSource(num_docs, last_docid); }
     1908
     1909    void reset(const Xapian::Database &) { did = 0; }
     1910
    19041911    // These bounds could be better, but that's not important here.
    19051912    Xapian::doccount get_termfreq_min() const { return 0; }
    19061913
     
    19371944    Xapian::Enquire enq(db);
    19381945    MyOddPostingSource src(db);
    19391946
    1940     // Check that passing NULL is rejected as intended.
    1941     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(NULL));
    1942     Xapian::PostingSource * nullsrc = NULL;
    1943     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(nullsrc));
    1944                
    19451947    enq.set_query(Xapian::Query(&src));
    19461948
    19471949    Xapian::MSet mset = enq.get_mset(0, 10);
     
    19931995        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    19941996    { }
    19951997
    1996     void reset() { did = 0; }
     1998    MyOddWeightingPostingSource(Xapian::doccount num_docs_,
     1999                                Xapian::doccount last_docid_)
     2000        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     2001    { }
    19972002
     2003    PostingSource * clone() const { return new MyOddWeightingPostingSource(num_docs, last_docid); }
     2004
     2005    void reset(const Xapian::Database &) { did = 0; }
     2006
    19982007    Xapian::weight get_weight() const {
    19992008        return (did % 2) ? 1000 : 0.001;
    20002009    }
     
    20902099        : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
    20912100    { }
    20922101
    2093     void reset() { did = 0; }
     2102    MyDontAskWeightPostingSource(Xapian::doccount num_docs_,
     2103                                 Xapian::doccount last_docid_)
     2104        : num_docs(num_docs_), last_docid(last_docid_), did(0)
     2105    { }
    20942106
     2107    PostingSource * clone() const { return new MyDontAskWeightPostingSource(num_docs, last_docid); }
     2108
     2109    void reset(const Xapian::Database &) { did = 0; }
     2110
    20952111    Xapian::weight get_weight() const {
    20962112        FAIL_TEST("MyDontAskWeightPostingSource::get_weight() called");
    20972113    }
     
    21632179}
    21642180
    21652181// Check that valueweightsource works correctly.
    2166 DEFINE_TESTCASE(valueweightsource1, backend && !remote) {
    2167     // FIXME: PostingSource doesn't currently work well with multi databases
    2168     // but we should try to resolve that issue.
    2169     SKIP_TEST_FOR_BACKEND("multi");
     2182DEFINE_TESTCASE(valueweightsource1, backend) {
    21702183    Xapian::Database db(get_database("apitest_phrase"));
    21712184    Xapian::Enquire enq(db);
    2172     Xapian::ValueWeightPostingSource src(db, 11);
     2185    Xapian::ValueWeightPostingSource src(11);
    21732186
    21742187    // Should be in descending order of length
    21752188    tout << "RAW" << endl;
     
    22012214// Check that valueweightsource gives the correct bounds for those databases
    22022215// which support value statistics.
    22032216DEFINE_TESTCASE(valueweightsource2, backend && valuestats) {
    2204     // FIXME: PostingSource doesn't currently work well with multi databases
    2205     // but we should try to resolve that issue.
    2206     SKIP_TEST_FOR_BACKEND("multi");
    22072217    Xapian::Database db(get_database("apitest_phrase"));
    2208     Xapian::ValueWeightPostingSource src(db, 11);
     2218    Xapian::ValueWeightPostingSource src(11);
     2219    src.reset(db);
    22092220    TEST_EQUAL(src.get_termfreq_min(), 17);
    22102221    TEST_EQUAL(src.get_termfreq_est(), 17);
    22112222    TEST_EQUAL(src.get_termfreq_max(), 17);
     
    22202231    // but we should try to resolve that issue.
    22212232    SKIP_TEST_FOR_BACKEND("multi");
    22222233    Xapian::Database db(get_database("apitest_phrase"));
    2223     Xapian::ValueWeightPostingSource src(db, 11);
     2234    Xapian::ValueWeightPostingSource src(11);
     2235    src.reset(db);
    22242236    TEST(!src.at_end());
    22252237    src.skip_to(8, 0.0);
    22262238    TEST(!src.at_end());
     
    22332245}
    22342246
    22352247// Check that fixedweightsource works correctly.
    2236 DEFINE_TESTCASE(fixedweightsource1, backend && !remote) {
    2237     // FIXME: PostingSource doesn't currently work well with multi databases
    2238     // but we should try to resolve that issue.
    2239     SKIP_TEST_FOR_BACKEND("multi");
     2248DEFINE_TESTCASE(fixedweightsource1, backend) {
    22402249    Xapian::Database db(get_database("apitest_phrase"));
    22412250    Xapian::Enquire enq(db);
    22422251    double wt = 5.6;
    22432252
    22442253    {
    2245         Xapian::FixedWeightPostingSource src(db, wt);
     2254        Xapian::FixedWeightPostingSource src(wt);
    22462255
    22472256        // Should be in increasing order of docid.
    22482257        enq.set_query(Xapian::Query(&src));
     
    22572266    // Do some direct tests, to check the skip_to() and check() methods work.
    22582267    {
    22592268        // Check next and skip_to().
    2260         Xapian::FixedWeightPostingSource src(db, wt);
     2269        Xapian::FixedWeightPostingSource src(wt);
     2270        src.reset(db);
    22612271
    22622272        src.next(1.0);
    22632273        TEST(!src.at_end());
     
    22732283    }
    22742284    {
    22752285        // Check check() as the first operation, followed by next.
    2276         Xapian::FixedWeightPostingSource src(db, wt);
     2286        Xapian::FixedWeightPostingSource src(wt);
     2287        src.reset(db);
    22772288
    22782289        TEST_EQUAL(src.check(5, 1.0), true);
    22792290        TEST(!src.at_end());
     
    22842295    }
    22852296    {
    22862297        // Check check() as the first operation, followed by skip_to().
    2287         Xapian::FixedWeightPostingSource src(db, wt);
     2298        Xapian::FixedWeightPostingSource src(wt);
     2299        src.reset(db);
    22882300
    22892301        TEST_EQUAL(src.check(5, 1.0), true);
    22902302        TEST(!src.at_end());
  • xapian-core/tests/api_percentages.cc

     
    3838    Xapian::weight maxwt;
    3939    bool started;
    4040
     41    MyPostingSource(const std::vector<std::pair<Xapian::docid, Xapian::weight> > &weights_,
     42                    Xapian::weight maxwt_)
     43        : weights(weights_), maxwt(maxwt_), started(false)
     44    {}
     45
    4146  public:
    4247    MyPostingSource() : maxwt(0.0), started(false) { }
    4348
     49    PostingSource * clone() const
     50    {
     51        return new MyPostingSource(weights, maxwt);
     52    }
     53
    4454    void append_docweight(Xapian::docid did, Xapian::weight wt) {
    4555        weights.push_back(make_pair(did, wt));
    4656        if (wt > maxwt) maxwt = wt;
     
    5060        if (wt > maxwt) maxwt = wt;
    5161    }
    5262
    53     void reset() { started = false; }
     63    void reset(const Xapian::Database &) { started = false; }
    5464
    5565    Xapian::weight get_weight() const { return i->second; }
    5666
  • 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_valuestream.cc

     
    162162 *
    163163 *  The original implementation went into an infinite loop in this case.
    164164 */
    165 DEFINE_TESTCASE(valueweightsource5, writable && valuestats) {
    166     // FIXME: PostingSource doesn't currently work well with multi databases
    167     // but we should try to resolve that issue.
    168     SKIP_TEST_FOR_BACKEND("multi");
     165DEFINE_TESTCASE(valueweightsource5, writable && valuestats & !multi) {
    169166    // inmemory's memory use is currently O(last_docid)!
    170167    SKIP_TEST_FOR_BACKEND("inmemory");
    171168    // Not supported currently.
     
    177174    db.replace_document(0xffffffff, doc);
    178175    db.flush();
    179176
    180     Xapian::ValueWeightPostingSource src(db, 1);
     177    Xapian::ValueWeightPostingSource src(1);
     178    src.reset(db);
    181179    src.next(0.0);
    182180    TEST(!src.at_end());
    183181    TEST_EQUAL(src.get_docid(), 1);
     
    210208//      16  Pad
    211209//      17  Pad
    212210//
    213 DEFINE_TESTCASE(valuemapsource1, backend && !remote) {
    214     // FIXME: PostingSource doesn't currently work well with multi databases
    215     // but we should try to resolve that issue.
    216     SKIP_TEST_FOR_BACKEND("multi");
     211DEFINE_TESTCASE(valuemapsource1, backend) {
    217212    Xapian::Database db(get_database("apitest_phrase"));
    218213    Xapian::Enquire enq(db);
    219214
    220     Xapian::ValueMapPostingSource src(db, 13);
     215    Xapian::ValueMapPostingSource src(13);
    221216    src.add_mapping("Thi", 2.0);
    222217    src.add_mapping("The", 1.0);
    223218    src.add_mapping("You", 3.0);
     
    251246
    252247// Regression test for valuepostingsource subclasses: used to segfault if skip_to()
    253248// called on an empty list.
    254 DEFINE_TESTCASE(valuemapsource2, backend && !remote) {
    255     // FIXME: PostingSource doesn't currently work well with multi databases
    256     // but we should try to resolve that issue.
    257     SKIP_TEST_FOR_BACKEND("multi");
     249DEFINE_TESTCASE(valuemapsource2, backend && !remote && !multi) {
    258250    Xapian::Database db(get_database("apitest_phrase"));
    259     Xapian::Enquire enq(db);
    260251
    261252    {
    262         Xapian::ValueMapPostingSource src(db, 100);
     253        Xapian::ValueMapPostingSource src(100);
     254        src.reset(db);
     255        TEST(src.at_end() == false);
    263256        src.next(0.0);
    264257        TEST(src.at_end() == true);
    265258    }
    266259
    267260    {
    268         Xapian::ValueMapPostingSource src(db, 100);
     261        Xapian::ValueMapPostingSource src(100);
     262        src.reset(db);
     263        TEST(src.at_end() == false);
    269264        src.skip_to(1, 0.0);
    270265        TEST(src.at_end() == true);
    271266    }
    272267
    273268    {
    274         Xapian::ValueMapPostingSource src(db, 100);
     269        Xapian::ValueMapPostingSource src(100);
     270        src.reset(db);
     271        TEST(src.at_end() == false);
    275272        src.check(1, 0.0);
    276273        TEST(src.at_end() == true);
    277274    }
    278275
    279276    return true;
    280277}
     278
     279// Regression test for fixedweightpostingsource: used to segfault if skip_to()
     280// called on an empty list.
     281DEFINE_TESTCASE(fixedweightsource2, !backend) {
     282    Xapian::Database db;
     283
     284    {
     285        Xapian::FixedWeightPostingSource src(5.0);
     286        src.reset(db);
     287        TEST(src.at_end() == false);
     288        src.next(0.0);
     289        TEST(src.at_end() == true);
     290    }
     291
     292    {
     293        Xapian::FixedWeightPostingSource src(5.0);
     294        src.reset(db);
     295        TEST(src.at_end() == false);
     296        src.skip_to(1, 0.0);
     297        TEST(src.at_end() == true);
     298    }
     299
     300    // No need to test behaviour of check() - check is only allowed to be
     301    // called with document IDs which exist, so can never be called for a
     302    // FixedWeightPostingSource with an empty database.
     303
     304    return true;
     305}
  • xapian-core/include/xapian/postingsource.h

     
    138138    /// Return the current docid.
    139139    virtual Xapian::docid get_docid() const = 0;
    140140
     141    /** Clone the posting source.
     142     *
     143     *  The clone should inherit the configuration of the parent, but need not
     144     *  inherit the state.  ie, the clone does not need to be in the same
     145     *  iteration position as the original: the matcher will always call
     146     *  reset() on the clone before attempting to move the iterator, or read
     147     *  the information about the current position of the iterator.
     148     *
     149     *  This may return NULL to indicate that cloning is not supported.  In
     150     *  this case, the PostingSource may only be used with a single-database
     151     *  search.
     152     *
     153     *  The default implementation returns NULL.
     154     */
     155    virtual PostingSource * clone() const;
     156
     157    /** Name of the posting source, for performing remote searches.
     158     *
     159     *  If the subclass is called FooPostingSource, this should return "Foo".
     160     *
     161     *  This should only be implemented if serialise() and unserialise() are
     162     *  also implemented.
     163     *
     164     *  The default implmenentation returns an empty string, to indicate that
     165     *  serialise() and unserialise() are not implemented.
     166     */
     167    virtual std::string name() const;
     168
     169    /** Serialise object parameters into a string.
     170     *
     171     *  The serialised parameters should represent the configuration of the
     172     *  posting source, but need not (indeed, should not) represent the current
     173     *  iteration state.
     174     */
     175    virtual std::string serialise() const;
     176
     177    /** Create object given string serialisation returned by serialise().
     178     *
     179     *  @param s A serialised instance of this PostingSource subclass.
     180     */
     181    virtual PostingSource * unserialise(const std::string &s) const;
     182
    141183    /** Reset this PostingSource to its freshly constructed state.
    142184     *
    143185     *  This is called automatically by the matcher prior to each query being
    144186     *  processed.
     187     *
     188     *  FIXME - document the db parameter.
    145189     */
    146     virtual void reset() = 0;
     190    virtual void reset(const Database & db) = 0;
    147191
    148192    /** Return a string describing this object.
    149193     *
     
    171215    Xapian::valueno slot;
    172216
    173217    /// Value stream iterator.
    174     Xapian::ValueIterator it;
     218    Xapian::ValueIterator value_it;
    175219
    176220    /// End iterator corresponding to it.
    177     Xapian::ValueIterator end;
     221    Xapian::ValueIterator value_end;
    178222
    179223    /// Flag indicating if we've started (true if we have).
    180224    bool started;
    181225
    182226    /** An upper bound on the weight returned.
    183227     *
    184      *  Subclasses should set this in their constructor if they know a bound on
    185      *  the weight.  It defaults to DBL_MAX.
     228     *  Subclasses should set this in their reset method if they know a bound
     229     *  on the weight.  It defaults to DBL_MAX.
    186230     */
    187231    double max_weight;
    188232
     
    210254  public:
    211255    /** Construct a ValuePostingSource.
    212256     *
    213      *  @param db_ The database to read values from.
    214257     *  @param slot_ The value slot to read values from.
    215258     */
    216     ValuePostingSource(Xapian::Database db_, Xapian::valueno slot_);
     259    ValuePostingSource(Xapian::valueno slot_);
    217260
    218261    Xapian::doccount get_termfreq_min() const;
    219262    Xapian::doccount get_termfreq_est() const;
     
    229272
    230273    Xapian::docid get_docid() const;
    231274
    232     void reset();
     275    void reset(const Database & db_);
    233276};
    234277
    235278/** A posting source which reads weights from a value slot.
     
    248291 */
    249292class XAPIAN_VISIBILITY_DEFAULT ValueWeightPostingSource
    250293        : public ValuePostingSource {
     294    /// Upper bound on the value returned specified in constructor.
     295    double specified_max_weight;
     296
    251297  public:
    252298    /** Construct a ValueWeightPostingSource.
    253299     *
    254      *  @param db_ The database to read values from.
    255300     *  @param slot_ The value slot to read values from.
    256301     */
    257     ValueWeightPostingSource(Xapian::Database db_, Xapian::valueno slot_);
     302    ValueWeightPostingSource(Xapian::valueno slot_);
    258303
    259304    /** Construct a ValueWeightPostingSource.
    260305     *
    261      *  @param db_ The database to read values from.
    262306     *  @param slot_ The value slot to read values from.
    263307     *  @param max_weight_ An upper bound on the weights which are stored in
    264308     *  the value slot.  Note that for the chert database format, information
     
    266310     *  constructor need only be used if more accurate information is
    267311     *  available.
    268312     */
    269     ValueWeightPostingSource(Xapian::Database db_,
    270                              Xapian::valueno slot_,
    271                              double max_weight_);
     313    ValueWeightPostingSource(Xapian::valueno slot_, double max_weight_);
    272314
    273315    Xapian::weight get_weight() const;
     316    ValueWeightPostingSource * clone() const;
     317    std::string name() const;
     318    std::string serialise() const;
     319    PostingSource * unserialise(const std::string &s) const;
     320    void reset(const Database & db_);
    274321
    275322    std::string get_description() const;
    276323};
     
    289336    /// The default weight
    290337    double default_weight;
    291338
     339    /// The maximum weight in weight_map.
     340    double max_weight_in_map;
     341
    292342    /// The value -> weight map
    293343    std::map<std::string, double> weight_map;
    294344
    295345  public:
    296346    /** Construct a ValueWeightPostingSource.
    297347     *
    298      *  @param db_ The database to read values from.
    299348     *  @param slot_ The value slot to read values from.
    300349     *  @param default_weight The default weight to return for unmapped values.
    301350     */
    302     ValueMapPostingSource(Xapian::Database db_, Xapian::valueno slot_);
     351    ValueMapPostingSource(Xapian::valueno slot_);
    303352
    304353    /** Add a mapping.
    305354     *
     
    317366    void set_default_weight(double wt);
    318367
    319368    Xapian::weight get_weight() const;
     369    ValueMapPostingSource * clone() const;
     370    std::string name() const;
     371    std::string serialise() const;
     372    PostingSource * unserialise(const std::string &s) const;
     373    void reset(const Database & db_);
    320374
    321375    std::string get_description() const;
    322376};
     
    351405  public:
    352406    /** Construct a FixedWeightPostingSource.
    353407     *
    354      *  @param db_ The database to read values from.
    355408     *  @param slot_ The value slot to read values from.
    356409     */
    357     FixedWeightPostingSource(Xapian::Database db_, Xapian::weight wt_);
     410    FixedWeightPostingSource(Xapian::weight wt_);
    358411
    359412    Xapian::doccount get_termfreq_min() const;
    360413    Xapian::doccount get_termfreq_est() const;
     
    371424
    372425    Xapian::docid get_docid() const;
    373426
    374     void reset();
     427    FixedWeightPostingSource * clone() const;
     428    std::string name() const;
     429    std::string serialise() const;
     430    PostingSource * unserialise(const std::string &s) const;
     431    void reset(const Database & db_);
    375432
    376433    std::string get_description() const;
    377434};
  • 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         *  An attempt to clone the posting source will be made immediately, so
     211         *  if the posting source supports clone(), the source supplied may be
     212         *  safely deallocated after this call.  If the source does not support
     213         *  clone, the caller must ensure that the posting source remains valid
     214         *  until the Query is deallocated.
     215         *
     216         *  @param external_source The source to use in the query.
     217         */
    208218        explicit Query(Xapian::PostingSource * external_source);
    209219
    210220        /** A query which matches all documents in the database. */
     
    249259        std::string serialise() const;
    250260
    251261        /** Unserialise a query from a string produced by serialise().
     262         *  FIXME - need to add a way to register posting sources.
    252263         */
    253264        static Query unserialise(const std::string &s);
    254265
     
    339350        /// External posting source.
    340351        Xapian::PostingSource * external_source;
    341352
     353        /// Flag, indicating whether the external source is owned by the query.
     354        bool external_source_owned;
     355
    342356        /** swap the contents of this with another Xapian::Query::Internal,
    343357         *  in a way which is guaranteed not to throw.  This is
    344358         *  used with the assignment operator to make it exception
     
    414428        Internal(op_t op_, Xapian::valueno valno, const std::string &value);
    415429
    416430        /// Construct an external source query.
    417         explicit Internal(Xapian::PostingSource * external_source_);
     431        explicit Internal(Xapian::PostingSource * external_source_, bool owned);
    418432
    419433        /** Destructor. */
    420434        ~Internal();
    421435
    422         static Xapian::Query::Internal * unserialise(const std::string &s);
     436        static Xapian::Query::Internal * unserialise(const std::string &s,
     437                const std::map<std::string, Xapian::PostingSource *> &sources);
    423438
    424439        /** Add a subquery.
    425440         */
  • 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;
     121    source = new Xapian::ValueMapPostingSource(0);
     122    postingsources[source->name()] = source;
     123    source = new Xapian::FixedWeightPostingSource(0);
     124    postingsources[source->name()] = source;
    117125}
    118126
    119127RemoteServer::~RemoteServer()
     
    121129    delete db;
    122130    // wdb is either NULL or equal to db, so we shouldn't delete it too!
    123131
    124     map<string, Xapian::Weight*>::const_iterator i;
    125     for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
    126         delete i->second;
     132    {
     133        map<string, Xapian::Weight*>::const_iterator i;
     134        for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
     135            delete i->second;
     136        }
    127137    }
     138
     139    {
     140        map<string, Xapian::PostingSource *>::const_iterator i;
     141        for (i = postingsources.begin(); i != postingsources.end(); ++i) {
     142            delete i->second;
     143        }
     144    }
    128145}
    129146
    130147message_type
     
    365382
    366383    // Unserialise the Query.
    367384    len = decode_length(&p, p_end, true);
    368     AutoPtr<Xapian::Query::Internal> query(Xapian::Query::Internal::unserialise(string(p, len)));
     385    AutoPtr<Xapian::Query::Internal> query(Xapian::Query::Internal::unserialise(string(p, len), postingsources));
    369386    p += len;
    370387
    371388    // Unserialise assorted Enquire settings.
     
    610627
    611628    send_message(REPLY_ADDDOCUMENT, encode_length(did));
    612629}
     630
     631
     632void
     633RemoteServer::register_posting_source(const Xapian::PostingSource &source)
     634{
     635    if (source.name().empty()) {
     636        throw Xapian::InvalidOperationError("Unable to register posting source - name() method returns empty string.");
     637    }
     638    Xapian::PostingSource * sourceclone = source.clone();
     639    if (!sourceclone) {
     640        throw Xapian::InvalidOperationError("Unable to register posting source - clone() method returns NULL.");
     641    }
     642    try {
     643        postingsources[source.name()] = sourceclone;
     644    } catch(...) {
     645        delete sourceclone;
     646        throw;
     647    }
     648}
  • 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/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 ValuePostingSource::ValuePostingSource(Xapian::Database db_,
    78                                        Xapian::valueno slot_)
    79         : db(db_),
    80           slot(slot_),
    81           it(db.valuestream_begin(slot)),
    82           end(db.valuestream_end(slot)),
    83           started(false),
    84           max_weight(DBL_MAX)
     103ValuePostingSource::ValuePostingSource(Xapian::valueno slot_)
     104        : slot(slot_)
    85105{
    86     try {
    87         termfreq_max = db.get_value_freq(slot);
    88         termfreq_est = termfreq_max;
    89         termfreq_min = termfreq_max;
    90     } catch (const Xapian::UnimplementedError &) {
    91         termfreq_max = db.get_doccount();
    92         termfreq_est = termfreq_max / 2;
    93         termfreq_min = 0;
    94     }
    95106}
    96107
    97108Xapian::doccount
     
    123134{
    124135    if (!started) {
    125136        started = true;
    126         it = db.valuestream_begin(slot);
    127         end = db.valuestream_end(slot);
     137        value_it = db.valuestream_begin(slot);
     138        value_end = db.valuestream_end(slot);
    128139    } else {
    129         ++it;
     140        ++value_it;
    130141    }
    131142
    132     if (it == end) return;
     143    if (value_it == value_end) return;
    133144
    134145    if (min_wt > max_weight) {
    135         it = end;
     146        value_it = value_end;
    136147        return;
    137148    }
    138149}
     
    143154{
    144155    if (!started) {
    145156        started = true;
    146         it = db.valuestream_begin(slot);
    147         end = db.valuestream_end(slot);
     157        value_it = db.valuestream_begin(slot);
     158        value_end = db.valuestream_end(slot);
    148159
    149         if (it == end) return;
     160        if (value_it == value_end) return;
    150161    }
    151162
    152163    if (min_wt > max_weight) {
    153         it = end;
     164        value_it = value_end;
    154165        return;
    155166    }
    156     it.skip_to(min_docid);
     167    value_it.skip_to(min_docid);
    157168}
    158169
    159170bool
     
    162173{
    163174    if (!started) {
    164175        started = true;
    165         it = db.valuestream_begin(slot);
    166         end = db.valuestream_end(slot);
     176        value_it = db.valuestream_begin(slot);
     177        value_end = db.valuestream_end(slot);
    167178
    168         if (it == end) return true;
     179        if (value_it == value_end) return true;
    169180    }
    170181
    171182    if (min_wt > max_weight) {
    172         it = end;
     183        value_it = value_end;
    173184        return true;
    174185    }
    175     return it.check(min_docid);
     186    return value_it.check(min_docid);
    176187}
    177188
    178189bool
    179190ValuePostingSource::at_end() const
    180191{
    181     return it == end;
     192    return started && value_it == value_end;
    182193}
    183194
    184195Xapian::docid
    185196ValuePostingSource::get_docid() const
    186197{
    187     return it.get_docid();
     198    return value_it.get_docid();
    188199}
    189200
    190201void
    191 ValuePostingSource::reset()
     202ValuePostingSource::reset(const Database & db_)
    192203{
     204    db = db_;
    193205    started = false;
     206    max_weight = DBL_MAX;
     207    try {
     208        termfreq_max = db.get_value_freq(slot);
     209        termfreq_est = termfreq_max;
     210        termfreq_min = termfreq_max;
     211    } catch (const Xapian::UnimplementedError &) {
     212        termfreq_max = db.get_doccount();
     213        termfreq_est = termfreq_max / 2;
     214        termfreq_min = 0;
     215    }
    194216}
    195217
    196218
    197 ValueWeightPostingSource::ValueWeightPostingSource(Xapian::Database db_,
    198                                                    Xapian::valueno slot_)
    199         : ValuePostingSource(db_, slot_)
     219ValueWeightPostingSource::ValueWeightPostingSource(Xapian::valueno slot_)
     220        : ValuePostingSource(slot_),
     221          specified_max_weight(DBL_MAX)
    200222{
    201     try {
    202         max_weight = sortable_unserialise(db_.get_value_upper_bound(slot_));
    203     } catch (const Xapian::UnimplementedError &) {
    204     }
    205223}
    206224
    207 ValueWeightPostingSource::ValueWeightPostingSource(Xapian::Database db_,
    208                                                    Xapian::valueno slot_,
     225ValueWeightPostingSource::ValueWeightPostingSource(Xapian::valueno slot_,
    209226                                                   double max_weight_)
    210     : ValuePostingSource(db_, slot_)
     227        : ValuePostingSource(slot_),
     228          specified_max_weight(max_weight_)
    211229{
    212     try {
    213         double ubound = sortable_unserialise(db_.get_value_upper_bound(slot_));
    214         max_weight = std::min(max_weight_, ubound);
    215     } catch (const Xapian::UnimplementedError &) {
    216         max_weight = max_weight_;
    217     }
    218230}
    219231
    220232Xapian::weight
     
    222234{
    223235    Assert(!at_end());
    224236    Assert(started);
    225     return sortable_unserialise(*it);
     237    return sortable_unserialise(*value_it);
    226238}
    227239
     240ValueWeightPostingSource *
     241ValueWeightPostingSource::clone() const
     242{
     243    return new ValueWeightPostingSource(slot, specified_max_weight);
     244}
     245
    228246std::string
     247ValueWeightPostingSource::name() const
     248{
     249    return std::string("ValueWeight");
     250}
     251
     252std::string
     253ValueWeightPostingSource::serialise() const
     254{
     255    return encode_length(slot) + serialise_double(specified_max_weight);
     256}
     257
     258PostingSource *
     259ValueWeightPostingSource::unserialise(const std::string &s) const
     260{
     261    const char * p = s.data();
     262    const char * end = p + s.size();
     263
     264    Xapian::valueno new_valno = decode_length(&p, end, false);
     265    double new_spec_max = unserialise_double(&p, end);
     266    if (p != end) {
     267        throw Xapian::NetworkError("Bad serialised ValueWeightPostingSource - junk at end");
     268    }
     269
     270    return new ValueWeightPostingSource(new_valno, new_spec_max);
     271}
     272
     273void
     274ValueWeightPostingSource::reset(const Database & db_)
     275{
     276    ValuePostingSource::reset(db_);
     277
     278    try {
     279        double ubound = sortable_unserialise(db.get_value_upper_bound(slot));
     280        max_weight = std::min(specified_max_weight, ubound);
     281    } catch (const Xapian::UnimplementedError &) {
     282        max_weight = specified_max_weight;
     283    }
     284}
     285
     286std::string
    229287ValueWeightPostingSource::get_description() const
    230288{
    231289    return "Xapian::ValueWeightPostingSource(slot=" + om_tostring(slot) + ")";
    232290}
    233291
    234292
    235 ValueMapPostingSource::ValueMapPostingSource(Xapian::Database db_,
    236                                              Xapian::valueno slot_)
    237         : ValuePostingSource(db_, slot_),
    238           default_weight(0.0)
     293ValueMapPostingSource::ValueMapPostingSource(Xapian::valueno slot_)
     294        : ValuePostingSource(slot_),
     295          default_weight(0.0),
     296          max_weight_in_map(0.0)
    239297{
    240298}
    241299
     
    243301ValueMapPostingSource::add_mapping(std::string key_, double weight_)
    244302{
    245303    weight_map[key_] = weight_;
    246     max_weight = std::max(weight_, max_weight);
     304    max_weight_in_map = std::max(weight_, max_weight_in_map);
    247305}
    248306
    249307void
    250308ValueMapPostingSource::clear_mappings()
    251309{
    252310    weight_map.clear();
    253     max_weight = default_weight;
     311    max_weight_in_map = 0.0;
    254312}
    255313
    256314void
     
    263321Xapian::weight
    264322ValueMapPostingSource::get_weight() const
    265323{
    266     std::map<std::string, double>::const_iterator wit = weight_map.find(*it);
     324    std::map<std::string, double>::const_iterator wit = weight_map.find(*value_it);
    267325    if (wit == weight_map.end()) {
    268326        return default_weight;
    269327    } else {
     
    271329    }
    272330}
    273331
     332ValueMapPostingSource *
     333ValueMapPostingSource::clone() const
     334{
     335    AutoPtr<ValueMapPostingSource> res(new ValueMapPostingSource(slot));
     336    std::map<std::string, double>::const_iterator i;
     337    for (i = weight_map.begin(); i != weight_map.end(); ++i)
     338    {
     339        res->add_mapping(i->first, i->second);
     340    }
     341    res->set_default_weight(default_weight);
     342    return res.release();
     343}
     344
    274345std::string
     346ValueMapPostingSource::name() const
     347{
     348    return std::string("ValueMap");
     349}
     350
     351std::string
     352ValueMapPostingSource::serialise() const
     353{
     354    std::string result;
     355    result = encode_length(slot) + serialise_double(default_weight);
     356
     357    std::map<std::string, double>::const_iterator i;
     358    for (i = weight_map.begin(); i != weight_map.end(); ++i)
     359    {
     360        result.append(encode_length(i->first.size()));
     361        result.append(i->first);
     362        result.append(serialise_double(i->second));
     363    }
     364
     365    return result;
     366}
     367
     368PostingSource *
     369ValueMapPostingSource::unserialise(const std::string &s) const
     370{
     371    const char * p = s.data();
     372    const char * end = p + s.size();
     373
     374    Xapian::valueno new_slot = decode_length(&p, end, false);
     375    AutoPtr<ValueMapPostingSource> res(new ValueMapPostingSource(new_slot));
     376    res->set_default_weight(unserialise_double(&p, end));
     377    while (p != end) {
     378        size_t keylen = decode_length(&p, end, true);
     379        string key(p, keylen);
     380        p += keylen;
     381        res->add_mapping(key, unserialise_double(&p, end));
     382    }
     383    return res.release();
     384}
     385
     386void
     387ValueMapPostingSource::reset(const Database & db_)
     388{
     389    ValuePostingSource::reset(db_);
     390    max_weight = std::max(max_weight_in_map, default_weight);
     391}
     392
     393std::string
    275394ValueMapPostingSource::get_description() const
    276395{
    277396    return "Xapian::ValueMapPostingSource(slot=" + om_tostring(slot) + ")";
    278397}
    279398
    280399
    281 FixedWeightPostingSource::FixedWeightPostingSource(Xapian::Database db_,
    282                                                    Xapian::weight wt_)
    283         : db(db_), termfreq(db_.get_doccount()),
    284           it(db.postlist_begin(std::string())),
    285           end(db.postlist_end(std::string())),
    286           wt(wt_),
     400FixedWeightPostingSource::FixedWeightPostingSource(Xapian::weight wt_)
     401        : wt(wt_),
    287402          started(false)
    288403{
    289404}
     
    350465        started = true;
    351466        it = db.postlist_begin(std::string());
    352467        end = db.postlist_end(std::string());
     468
     469        if (it == end) return;
    353470    }
    354471
    355472    if (check_docid) {
     
    378495bool
    379496FixedWeightPostingSource::at_end() const
    380497{
    381     return it == end;
     498    if (check_docid != 0) return false;
     499    return started && it == end;
    382500}
    383501
    384502Xapian::docid
     
    388506    return *it;
    389507}
    390508
     509FixedWeightPostingSource *
     510FixedWeightPostingSource::clone() const
     511{
     512    return new FixedWeightPostingSource(wt);
     513}
     514
     515std::string
     516FixedWeightPostingSource::name() const
     517{
     518    return std::string("FixedWeight");
     519}
     520
     521std::string
     522FixedWeightPostingSource::serialise() const
     523{
     524    return serialise_double(wt);
     525}
     526
     527PostingSource *
     528FixedWeightPostingSource::unserialise(const std::string &s) const
     529{
     530    const char * p = s.data();
     531    const char * s_end = p + s.size();
     532    double new_wt = unserialise_double(&p, s_end);
     533    if (p != s_end) {
     534        throw Xapian::NetworkError("Bad serialised ValueWeightPostingSource - junk at end");
     535    }
     536    return new FixedWeightPostingSource(new_wt);
     537}
     538
    391539void
    392 FixedWeightPostingSource::reset()
     540FixedWeightPostingSource::reset(const Xapian::Database & db_)
    393541{
     542    db = db_;
     543    termfreq = db_.get_doccount();
    394544    started = false;
    395545    check_docid = 0;
    396546}
  • xapian-core/api/omqueryinternal.cc

     
    4141#include <cfloat>
    4242#include <climits>
    4343#include <cmath>
     44#include <map>
    4445#include <set>
    4546#include <vector>
    4647
     
    141142        result += '[';
    142143        result += encode_length(tname.length());
    143144        result += tname;
    144         if (term_pos != curpos) result += '@' + om_tostring(term_pos);
    145         if (wqf != 1) result += '#' + om_tostring(wqf);
     145        if (term_pos != curpos) result += '@' + om_tostring(term_pos); // FIXME - should this use encode_length()?
     146        if (wqf != 1) result += '#' + om_tostring(wqf); // FIXME - should this use encode_length()?
    146147        ++curpos;
    147148    } else if (op == Xapian::Query::Internal::OP_EXTERNAL_SOURCE) {
    148         throw Xapian::UnimplementedError("Remote backend doesn't support PostingSource");
     149        string sourcename = external_source->name();
     150        if (sourcename.empty())
     151            throw Xapian::UnimplementedError("This PostingSource doesn't support remote use.");
     152        result += '!';
     153        result += encode_length(sourcename.length());
     154        result += sourcename;
     155        string sourcedata = external_source->serialise();
     156        result += encode_length(sourcedata.length());
     157        result += sourcedata;
    149158    } else {
    150159        result += "(";
    151160        for (subquery_list::const_iterator i = subqs.begin();
     
    157166            case Xapian::Query::Internal::OP_LEAF:
    158167                Assert(false);
    159168                break;
     169            case Xapian::Query::Internal::OP_EXTERNAL_SOURCE:
     170                Assert(false);
     171                break;
    160172            case Xapian::Query::OP_AND:
    161173                result += "&";
    162174                break;
     
    379391    const char *p;
    380392    const char *end;
    381393    Xapian::termpos curpos;
     394    const map<string, Xapian::PostingSource *> & sources;
    382395
    383396    Xapian::Query::Internal * readquery();
     397    Xapian::Query::Internal * readexternal();
    384398    Xapian::Query::Internal * readcompound();
    385399
    386400  public:
    387     QUnserial(const string & s) : p(s.c_str()), end(p + s.size()), curpos(1) { }
     401    QUnserial(const string & s,
     402              const map<string, Xapian::PostingSource *> & sources_)
     403            : p(s.c_str()), end(p + s.size()), curpos(1), sources(sources_) { }
    388404    Xapian::Query::Internal * decode();
    389405};
    390406
     
    423439            ++curpos;
    424440            return new Xapian::Query::Internal(tname, wqf, term_pos);
    425441        }
     442        case '!':
     443            return readexternal();
    426444        case '(':
    427445            return readcompound();
    428446        default:
     
    431449    }
    432450}
    433451
     452Xapian::Query::Internal *
     453QUnserial::readexternal()
     454{
     455    if (p == end)
     456        throw Xapian::InvalidArgumentError("Bad serialised query");
     457
     458    size_t length = decode_length(&p, end, true);
     459    string sourcename(p, length);
     460    map<string, Xapian::PostingSource *>::const_iterator i;
     461    i = sources.find(string(p, length));
     462    if (i == sources.end()) {
     463        throw Xapian::InvalidArgumentError("PostingSource " + string(p, length) + " not registered");
     464    }
     465
     466    p += length;
     467    length = decode_length(&p, end, true);
     468    string sourcedata(p, length);
     469    p += length;
     470
     471    return new Xapian::Query::Internal(i->second->unserialise(sourcedata), true);
     472}
     473
    434474static Xapian::Query::Internal *
    435475qint_from_vector(Xapian::Query::op op,
    436476                 const vector<Xapian::Query::Internal *> & vec,
     
    475515                    --p;
    476516                    subqs.push_back(readquery());
    477517                    break;
     518                case '!':
     519                    subqs.push_back(readexternal());
     520                    break;
    478521                case '(': {
    479522                    subqs.push_back(readcompound());
    480523                    break;
     
    562605}
    563606
    564607Xapian::Query::Internal *
    565 Xapian::Query::Internal::unserialise(const string &s)
     608Xapian::Query::Internal::unserialise(const string &s,
     609                        const map<string, Xapian::PostingSource *> & sources)
    566610{
    567611    Assert(s.length() > 1);
    568     QUnserial u(s);
     612    QUnserial u(s, sources);
    569613    Xapian::Query::Internal * qint = u.decode();
    570614    AssertEq(s, qint->serialise());
    571615    return qint;
    572616}
    573617#else
    574618Xapian::Query::Internal *
    575 Xapian::Query::Internal::unserialise(const string &)
     619Xapian::Query::Internal::unserialise(const string &,
     620                        const map<string, Xapian::PostingSource *> & sources)
    576621{
    577622    throw Xapian::InternalError("query serialisation not compiled in");
    578623}
     
    596641    std::swap(term_pos, other.term_pos);
    597642    std::swap(wqf, other.wqf);
    598643    std::swap(external_source, other.external_source);
     644    std::swap(external_source_owned, other.external_source_owned);
    599645}
    600646
    601647Xapian::Query::Internal::Internal(const Xapian::Query::Internal &copyme)
     
    607653          str_parameter(copyme.str_parameter),
    608654          term_pos(copyme.term_pos),
    609655          wqf(copyme.wqf),
    610           external_source(copyme.external_source)
     656          external_source(NULL),
     657          external_source_owned(false)
    611658{
    612659    for (subquery_list::const_iterator i = copyme.subqs.begin();
    613660         i != copyme.subqs.end();
    614661         ++i) {
    615662        subqs.push_back(new Xapian::Query::Internal(**i));
    616663    }
     664    if (copyme.external_source) {
     665        external_source = copyme.external_source->clone();
     666        if (external_source == NULL) {
     667            external_source = copyme.external_source;
     668            external_source_owned = false;
     669        } else {
     670            external_source_owned = true;
     671        }
     672    }
    617673}
    618674
    619675//////////////////////////////////////////
     
    626682          parameter(0),
    627683          tname(tname_),
    628684          term_pos(term_pos_),
    629           wqf(wqf_)
     685          wqf(wqf_),
     686          external_source(NULL),
     687          external_source_owned(false)
    630688{
    631689    validate_query();
    632690}
     
    637695          parameter(parameter_),
    638696          tname(),
    639697          term_pos(0),
    640           wqf(0)
     698          wqf(0),
     699          external_source(NULL),
     700          external_source_owned(false)
    641701{
    642702    if (parameter != 0 && op != OP_PHRASE && op != OP_NEAR && op != OP_ELITE_SET)
    643703        throw Xapian::InvalidArgumentError("parameter is only meaningful for OP_NEAR, OP_PHRASE, or OP_ELITE_SET");
     
    648708        : op(op_),
    649709          parameter(Xapian::termcount(valno)),
    650710          tname(begin),
    651           str_parameter(end)
     711          str_parameter(end),
     712          external_source(NULL),
     713          external_source_owned(false)
    652714{
    653715    if (op != OP_VALUE_RANGE)
    654716        throw Xapian::InvalidArgumentError("This constructor is only meaningful for OP_VALUE_RANGE");
     
    659721                                  const std::string &value)
    660722        : op(op_),
    661723          parameter(Xapian::termcount(valno)),
    662           tname(value)
     724          tname(value),
     725          external_source(NULL),
     726          external_source_owned(false)
    663727{
    664728    if (op != OP_VALUE_GE && op != OP_VALUE_LE)
    665729        throw Xapian::InvalidArgumentError("This constructor is only meaningful for OP_VALUE_GE or OP_VALUE_LE");
     
    673737    validate_query();
    674738}
    675739
    676 Xapian::Query::Internal::Internal(PostingSource * external_source_)
    677     : op(OP_EXTERNAL_SOURCE), external_source(external_source_)
     740Xapian::Query::Internal::Internal(PostingSource * external_source_, bool owned)
     741        : op(OP_EXTERNAL_SOURCE), external_source(external_source_),
     742          external_source_owned(owned)
    678743{
    679     if (!external_source)
    680         throw Xapian::InvalidArgumentError("The external_source parameter can not be NULL");
     744    Assert(external_source);
    681745}
    682746
    683747Xapian::Query::Internal::~Internal()
     
    686750    for (i = subqs.begin(); i != subqs.end(); i++) {
    687751        delete *i;
    688752    }
     753    if (external_source_owned) {
     754        delete external_source;
     755    }
    689756}
    690757
    691758Xapian::Query::Internal *
  • xapian-core/api/omquery.cc

     
    2929#include "utils.h"
    3030
    3131#include "xapian/error.h"
     32#include "xapian/postingsource.h"
    3233#include "xapian/termiterator.h"
    3334
    3435#include <vector>
     
    160161}
    161162
    162163Query::Query(PostingSource * external_source)
    163         : internal(new Query::Internal(external_source))
     164        : internal(NULL)
    164165{
    165166    DEBUGAPICALL(void, "Xapian::Query::Query", external_source);
     167    PostingSource * clone = external_source->clone();
     168    if (clone) {
     169        internal = new Query::Internal(clone, true);
     170    } else {
     171        internal = new Query::Internal(external_source, false);
     172    }
    166173}
    167174
    168175// Copy constructor
     
    207214    DEBUGAPICALL_STATIC(Xapian::Query, "Xapian::Query::unserialise", s);
    208215    Query result;
    209216    if (!s.empty()) {
    210         result.internal = Xapian::Query::Internal::unserialise(s);
     217        std::map<std::string, Xapian::PostingSource *> sources;
     218        result.internal = Xapian::Query::Internal::unserialise(s, sources);
    211219    }
    212220    RETURN(result);
    213221}
  • xapian-bindings/python/generate-python-exceptions

     
    3939    get_docid
    4040    get_description
    4141    reset
     42    name
     43    serialise
    4244);
    4345
    4446open FD, ">except.i" or die $!;
  • 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/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 *);