POSIX thread updates. First work on term sets.
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /*
2  * Copyright (C) 1995-2000, Index Data
3  * All rights reserved.
4  *
5  * $Log: zebraapi.c,v $
6  * Revision 1.44  2001-10-15 19:53:43  adam
7  * POSIX thread updates. First work on term sets.
8  *
9  * Revision 1.43  2000/12/05 12:22:53  adam
10  * Termlist source implemented (so that we can index values of XML/SGML
11  * attributes).
12  *
13  * Revision 1.42  2000/12/05 10:01:44  adam
14  * Fixed bug regarding user-defined attribute sets.
15  *
16  * Revision 1.41  2000/12/01 17:59:08  adam
17  * Fixed bug regarding online updates on WIN32.
18  * When zebra.cfg is not available the server will not abort.
19  *
20  * Revision 1.40  2000/11/29 15:21:31  adam
21  * Fixed problem with passwd db.
22  *
23  * Revision 1.39  2000/11/29 14:24:01  adam
24  * Script configure uses yaz pthreads options. Added locking for
25  * zebra_register_{lock,unlock}.
26  *
27  * Revision 1.38  2000/11/08 13:46:58  adam
28  * Fixed scan: server could break if bad attribute/database was selected.
29  * Work on remote update.
30  *
31  * Revision 1.37  2000/10/17 12:37:09  adam
32  * Fixed notification of live-updates. Fixed minor problem with mf_init
33  * where it didn't handle shadow area file names correctly.
34  *
35  * Revision 1.36  2000/09/06 08:59:36  adam
36  * Using read-only (for now) for server.
37  *
38  * Revision 1.35  2000/07/07 12:49:20  adam
39  * Optimized resultSetInsert{Rank,Sort}.
40  *
41  * Revision 1.34  2000/06/09 13:56:38  ian
42  * Added some logging on Authentication and searches.
43  *
44  * Revision 1.33  2000/05/18 12:01:36  adam
45  * System call times(2) used again. More 64-bit fixes.
46  *
47  * Revision 1.32  2000/04/19 14:35:59  adam
48  * WIN32 update (this version is known not to work on Windows).
49  *
50  * Revision 1.31  2000/04/05 10:07:02  adam
51  * Minor zebra compile fix.
52  *
53  * Revision 1.30  2000/04/05 09:49:35  adam
54  * On Unix, zebra/z'mbol uses automake.
55  *
56  * Revision 1.29  2000/03/20 19:08:36  adam
57  * Added remote record import using Z39.50 extended services and Segment
58  * Requests.
59  *
60  * Revision 1.28  2000/03/15 15:00:30  adam
61  * First work on threaded version.
62  *
63  * Revision 1.27  2000/02/24 12:31:17  adam
64  * Added zebra_string_norm.
65  *
66  * Revision 1.26  1999/11/30 13:48:03  adam
67  * Improved installation. Updated for inclusion of YAZ header files.
68  *
69  * Revision 1.25  1999/11/04 15:00:45  adam
70  * Implemented delete result set(s).
71  *
72  * Revision 1.24  1999/10/14 14:33:50  adam
73  * Added truncation 5=106.
74  *
75  * Revision 1.23  1999/09/07 11:36:32  adam
76  * Minor changes.
77  *
78  * Revision 1.22  1999/08/02 10:13:47  adam
79  * Fixed bug regarding zebra_hits.
80  *
81  * Revision 1.21  1999/07/14 10:59:26  adam
82  * Changed functions isc_getmethod, isams_getmethod.
83  * Improved fatal error handling (such as missing EXPLAIN schema).
84  *
85  * Revision 1.20  1999/07/06 12:28:04  adam
86  * Updated record index structure. Format includes version ID. Compression
87  * algorithm ID is stored for each record block.
88  *
89  * Revision 1.19  1999/05/26 07:49:13  adam
90  * C++ compilation.
91  *
92  * Revision 1.18  1999/05/15 14:36:38  adam
93  * Updated dictionary. Implemented "compression" of dictionary.
94  *
95  * Revision 1.17  1999/05/12 13:08:06  adam
96  * First version of ISAMS.
97  *
98  * Revision 1.16  1999/02/19 10:38:30  adam
99  * Implemented chdir-setting.
100  *
101  * Revision 1.15  1999/02/17 12:18:12  adam
102  * Fixed zebra_close so that a NULL pointer is ignored.
103  *
104  * Revision 1.14  1999/02/02 14:51:11  adam
105  * Updated WIN32 code specific sections. Changed header.
106  *
107  * Revision 1.13  1998/12/16 12:23:30  adam
108  * Added facility for database name mapping using resource mapdb.
109  *
110  * Revision 1.12  1998/11/16 10:18:10  adam
111  * Better error reporting for result sets.
112  *
113  * Revision 1.11  1998/10/16 08:14:34  adam
114  * Updated record control system.
115  *
116  * Revision 1.10  1998/09/22 10:03:42  adam
117  * Changed result sets to be persistent in the sense that they can
118  * be re-searched if needed.
119  * Fixed memory leak in rsm_or.
120  *
121  * Revision 1.9  1998/09/02 13:53:17  adam
122  * Extra parameter decode added to search routines to implement
123  * persistent queries.
124  *
125  * Revision 1.8  1998/08/24 17:29:23  adam
126  * Minor changes.
127  *
128  * Revision 1.7  1998/06/24 12:16:13  adam
129  * Support for relations on text operands. Open range support in
130  * DFA module (i.e. [-j], [g-]).
131  *
132  * Revision 1.6  1998/06/22 11:36:47  adam
133  * Added authentication check facility to zebra.
134  *
135  * Revision 1.5  1998/06/13 00:14:08  adam
136  * Minor changes.
137  *
138  * Revision 1.4  1998/06/12 12:22:12  adam
139  * Work on Zebra API.
140  *
141  * Revision 1.3  1998/05/27 16:57:44  adam
142  * Zebra returns surrogate diagnostic for single records when
143  * appropriate.
144  *
145  * Revision 1.2  1998/05/20 10:12:19  adam
146  * Implemented automatic EXPLAIN database maintenance.
147  * Modified Zebra to work with ASN.1 compiled version of YAZ.
148  *
149  * Revision 1.1  1998/03/05 08:45:13  adam
150  * New result set model and modular ranking system. Moved towards
151  * descent server API. System information stored as "SGML" records.
152  *
153  */
154
155 #include <assert.h>
156 #include <stdio.h>
157 #ifdef WIN32
158 #include <io.h>
159 #include <process.h>
160 #include <direct.h>
161 #else
162 #include <unistd.h>
163 #endif
164
165 #include <yaz/diagbib1.h>
166 #include "zserver.h"
167 #include <charmap.h>
168
169 static void zebra_chdir (ZebraService zh)
170 {
171     const char *dir = res_get (zh->res, "chdir");
172     if (!dir)
173         return;
174     logf (LOG_DEBUG, "chdir %s", dir);
175 #ifdef WIN32
176     _chdir(dir);
177 #else
178     chdir (dir);
179 #endif
180 }
181
182 static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
183                                const char *buf, size_t buf_size,
184                                const char *databaseName, int delete_flag,
185                                int test_mode, int *sysno,
186                                int store_keys, int store_data,
187                                const char *match_criteria);
188
189 static int explain_extract (void *handle, Record rec, data1_node *n);
190 static void extract_index (ZebraHandle zh);
191
192 static void zebra_register_unlock (ZebraHandle zh);
193
194 static int zebra_register_activate (ZebraService zh, int rw);
195 static int zebra_register_deactivate (ZebraService zh);
196
197 static int zebra_register_lock (ZebraHandle zh, int rw)
198 {
199     time_t lastChange;
200     int state;
201     zh->errCode = 0;
202     zh->errString = 0;
203     if (!zh->service->active)
204     {
205         zh->errCode = 1019;
206         return 1;
207     }
208     
209 #if HAVE_SYS_TIMES_H
210     times (&zh->tms1);
211 #endif
212
213     zebra_mutex_cond_lock (&zh->service->session_lock);
214
215     state = zebra_server_lock_get_state(zh->service, &lastChange);
216
217     zebra_server_lock (zh->service, state);
218
219     switch (state)
220     {
221     case 'c':
222         state = 1;
223         break;
224     default:
225         state = 0;
226     }
227     if (rw)
228         logf (LOG_LOG, "Register in read/write mode");
229     else if (zh->service->registerState == state)
230     {
231         logf (LOG_DEBUG, "registerChange = %ld lastChange = %ld",
232             (long) zh->service->registerChange, (long)lastChange);
233         if (zh->service->registerChange >= lastChange)
234         {
235             return 0;
236         }
237         logf (LOG_LOG, "Register completely updated since last access");
238     }
239     else if (zh->service->registerState == -1)
240         logf (LOG_LOG, "Reading register using state %d pid=%ld", state,
241               (long) getpid());
242     else
243         logf (LOG_LOG, "Register has changed state from %d to %d",
244               zh->service->registerState, state);
245     zh->service->registerChange = lastChange;
246
247     zebra_register_deactivate (zh->service);
248
249     zh->service->registerState = state;
250
251     zebra_register_activate (zh->service, rw);
252     return 0;
253 }
254
255
256 static void zebra_register_unlock (ZebraHandle zh)
257 {
258     if (zh->service->registerState != -1)
259         zebra_server_unlock (zh->service, zh->service->registerState);
260     zebra_mutex_cond_unlock (&zh->service->session_lock);
261 #if HAVE_SYS_TIMES_H
262     times (&zh->tms2);
263     logf (LOG_LOG, "user/system: %ld/%ld",
264                     (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
265                     (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
266
267 #endif
268 }
269
270 ZebraHandle zebra_open (ZebraService zs)
271 {
272     ZebraHandle zh;
273
274     assert (zs);
275     if (zs->stop_flag)
276         return 0;
277
278     zh = (ZebraHandle) xmalloc (sizeof(*zh));
279     yaz_log (LOG_LOG, "zebra_open zs=%p returns %p", zs, zh);
280
281     zh->service = zs;
282     zh->sets = 0;
283     zh->destroyed = 0;
284     zh->errCode = 0;
285     zh->errString = 0;
286
287     zh->key_buf = 0;
288     zh->admin_databaseName = 0;
289     
290     zebra_mutex_cond_lock (&zs->session_lock);
291
292     zh->next = zs->sessions;
293     zs->sessions = zh;
294
295     zebra_mutex_cond_unlock (&zs->session_lock);
296
297     return zh;
298 }
299
300
301 ZebraService zebra_start (const char *configName)
302 {
303     ZebraService zh = xmalloc (sizeof(*zh));
304
305     yaz_log (LOG_LOG, "zebra_start %s", configName);
306
307     zh->configName = xstrdup(configName);
308     zh->sessions = 0;
309     zh->stop_flag = 0;
310     zh->active = 1;
311
312     zh->registerState = -1;
313     zh->registerChange = 0;
314
315     if (!(zh->res = res_open (zh->configName)))
316     {
317         logf (LOG_WARN, "Failed to read resources `%s'", zh->configName);
318 //      return zh;
319     }
320     zebra_chdir (zh);
321     zebra_server_lock_init (zh);
322     zebra_mutex_cond_init (&zh->session_lock);
323     if (!res_get (zh->res, "passwd"))
324         zh->passwd_db = NULL;
325     else
326     {
327         zh->passwd_db = passwd_db_open ();
328         if (!zh->passwd_db)
329             logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
330         else
331             passwd_db_file (zh->passwd_db, res_get (zh->res, "passwd"));
332     }
333
334     return zh;
335 }
336
337 static int zebra_register_activate (ZebraService zh, int rw)
338 {
339     if (zh->active > 1)
340     {
341         yaz_log (LOG_LOG, "zebra_register_activate (ignored since active=%d)",
342                  zh->active);
343         return 0;
344     }
345     yaz_log (LOG_LOG, "zebra_register_activate shadow=%s",
346              zh->registerState ? "yes" : "no");
347
348     zh->dh = data1_create ();
349     if (!zh->dh)
350         return -1;
351     zh->bfs = bfs_create (res_get (zh->res, "register"));
352     if (!zh->bfs)
353     {
354         data1_destroy(zh->dh);
355         return -1;
356     }
357     bf_lockDir (zh->bfs, res_get (zh->res, "lockDir"));
358     bf_cache (zh->bfs, zh->registerState ? res_get (zh->res, "shadow") : NULL);
359     data1_set_tabpath (zh->dh, res_get(zh->res, "profilePath"));
360     zh->recTypes = recTypes_init (zh->dh);
361     recTypes_default_handlers (zh->recTypes);
362
363     zh->records = NULL;
364     zh->zebra_maps = zebra_maps_open (zh->res);
365     zh->rank_classes = NULL;
366
367     zh->records = 0;
368     zh->dict = 0;
369     zh->sortIdx = 0;
370     zh->isams = 0;
371 #if ZMBOL
372     zh->isam = 0;
373     zh->isamc = 0;
374     zh->isamd = 0;
375 #endif
376     zh->zei = 0;
377     
378     zebraRankInstall (zh, rank1_class);
379
380     if (!(zh->records = rec_open (zh->bfs, rw, 0)))
381     {
382         logf (LOG_WARN, "rec_open");
383         return -1;
384     }
385     if (!(zh->dict = dict_open (zh->bfs, FNAME_DICT, 80, rw, 0)))
386     {
387         logf (LOG_WARN, "dict_open");
388         return -1;
389     }
390     if (!(zh->sortIdx = sortIdx_open (zh->bfs, rw)))
391     {
392         logf (LOG_WARN, "sortIdx_open");
393         return -1;
394     }
395     if (res_get_match (zh->res, "isam", "s", ISAM_DEFAULT))
396     {
397         struct ISAMS_M_s isams_m;
398         if (!(zh->isams = isams_open (zh->bfs, FNAME_ISAMS, rw,
399                                       key_isams_m(zh->res, &isams_m))))
400         {
401             logf (LOG_WARN, "isams_open");
402             return -1;
403         }
404     }
405 #if ZMBOL
406     else if (res_get_match (zh->res, "isam", "i", ISAM_DEFAULT))
407     {
408         if (!(zh->isam = is_open (zh->bfs, FNAME_ISAM, key_compare, rw,
409                                   sizeof (struct it_key), zh->res)))
410         {
411             logf (LOG_WARN, "is_open");
412             return -1;
413         }
414     }
415     else if (res_get_match (zh->res, "isam", "c", ISAM_DEFAULT))
416     {
417         struct ISAMC_M_s isamc_m;
418         if (!(zh->isamc = isc_open (zh->bfs, FNAME_ISAMC,
419                                     rw, key_isamc_m(zh->res, &isamc_m))))
420         {
421             logf (LOG_WARN, "isc_open");
422             return -1;
423         }
424     }
425     else if (res_get_match (zh->res, "isam", "d", ISAM_DEFAULT))
426     {
427         struct ISAMD_M_s isamd_m;
428         
429         if (!(zh->isamd = isamd_open (zh->bfs, FNAME_ISAMD,
430                                       rw, key_isamd_m(zh->res, &isamd_m))))
431         {
432             logf (LOG_WARN, "isamd_open");
433             return -1;
434         }
435     }
436 #endif
437     zh->zei = zebraExplain_open (zh->records, zh->dh,
438                                  zh->res, rw, 0 /* rGroup */,
439                                  explain_extract);
440     if (!zh->zei)
441     {
442         logf (LOG_WARN, "Cannot obtain EXPLAIN information");
443         return -1;
444     }
445     zh->active = 2;
446     yaz_log (LOG_LOG, "zebra_register_activate ok");
447     return 0;
448 }
449
450 void zebra_admin_shutdown (ZebraHandle zh)
451 {
452     zebra_mutex_cond_lock (&zh->service->session_lock);
453     zh->service->stop_flag = 1;
454     if (!zh->service->sessions)
455         zebra_register_deactivate(zh->service);
456     zh->service->active = 0;
457     zebra_mutex_cond_unlock (&zh->service->session_lock);
458 }
459
460 void zebra_admin_start (ZebraHandle zh)
461 {
462     ZebraService zs = zh->service;
463     zh->errCode = 0;
464     zebra_mutex_cond_lock (&zs->session_lock);
465     if (!zs->stop_flag)
466         zh->service->active = 1;
467     zebra_mutex_cond_unlock (&zs->session_lock);
468 }
469
470 static int zebra_register_deactivate (ZebraService zs)
471 {
472     zs->stop_flag = 0;
473     if (zs->active <= 1)
474     {
475         yaz_log(LOG_LOG, "zebra_register_deactivate (ignored since active=%d)",
476                 zs->active);
477         return 0;
478     }
479     yaz_log(LOG_LOG, "zebra_register_deactivate");
480     zebra_chdir (zs);
481     if (zs->records)
482     {
483         zebraExplain_close (zs->zei, 0);
484         dict_close (zs->dict);
485         sortIdx_close (zs->sortIdx);
486         if (zs->isams)
487             isams_close (zs->isams);
488 #if ZMBOL
489         if (zs->isam)
490             is_close (zs->isam);
491         if (zs->isamc)
492             isc_close (zs->isamc);
493         if (zs->isamd)
494             isamd_close (zs->isamd);
495 #endif
496         rec_close (&zs->records);
497     }
498     recTypes_destroy (zs->recTypes);
499     zebra_maps_close (zs->zebra_maps);
500     zebraRankDestroy (zs);
501     bfs_destroy (zs->bfs);
502     data1_destroy (zs->dh);
503
504     if (zs->passwd_db)
505         passwd_db_close (zs->passwd_db);
506     zs->active = 1;
507     return 0;
508 }
509
510 void zebra_stop(ZebraService zs)
511 {
512     if (!zs)
513         return ;
514     yaz_log (LOG_LOG, "zebra_stop");
515
516     zebra_mutex_cond_lock (&zs->session_lock);
517     while (zs->sessions)
518         zebra_close (zs->sessions);
519
520     zebra_mutex_cond_unlock (&zs->session_lock);
521
522     zebra_mutex_cond_destroy (&zs->session_lock);
523
524     zebra_register_deactivate(zs);
525     res_close (zs->res);
526     xfree (zs->configName);
527     xfree (zs);
528 }
529
530 void zebra_close (ZebraHandle zh)
531 {
532     ZebraService zs = zh->service;
533     struct zebra_session **sp;
534
535     yaz_log (LOG_LOG, "zebra_close zh=%p", zh);
536     if (!zh)
537         return ;
538     resultSetDestroy (zh, -1, 0, 0);
539
540     if (zh->key_buf)
541     {
542         xfree (zh->key_buf);
543         zh->key_buf = 0;
544     }
545     xfree (zh->admin_databaseName);
546     zebra_mutex_cond_lock (&zs->session_lock);
547     sp = &zs->sessions;
548     while (1)
549     {
550         assert (*sp);
551         if (*sp == zh)
552         {
553             *sp = (*sp)->next;
554             break;
555         }
556         sp = &(*sp)->next;
557     }
558     if (!zs->sessions && zs->stop_flag)
559         zebra_register_deactivate(zs);
560     zebra_mutex_cond_unlock (&zs->session_lock);
561     xfree (zh);
562 }
563
564 struct map_baseinfo {
565     ZebraHandle zh;
566     NMEM mem;
567     int num_bases;
568     char **basenames;
569     int new_num_bases;
570     char **new_basenames;
571     int new_num_max;
572 };
573         
574 void map_basenames_func (void *vp, const char *name, const char *value)
575 {
576     struct map_baseinfo *p = (struct map_baseinfo *) vp;
577     int i, no;
578     char fromdb[128], todb[8][128];
579     
580     no =
581         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
582                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
583                 todb[5], todb[6], todb[7]);
584     if (no < 2)
585         return ;
586     no--;
587     for (i = 0; i<p->num_bases; i++)
588         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
589         {
590             p->basenames[i] = 0;
591             for (i = 0; i < no; i++)
592             {
593                 if (p->new_num_bases == p->new_num_max)
594                     return;
595                 p->new_basenames[(p->new_num_bases)++] = 
596                     nmem_strdup (p->mem, todb[i]);
597             }
598             return;
599         }
600 }
601
602 void map_basenames (ZebraHandle zh, ODR stream,
603                     int *num_bases, char ***basenames)
604 {
605     struct map_baseinfo info;
606     struct map_baseinfo *p = &info;
607     int i;
608
609     info.zh = zh;
610     info.num_bases = *num_bases;
611     info.basenames = *basenames;
612     info.new_num_max = 128;
613     info.new_num_bases = 0;
614     info.new_basenames = (char **)
615         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
616     info.mem = stream->mem;
617
618     res_trav (zh->service->res, "mapdb", &info, map_basenames_func);
619     
620     for (i = 0; i<p->num_bases; i++)
621         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
622         {
623             p->new_basenames[(p->new_num_bases)++] = 
624                 nmem_strdup (p->mem, p->basenames[i]);
625         }
626     *num_bases = info.new_num_bases;
627     *basenames = info.new_basenames;
628     for (i = 0; i<*num_bases; i++)
629         logf (LOG_LOG, "base %s", (*basenames)[i]);
630 }
631
632 void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
633                        Z_RPNQuery *query, int num_bases, char **basenames, 
634                        const char *setname)
635 {
636     zh->hits = 0;
637     if (zebra_register_lock (zh, 0))
638         return;
639     map_basenames (zh, stream, &num_bases, &basenames);
640     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
641
642     zebra_register_unlock (zh);
643
644     logf(LOG_APP,"SEARCH:%d:",zh->hits);
645 }
646
647 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
648                              const char *setname, Z_RecordComposition *comp,
649                              oid_value input_format, int num_recs,
650                              ZebraRetrievalRecord *recs)
651 {
652     ZebraPosSet poset;
653     int i, *pos_array;
654
655     if (zebra_register_lock (zh, 0))
656         return;
657     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
658     for (i = 0; i<num_recs; i++)
659         pos_array[i] = recs[i].position;
660     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
661     if (!poset)
662     {
663         logf (LOG_DEBUG, "zebraPosSetCreate error");
664         zh->errCode = 30;
665         zh->errString = nmem_strdup (stream->mem, setname);
666     }
667     else
668     {
669         for (i = 0; i<num_recs; i++)
670         {
671             if (poset[i].term)
672             {
673                 recs[i].errCode = 0;
674                 recs[i].format = VAL_SUTRS;
675                 recs[i].len = strlen(poset[i].term);
676                 recs[i].buf = poset[i].term;
677                 recs[i].base = poset[i].db;
678             }
679             else if (poset[i].sysno)
680             {
681                 recs[i].errCode =
682                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
683                                         stream, input_format, comp,
684                                         &recs[i].format, &recs[i].buf,
685                                         &recs[i].len,
686                                         &recs[i].base);
687                 recs[i].errString = NULL;
688             }
689             else
690             {
691                 char num_str[20];
692
693                 sprintf (num_str, "%d", pos_array[i]);  
694                 zh->errCode = 13;
695                 zh->errString = nmem_strdup (stream->mem, num_str);
696                 break;
697             }
698         }
699         zebraPosSetDestroy (zh, poset, num_recs);
700     }
701     zebra_register_unlock (zh);
702     xfree (pos_array);
703 }
704
705 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
706                  oid_value attributeset,
707                  int num_bases, char **basenames,
708                  int *position, int *num_entries, ZebraScanEntry **entries,
709                  int *is_partial)
710 {
711     if (zebra_register_lock (zh, 0))
712     {
713         *entries = 0;
714         *num_entries = 0;
715         return;
716     }
717     map_basenames (zh, stream, &num_bases, &basenames);
718     rpn_scan (zh, stream, zapt, attributeset,
719               num_bases, basenames, position,
720               num_entries, entries, is_partial);
721     zebra_register_unlock (zh);
722 }
723
724 void zebra_sort (ZebraHandle zh, ODR stream,
725                  int num_input_setnames, const char **input_setnames,
726                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
727                  int *sort_status)
728 {
729     if (zebra_register_lock (zh, 0))
730         return;
731     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
732                    output_setname, sort_sequence, sort_status);
733     zebra_register_unlock (zh);
734 }
735
736 int zebra_deleleResultSet(ZebraHandle zh, int function,
737                           int num_setnames, char **setnames,
738                           int *statuses)
739 {
740     int i, status;
741     if (zebra_register_lock (zh, 0))
742         return Z_DeleteStatus_systemProblemAtTarget;
743     switch (function)
744     {
745     case Z_DeleteRequest_list:
746         resultSetDestroy (zh, num_setnames, setnames, statuses);
747         break;
748     case Z_DeleteRequest_all:
749         resultSetDestroy (zh, -1, 0, statuses);
750         break;
751     }
752     zebra_register_unlock (zh);
753     status = Z_DeleteStatus_success;
754     for (i = 0; i<num_setnames; i++)
755         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
756             status = statuses[i];
757     return status;
758 }
759
760 int zebra_errCode (ZebraHandle zh)
761 {
762     return zh->errCode;
763 }
764
765 const char *zebra_errString (ZebraHandle zh)
766 {
767     return diagbib1_str (zh->errCode);
768 }
769
770 char *zebra_errAdd (ZebraHandle zh)
771 {
772     return zh->errString;
773 }
774
775 int zebra_hits (ZebraHandle zh)
776 {
777     return zh->hits;
778 }
779
780 int zebra_auth (ZebraService zh, const char *user, const char *pass)
781 {
782     if (!zh->passwd_db || !passwd_db_auth (zh->passwd_db, user, pass))
783     {
784         logf(LOG_APP,"AUTHOK:%s", user?user:"ANONYMOUS");
785         return 0;
786     }
787
788     logf(LOG_APP,"AUTHFAIL:%s", user?user:"ANONYMOUS");
789     return 1;
790 }
791
792 void zebra_admin_import_begin (ZebraHandle zh, const char *database)
793 {
794     if (zebra_register_lock (zh, 1))
795         return;
796     xfree (zh->admin_databaseName);
797     zh->admin_databaseName = xstrdup(database);
798 }
799
800 void zebra_admin_import_end (ZebraHandle zh)
801 {
802     zebraExplain_flush (zh->service->zei, 1, zh);
803     extract_index (zh);
804     zebra_register_unlock (zh);
805 }
806
807 void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
808 {
809     int sysno;
810     int i;
811     if (zh->service->active < 2)
812         return;
813     for (i = 0; i<segment->num_segmentRecords; i++)
814     {
815         Z_NamePlusRecord *npr = segment->segmentRecords[i];
816         const char *databaseName = npr->databaseName;
817
818         if (!databaseName)
819             databaseName = zh->admin_databaseName;
820         printf ("--------------%d--------------------\n", i);
821         if (npr->which == Z_NamePlusRecord_intermediateFragment)
822         {
823             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
824             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
825             {
826                 Odr_oct *oct = fragment->u.notExternallyTagged;
827                 printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
828                         oct->buf);
829                 
830                 sysno = 0;
831                 extract_rec_in_mem (zh, "grs.sgml",
832                                     oct->buf, oct->len,
833                                     databaseName,
834                                     0 /* delete_flag */,
835                                     0 /* test_mode */,
836                                     &sysno /* sysno */,
837                                     1 /* store_keys */,
838                                     1 /* store_data */,
839                                     0 /* match criteria */);
840             }
841         }
842     }
843 }
844
845 void zebra_admin_create (ZebraHandle zh, const char *database)
846 {
847     ZebraService zs = zh->service;
848     if (zebra_register_lock(zh, 1))
849     {
850         zh->errCode = 1019;
851         return;
852     }
853     /* announce database */
854     if (zebraExplain_newDatabase (zs->zei, database, 0 /* explainDatabase */))
855     {
856         zh->errCode = 224;
857         zh->errString = "Database already exist";
858     }
859     zebraExplain_flush (zh->service->zei, 1, zh);
860     extract_index (zh);
861     zebra_register_unlock(zh);
862 }
863
864 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
865                        const char *input_str, int input_len,
866                        char *output_str, int output_len)
867 {
868     WRBUF wrbuf;
869     if (!zh->service->zebra_maps)
870         return -1;
871     wrbuf = zebra_replace(zh->service->zebra_maps, reg_id, "",
872                           input_str, input_len);
873     if (!wrbuf)
874         return -2;
875     if (wrbuf_len(wrbuf) >= output_len)
876         return -3;
877     if (wrbuf_len(wrbuf))
878         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
879     output_str[wrbuf_len(wrbuf)] = '\0';
880     return wrbuf_len(wrbuf);
881 }
882
883 static void extract_init (struct recExtractCtrl *p, RecWord *w)
884 {
885     w->zebra_maps = p->zebra_maps;
886     w->seqnos = p->seqno;
887     w->attrSet = VAL_BIB1;
888     w->attrUse = 1016;
889     w->reg_type = 'w';
890     w->extractCtrl = p;
891 }
892
893 static void extract_add_index_string (RecWord *p, const char *string,
894                                       int length)
895 {
896     char *dst;
897     unsigned char attrSet;
898     unsigned short attrUse;
899     int lead = 0;
900     int diff = 0;
901     int *pseqno = &p->seqnos[p->reg_type];
902     ZebraHandle zh = p->extractCtrl->handle;
903     ZebraExplainInfo zei = zh->service->zei;
904     struct recKeys *keys = &zh->keys;
905
906     if (keys->buf_used+1024 > keys->buf_max)
907     {
908         char *b;
909
910         b = (char *) xmalloc (keys->buf_max += 128000);
911         if (keys->buf_used > 0)
912             memcpy (b, keys->buf, keys->buf_used);
913         xfree (keys->buf);
914         keys->buf = b;
915     }
916     dst = keys->buf + keys->buf_used;
917
918     attrSet = p->attrSet;
919     if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
920         lead |= 1;
921     else
922         keys->prevAttrSet = attrSet;
923     attrUse = p->attrUse;
924     if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
925         lead |= 2;
926     else
927         keys->prevAttrUse = attrUse;
928 #if 1
929     diff = 1 + *pseqno - keys->prevSeqNo;
930     if (diff >= 1 && diff <= 15)
931         lead |= (diff << 2);
932     else
933         diff = 0;
934 #endif
935     keys->prevSeqNo = *pseqno;
936     
937     *dst++ = lead;
938
939 #if SU_SCHEME
940     if ((lead & 3) < 3)
941     {
942         int ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
943         if (ch < 0)
944         {
945             ch = zebraExplain_addSU (zei, attrSet, attrUse);
946             yaz_log (LOG_LOG, "addSU set=%d use=%d SU=%d",
947                      attrSet, attrUse, ch);
948         }
949         assert (ch > 0);
950         memcpy (dst, &ch, sizeof(ch));
951         dst += sizeof(ch);
952     }
953 #else
954     if (!(lead & 1))
955     {
956         memcpy (dst, &attrSet, sizeof(attrSet));
957         dst += sizeof(attrSet);
958     }
959     if (!(lead & 2))
960     {
961         memcpy (dst, &attrUse, sizeof(attrUse));
962         dst += sizeof(attrUse);
963     }
964 #endif
965     *dst++ = p->reg_type;
966     memcpy (dst, string, length);
967     dst += length;
968     *dst++ = '\0';
969
970     if (!diff)
971     {
972         memcpy (dst, pseqno, sizeof(*pseqno));
973         dst += sizeof(*pseqno);
974     }
975     keys->buf_used = dst - keys->buf;
976     if (*pseqno)
977         (*pseqno)++;
978 }
979
980 static void extract_add_sort_string (RecWord *p, const char *string,
981                                      int length)
982 {
983     struct sortKey *sk;
984     ZebraHandle zh = p->extractCtrl->handle;
985     struct sortKey *sortKeys = zh->sortKeys;
986
987     for (sk = sortKeys; sk; sk = sk->next)
988         if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
989             return;
990
991     sk = (struct sortKey *) xmalloc (sizeof(*sk));
992     sk->next = sortKeys;
993     sortKeys = sk;
994
995     sk->string = (char *) xmalloc (length);
996     sk->length = length;
997     memcpy (sk->string, string, length);
998
999     sk->attrSet = p->attrSet;
1000     sk->attrUse = p->attrUse;
1001 }
1002
1003 static void extract_add_string (RecWord *p, const char *string, int length)
1004 {
1005     assert (length > 0);
1006     if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
1007         extract_add_sort_string (p, string, length);
1008     else
1009         extract_add_index_string (p, string, length);
1010 }
1011
1012 static void extract_add_incomplete_field (RecWord *p)
1013 {
1014     const char *b = p->string;
1015     int remain = p->length;
1016     const char **map = 0;
1017
1018     if (remain > 0)
1019         map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1020
1021     while (map)
1022     {
1023         char buf[IT_MAX_WORD+1];
1024         int i, remain;
1025
1026         /* Skip spaces */
1027         while (map && *map && **map == *CHR_SPACE)
1028         {
1029             remain = p->length - (b - p->string);
1030             if (remain > 0)
1031                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1032             else
1033                 map = 0;
1034         }
1035         if (!map)
1036             break;
1037         i = 0;
1038         while (map && *map && **map != *CHR_SPACE)
1039         {
1040             const char *cp = *map;
1041
1042             while (i < IT_MAX_WORD && *cp)
1043                 buf[i++] = *(cp++);
1044             remain = p->length - (b - p->string);
1045             if (remain > 0)
1046                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1047             else
1048                 map = 0;
1049         }
1050         if (!i)
1051             return;
1052         extract_add_string (p, buf, i);
1053     }
1054     (p->seqnos[p->reg_type])++; /* to separate this from next one  */
1055 }
1056
1057 static void extract_add_complete_field (RecWord *p)
1058 {
1059     const char *b = p->string;
1060     char buf[IT_MAX_WORD+1];
1061     const char **map = 0;
1062     int i = 0, remain = p->length;
1063
1064     if (remain > 0)
1065         map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
1066
1067     while (remain > 0 && i < IT_MAX_WORD)
1068     {
1069         while (map && *map && **map == *CHR_SPACE)
1070         {
1071             remain = p->length - (b - p->string);
1072             if (remain > 0)
1073                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1074             else
1075                 map = 0;
1076         }
1077         if (!map)
1078             break;
1079
1080         if (i && i < IT_MAX_WORD)
1081             buf[i++] = *CHR_SPACE;
1082         while (map && *map && **map != *CHR_SPACE)
1083         {
1084             const char *cp = *map;
1085
1086             if (i >= IT_MAX_WORD)
1087                 break;
1088             while (i < IT_MAX_WORD && *cp)
1089                 buf[i++] = *(cp++);
1090             remain = p->length  - (b - p->string);
1091             if (remain > 0)
1092                 map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
1093                                         remain);
1094             else
1095                 map = 0;
1096         }
1097     }
1098     if (!i)
1099         return;
1100     extract_add_string (p, buf, i);
1101 }
1102
1103 static void extract_token_add (RecWord *p)
1104 {
1105     WRBUF wrbuf;
1106     if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
1107                                p->string, p->length)))
1108     {
1109         p->string = wrbuf_buf(wrbuf);
1110         p->length = wrbuf_len(wrbuf);
1111     }
1112     if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
1113         extract_add_complete_field (p);
1114     else
1115         extract_add_incomplete_field(p);
1116 }
1117
1118 static void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid)
1119 {
1120     ZebraHandle zh = (ZebraHandle) (p->handle);
1121     zebraExplain_addSchema (zh->service->zei, oid);
1122 }
1123
1124 static void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
1125                                    int cmd, struct sortKey **skp)
1126 {
1127     struct sortKey *sk = *skp;
1128     SortIdx sortIdx = zh->service->sortIdx;
1129
1130     sortIdx_sysno (sortIdx, sysno);
1131     while (sk)
1132     {
1133         struct sortKey *sk_next = sk->next;
1134         sortIdx_type (sortIdx, sk->attrUse);
1135         sortIdx_add (sortIdx, sk->string, sk->length);
1136         xfree (sk->string);
1137         xfree (sk);
1138         sk = sk_next;
1139     }
1140     *skp = 0;
1141 }
1142
1143 struct encode_info {
1144     int  sysno;
1145     int  seqno;
1146     int  cmd;
1147     char buf[768];
1148 };
1149
1150 void encode_key_init (struct encode_info *i)
1151 {
1152     i->sysno = 0;
1153     i->seqno = 0;
1154     i->cmd = -1;
1155 }
1156
1157 char *encode_key_int (int d, char *bp)
1158 {
1159     if (d <= 63)
1160         *bp++ = d;
1161     else if (d <= 16383)
1162     {
1163         *bp++ = 64 + (d>>8);
1164         *bp++ = d  & 255;
1165     }
1166     else if (d <= 4194303)
1167     {
1168         *bp++ = 128 + (d>>16);
1169         *bp++ = (d>>8) & 255;
1170         *bp++ = d & 255;
1171     }
1172     else
1173     {
1174         *bp++ = 192 + (d>>24);
1175         *bp++ = (d>>16) & 255;
1176         *bp++ = (d>>8) & 255;
1177         *bp++ = d & 255;
1178     }
1179     return bp;
1180 }
1181
1182 void encode_key_write (char *k, struct encode_info *i, FILE *outf)
1183 {
1184     struct it_key key;
1185     char *bp = i->buf;
1186
1187     while ((*bp++ = *k++))
1188         ;
1189     memcpy (&key, k+1, sizeof(struct it_key));
1190     bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
1191     if (i->sysno != key.sysno)
1192     {
1193         i->sysno = key.sysno;
1194         i->seqno = 0;
1195     }
1196     else if (!i->seqno && !key.seqno && i->cmd == *k)
1197         return;
1198     bp = encode_key_int (key.seqno - i->seqno, bp);
1199     i->seqno = key.seqno;
1200     i->cmd = *k;
1201     if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
1202     {
1203         logf (LOG_FATAL|LOG_ERRNO, "fwrite");
1204         exit (1);
1205     }
1206 }
1207
1208 static void extract_flushWriteKeys (ZebraHandle zh)
1209 {
1210     FILE *outf;
1211     char out_fname[200];
1212     char *prevcp, *cp;
1213     struct encode_info encode_info;
1214     int ptr_i = zh->ptr_i;
1215 #if SORT_EXTRA
1216     int i;
1217 #endif
1218     if (!zh->key_buf || ptr_i <= 0)
1219         return;
1220
1221     (zh->key_file_no)++;
1222     logf (LOG_LOG, "sorting section %d", (zh->key_file_no));
1223 #if !SORT_EXTRA
1224     qsort (zh->key_buf + zh->ptr_top - ptr_i, ptr_i, sizeof(char*),
1225             key_qsort_compare);
1226     extract_get_fname_tmp (zh, out_fname, zh->key_file_no);
1227
1228     if (!(outf = fopen (out_fname, "wb")))
1229     {
1230         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1231         exit (1);
1232     }
1233     logf (LOG_LOG, "writing section %d", zh->key_file_no);
1234     prevcp = cp = (zh->key_buf)[zh->ptr_top - ptr_i];
1235     
1236     encode_key_init (&encode_info);
1237     encode_key_write (cp, &encode_info, outf);
1238     
1239     while (--ptr_i > 0)
1240     {
1241         cp = (zh->key_buf)[zh->ptr_top - ptr_i];
1242         if (strcmp (cp, prevcp))
1243         {
1244             encode_key_init (&encode_info);
1245             encode_key_write (cp, &encode_info, outf);
1246             prevcp = cp;
1247         }
1248         else
1249             encode_key_write (cp + strlen(cp), &encode_info, outf);
1250     }
1251 #else
1252     qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
1253     extract_get_fname_tmp (out_fname, key_file_no);
1254
1255     if (!(outf = fopen (out_fname, "wb")))
1256     {
1257         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1258         exit (1);
1259     }
1260     logf (LOG_LOG, "writing section %d", key_file_no);
1261     i = ptr_i;
1262     prevcp =  key_buf[ptr_top-i];
1263     while (1)
1264         if (!--i || strcmp (prevcp, key_buf[ptr_top-i]))
1265         {
1266             key_y_len = strlen(prevcp)+1;
1267 #if 0
1268             logf (LOG_LOG, "key_y_len: %2d %02x %02x %s",
1269                       key_y_len, prevcp[0], prevcp[1], 2+prevcp);
1270 #endif
1271             qsort (key_buf + ptr_top-ptr_i, ptr_i - i,
1272                                    sizeof(char*), key_y_compare);
1273             cp = key_buf[ptr_top-ptr_i];
1274             --key_y_len;
1275             encode_key_init (&encode_info);
1276             encode_key_write (cp, &encode_info, outf);
1277             while (--ptr_i > i)
1278             {
1279                 cp = key_buf[ptr_top-ptr_i];
1280                 encode_key_write (cp+key_y_len, &encode_info, outf);
1281             }
1282             if (!i)
1283                 break;
1284             prevcp = key_buf[ptr_top-ptr_i];
1285         }
1286 #endif
1287     if (fclose (outf))
1288     {
1289         logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
1290         exit (1);
1291     }
1292     logf (LOG_LOG, "finished section %d", zh->key_file_no);
1293     zh->ptr_i = 0;
1294     zh->key_buf_used = 0;
1295 }
1296
1297 static void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
1298                                      int cmd, struct recKeys *reckeys)
1299 {
1300 #if SU_SCHEME
1301 #else
1302     unsigned char attrSet = (unsigned char) -1;
1303     unsigned short attrUse = (unsigned short) -1;
1304 #endif
1305     int seqno = 0;
1306     int off = 0;
1307     int ch = 0;
1308     ZebraExplainInfo zei = zh->service->zei;
1309
1310     if (!zh->key_buf)
1311     {
1312         int mem = 8*1024*1024;
1313         zh->key_buf = (char**) xmalloc (mem);
1314         zh->ptr_top = mem/sizeof(char*);
1315         zh->ptr_i = 0;
1316         zh->key_buf_used = 0;
1317         zh->key_file_no = 0;
1318     }
1319     zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
1320     while (off < reckeys->buf_used)
1321     {
1322         const char *src = reckeys->buf + off;
1323         struct it_key key;
1324         int lead;
1325     
1326         lead = *src++;
1327
1328 #if SU_SCHEME
1329         if ((lead & 3) < 3)
1330         {
1331             memcpy (&ch, src, sizeof(ch));
1332             src += sizeof(ch);
1333         }
1334 #else
1335         if (!(lead & 1))
1336         {
1337             memcpy (&attrSet, src, sizeof(attrSet));
1338             src += sizeof(attrSet);
1339         }
1340         if (!(lead & 2))
1341         {
1342             memcpy (&attrUse, src, sizeof(attrUse));
1343             src += sizeof(attrUse);
1344         }
1345 #endif
1346         if (zh->key_buf_used + 1024 > (zh->ptr_top-zh->ptr_i)*sizeof(char*))
1347             extract_flushWriteKeys (zh);
1348         ++(zh->ptr_i);
1349         (zh->key_buf)[zh->ptr_top - zh->ptr_i] =
1350             (char*)zh->key_buf + zh->key_buf_used;
1351 #if SU_SCHEME
1352 #else
1353         ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
1354         if (ch < 0)
1355             ch = zebraExplain_addSU (zei, attrSet, attrUse);
1356 #endif
1357         assert (ch > 0);
1358         zh->key_buf_used +=
1359             key_SU_encode (ch,((char*)zh->key_buf) + zh->key_buf_used);
1360
1361         while (*src)
1362             ((char*)zh->key_buf) [(zh->key_buf_used)++] = *src++;
1363         src++;
1364         ((char*)(zh->key_buf))[(zh->key_buf_used)++] = '\0';
1365         ((char*)(zh->key_buf))[(zh->key_buf_used)++] = cmd;
1366
1367         if (lead & 60)
1368             seqno += ((lead>>2) & 15)-1;
1369         else
1370         {
1371             memcpy (&seqno, src, sizeof(seqno));
1372             src += sizeof(seqno);
1373         }
1374         key.seqno = seqno;
1375         key.sysno = sysno;
1376         memcpy ((char*)zh->key_buf + zh->key_buf_used, &key, sizeof(key));
1377         (zh->key_buf_used) += sizeof(key);
1378         off = src - reckeys->buf;
1379     }
1380     assert (off == reckeys->buf_used);
1381 }
1382
1383 static void extract_index (ZebraHandle zh)
1384 {
1385     extract_flushWriteKeys (zh);
1386     zebra_index_merge (zh);
1387 }
1388
1389 static int explain_extract (void *handle, Record rec, data1_node *n)
1390 {
1391     ZebraHandle zh = (ZebraHandle) handle;
1392     struct recExtractCtrl extractCtrl;
1393     int i;
1394
1395     if (zebraExplain_curDatabase (zh->service->zei,
1396                                   rec->info[recInfo_databaseName]))
1397     {
1398         abort();
1399         if (zebraExplain_newDatabase (zh->service->zei,
1400                                       rec->info[recInfo_databaseName], 0))
1401             abort ();
1402     }
1403
1404     zh->keys.buf_used = 0;
1405     zh->keys.prevAttrUse = -1;
1406     zh->keys.prevAttrSet = -1;
1407     zh->keys.prevSeqNo = 0;
1408     zh->sortKeys = 0;
1409     
1410     extractCtrl.init = extract_init;
1411     extractCtrl.tokenAdd = extract_token_add;
1412     extractCtrl.schemaAdd = extract_schema_add;
1413     extractCtrl.dh = zh->service->dh;
1414     for (i = 0; i<256; i++)
1415         extractCtrl.seqno[i] = 0;
1416     extractCtrl.zebra_maps = zh->service->zebra_maps;
1417     extractCtrl.flagShowRecords = 0;
1418     extractCtrl.handle = handle;
1419     
1420     grs_extract_tree(&extractCtrl, n);
1421
1422     logf (LOG_LOG, "flush explain record, sysno=%d", rec->sysno);
1423
1424     if (rec->size[recInfo_delKeys])
1425     {
1426         struct recKeys delkeys;
1427         struct sortKey *sortKeys = 0;
1428
1429         delkeys.buf_used = rec->size[recInfo_delKeys];
1430         delkeys.buf = rec->info[recInfo_delKeys];
1431         extract_flushSortKeys (zh, rec->sysno, 0, &sortKeys);
1432         extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
1433     }
1434     extract_flushRecordKeys (zh, rec->sysno, 1, &zh->keys);
1435     extract_flushSortKeys (zh, rec->sysno, 1, &zh->sortKeys);
1436
1437     xfree (rec->info[recInfo_delKeys]);
1438     rec->size[recInfo_delKeys] = zh->keys.buf_used;
1439     rec->info[recInfo_delKeys] = zh->keys.buf;
1440     zh->keys.buf = NULL;
1441     zh->keys.buf_max = 0;
1442     return 0;
1443 }
1444
1445 static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
1446                                const char *buf, size_t buf_size,
1447                                const char *databaseName, int delete_flag,
1448                                int test_mode, int *sysno,
1449                                int store_keys, int store_data,
1450                                const char *match_criteria)
1451 {
1452     RecordAttr *recordAttr;
1453     struct recExtractCtrl extractCtrl;
1454     int i, r;
1455     RecType recType;
1456     char subType[1024];
1457     void *clientData;
1458     const char *fname = "<no file>";
1459     Record rec;
1460     long recordOffset = 0;
1461     struct zebra_fetch_control fc;
1462
1463     fc.fd = -1;
1464     fc.record_int_buf = buf;
1465     fc.record_int_len = buf_size;
1466     fc.record_int_pos = 0;
1467     fc.offset_end = 0;
1468     fc.record_offset = 0;
1469
1470     extractCtrl.offset = 0;
1471     extractCtrl.readf = zebra_record_int_read;
1472     extractCtrl.seekf = zebra_record_int_seek;
1473     extractCtrl.tellf = zebra_record_int_tell;
1474     extractCtrl.endf = zebra_record_int_end;
1475     extractCtrl.fh = &fc;
1476
1477     /* announce database */
1478     if (zebraExplain_curDatabase (zh->service->zei, databaseName))
1479     {
1480         if (zebraExplain_newDatabase (zh->service->zei, databaseName, 0))
1481             return 0;
1482     }
1483     if (!(recType =
1484           recType_byName (zh->service->recTypes, recordType, subType,
1485                           &clientData)))
1486     {
1487         logf (LOG_WARN, "No such record type: %s", recordType);
1488         return 0;
1489     }
1490
1491     zh->keys.buf_used = 0;
1492     zh->keys.prevAttrUse = -1;
1493     zh->keys.prevAttrSet = -1;
1494     zh->keys.prevSeqNo = 0;
1495     zh->sortKeys = 0;
1496
1497     extractCtrl.subType = subType;
1498     extractCtrl.init = extract_init;
1499     extractCtrl.tokenAdd = extract_token_add;
1500     extractCtrl.schemaAdd = extract_schema_add;
1501     extractCtrl.dh = zh->service->dh;
1502     extractCtrl.handle = zh;
1503     extractCtrl.zebra_maps = zh->service->zebra_maps;
1504     extractCtrl.flagShowRecords = 0;
1505     for (i = 0; i<256; i++)
1506     {
1507         if (zebra_maps_is_positioned(zh->service->zebra_maps, i))
1508             extractCtrl.seqno[i] = 1;
1509         else
1510             extractCtrl.seqno[i] = 0;
1511     }
1512
1513     r = (*recType->extract)(clientData, &extractCtrl);
1514
1515     if (r == RECCTRL_EXTRACT_EOF)
1516         return 0;
1517     else if (r == RECCTRL_EXTRACT_ERROR)
1518     {
1519         /* error occured during extraction ... */
1520 #if 1
1521         yaz_log (LOG_WARN, "extract error");
1522 #else
1523         if (rGroup->flagRw &&
1524             records_processed < rGroup->fileVerboseLimit)
1525         {
1526             logf (LOG_WARN, "fail %s %s %ld", rGroup->recordType,
1527                   fname, (long) recordOffset);
1528         }
1529 #endif
1530         return 0;
1531     }
1532     if (zh->keys.buf_used == 0)
1533     {
1534         /* the extraction process returned no information - the record
1535            is probably empty - unless flagShowRecords is in use */
1536         if (test_mode)
1537             return 1;
1538         logf (LOG_WARN, "No keys generated for record");
1539         logf (LOG_WARN, " The file is probably empty");
1540         return 1;
1541     }
1542     /* match criteria */
1543
1544     if (! *sysno)
1545     {
1546         /* new record */
1547         if (delete_flag)
1548         {
1549             logf (LOG_LOG, "delete %s %s %ld", recordType,
1550                   fname, (long) recordOffset);
1551             logf (LOG_WARN, "cannot delete record above (seems new)");
1552             return 1;
1553         }
1554         logf (LOG_LOG, "add %s %s %ld", recordType, fname,
1555               (long) recordOffset);
1556         rec = rec_new (zh->service->records);
1557
1558         *sysno = rec->sysno;
1559
1560         recordAttr = rec_init_attr (zh->service->zei, rec);
1561
1562 #if 0
1563         if (matchStr)
1564         {
1565             dict_insert (matchDict, matchStr, sizeof(*sysno), sysno);
1566         }
1567 #endif
1568         extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
1569         extract_flushSortKeys (zh, *sysno, 1, &zh->sortKeys);
1570     }
1571     else
1572     {
1573         /* record already exists */
1574         struct recKeys delkeys;
1575
1576         rec = rec_get (zh->service->records, *sysno);
1577         assert (rec);
1578         
1579         recordAttr = rec_init_attr (zh->service->zei, rec);
1580
1581         if (recordAttr->runNumber ==
1582             zebraExplain_runNumberIncrement (zh->service->zei, 0))
1583         {
1584             logf (LOG_LOG, "skipped %s %s %ld", recordType,
1585                   fname, (long) recordOffset);
1586             rec_rm (&rec);
1587             return 1;
1588         }
1589         delkeys.buf_used = rec->size[recInfo_delKeys];
1590         delkeys.buf = rec->info[recInfo_delKeys];
1591         extract_flushSortKeys (zh, *sysno, 0, &zh->sortKeys);
1592         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
1593         if (delete_flag)
1594         {
1595             /* record going to be deleted */
1596             if (!delkeys.buf_used)
1597             {
1598                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1599                       fname, (long) recordOffset);
1600                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
1601             }
1602             else
1603             {
1604                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1605                       fname, (long) recordOffset);
1606 #if 0
1607                 if (matchStr)
1608                     dict_delete (matchDict, matchStr);
1609 #endif
1610                 rec_del (zh->service->records, &rec);
1611             }
1612             rec_rm (&rec);
1613             return 1;
1614         }
1615         else
1616         {
1617             /* record going to be updated */
1618             if (!delkeys.buf_used)
1619             {
1620                 logf (LOG_LOG, "update %s %s %ld", recordType,
1621                       fname, (long) recordOffset);
1622                 logf (LOG_WARN, "cannot update file above, storeKeys false");
1623             }
1624             else
1625             {
1626                 logf (LOG_LOG, "update %s %s %ld", recordType,
1627                       fname, (long) recordOffset);
1628                 extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
1629             }
1630         }
1631     }
1632     /* update file type */
1633     xfree (rec->info[recInfo_fileType]);
1634     rec->info[recInfo_fileType] =
1635         rec_strdup (recordType, &rec->size[recInfo_fileType]);
1636
1637     /* update filename */
1638     xfree (rec->info[recInfo_filename]);
1639     rec->info[recInfo_filename] =
1640         rec_strdup (fname, &rec->size[recInfo_filename]);
1641
1642     /* update delete keys */
1643     xfree (rec->info[recInfo_delKeys]);
1644     if (zh->keys.buf_used > 0 && store_keys == 1)
1645     {
1646         rec->size[recInfo_delKeys] = zh->keys.buf_used;
1647         rec->info[recInfo_delKeys] = zh->keys.buf;
1648         zh->keys.buf = NULL;
1649         zh->keys.buf_max = 0;
1650     }
1651     else
1652     {
1653         rec->info[recInfo_delKeys] = NULL;
1654         rec->size[recInfo_delKeys] = 0;
1655     }
1656
1657     /* save file size of original record */
1658     zebraExplain_recordBytesIncrement (zh->service->zei,
1659                                        - recordAttr->recordSize);
1660 #if 0
1661     recordAttr->recordSize = fi->file_moffset - recordOffset;
1662     if (!recordAttr->recordSize)
1663         recordAttr->recordSize = fi->file_max - recordOffset;
1664 #else
1665     recordAttr->recordSize = buf_size;
1666 #endif
1667     zebraExplain_recordBytesIncrement (zh->service->zei,
1668                                        recordAttr->recordSize);
1669
1670     /* set run-number for this record */
1671     recordAttr->runNumber =
1672         zebraExplain_runNumberIncrement (zh->service->zei, 0);
1673
1674     /* update store data */
1675     xfree (rec->info[recInfo_storeData]);
1676     if (store_data == 1)
1677     {
1678         rec->size[recInfo_storeData] = recordAttr->recordSize;
1679         rec->info[recInfo_storeData] = (char *)
1680             xmalloc (recordAttr->recordSize);
1681 #if 1
1682         memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
1683 #else
1684         if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
1685         {
1686             logf (LOG_ERRNO|LOG_FATAL, "seek to %ld in %s",
1687                   (long) recordOffset, fname);
1688             exit (1);
1689         }
1690         if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
1691             < recordAttr->recordSize)
1692         {
1693             logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
1694                   recordAttr->recordSize, fname);
1695             exit (1);
1696         }
1697 #endif
1698     }
1699     else
1700     {
1701         rec->info[recInfo_storeData] = NULL;
1702         rec->size[recInfo_storeData] = 0;
1703     }
1704     /* update database name */
1705     xfree (rec->info[recInfo_databaseName]);
1706     rec->info[recInfo_databaseName] =
1707         rec_strdup (databaseName, &rec->size[recInfo_databaseName]); 
1708
1709     /* update offset */
1710     recordAttr->recordOffset = recordOffset;
1711     
1712     /* commit this record */
1713     rec_put (zh->service->records, &rec);
1714
1715     return 0;
1716 }