32f9f27d6e54bde2748d1e6739801c21f827f600
[idzebra-moved-to-github.git] / perl / zebra_api_ext.c
1 #include <assert.h>
2 #include <stdio.h>
3 #ifdef WIN32
4 #include <io.h>
5 #include <process.h>
6 #include <direct.h>
7 #else
8 #include <unistd.h>
9 #endif
10
11 #include <yaz/diagbib1.h>
12 #include "index.h"
13 #include <charmap.h>
14 #include <data1.h>
15 #include "zebra_perl.h"
16 #include "zebra_api_ext.h"
17 #include "yaz/log.h"
18 #include <yaz/pquery.h>
19 #include <yaz/cql.h>
20 #include <yaz/sortspec.h>
21
22 void data1_print_tree(data1_handle dh, data1_node *n, FILE *out) {
23   data1_pr_tree(dh, n, stdout);
24 }
25
26 int zebra_get_shadow_enable (ZebraHandle zh) {
27   return (zh->shadow_enable);
28 }
29
30 void zebra_set_shadow_enable (ZebraHandle zh, int value) {
31   zh->shadow_enable = value;
32 }
33
34 void init_recordGroup (recordGroup *rg) {
35     rg->groupName = NULL;
36     rg->databaseName = NULL;
37     rg->path = NULL;
38     rg->recordId = NULL;
39     rg->recordType = NULL;
40     rg->flagStoreData = -1;
41     rg->flagStoreKeys = -1; 
42     rg->flagRw = 1;
43     rg->databaseNamePath = 0;
44     rg->explainDatabase = 0; 
45     rg->fileVerboseLimit = 100000; 
46     rg->followLinks = -1;
47
48
49
50 /* This is from extract.c... it seems useful, when extract_rec_in mem is 
51    called... and in general... Should be moved to somewhere else */
52 void res_get_recordGroup (ZebraHandle zh,
53                           recordGroup *rGroup,
54                           const char *ext) {
55   char gprefix[128];
56   char ext_res[128]; 
57     
58   if (!rGroup->groupName || !*rGroup->groupName)
59     *gprefix = '\0';
60   else 
61     sprintf (gprefix, "%s.", rGroup->groupName);
62   
63   /* determine file type - depending on extension */
64   if (!rGroup->recordType) {
65     sprintf (ext_res, "%srecordType.%s", gprefix, ext);
66     if (!(rGroup->recordType = res_get (zh->res, ext_res))) {
67       sprintf (ext_res, "%srecordType", gprefix);
68       rGroup->recordType = res_get (zh->res, ext_res);
69     }
70   }
71   /* determine match criteria */
72   if (!rGroup->recordId) { 
73     sprintf (ext_res, "%srecordId.%s", gprefix, ext);
74     if (!(rGroup->recordId = res_get (zh->res, ext_res))) {
75       sprintf (ext_res, "%srecordId", gprefix);
76       rGroup->recordId = res_get (zh->res, ext_res);
77     }
78   } 
79   
80   /* determine database name */
81   if (!rGroup->databaseName) {
82     sprintf (ext_res, "%sdatabase.%s", gprefix, ext);
83     if (!(rGroup->databaseName = res_get (zh->res, ext_res))) { 
84       sprintf (ext_res, "%sdatabase", gprefix);
85       rGroup->databaseName = res_get (zh->res, ext_res);
86     }
87   }
88   if (!rGroup->databaseName)
89     rGroup->databaseName = "Default";
90
91   /* determine if explain database */
92   sprintf (ext_res, "%sexplainDatabase", gprefix);
93   rGroup->explainDatabase =
94     atoi (res_get_def (zh->res, ext_res, "0"));
95
96   /* storeData */
97   if (rGroup->flagStoreData == -1) {
98     const char *sval;
99     sprintf (ext_res, "%sstoreData.%s", gprefix, ext);
100     if (!(sval = res_get (zh->res, ext_res))) {
101       sprintf (ext_res, "%sstoreData", gprefix);
102       sval = res_get (zh->res, ext_res);
103     }
104     if (sval)
105       rGroup->flagStoreData = atoi (sval);
106   }
107   if (rGroup->flagStoreData == -1)  rGroup->flagStoreData = 0;
108
109   /* storeKeys */
110   if (rGroup->flagStoreKeys == -1)  {
111     const char *sval;
112     
113     sprintf (ext_res, "%sstoreKeys.%s", gprefix, ext);
114     sval = res_get (zh->res, ext_res);
115     if (!sval) {
116       sprintf (ext_res, "%sstoreKeys", gprefix);
117       sval = res_get (zh->res, ext_res);
118     }
119     if (!sval)  sval = res_get (zh->res, "storeKeys");
120     if (sval) rGroup->flagStoreKeys = atoi (sval);
121   }
122   if (rGroup->flagStoreKeys == -1) rGroup->flagStoreKeys = 0;
123   
124
125
126 int zebra_trans_processed(ZebraTransactionStatus s) {
127   return (s.processed);
128 }
129
130 /* ---------------------------------------------------------------------------
131   Record insert(=update), delete 
132
133   If sysno is provided, then it's used to identify the reocord.
134   If not, and match_criteria is provided, then sysno is guessed
135   If not, and a record is provided, then sysno is got from there
136 */
137
138 int zebra_update_record (ZebraHandle zh, 
139                          struct recordGroup *rGroup,
140                          const char *recordType,
141                          int sysno, const char *match, const char *fname,
142                          const char *buf, int buf_size)
143
144 {
145     int res;
146
147     if (buf_size < 1) buf_size = strlen(buf);
148
149     zebra_begin_trans(zh);
150     res=bufferExtractRecord (zh, buf, buf_size, rGroup, 
151                              0, // delete_flag 
152                              0, // test_mode,
153                              recordType,
154                              &sysno,   
155                              match, fname);     
156     zebra_end_trans(zh); 
157     return sysno; 
158 }
159
160 int zebra_delete_record (ZebraHandle zh, 
161                          struct recordGroup *rGroup, 
162                          const char *recordType,
163                          int sysno, const char *match, const char *fname,
164                          const char *buf, int buf_size)
165 {
166     int res;
167
168     if (buf_size < 1) buf_size = strlen(buf);
169
170     zebra_begin_trans(zh);
171     res=bufferExtractRecord (zh, buf, buf_size, rGroup, 
172                              1, // delete_flag
173                              0, // test_mode, 
174                              recordType,
175                              &sysno,
176                              match,fname);    
177     zebra_end_trans(zh);
178     return sysno;   
179 }
180
181 /* ---------------------------------------------------------------------------
182   Searching 
183
184   zebra_search_RPN is the same as zebra_search_rpn, except that read locking
185   is not mandatory. (it's repeatable now, also in zebraapi.c)
186 */
187
188 void zebra_search_RPN (ZebraHandle zh, ODR decode, ODR stream,
189                        Z_RPNQuery *query, const char *setname, int *hits)
190 {
191     zh->hits = 0;
192     *hits = 0;
193
194     if (zebra_begin_read (zh))
195         return;
196     resultSetAddRPN (zh, decode, stream, query, 
197                      zh->num_basenames, zh->basenames, setname);
198
199     zebra_end_read (zh);
200
201     *hits = zh->hits;
202 }
203
204 int zebra_search_PQF (ZebraHandle zh, 
205                       ODR odr_input, ODR odr_output, 
206                       const char *pqf_query,
207                       const char *setname)
208
209 {
210   int hits;
211   Z_RPNQuery *query;
212   query = p_query_rpn (odr_input, PROTO_Z3950, pqf_query);
213
214   if (!query) {
215     logf (LOG_WARN, "bad query %s\n", pqf_query);
216     odr_reset (odr_input);
217     return(0);
218   }
219   zebra_search_RPN (zh, odr_input, odr_output, query, setname, &hits);
220
221   odr_reset (odr_input);
222   odr_reset (odr_output);
223   
224   return(hits);
225 }
226
227 int zebra_cql2pqf (cql_transform_t ct, 
228                    const char *query, char *res, int len) {
229   
230   int status;
231   const char *addinfo = "";
232   CQL_parser cp = cql_parser_create();
233
234   if (status = cql_parser_string(cp, query)) {
235     cql_parser_destroy(cp);
236     return (status);
237   }
238
239   if (cql_transform_buf(ct, cql_parser_result(cp), res, len)) {
240     status = cql_transform_error(ct, &addinfo);
241     logf (LOG_WARN,"Transform error %d %s\n", status, addinfo ? addinfo : "");
242     cql_parser_destroy(cp);
243     return (status);
244   }
245
246   cql_parser_destroy(cp);
247   return (0);
248 }
249
250 void zebra_scan_PQF (ZebraHandle zh,
251                      ScanObj *so,
252                      ODR stream,
253                      const char *pqf_query)
254 {
255   Z_AttributesPlusTerm *zapt;
256   Odr_oid *attrsetid;
257   const char* oidname;
258   oid_value attributeset;
259   ZebraScanEntry *entries;
260   int i, class;
261
262   logf(LOG_DEBUG,  
263        "scan req: pos:%d, num:%d, partial:%d", 
264        so->position, so->num_entries, so->is_partial);
265
266   zapt = p_query_scan (stream, PROTO_Z3950, &attrsetid, pqf_query);
267
268   oidname = yaz_z3950oid_to_str (attrsetid, &class); 
269   logf (LOG_DEBUG, "Attributreset: %s", oidname);
270   attributeset = oid_getvalbyname(oidname);
271
272   if (!zapt) {
273     logf (LOG_WARN, "bad query %s\n", pqf_query);
274     odr_reset (stream);
275     return;
276   }
277
278   so->entries = (scanEntry *)
279     odr_malloc (stream, sizeof(so->entries) * (so->num_entries));
280
281
282   zebra_scan (zh, stream, zapt, attributeset, 
283               &so->position, &so->num_entries, 
284               (ZebraScanEntry **) &so->entries, &so->is_partial);
285
286   logf(LOG_DEBUG, 
287        "scan res: pos:%d, num:%d, partial:%d", 
288        so->position, so->num_entries, so->is_partial);
289 }
290
291 scanEntry *getScanEntry(ScanObj *so, int pos) {
292   return (&so->entries[pos-1]);
293 }
294
295 /* ---------------------------------------------------------------------------
296   Record retrieval 
297   2 phase retrieval - I didn't manage to return array of blessed references
298   to wrapped structures... it's feasible, but I'll need some time 
299   / pop - 2002-11-17
300 */
301
302 void record_retrieve(RetrievalObj *ro,
303                      ODR stream,
304                      RetrievalRecord *res,
305                      int pos) 
306 {
307   int i = pos - 1;
308
309
310   RetrievalRecordBuf *buf = 
311     (RetrievalRecordBuf *) odr_malloc(stream, sizeof(*buf));  
312
313   res->errCode    = ro->records[i].errCode;
314   if (ro->records[i].errString) {
315     res->errString  = odr_strdup(stream, ro->records[i].errString);
316   } else {
317     res->errString = "";
318   }
319   res->position   = ro->records[i].position;
320   res->base       = ro->records[i].base;
321   res->format     = (char *) 
322     yaz_z3950_oid_value_to_str(ro->records[i].format, CLASS_RECSYN); 
323   res->buf        = buf;
324   res->buf->len   = ro->records[i].len;
325   res->buf->buf   = ro->records[i].buf;
326   res->score      = ro->records[i].score;
327   res->sysno      = ro->records[i].sysno;
328
329 }
330
331 /* most of the code here was copied from yaz-client */
332 void records_retrieve(ZebraHandle zh,
333                       ODR stream,
334                       const char *setname,
335                       const char *a_eset, 
336                       const char *a_schema,
337                       const char *a_format,
338                       int from,
339                       int to,
340                       RetrievalObj *res) 
341 {
342   static enum oid_value recordsyntax = VAL_SUTRS;
343   static enum oid_value schema = VAL_NONE;
344   static Z_ElementSetNames *elementSetNames = 0; 
345   static Z_RecordComposition compo;
346   static Z_ElementSetNames esn;
347   static char what[100];
348   int i;
349   int oid[OID_SIZE];
350
351   compo.which = -1;
352
353   if (from < 1) from = 1;
354   if (from > to) to = from;
355   res->noOfRecords = to - from + 1;
356
357   res->records = odr_malloc (stream, 
358                              sizeof(*res->records) * (res->noOfRecords));  
359
360   for (i = 0; i<res->noOfRecords; i++) res->records[i].position = from+i;
361
362   if (!a_eset || !*a_eset) {
363     elementSetNames = 0;
364   } else {
365     strcpy(what, a_eset);
366     esn.which = Z_ElementSetNames_generic;
367     esn.u.generic = what;
368     elementSetNames = &esn;
369   }
370
371   if (!a_schema || !*a_schema) {
372     schema = VAL_NONE;
373   } else {
374     schema = oid_getvalbyname (a_schema);
375     if (schema == VAL_NONE) {
376       logf(LOG_WARN,"unknown schema '%s'",a_schema);
377     }
378   }
379
380   
381   if (!a_format || !*a_format) {
382     recordsyntax = VAL_SUTRS;
383   } else {
384     recordsyntax = oid_getvalbyname (a_format);
385     if (recordsyntax == VAL_NONE) {
386       logf(LOG_WARN,"unknown record syntax '%s', using SUTRS",a_schema);
387       recordsyntax = VAL_SUTRS;
388     }
389   }
390
391   if (schema != VAL_NONE) {
392     oident prefschema;
393
394     prefschema.proto = PROTO_Z3950;
395     prefschema.oclass = CLASS_SCHEMA;
396     prefschema.value = schema;
397     
398     compo.which = Z_RecordComp_complex;
399     compo.u.complex = (Z_CompSpec *)
400       odr_malloc(stream, sizeof(*compo.u.complex));
401     compo.u.complex->selectAlternativeSyntax = (bool_t *) 
402       odr_malloc(stream, sizeof(bool_t));
403     *compo.u.complex->selectAlternativeSyntax = 0;
404     
405     compo.u.complex->generic = (Z_Specification *)
406       odr_malloc(stream, sizeof(*compo.u.complex->generic));
407     compo.u.complex->generic->which = Z_Schema_oid;
408     compo.u.complex->generic->schema.oid = (Odr_oid *)
409       odr_oiddup(stream, oid_ent_to_oid(&prefschema, oid));
410     if (!compo.u.complex->generic->schema.oid)
411       {
412         /* OID wasn't a schema! Try record syntax instead. */
413         prefschema.oclass = CLASS_RECSYN;
414         compo.u.complex->generic->schema.oid = (Odr_oid *)
415           odr_oiddup(stream, oid_ent_to_oid(&prefschema, oid));
416       }
417     if (!elementSetNames)
418       compo.u.complex->generic->elementSpec = 0;
419     else
420       {
421         compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
422           odr_malloc(stream, sizeof(Z_ElementSpec));
423         compo.u.complex->generic->elementSpec->which =
424           Z_ElementSpec_elementSetName;
425         compo.u.complex->generic->elementSpec->u.elementSetName =
426           elementSetNames->u.generic;
427       }
428     compo.u.complex->num_dbSpecific = 0;
429     compo.u.complex->dbSpecific = 0;
430     compo.u.complex->num_recordSyntax = 0;
431     compo.u.complex->recordSyntax = 0;
432   } 
433   else if (elementSetNames) {
434     compo.which = Z_RecordComp_simple;
435     compo.u.simple = elementSetNames;
436   }
437
438   if (compo.which == -1) {
439     api_records_retrieve (zh, stream, setname, 
440                             NULL, 
441                             recordsyntax,
442                             res->noOfRecords, res->records);
443   } else {
444     api_records_retrieve (zh, stream, setname, 
445                             &compo,
446                             recordsyntax,
447                             res->noOfRecords, res->records);
448   }
449
450 }
451  
452 int zebra_trans_no (ZebraHandle zh) {
453   return (zh->trans_no);
454 }
455
456 /* almost the same as zebra_records_retrieve ... but how did it work? 
457    I mean for multiple records ??? CHECK ??? */
458 void api_records_retrieve (ZebraHandle zh, ODR stream,
459                            const char *setname, Z_RecordComposition *comp,
460                            oid_value input_format, int num_recs,
461                            ZebraRetrievalRecord *recs)
462 {
463     ZebraPosSet poset;
464     int i, *pos_array;
465
466     if (!zh->res)
467     {
468         zh->errCode = 30;
469         zh->errString = odr_strdup (stream, setname);
470         return;
471     }
472     
473     zh->errCode = 0; 
474
475     if (zebra_begin_read (zh))
476         return;
477
478     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
479     for (i = 0; i<num_recs; i++)
480         pos_array[i] = recs[i].position;
481     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
482     if (!poset)
483     {
484         logf (LOG_DEBUG, "zebraPosSetCreate error");
485         zh->errCode = 30;
486         zh->errString = nmem_strdup (stream->mem, setname);
487     }
488     else
489     {
490         for (i = 0; i<num_recs; i++)
491         {
492             if (poset[i].term)
493             {
494                 recs[i].errCode = 0;
495                 recs[i].format = VAL_SUTRS;
496                 recs[i].len = strlen(poset[i].term);
497                 recs[i].buf = poset[i].term;
498                 recs[i].base = poset[i].db;
499                 recs[i].sysno = 0;
500             
501             }
502             else if (poset[i].sysno)
503             {
504               /* changed here ??? CHECK ??? */
505               char *b;
506                 recs[i].errCode =
507                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
508                                         stream, input_format, comp,
509                                         &recs[i].format, 
510                                         &b,
511                                         &recs[i].len,
512                                         &recs[i].base);
513                 recs[i].buf = (char *) odr_malloc(stream,recs[i].len);
514                 memcpy(recs[i].buf, b, recs[i].len);
515                 recs[i].errString = 0; /* Hmmm !!! we should get this */ 
516                 recs[i].sysno = poset[i].sysno;
517                 recs[i].score = poset[i].score;
518             }
519             else
520             {
521                 char num_str[20];
522
523                 sprintf (num_str, "%d", pos_array[i]);  
524                 zh->errCode = 13;
525                 zh->errString = odr_strdup (stream, num_str);
526                 break;
527             }
528
529         }
530         zebraPosSetDestroy (zh, poset, num_recs);
531     }
532     zebra_end_read (zh);
533     xfree (pos_array);
534 }
535
536
537 /* ---------------------------------------------------------------------------
538   Sort - a simplified interface, with optional read locks.
539 */
540 int sort (ZebraHandle zh, 
541           ODR stream,
542           const char *sort_spec,
543           const char *output_setname,
544           const char **input_setnames
545           ) 
546 {
547   int num_input_setnames = 0;
548   int sort_status = 0;
549   Z_SortKeySpecList *sort_sequence = yaz_sort_spec (stream, sort_spec);
550   if (!sort_sequence) {
551     logf(LOG_WARN,"invalid sort specs '%s'", sort_spec);
552     zh->errCode = 207;
553     return (-1);
554   }
555   
556   /* we can do this, since the typemap code for char** will 
557      put a NULL at the end of list */
558   while (input_setnames[num_input_setnames]) num_input_setnames++;
559
560   if (zebra_begin_read (zh))
561     return;
562   
563   resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
564                  output_setname, sort_sequence, &sort_status);
565   
566   zebra_end_read(zh);
567   return (sort_status);
568 }