Add re-entrant CQL/Solr/RPN functions
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 10 Apr 2014 12:19:32 +0000 (14:19 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 10 Apr 2014 12:19:32 +0000 (14:19 +0200)
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
include/yaz/rpn2cql.h
include/yaz/rpn2solr.h
src/cqltransform.c
src/rpn2cql.c
src/rpn2solr.c
test/test_rpn2cql.c

index f5b6ea9..f1cdd78 100644 (file)
@@ -33,6 +33,7 @@
 #define CQL_H_INCLUDED
 #include <stdio.h>
 #include <yaz/nmem.h>
+#include <yaz/wrbuf.h>
 
 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
index 3c6691f..a7afd0b 100644 (file)
 
 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
index 42f1004..630137e 100644 (file)
 
 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
index f560445..0ab9079 100644 (file)
@@ -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;
 }
 
index 7763db3..842d1a9 100644 (file)
@@ -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;
 }
index 332ae88..f790ea2 100644 (file)
@@ -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)
index 0d929e5..0d05fab 100644 (file)
@@ -15,7 +15,8 @@
 #include <yaz/wrbuf.h>
 #include <yaz/pquery.h>
 
-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);
 }