Ticket #295: remotepostsource2.patch

File remotepostsource2.patch, 29.8 kB (added by richard, 3 months 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)