X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fzoom-c.c;h=cd13a010f568eb60c6c1fe2eb9b2ba8d34316707;hp=9ea9ffd1b0002b5ec65a9d226a968883564d6b1f;hb=6202be57112ed26410889081bb0ab87a779ae0bf;hpb=609db10a44b3423a6a1f5f33478a2e5e564c583a diff --git a/src/zoom-c.c b/src/zoom-c.c index 9ea9ffd..cd13a01 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: zoom-c.c,v 1.57 2005-12-19 20:19:29 adam Exp $ + * $Id: zoom-c.c,v 1.62 2005-12-21 16:41:36 mike Exp $ */ /** * \file zoom-c.c @@ -11,6 +11,7 @@ #include #include +#include #include "zoom-p.h" #include @@ -23,6 +24,7 @@ #include #include #include +#include #if HAVE_SYS_TYPES_H #include @@ -50,6 +52,8 @@ typedef enum { static zoom_ret ZOOM_connection_send_init (ZOOM_connection c); static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out); +static char *cql2pqf(ZOOM_connection c, const char *cql); + static void initlog() { @@ -163,7 +167,13 @@ static void set_ZOOM_error (ZOOM_connection c, int error, static void clear_error (ZOOM_connection c) { - + /* + * If an error is tied to an operation then it's ok to clear: for + * example, a diagnostic returned from a search is cleared by a + * subsequent search. However, problems such as Connection Lost + * or Init Refused are not cleared, because they are not + * recoverable: doing another search doesn't help. + */ switch (c->error) { case ZOOM_ERROR_CONNECT: @@ -520,6 +530,31 @@ ZOOM_query_cql(ZOOM_query s, const char *str) return 0; } +/* + * Translate the CQL string client-side into RPN which is passed to + * the server. This is useful for server's that don't themselves + * support CQL, for which ZOOM_query_cql() is useless. `conn' is used + * only as a place to stash diagnostics if compilation fails; if this + * information is not needed, a null pointer may be used. + */ +ZOOM_API(int) +ZOOM_query_cql2rpn(ZOOM_query s, const char *str, ZOOM_connection conn) +{ + char *rpn; + int ret; + + yaz_log(log_details, "%p ZOOM_query_cql2rpn str=%s conn=%p", s, str, conn); + if (conn == 0) + conn = ZOOM_connection_create(0); + + if ((rpn = cql2pqf(conn, str)) == 0) + return -1; + + ret = ZOOM_query_prefix(s, rpn); + xfree(rpn); + return ret; +} + ZOOM_API(int) ZOOM_query_sortby(ZOOM_query s, const char *criteria) { @@ -1094,7 +1129,7 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c) ZOOM_options_get(c->options, "implementationName"), odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName)); - version = odr_strdup(c->odr_out, "$Revision: 1.57 $"); + version = odr_strdup(c->odr_out, "$Revision: 1.62 $"); if (strlen(version) > 10) /* check for unexpanded CVS strings */ version[strlen(version)-2] = '\0'; ireq->implementationVersion = odr_prepend(c->odr_out, @@ -2414,6 +2449,7 @@ ZOOM_connection_scan1 (ZOOM_connection c, ZOOM_query q) { ZOOM_scanset scan = (ZOOM_scanset) xmalloc (sizeof(*scan)); char *start; + char *freeme = 0; scan->connection = c; scan->odr = odr_createmem (ODR_DECODE); @@ -2436,17 +2472,19 @@ ZOOM_connection_scan1 (ZOOM_connection c, ZOOM_query q) } else if (q->z_query->which == Z_Query_type_104) { yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p CQL '%s'", c, q, q->query_string); - /* Not yet supported */ - abort(); + start = freeme = cql2pqf(c, q->query_string); + if (start == 0) + return 0; } else { yaz_log(YLOG_FATAL, "%p ZOOM_connection_scan1 q=%p unknown type '%s'", c, q, q->query_string); abort(); } - if ((scan->termListAndStartPoint = - p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, - start)) != 0) + scan->termListAndStartPoint = + p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, start); + xfree (freeme); + if (scan->termListAndStartPoint != 0) { ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_SCAN); task->u.scan.scan = scan; @@ -3698,6 +3736,10 @@ ZOOM_diag_str (int error) return "Unsupported query type"; case ZOOM_ERROR_INVALID_QUERY: return "Invalid query"; + case ZOOM_ERROR_CQL_PARSE: + return "CQL parsing error"; + case ZOOM_ERROR_CQL_TRANSFORM: + return "CQL transformation error"; default: return diagbib1_str (error); } @@ -3991,6 +4033,69 @@ ZOOM_event (int no, ZOOM_connection *cs) } return 0; } + + +/* + * Returns an xmalloc()d string containing RPN that corresponds to the + * CQL passed in. On error, sets the Connection object's error state + * and returns a null pointer. + * ### We could cache CQL parser and/or transformer in Connection. + */ +static char *cql2pqf(ZOOM_connection c, const char *cql) +{ + CQL_parser parser; + int error; + struct cql_node *node; + const char *cqlfile; + static cql_transform_t trans; + char pqfbuf[512]; + + parser = cql_parser_create(); + if ((error = cql_parser_string(parser, cql)) != 0) { + cql_parser_destroy(parser); + set_ZOOM_error(c, ZOOM_ERROR_CQL_PARSE, cql); + return 0; + } + + node = cql_parser_result(parser); + /* ### Do not call cql_parser_destroy() yet: it destroys `node'! */ + + cqlfile = ZOOM_connection_option_get(c, "cqlfile"); + if (cqlfile == 0) { + cql_parser_destroy(parser); + cql_node_destroy(node); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, "no CQL transform file"); + return 0; + } + + if ((trans = cql_transform_open_fname(cqlfile)) == 0) { + char buf[512]; + cql_parser_destroy(parser); + cql_node_destroy(node); + sprintf(buf, "can't open CQL transform file '%.200s': %.200s", + cqlfile, strerror(errno)); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + return 0; + } + + error = cql_transform_buf(trans, node, pqfbuf, sizeof pqfbuf); + cql_parser_destroy(parser); + cql_node_destroy(node); + if (error != 0) { + char buf[512]; + const char *addinfo; + error = cql_transform_error(trans, &addinfo); + cql_transform_close(trans); + sprintf(buf, "%.200s (addinfo=%.200s)", cql_strerror(error), addinfo); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + return 0; + } + + cql_transform_close(trans); + return xstrdup(pqfbuf); +} + + /* * Local variables: * c-basic-offset: 4