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