+ else if (srw_req->query_type == Z_SRW_query_type_pqf)
+ {
+ Z_RPNQuery *RPNquery;
+ YAZ_PQF_Parser pqf_parser;
+
+ pqf_parser = yaz_pqf_create();
+
+ RPNquery = yaz_pqf_parse(pqf_parser, assoc->decode,
+ srw_req->query.pqf);
+ if (!RPNquery)
+ {
+ const char *pqf_msg;
+ size_t off;
+ int code = yaz_pqf_error(pqf_parser, &pqf_msg, &off);
+ yaz_log(log_requestdetail, "Parse error %d %s near offset %ld",
+ code, pqf_msg, (long) off);
+ srw_error = YAZ_SRW_QUERY_SYNTAX_ERROR;
+ }
+
+ rr.query->which = Z_Query_type_1;
+ rr.query->u.type_1 = RPNquery;
+
+ yaz_pqf_destroy(pqf_parser);
+ }
+ else
+ {
+ yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
+ &srw_res->num_diagnostics,
+ YAZ_SRW_UNSUPP_QUERY_TYPE, 0);
+ }
+ if (rr.query->u.type_1)
+ {
+ rr.stream = assoc->encode;
+ rr.decode = assoc->decode;
+ rr.print = assoc->print;
+ if ( srw_req->sort.sortKeys )
+ rr.srw_sortKeys = odr_strdup(assoc->encode,
+ srw_req->sort.sortKeys );
+ rr.association = assoc;
+ rr.hits = 0;
+ rr.errcode = 0;
+ rr.errstring = 0;
+ rr.search_info = 0;
+ yaz_log_zquery_level(log_requestdetail,rr.query);
+
+ (assoc->init->bend_search)(assoc->backend, &rr);
+ if (rr.errcode)
+ {
+ if (rr.errcode == YAZ_BIB1_DATABASE_UNAVAILABLE)
+ {
+ *http_code = 404;
+ }
+ else
+ {
+ srw_error = yaz_diag_bib1_to_srw(rr.errcode);
+ yaz_add_srw_diagnostic(assoc->encode,
+ &srw_res->diagnostics,
+ &srw_res->num_diagnostics,
+ srw_error, rr.errstring);
+ }
+ }
+ else
+ {
+ int number = srw_req->maximumRecords ?
+ odr_int_to_int(*srw_req->maximumRecords) : 0;
+ int start = srw_req->startRecord ?
+ odr_int_to_int(*srw_req->startRecord) : 1;
+
+ yaz_log(log_requestdetail, "Request to pack %d+%d out of "
+ ODR_INT_PRINTF,
+ start, number, rr.hits);
+
+ srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
+ if (rr.srw_setname)
+ {
+ srw_res->resultSetId =
+ odr_strdup(assoc->encode, rr.srw_setname );
+ srw_res->resultSetIdleTime =
+ odr_intdup(assoc->encode, *rr.srw_setnameIdleTime );
+ }
+
+ if (start > rr.hits || start < 1)
+ {
+ /* if hits<=0 and start=1 we don't return a diagnostic */
+ if (start != 1)
+ yaz_add_srw_diagnostic(
+ assoc->encode,
+ &srw_res->diagnostics, &srw_res->num_diagnostics,
+ YAZ_SRW_FIRST_RECORD_POSITION_OUT_OF_RANGE, 0);
+ }
+ else if (number > 0)
+ {
+ int i;
+ int ok = 1;
+ if (start + number > rr.hits)
+ number = odr_int_to_int(rr.hits) - start + 1;
+
+ /* Call bend_present if defined */
+ if (assoc->init->bend_present)
+ {
+ bend_present_rr *bprr = (bend_present_rr*)
+ odr_malloc(assoc->decode, sizeof(*bprr));
+ bprr->setname = "default";
+ bprr->start = start;
+ bprr->number = number;
+ if (srw_req->recordSchema)
+ {
+ bprr->comp = (Z_RecordComposition *) odr_malloc(assoc->decode,
+ sizeof(*bprr->comp));
+ bprr->comp->which = Z_RecordComp_simple;
+ bprr->comp->u.simple = (Z_ElementSetNames *)
+ odr_malloc(assoc->decode, sizeof(Z_ElementSetNames));
+ bprr->comp->u.simple->which = Z_ElementSetNames_generic;
+ bprr->comp->u.simple->u.generic = srw_req->recordSchema;
+ }
+ else
+ {
+ bprr->comp = 0;
+ }
+ bprr->stream = assoc->encode;
+ bprr->referenceId = 0;
+ bprr->print = assoc->print;
+ bprr->association = assoc;
+ bprr->errcode = 0;
+ bprr->errstring = NULL;
+ (*assoc->init->bend_present)(assoc->backend, bprr);
+
+ if (bprr->errcode)
+ {
+ srw_error = yaz_diag_bib1_to_srw(bprr->errcode);
+ yaz_add_srw_diagnostic(assoc->encode,
+ &srw_res->diagnostics,
+ &srw_res->num_diagnostics,
+ srw_error, bprr->errstring);
+ ok = 0;
+ }
+ }
+
+ if (ok)
+ {
+ int j = 0;
+ int packing = Z_SRW_recordPacking_string;
+ if (srw_req->recordPacking)
+ {
+ packing =
+ yaz_srw_str_to_pack(srw_req->recordPacking);
+ if (packing == -1)
+ packing = Z_SRW_recordPacking_string;
+ }
+ srw_res->records = (Z_SRW_record *)
+ odr_malloc(assoc->encode,
+ number * sizeof(*srw_res->records));
+
+ srw_res->extra_records = (Z_SRW_extra_record **)
+ odr_malloc(assoc->encode,
+ number*sizeof(*srw_res->extra_records));
+
+ for (i = 0; i<number; i++)
+ {
+ int errcode;
+ const char *addinfo = 0;
+
+ srw_res->records[j].recordPacking = packing;
+ srw_res->records[j].recordData_buf = 0;
+ srw_res->extra_records[j] = 0;
+ yaz_log(YLOG_DEBUG, "srw_bend_fetch %d", i+start);
+ errcode = srw_bend_fetch(assoc, i+start, srw_req,
+ srw_res->records + j,
+ &addinfo);
+ if (errcode)
+ {
+ yaz_add_srw_diagnostic(assoc->encode,
+ &srw_res->diagnostics,
+ &srw_res->num_diagnostics,
+ yaz_diag_bib1_to_srw(errcode),
+ addinfo);
+
+ break;
+ }
+ if (srw_res->records[j].recordData_buf)
+ j++;
+ }
+ srw_res->num_records = j;
+ if (!j)
+ srw_res->records = 0;
+ }
+ }
+ if (rr.extra_response_data)
+ {
+ res->extraResponseData_buf = rr.extra_response_data;
+ res->extraResponseData_len = strlen(rr.extra_response_data);
+ }
+ if (rr.estimated_hit_count || rr.partial_resultset)
+ {
+ yaz_add_srw_diagnostic(
+ assoc->encode,
+ &srw_res->diagnostics,
+ &srw_res->num_diagnostics,
+ YAZ_SRW_RESULT_SET_CREATED_WITH_VALID_PARTIAL_RESULTS_AVAILABLE,
+ 0);
+ }
+ }
+ }
+ }
+ if (log_request)
+ {
+ const char *querystr = "?";
+ const char *querytype = "?";
+ WRBUF wr = wrbuf_alloc();
+
+ switch (srw_req->query_type)
+ {
+ case Z_SRW_query_type_cql:
+ querytype = "CQL";
+ querystr = srw_req->query.cql;
+ break;
+ case Z_SRW_query_type_pqf:
+ querytype = "PQF";
+ querystr = srw_req->query.pqf;
+ break;
+ }
+ wrbuf_printf(wr, "SRWSearch %s ", srw_req->database);
+ if (srw_res->num_diagnostics)
+ wrbuf_printf(wr, "ERROR %s", srw_res->diagnostics[0].uri);
+ else if (*http_code != 200)
+ wrbuf_printf(wr, "ERROR info:http/%d", *http_code);
+ else if (srw_res->numberOfRecords)
+ {
+ wrbuf_printf(wr, "OK " ODR_INT_PRINTF,
+ (srw_res->numberOfRecords ?
+ *srw_res->numberOfRecords : 0));
+ }
+ wrbuf_printf(wr, " %s " ODR_INT_PRINTF " +%d",
+ (srw_res->resultSetId ?
+ srw_res->resultSetId : "-"),
+ (srw_req->startRecord ? *srw_req->startRecord : 1),
+ srw_res->num_records);
+ yaz_log(log_request, "%s %s: %s", wrbuf_cstr(wr), querytype, querystr);
+ wrbuf_destroy(wr);
+ }
+}
+
+static char *srw_bend_explain_default(bend_explain_rr *rr)
+{
+#if YAZ_HAVE_XML2
+ xmlNodePtr ptr = (xmlNode *) rr->server_node_ptr;
+ if (!ptr)
+ return 0;
+ for (ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp((const char *) ptr->name, "explain"))
+ {
+ int len;
+ xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
+ xmlChar *buf_out;
+ char *content;
+
+ ptr = xmlCopyNode(ptr, 1);
+
+ xmlDocSetRootElement(doc, ptr);
+
+ xmlDocDumpMemory(doc, &buf_out, &len);
+ content = (char*) odr_malloc(rr->stream, 1+len);
+ memcpy(content, buf_out, len);
+ content[len] = '\0';
+
+ xmlFree(buf_out);
+ xmlFreeDoc(doc);
+ rr->explain_buf = content;
+ return 0;
+ }
+ }
+#endif
+ return 0;
+}
+
+static void srw_bend_explain(association *assoc,
+ Z_SRW_PDU *sr,
+ Z_SRW_explainResponse *srw_res,
+ int *http_code)
+{
+ Z_SRW_explainRequest *srw_req = sr->u.explain_request;
+ yaz_log(log_requestdetail, "Got SRW ExplainRequest");
+ *http_code = 404;
+ srw_bend_init(assoc, &srw_res->diagnostics, &srw_res->num_diagnostics, sr);
+ if (assoc->init)
+ {
+ bend_explain_rr rr;
+
+ rr.stream = assoc->encode;