X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fzoom-query.c;fp=src%2Fzoom-query.c;h=104987351389a81d7a99281aefc1c46b03d7f0ba;hb=63c48920fd45817bf28177279f65099670fe258b;hp=0000000000000000000000000000000000000000;hpb=b7ac19e96f5e53975064b3dec2be6cbd2c1eccb8;p=yaz-moved-to-github.git diff --git a/src/zoom-query.c b/src/zoom-query.c new file mode 100644 index 0000000..1049873 --- /dev/null +++ b/src/zoom-query.c @@ -0,0 +1,262 @@ +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2010 Index Data + * See the file LICENSE for details. + */ +/** + * \file zoom-query.c + * \brief Implements ZOOM C query interface. + */ + +#include +#include +#include +#include "zoom-p.h" + +#include +#include +#include +#include +#include +#include +#include + +struct ZOOM_query_p { + Z_Query *z_query; + Z_SortKeySpecList *sort_spec; + int refcount; + ODR odr; + char *query_string; +}; + +Z_Query *ZOOM_query_get_Z_Query(ZOOM_query s) +{ + return s->z_query; +} + + +Z_SortKeySpecList *ZOOM_query_get_sortspec(ZOOM_query s) +{ + return s->sort_spec; +} + +static void cql2pqf_wrbuf_puts(const char *buf, void *client_data) +{ + WRBUF wrbuf = (WRBUF) client_data; + wrbuf_puts(wrbuf, buf); +} + +char *ZOOM_query_get_query_string(ZOOM_query s) +{ + return s->query_string; +} + +/* + * 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; + const char *cqlfile; + cql_transform_t trans; + char *result = 0; + + parser = cql_parser_create(); + if ((error = cql_parser_string(parser, cql)) != 0) { + cql_parser_destroy(parser); + ZOOM_set_error(c, ZOOM_ERROR_CQL_PARSE, cql); + return 0; + } + + cqlfile = ZOOM_connection_option_get(c, "cqlfile"); + if (cqlfile == 0) + { + ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, "no CQL transform file"); + } + else if ((trans = cql_transform_open_fname(cqlfile)) == 0) + { + char buf[512]; + sprintf(buf, "can't open CQL transform file '%.200s': %.200s", + cqlfile, strerror(errno)); + ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + } + else + { + WRBUF wrbuf_result = wrbuf_alloc(); + error = cql_transform(trans, cql_parser_result(parser), + cql2pqf_wrbuf_puts, wrbuf_result); + if (error != 0) { + char buf[512]; + const char *addinfo; + error = cql_transform_error(trans, &addinfo); + sprintf(buf, "%.200s (addinfo=%.200s)", + cql_strerror(error), addinfo); + ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + } + else + { + result = xstrdup(wrbuf_cstr(wrbuf_result)); + } + cql_transform_close(trans); + wrbuf_destroy(wrbuf_result); + } + cql_parser_destroy(parser); + return result; +} + + +ZOOM_API(ZOOM_query) + ZOOM_query_create(void) +{ + ZOOM_query s = (ZOOM_query) xmalloc(sizeof(*s)); + + s->refcount = 1; + s->z_query = 0; + s->sort_spec = 0; + s->odr = odr_createmem(ODR_ENCODE); + s->query_string = 0; + + return s; +} + +ZOOM_API(void) + ZOOM_query_destroy(ZOOM_query s) +{ + if (!s) + return; + + (s->refcount)--; + if (s->refcount == 0) + { + odr_destroy(s->odr); + xfree(s); + } +} + +ZOOM_API(void) + ZOOM_query_addref(ZOOM_query s) +{ + s->refcount++; +} + +ZOOM_API(int) + ZOOM_query_prefix(ZOOM_query s, const char *str) +{ + s->query_string = odr_strdup(s->odr, str); + s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query)); + s->z_query->which = Z_Query_type_1; + s->z_query->u.type_1 = p_query_rpn(s->odr, str); + if (!s->z_query->u.type_1) + { + s->z_query = 0; + return -1; + } + return 0; +} + +ZOOM_API(int) + ZOOM_query_cql(ZOOM_query s, const char *str) +{ + Z_External *ext; + + s->query_string = odr_strdup(s->odr, str); + + ext = (Z_External *) odr_malloc(s->odr, sizeof(*ext)); + ext->direct_reference = odr_oiddup(s->odr, yaz_oid_userinfo_cql); + ext->indirect_reference = 0; + ext->descriptor = 0; + ext->which = Z_External_CQL; + ext->u.cql = s->query_string; + + s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query)); + s->z_query->which = Z_Query_type_104; + s->z_query->u.type_104 = ext; + + 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; + ZOOM_connection freeme = 0; + + if (conn == 0) + conn = freeme = ZOOM_connection_create(0); + + rpn = cql2pqf(conn, str); + if (freeme != 0) + ZOOM_connection_destroy(freeme); + if (rpn == 0) + return -1; + + ret = ZOOM_query_prefix(s, rpn); + xfree(rpn); + return ret; +} + +/* + * Analogous in every way to ZOOM_query_cql2rpn(), except that there + * is no analogous ZOOM_query_ccl() that just sends uninterpreted CCL + * to the server, as the YAZ GFS doesn't know how to handle this. + */ +ZOOM_API(int) + ZOOM_query_ccl2rpn(ZOOM_query s, const char *str, const char *config, + int *ccl_error, const char **error_string, + int *error_pos) +{ + int ret; + struct ccl_rpn_node *rpn; + CCL_bibset bibset = ccl_qual_mk(); + + if (config) + ccl_qual_buf(bibset, config); + + rpn = ccl_find_str(bibset, str, ccl_error, error_pos); + if (!rpn) + { + *error_string = ccl_err_msg(*ccl_error); + ret = -1; + } + else + { + WRBUF wr = wrbuf_alloc(); + ccl_pquery(wr, rpn); + ccl_rpn_delete(rpn); + ret = ZOOM_query_prefix(s, wrbuf_cstr(wr)); + wrbuf_destroy(wr); + } + ccl_qual_rm(&bibset); + return ret; +} + +ZOOM_API(int) + ZOOM_query_sortby(ZOOM_query s, const char *criteria) +{ + s->sort_spec = yaz_sort_spec(s->odr, criteria); + if (!s->sort_spec) + return -1; + return 0; +} + + +/* + * Local variables: + * c-basic-offset: 4 + * c-file-style: "Stroustrup" + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ +