Not creating a temporary file when indexing, if there would only
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /* $Id: zebraapi.c,v 1.117 2004-01-22 15:40:25 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <assert.h>
24 #include <stdio.h>
25 #ifdef WIN32
26 #include <io.h>
27 #include <process.h>
28 #include <direct.h>
29 #else
30 #include <unistd.h>
31 #endif
32
33 #include <yaz/diagbib1.h>
34 #include <yaz/pquery.h>
35 #include <yaz/sortspec.h>
36 #include "index.h"
37 #include <charmap.h>
38 #include "zebraapi.h"
39
40 /* simple asserts to validate the most essential input args */
41 #define ASSERTZH assert(zh && zh->service)
42 #define ASSERTZHRES assert(zh && zh->service && zh->res)
43 #define ASSERTZS assert(zs)
44
45 /* A simple log macro */
46 /* don't break with older yazen that lack log_app2 */
47 #ifdef LOG_APP2
48 #define LOG_API LOG_APP2
49 #else
50 #define LOG_API LOG_DEBUG
51 #endif
52
53 static Res zebra_open_res (ZebraHandle zh);
54 static void zebra_close_res (ZebraHandle zh);
55
56
57 static void zebra_chdir (ZebraService zs)
58 {
59     const char *dir ;
60     ASSERTZS;
61     yaz_log(LOG_API,"zebra_chdir");
62     dir = res_get (zs->global_res, "chdir");
63     if (!dir)
64         return;
65     logf (LOG_DEBUG, "chdir %s", dir);
66 #ifdef WIN32
67     _chdir(dir);
68 #else
69     chdir (dir);
70 #endif
71 }
72
73 static void zebra_flush_reg (ZebraHandle zh)
74 {
75     ASSERTZH;
76     yaz_log(LOG_API,"zebra_flush_reg");
77     zh->errCode=0;
78     zebraExplain_flush (zh->reg->zei, zh);
79     
80     extract_flushWriteKeys (zh,1 /* final */);
81     zebra_index_merge (zh );
82 }
83
84 static struct zebra_register *zebra_register_open (ZebraService zs, 
85                                                    const char *name,
86                                                    int rw, int useshadow,
87                                                    Res res,
88                                                    const char *reg_path);
89 static void zebra_register_close (ZebraService zs, struct zebra_register *reg);
90
91 ZebraHandle zebra_open (ZebraService zs)
92 {
93     ZebraHandle zh;
94     const char *default_encoding;
95     ASSERTZS;
96     yaz_log(LOG_API,"zebra_open");
97
98     if (!zs)
99         return 0;
100
101     zh = (ZebraHandle) xmalloc (sizeof(*zh));
102     yaz_log (LOG_DEBUG, "zebra_open zs=%p returns %p", zs, zh);
103
104     zh->service = zs;
105     zh->reg = 0;          /* no register attached yet */
106     zh->sets = 0;
107     zh->destroyed = 0;
108     zh->errCode = 0;
109     zh->errString = 0;
110     zh->res = 0; 
111
112     zh->reg_name = xstrdup ("");
113     zh->path_reg = 0;
114     zh->num_basenames = 0;
115     zh->basenames = 0;
116
117     zh->trans_no = 0;
118     zh->trans_w_no = 0;
119
120     zh->lock_normal = 0;
121     zh->lock_shadow = 0;
122
123     zh->shadow_enable = 1;
124
125     default_encoding = res_get_def(zs->global_res, "encoding", "ISO-8859-1");
126     zh->record_encoding = xstrdup (default_encoding);
127
128     zh->iconv_to_utf8 =
129         yaz_iconv_open ("UTF-8", default_encoding);
130     if (zh->iconv_to_utf8 == 0)
131         yaz_log (LOG_WARN, "iconv: %s to UTF-8 unsupported",
132            default_encoding);
133     zh->iconv_from_utf8 =
134         yaz_iconv_open (default_encoding, "UTF-8");
135     if (zh->iconv_to_utf8 == 0)
136         yaz_log (LOG_WARN, "iconv: UTF-8 to %s unsupported",
137            default_encoding);
138
139     zebra_mutex_cond_lock (&zs->session_lock);
140
141     zh->next = zs->sessions;
142     zs->sessions = zh;
143
144     zebra_mutex_cond_unlock (&zs->session_lock);
145
146     return zh;
147 }
148
149 ZebraService zebra_start (const char *configName, Res def_res, Res over_res)
150 {
151     Res res;
152
153     yaz_log(LOG_API|LOG_LOG,"zebra_start %s",configName);
154
155     if ((res = res_open (configName, def_res, over_res)))
156     {
157         ZebraService zh = xmalloc (sizeof(*zh));
158
159         yaz_log (LOG_DEBUG, "Read resources `%s'", configName);
160         
161         zh->global_res = res;
162         zh->configName = xstrdup(configName);
163         zh->sessions = 0;
164         
165         zebra_chdir (zh);
166         
167         zebra_mutex_cond_init (&zh->session_lock);
168         if (!res_get (zh->global_res, "passwd"))
169             zh->passwd_db = NULL;
170         else
171         {
172             zh->passwd_db = passwd_db_open ();
173             if (!zh->passwd_db)
174                 logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
175             else
176                 passwd_db_file (zh->passwd_db,
177                                 res_get (zh->global_res, "passwd"));
178         }
179         zh->path_root = res_get (zh->global_res, "root");
180         return zh;
181     }
182     return 0;
183 }
184
185
186 void zebra_pidfname(ZebraService zs, char *path)
187 {
188     zebra_lock_prefix (zs->global_res, path);
189     strcat(path, "zebrasrv.pid");
190 }
191
192 static
193 struct zebra_register *zebra_register_open (ZebraService zs, const char *name,
194                                             int rw, int useshadow, Res res,
195                                             const char *reg_path)
196 {
197     struct zebra_register *reg;
198     int record_compression = REC_COMPRESS_NONE;
199     const char *recordCompression = 0;
200     const char *profilePath;
201     char cwd[1024];
202
203     ASSERTZS;
204     
205     reg = xmalloc (sizeof(*reg));
206
207     assert (name);
208     reg->name = xstrdup (name);
209
210     reg->seqno = 0;
211     reg->last_val = 0;
212
213     assert (res);
214
215     yaz_log (LOG_LOG|LOG_API, "zebra_register_open rw = %d useshadow=%d p=%p,n=%s,rp=%s",
216              rw, useshadow, reg, name, reg_path ? reg_path : "(none)");
217     
218     reg->dh = data1_createx (DATA1_FLAG_XML);
219     if (!reg->dh)
220         return 0;
221     reg->bfs = bfs_create (res_get (res, "register"), reg_path);
222     if (!reg->bfs)
223     {
224         data1_destroy(reg->dh);
225         return 0;
226     }
227     if (useshadow)
228         bf_cache (reg->bfs, res_get (res, "shadow"));
229
230     getcwd(cwd, sizeof(cwd)-1);
231     profilePath = res_get_def(res, "profilePath", DEFAULT_PROFILE_PATH);
232     yaz_log(LOG_LOG, "profilePath=%s cwd=%s", profilePath, cwd);
233
234     data1_set_tabpath (reg->dh, profilePath);
235     data1_set_tabroot (reg->dh, reg_path);
236     reg->recTypes = recTypes_init (reg->dh);
237     recTypes_default_handlers (reg->recTypes);
238
239     reg->zebra_maps = zebra_maps_open (res, reg_path);
240     reg->rank_classes = NULL;
241
242     reg->key_buf = 0;
243
244     reg->keys.buf_max = 0;
245     reg->keys.buf = 0;
246     reg->sortKeys.buf = 0;
247     reg->sortKeys.buf_max = 0;
248
249     reg->records = 0;
250     reg->dict = 0;
251     reg->sortIdx = 0;
252     reg->isams = 0;
253     reg->matchDict = 0;
254     reg->isam = 0;
255     reg->isamc = 0;
256     reg->isamd = 0;
257     reg->isamb = 0;
258     reg->zei = 0;
259     reg->matchDict = 0;
260     reg->key_file_no = 0;
261     reg->ptr_i=0;
262     
263     zebraRankInstall (reg, rank1_class);
264     zebraRankInstall (reg, rankzv_class);
265     zebraRankInstall (reg, rankliv_class);
266
267     recordCompression = res_get_def (res, "recordCompression", "none");
268     if (!strcmp (recordCompression, "none"))
269         record_compression = REC_COMPRESS_NONE;
270     if (!strcmp (recordCompression, "bzip2"))
271         record_compression = REC_COMPRESS_BZIP2;
272
273     if (!(reg->records = rec_open (reg->bfs, rw, record_compression)))
274     {
275         logf (LOG_WARN, "rec_open");
276         return 0;
277     }
278     if (rw)
279     {
280         reg->matchDict = dict_open (reg->bfs, GMATCH_DICT, 20, 1, 0);
281     }
282     if (!(reg->dict = dict_open (reg->bfs, FNAME_DICT, 40, rw, 0)))
283     {
284         logf (LOG_WARN, "dict_open");
285         return 0;
286     }
287     if (!(reg->sortIdx = sortIdx_open (reg->bfs, rw)))
288     {
289         logf (LOG_WARN, "sortIdx_open");
290         return 0;
291     }
292     if (res_get_match (res, "isam", "s", ISAM_DEFAULT))
293     {
294         struct ISAMS_M_s isams_m;
295         if (!(reg->isams = isams_open (reg->bfs, FNAME_ISAMS, rw,
296                                       key_isams_m(res, &isams_m))))
297         {
298             logf (LOG_WARN, "isams_open");
299             return 0;
300         }
301     }
302     if (res_get_match (res, "isam", "i", ISAM_DEFAULT))
303     {
304         if (!(reg->isam = is_open (reg->bfs, FNAME_ISAM, key_compare, rw,
305                                   sizeof (struct it_key), res)))
306         {
307             logf (LOG_WARN, "is_open");
308             return 0;
309         }
310     }
311     if (res_get_match (res, "isam", "c", ISAM_DEFAULT))
312     {
313         struct ISAMC_M_s isamc_m;
314         if (!(reg->isamc = isc_open (reg->bfs, FNAME_ISAMC,
315                                     rw, key_isamc_m(res, &isamc_m))))
316         {
317             logf (LOG_WARN, "isc_open");
318             return 0;
319         }
320     }
321     if (res_get_match (res, "isam", "d", ISAM_DEFAULT))
322     {
323         struct ISAMD_M_s isamd_m;
324         
325         if (!(reg->isamd = isamd_open (reg->bfs, FNAME_ISAMD,
326                                       rw, key_isamd_m(res, &isamd_m))))
327         {
328             logf (LOG_WARN, "isamd_open");
329             return 0;
330         }
331     }
332     if (res_get_match (res, "isam", "b", ISAM_DEFAULT))
333     {
334         struct ISAMC_M_s isamc_m;
335         
336         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
337                                        rw, key_isamc_m(res, &isamc_m), 0)))
338         {
339             logf (LOG_WARN, "isamb_open");
340             return 0;
341         }
342     }
343     if (res_get_match (res, "isam", "bc", ISAM_DEFAULT))
344     {
345         struct ISAMC_M_s isamc_m;
346         
347         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
348                                        rw, key_isamc_m(res, &isamc_m), 1)))
349         {
350             logf (LOG_WARN, "isamb_open");
351             return 0;
352         }
353     }
354     if (res_get_match (res, "isam", "null", ISAM_DEFAULT))
355     {
356         struct ISAMC_M_s isamc_m;
357         
358         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
359                                        rw, key_isamc_m(res, &isamc_m), -1)))
360         {
361             logf (LOG_WARN, "isamb_open");
362             return 0;
363         }
364     }
365     reg->zei = zebraExplain_open (reg->records, reg->dh,
366                                   res, rw, reg,
367                                   explain_extract);
368     if (!reg->zei)
369     {
370         logf (LOG_WARN, "Cannot obtain EXPLAIN information");
371         return 0;
372     }
373     reg->active = 2;
374     yaz_log (LOG_DEBUG, "zebra_register_open ok p=%p", reg);
375     return reg;
376 }
377
378 int zebra_admin_shutdown (ZebraHandle zh)
379 {
380     ASSERTZH;
381     yaz_log(LOG_API,"zebra_admin_shutdown");
382     zh->errCode=0;
383
384     zebra_mutex_cond_lock (&zh->service->session_lock);
385     zh->service->stop_flag = 1;
386     zebra_mutex_cond_unlock (&zh->service->session_lock);
387     return 0;
388 }
389
390 int zebra_admin_start (ZebraHandle zh)
391 {
392     ZebraService zs;
393     ASSERTZH;
394     yaz_log(LOG_API,"zebra_admin_start");
395     zh->errCode=0;
396     zs = zh->service;
397     zebra_mutex_cond_lock (&zs->session_lock);
398     zebra_mutex_cond_unlock (&zs->session_lock);
399     return 0;
400 }
401
402 static void zebra_register_close (ZebraService zs, struct zebra_register *reg)
403 {
404     ASSERTZS;
405     yaz_log(LOG_LOG|LOG_API, "zebra_register_close p=%p", reg);
406     reg->stop_flag = 0;
407     zebra_chdir (zs);
408     if (reg->records)
409     {
410         zebraExplain_close (reg->zei);
411         dict_close (reg->dict);
412         if (reg->matchDict)
413             dict_close (reg->matchDict);
414         sortIdx_close (reg->sortIdx);
415         if (reg->isams)
416             isams_close (reg->isams);
417         if (reg->isam)
418             is_close (reg->isam);
419         if (reg->isamc)
420             isc_close (reg->isamc);
421         if (reg->isamd)
422             isamd_close (reg->isamd);
423         if (reg->isamb)
424             isamb_close (reg->isamb);
425         rec_close (&reg->records);
426     }
427
428     recTypes_destroy (reg->recTypes);
429     zebra_maps_close (reg->zebra_maps);
430     zebraRankDestroy (reg);
431     bfs_destroy (reg->bfs);
432     data1_destroy (reg->dh);
433
434     xfree (reg->sortKeys.buf);
435     xfree (reg->keys.buf);
436
437     xfree (reg->key_buf);
438     xfree (reg->name);
439     xfree (reg);
440 }
441
442 int zebra_stop(ZebraService zs)
443 {
444     if (!zs)
445         return 0;
446     yaz_log (LOG_LOG|LOG_API, "zebra_stop");
447
448     while (zs->sessions)
449     {
450         zebra_close (zs->sessions);
451     }
452         
453     zebra_mutex_cond_destroy (&zs->session_lock);
454
455     if (zs->passwd_db)
456         passwd_db_close (zs->passwd_db);
457
458     res_close (zs->global_res);
459     xfree (zs->configName);
460     xfree (zs);
461     return 0;
462 }
463
464 int zebra_close (ZebraHandle zh)
465 {
466     ZebraService zs;
467     struct zebra_session **sp;
468     int i;
469
470     yaz_log(LOG_API,"zebra_close");
471     if (!zh)
472         return 0;
473     ASSERTZH;
474     zh->errCode=0;
475     
476     zs = zh->service;
477     yaz_log (LOG_DEBUG, "zebra_close zh=%p", zh);
478     resultSetDestroy (zh, -1, 0, 0);
479
480     if (zh->reg)
481         zebra_register_close (zh->service, zh->reg);
482     zebra_close_res (zh);
483
484     xfree (zh->record_encoding);
485
486     for (i = 0; i < zh->num_basenames; i++)
487         xfree (zh->basenames[i]);
488     xfree (zh->basenames);
489
490     if (zh->iconv_to_utf8 != 0)
491         yaz_iconv_close (zh->iconv_to_utf8);
492     if (zh->iconv_from_utf8 != 0)
493         yaz_iconv_close (zh->iconv_from_utf8);
494
495     zebra_mutex_cond_lock (&zs->session_lock);
496     zebra_lock_destroy (zh->lock_normal);
497     zebra_lock_destroy (zh->lock_shadow);
498     sp = &zs->sessions;
499     while (1)
500     {
501         assert (*sp);
502         if (*sp == zh)
503         {
504             *sp = (*sp)->next;
505             break;
506         }
507         sp = &(*sp)->next;
508     }
509     zebra_mutex_cond_unlock (&zs->session_lock);
510     xfree (zh->reg_name);
511     zh->service=0; /* more likely to trigger an assert */
512     xfree (zh->path_reg);
513     xfree (zh);
514     return 0;
515 }
516
517 struct map_baseinfo {
518     ZebraHandle zh;
519     NMEM mem;
520     int num_bases;
521     char **basenames;
522     int new_num_bases;
523     char **new_basenames;
524     int new_num_max;
525 };
526
527 static Res zebra_open_res (ZebraHandle zh)
528 {
529     Res res = 0;
530     char fname[512];
531     ASSERTZH;
532     zh->errCode=0;
533
534     if (zh->path_reg)
535     {
536         sprintf (fname, "%.200s/zebra.cfg", zh->path_reg);
537         res = res_open (fname, zh->service->global_res, 0);
538         if (!res)
539             res = zh->service->global_res;
540     }
541     else if (*zh->reg_name == 0)
542     {
543         res = zh->service->global_res;
544     }
545     else
546     {
547         yaz_log (LOG_WARN, "no register root specified");
548         return 0;  /* no path for register - fail! */
549     }
550     return res;
551 }
552
553 static void zebra_close_res (ZebraHandle zh)
554 {
555     ASSERTZH;
556     zh->errCode=0;
557     if (zh->res != zh->service->global_res)
558         res_close (zh->res);
559     zh->res = 0;
560 }
561
562 static int zebra_select_register (ZebraHandle zh, const char *new_reg)
563 {
564     ASSERTZH;
565     zh->errCode=0;
566     if (zh->res && strcmp (zh->reg_name, new_reg) == 0)
567         return 0;
568     if (!zh->res)
569     {
570         assert (zh->reg == 0);
571         assert (*zh->reg_name == 0);
572     }
573     else
574     {
575         if (zh->reg)
576         {
577             resultSetInvalidate (zh);
578             zebra_register_close (zh->service, zh->reg);
579             zh->reg = 0;
580         }
581         zebra_close_res(zh);
582     }
583     xfree (zh->reg_name);
584     zh->reg_name = xstrdup (new_reg);
585
586     xfree (zh->path_reg);
587     zh->path_reg = 0;
588     if (zh->service->path_root)
589     {
590         zh->path_reg = xmalloc (strlen(zh->service->path_root) + 
591                                 strlen(zh->reg_name) + 3);
592         strcpy (zh->path_reg, zh->service->path_root);
593         if (*zh->reg_name)
594         {
595             strcat (zh->path_reg, "/");
596             strcat (zh->path_reg, zh->reg_name);
597         }
598     }
599     zh->res = zebra_open_res (zh);
600     
601     if (zh->lock_normal)
602         zebra_lock_destroy (zh->lock_normal);
603     zh->lock_normal = 0;
604
605     if (zh->lock_shadow)
606         zebra_lock_destroy (zh->lock_shadow);
607     zh->lock_shadow = 0;
608
609     if (zh->res)
610     {
611         char fname[512];
612         const char *lock_area  =res_get (zh->res, "lockDir");
613         
614         if (!lock_area && zh->path_reg)
615             res_set (zh->res, "lockDir", zh->path_reg);
616         sprintf (fname, "norm.%s.LCK", zh->reg_name);
617         zh->lock_normal =
618             zebra_lock_create (res_get(zh->res, "lockDir"), fname, 0);
619         
620         sprintf (fname, "shadow.%s.LCK", zh->reg_name);
621         zh->lock_shadow =
622             zebra_lock_create (res_get(zh->res, "lockDir"), fname, 0);
623
624     }
625     return 1;
626 }
627
628 void map_basenames_func (void *vp, const char *name, const char *value)
629 {
630     struct map_baseinfo *p = (struct map_baseinfo *) vp;
631     int i, no;
632     char fromdb[128], todb[8][128];
633     
634     no =
635         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
636                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
637                 todb[5], todb[6], todb[7]);
638     if (no < 2)
639         return ;
640     no--;
641     for (i = 0; i<p->num_bases; i++)
642         if (p->basenames[i] && !STRCASECMP (p->basenames[i], fromdb))
643         {
644             p->basenames[i] = 0;
645             for (i = 0; i < no; i++)
646             {
647                 if (p->new_num_bases == p->new_num_max)
648                     return;
649                 p->new_basenames[(p->new_num_bases)++] = 
650                     nmem_strdup (p->mem, todb[i]);
651             }
652             return;
653         }
654 }
655
656 void map_basenames (ZebraHandle zh, ODR stream,
657                     int *num_bases, char ***basenames)
658 {
659     struct map_baseinfo info;
660     struct map_baseinfo *p = &info;
661     int i;
662     ASSERTZH;
663     yaz_log(LOG_API,"map_basenames ");
664     zh->errCode=0;
665
666     info.zh = zh;
667     info.num_bases = *num_bases;
668     info.basenames = *basenames;
669     info.new_num_max = 128;
670     info.new_num_bases = 0;
671     info.new_basenames = (char **)
672         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
673     info.mem = stream->mem;
674
675     res_trav (zh->service->global_res, "mapdb", &info, map_basenames_func);
676     
677     for (i = 0; i<p->num_bases; i++)
678         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
679         {
680             p->new_basenames[(p->new_num_bases)++] = 
681                 nmem_strdup (p->mem, p->basenames[i]);
682         }
683     *num_bases = info.new_num_bases;
684     *basenames = info.new_basenames;
685     for (i = 0; i<*num_bases; i++)
686         logf (LOG_LOG, "base %s", (*basenames)[i]);
687 }
688
689 int zebra_select_database (ZebraHandle zh, const char *basename)
690 {
691     ASSERTZH;
692     yaz_log(LOG_API,"zebra_select_database %s",basename);
693     zh->errCode=0;
694     return zebra_select_databases (zh, 1, &basename);
695 }
696
697 int zebra_select_databases (ZebraHandle zh, int num_bases,
698                             const char **basenames)
699 {
700     int i;
701     const char *cp;
702     int len = 0;
703     char *new_reg = 0;
704     ASSERTZH;
705     yaz_log(LOG_API,"zebra_select_databases n=%d [0]=%s",
706                     num_bases,basenames[0]);
707     zh->errCode=0;
708     
709     if (num_bases < 1)
710     {
711         zh->errCode = 23;
712         return -1;
713     }
714     for (i = 0; i < zh->num_basenames; i++)
715         xfree (zh->basenames[i]);
716     xfree (zh->basenames);
717     
718     zh->num_basenames = num_bases;
719     zh->basenames = xmalloc (zh->num_basenames * sizeof(*zh->basenames));
720     for (i = 0; i < zh->num_basenames; i++)
721         zh->basenames[i] = xstrdup (basenames[i]);
722
723     cp = strrchr(basenames[0], '/');
724     if (cp)
725     {
726         len = cp - basenames[0];
727         new_reg = xmalloc (len + 1);
728         memcpy (new_reg, basenames[0], len);
729         new_reg[len] = '\0';
730     }
731     else
732         new_reg = xstrdup ("");
733     for (i = 1; i<num_bases; i++)
734     {
735         const char *cp1;
736
737         cp1 = strrchr (basenames[i], '/');
738         if (cp)
739         {
740             if (!cp1)
741             {
742                 zh->errCode = 23;
743                 return -1;
744             }
745             if (len != cp1 - basenames[i] ||
746                 memcmp (basenames[i], new_reg, len))
747             {
748                 zh->errCode = 23;
749                 return -1;
750             }
751         }
752         else
753         {
754             if (cp1)
755             {
756                 zh->errCode = 23;
757                 return -1;
758             }
759         }
760     }
761     zebra_select_register (zh, new_reg);
762     xfree (new_reg);
763     if (!zh->res)
764     {
765         zh->errCode = 109;
766         return -1;
767     }
768     if (!zh->lock_normal || !zh->lock_shadow)
769     {
770         zh->errCode = 2;
771         return -1;
772     }
773     return 0;
774 }
775
776 int zebra_search_RPN (ZebraHandle zh, ODR o,
777                        Z_RPNQuery *query, const char *setname, int *hits)
778 {
779     ASSERTZH;
780     yaz_log(LOG_API,"zebra_search_rpn");
781     zh->errCode=0;
782     zh->hits = 0;
783     *hits = 0;
784
785     if (zebra_begin_read (zh))
786         return 1;
787
788     zebra_livcode_transform(zh, query);
789
790     resultSetAddRPN (zh, odr_extract_mem(o), query, 
791                      zh->num_basenames, zh->basenames, setname);
792
793     zebra_end_read (zh);
794
795     *hits = zh->hits;
796     return 0;
797 }
798
799 int zebra_records_retrieve (ZebraHandle zh, ODR stream,
800                              const char *setname, Z_RecordComposition *comp,
801                              oid_value input_format, int num_recs,
802                              ZebraRetrievalRecord *recs)
803 {
804     ZebraPosSet poset;
805     int i, *pos_array, ret = 0;
806     ASSERTZH;
807     yaz_log(LOG_API,"zebra_records_retrieve n=%d",num_recs);
808     zh->errCode=0;
809
810     if (!zh->res)
811     {
812         zh->errCode = 30;
813         zh->errString = odr_strdup (stream, setname);
814         return -1;
815     }
816     
817     zh->errCode = 0;
818
819     if (zebra_begin_read (zh))
820         return -1;
821
822     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
823     for (i = 0; i<num_recs; i++)
824         pos_array[i] = recs[i].position;
825     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
826     if (!poset)
827     {
828         logf (LOG_DEBUG, "zebraPosSetCreate error");
829         zh->errCode = 30;
830         zh->errString = nmem_strdup (stream->mem, setname);
831         ret = -1;
832     }
833     else
834     {
835         for (i = 0; i<num_recs; i++)
836         {
837             if (poset[i].term)
838             {
839                 recs[i].errCode = 0;
840                 recs[i].format = VAL_SUTRS;
841                 recs[i].len = strlen(poset[i].term);
842                 recs[i].buf = poset[i].term;
843                 recs[i].base = poset[i].db;
844             }
845             else if (poset[i].sysno)
846             {
847                 recs[i].errCode =
848                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
849                                         stream, input_format, comp,
850                                         &recs[i].format, &recs[i].buf,
851                                         &recs[i].len,
852                                         &recs[i].base);
853                 recs[i].errString = NULL;
854             }
855             else
856             {
857                 char num_str[20];
858
859                 sprintf (num_str, "%d", pos_array[i]);  
860                 zh->errCode = 13;
861                 zh->errString = odr_strdup (stream, num_str);
862                 ret = -1;
863                 break;
864             }
865         }
866         zebraPosSetDestroy (zh, poset, num_recs);
867     }
868     zebra_end_read (zh);
869     xfree (pos_array);
870     return ret;
871 }
872
873 int zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
874                  oid_value attributeset,
875                  int *position, int *num_entries, ZebraScanEntry **entries,
876                  int *is_partial)
877 {
878     ASSERTZH;
879     yaz_log(LOG_API,"zebra_scan");
880     zh->errCode=0;
881     if (zebra_begin_read (zh))
882     {
883         *entries = 0;
884         *num_entries = 0;
885         return 1;
886     }
887     rpn_scan (zh, stream, zapt, attributeset,
888               zh->num_basenames, zh->basenames, position,
889               num_entries, entries, is_partial, 0, 0);
890     zebra_end_read (zh);
891     return 0;
892 }
893
894 int zebra_sort (ZebraHandle zh, ODR stream,
895                  int num_input_setnames, const char **input_setnames,
896                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
897                  int *sort_status)
898 {
899     ASSERTZH;
900     yaz_log(LOG_API,"zebra_sort");
901     zh->errCode=0;
902     if (zebra_begin_read (zh))
903         return 1;
904     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
905                    output_setname, sort_sequence, sort_status);
906     zebra_end_read(zh);
907     return 0;
908 }
909
910 int zebra_deleleResultSet(ZebraHandle zh, int function,
911                           int num_setnames, char **setnames,
912                           int *statuses)
913 {
914     int i, status;
915     ASSERTZH;
916     yaz_log(LOG_API,"zebra_deleleResultSet n=%d",num_setnames);
917     zh->errCode=0;
918     if (zebra_begin_read(zh))
919         return Z_DeleteStatus_systemProblemAtTarget;
920     switch (function)
921     {
922     case Z_DeleteRequest_list:
923         resultSetDestroy (zh, num_setnames, setnames, statuses);
924         break;
925     case Z_DeleteRequest_all:
926         resultSetDestroy (zh, -1, 0, statuses);
927         break;
928     }
929     zebra_end_read (zh);
930     status = Z_DeleteStatus_success;
931     for (i = 0; i<num_setnames; i++)
932         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
933             status = statuses[i];
934     return status;
935 }
936
937 int zebra_errCode (ZebraHandle zh)
938 {
939     if (zh)
940     {
941         yaz_log(LOG_API,"zebra_errCode: %d",zh->errCode);
942         return zh->errCode;
943     }
944     yaz_log(LOG_API,"zebra_errCode: o");
945     return 0; 
946 }
947
948 const char *zebra_errString (ZebraHandle zh)
949 {
950     const char *e="";
951     if (zh)
952         e= diagbib1_str (zh->errCode);
953     yaz_log(LOG_API,"zebra_errString: %s",e);
954     return e;
955 }
956
957 char *zebra_errAdd (ZebraHandle zh)
958 {
959     char *a="";
960     if (zh)
961         a= zh->errString;
962     yaz_log(LOG_API,"zebra_errAdd: %s",a);
963     return a;
964 }
965
966 void zebra_clearError(ZebraHandle zh)
967 {
968     if (zh)
969     {
970         zh->errCode=0;
971         zh->errString="";
972     }
973 }
974
975 int zebra_auth (ZebraHandle zh, const char *user, const char *pass)
976 {
977     ZebraService zs;
978     ASSERTZH;
979     yaz_log(LOG_API,"zebra_auth u=%s p=%s",user,pass);
980     zh->errCode=0;
981     zs= zh->service;
982     if (!zs->passwd_db || !passwd_db_auth (zs->passwd_db, user, pass))
983     {
984         logf(LOG_APP,"AUTHOK:%s", user?user:"ANONYMOUS");
985         return 0;
986     }
987
988     logf(LOG_APP,"AUTHFAIL:%s", user?user:"ANONYMOUS");
989     return 1;
990 }
991
992 int zebra_admin_import_begin (ZebraHandle zh, const char *database,
993                                const char *record_type)
994 {
995     ASSERTZH;
996     yaz_log(LOG_API,"zebra_admin_import_begin db=%s rt=%s", 
997                      database, record_type);
998     zh->errCode=0;
999     if (zebra_select_database(zh, database))
1000         return 1;
1001     zebra_begin_trans (zh, 1);
1002     return 0;
1003 }
1004
1005 int zebra_admin_import_end (ZebraHandle zh)
1006 {
1007     ASSERTZH;
1008     yaz_log(LOG_API,"zebra_admin_import_end");
1009     zh->errCode=0;
1010     zebra_end_trans (zh);
1011     return 0;
1012 }
1013
1014 int zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
1015 {
1016     int sysno;
1017     int i;
1018     ASSERTZH;
1019     yaz_log(LOG_API,"zebra_admin_import_segment");
1020     zh->errCode=0;
1021     for (i = 0; i<segment->num_segmentRecords; i++)
1022     {
1023         Z_NamePlusRecord *npr = segment->segmentRecords[i];
1024
1025         printf ("--------------%d--------------------\n", i);
1026         if (npr->which == Z_NamePlusRecord_intermediateFragment)
1027         {
1028             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
1029             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
1030             {
1031                 Odr_oct *oct = fragment->u.notExternallyTagged;
1032                 printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
1033                         oct->buf);
1034                 
1035                 sysno = 0;
1036                 
1037                 zebra_update_record(zh, 
1038                                     0, /* record Type */
1039                                     &sysno,
1040                                     0, /* match */
1041                                     0, /* fname */
1042                                     oct->buf, oct->len,
1043                                     0);
1044             }
1045         }
1046     }
1047     return 0;
1048 }
1049
1050 int zebra_admin_exchange_record (ZebraHandle zh,
1051                                  const char *rec_buf,
1052                                  size_t rec_len,
1053                                  const char *recid_buf, size_t recid_len,
1054                                  int action)
1055     /* 1 = insert. Fail it already exists */
1056     /* 2 = replace. Fail it does not exist */
1057     /* 3 = delete. Fail if does not exist */
1058     /* 4 = update. Insert/replace */
1059 {
1060     int sysno = 0;
1061     char *rinfo = 0;
1062     char recid_z[256];
1063     ASSERTZH;
1064     yaz_log(LOG_API,"zebra_admin_exchange_record ac=%d", action);
1065     zh->errCode=0;
1066
1067     if (!recid_buf || recid_len <= 0 || recid_len >= sizeof(recid_z))
1068         return -1;
1069     memcpy (recid_z, recid_buf, recid_len);
1070     recid_z[recid_len] = 0;
1071
1072     zebra_begin_trans(zh,1);
1073
1074     rinfo = dict_lookup (zh->reg->matchDict, recid_z);
1075     if (rinfo)
1076     {
1077         if (action == 1)  /* fail if insert */
1078         {
1079              zebra_end_trans(zh);
1080              return -1;
1081         }
1082
1083         memcpy (&sysno, rinfo+1, sizeof(sysno));
1084     }
1085     else
1086     {
1087         if (action == 2 || action == 3) /* fail if delete or update */
1088         {
1089             zebra_end_trans(zh);
1090             return -1;
1091         }
1092         action = 1;  /* make it an insert (if it's an update).. */
1093     }
1094     buffer_extract_record (zh, rec_buf, rec_len,
1095                            action == 3 ? 1 : 0 /* delete flag */,
1096                            0, /* test mode */
1097                            0, /* recordType */
1098                            &sysno, 
1099                            0, /* match */
1100                            0, /* fname */
1101                            0, /* force update */
1102                            1  /* allow update */
1103         );
1104     if (action == 1)
1105     {
1106         dict_insert (zh->reg->matchDict, recid_z, sizeof(sysno), &sysno);
1107     }
1108     else if (action == 3)
1109     {
1110         dict_delete (zh->reg->matchDict, recid_z);
1111     }
1112     zebra_end_trans(zh);
1113     return 0;
1114 }
1115
1116 int delete_w_handle(const char *info, void *handle)
1117 {
1118     ZebraHandle zh = (ZebraHandle) handle;
1119     ISAMC_P pos;
1120
1121     if (*info == sizeof(pos))
1122     {
1123         memcpy (&pos, info+1, sizeof(pos));
1124         isamb_unlink(zh->reg->isamb, pos);
1125     }
1126     return 0;
1127 }
1128
1129 static int delete_SU_handle(void *handle, int ord)
1130 {
1131     ZebraHandle zh = (ZebraHandle) handle;
1132     char ord_buf[20];
1133     int ord_len;
1134
1135     ord_len = key_SU_encode (ord, ord_buf);
1136     ord_buf[ord_len] = '\0';
1137
1138     assert (zh->reg->isamb);
1139     dict_delete_subtree(zh->reg->dict, ord_buf,
1140                         zh, delete_w_handle);
1141     return 0;
1142 }
1143
1144 int zebra_drop_database  (ZebraHandle zh, const char *database)
1145 {
1146     int ret = 0;
1147     ASSERTZH;
1148     yaz_log(LOG_API,"zebra_drop_database");
1149     zh->errCode = 0;
1150
1151     if (zebra_select_database (zh, database))
1152         return -1;
1153     if (zebra_begin_trans (zh, 1))
1154         return -1;
1155     if (zh->reg->isamb)
1156     {
1157         zebraExplain_curDatabase (zh->reg->zei, database);
1158         
1159         zebraExplain_trav_ord(zh->reg->zei, zh, delete_SU_handle);
1160         zebraExplain_removeDatabase(zh->reg->zei, zh);
1161     }
1162     else
1163     {
1164         yaz_log(LOG_WARN, "drop database only supported for isam:b");
1165         ret = -1;
1166     }
1167     zebra_end_trans (zh);
1168     return ret;
1169 }
1170
1171 int zebra_create_database (ZebraHandle zh, const char *database)
1172 {
1173     ASSERTZH;
1174     yaz_log(LOG_API,"zebra_create_database");
1175     zh->errCode=0;
1176
1177     if (zebra_select_database (zh, database))
1178         return -1;
1179     if (zebra_begin_trans (zh, 1))
1180         return -1;
1181
1182     /* announce database */
1183     if (zebraExplain_newDatabase (zh->reg->zei, database, 0 
1184                                   /* explainDatabase */))
1185     {
1186         zebra_end_trans (zh);
1187         zh->errCode = 224;
1188         zh->errString = "database already exist";
1189         return -1;
1190     }
1191     zebra_end_trans (zh);
1192     return 0;
1193 }
1194
1195 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
1196                        const char *input_str, int input_len,
1197                        char *output_str, int output_len)
1198 {
1199     WRBUF wrbuf;
1200     ASSERTZH;
1201     yaz_log(LOG_API,"zebra_string_norm ");
1202     zh->errCode=0;
1203     if (!zh->reg->zebra_maps)
1204         return -1;
1205     wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, "",
1206                           input_str, input_len);
1207     if (!wrbuf)
1208         return -2;
1209     if (wrbuf_len(wrbuf) >= output_len)
1210         return -3;
1211     if (wrbuf_len(wrbuf))
1212         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1213     output_str[wrbuf_len(wrbuf)] = '\0';
1214     return wrbuf_len(wrbuf);
1215 }
1216
1217
1218 int zebra_set_state (ZebraHandle zh, int val, int seqno)
1219 {
1220     char state_fname[256];
1221     char *fname;
1222     long p = getpid();
1223     FILE *f;
1224     ASSERTZH;
1225     yaz_log(LOG_API,"zebra_set_state v=%d seq=%d", val, seqno);
1226     zh->errCode=0;
1227
1228     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
1229     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
1230     f = fopen (fname, "w");
1231
1232     yaz_log (LOG_DEBUG, "%c %d %ld", val, seqno, p);
1233     fprintf (f, "%c %d %ld\n", val, seqno, p);
1234     fclose (f);
1235     xfree (fname);
1236     return 0;
1237 }
1238
1239 int zebra_get_state (ZebraHandle zh, char *val, int *seqno)
1240 {
1241     char state_fname[256];
1242     char *fname;
1243     FILE *f;
1244
1245     ASSERTZH;
1246     yaz_log(LOG_API,"zebra_get_state ");
1247     zh->errCode=0;
1248     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
1249     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
1250     f = fopen (fname, "r");
1251     *val = 'o';
1252     *seqno = 0;
1253
1254     if (f)
1255     {
1256         fscanf (f, "%c %d", val, seqno);
1257         fclose (f);
1258     }
1259     xfree (fname);
1260     return 0;
1261 }
1262
1263 int zebra_begin_read (ZebraHandle zh)
1264 {
1265     return zebra_begin_trans(zh, 0);
1266 }
1267
1268 int zebra_end_read (ZebraHandle zh)
1269 {
1270     return zebra_end_trans(zh);
1271 }
1272
1273 static void read_res_for_transaction(ZebraHandle zh)
1274 {
1275     const char *group = res_get(zh->res, "group");
1276     const char *v;
1277     
1278     zh->m_group = group;
1279     v = res_get_prefix(zh->res, "followLinks", group, "1");
1280     zh->m_follow_links = atoi(v);
1281
1282     zh->m_record_id = res_get_prefix(zh->res, "recordId", group, 0);
1283     zh->m_record_type = res_get_prefix(zh->res, "recordType", group, 0);
1284
1285     v = res_get_prefix(zh->res, "storeKeys", group, "1");
1286     zh->m_store_keys = atoi(v);
1287
1288     v = res_get_prefix(zh->res, "storeData", group, "1");
1289     zh->m_store_data = atoi(v);
1290
1291     v = res_get_prefix(zh->res, "explainDatabase", group, "0");
1292     zh->m_explain_database = atoi(v);
1293
1294     v = res_get_prefix(zh->res, "openRW", group, "1");
1295     zh->m_flag_rw = atoi(v);
1296
1297     v = res_get_prefix(zh->res, "fileVerboseLimit", group, "100000");
1298     zh->m_file_verbose_limit = atoi(v);
1299 }
1300
1301 int zebra_begin_trans (ZebraHandle zh, int rw)
1302 {
1303     if (!zh->res)
1304     {
1305         zh->errCode = 2;
1306         zh->errString = "zebra_begin_trans: no database selected";
1307         return -1;
1308     }
1309     ASSERTZHRES;
1310     yaz_log(LOG_API,"zebra_begin_trans rw=%d",rw);
1311     assert (zh->res);
1312     if (rw)
1313     {
1314         int pass;
1315         int seqno = 0;
1316         char val = '?';
1317         const char *rval = 0;
1318         
1319         (zh->trans_no++);
1320         if (zh->trans_w_no)
1321             return 0;
1322         if (zh->trans_no != 1)
1323         {
1324             zh->errCode = 2;
1325             zh->errString = "zebra_begin_trans: write trans not allowed within read trans";
1326             return -1;
1327         }
1328         if (zh->reg)
1329         {
1330             resultSetInvalidate (zh);
1331             zebra_register_close (zh->service, zh->reg);
1332         }
1333         zh->trans_w_no = zh->trans_no;
1334
1335         zh->errCode=0;
1336         
1337         zh->records_inserted = 0;
1338         zh->records_updated = 0;
1339         zh->records_deleted = 0;
1340         zh->records_processed = 0;
1341         
1342 #if HAVE_SYS_TIMES_H
1343         times (&zh->tms1);
1344 #endif
1345         /* lock */
1346         if (zh->shadow_enable)
1347             rval = res_get (zh->res, "shadow");
1348         
1349         for (pass = 0; pass < 2; pass++)
1350         {
1351             if (rval)
1352             {
1353                 zebra_lock_r (zh->lock_normal);
1354                 zebra_lock_w (zh->lock_shadow);
1355             }
1356             else
1357             {
1358                 zebra_lock_w (zh->lock_normal);
1359                 zebra_lock_w (zh->lock_shadow);
1360             }
1361             
1362             zebra_get_state (zh, &val, &seqno);
1363             if (val == 'c')
1364             {
1365                 yaz_log (LOG_LOG, "previous transaction didn't finish commit");
1366                 zebra_unlock (zh->lock_shadow);
1367                 zebra_unlock (zh->lock_normal);
1368                 zebra_commit (zh);
1369                 continue;
1370             }
1371             else if (val == 'd')
1372             {
1373                 if (rval)
1374                 {
1375                     BFiles bfs = bfs_create (res_get (zh->res, "shadow"),
1376                                              zh->path_reg);
1377                     yaz_log (LOG_LOG, "previous transaction didn't reach commit");
1378                     bf_commitClean (bfs, rval);
1379                     bfs_destroy (bfs);
1380             }
1381                 else
1382                 {
1383                     yaz_log (LOG_WARN, "your previous transaction didn't finish");
1384                 }
1385             }
1386             break;
1387         }
1388         if (pass == 2)
1389         {
1390             yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
1391             abort();
1392             return -1;
1393         }
1394         zebra_set_state (zh, 'd', seqno);
1395         
1396         zh->reg = zebra_register_open (zh->service, zh->reg_name,
1397                                        1, rval ? 1 : 0, zh->res,
1398                                        zh->path_reg);
1399         if (zh->reg)
1400             zh->reg->seqno = seqno;
1401         else
1402         {
1403             zebra_set_state (zh, 'o', seqno);
1404             
1405             zebra_unlock (zh->lock_shadow);
1406             zebra_unlock (zh->lock_normal);
1407
1408             zh->trans_no--;
1409             zh->trans_w_no = 0;
1410
1411             zh->errCode = 2;
1412             zh->errString = "zebra_begin_trans: cannot open register";
1413             yaz_log(LOG_FATAL, zh->errString);
1414             return -1;
1415         }
1416     }
1417     else
1418     {
1419         int dirty = 0;
1420         char val;
1421         int seqno;
1422         
1423         (zh->trans_no)++;
1424         
1425         if (zh->trans_no != 1)
1426         {
1427             zebra_flush_reg (zh);
1428             return 0;
1429         }
1430         zh->errCode=0;
1431 #if HAVE_SYS_TIMES_H
1432         times (&zh->tms1);
1433 #endif
1434         if (!zh->res)
1435         {
1436             (zh->trans_no)--;
1437             zh->errCode = 109;
1438             return -1;
1439         }
1440         if (!zh->lock_normal || !zh->lock_shadow)
1441         {
1442             (zh->trans_no)--;
1443             zh->errCode = 2;
1444             return -1;
1445         }
1446         zebra_get_state (zh, &val, &seqno);
1447         if (val == 'd')
1448             val = 'o';
1449         
1450         if (!zh->reg)
1451             dirty = 1;
1452         else if (seqno != zh->reg->seqno)
1453         {
1454             yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d",
1455                      seqno, zh->reg->seqno);
1456             dirty = 1;
1457         }
1458         else if (zh->reg->last_val != val)
1459         {
1460             yaz_log (LOG_LOG, "reopen last cur/old %d/%d",
1461                      val, zh->reg->last_val);
1462             dirty = 1;
1463         }
1464         if (!dirty)
1465             return 0;
1466         
1467         if (val == 'c')
1468             zebra_lock_r (zh->lock_shadow);
1469         else
1470             zebra_lock_r (zh->lock_normal);
1471         
1472         if (zh->reg)
1473         {
1474             resultSetInvalidate (zh);
1475             zebra_register_close (zh->service, zh->reg);
1476         }
1477         zh->reg = zebra_register_open (zh->service, zh->reg_name,
1478                                        0, val == 'c' ? 1 : 0,
1479                                        zh->res, zh->path_reg);
1480         if (!zh->reg)
1481         {
1482             zebra_unlock (zh->lock_normal);
1483             zebra_unlock (zh->lock_shadow);
1484             zh->trans_no--;
1485             zh->errCode = 109;
1486             return -1;
1487         }
1488         zh->reg->last_val = val;
1489         zh->reg->seqno = seqno;
1490     }
1491     read_res_for_transaction(zh);
1492     return 0;
1493 }
1494
1495 int zebra_end_trans (ZebraHandle zh)
1496 {
1497     ZebraTransactionStatus dummy;
1498     yaz_log(LOG_API,"zebra_end_trans");
1499     return zebra_end_transaction(zh, &dummy);
1500 }
1501
1502 int zebra_end_transaction (ZebraHandle zh, ZebraTransactionStatus *status)
1503 {
1504     char val;
1505     int seqno;
1506     const char *rval;
1507
1508     ASSERTZH;
1509     yaz_log(LOG_API,"zebra_end_transaction");
1510
1511     status->processed = 0;
1512     status->inserted  = 0;
1513     status->updated   = 0;
1514     status->deleted   = 0;
1515     status->utime     = 0;
1516     status->stime     = 0;
1517
1518     if (!zh->res || !zh->reg)
1519     {
1520         zh->errCode = 2;
1521         zh->errString = "zebra_end_trans: no open transaction";
1522         return -1;
1523     }
1524     if (zh->trans_no != zh->trans_w_no)
1525     {
1526         zh->trans_no--;
1527         if (zh->trans_no != 0)
1528             return 0;
1529
1530         /* release read lock */
1531
1532         zebra_unlock (zh->lock_normal);
1533         zebra_unlock (zh->lock_shadow);
1534     }
1535     else
1536     {   /* release write lock */
1537         zh->trans_no--;
1538         zh->trans_w_no = 0;
1539         
1540         yaz_log (LOG_LOG, "zebra_end_trans");
1541         rval = res_get (zh->res, "shadow");
1542         
1543         zebraExplain_runNumberIncrement (zh->reg->zei, 1);
1544         
1545         zebra_flush_reg (zh);
1546         
1547         resultSetInvalidate (zh);
1548
1549         zebra_register_close (zh->service, zh->reg);
1550         zh->reg = 0;
1551         
1552         yaz_log (LOG_LOG, "Records: %7d i/u/d %d/%d/%d", 
1553                  zh->records_processed, zh->records_inserted,
1554                  zh->records_updated, zh->records_deleted);
1555         
1556         status->processed = zh->records_processed;
1557         status->inserted = zh->records_inserted;
1558         status->updated = zh->records_updated;
1559         status->deleted = zh->records_deleted;
1560         
1561         zebra_get_state (zh, &val, &seqno);
1562         if (val != 'd')
1563         {
1564             BFiles bfs = bfs_create (rval, zh->path_reg);
1565             yaz_log (LOG_LOG, "deleting shadow stuff val=%c", val);
1566             bf_commitClean (bfs, rval);
1567             bfs_destroy (bfs);
1568         }
1569         if (!rval)
1570             seqno++;
1571         zebra_set_state (zh, 'o', seqno);
1572         
1573         zebra_unlock (zh->lock_shadow);
1574         zebra_unlock (zh->lock_normal);
1575         
1576     }
1577 #if HAVE_SYS_TIMES_H
1578     times (&zh->tms2);
1579     logf (LOG_LOG, "user/system: %ld/%ld",
1580           (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
1581           (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
1582     
1583     status->utime = (long) (zh->tms2.tms_utime - zh->tms1.tms_utime);
1584     status->stime = (long) (zh->tms2.tms_stime - zh->tms1.tms_stime);
1585 #endif
1586     return 0;
1587 }
1588
1589 int zebra_repository_update (ZebraHandle zh, const char *path)
1590 {
1591     ASSERTZH;
1592     zh->errCode=0;
1593     logf (LOG_LOG|LOG_API, "updating %s", path);
1594     repositoryUpdate (zh, path);
1595     return zh->errCode;
1596 }
1597
1598 int zebra_repository_delete (ZebraHandle zh, const char *path)
1599 {
1600     ASSERTZH;
1601     zh->errCode=0;
1602     logf (LOG_LOG|LOG_API, "deleting %s", path);
1603     repositoryDelete (zh, path);
1604     return zh->errCode;
1605 }
1606
1607 int zebra_repository_show (ZebraHandle zh, const char *path)
1608 {
1609     ASSERTZH;
1610     yaz_log(LOG_API,"zebra_repository_show");
1611     zh->errCode=0;
1612     repositoryShow (zh, path);
1613     return zh->errCode;
1614 }
1615
1616 static int zebra_commit_ex (ZebraHandle zh, int clean_only)
1617 {
1618     int seqno;
1619     char val;
1620     const char *rval;
1621     BFiles bfs;
1622     ASSERTZH;
1623     zh->errCode=0;
1624
1625     if (!zh->res)
1626     {
1627         zh->errCode = 109;
1628         return -1;
1629     }
1630     rval = res_get (zh->res, "shadow");    
1631     if (!rval)
1632     {
1633         logf (LOG_WARN, "Cannot perform commit");
1634         logf (LOG_WARN, "No shadow area defined");
1635         return 0;
1636     }
1637
1638     zebra_lock_w (zh->lock_normal);
1639     zebra_lock_r (zh->lock_shadow);
1640
1641     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
1642
1643     zebra_get_state (zh, &val, &seqno);
1644
1645     if (rval && *rval)
1646         bf_cache (bfs, rval);
1647     if (bf_commitExists (bfs))
1648     {
1649         if (clean_only)
1650             zebra_set_state (zh, 'd', seqno);
1651         else
1652         {
1653             zebra_set_state (zh, 'c', seqno);
1654             
1655             logf (LOG_LOG, "commit start");
1656             bf_commitExec (bfs);
1657 #ifndef WIN32
1658             sync ();
1659 #endif
1660         }
1661         logf (LOG_LOG, "commit clean");
1662         bf_commitClean (bfs, rval);
1663         seqno++;
1664         zebra_set_state (zh, 'o', seqno);
1665     }
1666     else
1667     {
1668         logf (LOG_LOG, "nothing to commit");
1669     }
1670     bfs_destroy (bfs);
1671
1672     zebra_unlock (zh->lock_shadow);
1673     zebra_unlock (zh->lock_normal);
1674     return 0;
1675 }
1676
1677 int zebra_clean (ZebraHandle zh)
1678 {
1679     yaz_log(LOG_API,"zebra_clean");
1680     return zebra_commit_ex(zh, 1);
1681 }
1682
1683 int zebra_commit (ZebraHandle zh)
1684 {
1685     yaz_log(LOG_API,"zebra_commit");
1686     return zebra_commit_ex(zh, 0);
1687 }
1688
1689 int zebra_init (ZebraHandle zh)
1690 {
1691     const char *rval;
1692     BFiles bfs = 0;
1693     ASSERTZH;
1694     yaz_log(LOG_API,"zebra_init");
1695     zh->errCode=0;
1696
1697     if (!zh->res)
1698     {
1699         zh->errCode = 109;
1700         return -1;
1701     }
1702     rval = res_get (zh->res, "shadow");
1703
1704     bfs = bfs_create (res_get (zh->service->global_res, "register"),
1705                       zh->path_reg);
1706     if (rval && *rval)
1707         bf_cache (bfs, rval);
1708     
1709     bf_reset (bfs);
1710     bfs_destroy (bfs);
1711     zebra_set_state (zh, 'o', 0);
1712     return 0;
1713 }
1714
1715 int zebra_compact (ZebraHandle zh)
1716 {
1717     BFiles bfs;
1718     ASSERTZH;
1719     yaz_log(LOG_API,"zebra_compact");
1720     zh->errCode=0;
1721     if (!zh->res)
1722     {
1723         zh->errCode = 109;
1724         return -1;
1725     }
1726     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
1727     inv_compact (bfs);
1728     bfs_destroy (bfs);
1729     return 0;
1730 }
1731
1732 int zebra_result (ZebraHandle zh, int *code, char **addinfo)
1733 {
1734     ASSERTZH;
1735     yaz_log(LOG_API,"zebra_result");
1736     *code = zh->errCode;
1737     *addinfo = zh->errString;
1738     return 0;
1739 }
1740
1741 int zebra_shadow_enable (ZebraHandle zh, int value)
1742 {
1743     ASSERTZH;
1744     yaz_log(LOG_API,"zebra_shadow_enable");
1745     zh->errCode=0;
1746     zh->shadow_enable = value;
1747     return 0;
1748 }
1749
1750 int zebra_record_encoding (ZebraHandle zh, const char *encoding)
1751 {
1752     ASSERTZH;
1753     yaz_log(LOG_API,"zebra_record_encoding");
1754     zh->errCode=0;
1755     xfree (zh->record_encoding);
1756
1757     /*
1758      * Fixme!
1759      * Something about charset aliases. Oleg???
1760      */
1761
1762     if (zh->iconv_to_utf8 != 0)
1763         yaz_iconv_close(zh->iconv_to_utf8);
1764     if (zh->iconv_from_utf8 != 0)
1765         yaz_iconv_close(zh->iconv_from_utf8);
1766     
1767     zh->record_encoding = xstrdup (encoding);
1768     
1769     logf(LOG_DEBUG, "Reset record encoding: %s", encoding);
1770     
1771     zh->iconv_to_utf8 =
1772         yaz_iconv_open ("UTF-8", encoding);
1773     if (zh->iconv_to_utf8 == 0)
1774         yaz_log (LOG_WARN, "iconv: %s to UTF-8 unsupported", encoding);
1775     zh->iconv_from_utf8 =
1776         yaz_iconv_open (encoding, "UTF-8");
1777     if (zh->iconv_to_utf8 == 0)
1778         yaz_log (LOG_WARN, "iconv: UTF-8 to %s unsupported", encoding);
1779
1780     return 0;
1781 }
1782
1783 int zebra_set_resource(ZebraHandle zh, const char *name, const char *value)
1784 {
1785     ASSERTZH;
1786     yaz_log(LOG_API,"zebra_set_resource %s:%s",name,value);
1787     zh->errCode=0;
1788     res_set(zh->res, name, value);
1789     return 0;
1790 }
1791
1792 const char *zebra_get_resource(ZebraHandle zh,
1793                                const char *name, const char *defaultvalue)
1794 {
1795     const char *v;
1796     ASSERTZH;
1797     v= res_get_def( zh->res, name, (char *)defaultvalue);
1798     zh->errCode=0;
1799     yaz_log(LOG_API,"zebra_get_resource %s:%s",name,v);
1800     return v;
1801 }
1802
1803 /* moved from zebra_api_ext.c by pop */
1804 /* FIXME: Should this really be public??? -Heikki */
1805
1806 int zebra_trans_no (ZebraHandle zh)
1807 {
1808     ASSERTZH;
1809     yaz_log(LOG_API,"zebra_trans_no");
1810     return zh->trans_no;
1811 }
1812
1813 int zebra_get_shadow_enable (ZebraHandle zh)
1814 {
1815     yaz_log(LOG_API,"zebra_get_shadow_enable");
1816     return (zh->shadow_enable);
1817 }
1818
1819 int zebra_set_shadow_enable (ZebraHandle zh, int value)
1820 {
1821     yaz_log(LOG_API,"zebra_set_shadow_enable %d",value);
1822     zh->shadow_enable = value;
1823     return 0;
1824 }
1825
1826 /* almost the same as zebra_records_retrieve ... but how did it work? 
1827    I mean for multiple records ??? CHECK ??? */
1828 void api_records_retrieve (ZebraHandle zh, ODR stream,
1829                            const char *setname, Z_RecordComposition *comp,
1830                            oid_value input_format, int num_recs,
1831                            ZebraRetrievalRecord *recs)
1832 {
1833     ZebraPosSet poset;
1834     int i, *pos_array;
1835     yaz_log(LOG_API,"api_records_retrieve s=%s n=%d",setname,num_recs);
1836
1837     if (!zh->res)
1838     {
1839         zh->errCode = 30;
1840         zh->errString = odr_strdup (stream, setname);
1841         return;
1842     }
1843     
1844     zh->errCode = 0; 
1845
1846     if (zebra_begin_read (zh))
1847         return;
1848
1849     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
1850     for (i = 0; i<num_recs; i++)
1851         pos_array[i] = recs[i].position;
1852     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
1853     if (!poset)
1854     {
1855         logf (LOG_DEBUG, "zebraPosSetCreate error");
1856         zh->errCode = 30;
1857         zh->errString = nmem_strdup (stream->mem, setname);
1858     }
1859     else
1860     {
1861         for (i = 0; i<num_recs; i++)
1862         {
1863             if (poset[i].term)
1864             {
1865                 recs[i].errCode = 0;
1866                 recs[i].format = VAL_SUTRS;
1867                 recs[i].len = strlen(poset[i].term);
1868                 recs[i].buf = poset[i].term;
1869                 recs[i].base = poset[i].db;
1870                 recs[i].sysno = 0;
1871             
1872             }
1873             else if (poset[i].sysno)
1874             {
1875               /* changed here ??? CHECK ??? */
1876               char *b;
1877                 recs[i].errCode =
1878                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
1879                                         stream, input_format, comp,
1880                                         &recs[i].format, 
1881                                         &b,
1882                                         &recs[i].len,
1883                                         &recs[i].base);
1884                 recs[i].buf = (char *) odr_malloc(stream,recs[i].len);
1885                 memcpy(recs[i].buf, b, recs[i].len);
1886                 recs[i].errString = 0; /* Hmmm !!! we should get this */ 
1887                 recs[i].sysno = poset[i].sysno;
1888                 recs[i].score = poset[i].score;
1889             }
1890             else
1891             {
1892                 char num_str[20];
1893
1894                 sprintf (num_str, "%d", pos_array[i]);  
1895                 zh->errCode = 13;
1896                 zh->errString = odr_strdup (stream, num_str);
1897                 break;
1898             }
1899
1900         }
1901         zebraPosSetDestroy (zh, poset, num_recs);
1902     }
1903     zebra_end_read (zh);
1904     xfree (pos_array);
1905 }
1906
1907
1908 /* ---------------------------------------------------------------------------
1909   Record insert(=update), delete 
1910
1911   If sysno is provided, then it's used to identify the record.
1912   If not, and match_criteria is provided, then sysno is guessed
1913   If not, and a record is provided, then sysno is got from there
1914 NOTE: Now returns 0 at success and updates sysno, which is an int*
1915   20-jun-2003 Heikki
1916 */
1917
1918 int zebra_add_record(ZebraHandle zh,
1919                      const char *buf, int buf_size)
1920 {
1921     int sysno = 0;
1922     return zebra_update_record(zh, 0, &sysno, 0, 0, buf, buf_size, 0);
1923 }
1924
1925 int zebra_insert_record (ZebraHandle zh, 
1926                          const char *recordType,
1927                          int *sysno, const char *match, const char *fname,
1928                          const char *buf, int buf_size)
1929 {
1930     int res;
1931     yaz_log(LOG_API,"zebra_insert_record sysno=%d", *sysno);
1932
1933     if (buf_size < 1) buf_size = strlen(buf);
1934
1935     zebra_begin_trans(zh, 1);
1936     res = buffer_extract_record (zh, buf, buf_size, 
1937                                  0, /* delete_flag  */
1938                                  0, /* test_mode */
1939                                  recordType,
1940                                  sysno,   
1941                                  match, fname,
1942                                  0, 
1943                                  0); /* allow_update */
1944     zebra_end_trans(zh); 
1945     return res; 
1946 }
1947
1948 int zebra_update_record (ZebraHandle zh, 
1949                          const char *recordType,
1950                          int* sysno, const char *match, const char *fname,
1951                          const char *buf, int buf_size,
1952                          int force_update)
1953 {
1954     int res;
1955
1956     yaz_log(LOG_API,"zebra_update_record sysno=%d", *sysno);
1957
1958     if (buf_size < 1) buf_size = strlen(buf);
1959
1960     zebra_begin_trans(zh, 1);
1961     res = buffer_extract_record (zh, buf, buf_size, 
1962                                  0, /* delete_flag */
1963                                  0, /* test_mode */
1964                                  recordType,
1965                                  sysno,   
1966                                  match, fname,
1967                                  force_update, 
1968                                  1); /* allow_update */
1969     zebra_end_trans(zh); 
1970     return res; 
1971 }
1972
1973 int zebra_delete_record (ZebraHandle zh, 
1974                          const char *recordType,
1975                          int *sysno, const char *match, const char *fname,
1976                          const char *buf, int buf_size,
1977                          int force_update) 
1978 {
1979     int res;
1980     yaz_log(LOG_API,"zebra_delete_record sysno=%d", *sysno);
1981
1982     if (buf_size < 1) buf_size = strlen(buf);
1983
1984     zebra_begin_trans(zh, 1);
1985     res = buffer_extract_record (zh, buf, buf_size,
1986                                  1, /* delete_flag */
1987                                  0, /* test_mode */
1988                                  recordType,
1989                                  sysno,
1990                                  match,fname,
1991                                  force_update,
1992                                  1); /* allow_update */
1993     zebra_end_trans(zh);
1994     return res;   
1995 }
1996
1997 /* ---------------------------------------------------------------------------
1998   Searching 
1999 */
2000
2001 int zebra_search_PQF (ZebraHandle zh, const char *pqf_query,
2002                       const char *setname, int *numhits)
2003 {
2004     int hits = 0;
2005     int res=-1;
2006     Z_RPNQuery *query;
2007     ODR odr = odr_createmem(ODR_ENCODE);
2008
2009     yaz_log(LOG_API,"zebra_search_PQF s=%s q=%s",setname, pqf_query);
2010     
2011     query = p_query_rpn (odr, PROTO_Z3950, pqf_query);
2012     
2013     if (!query)
2014         yaz_log (LOG_WARN, "bad query %s\n", pqf_query);
2015     else
2016         res=zebra_search_RPN (zh, odr, query, setname, &hits);
2017     
2018     odr_destroy(odr);
2019
2020     yaz_log(LOG_API,"Hits: %d",hits);
2021
2022     if (numhits)
2023         *numhits=hits;
2024
2025     return res;
2026 }
2027
2028 /* ---------------------------------------------------------------------------
2029   Sort - a simplified interface, with optional read locks.
2030   FIXME - This is a horrible name, will conflict with half the applications
2031 */
2032 int zebra_sort_by_specstr (ZebraHandle zh, 
2033                            ODR stream,
2034                            const char *sort_spec,
2035                            const char *output_setname,
2036                            const char **input_setnames) 
2037 {
2038     int num_input_setnames = 0;
2039     int sort_status = 0;
2040     Z_SortKeySpecList *sort_sequence = yaz_sort_spec (stream, sort_spec);
2041     yaz_log(LOG_API,"sort (FIXME) ");
2042     if (!sort_sequence)
2043     {
2044         logf(LOG_WARN,"invalid sort specs '%s'", sort_spec);
2045         zh->errCode = 207;
2046         return -1;
2047     }
2048     
2049     /* we can do this, since the perl typemap code for char** will 
2050        put a NULL at the end of list */
2051     while (input_setnames[num_input_setnames]) num_input_setnames++;
2052
2053     if (zebra_begin_read (zh))
2054         return -1;
2055     
2056     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
2057                    output_setname, sort_sequence, &sort_status);
2058     
2059     zebra_end_read(zh);
2060     return sort_status;
2061 }