1 /* This file is part of Metaproxy.
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>
23 #include <yaz/diagbib1.h>
24 #include <yaz/match_glob.h>
25 #include <yaz/querytowrbuf.h>
26 #include <boost/scoped_ptr.hpp>
27 #include <boost/thread/mutex.hpp>
28 #include <boost/thread/condition.hpp>
29 #include <boost/algorithm/string.hpp>
34 namespace mp = metaproxy_1;
35 namespace yf = mp::filter;
37 namespace metaproxy_1 {
39 class SPARQL : public Base {
46 typedef boost::shared_ptr<Session> SessionPtr;
47 typedef boost::shared_ptr<Conf> ConfPtr;
49 typedef boost::shared_ptr<FrontendSet> FrontendSetPtr;
50 typedef std::map<std::string,FrontendSetPtr> FrontendSets;
54 void process(metaproxy_1::Package & package) const;
55 void configure(const xmlNode * ptr, bool test_only,
57 SessionPtr get_session(Package &package, Z_APDU **apdu) const;
58 void release_session(Package &package) const;
59 boost::scoped_ptr<Rep> m_p;
60 std::list<ConfPtr> db_conf;
72 boost::condition m_cond_session_ready;
74 std::map<mp::Session,SessionPtr> m_clients;
76 class SPARQL::Result {
81 friend class FrontendSet;
86 class SPARQL::FrontendSet {
91 std::list<Result> results;
92 std::vector<ConfPtr> explaindblist;
94 class SPARQL::Session {
96 Session(const SPARQL *);
98 void handle_z(Package &package, Z_APDU *apdu);
99 Z_APDU *search(mp::Package &package,
102 const char *sparql_query,
104 FrontendSetPtr fset);
105 Z_APDU *explain_search(mp::Package &package,
108 const char *sparql_query,
109 FrontendSetPtr fset);
110 int invoke_sparql(mp::Package &package,
111 const char *sparql_query,
117 ODR odr, Odr_oid *preferredRecordSyntax,
118 Z_ElementSetNames *esn,
119 int start, int number, int &error_code, std::string &addinfo,
120 int *number_returned, int *next_position);
121 Z_Records *explain_fetch(
124 ODR odr, Odr_oid *preferredRecordSyntax,
125 Z_ElementSetNames *esn,
126 int start, int number, int &error_code, std::string &addinfo,
127 int *number_returned, int *next_position);
130 bool m_support_named_result_sets;
131 FrontendSets m_frontend_sets;
132 const SPARQL *m_sparql;
137 yf::SPARQL::Result::~Result()
143 yf::SPARQL::Result::Result()
148 yf::SPARQL::SPARQL() : m_p(new Rep)
152 yf::SPARQL::~SPARQL()
156 void yf::SPARQL::configure(const xmlNode *xmlnode, bool test_only,
159 const xmlNode *ptr = xmlnode->children;
162 for (; ptr; ptr = ptr->next)
164 if (ptr->type != XML_ELEMENT_NODE)
166 if (!strcmp((const char *) ptr->name, "defaults"))
168 const struct _xmlAttr *attr;
169 for (attr = ptr->properties; attr; attr = attr->next)
171 if (!strcmp((const char *) attr->name, "uri"))
172 uri = mp::xml::get_text(attr->children);
174 throw mp::filter::FilterException(
175 "Bad attribute " + std::string((const char *)
179 else if (!strcmp((const char *) ptr->name, "db"))
181 yaz_sparql_t s = yaz_sparql_create();
182 ConfPtr conf(new Conf);
186 const struct _xmlAttr *attr;
187 for (attr = ptr->properties; attr; attr = attr->next)
189 if (!strcmp((const char *) attr->name, "path"))
190 conf->db = mp::xml::get_text(attr->children);
191 else if (!strcmp((const char *) attr->name, "uri"))
192 conf->uri = mp::xml::get_text(attr->children);
193 else if (!strcmp((const char *) attr->name, "schema"))
194 conf->schema = mp::xml::get_text(attr->children);
195 else if (!strcmp((const char *) attr->name, "include"))
197 std::vector<std::string> dbs;
198 std::string db = mp::xml::get_text(attr->children);
199 boost::split(dbs, db, boost::is_any_of(" \t"));
201 for (i = 0; i < dbs.size(); i++)
203 if (dbs[i].length() == 0)
205 std::list<ConfPtr>::const_iterator it = db_conf.begin();
207 if (it == db_conf.end())
209 throw mp::filter::FilterException(
210 "include db not found: " + dbs[i]);
212 else if (dbs[i].compare((*it)->db) == 0)
214 yaz_sparql_include(s, (*it)->s);
222 throw mp::filter::FilterException(
223 "Bad attribute " + std::string((const char *)
226 xmlNode *p = ptr->children;
227 for (; p; p = p->next)
229 if (p->type != XML_ELEMENT_NODE)
231 std::string name = (const char *) p->name;
232 const struct _xmlAttr *attr;
233 for (attr = p->properties; attr; attr = attr->next)
235 if (!strcmp((const char *) attr->name, "type"))
238 name.append(mp::xml::get_text(attr->children));
241 throw mp::filter::FilterException(
242 "Bad attribute " + std::string((const char *)
245 std::string value = mp::xml::get_text(p);
246 if (yaz_sparql_add_pattern(s, name.c_str(), value.c_str()))
248 throw mp::filter::FilterException(
249 "Bad SPARQL config " + name);
252 if (!conf->uri.length())
254 throw mp::filter::FilterException("Missing uri");
256 if (!conf->db.length())
258 throw mp::filter::FilterException("Missing path");
260 db_conf.push_back(conf);
264 throw mp::filter::FilterException
266 + std::string((const char *) ptr->name)
267 + " in sparql filter");
272 yf::SPARQL::Conf::~Conf()
274 yaz_sparql_destroy(s);
277 yf::SPARQL::Session::Session(const SPARQL *sparql) :
279 m_support_named_result_sets(false),
284 yf::SPARQL::Session::~Session()
288 yf::SPARQL::SessionPtr yf::SPARQL::get_session(Package & package,
293 Z_GDU *gdu = package.request().get();
295 boost::mutex::scoped_lock lock(m_p->m_mutex);
297 std::map<mp::Session,SPARQL::SessionPtr>::iterator it;
299 if (gdu && gdu->which == Z_GDU_Z3950)
300 *apdu = gdu->u.z3950;
306 it = m_p->m_clients.find(package.session());
307 if (it == m_p->m_clients.end())
309 if (!it->second->m_in_use)
311 it->second->m_in_use = true;
314 m_p->m_cond_session_ready.wait(lock);
319 // new Z39.50 session ..
320 SessionPtr p(new Session(this));
321 m_p->m_clients[package.session()] = p;
325 void yf::SPARQL::release_session(Package &package) const
327 boost::mutex::scoped_lock lock(m_p->m_mutex);
328 std::map<mp::Session,SessionPtr>::iterator it;
330 it = m_p->m_clients.find(package.session());
331 if (it != m_p->m_clients.end())
333 it->second->m_in_use = false;
335 if (package.session().is_closed())
336 m_p->m_clients.erase(it);
337 m_p->m_cond_session_ready.notify_all();
341 static bool get_result(xmlDoc *doc, Odr_int *sz, Odr_int pos, xmlDoc **ndoc)
343 xmlNode *ptr = xmlDocGetRootElement(doc);
348 *ndoc = xmlNewDoc(BAD_CAST "1.0");
350 if (ptr->type == XML_ELEMENT_NODE &&
351 !strcmp((const char *) ptr->name, "RDF"))
355 q0 = xmlCopyNode(ptr, 2);
356 xmlDocSetRootElement(*ndoc, q0);
360 while (ptr && ptr->type != XML_ELEMENT_NODE)
362 if (ptr && ptr->type == XML_ELEMENT_NODE &&
363 !strcmp((const char *) ptr->name, "Description"))
365 xmlNode *p = ptr->children;
367 while (p && p->type != XML_ELEMENT_NODE)
369 if (p && p->type == XML_ELEMENT_NODE &&
370 !strcmp((const char *) p->name, "type"))
371 { /* SELECT RESULT */
372 for (ptr = ptr->children; ptr; ptr = ptr->next)
373 if (ptr->type == XML_ELEMENT_NODE &&
374 !strcmp((const char *) ptr->name, "solution"))
380 xmlNode *q1 = xmlCopyNode(ptr, 1);
388 { /* CONSTRUCT result */
389 for (; ptr; ptr = ptr->next)
390 if (ptr->type == XML_ELEMENT_NODE &&
391 !strcmp((const char *) ptr->name, "Description"))
397 xmlNode *q1 = xmlCopyNode(ptr, 1);
408 for (; ptr; ptr = ptr->next)
409 if (ptr->type == XML_ELEMENT_NODE &&
410 !strcmp((const char *) ptr->name, "sparql"))
416 q0 = xmlCopyNode(ptr, 2);
417 xmlDocSetRootElement(*ndoc, q0);
419 for (ptr = ptr->children; ptr; ptr = ptr->next)
420 if (ptr->type == XML_ELEMENT_NODE &&
421 !strcmp((const char *) ptr->name, "results"))
429 q1 = xmlCopyNode(ptr, 0);
432 for (ptr = ptr->children; ptr; ptr = ptr->next)
433 if (ptr->type == XML_ELEMENT_NODE &&
434 !strcmp((const char *) ptr->name, "result"))
440 xmlNode *q2 = xmlCopyNode(ptr, 1);
453 Z_Records *yf::SPARQL::Session::fetch(
456 ODR odr, Odr_oid *preferredRecordSyntax,
457 Z_ElementSetNames *esn,
458 int start, int number, int &error_code, std::string &addinfo,
459 int *number_returned, int *next_position)
461 Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
462 std::list<Result>::iterator it = fset->results.begin();
463 const char *schema = 0;
464 bool uri_lookup = false;
465 bool fetch_logged = false;
466 if (esn && esn->which == Z_ElementSetNames_generic)
467 schema = esn->u.generic;
469 for (; it != fset->results.end(); it++)
471 if (yaz_sparql_lookup_schema(it->conf->s, schema))
476 if (!schema || !strcmp(esn->u.generic, it->conf->schema.c_str()))
479 if (it == fset->results.end())
481 rec->which = Z_Records_NSD;
482 rec->u.nonSurrogateDiagnostic =
483 zget_DefaultDiagFormat(
485 YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_,
489 rec->which = Z_Records_DBOSD;
490 rec->u.databaseOrSurDiagnostics = (Z_NamePlusRecordList *)
491 odr_malloc(odr, sizeof(Z_NamePlusRecordList));
492 rec->u.databaseOrSurDiagnostics->records = (Z_NamePlusRecord **)
493 odr_malloc(odr, sizeof(Z_NamePlusRecord *) * number);
495 for (i = 0; i < number; i++)
497 rec->u.databaseOrSurDiagnostics->records[i] = (Z_NamePlusRecord *)
498 odr_malloc(odr, sizeof(Z_NamePlusRecord));
499 Z_NamePlusRecord *npr = rec->u.databaseOrSurDiagnostics->records[i];
500 npr->databaseName = odr_strdup(odr, fset->db.c_str());
501 npr->which = Z_NamePlusRecord_databaseRecord;
504 if (!get_result(it->doc, 0, start - 1 + i, &ndoc))
510 xmlNode *ndoc_root = xmlDocGetRootElement(ndoc);
519 xmlNode *n = ndoc_root;
522 if (n->type == XML_ELEMENT_NODE)
524 if (!strcmp((const char *) n->name, "uri") ||
525 !strcmp((const char *) n->name, "bnode") )
527 uri = mp::xml::get_text(n->children);
537 rec->which = Z_Records_NSD;
538 rec->u.nonSurrogateDiagnostic =
539 zget_DefaultDiagFormat(
541 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, 0);
547 mp::wrbuf addinfo, query, w;
548 int error = yaz_sparql_from_uri_wrbuf(it->conf->s,
550 uri.c_str(), schema);
554 { // Log the fetch query only once
555 package.log("sparql", YLOG_LOG,
556 "fetch query: for %s \n%s",
557 uri.c_str(), query.c_str() );
562 package.log("sparql", YLOG_LOG,
563 "fetch uri:%s", uri.c_str() );
565 error = invoke_sparql(package, query.c_str(),
570 rec->which = Z_Records_NSD;
571 rec->u.nonSurrogateDiagnostic =
572 zget_DefaultDiagFormat(
575 addinfo.len() ? addinfo.c_str() : 0);
579 npr->u.databaseRecord =
580 z_ext_record_xml(odr, w.c_str(), w.len());
585 xmlBufferPtr buf = xmlBufferCreate();
586 xmlNodeDump(buf, ndoc, ndoc_root, 0, 0);
587 yaz_log(YLOG_LOG, "record %s %.*s", uri_lookup ? "uri" : "normal",
588 (int) buf->use, (const char *) buf->content);
589 npr->u.databaseRecord =
590 z_ext_record_xml(odr, (const char *) buf->content, buf->use);
595 rec->u.databaseOrSurDiagnostics->num_records = i;
596 *number_returned = i;
597 if (start + number > fset->hits)
600 *next_position = start + number;
604 int yf::SPARQL::Session::invoke_sparql(mp::Package &package,
605 const char *sparql_query,
609 Package http_package(package.session(), package.origin());
612 http_package.copy_filter(package);
613 Z_GDU *gdu = z_get_HTTP_Request_uri(odr, conf->uri.c_str(), 0, 1);
615 z_HTTP_header_add(odr, &gdu->u.HTTP_Request->headers,
616 "Content-Type", "application/x-www-form-urlencoded");
617 z_HTTP_header_add(odr, &gdu->u.HTTP_Request->headers,
618 "Accept", "application/sparql-results+xml,"
619 "application/rdf+xml");
620 const char *names[2];
623 const char *values[1];
624 values[0] = sparql_query;
626 yaz_array_to_uri(&path, odr, (char **) names, (char **) values);
628 gdu->u.HTTP_Request->content_buf = path;
629 gdu->u.HTTP_Request->content_len = strlen(path);
631 yaz_log(YLOG_DEBUG, "sparql: HTTP request\n%s", sparql_query);
633 http_package.request() = gdu;
636 Z_GDU *gdu_resp = http_package.response().get();
638 if (!gdu_resp || gdu_resp->which != Z_GDU_HTTP_Response)
640 wrbuf_puts(w, "no HTTP response from backend");
641 return YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
643 else if (gdu_resp->u.HTTP_Response->code != 200)
645 Z_HTTP_Response *resp = gdu_resp->u.HTTP_Response;
646 wrbuf_printf(w, "sparql: HTTP error %d from backend",
648 package.log("sparql", YLOG_LOG,
649 "HTTP error %d from backend ",
651 package.log("sparql", YLOG_LOG,
652 "%.*s" , resp->content_len, resp->content_buf );
653 return YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
655 Z_HTTP_Response *resp = gdu_resp->u.HTTP_Response;
656 wrbuf_write(w, resp->content_buf, resp->content_len);
660 Z_Records *yf::SPARQL::Session::explain_fetch(
663 ODR odr, Odr_oid *preferredRecordSyntax,
664 Z_ElementSetNames *esn,
665 int start, int number, int &error_code, std::string &addinfo,
666 int *number_returned, int *next_position)
668 Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
669 rec->which = Z_Records_DBOSD;
670 rec->u.databaseOrSurDiagnostics = (Z_NamePlusRecordList *)
671 odr_malloc(odr, sizeof(Z_NamePlusRecordList));
672 rec->u.databaseOrSurDiagnostics->records = (Z_NamePlusRecord **)
673 odr_malloc(odr, sizeof(Z_NamePlusRecord *) * number);
675 for (i = 0; i < number; i++)
677 unsigned int idx = start + i - 1;
678 if ( idx >= fset->explaindblist.size() )
680 ConfPtr cp = fset->explaindblist[idx];
682 wrbuf_puts(w,"<info>\n");
683 wrbuf_puts(w," <databaseInfo>\n");
684 wrbuf_puts(w," <title>");
685 wrbuf_xmlputs(w, cp->db.c_str());
686 wrbuf_puts(w,"</title>\n");
687 wrbuf_puts(w," </databaseInfo>\n");
688 yaz_sparql_explain_indexes( cp->s, w, 2);
689 wrbuf_puts(w,"</info>\n");
691 rec->u.databaseOrSurDiagnostics->records[i] = (Z_NamePlusRecord *)
692 odr_malloc(odr, sizeof(Z_NamePlusRecord));
693 Z_NamePlusRecord *npr = rec->u.databaseOrSurDiagnostics->records[i];
694 npr->databaseName = odr_strdup(odr, fset->db.c_str());
695 npr->which = Z_NamePlusRecord_databaseRecord;
696 npr->u.databaseRecord =
697 z_ext_record_xml(odr, w.buf(), w.len() );
699 rec->u.databaseOrSurDiagnostics->num_records = i;
700 *number_returned = i;
701 if (start + number > (int)fset->explaindblist.size())
704 *next_position = start + number;
710 Z_APDU *yf::SPARQL::Session::explain_search(mp::Package &package,
713 const char *explain_query,
716 Z_SearchRequest *req = apdu_req->u.searchRequest;
717 Z_APDU *apdu_res = 0;
720 package.log("sparql", YLOG_LOG, "Explain search '%s'", explain_query );
721 const char *term = explain_query + strlen(explain_query);
722 while ( term > explain_query && *term != ' ')
725 if ( ! isalpha( *term) )
726 term=""; // anything non-alpha is taken to mean all
727 // Empty string is seen here as two double quotes ""
728 // so it returns all bases as well
730 std::list<ConfPtr>::const_iterator it = m_sparql->db_conf.begin();
731 m_frontend_sets[req->resultSetName] = fset;
732 fset->explaindblist.clear();
733 fset->explaindblist.reserve(m_sparql->db_conf.size());
735 for (; it != m_sparql->db_conf.end(); it++)
736 if ( (*it)->schema.length() > 0 && // searchable db
737 (!*term || strcmp(term,(*it)->db.c_str())==0) )
738 { // and want all, or found the matching one
740 package.log("sparql", YLOG_LOG, "Explain %d: '%s'",
741 numbases, (*it)->db.c_str() );
742 fset->explaindblist.push_back(*it);
744 int number_returned = 0;
745 int next_position = 0;
746 Z_Records *records = 0;
751 const char *element_set_name = 0;
752 mp::util::piggyback_sr(req, numbases, number, &element_set_name);
755 Z_ElementSetNames *esn;
757 if (number > *req->smallSetUpperBound)
758 esn = req->mediumSetElementSetNames;
760 esn = req->smallSetElementSetNames;
761 records = explain_fetch(package, fset,
762 odr, req->preferredRecordSyntax, esn,
771 apdu_res = odr.create_searchResponse(
772 apdu_req, error_code, addinfo.c_str());
776 apdu_res = odr.create_searchResponse(apdu_req, 0, 0);
777 Z_SearchResponse *resp = apdu_res->u.searchResponse;
778 *resp->resultCount = numbases;
779 *resp->numberOfRecordsReturned = number_returned;
780 *resp->nextResultSetPosition = next_position;
781 resp->records = records;
788 Z_APDU *yf::SPARQL::Session::search(mp::Package &package,
791 const char *sparql_query,
792 ConfPtr conf, FrontendSetPtr fset)
794 Z_SearchRequest *req = apdu_req->u.searchRequest;
795 Z_APDU *apdu_res = 0;
798 package.log("sparql", YLOG_LOG,
799 "search query:\n%s", sparql_query );
801 int error = invoke_sparql(package, sparql_query, conf, w);
804 apdu_res = odr.create_searchResponse(apdu_req, error,
810 xmlDocPtr doc = xmlParseMemory(w.c_str(), w.len());
813 apdu_res = odr.create_searchResponse(
815 YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
816 "invalid XML from backendbackend");
821 Z_Records *records = 0;
822 int number_returned = 0;
823 int next_position = 0;
829 fset->results.push_back(result);
830 yaz_log(YLOG_DEBUG, "saving sparql result xmldoc=%p", doc);
832 get_result(result.doc, &fset->hits, -1, 0);
833 m_frontend_sets[req->resultSetName] = fset;
838 const char *element_set_name = 0;
839 mp::util::piggyback_sr(req, fset->hits, number, &element_set_name);
842 Z_ElementSetNames *esn;
844 if (number > *req->smallSetUpperBound)
845 esn = req->mediumSetElementSetNames;
847 esn = req->smallSetElementSetNames;
848 records = fetch(package, fset,
849 odr, req->preferredRecordSyntax, esn,
858 odr.create_searchResponse(
859 apdu_req, error_code, addinfo.c_str());
864 odr.create_searchResponse(apdu_req, 0, 0);
865 Z_SearchResponse *resp = apdu_res->u.searchResponse;
866 *resp->resultCount = fset->hits;
867 *resp->numberOfRecordsReturned = number_returned;
868 *resp->nextResultSetPosition = next_position;
869 resp->records = records;
876 void yf::SPARQL::Session::handle_z(mp::Package &package, Z_APDU *apdu_req)
879 Z_APDU *apdu_res = 0;
880 if (apdu_req->which == Z_APDU_initRequest)
882 apdu_res = odr.create_initResponse(apdu_req, 0, 0);
883 Z_InitRequest *req = apdu_req->u.initRequest;
884 Z_InitResponse *resp = apdu_res->u.initResponse;
886 resp->implementationName = odr_strdup(odr, "sparql");
887 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
888 m_support_named_result_sets = true;
890 static const int masks[] = {
891 Z_Options_search, Z_Options_present,
892 Z_Options_namedResultSets, -1
894 for (i = 0; masks[i] != -1; i++)
895 if (ODR_MASK_GET(req->options, masks[i]))
896 ODR_MASK_SET(resp->options, masks[i]);
897 static const int versions[] = {
903 for (i = 0; versions[i] != -1; i++)
904 if (ODR_MASK_GET(req->protocolVersion, versions[i]))
905 ODR_MASK_SET(resp->protocolVersion, versions[i]);
908 *resp->preferredMessageSize = *req->preferredMessageSize;
909 *resp->maximumRecordSize = *req->maximumRecordSize;
911 else if (apdu_req->which == Z_APDU_close)
913 apdu_res = odr.create_close(apdu_req,
914 Z_Close_finished, 0);
915 package.session().close();
917 else if (apdu_req->which == Z_APDU_searchRequest)
919 Z_SearchRequest *req = apdu_req->u.searchRequest;
921 FrontendSets::iterator fset_it =
922 m_frontend_sets.find(req->resultSetName);
923 if (fset_it != m_frontend_sets.end())
925 // result set already exist
926 // if replace indicator is off: we return diagnostic if
927 // result set already exist.
928 if (*req->replaceIndicator == 0)
931 odr.create_searchResponse(
933 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
935 package.response() = apdu;
937 m_frontend_sets.erase(fset_it);
939 if (req->query->which != Z_Query_type_1)
941 apdu_res = odr.create_searchResponse(
942 apdu_req, YAZ_BIB1_QUERY_TYPE_UNSUPP, 0);
944 else if (req->num_databaseNames != 1)
946 apdu_res = odr.create_searchResponse(
948 YAZ_BIB1_ACCESS_TO_SPECIFIED_DATABASE_DENIED, 0);
952 std::string db = req->databaseNames[0];
953 std::list<ConfPtr>::const_iterator it;
954 FrontendSetPtr fset(new FrontendSet);
956 m_frontend_sets.erase(req->resultSetName);
960 it = m_sparql->db_conf.begin();
961 for (; it != m_sparql->db_conf.end(); it++)
962 if ((*it)->schema.length() > 0
963 && yaz_match_glob((*it)->db.c_str(), db.c_str()))
965 mp::wrbuf addinfo_wr;
968 yaz_sparql_from_rpn_wrbuf((*it)->s,
969 addinfo_wr, sparql_wr,
970 req->query->u.type_1);
973 apdu_res = odr.create_searchResponse(
975 addinfo_wr.len() ? addinfo_wr.c_str() : 0);
979 Z_APDU *apdu_1 = search(package, apdu_req, odr,
980 sparql_wr.c_str(), *it,
988 apdu_res = odr.create_searchResponse(
989 apdu_req, YAZ_BIB1_DATABASE_DOES_NOT_EXIST, db.c_str());
993 { // The magic "explain" base
994 yaz_log(YLOG_LOG,"About to call explain_search");
996 yaz_query_to_wrbuf(qry, req->query);
997 apdu_res = explain_search( package, apdu_req, odr,
999 // TODO - Extract at least a term from the query, and
1000 // do some filtering by that
1001 yaz_log(YLOG_LOG,"Returned from explain_search");
1005 else if (apdu_req->which == Z_APDU_presentRequest)
1007 Z_PresentRequest *req = apdu_req->u.presentRequest;
1008 FrontendSets::iterator fset_it =
1009 m_frontend_sets.find(req->resultSetId);
1010 if (fset_it == m_frontend_sets.end())
1013 odr.create_presentResponse(
1014 apdu_req, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1016 package.response() = apdu_res;
1019 int number_returned = 0;
1020 int next_position = 0;
1022 std::string addinfo;
1023 Z_ElementSetNames *esn = 0;
1024 if (req->recordComposition)
1026 if (req->recordComposition->which == Z_RecordComp_simple)
1027 esn = req->recordComposition->u.simple;
1031 odr.create_presentResponse(
1033 YAZ_BIB1_ONLY_A_SINGLE_ELEMENT_SET_NAME_SUPPORTED,
1035 package.response() = apdu_res;
1040 if ( fset_it->second->explaindblist.size() > 0 )
1041 records = explain_fetch(
1044 odr, req->preferredRecordSyntax, esn,
1045 *req->resultSetStartPoint, *req->numberOfRecordsRequested,
1046 error_code, addinfo,
1053 odr, req->preferredRecordSyntax, esn,
1054 *req->resultSetStartPoint, *req->numberOfRecordsRequested,
1055 error_code, addinfo,
1061 odr.create_presentResponse(apdu_req, error_code,
1067 odr.create_presentResponse(apdu_req, 0, 0);
1068 Z_PresentResponse *resp = apdu_res->u.presentResponse;
1069 resp->records = records;
1070 *resp->numberOfRecordsReturned = number_returned;
1071 *resp->nextResultSetPosition = next_position;
1076 apdu_res = odr.create_close(apdu_req,
1077 Z_Close_protocolError,
1078 "sparql: unhandled APDU");
1079 package.session().close();
1083 package.response() = apdu_res;
1086 void yf::SPARQL::process(mp::Package &package) const
1089 SessionPtr p = get_session(package, &apdu);
1092 p->handle_z(package, apdu);
1096 release_session(package);
1099 static mp::filter::Base* filter_creator()
1101 return new mp::filter::SPARQL;
1105 struct metaproxy_1_filter_struct metaproxy_1_filter_sparql = {
1116 * c-file-style: "Stroustrup"
1117 * indent-tabs-mode: nil
1119 * vim: shiftwidth=4 tabstop=8 expandtab