Implemented delete result set(s).
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /*
2  * Copyright (C) 1995-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zebraapi.c,v $
7  * Revision 1.25  1999-11-04 15:00:45  adam
8  * Implemented delete result set(s).
9  *
10  * Revision 1.24  1999/10/14 14:33:50  adam
11  * Added truncation 5=106.
12  *
13  * Revision 1.23  1999/09/07 11:36:32  adam
14  * Minor changes.
15  *
16  * Revision 1.22  1999/08/02 10:13:47  adam
17  * Fixed bug regarding zebra_hits.
18  *
19  * Revision 1.21  1999/07/14 10:59:26  adam
20  * Changed functions isc_getmethod, isams_getmethod.
21  * Improved fatal error handling (such as missing EXPLAIN schema).
22  *
23  * Revision 1.20  1999/07/06 12:28:04  adam
24  * Updated record index structure. Format includes version ID. Compression
25  * algorithm ID is stored for each record block.
26  *
27  * Revision 1.19  1999/05/26 07:49:13  adam
28  * C++ compilation.
29  *
30  * Revision 1.18  1999/05/15 14:36:38  adam
31  * Updated dictionary. Implemented "compression" of dictionary.
32  *
33  * Revision 1.17  1999/05/12 13:08:06  adam
34  * First version of ISAMS.
35  *
36  * Revision 1.16  1999/02/19 10:38:30  adam
37  * Implemented chdir-setting.
38  *
39  * Revision 1.15  1999/02/17 12:18:12  adam
40  * Fixed zebra_close so that a NULL pointer is ignored.
41  *
42  * Revision 1.14  1999/02/02 14:51:11  adam
43  * Updated WIN32 code specific sections. Changed header.
44  *
45  * Revision 1.13  1998/12/16 12:23:30  adam
46  * Added facility for database name mapping using resource mapdb.
47  *
48  * Revision 1.12  1998/11/16 10:18:10  adam
49  * Better error reporting for result sets.
50  *
51  * Revision 1.11  1998/10/16 08:14:34  adam
52  * Updated record control system.
53  *
54  * Revision 1.10  1998/09/22 10:03:42  adam
55  * Changed result sets to be persistent in the sense that they can
56  * be re-searched if needed.
57  * Fixed memory leak in rsm_or.
58  *
59  * Revision 1.9  1998/09/02 13:53:17  adam
60  * Extra parameter decode added to search routines to implement
61  * persistent queries.
62  *
63  * Revision 1.8  1998/08/24 17:29:23  adam
64  * Minor changes.
65  *
66  * Revision 1.7  1998/06/24 12:16:13  adam
67  * Support for relations on text operands. Open range support in
68  * DFA module (i.e. [-j], [g-]).
69  *
70  * Revision 1.6  1998/06/22 11:36:47  adam
71  * Added authentication check facility to zebra.
72  *
73  * Revision 1.5  1998/06/13 00:14:08  adam
74  * Minor changes.
75  *
76  * Revision 1.4  1998/06/12 12:22:12  adam
77  * Work on Zebra API.
78  *
79  * Revision 1.3  1998/05/27 16:57:44  adam
80  * Zebra returns surrogate diagnostic for single records when
81  * appropriate.
82  *
83  * Revision 1.2  1998/05/20 10:12:19  adam
84  * Implemented automatic EXPLAIN database maintenance.
85  * Modified Zebra to work with ASN.1 compiled version of YAZ.
86  *
87  * Revision 1.1  1998/03/05 08:45:13  adam
88  * New result set model and modular ranking system. Moved towards
89  * descent server API. System information stored as "SGML" records.
90  *
91  */
92
93 #include <stdio.h>
94 #ifdef WIN32
95 #include <io.h>
96 #include <process.h>
97 #include <direct.h>
98 #else
99 #include <unistd.h>
100 #endif
101
102 #include <diagbib1.h>
103 #include "zserver.h"
104
105 static void zebra_chdir (ZebraHandle zh)
106 {
107     const char *dir = res_get (zh->res, "chdir");
108     if (!dir)
109         return;
110     logf (LOG_DEBUG, "chdir %s", dir);
111 #ifdef WIN32
112     _chdir(dir);
113 #else
114     chdir (dir);
115 #endif
116 }
117
118 static void zebra_register_unlock (ZebraHandle zh);
119
120 static int zebra_register_lock (ZebraHandle zh)
121 {
122     time_t lastChange;
123     int state;
124
125     zh->errCode = 0;
126     zh->errString = 0;
127
128     zebra_chdir (zh);
129
130     state = zebra_server_lock_get_state(zh, &lastChange);
131
132     switch (state)
133     {
134     case 'c':
135         state = 1;
136         break;
137     default:
138         state = 0;
139     }
140     zebra_server_lock (zh, state);
141 #if HAVE_SYS_TIMES_H
142     times (&zh->tms1);
143 #endif
144     if (zh->registerState == state)
145     {
146         if (zh->registerChange >= lastChange)
147             return 0;
148         logf (LOG_LOG, "Register completely updated since last access");
149     }
150     else if (zh->registerState == -1)
151         logf (LOG_LOG, "Reading register using state %d pid=%ld", state,
152               (long) getpid());
153     else
154         logf (LOG_LOG, "Register has changed state from %d to %d",
155               zh->registerState, state);
156     zh->registerChange = lastChange;
157     if (zh->records)
158     {
159         zebraExplain_close (zh->zei, 0, 0);
160         if (zh->dict)
161             dict_close (zh->dict);
162         if (zh->sortIdx)
163             sortIdx_close (zh->sortIdx);
164         if (zh->isam)
165             is_close (zh->isam);
166         if (zh->isamc)
167             isc_close (zh->isamc);
168         if (zh->isams)
169             isams_close (zh->isams);
170         rec_close (&zh->records);
171     }
172     bf_cache (zh->bfs, state ? res_get (zh->res, "shadow") : NULL);
173     zh->registerState = state;
174
175     zh->isam = NULL;
176     zh->isamc = NULL;
177     zh->isams = NULL;
178     zh->dict = NULL;
179     zh->sortIdx = NULL;
180     zh->zei = NULL;
181
182     if (!(zh->records = rec_open (zh->bfs, 0, 0)))
183     {
184         logf (LOG_WARN, "rec_open");
185         zh->errCode = 2;
186     }
187     else
188     {
189         if (!(zh->dict = dict_open (zh->bfs, FNAME_DICT, 40, 0, 0)))
190         {
191             logf (LOG_WARN, "dict_open");
192             zh->errCode = 2;
193         }
194         if (!(zh->sortIdx = sortIdx_open (zh->bfs, 0)))
195         {
196             logf (LOG_WARN, "sortIdx_open");
197             zh->errCode = 2;
198         }
199         if (res_get_match (zh->res, "isam", "i", NULL))
200         {
201             if (!(zh->isam = is_open (zh->bfs, FNAME_ISAM, key_compare, 0,
202                                       sizeof (struct it_key), zh->res)))
203             {
204                 logf (LOG_WARN, "is_open");
205                 zh->errCode = 2;
206             }
207         }
208         else if (res_get_match (zh->res, "isam", "s", NULL))
209         {
210             struct ISAMS_M_s isams_m;
211             if (!(zh->isams = isams_open (zh->bfs, FNAME_ISAMS, 0,
212                                           key_isams_m(zh->res, &isams_m))))
213             {
214                 logf (LOG_WARN, "isams_open");
215                 zh->errCode = 2;
216             }
217         }
218         else
219         {
220             struct ISAMC_M_s isamc_m;
221             if (!(zh->isamc = isc_open (zh->bfs, FNAME_ISAMC,
222                                         0, key_isamc_m(zh->res, &isamc_m))))
223             {
224                 logf (LOG_WARN, "isc_open");
225                 zh->errCode = 2;
226             }
227         }
228         zh->zei = zebraExplain_open (zh->records, zh->dh, zh->res, 0, 0, 0);
229         if (!zh->zei)
230         {
231             logf (LOG_WARN, "Cannot obtain EXPLAIN information");
232             zh->errCode = 2;
233         }
234     }
235     if (zh->errCode)
236     {
237         zebra_register_unlock (zh);
238         zh->registerState = -1;
239         return -1;
240     }
241     return 0;
242 }
243
244 static void zebra_register_unlock (ZebraHandle zh)
245 {
246     static int waitSec = -1;
247
248 #if HAVE_SYS_TIMES_H
249     times (&zh->tms2);
250     logf (LOG_LOG, "user/system: %ld/%ld",
251                         (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
252                         (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
253 #endif
254     if (waitSec == -1)
255     {
256         char *s = res_get (zh->res, "debugRequestWait");
257         if (s)
258             waitSec = atoi (s);
259         else
260             waitSec = 0;
261     }
262 #ifdef WIN32
263 #else
264     if (waitSec > 0)
265         sleep (waitSec);
266 #endif
267     if (zh->registerState != -1)
268         zebra_server_unlock (zh, zh->registerState);
269 }
270
271 ZebraHandle zebra_open (const char *configName)
272 {
273     ZebraHandle zh;
274
275     zh = (ZebraHandle) xmalloc (sizeof(*zh));
276     if (!(zh->res = res_open (configName)))
277     {
278         logf (LOG_WARN, "Failed to read resources `%s'", configName);
279         return NULL;
280     }
281     zebra_chdir (zh);
282     zebra_server_lock_init (zh);
283     zh->dh = data1_create ();
284     if (!zh->dh)
285     {
286         zebra_server_lock_destroy (zh);
287         xfree (zh);
288         return 0;
289     }
290     zh->bfs = bfs_create (res_get (zh->res, "register"));
291     if (!zh->bfs)
292     {
293         zebra_server_lock_destroy (zh);
294         data1_destroy(zh->dh);
295         xfree (zh);
296         return 0;
297     }
298     bf_lockDir (zh->bfs, res_get (zh->res, "lockDir"));
299     data1_set_tabpath (zh->dh, res_get(zh->res, "profilePath"));
300     zh->sets = NULL;
301     zh->registerState = -1;  /* trigger open of registers! */
302     zh->registerChange = 0;
303     zh->recTypes = recTypes_init (zh->dh);
304     recTypes_default_handlers (zh->recTypes);
305
306     zh->records = NULL;
307     zh->zebra_maps = zebra_maps_open (zh->res);
308     zh->rank_classes = NULL;
309     zh->errCode = 0;
310     zh->errString = 0;
311     
312     zebraRankInstall (zh, rank1_class);
313
314     if (!res_get (zh->res, "passwd"))
315         zh->passwd_db = NULL;
316     else
317     {
318         zh->passwd_db = passwd_db_open ();
319         if (!zh->passwd_db)
320             logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
321         else
322             passwd_db_file (zh->passwd_db, res_get (zh->res, "passwd"));
323     }
324     return zh;
325 }
326
327 void zebra_close (ZebraHandle zh)
328 {
329     if (!zh)
330         return;
331     zebra_chdir (zh);
332     if (zh->records)
333     {
334         resultSetDestroy (zh, -1, 0, 0);
335         zebraExplain_close (zh->zei, 0, 0);
336         dict_close (zh->dict);
337         sortIdx_close (zh->sortIdx);
338         if (zh->isam)
339             is_close (zh->isam);
340         if (zh->isamc)
341             isc_close (zh->isamc);
342         if (zh->isams)
343             isams_close (zh->isams);
344         rec_close (&zh->records);
345         zebra_register_unlock (zh);
346     }
347     recTypes_destroy (zh->recTypes);
348     zebra_maps_close (zh->zebra_maps);
349     zebraRankDestroy (zh);
350     bfs_destroy (zh->bfs);
351     data1_destroy (zh->dh);
352     zebra_server_lock_destroy (zh);
353
354     if (zh->passwd_db)
355         passwd_db_close (zh->passwd_db);
356     res_close (zh->res);
357     xfree (zh);
358 }
359
360 struct map_baseinfo {
361     ZebraHandle zh;
362     NMEM mem;
363     int num_bases;
364     char **basenames;
365     int new_num_bases;
366     char **new_basenames;
367     int new_num_max;
368 };
369         
370 void map_basenames_func (void *vp, const char *name, const char *value)
371 {
372     struct map_baseinfo *p = (struct map_baseinfo *) vp;
373     int i, no;
374     char fromdb[128], todb[8][128];
375     
376     no =
377         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
378                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
379                 todb[5], todb[6], todb[7]);
380     if (no < 2)
381         return ;
382     no--;
383     for (i = 0; i<p->num_bases; i++)
384         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
385         {
386             p->basenames[i] = 0;
387             for (i = 0; i < no; i++)
388             {
389                 if (p->new_num_bases == p->new_num_max)
390                     return;
391                 p->new_basenames[(p->new_num_bases)++] = 
392                     nmem_strdup (p->mem, todb[i]);
393             }
394             return;
395         }
396 }
397
398 void map_basenames (ZebraHandle zh, ODR stream,
399                     int *num_bases, char ***basenames)
400 {
401     struct map_baseinfo info;
402     struct map_baseinfo *p = &info;
403     int i;
404
405     info.zh = zh;
406     info.num_bases = *num_bases;
407     info.basenames = *basenames;
408     info.new_num_max = 128;
409     info.new_num_bases = 0;
410     info.new_basenames = (char **)
411         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
412     info.mem = stream->mem;
413
414     res_trav (zh->res, "mapdb", &info, map_basenames_func);
415     
416     for (i = 0; i<p->num_bases; i++)
417         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
418         {
419             p->new_basenames[(p->new_num_bases)++] = 
420                 nmem_strdup (p->mem, p->basenames[i]);
421         }
422     *num_bases = info.new_num_bases;
423     *basenames = info.new_basenames;
424     for (i = 0; i<*num_bases; i++)
425         logf (LOG_LOG, "base %s", (*basenames)[i]);
426 }
427
428 void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
429                        Z_RPNQuery *query, int num_bases, char **basenames, 
430                        const char *setname)
431 {
432     zh->hits = 0;
433     if (zebra_register_lock (zh))
434         return;
435     map_basenames (zh, stream, &num_bases, &basenames);
436     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
437
438     zebra_register_unlock (zh);
439 }
440
441 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
442                              const char *setname, Z_RecordComposition *comp,
443                              oid_value input_format, int num_recs,
444                              ZebraRetrievalRecord *recs)
445 {
446     ZebraPosSet poset;
447     int i, *pos_array;
448
449     if (zebra_register_lock (zh))
450         return;
451     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
452     for (i = 0; i<num_recs; i++)
453         pos_array[i] = recs[i].position;
454     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
455     if (!poset)
456     {
457         logf (LOG_DEBUG, "zebraPosSetCreate error");
458         zh->errCode = 30;
459         zh->errString = nmem_strdup (stream->mem, setname);
460     }
461     else
462     {
463         for (i = 0; i<num_recs; i++)
464         {
465             if (!poset[i].sysno)
466             {
467                 char num_str[20];
468
469                 sprintf (num_str, "%d", pos_array[i]);  
470                 zh->errCode = 13;
471                 zh->errString = nmem_strdup (stream->mem, num_str);
472                 break;
473             }
474             else
475             {
476                 recs[i].errCode =
477                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
478                                         stream, input_format, comp,
479                                         &recs[i].format, &recs[i].buf,
480                                         &recs[i].len,
481                                         &recs[i].base);
482                 recs[i].errString = NULL;
483             }
484         }
485         zebraPosSetDestroy (zh, poset, num_recs);
486     }
487     zebra_register_unlock (zh);
488     xfree (pos_array);
489 }
490
491 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
492                  oid_value attributeset,
493                  int num_bases, char **basenames,
494                  int *position, int *num_entries, ZebraScanEntry **entries,
495                  int *is_partial)
496 {
497     if (zebra_register_lock (zh))
498     {
499         *entries = 0;
500         *num_entries = 0;
501         return;
502     }
503     map_basenames (zh, stream, &num_bases, &basenames);
504     rpn_scan (zh, stream, zapt, attributeset,
505               num_bases, basenames, position,
506               num_entries, entries, is_partial);
507     zebra_register_unlock (zh);
508 }
509
510 void zebra_sort (ZebraHandle zh, ODR stream,
511                  int num_input_setnames, const char **input_setnames,
512                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
513                  int *sort_status)
514 {
515     if (zebra_register_lock (zh))
516         return;
517     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
518                    output_setname, sort_sequence, sort_status);
519     zebra_register_unlock (zh);
520 }
521
522 int zebra_deleleResultSet(ZebraHandle zh, int function,
523                           int num_setnames, char **setnames,
524                           int *statuses)
525 {
526     int i, status;
527     if (zebra_register_lock (zh))
528         return Z_DeleteStatus_systemProblemAtTarget;
529     switch (function)
530     {
531     case Z_DeleteRequest_list:
532         resultSetDestroy (zh, num_setnames, setnames, statuses);
533         break;
534     case Z_DeleteRequest_all:
535         resultSetDestroy (zh, -1, 0, statuses);
536         break;
537     }
538     zebra_register_unlock (zh);
539     status = Z_DeleteStatus_success;
540     for (i = 0; i<num_setnames; i++)
541         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
542             status = statuses[i];
543     return status;
544 }
545
546 int zebra_errCode (ZebraHandle zh)
547 {
548     return zh->errCode;
549 }
550
551 const char *zebra_errString (ZebraHandle zh)
552 {
553     return diagbib1_str (zh->errCode);
554 }
555
556 char *zebra_errAdd (ZebraHandle zh)
557 {
558     return zh->errString;
559 }
560
561 int zebra_hits (ZebraHandle zh)
562 {
563     return zh->hits;
564 }
565
566 int zebra_auth (ZebraHandle zh, const char *user, const char *pass)
567 {
568     if (!zh->passwd_db || !passwd_db_auth (zh->passwd_db, user, pass))
569         return 0;
570     return 1;
571 }
572
573 void zebra_setDB (ZebraHandle zh, int num_bases, char **basenames)
574 {
575
576 }
577
578 void zebra_setRecordType (ZebraHandle zh, const char *type)
579 {
580
581 }
582
583 void zebra_setGroup (ZebraHandle zh, const char *group)
584 {
585
586 }
587
588 void zebra_admin (ZebraHandle zh, const char *command)
589 {
590
591 }