1 /* omquery.cc: External interface for running queries
2  *
3  * Copyright 1999,2000,2001 BrightStation PLC
4  * Copyright 2001,2002 Ananova Ltd
5  * Copyright 2003,2004,2005,2006,2007,2008,2009 Olly Betts
6  * Copyright 2006,2007,2008,2009 Lemur Consulting Ltd
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
21  * USA
22  */
23 
24 #include <config.h>
25 
26 #include "omqueryinternal.h"
27 
28 #include "debuglog.h"
29 #include "omassert.h"
30 #include "utils.h"
31 
32 #include "xapian/error.h"
33 #include "xapian/postingsource.h"
34 #include "xapian/registry.h"
35 #include "xapian/termiterator.h"
36 
37 #include <cmath>
38 
39 namespace Xapian {
40 
41 /// Add a subquery by reference
42 void
add_subquery(const Query & subq)43 Query::add_subquery(const Query & subq)
44 {
45     LOGCALL_VOID(API, "Xapian::Query::add_subquery", subq);
46     Assert(internal.get());
47     internal->add_subquery(subq.internal.get());
48 }
49 
50 /// Add a subquery by pointer
51 void
add_subquery(const Query * subq)52 Query::add_subquery(const Query * subq)
53 {
54     LOGCALL_VOID(API, "Xapian::Query::add_subquery", subq);
55     if (subq == 0) {
56 	throw InvalidArgumentError("Pointer to subquery may not be null");
57     }
58     Assert(internal.get());
59     internal->add_subquery(subq->internal.get());
60 }
61 
62 /// Add a subquery which is a single term
63 void
add_subquery(const string & tname)64 Query::add_subquery(const string & tname)
65 {
66     LOGCALL_VOID(API, "Xapian::Query::add_subquery", tname);
67     Assert(internal.get());
68     Query::Internal subqint(tname);
69     internal->add_subquery(&subqint);
70 }
71 
72 /// Setup the internals for the query, with the appropriate operator.
73 void
start_construction(Query::op op_,termcount parameter)74 Query::start_construction(Query::op op_, termcount parameter)
75 {
76     LOGCALL_VOID(API, "Xapian::Query::start_construction", op_);
77     Assert(!internal.get());
78     internal = new Query::Internal(op_, parameter);
79 }
80 
81 /// Check that query has an appropriate number of arguments, etc,
82 void
end_construction()83 Query::end_construction()
84 {
85     LOGCALL_VOID(API, "Xapian::Query::end_construction", NO_ARGS);
86     Assert(internal.get());
87     internal = internal->end_construction();
88 }
89 
90 /// Abort construction of the query: delete internal.
91 void
abort_construction()92 Query::abort_construction()
93 {
94     LOGCALL_VOID(API, "Xapian::Query::abort_construction", NO_ARGS);
95     Assert(internal.get());
96     internal = 0;
97 }
98 
Query(const string & tname_,termcount wqf_,termpos pos_)99 Query::Query(const string & tname_, termcount wqf_, termpos pos_)
100 	: internal(new Query::Internal(tname_, wqf_, pos_))
101 {
102     LOGCALL_VOID(API, "Xapian::Query::Query", tname_ | wqf_ | pos_);
103 }
104 
Query(Query::op op_,const Query & left,const Query & right)105 Query::Query(Query::op op_, const Query &left, const Query &right)
106 	: internal(new Query::Internal(op_, 0u))
107 {
108     LOGCALL_VOID(API, "Xapian::Query::Query", op_ | left | right);
109     try {
110 	add_subquery(left);
111 	add_subquery(right);
112 	end_construction();
113     } catch (...) {
114 	abort_construction();
115 	throw;
116     }
117 }
118 
Query(Query::op op_,Xapian::Query q,double parameter)119 Query::Query(Query::op op_, Xapian::Query q, double parameter)
120 {
121     LOGCALL_VOID(API, "Xapian::Query::Query", op_ | q | parameter);
122     if (op_ == OP_SCALE_WEIGHT) {
123 	if (!q.internal.get() ||
124 	    q.internal->op == OP_VALUE_RANGE ||
125 	    q.internal->op == OP_VALUE_GE ||
126 	    q.internal->op == OP_VALUE_LE) {
127 	    // Applying OP_SCALE_WEIGHT to Xapian::Query or OP_VALUE_*
128 	    // has no effect as they're all pure-boolean.
129 	    internal = q.internal;
130 	    return;
131 	}
132     }
133     try {
134 	start_construction(op_, 0);
135 	internal->set_dbl_parameter(parameter);
136 	add_subquery(q);
137 	end_construction();
138     } catch (...) {
139 	abort_construction();
140 	throw;
141     }
142 }
143 
Query(Query::op op_,Xapian::valueno slot,const string & begin,const string & end)144 Query::Query(Query::op op_, Xapian::valueno slot,
145 	     const string &begin, const string &end)
146     : internal(new Query::Internal(op_, slot, begin, end))
147 {
148     LOGCALL_VOID(API, "Xapian::Query::Query", op_ | slot | begin | end);
149 }
150 
Query(Query::op op_,Xapian::valueno slot,const std::string & value)151 Query::Query(Query::op op_, Xapian::valueno slot, const std::string &value)
152     : internal(new Query::Internal(op_, slot, value))
153 {
154     LOGCALL_VOID(API, "Xapian::Query::Query", op_ | slot | value);
155 }
156 
Query(PostingSource * external_source)157 Query::Query(PostingSource * external_source)
158 	: internal(NULL)
159 {
160     LOGCALL_VOID(API, "Xapian::Query::Query", external_source);
161     if (!external_source)
162 	throw Xapian::InvalidArgumentError("The external_source parameter can not be NULL");
163     PostingSource * clone = external_source->clone();
164     if (clone) {
165 	internal = new Query::Internal(clone, true);
166     } else {
167 	internal = new Query::Internal(external_source, false);
168     }
169 }
170 
171 // Copy constructor
Query(const Query & copyme)172 Query::Query(const Query & copyme)
173 	: internal(copyme.internal)
174 {
175     LOGCALL_VOID(API, "Xapian::Query::Query", copyme);
176 }
177 
178 // Assignment
179 Query &
operator =(const Query & copyme)180 Query::operator=(const Query & copyme)
181 {
182     LOGCALL(API, Xapian::Query &, "Xapian::Query::operator=", copyme);
183     internal = copyme.internal;
184     RETURN(*this);
185 }
186 
187 // Default constructor
Query()188 Query::Query() : internal(0)
189 {
190     LOGCALL_VOID(API, "Xapian::Query::Query", NO_ARGS);
191 }
192 
193 // Destructor
~Query()194 Query::~Query()
195 {
196     LOGCALL_VOID(API, "Xapian::Query::~Query", NO_ARGS);
197 }
198 
199 std::string
serialise() const200 Query::serialise() const
201 {
202     LOGCALL(API, std::string, "Xapian::Query::serialise", NO_ARGS);
203     if (!internal.get()) return std::string();
204     return internal->serialise();
205 }
206 
207 Query
unserialise(const std::string & s)208 Query::unserialise(const std::string &s)
209 {
210     LOGCALL_STATIC(API, Xapian::Query, "Xapian::Query::unserialise", s);
211     Query result;
212     if (!s.empty()) {
213 	result.internal = Xapian::Query::Internal::unserialise(s, Registry());
214     }
215     RETURN(result);
216 }
217 
218 Query
unserialise(const std::string & s,const Registry & reg)219 Query::unserialise(const std::string & s, const Registry & reg)
220 {
221     LOGCALL_STATIC(API, Xapian::Query, "Xapian::Query::unserialise", s | reg);
222     Query result;
223     if (!s.empty()) {
224 	result.internal = Xapian::Query::Internal::unserialise(s, reg);
225     }
226     RETURN(result);
227 }
228 
229 std::string
get_description() const230 Query::get_description() const
231 {
232     std::string res("Xapian::Query(");
233     if (internal.get()) res += internal->get_description();
234     res += ")";
235     return res;
236 }
237 
get_length() const238 termcount Query::get_length() const
239 {
240     LOGCALL(API, Xapian::termcount, "Xapian::Query::get_length", NO_ARGS);
241     RETURN(internal.get() ? internal->get_length() : 0);
242 }
243 
get_terms_begin() const244 TermIterator Query::get_terms_begin() const
245 {
246     LOGCALL(API, Xapian::TermIterator, "Xapian::Query::get_terms_begin", NO_ARGS);
247     if (!internal.get()) RETURN(TermIterator());
248     RETURN(internal->get_terms());
249 }
250 
251 bool
empty() const252 Query::empty() const
253 {
254     LOGCALL_VOID(API, "Xapian::Query::empty", NO_ARGS);
255     return internal.get() == 0;
256 }
257 
Query(Query::op op_,const std::string & left,const std::string & right)258 Query::Query(Query::op op_, const std::string & left, const std::string & right)
259     : internal(0)
260 {
261     try {
262 	start_construction(op_, 0);
263 	add_subquery(left);
264 	add_subquery(right);
265 	end_construction();
266     } catch (...) {
267 	abort_construction();
268 	throw;
269     }
270 }
271 
272 /* Define static members. */
273 const Xapian::Query Xapian::Query::MatchAll = Xapian::Query(string());
274 const Xapian::Query Xapian::Query::MatchNothing = Xapian::Query();
275 
276 }
277