1 /* This file is part of mp-xquery
2 Copyright (C) Index Data
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <metaproxy/package.hpp>
20 #include <metaproxy/util.hpp>
22 #include <yaz/oid_db.h>
23 #include <yaz/diagbib1.h>
30 #include <zorba/zorba.h>
31 #include <zorba/store_manager.h>
32 #include <zorba/serializer.h>
33 #include <zorba/singleton_item_sequence.h>
34 #include <zorba/zorba_exception.h>
37 namespace mp = metaproxy_1;
38 namespace yf = mp::filter;
39 namespace mp_util = metaproxy_1::util;
41 using namespace zorba;
43 namespace metaproxy_1 {
45 class XQuery : public Base {
49 void process(metaproxy_1::Package & package) const;
50 void configure(const xmlNode * ptr, bool test_only,
53 void stop(int signo) const;
55 bool convert_one_record(const char *input_buf,
57 std::string &result) const;
58 std::map<std::string, std::string> zorba_variables;
59 std::string zorba_filename;
60 std::string zorba_script;
61 std::string zorba_record_variable;
62 std::string elementset_input;
63 std::string elementset_output;
81 void yf::XQuery::start() const
85 void yf::XQuery::stop(int signo) const
89 bool yf::XQuery::convert_one_record(const char *input_buf,
91 std::string &result) const
93 XQuery_t tQuery = lQuery->clone();
95 zorba::DynamicContext* lDynamicContext = tQuery->getDynamicContext();
98 std::map<std::string, std::string>::const_iterator it;
99 for (it = zorba_variables.begin(); it != zorba_variables.end(); it++)
101 lItem = lZorba->getItemFactory()->createString(it->second);
102 lDynamicContext->setVariable(it->first, lItem);
104 std::string rec_content = "raw:" + std::string(input_buf, input_len);
105 lItem = lZorba->getItemFactory()->createString(rec_content);
106 lDynamicContext->setVariable(zorba_record_variable, lItem);
109 std::stringstream ss;
113 } catch ( ZorbaException &e) {
115 yaz_log(YLOG_WARN, "XQuery execute: %s", result.c_str());
120 void yf::XQuery::process(Package &package) const
122 Z_GDU *gdu_req = package.request().get();
123 Z_PresentRequest *pr_req = 0;
124 Z_SearchRequest *sr_req = 0;
126 const char *input_schema = 0;
127 Odr_oid *input_syntax = 0;
129 if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
130 gdu_req->u.z3950->which == Z_APDU_presentRequest)
132 pr_req = gdu_req->u.z3950->u.presentRequest;
135 mp_util::record_composition_to_esn(pr_req->recordComposition);
136 input_syntax = pr_req->preferredRecordSyntax;
138 else if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
139 gdu_req->u.z3950->which == Z_APDU_searchRequest)
141 sr_req = gdu_req->u.z3950->u.searchRequest;
143 input_syntax = sr_req->preferredRecordSyntax;
145 // we don't know how many hits we're going to get and therefore
146 // the effective element set name.. Therefore we can only allow
147 // two cases.. Both equal or absent.. If not, we'll just have to
148 // disable the piggyback!
149 if (sr_req->smallSetElementSetNames
151 sr_req->mediumSetElementSetNames
153 sr_req->smallSetElementSetNames->which == Z_ElementSetNames_generic
155 sr_req->mediumSetElementSetNames->which == Z_ElementSetNames_generic
157 !strcmp(sr_req->smallSetElementSetNames->u.generic,
158 sr_req->mediumSetElementSetNames->u.generic))
160 input_schema = sr_req->smallSetElementSetNames->u.generic;
162 else if (!sr_req->smallSetElementSetNames &&
163 !sr_req->mediumSetElementSetNames)
164 ; // input_schema is 0 already
167 // disable piggyback (perhaps it was disabled already)
168 *sr_req->smallSetUpperBound = 0;
169 *sr_req->largeSetLowerBound = 0;
170 *sr_req->mediumSetPresentNumber = 0;
174 // we can handle it in record_transform.
182 mp::odr odr_en(ODR_ENCODE);
184 const char *backend_schema = 0;
185 const Odr_oid *backend_syntax = 0;
187 if (input_schema && !strcmp(input_schema, elementset_input.c_str()) &&
188 (!input_syntax || !oid_oidcmp(input_syntax, yaz_oid_recsyn_xml)))
190 backend_schema = elementset_output.c_str();
191 backend_syntax = yaz_oid_recsyn_xml;
202 sr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
204 sr_req->preferredRecordSyntax = 0;
207 sr_req->smallSetElementSetNames
208 = (Z_ElementSetNames *)
209 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
210 sr_req->smallSetElementSetNames->which = Z_ElementSetNames_generic;
211 sr_req->smallSetElementSetNames->u.generic
212 = odr_strdup(odr_en, backend_schema);
213 sr_req->mediumSetElementSetNames = sr_req->smallSetElementSetNames;
217 sr_req->smallSetElementSetNames = 0;
218 sr_req->mediumSetElementSetNames = 0;
224 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
226 pr_req->preferredRecordSyntax = 0;
230 pr_req->recordComposition
231 = (Z_RecordComposition *)
232 odr_malloc(odr_en, sizeof(Z_RecordComposition));
233 pr_req->recordComposition->which
234 = Z_RecordComp_simple;
235 pr_req->recordComposition->u.simple
236 = (Z_ElementSetNames *)
237 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
238 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
239 pr_req->recordComposition->u.simple->u.generic
240 = odr_strdup(odr_en, backend_schema);
243 pr_req->recordComposition = 0;
247 Z_GDU *gdu_res = package.response().get();
249 // see if we have a records list to patch!
250 Z_NamePlusRecordList *records = 0;
251 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
252 gdu_res->u.z3950->which == Z_APDU_presentResponse)
254 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
257 && pr_res->numberOfRecordsReturned
258 && *(pr_res->numberOfRecordsReturned) > 0
260 && pr_res->records->which == Z_Records_DBOSD)
262 records = pr_res->records->u.databaseOrSurDiagnostics;
265 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
266 gdu_res->u.z3950->which == Z_APDU_searchResponse)
268 Z_SearchResponse *sr_res = gdu_res->u.z3950->u.searchResponse;
271 && sr_res->numberOfRecordsReturned
272 && *(sr_res->numberOfRecordsReturned) > 0
274 && sr_res->records->which == Z_Records_DBOSD)
276 records = sr_res->records->u.databaseOrSurDiagnostics;
282 for (i = 0; i < records->num_records; i++)
284 Z_NamePlusRecord **npr = &records->records[i];
285 if ((*npr)->which == Z_NamePlusRecord_databaseRecord)
287 const char *details = 0;
288 Z_External *r = (*npr)->u.databaseRecord;
290 if (r->which == Z_External_octet &&
291 !oid_oidcmp(r->direct_reference, yaz_oid_recsyn_xml))
294 if (convert_one_record(
295 r->u.octet_aligned->buf, r->u.octet_aligned->len,
298 (*npr)->u.databaseRecord =
299 z_ext_record_oid(odr_en, yaz_oid_recsyn_xml,
305 *npr = zget_surrogateDiagRec(
306 odr_en, (*npr)->databaseName,
307 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
313 package.response() = gdu_res;
317 void yf::XQuery::configure(const xmlNode * ptr, bool test_only,
320 for (ptr = ptr->children; ptr; ptr = ptr->next)
322 if (ptr->type != XML_ELEMENT_NODE)
324 if (!strcmp((const char *) ptr->name, "elementset"))
326 struct _xmlAttr *attr;
327 for (attr = ptr->properties; attr; attr = attr->next)
328 if (!strcmp((const char *) attr->name, "name"))
329 elementset_input = mp::xml::get_text(attr->children);
330 else if (!strcmp((const char *) attr->name, "backend"))
331 elementset_output = mp::xml::get_text(attr->children);
333 throw mp::filter::FilterException(
334 "Bad attribute " + std::string((const char *)
337 else if (!strcmp((const char *) ptr->name, "variable"))
341 struct _xmlAttr *attr;
342 for (attr = ptr->properties; attr; attr = attr->next)
343 if (!strcmp((const char *) attr->name, "name"))
344 name = mp::xml::get_text(attr->children);
345 else if (!strcmp((const char *) attr->name, "value"))
346 value = mp::xml::get_text(attr->children);
348 throw mp::filter::FilterException(
349 "Bad attribute " + std::string((const char *)
351 if (name.length() > 0)
352 zorba_variables[name] = value;
354 else if (!strcmp((const char *) ptr->name, "script"))
357 struct _xmlAttr *attr;
358 for (attr = ptr->properties; attr; attr = attr->next)
359 if (!strcmp((const char *) attr->name, "name"))
360 name = mp::xml::get_text(attr->children);
362 throw mp::filter::FilterException(
363 "Bad attribute " + std::string((const char *)
367 else if (!strcmp((const char *) ptr->name, "record"))
370 struct _xmlAttr *attr;
371 for (attr = ptr->properties; attr; attr = attr->next)
372 if (!strcmp((const char *) attr->name, "name"))
373 name = mp::xml::get_text(attr->children);
375 throw mp::filter::FilterException(
376 "Bad attribute " + std::string((const char *)
378 zorba_record_variable = name;
382 throw mp::filter::FilterException("Bad element "
383 + std::string((const char *)
387 if (zorba_script.length() == 0)
388 throw mp::filter::FilterException("Missing element script");
389 if (zorba_record_variable.length() == 0)
390 throw mp::filter::FilterException("Missing element record");
393 void* lStore = StoreManager::getStore();
394 lZorba = Zorba::getInstance(lStore);
396 lQuery = lZorba->createQuery();
399 size_t t = zorba_script.find_last_of('/');
400 if (t != std::string::npos)
401 lQuery->setFileName(zorba_script.substr(0, t + 1));
402 std::unique_ptr<std::istream> qfile(
403 new std::ifstream(zorba_script.c_str()));
404 Zorba_CompilerHints lHints;
405 lQuery->compile(*qfile, lHints);
406 } catch ( ZorbaException &e) {
407 std::string msg = "XQuery compile: ";
409 throw mp::filter::FilterException(msg);
414 static yf::Base* filter_creator()
416 return new mp::filter::XQuery;
420 struct metaproxy_1_filter_struct metaproxy_1_filter_xquery = {
431 * c-file-style: "Stroustrup"
432 * indent-tabs-mode: nil
434 * vim: shiftwidth=4 tabstop=8 expandtab