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

Last change on this file since 23398 was 23398, checked in by max, 13 years ago

Addition of new argument for sql action

File size: 12.8 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 // "sqlfilter" - boolean flag to control whether "delete all" or
126 // "keep all" functionality is available
127 arg_ainfo.shortname = "sqlfilter";
128 arg_ainfo.longname = "whether sql filtering is active or not";
129 arg_ainfo.multiplechar = false;
130 arg_ainfo.multiplevalue = false;
131 arg_ainfo.defaultstatus = cgiarginfo::weak;
132 arg_ainfo.argdefault = "0";
133 arg_ainfo.savedarginfo = cgiarginfo::must;
134 argsinfo.addarginfo (NULL, arg_ainfo);
135}
136
137sqlqueryaction::~sqlqueryaction ()
138{
139}
140
141void sqlqueryaction::configure (const text_t &key, const text_tarray &cfgline) {
142 action::configure (key, cfgline);
143}
144
145bool sqlqueryaction::init (ostream &logout)
146{
147 return basequeryaction::init (logout);
148}
149
150
151bool sqlqueryaction::check_cgiargs (cgiargsinfoclass &argsinfo,
152 cgiargsclass &args,
153 recptprotolistclass* protos,
154 ostream &logout)
155{
156
157 // check sqlfqn argument
158 int arg_sqlfqn = args.getintarg("sqlfqn");
159 if (arg_sqlfqn < -1) {
160 logout << "Warning: \"sqlfqn\" argument less than -1 (" << arg_sqlfqn << ")\n";
161 cgiarginfo *sqlfqninfo = argsinfo.getarginfo ("sqlfqn");
162 if (sqlfqninfo != NULL) args["sqlfqn"] = sqlfqninfo->argdefault;
163 }
164
165 return basequeryaction::check_cgiargs(argsinfo,args,protos,logout);
166}
167
168
169
170void sqlqueryaction::define_external_macros (displayclass &disp,
171 cgiargsclass &args,
172 recptprotolistclass *protos,
173 ostream &logout)
174{
175 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
176 if (collectproto == NULL) return;
177
178 ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(collectproto,
179 args["c"],
180 logout);
181 comerror_t err;
182 InfoFilterOptionsResponse_t response;
183 InfoFilterOptionsRequest_t request;
184 request.filterName = "SQLQueryFilter";
185
186 collectproto->get_filteroptions (args["c"], request, response, err, logout);
187 if (err == noError) {
188 FilterOption_tmap::const_iterator it_dom;
189 FilterOption_tmap::const_iterator it_ran;
190 FilterOption_tmap::const_iterator end = response.filterOptions.end();
191
192 // _sqlfqfselection_ field list
193 it_dom = response.filterOptions.find("IndexFieldDomain");
194 it_ran = response.filterOptions.find("IndexFieldRange");
195 if ((it_dom!=end) && (it_ran!=end)) {
196
197 set_option_macro ("sqlfqf",args["sqlfqf"], true,true,
198 (*it_dom).second, (*it_ran).second, disp);
199
200 if (args["b"] == "1") {
201 // set the sort field macro
202 set_sfselection_macro(args["sqlsf"], (*it_dom).second,(*it_ran).second,
203 disp);
204 }
205 }
206 }
207
208
209}
210
211
212void sqlqueryaction::set_sfselection_macro(text_t current_value,
213 const FilterOption_t &option_domain,
214 const FilterOption_t &option_range,
215 displayclass &disp)
216{
217
218 // we need at least one option here to continue
219 if (option_domain.validValues.size() < 1) { return; }
220 if (option_range.validValues.size() < 1) { return; }
221
222 text_t macrovalue = "<select name=\"sqlsf\">\n";
223
224 if (current_value.empty()) current_value = "";
225
226 text_tarray::const_iterator dom_thisvalue = option_domain.validValues.begin();
227 text_tarray::const_iterator dom_endvalue = option_domain.validValues.end();
228
229 text_tarray::const_iterator ran_thisvalue = option_range.validValues.begin();
230 text_tarray::const_iterator ran_endvalue = option_range.validValues.end();
231
232 int valid_count = 0;
233 while ((dom_thisvalue != dom_endvalue) && (ran_thisvalue != ran_endvalue)) {
234
235 if (*ran_thisvalue != "ZZ" && *ran_thisvalue != "TX") {
236 ++valid_count;
237
238 text_t option_val = *dom_thisvalue;
239 option_val.replace(",","/");
240
241 macrovalue += "<option value=\"" + option_val + "\"";
242 if (current_value == *dom_thisvalue)
243 macrovalue += " selected";
244 macrovalue += ">_" + *ran_thisvalue + "_\n";
245 }
246 ++dom_thisvalue;
247 ++ran_thisvalue;
248 }
249 macrovalue += "</select>";
250 if (valid_count > 0) {
251 disp.setmacro ("sqlsfselection", displayclass::defaultpackage, macrovalue);
252 }
253}
254
255
256void sqlqueryaction::get_formatted_query_string (text_t& formattedstring,
257 bool segment,
258 cgiargsclass& args,
259 displayclass& disp,
260 ostream& logout)
261{
262 if (args["qt"]=="0" && args["sqlqto"] != "1") { // normal text search
263 formattedstring = "SELECT DISTINCT docOID FROM document_metadata WHERE " + args["q"];
264 }
265 else if (args["qt"]=="1" || args["sqlqto"]=="1"){ // form search
266
267 if (args["b"]=="1" && args["fqa"]=="1") { // explicit query
268 formattedstring = args["q"];
269 }
270 else { // form search
271 // *****
272 // Consider making this its own method in basequeryaction
273 // then make parse_.*reg_query_form virtual method in class
274
275 if (args["b"]=="0") { // regular form
276 parse_sqlreg_query_form(formattedstring, args, segment);
277 }
278 else { // advanced form
279 parse_sqladv_query_form(formattedstring, args, segment);
280 }
281 args["q"] = formattedstring;
282
283 // reset the cgiargfqv macro - need to escape any quotes in it
284 disp.setmacro("cgiargfqv", "query", escape_quotes(args["fqv"]));
285
286 // also reset the _cgiargq_ macro as it has changed now
287 disp.setmacro("cgiargq", displayclass::defaultpackage, html_safe(args["q"]));
288
289 // reset the compressed options to include the q arg
290 text_t compressedoptions = recpt->get_compressed_arg(args, logout);
291 if (!compressedoptions.empty()) {
292 disp.setmacro ("compressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
293 // need a decoded version of compressedoptions for use within forms
294 // as browsers encode values from forms before sending to server
295 // (e.g. %25 becomes %2525)
296 decode_cgi_arg (compressedoptions);
297 if (args["w"] == "utf-8") { // if the encoding was utf-8, then compressed options was utf-8, and we need unicode.
298 // if encoding wasn't utf-8, then compressed opotions may be screwed up, but seems to work for 8 bit encodings?
299 compressedoptions = to_uni(compressedoptions);
300 }
301
302 disp.setmacro ("decodedcompressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
303 }
304 } // form search
305 } // args["qt"]=1
306 else {
307 logout << "ERROR (sqlqueryaction::get_formatted_query_string): querytype not defined\n";
308 }
309
310
311
312
313
314}
315
316
317// request.filterResultOptions and request.fields (if required) should
318// be set from the calling code
319void sqlqueryaction::set_queryfilter_options (FilterRequest_t &request,
320 const text_t &querystring,
321 cgiargsclass &args)
322{
323 request.filterName = "SQLQueryFilter";
324
325 OptionValue_t option;
326
327 option.name = "SQLWhere";
328 option.value = querystring;
329 request.filterOptions.push_back (option);
330
331 set_sql_queryfilter_options(request, args);
332}
333
334
335
336// should this change for cross coll search??
337bool sqlqueryaction::save_search_history (cgiargsclass &args, int numdocs,
338 isapprox isApprox)
339{
340
341
342 if (args["q"]=="") return true; // null query, dont save
343 if (args["hs"]=="0") return true; // only save when submit query pressed
344
345 // get userid
346 text_t userid = args["z"];
347
348 // the number of docs goes on the front of the query string
349 text_t query = text_t(numdocs);
350 if (isApprox==MoreThan) { // there were more docs found
351 query.push_back('+');
352 }
353 query += "c="+args["c"];
354
355 text_t qstring = args["q"];
356 //text_t formattedquery =cgi_safe(qstring);
357 //query += "&amp;q="+formattedquery;
358 query += ";q="+qstring;
359 bool display=false;
360 int hd = args.getintarg("hd");
361 if (hd > 0) display=true;
362 if (set_history_info(userid, query, dbhome, display)) return true;
363 else return false;
364
365}
366
367void sqlqueryaction::define_form_macros (displayclass &disp,
368 cgiargsclass &args,
369 recptprotolistclass *protos,
370 ostream &logout)
371{
372 // defines the following macros
373 // _sqlregformlist_
374 // _sqladvformlist_
375
376 text_t form = "";
377 int argsqlfqn = args.getintarg("sqlfqn");
378
379 if (args["b"] == "1") { // advanced form
380 form += "_firstsqladvformelement_\n";
381 for (int i=1; i<argsqlfqn; ++i) {
382 form += "_sqladvformelement_\n";
383 }
384 disp.setmacro("sqladvformlist", "query", form);
385 }
386 else { // simple form
387 for (int i=0; i<argsqlfqn; ++i) {
388 form += "_sqlregformelement_\n";
389 }
390 disp.setmacro("sqlregformlist", "query", form);
391 }
392
393}
394
395
396bool sqlqueryaction::do_action (cgiargsclass &args,
397 recptprotolistclass *protos,
398 browsermapclass *browsers, displayclass &disp,
399 outconvertclass &outconvert, ostream &textout,
400 ostream &logout)
401{
402 return search_single_collection (args, args["c"], protos, browsers, disp,
403 outconvert, textout, logout);
404}
405
406
407
Note: See TracBrowser for help on using the repository browser.