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