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