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

Last change on this file since 22984 was 22984, checked in by ak19, 14 years ago
  1. Undoing commit of 22934 where decode_commas was called on stem and fold comma separated list: previously separated due to url-encoding of commas. Now that the problem has been fixed at the source, the decode_commas hack is no longer necessary. 2. Commas in stem and fold are no longer url-encoded because the multiple_value field of the continuously-reused struct arg_ainfo is always set back to the default false after ever being set to true. So it no longer subtly stays at true to affect Greenstone functioning in unforeseen ways (such as suddenly and unnecessarily URL-encoding commas where this is not wanted).
File size: 12.3 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.multiplevalue = false;
50 arg_ainfo.defaultstatus = cgiarginfo::weak;
51 arg_ainfo.argdefault = "sqlq";
52 arg_ainfo.savedarginfo = cgiarginfo::must;
53 argsinfo.addarginfo (NULL, arg_ainfo);
54
55 // "sqlqto" - 0 = not available, 1 = available
56 arg_ainfo.shortname = "sqlqto";
57 arg_ainfo.longname = "sqlquery type options";
58 arg_ainfo.multiplechar = true; // can be empty or single char
59 arg_ainfo.multiplevalue = false;
60 arg_ainfo.defaultstatus = cgiarginfo::weak;
61 arg_ainfo.argdefault = g_EmptyText;
62 arg_ainfo.savedarginfo = cgiarginfo::must;
63 argsinfo.addarginfo (NULL, arg_ainfo);
64
65 // "sqlfqn" - number of fields in the query form
66 arg_ainfo.shortname = "sqlfqn";
67 arg_ainfo.longname = "sql form query num fields";
68 arg_ainfo.multiplechar = true;
69 arg_ainfo.multiplevalue = false;
70 arg_ainfo.defaultstatus = cgiarginfo::weak;
71 arg_ainfo.argdefault = "4";
72 arg_ainfo.savedarginfo = cgiarginfo::must;
73 argsinfo.addarginfo (NULL, arg_ainfo);
74
75 // "sqlfqf" - the list of field names in the form query
76 // - a comma separated list
77 arg_ainfo.shortname = "sqlfqf";
78 arg_ainfo.longname = "sql form query fields";
79 arg_ainfo.multiplechar = true;
80 arg_ainfo.multiplevalue = false;
81 arg_ainfo.defaultstatus = cgiarginfo::weak;
82 arg_ainfo.argdefault = g_EmptyText;
83 arg_ainfo.savedarginfo = cgiarginfo::must;
84 argsinfo.addarginfo (NULL, arg_ainfo);
85
86 // "sqlfqv" - the list of values in the form query
87 // - a comma separated list
88 arg_ainfo.shortname = "sqlfqv";
89 arg_ainfo.longname = "sql form query values";
90 arg_ainfo.multiplechar = true;
91 arg_ainfo.multiplevalue = false;
92 arg_ainfo.defaultstatus = cgiarginfo::weak;
93 arg_ainfo.argdefault = g_EmptyText;
94 arg_ainfo.savedarginfo = cgiarginfo::must;
95 argsinfo.addarginfo (NULL, arg_ainfo);
96
97 // "sqlfqc" - the list of boolean operators in the form query
98 // - a comma separated list
99 arg_ainfo.shortname = "sqlfqc";
100 arg_ainfo.longname = "sql form query combines";
101 arg_ainfo.multiplechar = true;
102 arg_ainfo.multiplevalue = false;
103 arg_ainfo.defaultstatus = cgiarginfo::weak;
104 arg_ainfo.argdefault = g_EmptyText;
105 arg_ainfo.savedarginfo = cgiarginfo::must;
106 argsinfo.addarginfo (NULL, arg_ainfo);
107
108 // ****
109 // Looks like 'multiplevalue' is left undefined (e.g. not set in
110 // constructor). This looks like a fairly major problem
111 // in terms of leaving it undefine
112 // => in the case of "sqlsf" leads to conflict over value it has
113
114 // "sqlsf" - Sort field. Set to field to be used for sorting search reult
115 // set
116 arg_ainfo.shortname = "sqlsf";
117 arg_ainfo.longname = "sql sort field";
118 arg_ainfo.multiplechar = true;
119 arg_ainfo.multiplevalue = false;
120 arg_ainfo.defaultstatus = cgiarginfo::weak;
121 arg_ainfo.argdefault = g_EmptyText;
122 arg_ainfo.savedarginfo = cgiarginfo::must;
123 argsinfo.addarginfo (NULL, arg_ainfo);
124
125}
126
127sqlqueryaction::~sqlqueryaction ()
128{
129}
130
131void sqlqueryaction::configure (const text_t &key, const text_tarray &cfgline) {
132 action::configure (key, cfgline);
133}
134
135bool sqlqueryaction::init (ostream &logout)
136{
137 return basequeryaction::init (logout);
138}
139
140
141bool sqlqueryaction::check_cgiargs (cgiargsinfoclass &argsinfo,
142 cgiargsclass &args,
143 recptprotolistclass* protos,
144 ostream &logout)
145{
146
147 // check sqlfqn argument
148 int arg_sqlfqn = args.getintarg("sqlfqn");
149 if (arg_sqlfqn < -1) {
150 logout << "Warning: \"sqlfqn\" argument less than -1 (" << arg_sqlfqn << ")\n";
151 cgiarginfo *sqlfqninfo = argsinfo.getarginfo ("sqlfqn");
152 if (sqlfqninfo != NULL) args["sqlfqn"] = sqlfqninfo->argdefault;
153 }
154
155 return basequeryaction::check_cgiargs(argsinfo,args,protos,logout);
156}
157
158
159
160void sqlqueryaction::define_external_macros (displayclass &disp,
161 cgiargsclass &args,
162 recptprotolistclass *protos,
163 ostream &logout)
164{
165 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
166 if (collectproto == NULL) return;
167
168 ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(collectproto,
169 args["c"],
170 logout);
171 comerror_t err;
172 InfoFilterOptionsResponse_t response;
173 InfoFilterOptionsRequest_t request;
174 request.filterName = "SQLQueryFilter";
175
176 collectproto->get_filteroptions (args["c"], request, response, err, logout);
177 if (err == noError) {
178 FilterOption_tmap::const_iterator it_dom;
179 FilterOption_tmap::const_iterator it_ran;
180 FilterOption_tmap::const_iterator end = response.filterOptions.end();
181
182 // _sqlfqfselection_ field list
183 it_dom = response.filterOptions.find("IndexFieldDomain");
184 it_ran = response.filterOptions.find("IndexFieldRange");
185 if ((it_dom!=end) && (it_ran!=end)) {
186
187 set_option_macro ("sqlfqf",args["sqlfqf"], true,true,
188 (*it_dom).second, (*it_ran).second, disp);
189
190 if (args["b"] == "1") {
191 // set the sort field macro
192 set_sfselection_macro(args["sqlsf"], (*it_dom).second,(*it_ran).second,
193 disp);
194 }
195 }
196 }
197
198
199}
200
201
202void sqlqueryaction::set_sfselection_macro(text_t current_value,
203 const FilterOption_t &option_domain,
204 const FilterOption_t &option_range,
205 displayclass &disp)
206{
207
208 // we need at least one option here to continue
209 if (option_domain.validValues.size() < 1) { return; }
210 if (option_range.validValues.size() < 1) { return; }
211
212 text_t macrovalue = "<select name=\"sqlsf\">\n";
213
214 if (current_value.empty()) current_value = "";
215
216 text_tarray::const_iterator dom_thisvalue = option_domain.validValues.begin();
217 text_tarray::const_iterator dom_endvalue = option_domain.validValues.end();
218
219 text_tarray::const_iterator ran_thisvalue = option_range.validValues.begin();
220 text_tarray::const_iterator ran_endvalue = option_range.validValues.end();
221
222 int valid_count = 0;
223 while ((dom_thisvalue != dom_endvalue) && (ran_thisvalue != ran_endvalue)) {
224
225 if (*ran_thisvalue != "ZZ" && *ran_thisvalue != "TX") {
226 ++valid_count;
227
228 text_t option_val = *dom_thisvalue;
229 option_val.replace(",","/");
230
231 macrovalue += "<option value=\"" + option_val + "\"";
232 if (current_value == *dom_thisvalue)
233 macrovalue += " selected";
234 macrovalue += ">_" + *ran_thisvalue + "_\n";
235 }
236 ++dom_thisvalue;
237 ++ran_thisvalue;
238 }
239 macrovalue += "</select>";
240 if (valid_count > 0) {
241 disp.setmacro ("sqlsfselection", displayclass::defaultpackage, macrovalue);
242 }
243}
244
245
246void sqlqueryaction::get_formatted_query_string (text_t& formattedstring,
247 bool segment,
248 cgiargsclass& args,
249 displayclass& disp,
250 ostream& logout)
251{
252 if (args["qt"]=="0" && args["sqlqto"] != "1") { // normal text search
253 formattedstring = "SELECT DISTINCT docOID FROM document_metadata WHERE " + args["q"];
254 }
255 else if (args["qt"]=="1" || args["sqlqto"]=="1"){ // form search
256
257 if (args["b"]=="1" && args["fqa"]=="1") { // explicit query
258 formattedstring = args["q"];
259 }
260 else { // form search
261 // *****
262 // Consider making this its own method in basequeryaction
263 // then make parse_.*reg_query_form virtual method in class
264
265 if (args["b"]=="0") { // regular form
266 parse_sqlreg_query_form(formattedstring, args, segment);
267 }
268 else { // advanced form
269 parse_sqladv_query_form(formattedstring, args, segment);
270 }
271 args["q"] = formattedstring;
272
273 // reset the cgiargfqv macro - need to escape any quotes in it
274 disp.setmacro("cgiargfqv", "query", escape_quotes(args["fqv"]));
275
276 // also reset the _cgiargq_ macro as it has changed now
277 disp.setmacro("cgiargq", displayclass::defaultpackage, html_safe(args["q"]));
278
279 // reset the compressed options to include the q arg
280 text_t compressedoptions = recpt->get_compressed_arg(args, logout);
281 if (!compressedoptions.empty()) {
282 disp.setmacro ("compressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
283 // need a decoded version of compressedoptions for use within forms
284 // as browsers encode values from forms before sending to server
285 // (e.g. %25 becomes %2525)
286 decode_cgi_arg (compressedoptions);
287 if (args["w"] == "utf-8") { // if the encoding was utf-8, then compressed options was utf-8, and we need unicode.
288 // if encoding wasn't utf-8, then compressed opotions may be screwed up, but seems to work for 8 bit encodings?
289 compressedoptions = to_uni(compressedoptions);
290 }
291
292 disp.setmacro ("decodedcompressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
293 }
294 } // form search
295 } // args["qt"]=1
296 else {
297 logout << "ERROR (sqlqueryaction::get_formatted_query_string): querytype not defined\n";
298 }
299
300
301
302
303
304}
305
306
307// request.filterResultOptions and request.fields (if required) should
308// be set from the calling code
309void sqlqueryaction::set_queryfilter_options (FilterRequest_t &request,
310 const text_t &querystring,
311 cgiargsclass &args)
312{
313 request.filterName = "SQLQueryFilter";
314
315 OptionValue_t option;
316
317 option.name = "SQLWhere";
318 option.value = querystring;
319 request.filterOptions.push_back (option);
320
321 set_sql_queryfilter_options(request, args);
322}
323
324
325
326// should this change for cross coll search??
327bool sqlqueryaction::save_search_history (cgiargsclass &args, int numdocs,
328 isapprox isApprox)
329{
330
331
332 if (args["q"]=="") return true; // null query, dont save
333 if (args["hs"]=="0") return true; // only save when submit query pressed
334
335 // get userid
336 text_t userid = args["z"];
337
338 // the number of docs goes on the front of the query string
339 text_t query = text_t(numdocs);
340 if (isApprox==MoreThan) { // there were more docs found
341 query.push_back('+');
342 }
343 query += "c="+args["c"];
344
345 text_t qstring = args["q"];
346 //text_t formattedquery =cgi_safe(qstring);
347 //query += "&amp;q="+formattedquery;
348 query += ";q="+qstring;
349 bool display=false;
350 int hd = args.getintarg("hd");
351 if (hd > 0) display=true;
352 if (set_history_info(userid, query, dbhome, display)) return true;
353 else return false;
354
355}
356
357void sqlqueryaction::define_form_macros (displayclass &disp,
358 cgiargsclass &args,
359 recptprotolistclass *protos,
360 ostream &logout)
361{
362 // defines the following macros
363 // _sqlregformlist_
364 // _sqladvformlist_
365
366 text_t form = "";
367 int argsqlfqn = args.getintarg("sqlfqn");
368
369 if (args["b"] == "1") { // advanced form
370 form += "_firstsqladvformelement_\n";
371 for (int i=1; i<argsqlfqn; ++i) {
372 form += "_sqladvformelement_\n";
373 }
374 disp.setmacro("sqladvformlist", "query", form);
375 }
376 else { // simple form
377 for (int i=0; i<argsqlfqn; ++i) {
378 form += "_sqlregformelement_\n";
379 }
380 disp.setmacro("sqlregformlist", "query", form);
381 }
382
383}
384
385
386bool sqlqueryaction::do_action (cgiargsclass &args,
387 recptprotolistclass *protos,
388 browsermapclass *browsers, displayclass &disp,
389 outconvertclass &outconvert, ostream &textout,
390 ostream &logout)
391{
392 return search_single_collection (args, args["c"], protos, browsers, disp,
393 outconvert, textout, logout);
394}
395
396
397
Note: See TracBrowser for help on using the repository browser.