1 /** @file
2  * @brief Xapian::Query internals
3  */
4 /* Copyright (C) 2011,2012,2013,2014,2015,2016,2018 Olly Betts
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20 
21 #ifndef XAPIAN_INCLUDED_QUERYINTERNAL_H
22 #define XAPIAN_INCLUDED_QUERYINTERNAL_H
23 
24 #include "postlist.h"
25 #include "queryvector.h"
26 #include "xapian/intrusive_ptr.h"
27 #include "xapian/query.h"
28 
29 /// Default set_size for OP_ELITE_SET:
30 const Xapian::termcount DEFAULT_ELITE_SET_SIZE = 10;
31 
32 class QueryOptimiser;
33 
34 namespace Xapian {
35 namespace Internal {
36 
37 class QueryTerm : public Query::Internal {
38     std::string term;
39 
40     Xapian::termcount wqf;
41 
42     Xapian::termpos pos;
43 
44   public:
45     // Construct a "MatchAll" QueryTerm.
QueryTerm()46     QueryTerm() : term(), wqf(1), pos(0) { }
47 
QueryTerm(const std::string & term_,Xapian::termcount wqf_,Xapian::termpos pos_)48     QueryTerm(const std::string & term_,
49 	      Xapian::termcount wqf_,
50 	      Xapian::termpos pos_)
51 	: term(term_), wqf(wqf_), pos(pos_) { }
52 
53     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
54 
get_term()55     const std::string & get_term() const { return term; }
56 
57     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
58 
get_length()59     termcount get_length() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION {
60 	return wqf;
61     }
62 
63     void serialise(std::string & result) const;
64 
65     std::string get_description() const;
66 
67     void gather_terms(void * void_terms) const;
68 };
69 
70 class QueryPostingSource : public Query::Internal {
71     Xapian::Internal::opt_intrusive_ptr<PostingSource> source;
72 
73   public:
74     explicit QueryPostingSource(PostingSource * source_);
75 
76     PostingIterator::Internal * postlist(QueryOptimiser *qopt, double factor) const;
77 
78     void serialise(std::string & result) const;
79 
80     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
81 
82     std::string get_description() const;
83 };
84 
85 class QueryScaleWeight : public Query::Internal {
86     double scale_factor;
87 
88     Query subquery;
89 
90   public:
91     QueryScaleWeight(double factor, const Query & subquery_);
92 
93     PostingIterator::Internal * postlist(QueryOptimiser *qopt, double factor) const;
94 
get_length()95     termcount get_length() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION {
96 	return subquery.internal->get_length();
97     }
98 
99     void serialise(std::string & result) const;
100 
101     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
102     size_t get_num_subqueries() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
103     const Query get_subquery(size_t n) const;
104 
105     std::string get_description() const;
106 
107     void gather_terms(void * void_terms) const;
108 };
109 
110 class QueryValueBase : public Query::Internal {
111   protected:
112     Xapian::valueno slot;
113 
114   public:
QueryValueBase(Xapian::valueno slot_)115     explicit QueryValueBase(Xapian::valueno slot_)
116 	: slot(slot_) { }
117 
get_slot()118     Xapian::valueno get_slot() const { return slot; }
119 };
120 
121 class QueryValueRange : public QueryValueBase {
122     std::string begin, end;
123 
124   public:
QueryValueRange(Xapian::valueno slot_,const std::string & begin_,const std::string & end_)125     QueryValueRange(Xapian::valueno slot_,
126 		    const std::string &begin_,
127 		    const std::string &end_)
128 	: QueryValueBase(slot_), begin(begin_), end(end_) { }
129 
130     PostingIterator::Internal * postlist(QueryOptimiser *qopt, double factor) const;
131 
132     void serialise(std::string & result) const;
133 
134     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
135 
136     std::string get_description() const;
137 };
138 
139 class QueryValueLE : public QueryValueBase {
140     std::string limit;
141 
142   public:
QueryValueLE(Xapian::valueno slot_,const std::string & limit_)143     QueryValueLE(Xapian::valueno slot_, const std::string &limit_)
144 	: QueryValueBase(slot_), limit(limit_) { }
145 
146     PostingIterator::Internal * postlist(QueryOptimiser *qopt, double factor) const;
147 
148     void serialise(std::string & result) const;
149 
150     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
151 
152     std::string get_description() const;
153 };
154 
155 class QueryValueGE : public QueryValueBase {
156     std::string limit;
157 
158   public:
QueryValueGE(Xapian::valueno slot_,const std::string & limit_)159     QueryValueGE(Xapian::valueno slot_, const std::string &limit_)
160 	: QueryValueBase(slot_), limit(limit_) { }
161 
162     PostingIterator::Internal * postlist(QueryOptimiser *qopt, double factor) const;
163 
164     void serialise(std::string & result) const;
165 
166     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
167 
168     std::string get_description() const;
169 };
170 
171 class QueryBranch : public Query::Internal {
172     virtual Xapian::Query::op get_op() const = 0;
173 
174   protected:
175     QueryVector subqueries;
176 
QueryBranch(size_t n_subqueries)177     explicit QueryBranch(size_t n_subqueries) : subqueries(n_subqueries) { }
178 
179     void serialise_(std::string & result, Xapian::termcount parameter = 0) const;
180 
181     void do_or_like(OrContext& ctx, QueryOptimiser * qopt, double factor,
182 		    Xapian::termcount elite_set_size = 0, size_t first = 0) const;
183 
184     PostList * do_synonym(QueryOptimiser * qopt, double factor) const;
185 
186     PostList * do_max(QueryOptimiser * qopt, double factor) const;
187 
188     const std::string get_description_helper(const char * op,
189 					     Xapian::termcount window = 0) const;
190 
191   public:
192     termcount get_length() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
193 
194     void serialise(std::string & result) const;
195 
196     void gather_terms(void * void_terms) const;
197 
198     virtual void add_subquery(const Xapian::Query & subquery) = 0;
199 
200     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
201     size_t get_num_subqueries() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
202     const Query get_subquery(size_t n) const;
203 
204     virtual Query::Internal * done() = 0;
205 };
206 
207 class QueryAndLike : public QueryBranch {
208   protected:
QueryAndLike(size_t num_subqueries_)209     explicit QueryAndLike(size_t num_subqueries_)
210 	: QueryBranch(num_subqueries_) { }
211 
212   public:
213     void add_subquery(const Xapian::Query & subquery);
214 
215     Query::Internal * done();
216 
217     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
218 
219     void postlist_sub_and_like(AndContext& ctx, QueryOptimiser * qopt, double factor) const;
220 };
221 
222 class QueryOrLike : public QueryBranch {
223   protected:
QueryOrLike(size_t num_subqueries_)224     explicit QueryOrLike(size_t num_subqueries_)
225 	: QueryBranch(num_subqueries_) { }
226 
227   public:
228     void add_subquery(const Xapian::Query & subquery);
229 
230     Query::Internal * done();
231 };
232 
233 class QueryAnd : public QueryAndLike {
234     Xapian::Query::op get_op() const;
235 
236   public:
QueryAnd(size_t n_subqueries)237     explicit QueryAnd(size_t n_subqueries) : QueryAndLike(n_subqueries) { }
238 
239     std::string get_description() const;
240 };
241 
242 class QueryOr : public QueryOrLike {
243     Xapian::Query::op get_op() const;
244 
245   public:
QueryOr(size_t n_subqueries)246     explicit QueryOr(size_t n_subqueries) : QueryOrLike(n_subqueries) { }
247 
248     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
249 
250     void postlist_sub_or_like(OrContext& ctx, QueryOptimiser * qopt, double factor) const;
251 
252     std::string get_description() const;
253 };
254 
255 class QueryAndNot : public QueryBranch {
256     Xapian::Query::op get_op() const;
257 
258   public:
QueryAndNot(size_t n_subqueries)259     explicit QueryAndNot(size_t n_subqueries) : QueryBranch(n_subqueries) { }
260 
261     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
262 
263     void postlist_sub_and_like(AndContext& ctx,
264 			       QueryOptimiser* qopt,
265 			       double factor) const;
266 
267     void add_subquery(const Xapian::Query & subquery);
268 
269     Query::Internal * done();
270 
271     std::string get_description() const;
272 };
273 
274 class QueryXor : public QueryOrLike {
275     Xapian::Query::op get_op() const;
276 
277   public:
QueryXor(size_t n_subqueries)278     explicit QueryXor(size_t n_subqueries) : QueryOrLike(n_subqueries) { }
279 
280     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
281 
282     void postlist_sub_xor(XorContext& ctx, QueryOptimiser * qopt, double factor) const;
283 
284     std::string get_description() const;
285 };
286 
287 class QueryAndMaybe : public QueryBranch {
288     Xapian::Query::op get_op() const;
289 
290   public:
QueryAndMaybe(size_t n_subqueries)291     explicit QueryAndMaybe(size_t n_subqueries) : QueryBranch(n_subqueries) { }
292 
293     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
294 
295     void postlist_sub_and_like(AndContext& ctx,
296 			       QueryOptimiser* qopt,
297 			       double factor) const;
298 
299     void add_subquery(const Xapian::Query & subquery);
300 
301     Query::Internal * done();
302 
303     std::string get_description() const;
304 };
305 
306 class QueryFilter : public QueryAndLike {
307     Xapian::Query::op get_op() const;
308 
309   public:
QueryFilter(size_t n_subqueries)310     explicit QueryFilter(size_t n_subqueries) : QueryAndLike(n_subqueries) { }
311 
312     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
313 
314     void postlist_sub_and_like(AndContext& ctx, QueryOptimiser * qopt, double factor) const;
315 
316     std::string get_description() const;
317 };
318 
319 class QueryWindowed : public QueryAndLike {
320   protected:
321     Xapian::termcount window;
322 
QueryWindowed(size_t n_subqueries,Xapian::termcount window_)323     QueryWindowed(size_t n_subqueries, Xapian::termcount window_)
324 	: QueryAndLike(n_subqueries), window(window_) { }
325 
326     void postlist_windowed(Xapian::Query::op op, AndContext& ctx,
327 			   QueryOptimiser * qopt, double factor) const;
328 
329   public:
get_window()330     size_t get_window() const { return window; }
331 
332     Query::Internal * done();
333 };
334 
335 class QueryNear : public QueryWindowed {
336     Xapian::Query::op get_op() const;
337 
338   public:
QueryNear(size_t n_subqueries,Xapian::termcount window_)339     QueryNear(size_t n_subqueries, Xapian::termcount window_)
340 	: QueryWindowed(n_subqueries, window_) { }
341 
342     void serialise(std::string & result) const;
343 
344     void postlist_sub_and_like(AndContext& ctx, QueryOptimiser * qopt, double factor) const;
345 
346     std::string get_description() const;
347 };
348 
349 class QueryPhrase : public QueryWindowed {
350     Xapian::Query::op get_op() const;
351 
352   public:
QueryPhrase(size_t n_subqueries,Xapian::termcount window_)353     QueryPhrase(size_t n_subqueries, Xapian::termcount window_)
354 	: QueryWindowed(n_subqueries, window_) { }
355 
356     void serialise(std::string & result) const;
357 
358     void postlist_sub_and_like(AndContext& ctx, QueryOptimiser * qopt, double factor) const;
359 
360     std::string get_description() const;
361 };
362 
363 class QueryEliteSet : public QueryOrLike {
364     Xapian::Query::op get_op() const;
365 
366     Xapian::termcount set_size;
367 
368   public:
QueryEliteSet(size_t n_subqueries,Xapian::termcount set_size_)369     QueryEliteSet(size_t n_subqueries, Xapian::termcount set_size_)
370 	: QueryOrLike(n_subqueries),
371 	  set_size(set_size_ ? set_size_ : DEFAULT_ELITE_SET_SIZE) { }
372 
373     void serialise(std::string & result) const;
374 
375     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
376 
377     void postlist_sub_or_like(OrContext& ctx, QueryOptimiser * qopt, double factor) const;
378 
379     std::string get_description() const;
380 };
381 
382 class QuerySynonym : public QueryOrLike {
383     Xapian::Query::op get_op() const;
384 
385   public:
QuerySynonym(size_t n_subqueries)386     explicit QuerySynonym(size_t n_subqueries) : QueryOrLike(n_subqueries) { }
387 
388     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
389 
390     Query::Internal * done();
391 
392     std::string get_description() const;
393 };
394 
395 class QueryMax : public QueryOrLike {
396     Xapian::Query::op get_op() const;
397 
398   public:
QueryMax(size_t n_subqueries)399     explicit QueryMax(size_t n_subqueries) : QueryOrLike(n_subqueries) { }
400 
401     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
402 
403     std::string get_description() const;
404 };
405 
406 class QueryWildcard : public Query::Internal {
407     std::string pattern;
408 
409     Xapian::termcount max_expansion;
410 
411     int max_type;
412 
413     Query::op combiner;
414 
415     Xapian::Query::op get_op() const;
416 
417   public:
QueryWildcard(const std::string & pattern_,Xapian::termcount max_expansion_,int max_type_,Query::op combiner_)418     QueryWildcard(const std::string &pattern_,
419 		  Xapian::termcount max_expansion_,
420 		  int max_type_,
421 		  Query::op combiner_)
422 	: pattern(pattern_),
423 	  max_expansion(max_expansion_),
424 	  max_type(max_type_),
425 	  combiner(combiner_)
426     { }
427 
428     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
429 
get_pattern()430     const std::string & get_pattern() const { return pattern; }
431 
432     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
433 
434     termcount get_length() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
435 
436     void serialise(std::string & result) const;
437 
438     /** Change the combining operator.
439      *
440      *  If there's only one reference to this object we change in-place
441      *  and return a pointer to the existing object; otherwise we create and
442      *  return a new QueryWildcard object.
443      */
change_combiner(Xapian::Query::op new_op)444     QueryWildcard* change_combiner(Xapian::Query::op new_op) {
445 	if (_refs == 1) {
446 	    combiner = new_op;
447 	    return this;
448 	}
449 	return new QueryWildcard(pattern,
450 				 max_expansion,
451 				 max_type,
452 				 new_op);
453     }
454 
455     std::string get_description() const;
456 };
457 
458 class QueryInvalid : public Query::Internal {
459   public:
QueryInvalid()460     QueryInvalid() { }
461 
462     Xapian::Query::op get_type() const XAPIAN_NOEXCEPT XAPIAN_PURE_FUNCTION;
463 
464     PostingIterator::Internal * postlist(QueryOptimiser * qopt, double factor) const;
465 
466     void serialise(std::string & result) const;
467 
468     std::string get_description() const;
469 };
470 
471 }
472 
473 }
474 
475 #endif // XAPIAN_INCLUDED_QUERYINTERNAL_H
476