From d161ec774d6250a6814918f68559560d5c9db8cc Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Thu, 10 Apr 2014 14:19:32 +0200 Subject: [PATCH] Add re-entrant CQL/Solr/RPN functions The re-entrant functions are: cql_transform_r, cql_transform_rpn2cql_stream_r, solr_transform_rpn2solr_stream_r. These have same functionality as cql_transform, cql_transform_rpn2cql_stream, solr_transform_rpn2solr_stream. They return the additional infomration as WRBUF to make them re-entrant. --- include/yaz/cql.h | 17 ++++++++------- include/yaz/rpn2cql.h | 26 ++++++++++++++++++----- include/yaz/rpn2solr.h | 18 +++++++++++++++- src/cqltransform.c | 55 ++++++++++++++++++++++++------------------------ src/rpn2cql.c | 30 +++++++++++++++++++++++--- src/rpn2solr.c | 19 +++++++++++++---- test/test_rpn2cql.c | 30 ++++++++++++++++++++------ 7 files changed, 140 insertions(+), 55 deletions(-) diff --git a/include/yaz/cql.h b/include/yaz/cql.h index f5b6ea9..f1cdd78 100644 --- a/include/yaz/cql.h +++ b/include/yaz/cql.h @@ -33,6 +33,7 @@ #define CQL_H_INCLUDED #include #include +#include YAZ_BEGIN_CDECL @@ -332,7 +333,7 @@ int cql_transform_define_pattern(cql_transform_t ct, const char *pattern, YAZ_EXPORT void cql_transform_close(cql_transform_t ct); -/** \brief tranforms PQF given a CQL tree +/** \brief tranforms PQF given a CQL tree (NOT re-entrant) \param ct CQL transform handle \param cn CQL node tree \param pr print function @@ -348,7 +349,7 @@ int cql_transform(cql_transform_t ct, void (*pr)(const char *buf, void *client_data), void *client_data); -/** \brief tranforms PQF given a CQL tree +/** \brief tranforms PQF given a CQL tree (re-entrant) \param ct CQL transform handle \param cn CQL node tree \param addinfo additional information (if error) @@ -359,12 +360,12 @@ int cql_transform(cql_transform_t ct, The result is written to a user-defined stream. */ -int cql_transform_cql2rpn(cql_transform_t ct, struct cql_node *cn, - char **addinfo, - void (*pr)(const char *buf, void *client_data), - void *client_data); +int cql_transform_r(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data); -/** \brief transforms PQF given a CQL tree (from FILE) +/** \brief transforms PQF given a CQL tree from FILE (not re-entrant) \param ct CQL transform handle \param cn CQL tree \param f FILE where output is written @@ -378,7 +379,7 @@ YAZ_EXPORT int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f); -/** \brief transforms PQF given a CQL tree (from FILE) +/** \brief transforms PQF given a CQL tree from buffer (not re-entrant) \param ct CQL transform handle \param cn CQL tree \param out buffer for output diff --git a/include/yaz/rpn2cql.h b/include/yaz/rpn2cql.h index 3c6691f..a7afd0b 100644 --- a/include/yaz/rpn2cql.h +++ b/include/yaz/rpn2cql.h @@ -37,7 +37,25 @@ YAZ_BEGIN_CDECL -/** \brief transforms RPN query to CQL output stream +/** \brief transforms RPN query to CQL output stream (re-entrant) + \param ct CQL transform handle + \param addinfo for additional error info + \param pr print function + \param client_data opaque data to be passed to print handler + \param q RPN Query + \retval 0 success + \retval !=0 failure (error code) + */ +YAZ_EXPORT +int cql_transform_rpn2cql_stream_r(cql_transform_t ct, + WRBUF addinfo, + void (*pr)(const char *buf, + void *client_data), + void *client_data, + Z_RPNQuery *q); + + +/** \brief transforms RPN query to CQL output stream (NOT re-entrant) \param ct CQL transform handle \param pr print function \param client_data opaque data to be passed to print handler @@ -52,7 +70,7 @@ int cql_transform_rpn2cql_stream(cql_transform_t ct, Z_RPNQuery *q); -/** \brief transforms RPN query to CQL WRBUF +/** \brief transforms RPN query to CQL WRBUF (NOT re-entrant) \param ct CQL transform handle \param w WRBUF handle for result \param q RPN Query @@ -60,9 +78,7 @@ int cql_transform_rpn2cql_stream(cql_transform_t ct, \retval !=0 failure (error code) */ YAZ_EXPORT -int cql_transform_rpn2cql_wrbuf(cql_transform_t ct, - WRBUF w, - Z_RPNQuery *q); +int cql_transform_rpn2cql_wrbuf(cql_transform_t ct, WRBUF w, Z_RPNQuery *q); /** \brief find a pattern that has a subset of attributes \param ct CQL transform handle diff --git a/include/yaz/rpn2solr.h b/include/yaz/rpn2solr.h index 42f1004..630137e 100644 --- a/include/yaz/rpn2solr.h +++ b/include/yaz/rpn2solr.h @@ -37,7 +37,23 @@ YAZ_BEGIN_CDECL -/** \brief transforms RPN query to SOLR output stream +/** \brief transforms RPN query to SOLR output stream (re-entrant) + \param ct SOLR transform handle + \param addinfo additional info on error + \param pr print function + \param client_data opaque data to be passed to print handler + \param q RPN Query + \retval 0 success + \retval !=0 failure (error code) + */ +YAZ_EXPORT +int solr_transform_rpn2solr_stream_r(solr_transform_t ct, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data, + Z_RPNQuery *q); + +/** \brief transforms RPN query to SOLR output stream (NOT re-entrant) \param ct SOLR transform handle \param pr print function \param client_data opaque data to be passed to print handler diff --git a/src/cqltransform.c b/src/cqltransform.c index f560445..0ab9079 100644 --- a/src/cqltransform.c +++ b/src/cqltransform.c @@ -382,7 +382,7 @@ static const char *cql_lookup_property(cql_transform_t ct, return 0; } -int cql_pr_attr_uri(cql_transform_t ct, char **addinfo, const char *category, +int cql_pr_attr_uri(cql_transform_t ct, WRBUF addinfo, const char *category, const char *uri, const char *val, const char *default_val, void (*pr)(const char *buf, void *client_data), void *client_data, @@ -464,11 +464,11 @@ int cql_pr_attr_uri(cql_transform_t ct, char **addinfo, const char *category, if (errcode == 0) return 1; /* signal error, but do not set addinfo */ if (val) - *addinfo = xstrdup(val); + wrbuf_puts(addinfo, val); return errcode; } -int cql_pr_attr(cql_transform_t ct, char **addinfo, const char *category, +int cql_pr_attr(cql_transform_t ct, WRBUF addinfo, const char *category, const char *val, const char *default_val, void (*pr)(const char *buf, void *client_data), void *client_data, @@ -491,7 +491,7 @@ static void cql_pr_int(int val, static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, - char **addinfo, + WRBUF addinfo, void (*pr)(const char *buf, void *client_data), void *client_data) { @@ -523,7 +523,7 @@ static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, proxrel = 6; else { - *addinfo = xstrdup(relation); + wrbuf_puts(addinfo, relation); return YAZ_SRW_UNSUPP_PROX_RELATION; } } @@ -543,13 +543,13 @@ static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, unit = 8; else { - *addinfo = xstrdup(term); + wrbuf_puts(addinfo, term); return YAZ_SRW_UNSUPP_PROX_UNIT; } } else { - *addinfo = xstrdup(name); + wrbuf_puts(addinfo, name); return YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; } mods = mods->u.st.modifiers; @@ -580,7 +580,7 @@ static int has_modifier(struct cql_node *cn, const char *name) { } static int emit_term(cql_transform_t ct, - struct cql_node *cn, char **addinfo, + struct cql_node *cn, WRBUF addinfo, const char *term, int length, void (*pr)(const char *buf, void *client_data), void *client_data) @@ -778,7 +778,7 @@ static int emit_term(cql_transform_t ct, } static int emit_terms(cql_transform_t ct, struct cql_node *cn, - char **addinfo, + WRBUF addinfo, void (*pr)(const char *buf, void *client_data), void *client_data, const char *op) @@ -808,7 +808,7 @@ static int emit_terms(cql_transform_t ct, struct cql_node *cn, } static int emit_wordlist(cql_transform_t ct, struct cql_node *cn, - char **addinfo, + WRBUF addinfo, void (*pr)(const char *buf, void *client_data), void *client_data, const char *op) @@ -843,10 +843,10 @@ static int emit_wordlist(cql_transform_t ct, struct cql_node *cn, return r; } -int cql_transform_r(cql_transform_t ct, struct cql_node *cn, - char **addinfo, - void (*pr)(const char *buf, void *client_data), - void *client_data) +static int emit_node(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data) { const char *ns; int r = 0; @@ -871,7 +871,6 @@ int cql_transform_r(cql_transform_t ct, struct cql_node *cn, } else { - *addinfo = 0; return YAZ_SRW_UNSUPP_CONTEXT_SET; } cql_pr_attr(ct, addinfo, "always", 0, 0, pr, client_data, 0); @@ -905,19 +904,19 @@ int cql_transform_r(cql_transform_t ct, struct cql_node *cn, else if (mods) { /* Boolean modifiers other than on proximity not supported */ - *addinfo = xstrdup(mods->u.st.index); + wrbuf_puts(addinfo, mods->u.st.index); return YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; } - r = cql_transform_r(ct, cn->u.boolean.left, addinfo, pr, client_data); + r = emit_node(ct, cn->u.boolean.left, addinfo, pr, client_data); if (r) return r; - r = cql_transform_r(ct, cn->u.boolean.right, addinfo, pr, client_data); + r = emit_node(ct, cn->u.boolean.right, addinfo, pr, client_data); if (r) return r; break; case CQL_NODE_SORT: - r = cql_transform_r(ct, cn->u.sort.search, addinfo, pr, client_data); + r = emit_node(ct, cn->u.sort.search, addinfo, pr, client_data); break; default: fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which); @@ -926,10 +925,10 @@ int cql_transform_r(cql_transform_t ct, struct cql_node *cn, return r; } -int cql_transform_cql2rpn(cql_transform_t ct, struct cql_node *cn, - char **addinfo, - void (*pr)(const char *buf, void *client_data), - void *client_data) +int cql_transform_r(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data) { struct cql_prop_entry *e; NMEM nmem = nmem_create(); @@ -942,7 +941,7 @@ int cql_transform_cql2rpn(cql_transform_t ct, struct cql_node *cn, else if (!cql_strcmp(e->pattern, "set")) cql_apply_prefix(nmem, cn, 0, e->value); } - r = cql_transform_r(ct, cn, addinfo, pr, client_data); + r = emit_node(ct, cn, addinfo, pr, client_data); nmem_destroy(nmem); return r; } @@ -951,10 +950,10 @@ int cql_transform(cql_transform_t ct, struct cql_node *cn, void (*pr)(const char *buf, void *client_data), void *client_data) { - char *addinfo = 0; - int r = cql_transform_cql2rpn(ct, cn, &addinfo, pr, client_data); - cql_transform_set_error(ct, r, addinfo); - xfree(addinfo); + WRBUF addinfo = wrbuf_alloc(); + int r = cql_transform_r(ct, cn, addinfo, pr, client_data); + cql_transform_set_error(ct, r, wrbuf_cstr(addinfo)); + wrbuf_destroy(addinfo); return r; } diff --git a/src/rpn2cql.c b/src/rpn2cql.c index 7763db3..842d1a9 100644 --- a/src/rpn2cql.c +++ b/src/rpn2cql.c @@ -116,7 +116,10 @@ static int rpn2cql_attr(cql_transform_t ct, relation = lookup_relation_index_from_attr(attributes); if (!index) + { + wrbuf_rewind(w); return YAZ_BIB1_UNSUPP_USE_ATTRIBUTE; + } /* for serverChoice we omit index+relation+structure */ if (strcmp(index, "cql.serverChoice")) { @@ -172,7 +175,10 @@ static int rpn2cql_simple(cql_transform_t ct, Z_Operand *q, WRBUF w) { if (q->which != Z_Operand_APT) + { + wrbuf_rewind(w); return YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM; + } else { Z_AttributesPlusTerm *apt = q->u.attributesPlusTerm; @@ -202,6 +208,8 @@ static int rpn2cql_simple(cql_transform_t ct, lterm = strlen(sterm); break; default: + wrbuf_rewind(w); + wrbuf_printf(w, "%d", term->which); return YAZ_BIB1_TERM_TYPE_UNSUPP; } @@ -255,6 +263,8 @@ static int rpn2cql_simple(cql_transform_t ct, } else { + wrbuf_rewind(w); + wrbuf_printf(w, ODR_INT_PRINTF, trunc); return YAZ_BIB1_UNSUPP_TRUNCATION_ATTRIBUTE; } pr(wrbuf_cstr(w), client_data); @@ -306,6 +316,7 @@ static int rpn2cql_structure(cql_transform_t ct, *prox->relationType < Z_ProximityOperator_Prox_lessThan || *prox->relationType > Z_ProximityOperator_Prox_notEqual) { + wrbuf_rewind(w); return YAZ_BIB1_UNSUPP_SEARCH; } pr(op2name[*prox->relationType-1], client_data); @@ -335,16 +346,29 @@ static int rpn2cql_structure(cql_transform_t ct, } } +int cql_transform_rpn2cql_stream_r(cql_transform_t ct, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data, + Z_RPNQuery *q) +{ + /* addinfo (w) is used for both addinfo and house-keeping ! */ + int r = rpn2cql_structure(ct, pr, client_data, q->RPNStructure, 0, addinfo); + if (!r) + wrbuf_rewind(addinfo); /* no additional info if no error */ + return r; +} + + int cql_transform_rpn2cql_stream(cql_transform_t ct, void (*pr)(const char *buf, void *client_data), void *client_data, Z_RPNQuery *q) { - int r; WRBUF w = wrbuf_alloc(); - r = rpn2cql_structure(ct, pr, client_data, q->RPNStructure, 0, w); + int r = cql_transform_rpn2cql_stream_r(ct, w, pr, client_data, q); if (r) - cql_transform_set_error(ct, r, 0); + cql_transform_set_error(ct, r, wrbuf_len(w) ? wrbuf_cstr(w) : 0); wrbuf_destroy(w); return r; } diff --git a/src/rpn2solr.c b/src/rpn2solr.c index 332ae88..f790ea2 100644 --- a/src/rpn2solr.c +++ b/src/rpn2solr.c @@ -393,21 +393,32 @@ static int rpn2solr_structure(solr_transform_t ct, } } +int solr_transform_rpn2solr_stream_r(solr_transform_t ct, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data, + Z_RPNQuery *q) +{ + int r = rpn2solr_structure(ct, pr, client_data, q->RPNStructure, + /* nested*/ 0, addinfo); + if (!r) + wrbuf_rewind(addinfo); + return r; +} + int solr_transform_rpn2solr_stream(solr_transform_t ct, void (*pr)(const char *buf, void *client_data), void *client_data, Z_RPNQuery *q) { - int r; WRBUF w = wrbuf_alloc(); - r = rpn2solr_structure(ct, pr, client_data, q->RPNStructure, 0, w); + int r = solr_transform_rpn2solr_stream_r(ct, w, pr, client_data, q); if (r) - solr_transform_set_error(ct, r, 0); + solr_transform_set_error(ct, r, wrbuf_len(w) ? wrbuf_cstr(w) : 0); wrbuf_destroy(w); return r; } - int solr_transform_rpn2solr_wrbuf(solr_transform_t ct, WRBUF w, Z_RPNQuery *q) diff --git a/test/test_rpn2cql.c b/test/test_rpn2cql.c index 0d929e5..0d05fab 100644 --- a/test/test_rpn2cql.c +++ b/test/test_rpn2cql.c @@ -15,7 +15,8 @@ #include #include -static int compare(cql_transform_t ct, const char *pqf, const char *cql) +static int compare2(cql_transform_t ct, const char *pqf, const char *cql, + int expected_error) { int ret = 0; ODR odr = odr_createmem(ODR_ENCODE); @@ -28,15 +29,26 @@ static int compare(cql_transform_t ct, const char *pqf, const char *cql) if (r != 0) { + const char *addinfo = 0; + int err = cql_transform_error(ct, &addinfo); /* transform error */ yaz_log(YLOG_LOG, "%s -> Error %d", pqf, r); - if (!cql) /* also expected error? */ - ret = 1; + if (err == 0) + ; + else if (err == expected_error) + { + if (addinfo && cql && !strcmp(addinfo, cql)) + ret = 1; + else if (!addinfo && !cql) + ret = 1; + } } else if (r == 0) { yaz_log(YLOG_LOG, "%s -> %s", pqf, wrbuf_cstr(w)); - if (cql && !strcmp(wrbuf_cstr(w), cql)) + if (!expected_error) + ret = 1; + else if (cql && !strcmp(wrbuf_cstr(w), cql)) { ret = 1; } @@ -52,6 +64,11 @@ static int compare(cql_transform_t ct, const char *pqf, const char *cql) return ret; } +static int compare(cql_transform_t ct, const char *pqf, const char *cql) +{ + return compare2(ct, pqf, cql, 0); +} + static void tst1(void) { cql_transform_t ct = cql_transform_create(); @@ -65,7 +82,7 @@ static void tst1(void) YAZ_CHECK(compare(ct, "@and @and a b @and c d", "(a and b) and (c and d)")); YAZ_CHECK(compare(ct, "@attr 1=field abc", "field=abc")); - YAZ_CHECK(compare(ct, "@attr 1=4 abc", 0)); /* should fail */ + YAZ_CHECK(compare2(ct, "@attr 1=4 abc", 0, 114)); /* should fail */ cql_transform_define_pattern(ct, "index.title", "1=4"); YAZ_CHECK(compare(ct, "@attr 1=4 abc", "title=abc")); @@ -151,7 +168,8 @@ static void tst2(void) /* Other */ YAZ_CHECK(compare(ct, "@attr 2=103 @attr 1=_ALLRECORDS 1", "cql.allRecords=1")); - YAZ_CHECK(compare(ct, "@attr 1=500 abc", 0)); + YAZ_CHECK(compare2(ct, "@attr 1=500 abc", 0, 114)); + YAZ_CHECK(compare2(ct, "@attr 5=99 x", "99", 120)); cql_transform_close(ct); wrbuf_destroy(w); } -- 1.7.10.4