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