Using zebra::index::field:s rather than zebra::sort::field for retrieval
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /* $Id: zebraapi.c,v 1.239 2006-12-19 16:57:38 adam Exp $
2    Copyright (C) 1995-2006
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 this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <assert.h>
24 #include <stdio.h>
25 #include <limits.h>
26 #ifdef WIN32
27 #include <io.h>
28 #include <process.h>
29 #include <direct.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <yaz/diagbib1.h>
36 #include <yaz/pquery.h>
37 #include <yaz/sortspec.h>
38 #include "index.h"
39 #include "rank.h"
40 #include "orddict.h"
41 #include <charmap.h>
42 #include <idzebra/api.h>
43
44 #define DEFAULT_APPROX_LIMIT 2000000000
45
46 /* simple asserts to validate the most essential input args */
47 #define ASSERTZH assert(zh && zh->service)
48 #define ASSERTZHRES assert(zh && zh->service && zh->res)
49 #define ASSERTZS assert(zs)
50
51 static int log_level = 0;
52 static int log_level_initialized = 0;
53
54 static void zebra_open_res(ZebraHandle zh);
55 static void zebra_close_res(ZebraHandle zh);
56
57 static ZEBRA_RES zebra_check_handle(ZebraHandle zh)
58 {
59     if (zh)
60         return ZEBRA_OK;
61     return ZEBRA_FAIL;
62 }
63
64 #define ZEBRA_CHECK_HANDLE(zh) if (zebra_check_handle(zh) != ZEBRA_OK) return ZEBRA_FAIL
65
66 static void zebra_chdir (ZebraService zs)
67 {
68     const char *dir ;
69     ASSERTZS;
70     yaz_log(log_level, "zebra_chdir");
71     dir = res_get (zs->global_res, "chdir");
72     if (!dir)
73         return;
74     yaz_log (YLOG_DEBUG, "chdir %s", dir);
75 #ifdef WIN32
76     _chdir(dir);
77 #else
78     chdir (dir);
79 #endif
80 }
81
82 static ZEBRA_RES zebra_flush_reg (ZebraHandle zh)
83 {
84     ZEBRA_CHECK_HANDLE(zh);
85     yaz_log(log_level, "zebra_flush_reg");
86     zebraExplain_flush (zh->reg->zei, zh);
87
88     key_block_flush(zh->reg->key_block, 1);
89
90     zebra_index_merge(zh);
91     return ZEBRA_OK;
92 }
93
94 static struct zebra_register *zebra_register_open(ZebraService zs, 
95                                                   const char *name,
96                                                   int rw, int useshadow,
97                                                   Res res,
98                                                   const char *reg_path);
99 static void zebra_register_close(ZebraService zs, struct zebra_register *reg);
100
101 ZebraHandle zebra_open(ZebraService zs, Res res)
102 {
103     ZebraHandle zh;
104     const char *default_encoding;
105     if (!log_level_initialized)
106     {
107         log_level = yaz_log_module_level("zebraapi");
108         log_level_initialized = 1;
109     }
110
111     yaz_log(log_level, "zebra_open");
112
113     if (!zs)
114         return 0;
115
116     zh = (ZebraHandle) xmalloc(sizeof(*zh));
117     yaz_log (YLOG_DEBUG, "zebra_open zs=%p returns %p", zs, zh);
118
119     zh->service = zs;
120     zh->reg = 0;          /* no register attached yet */
121     zh->sets = 0;
122     zh->destroyed = 0;
123     zh->errCode = 0;
124     zh->errString = 0;
125     zh->res = 0; 
126     zh->session_res = res_open(zs->global_res, res);
127     zh->user_perm = 0;
128     zh->dbaccesslist = 0;
129
130     zh->reg_name = xstrdup ("");
131     zh->path_reg = 0;
132     zh->num_basenames = 0;
133     zh->basenames = 0;
134
135     zh->approx_limit = DEFAULT_APPROX_LIMIT;
136     zh->trans_no = 0;
137     zh->trans_w_no = 0;
138
139     zh->lock_normal = 0;
140     zh->lock_shadow = 0;
141
142     zh->shadow_enable = 1;
143     zh->m_staticrank = 0;
144     zh->m_segment_indexing = 0;
145
146     default_encoding = res_get_def(zh->session_res, "encoding", "ISO-8859-1");
147
148     zh->iconv_to_utf8 =
149         yaz_iconv_open ("UTF-8", default_encoding);
150     if (zh->iconv_to_utf8 == 0)
151         yaz_log (YLOG_WARN, "iconv: %s to UTF-8 unsupported",
152            default_encoding);
153     zh->iconv_from_utf8 =
154         yaz_iconv_open (default_encoding, "UTF-8");
155     if (zh->iconv_to_utf8 == 0)
156         yaz_log (YLOG_WARN, "iconv: UTF-8 to %s unsupported",
157            default_encoding);
158
159     zh->record_encoding = 0;
160
161     zebra_mutex_cond_lock (&zs->session_lock);
162
163     zh->next = zs->sessions;
164     zs->sessions = zh;
165
166     zebra_mutex_cond_unlock (&zs->session_lock);
167
168     zh->store_data_buf = 0;
169
170     zh->m_limit = zebra_limit_create(1, 0);
171
172     zh->nmem_error = nmem_create();
173
174     return zh;
175 }
176
177 ZebraService zebra_start(const char *configName)
178 {
179     return zebra_start_res(configName, 0, 0);
180 }
181
182 ZebraService zebra_start_res(const char *configName, Res def_res, Res over_res)
183 {
184     Res res;
185
186     zebra_flock_init();
187
188     if (!log_level_initialized)
189     {
190         log_level = yaz_log_module_level("zebraapi");
191         log_level_initialized = 1;
192     }
193     
194     yaz_log(YLOG_LOG, "zebra_start %s %s", ZEBRAVER,
195             configName ? configName : "");
196
197     if ((res = res_open(def_res, over_res)))
198     {
199         const char *passwd_plain = 0;
200         const char *passwd_encrypt = 0;
201         const char *dbaccess = 0;
202         ZebraService zh = 0;
203
204         if (configName)
205         {
206             ZEBRA_RES ret = res_read_file(res, configName);
207             if (ret != ZEBRA_OK)
208             {
209                 res_close(res);
210                 return 0;
211             }
212             if (zebra_check_res(res))
213             {
214                 yaz_log(YLOG_FATAL, "Configuration error(s) for %s",
215                         configName);
216                 return 0;
217             }
218         }
219         else
220         {
221             zebra_check_res(res);
222         }
223
224         zh = xmalloc(sizeof(*zh));
225         zh->global_res = res;
226         zh->sessions = 0;
227         
228         zebra_chdir (zh);
229         
230         zebra_mutex_cond_init (&zh->session_lock);
231         passwd_plain = res_get (zh->global_res, "passwd");
232         passwd_encrypt = res_get (zh->global_res, "passwd.c");
233         dbaccess = res_get (zh->global_res, "dbaccess");
234
235         if (!passwd_plain && !passwd_encrypt)
236             zh->passwd_db = NULL;
237         else 
238         {
239             zh->passwd_db = passwd_db_open();
240             if (!zh->passwd_db)
241                 yaz_log (YLOG_WARN|YLOG_ERRNO, "passwd_db_open failed");
242             else
243             {
244                 if (passwd_plain)
245                     passwd_db_file_plain(zh->passwd_db, passwd_plain);
246                 if (passwd_encrypt)
247                     passwd_db_file_crypt(zh->passwd_db, passwd_encrypt);
248             }
249         }
250
251         if (!dbaccess)
252             zh->dbaccess = NULL;
253         else {
254             zh->dbaccess = res_open(NULL, NULL);
255             if (res_read_file(zh->dbaccess, dbaccess) != ZEBRA_OK) {
256                 yaz_log(YLOG_FATAL, "Failed to read %s", dbaccess);
257                 return NULL;
258             }
259         }
260
261         zh->path_root = res_get (zh->global_res, "root");
262         zh->nmem = nmem_create();
263         zh->record_classes = recTypeClass_create (zh->global_res, zh->nmem);
264
265         if (1)
266         {
267             const char *module_path = res_get(res, "modulePath");
268             if (module_path)
269                 recTypeClass_load_modules(&zh->record_classes, zh->nmem,
270                                           module_path);
271         }
272         return zh;
273     }
274     return 0;
275 }
276
277 void zebra_filter_info(ZebraService zs, void *cd,
278                         void (*cb)(void *cd, const char *name))
279 {
280     ASSERTZS;
281     assert(cb);
282     recTypeClass_info(zs->record_classes, cd, cb);
283 }
284
285 void zebra_pidfname(ZebraService zs, char *path)
286 {
287     ASSERTZS;
288     zebra_lock_prefix (zs->global_res, path);
289     strcat(path, "zebrasrv.pid");
290 }
291
292 Dict dict_open_res (BFiles bfs, const char *name, int cache, int rw,
293                     int compact_flag, Res res)
294 {
295     int page_size = 4096;
296     char resource_str[200];
297     sprintf (resource_str, "dict.%.100s.pagesize", name);
298     assert(bfs);
299     assert(name);
300
301     if (res_get_int(res, resource_str, &page_size) == ZEBRA_OK)
302         yaz_log(YLOG_LOG, "Using custom dictionary page size %d for %s",
303                 page_size, name);
304     return dict_open(bfs, name, cache, rw, compact_flag, page_size);
305 }
306
307 static
308 struct zebra_register *zebra_register_open(ZebraService zs, const char *name,
309                                            int rw, int useshadow, Res res,
310                                            const char *reg_path)
311 {
312     struct zebra_register *reg;
313     int record_compression = REC_COMPRESS_NONE;
314     const char *recordCompression = 0;
315     const char *profilePath;
316     char cwd[1024];
317     int sort_type = ZEBRA_SORT_TYPE_FLAT;
318     ZEBRA_RES ret = ZEBRA_OK;
319
320     ASSERTZS;
321     
322     reg = xmalloc(sizeof(*reg));
323
324     assert (name);
325     reg->name = xstrdup (name);
326
327     reg->seqno = 0;
328     reg->last_val = 0;
329
330     assert (res);
331
332     yaz_log (YLOG_DEBUG, "zebra_register_open rw=%d useshadow=%d p=%p n=%s rp=%s",
333              rw, useshadow, reg, name, reg_path ? reg_path : "(none)");
334     
335     reg->dh = data1_create();
336     if (!reg->dh)
337     {
338         xfree(reg->name);
339         xfree(reg);
340         return 0;
341     }
342     reg->bfs = bfs_create (res_get (res, "register"), reg_path);
343     if (!reg->bfs)
344     {
345         data1_destroy(reg->dh);
346         xfree(reg->name);
347         xfree(reg);
348         return 0;
349     }
350     if (useshadow)
351     {
352         if (bf_cache (reg->bfs, res_get (res, "shadow")) == ZEBRA_FAIL)
353         {
354             bfs_destroy(reg->bfs);
355             data1_destroy(reg->dh);
356             xfree(reg->name);
357             xfree(reg);
358             return 0;
359         }
360     }
361
362     getcwd(cwd, sizeof(cwd)-1);
363     profilePath = res_get_def(res, "profilePath", 0);
364
365     data1_set_tabpath (reg->dh, profilePath);
366     data1_set_tabroot (reg->dh, reg_path);
367     reg->recTypes = recTypes_init (zs->record_classes, reg->dh);
368
369     reg->zebra_maps =
370         zebra_maps_open(res, reg_path, profilePath);
371     if (!reg->zebra_maps)
372     {
373         recTypes_destroy(reg->recTypes);
374         bfs_destroy(reg->bfs);
375         data1_destroy(reg->dh);
376         xfree(reg->name);
377         xfree(reg);
378         return 0;
379     }
380     reg->rank_classes = NULL;
381
382     reg->key_block = 0;
383     reg->keys = zebra_rec_keys_open();
384
385     reg->sortKeys = zebra_rec_keys_open();
386
387     reg->records = 0;
388     reg->dict = 0;
389     reg->sort_index = 0;
390     reg->isams = 0;
391     reg->matchDict = 0;
392     reg->isamc = 0;
393     reg->isamb = 0;
394     reg->zei = 0;
395     
396     /* installing rank classes */
397     zebraRankInstall (reg, rank_1_class);
398     zebraRankInstall (reg, rank_similarity_class);
399     zebraRankInstall (reg, rank_static_class);
400
401     recordCompression = res_get_def (res, "recordCompression", "none");
402     if (!strcmp (recordCompression, "none"))
403         record_compression = REC_COMPRESS_NONE;
404     if (!strcmp (recordCompression, "bzip2"))
405         record_compression = REC_COMPRESS_BZIP2;
406
407     if (1)
408     {
409         const char *index_fname = res_get_def(res, "index", "default.idx");
410         if (index_fname && *index_fname)
411         {
412             if (zebra_maps_read_file(reg->zebra_maps, index_fname) != ZEBRA_OK)
413                 ret = ZEBRA_FAIL;
414         }
415     }
416
417     if (!(reg->records = rec_open (reg->bfs, rw, record_compression)))
418     {
419         yaz_log (YLOG_WARN, "rec_open failed");
420         ret = ZEBRA_FAIL;
421     }
422     if (rw)
423     {
424         reg->matchDict = dict_open_res (reg->bfs, GMATCH_DICT, 20, 1, 0, res);
425     }
426     if (!(reg->dict = dict_open_res (reg->bfs, FNAME_DICT, 40, rw, 0, res)))
427     {
428         yaz_log (YLOG_WARN, "dict_open failed");
429         ret = ZEBRA_FAIL;
430     }
431
432     
433     if (res_get_match (res, "sortindex", "f", "f"))
434         sort_type = ZEBRA_SORT_TYPE_FLAT;
435     else if (res_get_match (res, "sortindex", "i", "f"))
436         sort_type = ZEBRA_SORT_TYPE_ISAMB;
437     else
438     {
439         yaz_log (YLOG_WARN, "bad_value for 'sortindex'");
440         ret = ZEBRA_FAIL;
441     }
442
443
444     if (!(reg->sort_index = zebra_sort_open(reg->bfs, rw, sort_type)))
445     {
446         yaz_log (YLOG_WARN, "zebra_sort_open failed");
447         ret = ZEBRA_FAIL;
448     }
449     if (res_get_match (res, "isam", "s", ISAM_DEFAULT))
450     {
451         struct ISAMS_M_s isams_m;
452         if (!(reg->isams = isams_open (reg->bfs, FNAME_ISAMS, rw,
453                                       key_isams_m(res, &isams_m))))
454         {
455             yaz_log (YLOG_WARN, "isams_open failed");
456             ret = ZEBRA_FAIL;
457         }
458     }
459     if (res_get_match (res, "isam", "c", ISAM_DEFAULT))
460     {
461         struct ISAMC_M_s isamc_m;
462         if (!(reg->isamc = isamc_open (reg->bfs, FNAME_ISAMC,
463                                     rw, key_isamc_m(res, &isamc_m))))
464         {
465             yaz_log (YLOG_WARN, "isamc_open failed");
466             ret = ZEBRA_FAIL;
467         }
468     }
469     if (res_get_match (res, "isam", "b", ISAM_DEFAULT))
470     {
471         struct ISAMC_M_s isamc_m;
472         
473         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
474                                        rw, key_isamc_m(res, &isamc_m), 0)))
475         {
476             yaz_log (YLOG_WARN, "isamb_open failed");
477             ret = ZEBRA_FAIL;
478         }
479     }
480     if (res_get_match (res, "isam", "bc", ISAM_DEFAULT))
481     {
482         struct ISAMC_M_s isamc_m;
483         
484         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
485                                        rw, key_isamc_m(res, &isamc_m), 1)))
486         {
487             yaz_log (YLOG_WARN, "isamb_open failed");
488             ret = ZEBRA_FAIL;
489         }
490     }
491     if (res_get_match (res, "isam", "null", ISAM_DEFAULT))
492     {
493         struct ISAMC_M_s isamc_m;
494         
495         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
496                                        rw, key_isamc_m(res, &isamc_m), -1)))
497         {
498             yaz_log (YLOG_WARN, "isamb_open failed");
499             ret = ZEBRA_FAIL;
500         }
501     }
502     if (ret == ZEBRA_OK)
503     {
504         reg->zei = zebraExplain_open(reg->records, reg->dh,
505                                      res, rw, reg,
506                                      zebra_extract_explain);
507         if (!reg->zei)
508         {
509             yaz_log (YLOG_WARN, "Cannot obtain EXPLAIN information");
510             ret = ZEBRA_FAIL;
511         }
512     }
513     
514     if (ret != ZEBRA_OK)
515     {
516         zebra_register_close(zs, reg);
517         return 0;
518     }
519     yaz_log (YLOG_DEBUG, "zebra_register_open ok p=%p", reg);
520     return reg;
521 }
522
523 ZEBRA_RES zebra_admin_shutdown (ZebraHandle zh)
524 {
525     ZEBRA_CHECK_HANDLE(zh);
526     yaz_log(log_level, "zebra_admin_shutdown");
527
528     zebra_mutex_cond_lock (&zh->service->session_lock);
529     zh->service->stop_flag = 1;
530     zebra_mutex_cond_unlock (&zh->service->session_lock);
531     return ZEBRA_OK;
532 }
533
534 ZEBRA_RES zebra_admin_start (ZebraHandle zh)
535 {
536     ZebraService zs;
537     ZEBRA_CHECK_HANDLE(zh);
538     yaz_log(log_level, "zebra_admin_start");
539     zs = zh->service;
540     zebra_mutex_cond_lock (&zs->session_lock);
541     zebra_mutex_cond_unlock (&zs->session_lock);
542     return ZEBRA_OK;
543 }
544
545 static void zebra_register_close(ZebraService zs, struct zebra_register *reg)
546 {
547     ASSERTZS;
548     assert(reg);
549     yaz_log(YLOG_DEBUG, "zebra_register_close p=%p", reg);
550     reg->stop_flag = 0;
551     zebra_chdir (zs);
552     
553     zebraExplain_close (reg->zei);
554     dict_close (reg->dict);
555     if (reg->matchDict)
556         dict_close (reg->matchDict);
557     zebra_sort_close(reg->sort_index);
558     if (reg->isams)
559         isams_close (reg->isams);
560     if (reg->isamc)
561         isamc_close (reg->isamc);
562     if (reg->isamb)
563         isamb_close (reg->isamb);
564     rec_close (&reg->records);
565
566     recTypes_destroy (reg->recTypes);
567     zebra_maps_close (reg->zebra_maps);
568     zebraRankDestroy (reg);
569     bfs_destroy (reg->bfs);
570     data1_destroy (reg->dh);
571
572     zebra_rec_keys_close(reg->keys);
573     zebra_rec_keys_close(reg->sortKeys);
574
575     key_block_destroy(&reg->key_block);
576     xfree(reg->name);
577     xfree(reg);
578 }
579
580 ZEBRA_RES zebra_stop(ZebraService zs)
581 {
582     if (!zs)
583         return ZEBRA_OK;
584     yaz_log (log_level, "zebra_stop");
585
586     while (zs->sessions)
587     {
588         zebra_close (zs->sessions);
589     }
590         
591     zebra_mutex_cond_destroy (&zs->session_lock);
592
593     if (zs->passwd_db)
594         passwd_db_close (zs->passwd_db);
595
596     recTypeClass_destroy(zs->record_classes);
597     nmem_destroy(zs->nmem);
598     res_close (zs->global_res);
599     xfree(zs);
600     return ZEBRA_OK;
601 }
602
603 ZEBRA_RES zebra_close(ZebraHandle zh)
604 {
605     ZebraService zs;
606     struct zebra_session **sp;
607     int i;
608
609     yaz_log(log_level, "zebra_close");
610     ZEBRA_CHECK_HANDLE(zh);
611
612     zh->errCode = 0;
613     
614     zs = zh->service;
615     yaz_log (YLOG_DEBUG, "zebra_close zh=%p", zh);
616     resultSetDestroy (zh, -1, 0, 0);
617
618     if (zh->reg)
619         zebra_register_close(zh->service, zh->reg);
620     zebra_close_res (zh);
621     res_close(zh->session_res);
622
623     xfree(zh->record_encoding);
624
625     xfree(zh->dbaccesslist);
626
627     for (i = 0; i < zh->num_basenames; i++)
628         xfree(zh->basenames[i]);
629     xfree(zh->basenames);
630
631     if (zh->iconv_to_utf8 != 0)
632         yaz_iconv_close (zh->iconv_to_utf8);
633     if (zh->iconv_from_utf8 != 0)
634         yaz_iconv_close (zh->iconv_from_utf8);
635
636     zebra_mutex_cond_lock (&zs->session_lock);
637     zebra_lock_destroy (zh->lock_normal);
638     zebra_lock_destroy (zh->lock_shadow);
639     sp = &zs->sessions;
640     while (1)
641     {
642         assert (*sp);
643         if (*sp == zh)
644         {
645             *sp = (*sp)->next;
646             break;
647         }
648         sp = &(*sp)->next;
649     }
650     zebra_mutex_cond_unlock (&zs->session_lock);
651     xfree(zh->reg_name);
652     xfree(zh->user_perm);
653     zh->service = 0; /* more likely to trigger an assert */
654
655     zebra_limit_destroy(zh->m_limit);
656
657     nmem_destroy(zh->nmem_error);
658
659     xfree(zh->path_reg);
660     xfree(zh);
661     return ZEBRA_OK;
662 }
663
664 struct map_baseinfo {
665     ZebraHandle zh;
666     NMEM mem;
667     int num_bases;
668     char **basenames;
669     int new_num_bases;
670     char **new_basenames;
671     int new_num_max;
672 };
673
674 static void zebra_open_res(ZebraHandle zh)
675 {
676     char fname[512];
677     ASSERTZH;
678     zh->errCode = 0;
679
680     if (zh->path_reg)
681     {
682         sprintf(fname, "%.200s/zebra.cfg", zh->path_reg);
683         zh->res = res_open(zh->session_res, 0);
684         res_read_file(zh->res, fname);
685     }
686     else if (*zh->reg_name == 0)
687     {
688         zh->res = res_open(zh->session_res, 0);
689     }
690     else
691     {
692         yaz_log (YLOG_WARN, "no register root specified");
693         zh->res = 0;  /* no path for register - fail! */
694     }
695 }
696
697 static void zebra_close_res (ZebraHandle zh)
698 {
699     ASSERTZH;
700     zh->errCode = 0;
701     res_close (zh->res);
702     zh->res = 0;
703 }
704
705 static void zebra_select_register (ZebraHandle zh, const char *new_reg)
706 {
707     ASSERTZH;
708     zh->errCode = 0;
709     if (zh->res && strcmp (zh->reg_name, new_reg) == 0)
710         return;
711     if (!zh->res)
712     {
713         assert (zh->reg == 0);
714         assert (*zh->reg_name == 0);
715     }
716     else
717     {
718         if (zh->reg)
719         {
720             resultSetInvalidate (zh);
721             zebra_register_close(zh->service, zh->reg);
722             zh->reg = 0;
723         }
724         zebra_close_res(zh);
725     }
726     xfree(zh->reg_name);
727     zh->reg_name = xstrdup (new_reg);
728
729     xfree(zh->path_reg);
730     zh->path_reg = 0;
731     if (zh->service->path_root)
732     {
733         zh->path_reg = xmalloc(strlen(zh->service->path_root) + 
734                                 strlen(zh->reg_name) + 3);
735         strcpy (zh->path_reg, zh->service->path_root);
736         if (*zh->reg_name)
737         {
738             strcat (zh->path_reg, "/");
739             strcat (zh->path_reg, zh->reg_name);
740         }
741     }
742     zebra_open_res(zh);
743     
744     if (zh->lock_normal)
745         zebra_lock_destroy (zh->lock_normal);
746     zh->lock_normal = 0;
747
748     if (zh->lock_shadow)
749         zebra_lock_destroy (zh->lock_shadow);
750     zh->lock_shadow = 0;
751
752     if (zh->res)
753     {
754         char fname[512];
755         const char *lock_area = res_get (zh->res, "lockDir");
756         
757         if (!lock_area && zh->path_reg)
758             res_set (zh->res, "lockDir", zh->path_reg);
759         sprintf (fname, "norm.%s.LCK", zh->reg_name);
760         zh->lock_normal =
761             zebra_lock_create (res_get(zh->res, "lockDir"), fname);
762         
763         sprintf (fname, "shadow.%s.LCK", zh->reg_name);
764         zh->lock_shadow =
765             zebra_lock_create (res_get(zh->res, "lockDir"), fname);
766
767         if (!zh->lock_normal || !zh->lock_shadow)
768         {
769             if (zh->lock_normal)
770             {
771                 zebra_lock_destroy(zh->lock_normal);
772                 zh->lock_normal = 0;
773             }
774             if (zh->lock_shadow)
775             {
776                 zebra_lock_destroy(zh->lock_shadow);
777                 zh->lock_shadow = 0;
778             }
779             zebra_close_res(zh);
780         }
781     }
782     if (zh->res)
783     {
784         int approx = 0;
785         if (res_get_int(zh->res, "estimatehits", &approx) == ZEBRA_OK)
786             zebra_set_approx_limit(zh, approx);
787     }
788     if (zh->res)
789     {
790         if (res_get_int(zh->res, "staticrank", &zh->m_staticrank) == ZEBRA_OK)
791             yaz_log(YLOG_LOG, "static rank set and is %d", zh->m_staticrank);
792     }
793     if (zh->res)
794     {
795         if (res_get_int(zh->res, "segment", &zh->m_segment_indexing) == 
796             ZEBRA_OK)
797         {
798             yaz_log(YLOG_DEBUG, "segment indexing set and is %d",
799                     zh->m_segment_indexing);
800         }
801     }
802 }
803
804 void map_basenames_func (void *vp, const char *name, const char *value)
805 {
806     struct map_baseinfo *p = (struct map_baseinfo *) vp;
807     int i, no;
808     char fromdb[128], todb[8][128];
809
810     assert(value);
811     assert(name);
812     assert(vp);
813     
814     no =
815         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
816                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
817                 todb[5], todb[6], todb[7]);
818     if (no < 2)
819         return ;
820     no--;
821     for (i = 0; i<p->num_bases; i++)
822         if (p->basenames[i] && !STRCASECMP (p->basenames[i], fromdb))
823         {
824             p->basenames[i] = 0;
825             for (i = 0; i < no; i++)
826             {
827                 if (p->new_num_bases == p->new_num_max)
828                     return;
829                 p->new_basenames[(p->new_num_bases)++] = 
830                     nmem_strdup (p->mem, todb[i]);
831             }
832             return;
833         }
834 }
835
836 int zebra_select_default_database(ZebraHandle zh)
837 {
838     if (!zh->res)
839     {
840         /* no database has been selected - so we select based on
841            resource setting (including group)
842         */
843         const char *group = res_get(zh->session_res, "group");
844         const char *v = res_get_prefix(zh->session_res,
845                                        "database", group, "Default");
846         return zebra_select_database(zh, v);
847     }
848     return 0;
849 }
850
851 void map_basenames (ZebraHandle zh, ODR stream,
852                     int *num_bases, char ***basenames)
853 {
854     struct map_baseinfo info;
855     struct map_baseinfo *p = &info;
856     int i;
857     ASSERTZH;
858     yaz_log(log_level, "map_basenames ");
859     assert(stream);
860
861     info.zh = zh;
862
863     info.num_bases = *num_bases;
864     info.basenames = *basenames;
865     info.new_num_max = 128;
866     info.new_num_bases = 0;
867     info.new_basenames = (char **)
868         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
869     info.mem = stream->mem;
870
871     res_trav (zh->session_res, "mapdb", &info, map_basenames_func);
872     
873     for (i = 0; i<p->num_bases; i++)
874         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
875         {
876             p->new_basenames[(p->new_num_bases)++] = 
877                 nmem_strdup (p->mem, p->basenames[i]);
878         }
879     *num_bases = info.new_num_bases;
880     *basenames = info.new_basenames;
881     for (i = 0; i<*num_bases; i++)
882         yaz_log (YLOG_DEBUG, "base %s", (*basenames)[i]);
883 }
884
885 ZEBRA_RES zebra_select_database (ZebraHandle zh, const char *basename)
886 {
887     ZEBRA_CHECK_HANDLE(zh);
888
889     yaz_log(log_level, "zebra_select_database %s",basename);
890     assert(basename);
891     return zebra_select_databases (zh, 1, &basename);
892 }
893
894 ZEBRA_RES zebra_select_databases (ZebraHandle zh, int num_bases,
895                                   const char **basenames)
896 {
897     int i;
898     const char *cp;
899     int len = 0;
900     char *new_reg = 0;
901
902     ZEBRA_CHECK_HANDLE(zh);
903     assert(basenames);
904
905     yaz_log(log_level, "zebra_select_databases n=%d [0]=%s",
906                     num_bases,basenames[0]);
907     zh->errCode = 0;
908     
909     if (num_bases < 1)
910     {
911         zh->errCode = YAZ_BIB1_COMBI_OF_SPECIFIED_DATABASES_UNSUPP;
912         return ZEBRA_FAIL;
913     }
914
915     /* Check if the user has access to all databases (Seb) */
916     /* You could argue that this should happen later, after we have
917      * determined that the database(s) exist. */
918     if (zh->dbaccesslist) {
919         for (i = 0; i < num_bases; i++) {
920             const char *db = basenames[i];
921             char *p, *pp;
922             for (p = zh->dbaccesslist; p && *p; p = pp) {
923                 int len;
924                 if ((pp = strchr(p, '+'))) {
925                     len = pp - p;
926                     pp++;
927                 }
928                 else
929                     len = strlen(p);
930                 if (len == strlen(db) && !strncmp(db, p, len))
931                     break;
932             }
933             if (!p) {
934                 zh->errCode = YAZ_BIB1_ACCESS_TO_SPECIFIED_DATABASE_DENIED;
935                 return ZEBRA_FAIL;
936             }
937         }
938     }
939
940     for (i = 0; i < zh->num_basenames; i++)
941         xfree(zh->basenames[i]);
942     xfree(zh->basenames);
943     
944     zh->num_basenames = num_bases;
945     zh->basenames = xmalloc(zh->num_basenames * sizeof(*zh->basenames));
946     for (i = 0; i < zh->num_basenames; i++)
947         zh->basenames[i] = xstrdup (basenames[i]);
948
949     cp = strrchr(basenames[0], '/');
950     if (cp)
951     {
952         len = cp - basenames[0];
953         new_reg = xmalloc(len + 1);
954         memcpy (new_reg, basenames[0], len);
955         new_reg[len] = '\0';
956     }
957     else
958         new_reg = xstrdup ("");
959     for (i = 1; i<num_bases; i++)
960     {
961         const char *cp1;
962
963         cp1 = strrchr (basenames[i], '/');
964         if (cp)
965         {
966             if (!cp1)
967             {
968                 zh->errCode = YAZ_BIB1_COMBI_OF_SPECIFIED_DATABASES_UNSUPP;
969                 return -1;
970             }
971             if (len != cp1 - basenames[i] ||
972                 memcmp (basenames[i], new_reg, len))
973             {
974                 zh->errCode = YAZ_BIB1_COMBI_OF_SPECIFIED_DATABASES_UNSUPP;
975                 return -1;
976             }
977         }
978         else
979         {
980             if (cp1)
981             {
982                 zh->errCode = YAZ_BIB1_COMBI_OF_SPECIFIED_DATABASES_UNSUPP;
983                 return ZEBRA_FAIL;
984             }
985         }
986     }
987     zebra_select_register (zh, new_reg);
988     xfree(new_reg);
989     if (!zh->res)
990     {
991         zh->errCode = YAZ_BIB1_DATABASE_UNAVAILABLE;
992         return ZEBRA_FAIL;
993     }
994     if (!zh->lock_normal || !zh->lock_shadow)
995     {
996         zh->errCode = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
997         return ZEBRA_FAIL;
998     }
999     return ZEBRA_OK;
1000 }
1001
1002 ZEBRA_RES zebra_set_approx_limit(ZebraHandle zh, zint approx_limit)
1003 {
1004     if (approx_limit == 0)
1005         approx_limit = DEFAULT_APPROX_LIMIT;
1006     zh->approx_limit = approx_limit;
1007     return ZEBRA_OK;
1008 }
1009
1010 ZEBRA_RES zebra_search_RPN(ZebraHandle zh, ODR o, Z_RPNQuery *query,
1011                            const char *setname, zint *hits)
1012 {
1013     ZEBRA_RES r;
1014     
1015     ZEBRA_CHECK_HANDLE(zh);
1016
1017     assert(o);
1018     assert(query);
1019     assert(hits);
1020     assert(setname);
1021     yaz_log(log_level, "zebra_search_rpn");
1022     zh->hits = 0;
1023     *hits = 0;
1024
1025     if (zebra_begin_read(zh) == ZEBRA_FAIL)
1026         return ZEBRA_FAIL;
1027
1028     r = resultSetAddRPN(zh, odr_extract_mem(o), query, 
1029                         zh->num_basenames, zh->basenames, setname);
1030     zebra_end_read(zh);
1031     *hits = zh->hits;
1032     return r;
1033 }
1034
1035 ZEBRA_RES zebra_records_retrieve(ZebraHandle zh, ODR stream,
1036                                  const char *setname,
1037                                  Z_RecordComposition *comp,
1038                                  oid_value input_format, int num_recs,
1039                                  ZebraRetrievalRecord *recs)
1040 {
1041     ZebraMetaRecord *poset;
1042     int i;
1043     ZEBRA_RES ret = ZEBRA_OK;
1044     zint *pos_array;
1045
1046     ZEBRA_CHECK_HANDLE(zh);
1047     assert(stream);
1048     assert(setname);
1049     assert(recs);
1050     assert(num_recs>0);
1051
1052     yaz_log(log_level, "zebra_records_retrieve n=%d", num_recs);
1053
1054     if (!zh->res)
1055     {
1056         zebra_setError(zh, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1057                        setname);
1058         return ZEBRA_FAIL;
1059     }
1060     
1061     if (zebra_begin_read (zh) == ZEBRA_FAIL)
1062         return ZEBRA_FAIL;
1063
1064     pos_array = (zint *) xmalloc(num_recs * sizeof(*pos_array));
1065     for (i = 0; i<num_recs; i++)
1066         pos_array[i] = recs[i].position;
1067     poset = zebra_meta_records_create(zh, setname, num_recs, pos_array);
1068     if (!poset)
1069     {
1070         yaz_log (YLOG_DEBUG, "zebraPosSetCreate error");
1071         zebra_setError(zh, YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1072                        setname);
1073         ret = ZEBRA_FAIL;
1074     }
1075     else
1076     {
1077         for (i = 0; i<num_recs; i++)
1078         {
1079             if (poset[i].term)
1080             {
1081                 recs[i].errCode = 0;
1082                 recs[i].format = VAL_SUTRS;
1083                 recs[i].len = strlen(poset[i].term);
1084                 recs[i].buf = poset[i].term;
1085                 recs[i].base = poset[i].db;
1086             }
1087             else if (poset[i].sysno)
1088             {
1089                 char *buf;
1090                 int len = 0;
1091                 zebra_snippets *hit_snippet = zebra_snippets_create();
1092
1093                 /* we disable hit snippets for now. It does not work well
1094                  and it slows retrieval down a lot */
1095 #if 0
1096                 zebra_snippets_hit_vector(zh, setname, poset[i].sysno, 
1097                                           hit_snippet);
1098 #endif
1099                 recs[i].errCode =
1100                     zebra_record_fetch(zh, poset[i].sysno, poset[i].score,
1101                                        hit_snippet,
1102                                        stream, input_format, comp,
1103                                        &recs[i].format, &buf, &len,
1104                                        &recs[i].base, &recs[i].errString);
1105                 
1106                 recs[i].len = len;
1107                 if (len > 0)
1108                 {
1109                     recs[i].buf = (char*) odr_malloc(stream, len);
1110                     memcpy(recs[i].buf, buf, len);
1111                 }
1112                 else
1113                     recs[i].buf = buf;
1114                 recs[i].score = poset[i].score;
1115                 recs[i].sysno = poset[i].sysno;
1116                 zebra_snippets_destroy(hit_snippet);
1117             }
1118             else
1119             {
1120                 /* only need to set it once */
1121                 if (pos_array[i] < zh->approx_limit && ret == ZEBRA_OK)
1122                 {
1123                     zebra_setError_zint(zh,
1124                                         YAZ_BIB1_PRESENT_REQUEST_OUT_OF_RANGE,
1125                                         pos_array[i]);
1126                     ret = ZEBRA_FAIL;
1127                     break;
1128                 }
1129                 recs[i].buf = 0;  /* no record and no error issued */
1130                 recs[i].len = 0;
1131                 recs[i].errCode = 0;
1132                 recs[i].format = VAL_NONE;
1133                 recs[i].sysno = 0;
1134             }
1135         }
1136         zebra_meta_records_destroy(zh, poset, num_recs);
1137     }
1138     zebra_end_read (zh);
1139     xfree(pos_array);
1140     return ret;
1141 }
1142
1143 ZEBRA_RES zebra_scan_PQF(ZebraHandle zh, ODR stream, const char *query,
1144                          int *position,
1145                          int *num_entries, ZebraScanEntry **entries,
1146                          int *is_partial,
1147                          const char *setname)
1148 {
1149     YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
1150     Z_AttributesPlusTerm *zapt;
1151     int *attributeSet;
1152     ZEBRA_RES res;
1153     
1154     if (!(zapt = yaz_pqf_scan(pqf_parser, stream, &attributeSet, query)))
1155     {
1156         res = ZEBRA_FAIL;
1157         zh->errCode = YAZ_BIB1_SCAN_MALFORMED_SCAN;
1158     }
1159     else
1160         res = zebra_scan(zh, stream, zapt, VAL_BIB1,
1161                          position, num_entries, entries, is_partial,
1162                          setname);
1163     yaz_pqf_destroy (pqf_parser);
1164     return res;
1165 }
1166
1167 ZEBRA_RES zebra_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
1168                      oid_value attributeset,
1169                      int *position,
1170                      int *num_entries, ZebraScanEntry **entries,
1171                      int *is_partial,
1172                      const char *setname)
1173 {
1174     ZEBRA_RES res;
1175     RSET limit_rset = 0;
1176
1177     ZEBRA_CHECK_HANDLE(zh);
1178
1179     assert(stream);
1180     assert(zapt);
1181     assert(position);
1182     assert(num_entries);
1183     assert(is_partial);
1184     assert(entries);
1185     yaz_log(log_level, "zebra_scan");
1186
1187     if (zebra_begin_read (zh) == ZEBRA_FAIL)
1188     {
1189         *entries = 0;
1190         *num_entries = 0;
1191         return ZEBRA_FAIL;
1192     }
1193     if (setname)
1194     {
1195         limit_rset = resultSetRef(zh, setname);
1196         if (!limit_rset)
1197         {
1198             zebra_setError(zh, 
1199                            YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1200                            setname);
1201             zebra_end_read (zh);
1202             return ZEBRA_FAIL;
1203         }
1204     }
1205     res = rpn_scan(zh, stream, zapt, attributeset,
1206                    zh->num_basenames, zh->basenames, position,
1207                    num_entries, entries, is_partial, limit_rset);
1208     zebra_end_read(zh);
1209     return res;
1210 }
1211
1212 ZEBRA_RES zebra_sort (ZebraHandle zh, ODR stream,
1213                       int num_input_setnames, const char **input_setnames,
1214                       const char *output_setname,
1215                       Z_SortKeySpecList *sort_sequence,
1216                       int *sort_status)
1217 {
1218     ZEBRA_RES res;
1219     ZEBRA_CHECK_HANDLE(zh);
1220     assert(stream);
1221     assert(num_input_setnames>0);
1222     assert(input_setnames);
1223     assert(sort_sequence);
1224     assert(sort_status);
1225     yaz_log(log_level, "zebra_sort");
1226
1227     if (zebra_begin_read(zh) == ZEBRA_FAIL)
1228         return ZEBRA_FAIL;
1229     res = resultSetSort(zh, stream->mem, num_input_setnames, input_setnames,
1230                         output_setname, sort_sequence, sort_status);
1231     zebra_end_read(zh);
1232     return res;
1233 }
1234
1235 int zebra_deleteResultSet(ZebraHandle zh, int function,
1236                           int num_setnames, char **setnames,
1237                           int *statuses)
1238 {
1239     int i, status;
1240     ASSERTZH;
1241     assert(statuses);
1242     yaz_log(log_level, "zebra_deleteResultSet n=%d",num_setnames);
1243
1244     if (zebra_begin_read(zh))
1245         return Z_DeleteStatus_systemProblemAtTarget;
1246     switch (function)
1247     {
1248     case Z_DeleteResultSetRequest_list:
1249         assert(num_setnames>0);
1250         assert(setnames);
1251         resultSetDestroy (zh, num_setnames, setnames, statuses);
1252         break;
1253     case Z_DeleteResultSetRequest_all:
1254         resultSetDestroy (zh, -1, 0, statuses);
1255         break;
1256     }
1257     zebra_end_read (zh);
1258     status = Z_DeleteStatus_success;
1259     for (i = 0; i<num_setnames; i++)
1260         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
1261             status = statuses[i];
1262     return status;
1263 }
1264
1265 int zebra_errCode (ZebraHandle zh)
1266 {
1267     if (zh)
1268     {
1269         yaz_log(log_level, "zebra_errCode: %d",zh->errCode);
1270         return zh->errCode;
1271     }
1272     yaz_log(log_level, "zebra_errCode: o");
1273     return 0; 
1274 }
1275
1276 const char *zebra_errString (ZebraHandle zh)
1277 {
1278     const char *e = 0;
1279     if (zh)
1280         e= diagbib1_str (zh->errCode);
1281     yaz_log(log_level, "zebra_errString: %s",e);
1282     return e;
1283 }
1284
1285 char *zebra_errAdd (ZebraHandle zh)
1286 {
1287     char *a = 0;
1288     if (zh)
1289         a= zh->errString;
1290     yaz_log(log_level, "zebra_errAdd: %s",a);
1291     return a;
1292 }
1293
1294 ZEBRA_RES zebra_auth (ZebraHandle zh, const char *user, const char *pass)
1295 {
1296     const char *p;
1297     const char *astring;
1298     char u[40];
1299     ZebraService zs;
1300
1301     ZEBRA_CHECK_HANDLE(zh);
1302
1303     zs = zh->service;
1304     
1305     sprintf(u, "perm.%.30s", user ? user : "anonymous");
1306     p = res_get(zs->global_res, u);
1307     xfree(zh->user_perm);
1308     zh->user_perm = xstrdup(p ? p : "r");
1309
1310     /* Determine database access list */
1311     astring = res_get(zs->dbaccess, user ? user : "anonymous");
1312     if (astring)
1313         zh->dbaccesslist = xstrdup(astring);
1314     else
1315         zh->dbaccesslist = 0;
1316
1317     /* users that don't require a password .. */
1318     if (zh->user_perm && strchr(zh->user_perm, 'a'))
1319         return ZEBRA_OK;
1320     
1321     if (!zs->passwd_db || !passwd_db_auth (zs->passwd_db, user, pass))
1322         return ZEBRA_OK;
1323     return ZEBRA_FAIL;
1324 }
1325
1326 ZEBRA_RES zebra_admin_import_begin (ZebraHandle zh, const char *database,
1327                                const char *record_type)
1328 {
1329     yaz_log(log_level, "zebra_admin_import_begin db=%s rt=%s", 
1330                      database, record_type);
1331     if (zebra_select_database(zh, database) == ZEBRA_FAIL)
1332         return ZEBRA_FAIL;
1333     return zebra_begin_trans(zh, 1);
1334 }
1335
1336 ZEBRA_RES zebra_admin_import_end (ZebraHandle zh)
1337 {
1338     ZEBRA_CHECK_HANDLE(zh);
1339     yaz_log(log_level, "zebra_admin_import_end");
1340     return zebra_end_trans(zh);
1341 }
1342
1343 ZEBRA_RES zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
1344 {
1345     ZEBRA_RES res = ZEBRA_OK;
1346     zint sysno;
1347     int i;
1348     ZEBRA_CHECK_HANDLE(zh);
1349     yaz_log(log_level, "zebra_admin_import_segment");
1350
1351     for (i = 0; i<segment->num_segmentRecords; i++)
1352     {
1353         Z_NamePlusRecord *npr = segment->segmentRecords[i];
1354
1355         if (npr->which == Z_NamePlusRecord_intermediateFragment)
1356         {
1357             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
1358             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
1359             {
1360                 Odr_oct *oct = fragment->u.notExternallyTagged;
1361                 sysno = 0;
1362                 
1363                 if (zebra_update_record(zh, 
1364                                         0, /* record Type */
1365                                         &sysno,
1366                                         0, /* match */
1367                                         0, /* fname */
1368                                         (const char *) oct->buf, oct->len,
1369                                         0) == ZEBRA_FAIL)
1370                     res = ZEBRA_FAIL;
1371             }
1372         }
1373     }
1374     return res;
1375 }
1376
1377 ZEBRA_RES zebra_admin_exchange_record(ZebraHandle zh,
1378                                       const char *rec_buf,
1379                                       size_t rec_len,
1380                                       const char *recid_buf, size_t recid_len,
1381                                       int action)
1382     /* 1 = insert. Fail it already exists */
1383     /* 2 = replace. Fail it does not exist */
1384     /* 3 = delete. Fail if does not exist */
1385     /* 4 = update. Insert/replace */
1386 {
1387     ZEBRA_RES res;
1388     zint sysno = 0;
1389     char *rinfo = 0;
1390     char recid_z[256];
1391     int db_ord;
1392     ZEBRA_CHECK_HANDLE(zh);
1393     assert(action>0 && action <=4);
1394     assert(rec_buf);
1395
1396     yaz_log(log_level, "zebra_admin_exchange_record ac=%d", action);
1397
1398     if (!recid_buf || recid_len <= 0 || recid_len >= sizeof(recid_z))
1399     {
1400         zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED,
1401                        "no record ID or empty record ID");
1402         return ZEBRA_FAIL;
1403     }
1404
1405     memcpy (recid_z, recid_buf, recid_len);
1406     recid_z[recid_len] = 0;
1407
1408     if (zebra_begin_trans(zh, 1) == ZEBRA_FAIL)
1409         return ZEBRA_FAIL;
1410
1411     db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1412     rinfo = dict_lookup_ord(zh->reg->matchDict, db_ord, recid_z);
1413     if (rinfo)
1414     {
1415         if (action == 1)  /* fail if insert */
1416         {
1417             if (zebra_end_trans(zh) != ZEBRA_OK)
1418                 yaz_log(YLOG_WARN, "zebra_end_trans failed");
1419             zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED,
1420                            "Cannot insert record: already exist");
1421             return ZEBRA_FAIL;
1422         }
1423
1424         memcpy (&sysno, rinfo+1, sizeof(sysno));
1425     }
1426     else
1427     {
1428         if (action == 2 || action == 3) /* fail if delete or update */
1429         {
1430             if (zebra_end_trans(zh) != ZEBRA_OK)
1431                 yaz_log(YLOG_WARN, "zebra_end_trans failed");
1432             zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED,
1433                            "Cannot delete/update record: does not exist");
1434             return ZEBRA_FAIL;
1435         }
1436         action = 1;  /* make it an insert (if it's an update).. */
1437     }
1438     res = zebra_buffer_extract_record(zh, rec_buf, rec_len,
1439                                       action == 3 ? 1 : 0 /* delete flag */,
1440                                       0, /* test mode */
1441                                       0, /* recordType */
1442                                       &sysno, 
1443                                       0, /* match */
1444                                       0, /* fname */
1445                                       0, /* force update */
1446                                       1  /* allow update */
1447         );
1448     if (res == ZEBRA_FAIL)
1449     {
1450         zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED,
1451                        "Unable to parse record");
1452     }
1453     if (action == 1)
1454     {
1455         dict_insert_ord(zh->reg->matchDict, db_ord, recid_z,
1456                         sizeof(sysno), &sysno);
1457     }
1458     else if (action == 3)
1459     {
1460         dict_delete_ord(zh->reg->matchDict, db_ord, recid_z);
1461     }
1462     if (zebra_end_trans(zh) != ZEBRA_OK)
1463     {
1464         yaz_log(YLOG_WARN, "zebra_end_trans failed");
1465         res = ZEBRA_FAIL;
1466     }
1467     return res;
1468 }
1469
1470 int delete_w_handle(const char *info, void *handle)
1471 {
1472     ZebraHandle zh = (ZebraHandle) handle;
1473     ISAM_P pos;
1474     ASSERTZH;
1475
1476     if (*info == sizeof(pos))
1477     {
1478         memcpy (&pos, info+1, sizeof(pos));
1479         isamb_unlink(zh->reg->isamb, pos);
1480     }
1481     return 0;
1482 }
1483
1484 static int delete_SU_handle(void *handle, int ord)
1485 {
1486     ZebraHandle zh = (ZebraHandle) handle;
1487     char ord_buf[20];
1488     int ord_len;
1489
1490     ord_len = key_SU_encode (ord, ord_buf);
1491     ord_buf[ord_len] = '\0';
1492
1493     assert (zh->reg->isamb);
1494     dict_delete_subtree(zh->reg->dict, ord_buf,
1495                         zh, delete_w_handle);
1496     return 0;
1497 }
1498
1499 ZEBRA_RES zebra_drop_database(ZebraHandle zh, const char *db)
1500 {
1501     ZEBRA_RES ret = ZEBRA_OK;
1502
1503     yaz_log(log_level, "zebra_drop_database %s", db);
1504     ZEBRA_CHECK_HANDLE(zh);
1505
1506     if (zebra_select_database (zh, db) == ZEBRA_FAIL)
1507         return ZEBRA_FAIL;
1508     if (zebra_begin_trans (zh, 1) == ZEBRA_FAIL)
1509         return ZEBRA_FAIL;
1510     if (zh->reg->isamb)
1511     {
1512         int db_ord;
1513         if (zebraExplain_curDatabase (zh->reg->zei, db))
1514         {
1515             zebra_setError(zh, YAZ_BIB1_DATABASE_DOES_NOT_EXIST, db);
1516             ret = ZEBRA_FAIL;
1517         }
1518         else
1519         {
1520             db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1521             dict_delete_subtree_ord(zh->reg->matchDict, db_ord,
1522                                     0 /* handle */, 0 /* func */);
1523             zebraExplain_trav_ord(zh->reg->zei, zh, delete_SU_handle);
1524             zebraExplain_removeDatabase(zh->reg->zei, zh);
1525             zebra_remove_file_match(zh);
1526         }
1527     }
1528     else
1529     {
1530         yaz_log(YLOG_WARN, "drop database only supported for isam:b");
1531         zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED,
1532                        "drop database only supported for isam:b");
1533         ret = ZEBRA_FAIL;
1534     }
1535     if (zebra_end_trans (zh) != ZEBRA_OK)
1536     {
1537         yaz_log(YLOG_WARN, "zebra_end_trans failed");
1538         ret = ZEBRA_FAIL;
1539     }
1540     return ret;
1541 }
1542
1543 ZEBRA_RES zebra_create_database (ZebraHandle zh, const char *db)
1544 {
1545     yaz_log(log_level, "zebra_create_database %s", db);
1546     ZEBRA_CHECK_HANDLE(zh);
1547     assert(db);
1548
1549     if (zebra_select_database (zh, db) == ZEBRA_FAIL)
1550         return ZEBRA_FAIL;
1551     if (zebra_begin_trans (zh, 1))
1552         return ZEBRA_FAIL;
1553
1554     /* announce database */
1555     if (zebraExplain_newDatabase (zh->reg->zei, db, 0 
1556                                   /* explainDatabase */))
1557     {
1558         if (zebra_end_trans (zh) != ZEBRA_OK)
1559         {
1560             yaz_log(YLOG_WARN, "zebra_end_trans failed");
1561         }
1562         zebra_setError(zh, YAZ_BIB1_ES_IMMEDIATE_EXECUTION_FAILED, db);
1563         return ZEBRA_FAIL;
1564     }
1565     return zebra_end_trans (zh);
1566 }
1567
1568 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
1569                        const char *input_str, int input_len,
1570                        char *output_str, int output_len)
1571 {
1572     WRBUF wrbuf;
1573     ASSERTZH;
1574     assert(input_str);
1575     assert(output_str);
1576     yaz_log(log_level, "zebra_string_norm ");
1577
1578     if (!zh->reg->zebra_maps)
1579         return -1;
1580     wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, "",
1581                           input_str, input_len);
1582     if (!wrbuf)
1583         return -2;
1584     if (wrbuf_len(wrbuf) >= output_len)
1585         return -3;
1586     if (wrbuf_len(wrbuf))
1587         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1588     output_str[wrbuf_len(wrbuf)] = '\0';
1589     return wrbuf_len(wrbuf);
1590 }
1591
1592 /** \brief set register state (state*.LCK)
1593     \param zh Zebra handle
1594     \param val state
1595     \param seqno sequence number
1596     
1597     val is one of:
1598     d=writing to shadow(dirty)
1599     o=no writing, 
1600     c=commit
1601 */
1602 static void zebra_set_state (ZebraHandle zh, int val, int seqno)
1603 {
1604     char state_fname[256];
1605     char *fname;
1606     long p = getpid();
1607     FILE *f;
1608     ASSERTZH;
1609     yaz_log(log_level, "zebra_set_state v=%d seq=%d", val, seqno);
1610
1611     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
1612     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
1613     f = fopen (fname, "w");
1614
1615     yaz_log (YLOG_DEBUG, "zebra_set_state: %c %d %ld", val, seqno, p);
1616     fprintf (f, "%c %d %ld\n", val, seqno, p);
1617     fclose (f);
1618     xfree(fname);
1619 }
1620
1621 static void zebra_get_state (ZebraHandle zh, char *val, int *seqno)
1622 {
1623     char state_fname[256];
1624     char *fname;
1625     FILE *f;
1626
1627     ASSERTZH;
1628     yaz_log(log_level, "zebra_get_state ");
1629
1630     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
1631     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
1632     f = fopen (fname, "r");
1633     *val = 'o';
1634     *seqno = 0;
1635
1636     if (f)
1637     {
1638         fscanf (f, "%c %d", val, seqno);
1639         fclose (f);
1640     }
1641     xfree(fname);
1642 }
1643
1644 ZEBRA_RES zebra_begin_read (ZebraHandle zh)
1645 {
1646     return zebra_begin_trans(zh, 0);
1647 }
1648
1649 ZEBRA_RES zebra_end_read (ZebraHandle zh)
1650 {
1651     return zebra_end_trans(zh);
1652 }
1653
1654 static void read_res_for_transaction(ZebraHandle zh)
1655 {
1656     const char *group = res_get(zh->res, "group");
1657     const char *v;
1658     /* FIXME - do we still use groups ?? */
1659     
1660     zh->m_group = group;
1661     v = res_get_prefix(zh->res, "followLinks", group, "1");
1662     zh->m_follow_links = atoi(v);
1663
1664     zh->m_record_id = res_get_prefix(zh->res, "recordId", group, 0);
1665     zh->m_record_type = res_get_prefix(zh->res, "recordType", group, 0);
1666
1667     v = res_get_prefix(zh->res, "storeKeys", group, "1");
1668     zh->m_store_keys = atoi(v);
1669
1670     v = res_get_prefix(zh->res, "storeData", group, "1");
1671     zh->m_store_data = atoi(v);
1672
1673     v = res_get_prefix(zh->res, "explainDatabase", group, "0");
1674     zh->m_explain_database = atoi(v);
1675
1676     v = res_get_prefix(zh->res, "openRW", group, "1");
1677     zh->m_flag_rw = atoi(v);
1678
1679     v = res_get_prefix(zh->res, "fileVerboseLimit", group, "100000");
1680     zh->m_file_verbose_limit = atoi(v);
1681 }
1682
1683 ZEBRA_RES zebra_begin_trans(ZebraHandle zh, int rw)
1684 {
1685     ZEBRA_CHECK_HANDLE(zh);
1686     zebra_select_default_database(zh);
1687     if (!zh->res)
1688     {
1689         zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
1690                        "zebra_begin_trans: no database selected");
1691         return ZEBRA_FAIL;
1692     }
1693     ASSERTZHRES;
1694     yaz_log(log_level, "zebra_begin_trans rw=%d",rw);
1695
1696     if (zh->user_perm)
1697     {
1698         if (rw && !strchr(zh->user_perm, 'w'))
1699         {
1700             zebra_setError(
1701                 zh,
1702                 YAZ_BIB1_ES_PERMISSION_DENIED_ON_ES_CANNOT_MODIFY_OR_DELETE,
1703                 0);
1704             return ZEBRA_FAIL;
1705         }
1706     }
1707
1708     assert (zh->res);
1709     if (rw)
1710     {
1711         int seqno = 0;
1712         char val = '?';
1713         const char *rval = 0;
1714         
1715         (zh->trans_no++);
1716         if (zh->trans_w_no)
1717         {
1718             read_res_for_transaction(zh);
1719             return 0;
1720         }
1721         if (zh->trans_no != 1)
1722         {
1723             zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
1724                            "zebra_begin_trans: no write trans within read");
1725             return ZEBRA_FAIL;
1726         }
1727         if (zh->reg)
1728         {
1729             resultSetInvalidate (zh);
1730             zebra_register_close(zh->service, zh->reg);
1731         }
1732         zh->trans_w_no = zh->trans_no;
1733
1734         zh->records_inserted = 0;
1735         zh->records_updated = 0;
1736         zh->records_deleted = 0;
1737         zh->records_processed = 0;
1738         
1739 #if HAVE_SYS_TIMES_H
1740         times (&zh->tms1);
1741 #endif
1742         /* lock */
1743         if (zh->shadow_enable)
1744             rval = res_get (zh->res, "shadow");
1745         
1746         if (rval)
1747         {
1748             zebra_lock_r(zh->lock_normal);
1749             zebra_lock_w(zh->lock_shadow);
1750         }
1751         else
1752         {
1753             zebra_lock_w(zh->lock_normal);
1754             zebra_lock_w(zh->lock_shadow);
1755         }
1756         zebra_get_state (zh, &val, &seqno);
1757         if (val != 'o')
1758         {
1759             /* either we didn't finish commit or shadow is dirty */
1760             zebra_unlock (zh->lock_shadow);
1761             zebra_unlock (zh->lock_normal);
1762             if (zebra_commit (zh))
1763             {
1764                 zh->trans_no--;
1765                 zh->trans_w_no = 0;
1766                 return ZEBRA_FAIL;
1767             }
1768             if (rval)
1769             {
1770                 zebra_lock_r(zh->lock_normal);
1771                 zebra_lock_w(zh->lock_shadow);
1772             }
1773             else
1774             {
1775                 zebra_lock_w(zh->lock_normal);
1776                 zebra_lock_w(zh->lock_shadow);
1777             }
1778         }
1779
1780         zebra_set_state (zh, 'd', seqno);
1781         
1782         zh->reg = zebra_register_open(zh->service, zh->reg_name,
1783                                       1, rval ? 1 : 0, zh->res,
1784                                       zh->path_reg);
1785         if (zh->reg)
1786             zh->reg->seqno = seqno;
1787         else
1788         {
1789             zebra_set_state (zh, 'o', seqno);
1790             
1791             zebra_unlock (zh->lock_shadow);
1792             zebra_unlock (zh->lock_normal);
1793
1794             zh->trans_no--;
1795             zh->trans_w_no = 0;
1796
1797             zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
1798                            "zebra_begin_trans: cannot open register");
1799             yaz_log(YLOG_FATAL, "%s", zh->errString);
1800             return ZEBRA_FAIL;
1801         }
1802         zebraExplain_curDatabase(zh->reg->zei, zh->basenames[0]);
1803     }
1804     else
1805     {
1806         int dirty = 0;
1807         char val;
1808         int seqno;
1809         
1810         (zh->trans_no)++;
1811         
1812         if (zh->trans_no != 1)
1813         {
1814             return zebra_flush_reg (zh);
1815         }
1816 #if HAVE_SYS_TIMES_H
1817         times (&zh->tms1);
1818 #endif
1819         if (!zh->res)
1820         {
1821             (zh->trans_no)--;
1822             zh->errCode = YAZ_BIB1_DATABASE_UNAVAILABLE;
1823             return ZEBRA_FAIL;
1824         }
1825         if (!zh->lock_normal || !zh->lock_shadow)
1826         {
1827             (zh->trans_no)--;
1828             zh->errCode = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
1829             return ZEBRA_FAIL;
1830         }
1831         zebra_get_state (zh, &val, &seqno);
1832         if (val == 'd')
1833             val = 'o';
1834         
1835         if (!zh->reg)
1836             dirty = 1;
1837         else if (seqno != zh->reg->seqno)
1838         {
1839             yaz_log (YLOG_DEBUG, "reopen seqno cur/old %d/%d",
1840                      seqno, zh->reg->seqno);
1841             dirty = 1;
1842         }
1843         else if (zh->reg->last_val != val)
1844         {
1845             yaz_log (YLOG_DEBUG, "reopen last cur/old %d/%d",
1846                      val, zh->reg->last_val);
1847             dirty = 1;
1848         }
1849         if (!dirty)
1850             return ZEBRA_OK;
1851         
1852         if (val == 'c')
1853             zebra_lock_r (zh->lock_shadow);
1854         else
1855             zebra_lock_r (zh->lock_normal);
1856         
1857         if (zh->reg)
1858         {
1859             resultSetInvalidate (zh);
1860             zebra_register_close(zh->service, zh->reg);
1861         }
1862         zh->reg = zebra_register_open(zh->service, zh->reg_name,
1863                                       0, val == 'c' ? 1 : 0,
1864                                       zh->res, zh->path_reg);
1865         if (!zh->reg)
1866         {
1867             zebra_unlock (zh->lock_normal);
1868             zebra_unlock (zh->lock_shadow);
1869             zh->trans_no--;
1870             zh->errCode = YAZ_BIB1_DATABASE_UNAVAILABLE;
1871             return ZEBRA_FAIL;
1872         }
1873         zh->reg->last_val = val;
1874         zh->reg->seqno = seqno;
1875     }
1876     read_res_for_transaction(zh);
1877     return ZEBRA_OK;
1878 }
1879
1880 ZEBRA_RES zebra_end_trans (ZebraHandle zh)
1881 {
1882     ZebraTransactionStatus dummy;
1883
1884     yaz_log(log_level, "zebra_end_trans");
1885     ZEBRA_CHECK_HANDLE(zh);
1886     return zebra_end_transaction(zh, &dummy);
1887 }
1888
1889 ZEBRA_RES zebra_end_transaction (ZebraHandle zh, ZebraTransactionStatus *status)
1890 {
1891     char val;
1892     int seqno;
1893     const char *rval;
1894
1895     ZEBRA_CHECK_HANDLE(zh);
1896
1897     assert(status);
1898     yaz_log(log_level, "zebra_end_transaction");
1899
1900     status->processed = 0;
1901     status->inserted  = 0;
1902     status->updated   = 0;
1903     status->deleted   = 0;
1904     status->utime     = 0;
1905     status->stime     = 0;
1906
1907     if (!zh->res || !zh->reg)
1908     {
1909         zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
1910                        "zebra_end_trans: no open transaction");
1911         return ZEBRA_FAIL;
1912     }
1913     if (zh->trans_no != zh->trans_w_no)
1914     {
1915         zh->trans_no--;
1916         if (zh->trans_no != 0)
1917             return ZEBRA_OK;
1918
1919         /* release read lock */
1920
1921         zebra_unlock (zh->lock_normal);
1922         zebra_unlock (zh->lock_shadow);
1923     }
1924     else
1925     {   /* release write lock */
1926         zh->trans_no--;
1927         zh->trans_w_no = 0;
1928         
1929         yaz_log (YLOG_DEBUG, "zebra_end_trans");
1930         rval = res_get (zh->res, "shadow");
1931         
1932         zebraExplain_runNumberIncrement (zh->reg->zei, 1);
1933         
1934         zebra_flush_reg (zh);
1935         
1936         resultSetInvalidate (zh);
1937
1938         zebra_register_close(zh->service, zh->reg);
1939         zh->reg = 0;
1940         
1941         yaz_log (YLOG_LOG, "Records: "ZINT_FORMAT" i/u/d "
1942                         ZINT_FORMAT"/"ZINT_FORMAT"/"ZINT_FORMAT, 
1943                  zh->records_processed, zh->records_inserted,
1944                  zh->records_updated, zh->records_deleted);
1945         
1946         status->processed = zh->records_processed;
1947         status->inserted = zh->records_inserted;
1948         status->updated = zh->records_updated;
1949         status->deleted = zh->records_deleted;
1950         
1951         zebra_get_state (zh, &val, &seqno);
1952         if (val != 'd')
1953         {
1954             BFiles bfs = bfs_create (rval, zh->path_reg);
1955             yaz_log (YLOG_DEBUG, "deleting shadow val=%c", val);
1956             bf_commitClean (bfs, rval);
1957             bfs_destroy (bfs);
1958         }
1959         if (!rval)
1960             seqno++;
1961         zebra_set_state (zh, 'o', seqno);
1962         
1963         zebra_unlock (zh->lock_shadow);
1964         zebra_unlock (zh->lock_normal);
1965         
1966     }
1967 #if HAVE_SYS_TIMES_H
1968     times (&zh->tms2);
1969     yaz_log (log_level, "user/system: %ld/%ld",
1970           (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
1971           (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
1972     
1973     status->utime = (long) (zh->tms2.tms_utime - zh->tms1.tms_utime);
1974     status->stime = (long) (zh->tms2.tms_stime - zh->tms1.tms_stime);
1975 #endif
1976     return ZEBRA_OK;
1977 }
1978
1979 ZEBRA_RES zebra_repository_update(ZebraHandle zh, const char *path)
1980 {
1981     ASSERTZH;
1982     assert(path);
1983     yaz_log (log_level, "updating %s", path);
1984
1985     if (zh->m_record_id && !strcmp (zh->m_record_id, "file"))
1986         return zebra_update_file_match(zh, path);
1987     else
1988         return zebra_update_from_path(zh, path);
1989 }
1990
1991 ZEBRA_RES zebra_repository_delete(ZebraHandle zh, const char *path)
1992 {
1993     ASSERTZH;
1994     assert(path);
1995     yaz_log (log_level, "deleting %s", path);
1996     return zebra_delete_from_path(zh, path);
1997 }
1998
1999 ZEBRA_RES zebra_repository_show(ZebraHandle zh, const char *path)
2000 {
2001     ASSERTZH;
2002     assert(path);
2003     yaz_log(log_level, "zebra_repository_show");
2004     repositoryShow (zh, path);
2005     return ZEBRA_OK;
2006 }
2007
2008 static ZEBRA_RES zebra_commit_ex(ZebraHandle zh, int clean_only)
2009 {
2010     int seqno;
2011     char val;
2012     const char *rval;
2013     BFiles bfs;
2014     ZEBRA_RES res = ZEBRA_OK;
2015
2016     ASSERTZH;
2017
2018     zebra_select_default_database(zh);
2019     if (!zh->res)
2020     {
2021         zh->errCode = YAZ_BIB1_DATABASE_UNAVAILABLE;
2022         return ZEBRA_FAIL;
2023     }
2024     rval = res_get(zh->res, "shadow");    
2025     if (!rval)
2026     {
2027         yaz_log (YLOG_WARN, "Cannot perform commit - No shadow area defined");
2028         return ZEBRA_OK;
2029     }
2030
2031     zebra_lock_w(zh->lock_normal);
2032     zebra_lock_r(zh->lock_shadow);
2033
2034     bfs = bfs_create(res_get (zh->res, "register"), zh->path_reg);
2035     if (!bfs)
2036     {
2037         zebra_unlock(zh->lock_shadow);
2038         zebra_unlock(zh->lock_normal);
2039         return ZEBRA_FAIL;
2040     }
2041     zebra_get_state(zh, &val, &seqno);
2042
2043     if (val == 'd')
2044     {
2045         yaz_log(YLOG_WARN, "previous transaction didn't reach commit");
2046         clean_only = 1;
2047     }
2048
2049     if (rval && *rval)
2050         bf_cache (bfs, rval);
2051     if (bf_commitExists (bfs))
2052     {
2053         if (clean_only)
2054             zebra_set_state(zh, 'd', seqno);
2055         else
2056         {
2057             zebra_set_state(zh, 'c', seqno);
2058             
2059             yaz_log(YLOG_DEBUG, "commit start");
2060             if (bf_commitExec (bfs))
2061                 res = ZEBRA_FAIL;
2062         }
2063         if (res == ZEBRA_OK)
2064         {
2065             seqno++;
2066             zebra_set_state(zh, 'o', seqno);
2067             
2068             zebra_unlock(zh->lock_shadow);
2069             zebra_unlock(zh->lock_normal);
2070             
2071             zebra_lock_w(zh->lock_shadow);
2072             bf_commitClean(bfs, rval);
2073             zebra_unlock(zh->lock_shadow);
2074         }
2075         else
2076         {
2077             zebra_unlock(zh->lock_shadow);
2078             zebra_unlock(zh->lock_normal);
2079             yaz_log(YLOG_WARN, "zebra_commit: failed");
2080         }
2081     }
2082     else
2083     {
2084         zebra_unlock(zh->lock_shadow);
2085         zebra_unlock(zh->lock_normal);
2086         yaz_log(log_level, "nothing to commit");
2087     }
2088     bfs_destroy(bfs);
2089
2090     return res;
2091 }
2092
2093 ZEBRA_RES zebra_clean(ZebraHandle zh)
2094 {
2095     yaz_log(log_level, "zebra_clean");
2096     ZEBRA_CHECK_HANDLE(zh);
2097     return zebra_commit_ex(zh, 1);
2098 }
2099
2100 ZEBRA_RES zebra_commit(ZebraHandle zh)
2101 {
2102     yaz_log(log_level, "zebra_commit");
2103     ZEBRA_CHECK_HANDLE(zh);
2104     return zebra_commit_ex(zh, 0);
2105 }
2106
2107
2108 ZEBRA_RES zebra_init(ZebraHandle zh)
2109 {
2110     const char *rval;
2111     BFiles bfs = 0;
2112
2113     yaz_log(log_level, "zebra_init");
2114
2115     ZEBRA_CHECK_HANDLE(zh);
2116
2117     zebra_select_default_database(zh);
2118     if (!zh->res)
2119     {
2120         zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
2121                        "cannot select default database");
2122         return ZEBRA_FAIL;
2123     }
2124     rval = res_get (zh->res, "shadow");
2125
2126     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
2127     if (!bfs)
2128     {
2129         zebra_setError(zh, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, "bfs_create");
2130         return ZEBRA_FAIL;
2131     }
2132     if (rval && *rval)
2133         bf_cache (bfs, rval);
2134     
2135     bf_reset (bfs);
2136     bfs_destroy (bfs);
2137     zebra_set_state (zh, 'o', 0);
2138     return ZEBRA_OK;
2139 }
2140
2141 ZEBRA_RES zebra_compact(ZebraHandle zh)
2142 {
2143     BFiles bfs;
2144
2145     yaz_log(log_level, "zebra_compact");
2146     ZEBRA_CHECK_HANDLE(zh);
2147     if (!zh->res)
2148     {
2149         zh->errCode = YAZ_BIB1_DATABASE_UNAVAILABLE;
2150         return ZEBRA_FAIL;
2151     }
2152     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
2153     inv_compact (bfs);
2154     bfs_destroy (bfs);
2155     return ZEBRA_OK;
2156 }
2157
2158 void zebra_result(ZebraHandle zh, int *code, char **addinfo)
2159 {
2160     yaz_log(log_level, "zebra_result");
2161     if (zh)
2162     {
2163         *code = zh->errCode;
2164         *addinfo = zh->errString;
2165     }
2166     else
2167     {
2168         *code = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
2169         *addinfo ="ZebraHandle is NULL";
2170     }
2171 }
2172
2173 void zebra_shadow_enable(ZebraHandle zh, int value)
2174 {
2175     ASSERTZH;
2176     yaz_log(log_level, "zebra_shadow_enable");
2177     zh->shadow_enable = value;
2178 }
2179
2180 ZEBRA_RES zebra_octet_term_encoding(ZebraHandle zh, const char *encoding)
2181 {
2182     yaz_log(log_level, "zebra_octet_term_encoding %s", encoding);
2183     ZEBRA_CHECK_HANDLE(zh);
2184     assert(encoding);
2185
2186     if (zh->iconv_to_utf8 != 0)
2187         yaz_iconv_close(zh->iconv_to_utf8);
2188     if (zh->iconv_from_utf8 != 0)
2189         yaz_iconv_close(zh->iconv_from_utf8);
2190     
2191     zh->iconv_to_utf8 =
2192         yaz_iconv_open ("UTF-8", encoding);
2193     if (zh->iconv_to_utf8 == 0)
2194         yaz_log (YLOG_WARN, "iconv: %s to UTF-8 unsupported", encoding);
2195     zh->iconv_from_utf8 =
2196         yaz_iconv_open (encoding, "UTF-8");
2197     if (zh->iconv_to_utf8 == 0)
2198         yaz_log (YLOG_WARN, "iconv: UTF-8 to %s unsupported", encoding);
2199
2200     return ZEBRA_OK;
2201 }
2202
2203 ZEBRA_RES zebra_record_encoding (ZebraHandle zh, const char *encoding)
2204 {
2205     yaz_log(log_level, "zebra_record_encoding");
2206     ZEBRA_CHECK_HANDLE(zh);
2207     xfree(zh->record_encoding);
2208     zh->record_encoding = 0;
2209     if (encoding)
2210         zh->record_encoding = xstrdup (encoding);
2211     return ZEBRA_OK;
2212 }
2213
2214 void zebra_set_resource(ZebraHandle zh, const char *name, const char *value)
2215 {
2216     assert(name);
2217     assert(value);
2218     yaz_log(log_level, "zebra_set_resource %s:%s", name, value);
2219     ASSERTZH;
2220     res_set(zh->res, name, value);
2221 }
2222
2223 const char *zebra_get_resource(ZebraHandle zh,
2224                                const char *name, const char *defaultvalue)
2225 {
2226     const char *v;
2227     ASSERTZH;
2228     assert(name);
2229     v = res_get_def (zh->res, name, (char *)defaultvalue);
2230     yaz_log(log_level, "zebra_get_resource %s:%s", name, v);
2231     return v;
2232 }
2233
2234 /* moved from zebra_api_ext.c by pop */
2235 /* FIXME: Should this really be public??? -Heikki */
2236
2237 int zebra_trans_no (ZebraHandle zh)
2238 {
2239     yaz_log(log_level, "zebra_trans_no");
2240     ASSERTZH;
2241     return zh->trans_no;
2242 }
2243
2244 int zebra_get_shadow_enable (ZebraHandle zh)
2245 {
2246     yaz_log(log_level, "zebra_get_shadow_enable");
2247     ASSERTZH;
2248     return zh->shadow_enable;
2249 }
2250
2251 void zebra_set_shadow_enable (ZebraHandle zh, int value)
2252 {
2253     yaz_log(log_level, "zebra_set_shadow_enable %d",value);
2254     ASSERTZH;
2255     zh->shadow_enable = value;
2256 }
2257
2258 ZEBRA_RES zebra_add_record(ZebraHandle zh,
2259                            const char *buf, int buf_size)
2260 {
2261     return zebra_update_record(zh, 0, 0 /* sysno */, 0, 0, buf, buf_size, 0);
2262 }
2263
2264 ZEBRA_RES zebra_insert_record(ZebraHandle zh, 
2265                               const char *recordType,
2266                               zint *sysno, const char *match,
2267                               const char *fname,
2268                               const char *buf, int buf_size, int force_update)
2269 {
2270     ZEBRA_RES res;
2271     ASSERTZH;
2272     assert(sysno);
2273     assert(buf);
2274     yaz_log(log_level, "zebra_insert_record sysno=" ZINT_FORMAT, *sysno);
2275
2276     if (buf_size < 1)
2277         buf_size = strlen(buf);
2278
2279     if (zebra_begin_trans(zh, 1) == ZEBRA_FAIL)
2280         return ZEBRA_FAIL;
2281     res = zebra_buffer_extract_record(zh, buf, buf_size, 
2282                                       0, /* delete_flag  */
2283                                       0, /* test_mode */
2284                                       recordType,
2285                                       sysno,   
2286                                       match, fname,
2287                                       0, 
2288                                       0); /* allow_update */
2289     if (zebra_end_trans(zh) != ZEBRA_OK)
2290     {
2291         yaz_log(YLOG_WARN, "zebra_end_trans failed");
2292         res = ZEBRA_FAIL;
2293     }
2294     return res; 
2295 }
2296
2297 ZEBRA_RES zebra_update_record(ZebraHandle zh, 
2298                               const char *recordType,
2299                               zint *sysno, const char *match,
2300                               const char *fname,
2301                               const char *buf, int buf_size,
2302                               int force_update)
2303 {
2304     ZEBRA_RES res;
2305
2306     ZEBRA_CHECK_HANDLE(zh);
2307
2308     assert(buf);
2309
2310     yaz_log(log_level, "zebra_update_record");
2311     if (sysno)
2312         yaz_log(log_level, " sysno=" ZINT_FORMAT, *sysno);
2313
2314     if (buf_size < 1) buf_size = strlen(buf);
2315
2316     if (zebra_begin_trans(zh, 1) == ZEBRA_FAIL)
2317         return ZEBRA_FAIL;
2318     res = zebra_buffer_extract_record(zh, buf, buf_size, 
2319                                       0, /* delete_flag */
2320                                       0, /* test_mode */
2321                                       recordType,
2322                                       sysno,   
2323                                       match, fname,
2324                                       force_update, 
2325                                       1); /* allow_update */
2326     if (zebra_end_trans(zh) != ZEBRA_OK)
2327     {
2328         yaz_log(YLOG_WARN, "zebra_end_trans failed");
2329         res = ZEBRA_FAIL;
2330     }
2331     return res; 
2332 }
2333
2334 ZEBRA_RES zebra_delete_record(ZebraHandle zh, 
2335                               const char *recordType,
2336                               zint *sysno, const char *match,
2337                               const char *fname,
2338                               const char *buf, int buf_size,
2339                               int force_update) 
2340 {
2341     ZEBRA_RES res;
2342
2343     ZEBRA_CHECK_HANDLE(zh);
2344
2345     assert(buf);
2346     yaz_log(log_level, "zebra_delete_record");
2347     if (sysno)
2348         yaz_log(log_level, " sysno=" ZINT_FORMAT, *sysno);
2349
2350     if (buf_size < 1) buf_size = strlen(buf);
2351
2352     if (zebra_begin_trans(zh, 1) == ZEBRA_FAIL)
2353         return ZEBRA_FAIL;
2354     res = zebra_buffer_extract_record(zh, buf, buf_size,
2355                                       1, /* delete_flag */
2356                                       0, /* test_mode */
2357                                       recordType,
2358                                       sysno,
2359                                       match,fname,
2360                                       force_update,
2361                                       1); /* allow_update */
2362     if (zebra_end_trans(zh) != ZEBRA_OK)
2363     {
2364         yaz_log(YLOG_WARN, "zebra_end_trans failed");
2365         res = ZEBRA_FAIL;
2366     }
2367     return res;
2368 }
2369
2370 /* ---------------------------------------------------------------------------
2371   Searching 
2372 */
2373
2374 ZEBRA_RES zebra_search_PQF(ZebraHandle zh, const char *pqf_query,
2375                            const char *setname, zint *hits)
2376 {
2377     zint lhits = 0;
2378     ZEBRA_RES res = ZEBRA_OK;
2379     Z_RPNQuery *query;
2380     ODR odr;
2381
2382     ZEBRA_CHECK_HANDLE(zh);
2383
2384     odr = odr_createmem(ODR_ENCODE);
2385
2386     assert(pqf_query);
2387     assert(setname);
2388
2389     yaz_log(log_level, "zebra_search_PQF s=%s q=%s", setname, pqf_query);
2390     
2391     query = p_query_rpn (odr, PROTO_Z3950, pqf_query);
2392     
2393     if (!query)
2394     {
2395         yaz_log (YLOG_WARN, "bad query %s\n", pqf_query);
2396         zh->errCode = YAZ_BIB1_MALFORMED_QUERY;
2397         res = ZEBRA_FAIL;
2398     }
2399     else
2400         res = zebra_search_RPN(zh, odr, query, setname, &lhits);
2401     
2402     odr_destroy(odr);
2403
2404     yaz_log(log_level, "Hits: " ZINT_FORMAT, lhits);
2405
2406     if (hits)
2407         *hits = lhits;
2408
2409     return res;
2410 }
2411
2412 /* ---------------------------------------------------------------------------
2413   Sort - a simplified interface, with optional read locks.
2414 */
2415 int zebra_sort_by_specstr (ZebraHandle zh, ODR stream,
2416                            const char *sort_spec,
2417                            const char *output_setname,
2418                            const char **input_setnames) 
2419 {
2420     int num_input_setnames = 0;
2421     int sort_status = 0;
2422     Z_SortKeySpecList *sort_sequence;
2423
2424     ZEBRA_CHECK_HANDLE(zh);
2425     assert(stream);
2426     assert(sort_spec);
2427     assert(output_setname);
2428     assert(input_setnames);
2429     sort_sequence = yaz_sort_spec (stream, sort_spec);
2430     yaz_log(log_level, "sort (FIXME) ");
2431     if (!sort_sequence)
2432     {
2433         yaz_log(YLOG_WARN, "invalid sort specs '%s'", sort_spec);
2434         zh->errCode = YAZ_BIB1_CANNOT_SORT_ACCORDING_TO_SEQUENCE;
2435         return -1;
2436     }
2437     
2438     /* we can do this, since the perl typemap code for char** will 
2439        put a NULL at the end of list */
2440     while (input_setnames[num_input_setnames]) num_input_setnames++;
2441
2442     if (zebra_begin_read (zh))
2443         return -1;
2444     
2445     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
2446                    output_setname, sort_sequence, &sort_status);
2447     
2448     zebra_end_read(zh);
2449     return sort_status;
2450 }
2451
2452 /* ---------------------------------------------------------------------------
2453   Get BFS for Zebra system (to make alternative storage methods)
2454 */
2455 struct BFiles_struct *zebra_get_bfs(ZebraHandle zh)
2456 {
2457     if (zh && zh->reg)
2458         return zh->reg->bfs;
2459     return 0;
2460 }
2461
2462
2463 /* ---------------------------------------------------------------------------
2464   Set limit for search/scan
2465 */
2466 ZEBRA_RES zebra_set_limit(ZebraHandle zh, int complement_flag, zint *ids)
2467 {
2468     ZEBRA_CHECK_HANDLE(zh);
2469     zebra_limit_destroy(zh->m_limit);
2470     zh->m_limit = zebra_limit_create(complement_flag, ids);
2471     return ZEBRA_OK;
2472 }
2473
2474 /*
2475   Set Error code + addinfo
2476 */
2477 void zebra_setError(ZebraHandle zh, int code, const char *addinfo)
2478 {
2479     if (!zh)
2480         return;
2481     zh->errCode = code;
2482     nmem_reset(zh->nmem_error);
2483     zh->errString = addinfo ? nmem_strdup(zh->nmem_error, addinfo) : 0;
2484 }
2485
2486 void zebra_setError_zint(ZebraHandle zh, int code, zint i)
2487 {
2488     char vstr[60];
2489     sprintf(vstr, ZINT_FORMAT, i);
2490
2491     zh->errCode = code;
2492     nmem_reset(zh->nmem_error);
2493     zh->errString = nmem_strdup(zh->nmem_error, vstr);
2494 }
2495
2496 void zebra_lock_prefix(Res res, char *path)
2497 {
2498     const char *lock_dir = res_get_def (res, "lockDir", "");
2499     
2500     strcpy(path, lock_dir);
2501     if (*path && path[strlen(path)-1] != '/')
2502         strcat (path, "/");
2503 }
2504
2505 /*
2506  * Local variables:
2507  * c-basic-offset: 4
2508  * indent-tabs-mode: nil
2509  * End:
2510  * vim: shiftwidth=4 tabstop=8 expandtab
2511  */
2512