source: main/trunk/greenstone2/runtime-src/src/recpt/sqlqueryaction.cpp@ 22693

Last change on this file since 22693 was 22693, checked in by davidb, 14 years ago

'multiplevalue' appears to be left undefined -- in general for all args being set. In the case of 'sqlsf' this lead to a conflict-warning message. The current fix, sorts out the problem in this one case, but looks like a more general solution should be implemented. This could be as simple as ensuring sensible default values in its constructor

File size: 12.1 KB
Line 
1/**********************************************************************
2 *
3 * sqlqueryaction.cpp --
4 * Copyright (C) 2010 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "sqlqueryaction.h"
27#include "querytools.h"
28#include "formattools.h"
29#include "cgiutils.h"
30#include "OIDtools.h"
31#include "fileutil.h"
32#include "text_t.h"
33#include "historydb.h"
34#include "htmlutils.h" // for html_safe in do_action
35#include "gsdltools.h"
36#include <stdlib.h> // for strtol
37#include <assert.h>
38
39
40sqlqueryaction::sqlqueryaction ()
41 : basequeryaction()
42{
43 cgiarginfo arg_ainfo;
44
45 // this action uses cgi variable "a"
46 arg_ainfo.shortname = "a";
47 arg_ainfo.longname = "action";
48 arg_ainfo.multiplechar = true;
49 arg_ainfo.defaultstatus = cgiarginfo::weak;
50 arg_ainfo.argdefault = "sqlq";
51 arg_ainfo.savedarginfo = cgiarginfo::must;
52 argsinfo.addarginfo (NULL, arg_ainfo);
53
54 // "sqlqto" - 0 = not available, 1 = available
55 arg_ainfo.shortname = "sqlqto";
56 arg_ainfo.longname = "sqlquery type options";
57 arg_ainfo.multiplechar = true; // can be empty or single char
58 arg_ainfo.defaultstatus = cgiarginfo::weak;
59 arg_ainfo.argdefault = g_EmptyText;
60 arg_ainfo.savedarginfo = cgiarginfo::must;
61 argsinfo.addarginfo (NULL, arg_ainfo);
62
63 // "sqlfqn" - number of fields in the query form
64 arg_ainfo.shortname = "sqlfqn";
65 arg_ainfo.longname = "sql form query num fields";
66 arg_ainfo.multiplechar = true;
67 arg_ainfo.defaultstatus = cgiarginfo::weak;
68 arg_ainfo.argdefault = "4";
69 arg_ainfo.savedarginfo = cgiarginfo::must;
70 argsinfo.addarginfo (NULL, arg_ainfo);
71
72 // "sqlfqf" - the list of field names in the form query
73 // - a comma separated list
74 arg_ainfo.shortname = "sqlfqf";
75 arg_ainfo.longname = "sql form query fields";
76 arg_ainfo.multiplechar = true;
77 arg_ainfo.defaultstatus = cgiarginfo::weak;
78 arg_ainfo.argdefault = g_EmptyText;
79 arg_ainfo.savedarginfo = cgiarginfo::must;
80 argsinfo.addarginfo (NULL, arg_ainfo);
81
82 // "sqlfqv" - the list of values in the form query
83 // - a comma separated list
84 arg_ainfo.shortname = "sqlfqv";
85 arg_ainfo.longname = "sql form query values";
86 arg_ainfo.multiplechar = true;
87 arg_ainfo.defaultstatus = cgiarginfo::weak;
88 arg_ainfo.argdefault = g_EmptyText;
89 arg_ainfo.savedarginfo = cgiarginfo::must;
90 argsinfo.addarginfo (NULL, arg_ainfo);
91
92 // "sqlfqc" - the list of boolean operators in the form query
93 // - a comma separated list
94 arg_ainfo.shortname = "sqlfqc";
95 arg_ainfo.longname = "sql form query combines";
96 arg_ainfo.multiplechar = true;
97 arg_ainfo.defaultstatus = cgiarginfo::weak;
98 arg_ainfo.argdefault = g_EmptyText;
99 arg_ainfo.savedarginfo = cgiarginfo::must;
100 argsinfo.addarginfo (NULL, arg_ainfo);
101
102 // ****
103 // Looks like 'multiplevalue' is left undefined (e.g. not set in
104 // constructor). This looks like a fairly major problem
105 // in terms of leaving it undefine
106 // => in the case of "sqlsf" leads to conflict over value it has
107
108 // "sqlsf" - Sort field. Set to field to be used for sorting search reult
109 // set
110 arg_ainfo.shortname = "sqlsf";
111 arg_ainfo.longname = "sql sort field";
112 arg_ainfo.multiplechar = true;
113 arg_ainfo.multiplevalue = false;
114 arg_ainfo.defaultstatus = cgiarginfo::weak;
115 arg_ainfo.argdefault = g_EmptyText;
116 arg_ainfo.savedarginfo = cgiarginfo::must;
117 argsinfo.addarginfo (NULL, arg_ainfo);
118
119}
120
121sqlqueryaction::~sqlqueryaction ()
122{
123}
124
125void sqlqueryaction::configure (const text_t &key, const text_tarray &cfgline) {
126 action::configure (key, cfgline);
127}
128
129bool sqlqueryaction::init (ostream &logout)
130{
131 return basequeryaction::init (logout);
132}
133
134
135bool sqlqueryaction::check_cgiargs (cgiargsinfoclass &argsinfo,
136 cgiargsclass &args,
137 recptprotolistclass* protos,
138 ostream &logout)
139{
140
141 // check sqlfqn argument
142 int arg_sqlfqn = args.getintarg("sqlfqn");
143 if (arg_sqlfqn < -1) {
144 logout << "Warning: \"sqlfqn\" argument less than -1 (" << arg_sqlfqn << ")\n";
145 cgiarginfo *sqlfqninfo = argsinfo.getarginfo ("sqlfqn");
146 if (sqlfqninfo != NULL) args["sqlfqn"] = sqlfqninfo->argdefault;
147 }
148
149 return basequeryaction::check_cgiargs(argsinfo,args,protos,logout);
150}
151
152
153
154void sqlqueryaction::define_external_macros (displayclass &disp,
155 cgiargsclass &args,
156 recptprotolistclass *protos,
157 ostream &logout)
158{
159 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
160 if (collectproto == NULL) return;
161
162 ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(collectproto,
163 args["c"],
164 logout);
165 comerror_t err;
166 InfoFilterOptionsResponse_t response;
167 InfoFilterOptionsRequest_t request;
168 request.filterName = "SQLQueryFilter";
169
170 collectproto->get_filteroptions (args["c"], request, response, err, logout);
171 if (err == noError) {
172 FilterOption_tmap::const_iterator it_dom;
173 FilterOption_tmap::const_iterator it_ran;
174 FilterOption_tmap::const_iterator end = response.filterOptions.end();
175
176 // _sqlfqfselection_ field list
177 it_dom = response.filterOptions.find("IndexFieldDomain");
178 it_ran = response.filterOptions.find("IndexFieldRange");
179 if ((it_dom!=end) && (it_ran!=end)) {
180
181 set_option_macro ("sqlfqf",args["sqlfqf"], true,true,
182 (*it_dom).second, (*it_ran).second, disp);
183
184 if (args["b"] == "1") {
185 // set the sort field macro
186 set_sfselection_macro(args["sqlsf"], (*it_dom).second,(*it_ran).second,
187 disp);
188 }
189 }
190 }
191
192
193}
194
195
196void sqlqueryaction::set_sfselection_macro(text_t current_value,
197 const FilterOption_t &option_domain,
198 const FilterOption_t &option_range,
199 displayclass &disp)
200{
201
202 // we need at least one option here to continue
203 if (option_domain.validValues.size() < 1) { return; }
204 if (option_range.validValues.size() < 1) { return; }
205
206 text_t macrovalue = "<select name=\"sqlsf\">\n";
207
208 if (current_value.empty()) current_value = "";
209
210 text_tarray::const_iterator dom_thisvalue = option_domain.validValues.begin();
211 text_tarray::const_iterator dom_endvalue = option_domain.validValues.end();
212
213 text_tarray::const_iterator ran_thisvalue = option_range.validValues.begin();
214 text_tarray::const_iterator ran_endvalue = option_range.validValues.end();
215
216 int valid_count = 0;
217 while ((dom_thisvalue != dom_endvalue) && (ran_thisvalue != ran_endvalue)) {
218
219 if (*ran_thisvalue != "ZZ" && *ran_thisvalue != "TX") {
220 ++valid_count;
221
222 text_t option_val = *dom_thisvalue;
223 option_val.replace(",","/");
224
225 macrovalue += "<option value=\"" + option_val + "\"";
226 if (current_value == *dom_thisvalue)
227 macrovalue += " selected";
228 macrovalue += ">_" + *ran_thisvalue + "_\n";
229 }
230 ++dom_thisvalue;
231 ++ran_thisvalue;
232 }
233 macrovalue += "</select>";
234 if (valid_count > 0) {
235 disp.setmacro ("sqlsfselection", displayclass::defaultpackage, macrovalue);
236 }
237}
238
239
240void sqlqueryaction::get_formatted_query_string (text_t& formattedstring,
241 bool segment,
242 cgiargsclass& args,
243 displayclass& disp,
244 ostream& logout)
245{
246 if (args["qt"]=="0" && args["sqlqto"] != "1") { // normal text search
247 formattedstring = "SELECT DISTINCT docOID FROM document_metadata WHERE " + args["q"];
248 }
249 else if (args["qt"]=="1" || args["sqlqto"]=="1"){ // form search
250
251 if (args["b"]=="1" && args["fqa"]=="1") { // explicit query
252 formattedstring = args["q"];
253 }
254 else { // form search
255 // *****
256 // Consider making this its own method in basequeryaction
257 // then make parse_.*reg_query_form virtual method in class
258
259 if (args["b"]=="0") { // regular form
260 parse_sqlreg_query_form(formattedstring, args, segment);
261 }
262 else { // advanced form
263 parse_sqladv_query_form(formattedstring, args, segment);
264 }
265 args["q"] = formattedstring;
266
267 // reset the cgiargfqv macro - need to escape any quotes in it
268 disp.setmacro("cgiargfqv", "query", escape_quotes(args["fqv"]));
269
270 // also reset the _cgiargq_ macro as it has changed now
271 disp.setmacro("cgiargq", displayclass::defaultpackage, html_safe(args["q"]));
272
273 // reset the compressed options to include the q arg
274 text_t compressedoptions = recpt->get_compressed_arg(args, logout);
275 if (!compressedoptions.empty()) {
276 disp.setmacro ("compressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
277 // need a decoded version of compressedoptions for use within forms
278 // as browsers encode values from forms before sending to server
279 // (e.g. %25 becomes %2525)
280 decode_cgi_arg (compressedoptions);
281 if (args["w"] == "utf-8") { // if the encoding was utf-8, then compressed options was utf-8, and we need unicode.
282 // if encoding wasn't utf-8, then compressed opotions may be screwed up, but seems to work for 8 bit encodings?
283 compressedoptions = to_uni(compressedoptions);
284 }
285
286 disp.setmacro ("decodedcompressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
287 }
288 } // form search
289 } // args["qt"]=1
290 else {
291 logout << "ERROR (sqlqueryaction::get_formatted_query_string): querytype not defined\n";
292 }
293
294
295
296
297
298}
299
300
301// request.filterResultOptions and request.fields (if required) should
302// be set from the calling code
303void sqlqueryaction::set_queryfilter_options (FilterRequest_t &request,
304 const text_t &querystring,
305 cgiargsclass &args)
306{
307 request.filterName = "SQLQueryFilter";
308
309 OptionValue_t option;
310
311 option.name = "SQLWhere";
312 option.value = querystring;
313 request.filterOptions.push_back (option);
314
315 set_sql_queryfilter_options(request, args);
316}
317
318
319
320// should this change for cross coll search??
321bool sqlqueryaction::save_search_history (cgiargsclass &args, int numdocs,
322 isapprox isApprox)
323{
324
325
326 if (args["q"]=="") return true; // null query, dont save
327 if (args["hs"]=="0") return true; // only save when submit query pressed
328
329 // get userid
330 text_t userid = args["z"];
331
332 // the number of docs goes on the front of the query string
333 text_t query = text_t(numdocs);
334 if (isApprox==MoreThan) { // there were more docs found
335 query.push_back('+');
336 }
337 query += "c="+args["c"];
338
339 text_t qstring = args["q"];
340 //text_t formattedquery =cgi_safe(qstring);
341 //query += "&amp;q="+formattedquery;
342 query += ";q="+qstring;
343 bool display=false;
344 int hd = args.getintarg("hd");
345 if (hd > 0) display=true;
346 if (set_history_info(userid, query, dbhome, display)) return true;
347 else return false;
348
349}
350
351void sqlqueryaction::define_form_macros (displayclass &disp,
352 cgiargsclass &args,
353 recptprotolistclass *protos,
354 ostream &logout)
355{
356 // defines the following macros
357 // _sqlregformlist_
358 // _sqladvformlist_
359
360 text_t form = "";
361 int argsqlfqn = args.getintarg("sqlfqn");
362
363 if (args["b"] == "1") { // advanced form
364 form += "_firstsqladvformelement_\n";
365 for (int i=1; i<argsqlfqn; ++i) {
366 form += "_sqladvformelement_\n";
367 }
368 disp.setmacro("sqladvformlist", "query", form);
369 }
370 else { // simple form
371 for (int i=0; i<argsqlfqn; ++i) {
372 form += "_sqlregformelement_\n";
373 }
374 disp.setmacro("sqlregformlist", "query", form);
375 }
376
377}
378
379
380bool sqlqueryaction::do_action (cgiargsclass &args,
381 recptprotolistclass *protos,
382 browsermapclass *browsers, displayclass &disp,
383 outconvertclass &outconvert, ostream &textout,
384 ostream &logout)
385{
386 return search_single_collection (args, args["c"], protos, browsers, disp,
387 outconvert, textout, logout);
388}
389
390
391
Note: See TracBrowser for help on using the repository browser.