root/main/trunk/greenstone2/runtime-src/src/recpt/sqlqueryaction.cpp @ 22044

Revision 22044, 11.8 KB (checked in by davidb, 10 years ago)

Introduction of sql-query action. This has been achived be creating a base call for query-action (sharing common functionality for fulltext query action and sql query action).

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