yaz_cql_parse does CQL to RPN (and the reverse)
authorAdam Dickmeiss <adam@indexdata.dk>
Fri, 5 Sep 2014 13:30:01 +0000 (15:30 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 7 Oct 2014 13:56:37 +0000 (15:56 +0200)
php_yaz.c
php_yaz.h
tests/connect.phpt [new file with mode: 0644]
tests/cql.phpt [new file with mode: 0644]
tests/database.phpt [new file with mode: 0644]
tests/record.phpt [new file with mode: 0644]

index 0964cbd..9258365 100644 (file)
--- a/php_yaz.c
+++ b/php_yaz.c
 #include <yaz/marcdisp.h>
 #include <yaz/yaz-util.h>
 #include <yaz/yaz-ccl.h>
 #include <yaz/marcdisp.h>
 #include <yaz/yaz-util.h>
 #include <yaz/yaz-ccl.h>
+#include <yaz/cql.h>
 #include <yaz/oid_db.h>
 #include <yaz/zoom.h>
 #include <yaz/oid_db.h>
 #include <yaz/zoom.h>
+#include <yaz/pquery.h>
 
 #ifndef ODR_INT_PRINTF
 #define ODR_INT_PRINTF "%d"
 
 #ifndef ODR_INT_PRINTF
 #define ODR_INT_PRINTF "%d"
@@ -58,6 +60,7 @@ typedef struct Yaz_AssociationInfo *Yaz_Association;
 
 struct Yaz_AssociationInfo {
        CCL_bibset bibset;
 
 struct Yaz_AssociationInfo {
        CCL_bibset bibset;
+       cql_transform_t ct;
        ZOOM_connection zoom_conn;
        ZOOM_resultset zoom_set;
        ZOOM_scanset zoom_scan;
        ZOOM_connection zoom_conn;
        ZOOM_resultset zoom_set;
        ZOOM_scanset zoom_scan;
@@ -85,6 +88,7 @@ static Yaz_Association yaz_association_mk()
        p->order = 0;
        p->persistent = 0;
        p->bibset = ccl_qual_mk();
        p->order = 0;
        p->persistent = 0;
        p->bibset = ccl_qual_mk();
+       p->ct = cql_transform_create();
        p->time_stamp = 0;
        return p;
 }
        p->time_stamp = 0;
        return p;
 }
@@ -95,6 +99,7 @@ static void yaz_association_destroy(Yaz_Association p)
                return;
        }
 
                return;
        }
 
+       cql_transform_close(p->ct);
        ZOOM_resultset_destroy(p->zoom_set);
        ZOOM_scanset_destroy(p->zoom_scan);
        ZOOM_package_destroy(p->zoom_package);
        ZOOM_resultset_destroy(p->zoom_set);
        ZOOM_scanset_destroy(p->zoom_scan);
        ZOOM_package_destroy(p->zoom_package);
@@ -163,6 +168,8 @@ zend_function_entry yaz_functions [] = {
        PHP_FE(yaz_present, NULL)
        PHP_FE(yaz_ccl_conf, NULL)
        PHP_FE(yaz_ccl_parse, third_argument_force_ref)
        PHP_FE(yaz_present, NULL)
        PHP_FE(yaz_ccl_conf, NULL)
        PHP_FE(yaz_ccl_parse, third_argument_force_ref)
+       PHP_FE(yaz_cql_parse, third_argument_force_ref)
+       PHP_FE(yaz_cql_conf, NULL)
        PHP_FE(yaz_database, NULL)
        PHP_FE(yaz_sort, NULL)
        PHP_FE(yaz_schema, NULL)
        PHP_FE(yaz_database, NULL)
        PHP_FE(yaz_sort, NULL)
        PHP_FE(yaz_schema, NULL)
@@ -1933,6 +1940,132 @@ PHP_FUNCTION(yaz_ccl_parse)
 }
 /* }}} */
 
 }
 /* }}} */
 
+
+/* {{{ proto bool yaz_cql_parse(resource id, string cql, array res, bool rev)
+   Parse a CQL query */
+PHP_FUNCTION(yaz_cql_parse)
+{
+       zval *pval_id, *pval_res = 0;
+       char *query;
+       int query_len;
+       Yaz_Association p;
+       zend_bool reverse = 0;
+
+       if (ZEND_NUM_ARGS() != 4 ||
+               zend_parse_parameters(4 TSRMLS_CC, "zszb",
+                                                         &pval_id, &query, &query_len, &pval_res, &reverse)
+               == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       zval_dtor(pval_res);
+       array_init(pval_res);
+       get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
+       if (p) {
+               if (reverse) {
+            ODR odr = odr_createmem(ODR_ENCODE);
+            YAZ_PQF_Parser pp = yaz_pqf_create();
+            Z_RPNQuery *rpn = yaz_pqf_parse(pp, odr, query);
+                       WRBUF wrbuf_cql = wrbuf_alloc();
+                       int r;
+                       if (!rpn) {
+                               add_assoc_long(pval_res, "errorcode", 0);
+                               add_assoc_string(pval_res, "addinfo",
+                                                                (char *) "PQF syntax error", 1);
+                               RETVAL_FALSE;
+                       } else if ((r = cql_transform_rpn2cql_stream(p->ct, wrbuf_vp_puts,
+                                                                                                                wrbuf_cql, rpn))) {
+                               add_assoc_long(pval_res, "errorcode", r);
+                               RETVAL_FALSE;
+                       } else {
+                               add_assoc_string(pval_res, "cql",
+                                                                (char *) wrbuf_cstr(wrbuf_cql), 1);
+                               RETVAL_TRUE;
+                       }
+                       wrbuf_destroy(wrbuf_cql);
+                       yaz_pqf_destroy(pp);
+            odr_destroy(odr);
+               } else {
+                       CQL_parser cp = cql_parser_create();
+                       int r = cql_parser_string(cp, query);
+                       if (r) {
+                               add_assoc_long(pval_res, "errorcode", 0);
+                               add_assoc_string(pval_res, "addinfo",
+                                                                (char *) "syntax error", 1);
+                               RETVAL_FALSE;
+                       } else {
+                               WRBUF wrbuf_addinfo = wrbuf_alloc();
+                               WRBUF wrbuf_pqf = wrbuf_alloc();
+                               r = cql_transform_r(p->ct, cql_parser_result(cp), wrbuf_addinfo,
+                                                                       wrbuf_vp_puts, wrbuf_pqf);
+                               if (r) {
+                                       add_assoc_long(pval_res, "errorcode", r);
+                                       if (wrbuf_len(wrbuf_addinfo))
+                                               add_assoc_string(pval_res, "addinfo",
+                                                                                (char *) wrbuf_cstr(wrbuf_addinfo), 1);
+                                       RETVAL_FALSE;
+                               } else {
+                                       wrbuf_chop_right(wrbuf_pqf);
+                                       add_assoc_string(pval_res, "rpn",
+                                                                        (char *) wrbuf_cstr(wrbuf_pqf), 1);
+                                       RETVAL_TRUE;
+                               }
+                               wrbuf_destroy(wrbuf_pqf);
+                               wrbuf_destroy(wrbuf_addinfo);
+                       }
+                       cql_parser_destroy(cp);
+               }
+       } else {
+               RETVAL_FALSE;
+       }
+       release_assoc(p);
+}
+/* }}} */
+
+/* {{{ proto void yaz_cql_conf(resource id, array package)
+   Configure CQL package */
+PHP_FUNCTION(yaz_cql_conf)
+{
+       zval *pval_id, *pval_package;
+       Yaz_Association p;
+
+       if (ZEND_NUM_ARGS() != 2 ||
+               zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package)
+               == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
+       if (p) {
+               HashTable *ht = Z_ARRVAL_PP(&pval_package);
+               HashPosition pos;
+               zval **ent;
+               char *key;
+
+               cql_transform_close(p->ct);
+               p->ct = cql_transform_create();
+
+               for (zend_hash_internal_pointer_reset_ex(ht, &pos);
+                       zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
+                       zend_hash_move_forward_ex(ht, &pos)
+               ) {
+                       ulong idx;
+#if PHP_API_VERSION > 20010101
+                       int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
+#else
+                       int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
+#endif
+                       if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
+                               continue;
+                       }
+
+                       cql_transform_define_pattern(p->ct, key, (*ent)->value.str.val);
+               }
+       }
+       release_assoc(p);
+}
+/* }}} */
+
+
 /* {{{ proto bool yaz_database (resource id, string databases)
    Specify the databases within a session */
 PHP_FUNCTION(yaz_database)
 /* {{{ proto bool yaz_database (resource id, string databases)
    Specify the databases within a session */
 PHP_FUNCTION(yaz_database)
index 094dfa9..3ca0594 100644 (file)
--- a/php_yaz.h
+++ b/php_yaz.h
@@ -49,6 +49,8 @@ PHP_FUNCTION(yaz_es_result);
 PHP_FUNCTION(yaz_present);
 PHP_FUNCTION(yaz_ccl_conf);
 PHP_FUNCTION(yaz_ccl_parse);
 PHP_FUNCTION(yaz_present);
 PHP_FUNCTION(yaz_ccl_conf);
 PHP_FUNCTION(yaz_ccl_parse);
+PHP_FUNCTION(yaz_cql_parse);
+PHP_FUNCTION(yaz_cql_conf);
 PHP_FUNCTION(yaz_database);
 PHP_FUNCTION(yaz_sort);
 PHP_FUNCTION(yaz_schema);
 PHP_FUNCTION(yaz_database);
 PHP_FUNCTION(yaz_sort);
 PHP_FUNCTION(yaz_schema);
diff --git a/tests/connect.phpt b/tests/connect.phpt
new file mode 100644 (file)
index 0000000..16c0b55
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+yaz_connect
+--SKIPIF--
+<?php if (!extension_loaded("yaz")) print "skip"; ?>
+--FILE--
+<?php
+$z = yaz_connect("z3950.indexdata.com/gils");
+yaz_search($z, "rpn", "computer");
+yaz_wait();
+echo yaz_errno($z) . "\n";
+echo yaz_hits($z) . "\n";
+yaz_search($z, "rpn", "@attr 1=99 computer");
+yaz_wait();
+echo yaz_errno($z) . "\n";
+echo yaz_hits($z) . "\n";
+--EXPECT--
+0
+3
+114
+0
diff --git a/tests/cql.phpt b/tests/cql.phpt
new file mode 100644 (file)
index 0000000..479b166
--- /dev/null
@@ -0,0 +1,51 @@
+--TEST--
+cql
+--SKIPIF--
+<?php if (!extension_loaded("yaz")) print "skip"; ?>
+--FILE--
+<?php
+$z = yaz_connect("bogus");
+if (yaz_cql_parse($z, "computer", $res, false)) {
+   echo $res['rpn'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+yaz_cql_conf($z, array(
+ "set.cql" => "info:srw/cql-context-set/1/cql-v1.2",
+ "index.cql.serverChoice" => "1=1016",
+ "relation.eq" => "3=3",
+ "structure.*" => "4=1",
+ "position.any" => "6=1"
+ ));
+if (yaz_cql_parse($z, "computer", $res, false)) {
+   echo $res['rpn'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+if (yaz_cql_parse($z, "computer and", $res, true)) {
+   echo $res['cql'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+if (yaz_cql_parse($z, "computer", $res, true)) {
+   echo $res['cql'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+if (yaz_cql_parse($z, "@and a @attr 1=1016 b", $res, true)) {
+   echo $res['cql'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+if (yaz_cql_parse($z, "@and a", $res, true)) {
+   echo $res['cql'] . "\n";
+} else {
+   echo $res['errorcode'] . "\n";
+}
+--EXPECT--
+15
+@attr 3=3 @attr 4=1 @attr 6=1 @attr 1=1016 "computer"
+0
+computer
+a and b
+0
diff --git a/tests/database.phpt b/tests/database.phpt
new file mode 100644 (file)
index 0000000..2f7229d
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+yaz_database
+--SKIPIF--
+<?php if (!extension_loaded("yaz")) print "skip"; ?>
+--FILE--
+<?php
+$z = yaz_connect("z3950.indexdata.com");
+yaz_database($z, "marc");
+yaz_search($z, "rpn", "@attr 1=99 computer");
+yaz_wait();
+echo yaz_errno($z) . ":" . yaz_error($z) . ":" . yaz_addinfo($z) . "\n";
+echo yaz_hits($z) . "\n";
+yaz_search($z, "rpn", "computer");
+yaz_wait();
+echo yaz_errno($z) . ":" . yaz_error($z) . ":" . yaz_addinfo($z) . "\n";
+echo yaz_hits($z) . "\n";
+--EXPECT--
+114:Unsupported Use attribute:99
+0
+0::
+10
diff --git a/tests/record.phpt b/tests/record.phpt
new file mode 100644 (file)
index 0000000..f43bb68
--- /dev/null
@@ -0,0 +1,63 @@
+--TEST--
+yaz_record
+--SKIPIF--
+<?php if (!extension_loaded("yaz")) print "skip"; ?>
+--FILE--
+<?php
+$z = yaz_connect("z3950.indexdata.com/marc");
+yaz_search($z, "rpn", "computer");
+yaz_syntax($z, "marc21");
+yaz_wait();
+echo yaz_errno($z) . ":" . yaz_error($z) . ":" . yaz_addinfo($z) . "\n";
+echo yaz_hits($z) . "\n";
+echo yaz_record($z, 1, "string");
+echo yaz_record($z, 1, "xml");
+--EXPECT--
+0::
+10
+00366nam  22001698a 4504
+001    11224466 
+003 DLC
+005 00000000000000.0
+008 910710c19910701nju           00010 eng  
+010    $a    11224466 
+040    $a DLC $c DLC
+050 00 $a 123-xyz
+100 10 $a Jack Collins
+245 10 $a How to program a computer
+260 1  $a Penguin
+263    $a 8710
+300    $a p. cm.
+
+<record xmlns="http://www.loc.gov/MARC21/slim">
+  <leader>00366nam a22001698a 4504</leader>
+  <controlfield tag="001">   11224466 </controlfield>
+  <controlfield tag="003">DLC</controlfield>
+  <controlfield tag="005">00000000000000.0</controlfield>
+  <controlfield tag="008">910710c19910701nju           00010 eng  </controlfield>
+  <datafield tag="010" ind1=" " ind2=" ">
+    <subfield code="a">   11224466 </subfield>
+  </datafield>
+  <datafield tag="040" ind1=" " ind2=" ">
+    <subfield code="a">DLC</subfield>
+    <subfield code="c">DLC</subfield>
+  </datafield>
+  <datafield tag="050" ind1="0" ind2="0">
+    <subfield code="a">123-xyz</subfield>
+  </datafield>
+  <datafield tag="100" ind1="1" ind2="0">
+    <subfield code="a">Jack Collins</subfield>
+  </datafield>
+  <datafield tag="245" ind1="1" ind2="0">
+    <subfield code="a">How to program a computer</subfield>
+  </datafield>
+  <datafield tag="260" ind1="1" ind2=" ">
+    <subfield code="a">Penguin</subfield>
+  </datafield>
+  <datafield tag="263" ind1=" " ind2=" ">
+    <subfield code="a">8710</subfield>
+  </datafield>
+  <datafield tag="300" ind1=" " ind2=" ">
+    <subfield code="a">p. cm.</subfield>
+  </datafield>
+</record>