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