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