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 <boost/scoped_ptr.hpp>
26 #include <boost/thread/mutex.hpp>
27 #include <boost/thread/condition.hpp>
28 #include <boost/algorithm/string.hpp>
33 namespace mp = metaproxy_1;
34 namespace yf = mp::filter;
36 namespace metaproxy_1 {
38 class SPARQL : public Base {
45 typedef boost::shared_ptr<Session> SessionPtr;
46 typedef boost::shared_ptr<Conf> ConfPtr;
48 typedef boost::shared_ptr<FrontendSet> FrontendSetPtr;
49 typedef std::map<std::string,FrontendSetPtr> FrontendSets;
53 void process(metaproxy_1::Package & package) const;
54 void configure(const xmlNode * ptr, bool test_only,
56 SessionPtr get_session(Package &package, Z_APDU **apdu) const;
57 void release_session(Package &package) const;
58 boost::scoped_ptr<Rep> m_p;
59 std::list<ConfPtr> db_conf;
71 boost::condition m_cond_session_ready;
73 std::map<mp::Session,SessionPtr> m_clients;
75 class SPARQL::Result {
80 friend class FrontendSet;
85 class SPARQL::FrontendSet {
90 std::list<Result> results;
91 std::vector<ConfPtr> explaindblist;
93 class SPARQL::Session {
95 Session(const SPARQL *);
97 void handle_z(Package &package, Z_APDU *apdu);
98 Z_APDU *search(mp::Package &package,
101 const char *sparql_query,
103 FrontendSetPtr fset);
104 Z_APDU *explain_search(mp::Package &package,
107 const char *sparql_query,
108 FrontendSetPtr fset);
109 int invoke_sparql(mp::Package &package,
110 const char *sparql_query,
116 ODR odr, Odr_oid *preferredRecordSyntax,
117 Z_ElementSetNames *esn,
118 int start, int number, int &error_code, std::string &addinfo,
119 int *number_returned, int *next_position);
120 Z_Records *explain_fetch(
123 ODR odr, Odr_oid *preferredRecordSyntax,
124 Z_ElementSetNames *esn,
125 int start, int number, int &error_code, std::string &addinfo,
126 int *number_returned, int *next_position);
129 bool m_support_named_result_sets;
130 FrontendSets m_frontend_sets;
131 const SPARQL *m_sparql;
136 yf::SPARQL::Result::~Result()
142 yf::SPARQL::Result::Result()
147 yf::SPARQL::SPARQL() : m_p(new Rep)
151 yf::SPARQL::~SPARQL()
155 void yf::SPARQL::configure(const xmlNode *xmlnode, bool test_only,
158 const xmlNode *ptr = xmlnode->children;
161 for (; ptr; ptr = ptr->next)
163 if (ptr->type != XML_ELEMENT_NODE)
165 if (!strcmp((const char *) ptr->name, "defaults"))
167 const struct _xmlAttr *attr;
168 for (attr = ptr->properties; attr; attr = attr->next)
170 if (!strcmp((const char *) attr->name, "uri"))
171 uri = mp::xml::get_text(attr->children);
173 throw mp::filter::FilterException(
174 "Bad attribute " + std::string((const char *)
178 else if (!strcmp((const char *) ptr->name, "db"))
180 yaz_sparql_t s = yaz_sparql_create();
181 ConfPtr conf(new Conf);
185 const struct _xmlAttr *attr;
186 for (attr = ptr->properties; attr; attr = attr->next)
188 if (!strcmp((const char *) attr->name, "path"))
189 conf->db = mp::xml::get_text(attr->children);
190 else if (!strcmp((const char *) attr->name, "uri"))
191 conf->uri = mp::xml::get_text(attr->children);
192 else if (!strcmp((const char *) attr->name, "schema"))
193 conf->schema = mp::xml::get_text(attr->children);
194 else if (!strcmp((const char *) attr->name, "include"))
196 std::vector<std::string> dbs;
197 std::string db = mp::xml::get_text(attr->children);
198 boost::split(dbs, db, boost::is_any_of(" \t"));
200 for (i = 0; i < dbs.size(); i++)
202 if (dbs[i].length() == 0)
204 std::list<ConfPtr>::const_iterator it = db_conf.begin();
206 if (it == db_conf.end())
208 throw mp::filter::FilterException(
209 "include db not found: " + dbs[i]);
211 else if (dbs[i].compare((*it)->db) == 0)
213 yaz_sparql_include(s, (*it)->s);
221 throw mp::filter::FilterException(
222 "Bad attribute " + std::string((const char *)
225 xmlNode *p = ptr->children;
226 for (; p; p = p->next)
228 if (p->type != XML_ELEMENT_NODE)
230 std::string name = (const char *) p->name;
231 const struct _xmlAttr *attr;
232 for (attr = p->properties; attr; attr = attr->next)
234 if (!strcmp((const char *) attr->name, "type"))
237 name.append(mp::xml::get_text(attr->children));
240 throw mp::filter::FilterException(
241 "Bad attribute " + std::string((const char *)
244 std::string value = mp::xml::get_text(p);
245 if (yaz_sparql_add_pattern(s, name.c_str(), value.c_str()))
247 throw mp::filter::FilterException(
248 "Bad SPARQL config " + name);
251 if (!conf->uri.length())
253 throw mp::filter::FilterException("Missing uri");
255 if (!conf->db.length())
257 throw mp::filter::FilterException("Missing path");
259 db_conf.push_back(conf);
263 throw mp::filter::FilterException
265 + std::string((const char *) ptr->name)
266 + " in sparql filter");
271 yf::SPARQL::Conf::~Conf()
273 yaz_sparql_destroy(s);
276 yf::SPARQL::Session::Session(const SPARQL *sparql) :
278 m_support_named_result_sets(false),
283 yf::SPARQL::Session::~Session()
287 yf::SPARQL::SessionPtr yf::SPARQL::get_session(Package & package,
292 Z_GDU *gdu = package.request().get();
294 boost::mutex::scoped_lock lock(m_p->m_mutex);
296 std::map<mp::Session,SPARQL::SessionPtr>::iterator it;
298 if (gdu && gdu->which == Z_GDU_Z3950)
299 *apdu = gdu->u.z3950;
305 it = m_p->m_clients.find(package.session());
306 if (it == m_p->m_clients.end())
308 if (!it->second->m_in_use)
310 it->second->m_in_use = true;
313 m_p->m_cond_session_ready.wait(lock);
318 // new Z39.50 session ..
319 SessionPtr p(new Session(this));
320 m_p->m_clients[package.session()] = p;
324 void yf::SPARQL::release_session(Package &package) const
326 boost::mutex::scoped_lock lock(m_p->m_mutex);
327 std::map<mp::Session,SessionPtr>::iterator it;
329 it = m_p->m_clients.find(package.session());
330 if (it != m_p->m_clients.end())
332 it->second->m_in_use = false;
334 if (package.session().is_closed())
335 m_p->m_clients.erase(it);
336 m_p->m_cond_session_ready.notify_all();
340 static bool get_result(xmlDoc *doc, Odr_int *sz, Odr_int pos, xmlDoc **ndoc)
342 xmlNode *ptr = xmlDocGetRootElement(doc);
347 *ndoc = xmlNewDoc(BAD_CAST "1.0");
349 if (ptr->type == XML_ELEMENT_NODE &&
350 !strcmp((const char *) ptr->name, "RDF"))
354 q0 = xmlCopyNode(ptr, 2);
355 xmlDocSetRootElement(*ndoc, q0);
359 while (ptr && ptr->type != XML_ELEMENT_NODE)
361 if (ptr && ptr->type == XML_ELEMENT_NODE &&
362 !strcmp((const char *) ptr->name, "Description"))
364 xmlNode *p = ptr->children;
366 while (p && p->type != XML_ELEMENT_NODE)
368 if (p && p->type == XML_ELEMENT_NODE &&
369 !strcmp((const char *) p->name, "type"))
370 { /* SELECT RESULT */
371 for (ptr = ptr->children; ptr; ptr = ptr->next)
372 if (ptr->type == XML_ELEMENT_NODE &&
373 !strcmp((const char *) ptr->name, "solution"))
379 xmlNode *q1 = xmlCopyNode(ptr, 1);
387 { /* CONSTRUCT result */
388 for (; ptr; ptr = ptr->next)
389 if (ptr->type == XML_ELEMENT_NODE &&
390 !strcmp((const char *) ptr->name, "Description"))
396 xmlNode *q1 = xmlCopyNode(ptr, 1);
407 for (; ptr; ptr = ptr->next)
408 if (ptr->type == XML_ELEMENT_NODE &&
409 !strcmp((const char *) ptr->name, "sparql"))
415 q0 = xmlCopyNode(ptr, 2);
416 xmlDocSetRootElement(*ndoc, q0);
418 for (ptr = ptr->children; ptr; ptr = ptr->next)
419 if (ptr->type == XML_ELEMENT_NODE &&
420 !strcmp((const char *) ptr->name, "results"))
428 q1 = xmlCopyNode(ptr, 0);
431 for (ptr = ptr->children; ptr; ptr = ptr->next)
432 if (ptr->type == XML_ELEMENT_NODE &&
433 !strcmp((const char *) ptr->name, "result"))
439 xmlNode *q2 = xmlCopyNode(ptr, 1);
452 Z_Records *yf::SPARQL::Session::fetch(
455 ODR odr, Odr_oid *preferredRecordSyntax,
456 Z_ElementSetNames *esn,
457 int start, int number, int &error_code, std::string &addinfo,
458 int *number_returned, int *next_position)
460 Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
461 std::list<Result>::iterator it = fset->results.begin();
462 const char *schema = 0;
463 bool uri_lookup = false;
464 bool fetch_logged = false;
465 if (esn && esn->which == Z_ElementSetNames_generic)
466 schema = esn->u.generic;
468 for (; it != fset->results.end(); it++)
470 if (yaz_sparql_lookup_schema(it->conf->s, schema))
475 if (!schema || !strcmp(esn->u.generic, it->conf->schema.c_str()))
478 if (it == fset->results.end())
480 rec->which = Z_Records_NSD;
481 rec->u.nonSurrogateDiagnostic =
482 zget_DefaultDiagFormat(
484 YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_,
488 rec->which = Z_Records_DBOSD;
489 rec->u.databaseOrSurDiagnostics = (Z_NamePlusRecordList *)
490 odr_malloc(odr, sizeof(Z_NamePlusRecordList));
491 rec->u.databaseOrSurDiagnostics->records = (Z_NamePlusRecord **)
492 odr_malloc(odr, sizeof(Z_NamePlusRecord *) * number);
494 for (i = 0; i < number; i++)
496 rec->u.databaseOrSurDiagnostics->records[i] = (Z_NamePlusRecord *)
497 odr_malloc(odr, sizeof(Z_NamePlusRecord));
498 Z_NamePlusRecord *npr = rec->u.databaseOrSurDiagnostics->records[i];
499 npr->databaseName = odr_strdup(odr, fset->db.c_str());
500 npr->which = Z_NamePlusRecord_databaseRecord;
503 if (!get_result(it->doc, 0, start - 1 + i, &ndoc))
509 xmlNode *ndoc_root = xmlDocGetRootElement(ndoc);
518 xmlNode *n = ndoc_root;
521 if (n->type == XML_ELEMENT_NODE)
523 if (!strcmp((const char *) n->name, "uri") ||
524 !strcmp((const char *) n->name, "bnode") )
526 uri = mp::xml::get_text(n->children);
536 rec->which = Z_Records_NSD;
537 rec->u.nonSurrogateDiagnostic =
538 zget_DefaultDiagFormat(
540 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, 0);
546 mp::wrbuf addinfo, query, w;
547 int error = yaz_sparql_from_uri_wrbuf(it->conf->s,
549 uri.c_str(), schema);
553 { // Log the fetch query only once
554 package.log("sparql", YLOG_LOG,
555 "fetch query: for %s \n%s",
556 uri.c_str(), query.c_str() );
561 package.log("sparql", YLOG_LOG,
562 "fetch uri:%s", uri.c_str() );
564 error = invoke_sparql(package, query.c_str(),
569 rec->which = Z_Records_NSD;
570 rec->u.nonSurrogateDiagnostic =
571 zget_DefaultDiagFormat(
574 addinfo.len() ? addinfo.c_str() : 0);
578 npr->u.databaseRecord =
579 z_ext_record_xml(odr, w.c_str(), w.len());
584 xmlBufferPtr buf = xmlBufferCreate();
585 xmlNodeDump(buf, ndoc, ndoc_root, 0, 0);
586 yaz_log(YLOG_LOG, "record %s %.*s", uri_lookup ? "uri" : "normal",
587 (int) buf->use, (const char *) buf->content);
588 npr->u.databaseRecord =
589 z_ext_record_xml(odr, (const char *) buf->content, buf->use);
594 rec->u.databaseOrSurDiagnostics->num_records = i;
595 *number_returned = i;
596 if (start + number > fset->hits)
599 *next_position = start + number;
603 int yf::SPARQL::Session::invoke_sparql(mp::Package &package,
604 const char *sparql_query,
608 Package http_package(package.session(), package.origin());
611 http_package.copy_filter(package);
612 Z_GDU *gdu = z_get_HTTP_Request_uri(odr, conf->uri.c_str(), 0, 1);
614 z_HTTP_header_add(odr, &gdu->u.HTTP_Request->headers,
615 "Content-Type", "application/x-www-form-urlencoded");
616 z_HTTP_header_add(odr, &gdu->u.HTTP_Request->headers,
617 "Accept", "application/sparql-results+xml,"
618 "application/rdf+xml");
619 const char *names[2];
622 const char *values[1];
623 values[0] = sparql_query;
625 yaz_array_to_uri(&path, odr, (char **) names, (char **) values);
627 gdu->u.HTTP_Request->content_buf = path;
628 gdu->u.HTTP_Request->content_len = strlen(path);
630 yaz_log(YLOG_DEBUG, "sparql: HTTP request\n%s", sparql_query);
632 http_package.request() = gdu;
635 Z_GDU *gdu_resp = http_package.response().get();
637 if (!gdu_resp || gdu_resp->which != Z_GDU_HTTP_Response)
639 wrbuf_puts(w, "no HTTP response from backend");
640 return YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
642 else if (gdu_resp->u.HTTP_Response->code != 200)
644 Z_HTTP_Response *resp = gdu_resp->u.HTTP_Response;
645 wrbuf_printf(w, "sparql: HTTP error %d from backend",
647 package.log("sparql", YLOG_LOG,
648 "HTTP error %d from backend ",
650 package.log("sparql", YLOG_LOG,
651 "%.*s" , resp->content_len, resp->content_buf );
652 return YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
654 Z_HTTP_Response *resp = gdu_resp->u.HTTP_Response;
655 wrbuf_write(w, resp->content_buf, resp->content_len);
659 Z_Records *yf::SPARQL::Session::explain_fetch(
662 ODR odr, Odr_oid *preferredRecordSyntax,
663 Z_ElementSetNames *esn,
664 int start, int number, int &error_code, std::string &addinfo,
665 int *number_returned, int *next_position)
667 Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
668 rec->which = Z_Records_DBOSD;
669 rec->u.databaseOrSurDiagnostics = (Z_NamePlusRecordList *)
670 odr_malloc(odr, sizeof(Z_NamePlusRecordList));
671 rec->u.databaseOrSurDiagnostics->records = (Z_NamePlusRecord **)
672 odr_malloc(odr, sizeof(Z_NamePlusRecord *) * number);
674 for (i = 0; i < number; i++)
676 int idx = start + i - 1;
677 ConfPtr cp = fset->explaindblist[ idx];
678 package.log("sparql", YLOG_LOG, "fetch explain %d:%s", idx, cp->db.c_str() );
680 wrbuf_puts(w,"<explain xmlns=\"http://explain.z3950.org/dtd/2.0/\">\n");
681 wrbuf_puts(w," <databaseInfo>\n");
682 wrbuf_puts(w," <title>");
683 wrbuf_xmlputs(w, cp->db.c_str());
684 wrbuf_puts(w,"</title>\n");
685 wrbuf_puts(w," </databaseInfo>\n");
686 yaz_sparql_explain_indexes( cp->s, w, 2);
687 wrbuf_puts(w,"</explain>\n");
689 rec->u.databaseOrSurDiagnostics->records[i] = (Z_NamePlusRecord *)
690 odr_malloc(odr, sizeof(Z_NamePlusRecord));
691 Z_NamePlusRecord *npr = rec->u.databaseOrSurDiagnostics->records[i];
692 npr->databaseName = odr_strdup(odr, fset->db.c_str());
693 npr->which = Z_NamePlusRecord_databaseRecord;
694 npr->u.databaseRecord =
695 z_ext_record_xml(odr, w.buf(), w.len() );
697 rec->u.databaseOrSurDiagnostics->num_records = i;
698 *number_returned = i;
699 if (start + number > fset->hits)
702 *next_position = start + number;
708 Z_APDU *yf::SPARQL::Session::explain_search(mp::Package &package,
711 const char *sparql_query,
714 Z_SearchRequest *req = apdu_req->u.searchRequest;
715 Z_APDU *apdu_res = 0;
718 package.log("sparql", YLOG_LOG, "Explain search" );
720 //std::list<std::string> dblist;
721 std::list<ConfPtr>::const_iterator it = m_sparql->db_conf.begin();
722 m_frontend_sets[req->resultSetName] = fset;
723 fset->explaindblist.clear();
724 fset->explaindblist.reserve(m_sparql->db_conf.size());
726 for (; it != m_sparql->db_conf.end(); it++)
727 if ((*it)->schema.length() > 0 ) // searchable db
730 package.log("sparql", YLOG_LOG, "Explain %d: '%s'",
731 numbases, (*it)->db.c_str() );
732 fset->explaindblist.push_back(*it);
734 //yf::SPARQL::Result res;
737 "<explain xmlns='http://explain.z3950.org/dtd/2.0/'>"
744 //res.doc = xmlParseMemory(z.c_str(), z.size());
748 int number_returned = 0;
749 int next_position = 0;
750 Z_Records *records = 0;
755 const char *element_set_name = 0;
756 mp::util::piggyback_sr(req, numbases, number, &element_set_name);
759 Z_ElementSetNames *esn;
761 if (number > *req->smallSetUpperBound)
762 esn = req->mediumSetElementSetNames;
764 esn = req->smallSetElementSetNames;
765 records = explain_fetch(package, fset,
766 odr, req->preferredRecordSyntax, esn,
775 apdu_res = odr.create_searchResponse(
776 apdu_req, error_code, addinfo.c_str());
780 apdu_res = odr.create_searchResponse(apdu_req, 0, 0);
781 Z_SearchResponse *resp = apdu_res->u.searchResponse;
782 *resp->resultCount = numbases;
783 *resp->numberOfRecordsReturned = number_returned;
784 *resp->nextResultSetPosition = next_position;
785 resp->records = records;
791 Z_APDU *yf::SPARQL::Session::search(mp::Package &package,
794 const char *sparql_query,
795 ConfPtr conf, FrontendSetPtr fset)
797 Z_SearchRequest *req = apdu_req->u.searchRequest;
798 Z_APDU *apdu_res = 0;
801 package.log("sparql", YLOG_LOG,
802 "search query:\n%s", sparql_query );
804 int error = invoke_sparql(package, sparql_query, conf, w);
807 apdu_res = odr.create_searchResponse(apdu_req, error,
813 xmlDocPtr doc = xmlParseMemory(w.c_str(), w.len());
816 apdu_res = odr.create_searchResponse(
818 YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
819 "invalid XML from backendbackend");
824 Z_Records *records = 0;
825 int number_returned = 0;
826 int next_position = 0;
832 fset->results.push_back(result);
833 yaz_log(YLOG_DEBUG, "saving sparql result xmldoc=%p", doc);
835 get_result(result.doc, &fset->hits, -1, 0);
836 m_frontend_sets[req->resultSetName] = fset;
841 const char *element_set_name = 0;
842 mp::util::piggyback_sr(req, fset->hits, number, &element_set_name);
845 Z_ElementSetNames *esn;
847 if (number > *req->smallSetUpperBound)
848 esn = req->mediumSetElementSetNames;
850 esn = req->smallSetElementSetNames;
851 records = fetch(package, fset,
852 odr, req->preferredRecordSyntax, esn,
861 odr.create_searchResponse(
862 apdu_req, error_code, addinfo.c_str());
867 odr.create_searchResponse(apdu_req, 0, 0);
868 Z_SearchResponse *resp = apdu_res->u.searchResponse;
869 *resp->resultCount = fset->hits;
870 *resp->numberOfRecordsReturned = number_returned;
871 *resp->nextResultSetPosition = next_position;
872 resp->records = records;
879 void yf::SPARQL::Session::handle_z(mp::Package &package, Z_APDU *apdu_req)
882 Z_APDU *apdu_res = 0;
883 if (apdu_req->which == Z_APDU_initRequest)
885 apdu_res = odr.create_initResponse(apdu_req, 0, 0);
886 Z_InitRequest *req = apdu_req->u.initRequest;
887 Z_InitResponse *resp = apdu_res->u.initResponse;
889 resp->implementationName = odr_strdup(odr, "sparql");
890 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
891 m_support_named_result_sets = true;
893 static const int masks[] = {
894 Z_Options_search, Z_Options_present,
895 Z_Options_namedResultSets, -1
897 for (i = 0; masks[i] != -1; i++)
898 if (ODR_MASK_GET(req->options, masks[i]))
899 ODR_MASK_SET(resp->options, masks[i]);
900 static const int versions[] = {
906 for (i = 0; versions[i] != -1; i++)
907 if (ODR_MASK_GET(req->protocolVersion, versions[i]))
908 ODR_MASK_SET(resp->protocolVersion, versions[i]);
911 *resp->preferredMessageSize = *req->preferredMessageSize;
912 *resp->maximumRecordSize = *req->maximumRecordSize;
914 else if (apdu_req->which == Z_APDU_close)
916 apdu_res = odr.create_close(apdu_req,
917 Z_Close_finished, 0);
918 package.session().close();
920 else if (apdu_req->which == Z_APDU_searchRequest)
922 Z_SearchRequest *req = apdu_req->u.searchRequest;
924 FrontendSets::iterator fset_it =
925 m_frontend_sets.find(req->resultSetName);
926 if (fset_it != m_frontend_sets.end())
928 // result set already exist
929 // if replace indicator is off: we return diagnostic if
930 // result set already exist.
931 if (*req->replaceIndicator == 0)
934 odr.create_searchResponse(
936 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
938 package.response() = apdu;
940 m_frontend_sets.erase(fset_it);
942 if (req->query->which != Z_Query_type_1)
944 apdu_res = odr.create_searchResponse(
945 apdu_req, YAZ_BIB1_QUERY_TYPE_UNSUPP, 0);
947 else if (req->num_databaseNames != 1)
949 apdu_res = odr.create_searchResponse(
951 YAZ_BIB1_ACCESS_TO_SPECIFIED_DATABASE_DENIED, 0);
955 std::string db = req->databaseNames[0];
956 std::list<ConfPtr>::const_iterator it;
957 FrontendSetPtr fset(new FrontendSet);
959 m_frontend_sets.erase(req->resultSetName);
961 if ( db != "explain" )
963 it = m_sparql->db_conf.begin();
964 for (; it != m_sparql->db_conf.end(); it++)
965 if ((*it)->schema.length() > 0
966 && yaz_match_glob((*it)->db.c_str(), db.c_str()))
968 mp::wrbuf addinfo_wr;
971 yaz_sparql_from_rpn_wrbuf((*it)->s,
972 addinfo_wr, sparql_wr,
973 req->query->u.type_1);
976 apdu_res = odr.create_searchResponse(
978 addinfo_wr.len() ? addinfo_wr.c_str() : 0);
982 Z_APDU *apdu_1 = search(package, apdu_req, odr,
983 sparql_wr.c_str(), *it,
991 apdu_res = odr.create_searchResponse(
992 apdu_req, YAZ_BIB1_DATABASE_DOES_NOT_EXIST, db.c_str());
996 { // The magic "explain" base
997 yaz_log(YLOG_LOG,"About to call explain_search");
998 const char *qry = "query";
999 apdu_res = explain_search( package, apdu_req, odr,
1001 // TODO - Extract at least a term from the query, and
1002 // do some filtering by that
1003 yaz_log(YLOG_LOG,"Returned from explain_search");
1007 else if (apdu_req->which == Z_APDU_presentRequest)
1009 Z_PresentRequest *req = apdu_req->u.presentRequest;
1010 FrontendSets::iterator fset_it =
1011 m_frontend_sets.find(req->resultSetId);
1012 if (fset_it == m_frontend_sets.end())
1015 odr.create_presentResponse(
1016 apdu_req, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1018 package.response() = apdu_res;
1021 int number_returned = 0;
1022 int next_position = 0;
1024 std::string addinfo;
1025 Z_ElementSetNames *esn = 0;
1026 if (req->recordComposition)
1028 if (req->recordComposition->which == Z_RecordComp_simple)
1029 esn = req->recordComposition->u.simple;
1033 odr.create_presentResponse(
1035 YAZ_BIB1_ONLY_A_SINGLE_ELEMENT_SET_NAME_SUPPORTED,
1037 package.response() = apdu_res;
1042 if ( fset_it->second->explaindblist.size() > 0 )
1043 records = explain_fetch(
1046 odr, req->preferredRecordSyntax, esn,
1047 *req->resultSetStartPoint, *req->numberOfRecordsRequested,
1048 error_code, addinfo,
1055 odr, req->preferredRecordSyntax, esn,
1056 *req->resultSetStartPoint, *req->numberOfRecordsRequested,
1057 error_code, addinfo,
1063 odr.create_presentResponse(apdu_req, error_code,
1069 odr.create_presentResponse(apdu_req, 0, 0);
1070 Z_PresentResponse *resp = apdu_res->u.presentResponse;
1071 resp->records = records;
1072 *resp->numberOfRecordsReturned = number_returned;
1073 *resp->nextResultSetPosition = next_position;
1078 apdu_res = odr.create_close(apdu_req,
1079 Z_Close_protocolError,
1080 "sparql: unhandled APDU");
1081 package.session().close();
1085 package.response() = apdu_res;
1088 void yf::SPARQL::process(mp::Package &package) const
1091 SessionPtr p = get_session(package, &apdu);
1094 p->handle_z(package, apdu);
1098 release_session(package);
1101 static mp::filter::Base* filter_creator()
1103 return new mp::filter::SPARQL;
1107 struct metaproxy_1_filter_struct metaproxy_1_filter_sparql = {
1118 * c-file-style: "Stroustrup"
1119 * indent-tabs-mode: nil
1121 * vim: shiftwidth=4 tabstop=8 expandtab