Added ZEBRA_CHECK_HANDLE(zh) which returns ZEBRA_FAIL if handle is
[idzebra-moved-to-github.git] / index / zinfo.c
1 /* $Id: zinfo.c,v 1.57 2006-03-30 09:52:15 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 <sys/types.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28
29 #include <idzebra/version.h>
30 #include "zinfo.h"
31
32 #define ZINFO_DEBUG 0
33
34 struct zebSUInfo {
35     int index_type;
36 #define ZEB_SU_SET_USE 1
37 #define ZEB_SU_STR 2
38     int which;
39     union {
40         char *str;
41         struct {
42             int set;
43             int use;
44         } su;
45     } u;
46     int ordinal;
47 };
48
49 struct zebSUInfoB {
50     struct zebSUInfo info;
51     struct zebSUInfoB *next;
52 };
53
54 typedef struct zebAccessObjectB *zebAccessObject;
55 struct zebAccessObjectB {
56     void *handle;
57     SYSNO sysno;
58     Odr_oid *oid;
59     zebAccessObject next;
60 };
61
62 typedef struct zebAccessInfoB *zebAccessInfo;
63 struct zebAccessInfoB {
64     zebAccessObject attributeSetIds;
65     zebAccessObject schemas;
66 };
67
68 typedef struct {
69     struct zebSUInfoB *SUInfo;
70     SYSNO sysno;
71     int dirty;
72     int readFlag;
73     data1_node *data1_tree;
74 } *zebAttributeDetails;
75
76 struct zebDatabaseInfoB {
77     zebAttributeDetails attributeDetails;
78     int ordinalDatabase;
79     char *databaseName;
80     data1_node *data1_database;
81     zint recordCount;    /* records in db */
82     zint recordBytes;    /* size of records */
83     SYSNO sysno;         /* sysno of database info */
84     int readFlag;        /* 1: read is needed when referenced; 0 if not */
85     int dirty;           /* 1: database is dirty: write is needed */
86     struct zebDatabaseInfoB *next;
87     zebAccessInfo accessInfo;
88 };
89
90 struct zebraExplainAttset {
91     char *name;
92     int ordinal;
93     struct zebraExplainAttset *next;
94 };
95
96 struct zebraCategoryListInfo {
97     int dirty;
98     SYSNO sysno;
99     data1_node *data1_categoryList;
100 };
101
102 struct zebraExplainInfo {
103     int ordinalSU;
104     int ordinalDatabase;
105     zint runNumber;
106     int dirty;
107     int write_flag;
108     Records records;
109     data1_handle dh;
110     Res res;
111     struct zebraExplainAttset *attsets;
112     NMEM nmem;
113     data1_node *data1_target;
114     struct zebraCategoryListInfo *categoryList;
115     struct zebDatabaseInfoB *databaseInfo;
116     struct zebDatabaseInfoB *curDatabaseInfo;
117     zebAccessInfo accessInfo;
118     char date[15]; /* YYYY MMDD HH MM SS */
119     int (*updateFunc)(void *handle, Record drec, data1_node *n);
120     void *updateHandle;
121 };
122
123 static void zebraExplain_initCommonInfo(ZebraExplainInfo zei, data1_node *n);
124 static void zebraExplain_initAccessInfo(ZebraExplainInfo zei, data1_node *n);
125
126 static data1_node *read_sgml_rec(data1_handle dh, NMEM nmem, Record rec)
127 {
128     return data1_read_sgml(dh, nmem, rec->info[recInfo_storeData]);
129 }
130
131 static void zebraExplain_writeDatabase(ZebraExplainInfo zei,
132                                         struct zebDatabaseInfoB *zdi,
133                                         int key_flush);
134 static void zebraExplain_writeAttributeDetails(ZebraExplainInfo zei,
135                                                 zebAttributeDetails zad,
136                                                 const char *databaseName,
137                                                 int key_flush);
138 static void zebraExplain_writeTarget(ZebraExplainInfo zei, int key_flush);
139 static void zebraExplain_writeAttributeSet(ZebraExplainInfo zei,
140                                             zebAccessObject o,
141                                             int key_flush);
142 static void zebraExplain_writeCategoryList(ZebraExplainInfo zei,
143                                             struct zebraCategoryListInfo *zcl,
144                                             int key_flush);
145
146
147 static Record createRecord(Records records, SYSNO *sysno)
148 {
149     Record rec;
150     if (*sysno)
151     {
152         rec = rec_get(records, *sysno);
153         if (!rec)
154             return 0;
155         xfree(rec->info[recInfo_storeData]);
156     }
157     else
158     {
159         rec = rec_new(records);
160         if (!rec)
161             return 0;
162         *sysno = rec->sysno;
163         
164         rec->info[recInfo_fileType] =
165             rec_strdup("grs.sgml", &rec->size[recInfo_fileType]);
166         rec->info[recInfo_databaseName] =
167             rec_strdup("IR-Explain-1",
168                         &rec->size[recInfo_databaseName]); 
169     }
170     return rec;
171 }
172
173 void zebraExplain_flush(ZebraExplainInfo zei, void *handle)
174 {
175     if (!zei)
176         return;
177     zei->updateHandle = handle;
178     if (zei->write_flag)
179     {
180         struct zebDatabaseInfoB *zdi;
181         zebAccessObject o;
182
183         /* write each database info record */
184         for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
185         {
186             zebraExplain_writeDatabase(zei, zdi, 1);
187             zebraExplain_writeAttributeDetails(zei, zdi->attributeDetails,
188                                                 zdi->databaseName, 1);
189         }
190         zebraExplain_writeTarget(zei, 1);
191         zebraExplain_writeCategoryList(zei,
192                                         zei->categoryList,
193                                         1);
194         assert(zei->accessInfo);
195         for (o = zei->accessInfo->attributeSetIds; o; o = o->next)
196             if (!o->sysno)
197                 zebraExplain_writeAttributeSet(zei, o, 1);
198         for (o = zei->accessInfo->schemas; o; o = o->next)
199             if (!o->sysno)
200             {
201 /*              zebraExplain_writeSchema(zei, o, 1); */
202             }
203
204         for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
205         {
206             zebraExplain_writeDatabase(zei, zdi, 0);
207             zebraExplain_writeAttributeDetails(zei, zdi->attributeDetails,
208                                                 zdi->databaseName, 0);
209         }
210         zebraExplain_writeTarget(zei, 0);
211     }
212 }
213
214 void zebraExplain_close(ZebraExplainInfo zei)
215 {
216 #if ZINFO_DEBUG
217     yaz_log(YLOG_LOG, "zebraExplain_close");
218 #endif
219     if (!zei)
220         return;
221     zebraExplain_flush(zei, zei->updateHandle);
222     nmem_destroy(zei->nmem);
223 }
224
225 void zebraExplain_mergeOids (ZebraExplainInfo zei, data1_node *n,
226                              zebAccessObject *op)
227 {
228     data1_node *np;
229
230     for (np = n->child; np; np = np->next)
231     {
232         char str[64];
233         int len;
234         Odr_oid *oid;
235         zebAccessObject ao;
236
237         if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "oid"))
238             continue;
239         len = np->child->u.data.len;
240         if (len > 63)
241             len = 63;
242         memcpy(str, np->child->u.data.data, len);
243         str[len] = '\0';
244         
245         oid = odr_getoidbystr_nmem(zei->nmem, str);
246
247         for (ao = *op; ao; ao = ao->next)
248             if (!oid_oidcmp(oid, ao->oid))
249             {
250                 ao->sysno = 1;
251                 break;
252             }
253         if (!ao)
254         {
255             ao = (zebAccessObject) nmem_malloc(zei->nmem, sizeof(*ao));
256             ao->handle = NULL;
257             ao->sysno = 1;
258             ao->oid = oid;
259             ao->next = *op;
260             *op = ao;
261         }
262     }
263 }
264
265 void zebraExplain_mergeAccessInfo(ZebraExplainInfo zei, data1_node *n,
266                                    zebAccessInfo *accessInfo)
267 {
268     data1_node *np;
269     
270     if (!n)
271     {
272         *accessInfo = (zebAccessInfo)
273             nmem_malloc(zei->nmem, sizeof(**accessInfo));
274         (*accessInfo)->attributeSetIds = NULL;
275         (*accessInfo)->schemas = NULL;
276     }
277     else
278     {
279         if (!(n = data1_search_tag(zei->dh, n->child, "accessInfo")))
280             return;
281         if ((np = data1_search_tag(zei->dh, n->child, "attributeSetIds")))
282             zebraExplain_mergeOids(zei, np,
283                                     &(*accessInfo)->attributeSetIds);
284         if ((np = data1_search_tag(zei->dh, n->child, "schemas")))
285             zebraExplain_mergeOids(zei, np,
286                                     &(*accessInfo)->schemas);
287     }
288 }
289
290 /* Explain structure
291     root record
292       of type targetInfo
293       and has sysno = 1
294
295     databaseList (list of databases)
296 */
297 /*
298 Example root:
299 explain:
300   targetInfo: TargetInfo
301     name: Zebra
302     namedResultSets: 1
303     multipleDbSearch: 1
304     nicknames:
305       name: Zebra
306     commonInfo:
307       dateAdded: 20030630190601
308       dateChanged: 20030630190601
309       languageCode: EN
310     accessinfo:
311       unitSystems:
312         string: ISO
313       attributeSetIds:
314         oid: 1.2.840.10003.3.2
315         oid: 1.2.840.10003.3.5
316         oid: 1.2.840.10003.3.1
317       schemas:
318         oid: 1.2.840.10003.13.1000.81.2
319         oid: 1.2.840.10003.13.2
320     zebraInfo:
321       version: 1.3.12
322       databaseList:
323         database:
324           name: Default
325           id: 50
326           attributeDetailsId: 51
327         database:
328           name: IR-Explain-1
329           id: 52
330           attributeDetailsId: 53
331       ordinalSU: 38
332       runNumber: 1
333 nextResultSetPosition = 2
334 */
335
336 ZebraExplainInfo zebraExplain_open(
337     Records records, data1_handle dh,
338     Res res,
339     int writeFlag,
340     void *updateHandle,
341     int (*updateFunc)(void *handle, Record drec, data1_node *n))
342 {
343     Record trec;
344     ZebraExplainInfo zei;
345     struct zebDatabaseInfoB **zdip;
346     time_t our_time;
347     struct tm *tm;
348     NMEM nmem = nmem_create();
349
350 #if ZINFO_DEBUG
351     yaz_log(YLOG_LOG, "zebraExplain_open wr=%d", writeFlag);
352 #endif
353     zei = (ZebraExplainInfo) nmem_malloc(nmem, sizeof(*zei));
354     zei->databaseInfo = 0;
355     zei->write_flag = writeFlag;
356     zei->updateHandle = updateHandle;
357     zei->updateFunc = updateFunc;
358     zei->dirty = 0;
359     zei->ordinalDatabase = 1;
360     zei->curDatabaseInfo = NULL;
361     zei->records = records;
362     zei->nmem = nmem;
363     zei->dh = dh;
364     zei->attsets = NULL;
365     zei->res = res;
366     zei->categoryList = (struct zebraCategoryListInfo *)
367         nmem_malloc(zei->nmem, sizeof(*zei->categoryList));
368     zei->categoryList->sysno = 0;
369     zei->categoryList->dirty = 0;
370     zei->categoryList->data1_categoryList = NULL;
371
372     if ( atoi(res_get_def(res, "notimestamps", "0") )== 0)
373     {
374         time(&our_time);
375         tm = localtime(&our_time);
376         sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
377                  tm->tm_year+1900, tm->tm_mon+1,  tm->tm_mday,
378                  tm->tm_hour, tm->tm_min, tm->tm_sec);
379     } else {
380         sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
381                  0, 0, 0,  0, 0, 0);
382     }
383     zdip = &zei->databaseInfo;
384     trec = rec_get_root(records);      /* get "root" record */
385
386     zei->ordinalSU = 1;
387     zei->runNumber = 0;
388
389     zebraExplain_mergeAccessInfo(zei, 0, &zei->accessInfo);
390     if (trec)    /* targetInfo already exists ... */
391     {
392         data1_node *node_tgtinfo, *node_zebra, *node_list, *np;
393
394         zei->data1_target = read_sgml_rec(zei->dh, zei->nmem, trec);
395 #if 0
396         if (!zei->data1_target || !zei->data1_target->u.root.absyn)
397 #else
398         if (!zei->data1_target)
399 #endif
400         {
401             yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
402             nmem_destroy(zei->nmem);
403             return 0;
404         }
405 #if ZINFO_DEBUG
406         data1_pr_tree(zei->dh, zei->data1_target, stderr);
407 #endif
408         node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
409                                          "/targetInfo");
410         zebraExplain_mergeAccessInfo(zei, node_tgtinfo,
411                                       &zei->accessInfo);
412
413         node_zebra = data1_search_tag(zei->dh, node_tgtinfo->child,
414                                        "zebraInfo");
415         np = 0;
416         if (node_zebra)
417         {
418             node_list = data1_search_tag(zei->dh, node_zebra->child,
419                                           "databaseList");
420             if (node_list)
421                 np = node_list->child;
422         }
423         for(; np; np = np->next)
424         {
425             data1_node *node_name = NULL;
426             data1_node *node_id = NULL;
427             data1_node *node_aid = NULL;
428             data1_node *np2;
429             if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "database"))
430                 continue;
431             for(np2 = np->child; np2; np2 = np2->next)
432             {
433                 if (np2->which != DATA1N_tag)
434                     continue;
435                 if (!strcmp(np2->u.tag.tag, "name"))
436                     node_name = np2->child;
437                 else if (!strcmp(np2->u.tag.tag, "id"))
438                     node_id = np2->child;
439                 else if (!strcmp(np2->u.tag.tag, "attributeDetailsId"))
440                     node_aid = np2->child;
441             }
442             assert(node_id && node_name && node_aid);
443             
444             *zdip =(struct zebDatabaseInfoB *) 
445                 nmem_malloc(zei->nmem, sizeof(**zdip));
446             (*zdip)->readFlag = 1;
447             (*zdip)->dirty = 0;
448             (*zdip)->data1_database = NULL;
449             (*zdip)->recordCount = 0;
450             (*zdip)->recordBytes = 0;
451             zebraExplain_mergeAccessInfo (zei, 0, &(*zdip)->accessInfo);
452
453             (*zdip)->databaseName = (char *)
454                 nmem_malloc (zei->nmem, 1+node_name->u.data.len);
455             memcpy((*zdip)->databaseName, node_name->u.data.data,
456                    node_name->u.data.len);
457             (*zdip)->databaseName[node_name->u.data.len] = '\0';
458             (*zdip)->sysno = atoi_zn (node_id->u.data.data,
459                                       node_id->u.data.len);
460             (*zdip)->attributeDetails = (zebAttributeDetails)
461                 nmem_malloc (zei->nmem, sizeof(*(*zdip)->attributeDetails));
462             (*zdip)->attributeDetails->sysno = atoi_zn (node_aid->u.data.data,
463                                                         node_aid->u.data.len);
464             (*zdip)->attributeDetails->readFlag = 1;
465             (*zdip)->attributeDetails->dirty = 0;
466             (*zdip)->attributeDetails->SUInfo = NULL;
467
468             zdip = &(*zdip)->next;
469         }
470         if (node_zebra)
471         {
472             np = data1_search_tag(zei->dh, node_zebra->child,
473                                   "ordinalSU");
474             np = np->child;
475             assert (np && np->which == DATA1N_data);
476             zei->ordinalSU = atoi_n(np->u.data.data, np->u.data.len);
477             
478             np = data1_search_tag(zei->dh, node_zebra->child,
479                                   "ordinalDatabase");
480             np = np->child;
481             assert (np && np->which == DATA1N_data);
482             zei->ordinalDatabase = atoi_n(np->u.data.data, np->u.data.len);
483
484             np = data1_search_tag(zei->dh, node_zebra->child,
485                                    "runNumber");
486             np = np->child;
487             assert (np && np->which == DATA1N_data);
488             zei->runNumber = atoi_zn(np->u.data.data, np->u.data.len);
489             yaz_log(YLOG_DEBUG, "read runnumber=" ZINT_FORMAT, zei->runNumber);
490             *zdip = NULL;
491         }
492         rec_rm(&trec);
493     }
494     else  /* create initial targetInfo */
495     {
496         data1_node *node_tgtinfo;
497
498         *zdip = NULL;
499         if (writeFlag)
500         {
501             char *sgml_buf;
502             int sgml_len;
503
504             zei->data1_target =
505                 data1_read_sgml(zei->dh, zei->nmem,
506                                  "<explain><targetInfo>TargetInfo\n"
507                                  "<name>Zebra</>\n"
508                                  "<namedResultSets>1</>\n"
509                                  "<multipleDBSearch>1</>\n"
510                                  "<nicknames><name>Zebra</></>\n"
511                                  "</></>\n" );
512             if (!zei->data1_target)
513             {
514                 yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
515                 nmem_destroy(zei->nmem);
516                 return 0;
517             }
518             node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
519                                              "/targetInfo");
520             assert(node_tgtinfo);
521
522             zebraExplain_initCommonInfo(zei, node_tgtinfo);
523             zebraExplain_initAccessInfo(zei, node_tgtinfo);
524
525             /* write now because we want to be sure about the sysno */
526             trec = rec_new(records);
527             if (!trec)
528             {
529                 yaz_log(YLOG_FATAL, "Cannot create root Explain record");
530                 nmem_destroy(zei->nmem);
531                 return 0;
532             }
533             trec->info[recInfo_fileType] =
534                 rec_strdup("grs.sgml", &trec->size[recInfo_fileType]);
535             trec->info[recInfo_databaseName] =
536                 rec_strdup("IR-Explain-1", &trec->size[recInfo_databaseName]);
537             
538             sgml_buf = data1_nodetoidsgml(dh, zei->data1_target, 0, &sgml_len);
539             trec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
540             memcpy(trec->info[recInfo_storeData], sgml_buf, sgml_len);
541             trec->size[recInfo_storeData] = sgml_len;
542                 
543             rec_put(records, &trec);
544             rec_rm(&trec);
545         }
546         
547         zebraExplain_newDatabase(zei, "IR-Explain-1", 0);
548             
549         if (!zei->categoryList->dirty)
550         {
551             struct zebraCategoryListInfo *zcl = zei->categoryList;
552             data1_node *node_cl;
553             
554             zcl->dirty = 1;
555             zcl->data1_categoryList =
556                 data1_read_sgml(zei->dh, zei->nmem,
557                                  "<explain><categoryList>CategoryList\n"
558                                  "</></>\n");
559         
560             if (zcl->data1_categoryList)
561             {
562                 node_cl = data1_search_tag(zei->dh, zcl->data1_categoryList,
563                                             "/categoryList");
564                 assert(node_cl);
565                 zebraExplain_initCommonInfo(zei, node_cl);
566             }
567         }
568     }
569     return zei;
570 }
571
572 static void zebraExplain_readAttributeDetails(ZebraExplainInfo zei,
573                                                zebAttributeDetails zad)
574 {
575     Record rec;
576     struct zebSUInfoB **zsuip = &zad->SUInfo;
577     data1_node *node_adinfo, *node_zebra, *node_list, *np;
578
579     assert (zad->sysno);
580     rec = rec_get(zei->records, zad->sysno);
581
582     zad->data1_tree = read_sgml_rec(zei->dh, zei->nmem, rec);
583
584     node_adinfo = data1_search_tag(zei->dh, zad->data1_tree,
585                                     "/attributeDetails");
586     node_zebra = data1_search_tag(zei->dh, node_adinfo->child,
587                                  "zebraInfo");
588     node_list = data1_search_tag(zei->dh, node_zebra->child,
589                                   "attrlist");
590     for (np = node_list->child; np; np = np->next)
591     {
592         data1_node *node_set = NULL;
593         data1_node *node_use = NULL;
594         data1_node *node_str = NULL;
595         data1_node *node_ordinal = NULL;
596         data1_node *node_type = NULL;
597         data1_node *np2;
598         char oid_str[128];
599         int oid_str_len;
600
601         if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "attr"))
602             continue;
603         for (np2 = np->child; np2; np2 = np2->next)
604         {
605             if (np2->which != DATA1N_tag || !np2->child ||
606                 np2->child->which != DATA1N_data)
607                 continue;
608             if (!strcmp(np2->u.tag.tag, "set"))
609                 node_set = np2->child;
610             else if (!strcmp(np2->u.tag.tag, "use"))
611                 node_use = np2->child;
612             else if (!strcmp(np2->u.tag.tag, "str"))
613                 node_str = np2->child;
614             else if (!strcmp(np2->u.tag.tag, "ordinal"))
615                 node_ordinal = np2->child;
616             else if (!strcmp(np2->u.tag.tag, "type"))
617                 node_type = np2->child;
618         }
619         assert(node_ordinal);
620
621         *zsuip = (struct zebSUInfoB *)
622             nmem_malloc(zei->nmem, sizeof(**zsuip));
623
624         if (node_type && node_type->u.data.len > 0)
625             (*zsuip)->info.index_type =  node_type->u.data.data[0];
626         else
627         {
628             yaz_log(YLOG_WARN, "Missing attribute 'type' in attribute info");
629             (*zsuip)->info.index_type = 'w';
630         }
631
632         if (node_set && node_use)
633         {
634             (*zsuip)->info.which = ZEB_SU_SET_USE;
635             
636             oid_str_len = node_set->u.data.len;
637             if (oid_str_len >= (int) sizeof(oid_str))
638                 oid_str_len = sizeof(oid_str)-1;
639             memcpy(oid_str, node_set->u.data.data, oid_str_len);
640             oid_str[oid_str_len] = '\0';
641
642             (*zsuip)->info.u.su.set = oid_getvalbyname(oid_str);
643             
644             (*zsuip)->info.u.su.use = atoi_n(node_use->u.data.data,
645                                          node_use->u.data.len);
646             yaz_log(YLOG_DEBUG, "set=%d use=%d ordinal=%d",
647                      (*zsuip)->info.u.su.set, (*zsuip)->info.u.su.use,
648                      (*zsuip)->info.ordinal);
649         }
650         else if (node_str)
651         {
652             (*zsuip)->info.which = ZEB_SU_STR;
653             
654             (*zsuip)->info.u.str = nmem_strdupn(zei->nmem,
655                                                 node_str->u.data.data,
656                                                 node_str->u.data.len);
657         }
658         else
659         {
660             yaz_log(YLOG_WARN, "Missing set/use/str in attribute info");
661             continue;
662         }
663         (*zsuip)->info.ordinal = atoi_n (node_ordinal->u.data.data,
664                                          node_ordinal->u.data.len);
665         zsuip = &(*zsuip)->next;
666     }
667     *zsuip = NULL;
668     zad->readFlag = 0;
669     rec_rm (&rec);
670 }
671
672 static void zebraExplain_readDatabase (ZebraExplainInfo zei,
673                                        struct zebDatabaseInfoB *zdi)
674 {
675     Record rec;
676     data1_node *node_dbinfo, *node_zebra, *np;
677
678     assert (zdi->sysno);
679     rec = rec_get (zei->records, zdi->sysno);
680
681     zdi->data1_database = read_sgml_rec (zei->dh, zei->nmem, rec);
682     
683     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
684                                     "/databaseInfo");
685     assert (node_dbinfo);
686     zebraExplain_mergeAccessInfo (zei, node_dbinfo, &zdi->accessInfo);
687
688     node_zebra = data1_search_tag (zei->dh, node_dbinfo->child,
689                                  "zebraInfo");
690     if (node_zebra
691         && (np = data1_search_tag (zei->dh, node_zebra->child,
692                                    "recordBytes")) 
693         && np->child && np->child->which == DATA1N_data)
694         zdi->recordBytes = atoi_zn (np->child->u.data.data,
695                                     np->child->u.data.len);
696
697     if (node_zebra
698         && (np = data1_search_tag (zei->dh, node_zebra->child,
699                                    "ordinalDatabase")) 
700         && np->child && np->child->which == DATA1N_data)
701         zdi->ordinalDatabase = atoi_n(np->child->u.data.data,
702                                       np->child->u.data.len);
703
704     if ((np = data1_search_tag (zei->dh, node_dbinfo->child,
705                                 "recordCount")) &&
706         (np = data1_search_tag (zei->dh, np->child,
707                                 "recordCountActual")) &&
708         np->child->which == DATA1N_data)
709     {
710         zdi->recordCount = atoi_zn (np->child->u.data.data,
711                                     np->child->u.data.len);
712     }
713     zdi->readFlag = 0;
714     rec_rm (&rec);
715 }
716
717 int zebraExplain_removeDatabase(ZebraExplainInfo zei, void *update_handle)
718 {
719     struct zebDatabaseInfoB **zdip = &zei->databaseInfo;
720
721     while (*zdip)
722     {
723         if (*zdip == zei->curDatabaseInfo)
724         {
725             struct zebDatabaseInfoB *zdi = *zdip;
726             Record rec;
727
728             zei->dirty = 1;
729             zei->updateHandle = update_handle;
730
731             if (zdi->attributeDetails)
732             {
733                 /* remove attribute details keys and delete it */
734                 zebAttributeDetails zad = zdi->attributeDetails;
735                 
736                 rec = rec_get(zei->records, zad->sysno);
737                 (*zei->updateFunc)(zei->updateHandle, rec, 0);
738                 rec_rm(&rec);
739             }
740             /* remove database record keys and delete it */
741             rec = rec_get (zei->records, zdi->sysno);
742             (*zei->updateFunc)(zei->updateHandle, rec, 0);
743             rec_rm(&rec);
744
745             /* remove from list */
746             *zdip = zdi->next;
747
748             /* current database is IR-Explain-1 */
749             return 0;
750         }
751         zdip = &(*zdip)->next;
752     }
753     return -1;
754 }
755
756 int zebraExplain_curDatabase (ZebraExplainInfo zei, const char *database)
757 {
758     struct zebDatabaseInfoB *zdi;
759     const char *database_n = strrchr (database, '/');
760
761     if (database_n)
762         database_n++;
763     else
764         database_n = database;
765     
766     assert (zei);
767     if (zei->curDatabaseInfo &&
768         !STRCASECMP (zei->curDatabaseInfo->databaseName, database))
769         return 0;
770     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
771     {
772         if (!STRCASECMP (zdi->databaseName, database_n))
773             break;
774     }
775     if (!zdi)
776         return -1;
777 #if ZINFO_DEBUG
778     yaz_log(YLOG_LOG, "zebraExplain_curDatabase: %s", database);
779 #endif
780     if (zdi->readFlag)
781     {
782 #if ZINFO_DEBUG
783         yaz_log(YLOG_LOG, "zebraExplain_readDatabase: %s", database);
784 #endif
785         zebraExplain_readDatabase (zei, zdi);
786     }
787     if (zdi->attributeDetails->readFlag)
788     {
789 #if ZINFO_DEBUG
790         yaz_log(YLOG_LOG, "zebraExplain_readAttributeDetails: %s", database);
791 #endif
792         zebraExplain_readAttributeDetails (zei, zdi->attributeDetails);
793     }
794     zei->curDatabaseInfo = zdi;
795     return 0;
796 }
797
798 static void zebraExplain_initCommonInfo (ZebraExplainInfo zei, data1_node *n)
799 {
800     data1_node *c = data1_mk_tag (zei->dh, zei->nmem, "commonInfo", 0, n);
801     data1_mk_tag_data_text (zei->dh, c, "dateAdded", zei->date, zei->nmem);
802     data1_mk_tag_data_text (zei->dh, c, "dateChanged", zei->date, zei->nmem);
803     data1_mk_tag_data_text (zei->dh, c, "languageCode", "EN", zei->nmem);
804 }
805
806 static void zebraExplain_updateCommonInfo (ZebraExplainInfo zei, data1_node *n)
807 {
808     data1_node *c = data1_search_tag (zei->dh, n->child, "commonInfo");
809     assert (c);
810     data1_mk_tag_data_text_uni (zei->dh, c, "dateChanged", zei->date,
811                                 zei->nmem);
812 }
813
814 static void zebraExplain_initAccessInfo (ZebraExplainInfo zei, data1_node *n)
815 {
816     data1_node *c = data1_mk_tag (zei->dh, zei->nmem, "accessInfo", 0, n);
817     data1_node *d = data1_mk_tag (zei->dh, zei->nmem, "unitSystems", 0, c);
818     data1_mk_tag_data_text (zei->dh, d, "string", "ISO", zei->nmem);
819 }
820
821 static void zebraExplain_updateAccessInfo (ZebraExplainInfo zei, data1_node *n,
822                                            zebAccessInfo accessInfo)
823 {
824     data1_node *c = data1_search_tag (zei->dh, n->child, "accessInfo");
825     data1_node *d;
826     zebAccessObject p;
827     
828     if (!c)
829     {
830         data1_pr_tree (zei->dh, n, stdout);
831         exit (0);
832         assert (c);
833     }
834
835     if ((p = accessInfo->attributeSetIds))
836     {
837         d = data1_mk_tag_uni (zei->dh, zei->nmem, "attributeSetIds", c);
838         for (; p; p = p->next)
839             data1_mk_tag_data_oid (zei->dh, d, "oid", p->oid, zei->nmem);
840     }
841     if ((p = accessInfo->schemas))
842     {
843         d = data1_mk_tag_uni (zei->dh, zei->nmem, "schemas", c);
844         for (; p; p = p->next)
845             data1_mk_tag_data_oid (zei->dh, d, "oid", p->oid, zei->nmem);
846     }
847 }
848
849 int zebraExplain_newDatabase (ZebraExplainInfo zei, const char *database,
850                               int explain_database)
851 {
852     struct zebDatabaseInfoB *zdi;
853     data1_node *node_dbinfo, *node_adinfo;
854     const char *database_n = strrchr (database, '/');
855
856     if (database_n)
857         database_n++;
858     else
859         database_n = database;
860
861 #if ZINFO_DEBUG
862     yaz_log(YLOG_LOG, "zebraExplain_newDatabase: %s", database);
863 #endif
864     assert (zei);
865     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
866     {
867         if (!STRCASECMP (zdi->databaseName, database_n))
868             break;
869     }
870     if (zdi)
871         return -1;
872     /* it's new really. make it */
873     zdi = (struct zebDatabaseInfoB *) nmem_malloc (zei->nmem, sizeof(*zdi));
874     zdi->next = zei->databaseInfo;
875     zei->databaseInfo = zdi;
876     zdi->sysno = 0;
877     zdi->recordCount = 0;
878     zdi->recordBytes = 0;
879     zdi->readFlag = 0;
880     zdi->databaseName = nmem_strdup (zei->nmem, database_n);
881
882     zdi->ordinalDatabase = zei->ordinalDatabase++;
883
884     zebraExplain_mergeAccessInfo (zei, 0, &zdi->accessInfo);
885     
886     assert (zei->dh);
887     assert (zei->nmem);
888
889     zdi->data1_database =
890         data1_read_sgml (zei->dh, zei->nmem, 
891                          "<explain><databaseInfo>DatabaseInfo\n"
892                          "</></>\n");
893     if (!zdi->data1_database)
894         return -2;
895
896     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
897                                     "/databaseInfo");
898     assert (node_dbinfo);
899
900     zebraExplain_initCommonInfo (zei, node_dbinfo);
901     zebraExplain_initAccessInfo (zei, node_dbinfo);
902
903     data1_mk_tag_data_text (zei->dh, node_dbinfo, "name",
904                                database, zei->nmem);
905     
906     if (explain_database)
907         data1_mk_tag_data_text (zei->dh, node_dbinfo, "explainDatabase",
908                                 "", zei->nmem);
909     
910     data1_mk_tag_data_text (zei->dh, node_dbinfo, "userFee",
911                             "0", zei->nmem);
912     
913     data1_mk_tag_data_text (zei->dh, node_dbinfo, "available",
914                             "1", zei->nmem);
915     
916 #if ZINFO_DEBUG
917     data1_pr_tree (zei->dh, zdi->data1_database, stderr);
918 #endif
919     zdi->dirty = 1;
920     zei->dirty = 1;
921     zei->curDatabaseInfo = zdi;
922
923     zdi->attributeDetails = (zebAttributeDetails)
924         nmem_malloc (zei->nmem, sizeof(*zdi->attributeDetails));
925     zdi->attributeDetails->readFlag = 0;
926     zdi->attributeDetails->sysno = 0;
927     zdi->attributeDetails->dirty = 1;
928     zdi->attributeDetails->SUInfo = NULL;
929     zdi->attributeDetails->data1_tree =
930         data1_read_sgml (zei->dh, zei->nmem,
931                          "<explain><attributeDetails>AttributeDetails\n"
932                          "</></>\n");
933
934     node_adinfo = data1_search_tag (zei->dh, zdi->attributeDetails->data1_tree,
935                                     "/attributeDetails");
936     assert (node_adinfo);
937
938     zebraExplain_initCommonInfo (zei, node_adinfo);
939
940     return 0;
941 }
942
943 static void writeAttributeValueDetails (ZebraExplainInfo zei,
944                                   zebAttributeDetails zad,
945                                   data1_node *node_atvs, data1_attset *attset)
946
947 {
948     struct zebSUInfoB *zsui;
949     int set_ordinal = attset->reference;
950     data1_attset_child *c;
951
952     for (c = attset->children; c; c = c->next)
953         writeAttributeValueDetails (zei, zad, node_atvs, c->child);
954     for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
955     {
956         if (zsui->info.which == ZEB_SU_SET_USE && 
957             set_ordinal == zsui->info.u.su.set)
958         {
959             data1_node *node_attvalue, *node_value;
960             node_attvalue = data1_mk_tag (zei->dh, zei->nmem, "attributeValue",
961                                           0 /* attr */, node_atvs);
962             node_value = data1_mk_tag (zei->dh, zei->nmem, "value",
963                                        0 /* attr */, node_attvalue);
964             data1_mk_tag_data_int (zei->dh, node_value, "numeric",
965                                    zsui->info.u.su.use, zei->nmem);
966         }
967     }
968 }
969
970 static void zebraExplain_writeCategoryList (ZebraExplainInfo zei,
971                                             struct zebraCategoryListInfo *zcl,
972                                             int key_flush)
973 {
974     char *sgml_buf;
975     int sgml_len;
976     int i;
977     Record drec;
978     data1_node *node_ci, *node_categoryList;
979     SYSNO sysno = 0;
980     static char *category[] = {
981         "CategoryList",
982         "TargetInfo",
983         "DatabaseInfo",
984         "AttributeDetails",
985         NULL
986     };
987
988     assert (zcl);
989     if (!zcl->dirty)
990         return ;
991     zcl->dirty = 1;
992     node_categoryList = zcl->data1_categoryList;
993
994 #if ZINFO_DEBUG
995     yaz_log(YLOG_LOG, "zebraExplain_writeCategoryList");
996 #endif
997
998     drec = createRecord (zei->records, &sysno);
999     if (!drec)
1000         return;
1001     
1002     node_ci = data1_search_tag (zei->dh, node_categoryList,
1003                                 "/categoryList");
1004     assert (node_ci);
1005     node_ci = data1_mk_tag (zei->dh, zei->nmem, "categories", 0 /* attr */,
1006                             node_ci);
1007     assert (node_ci);
1008     
1009     for (i = 0; category[i]; i++)
1010     {
1011         data1_node *node_cat = data1_mk_tag (zei->dh, zei->nmem,  "category",
1012                                              0 /* attr */, node_ci);
1013
1014         data1_mk_tag_data_text (zei->dh, node_cat, "name",
1015                                 category[i], zei->nmem);
1016     }
1017     /* extract *searchable* keys from it. We do this here, because
1018        record count, etc. is affected */
1019     if (key_flush)
1020         (*zei->updateFunc)(zei->updateHandle, drec, node_categoryList);
1021
1022     /* convert to "SGML" and write it */
1023 #if ZINFO_DEBUG
1024     data1_pr_tree (zei->dh, node_categoryList, stderr);
1025 #endif
1026     sgml_buf = data1_nodetoidsgml(zei->dh, node_categoryList, 0, &sgml_len);
1027     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1028     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1029     drec->size[recInfo_storeData] = sgml_len;
1030     
1031     rec_put (zei->records, &drec);
1032 }
1033
1034 static void zebraExplain_writeAttributeDetails (ZebraExplainInfo zei,
1035                                                 zebAttributeDetails zad,
1036                                                 const char *databaseName,
1037                                                 int key_flush)
1038 {
1039     char *sgml_buf;
1040     int sgml_len;
1041     Record drec;
1042     data1_node *node_adinfo, *node_list, *node_zebra, *node_attributesBySet;
1043     struct zebSUInfoB *zsui;
1044     int set_min;
1045     
1046     if (!zad->dirty)
1047         return;
1048     
1049     zad->dirty = 0;
1050 #if ZINFO_DEBUG
1051     yaz_log(YLOG_LOG, "zebraExplain_writeAttributeDetails");    
1052 #endif
1053
1054     drec = createRecord (zei->records, &zad->sysno);
1055     if (!drec)
1056         return;
1057     assert (zad->data1_tree);
1058
1059     node_adinfo = data1_search_tag (zei->dh, zad->data1_tree,
1060                                    "/attributeDetails");
1061     zebraExplain_updateCommonInfo (zei, node_adinfo);
1062
1063     data1_mk_tag_data_text (zei->dh, node_adinfo, "name",
1064                             databaseName, zei->nmem);
1065
1066     /* extract *searchable* keys from it. We do this here, because
1067        record count, etc. is affected */
1068     if (key_flush)
1069         (*zei->updateFunc)(zei->updateHandle, drec, zad->data1_tree);
1070
1071     node_attributesBySet = data1_mk_tag_uni (zei->dh, zei->nmem,
1072                                            "attributesBySet", node_adinfo);
1073     set_min = -1;
1074     while (1)
1075     {
1076         data1_node *node_asd;
1077         data1_attset *attset;
1078         int set_ordinal = -1;
1079         for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
1080         {
1081             if (zsui->info.which == ZEB_SU_SET_USE &&
1082                 (set_ordinal < 0 || set_ordinal > zsui->info.u.su.set)
1083                 && zsui->info.u.su.set > set_min)
1084                 set_ordinal = zsui->info.u.su.set;
1085         }
1086         if (set_ordinal < 0)
1087             break;
1088         set_min = set_ordinal;
1089         node_asd = data1_mk_tag (zei->dh, zei->nmem,
1090                                  "attributeSetDetails",
1091                                  0 /* attr */, node_attributesBySet);
1092
1093         attset = data1_attset_search_id (zei->dh, set_ordinal);
1094         if (!attset)
1095         {
1096             zebraExplain_loadAttsets (zei->dh, zei->res);
1097             attset = data1_attset_search_id (zei->dh, set_ordinal);
1098         }
1099         if (attset)
1100         {
1101             int oid[OID_SIZE];
1102             oident oe;
1103             
1104             oe.proto = PROTO_Z3950;
1105             oe.oclass = CLASS_ATTSET;
1106             oe.value = (enum oid_value) set_ordinal;
1107             
1108             if (oid_ent_to_oid (&oe, oid))
1109             {
1110                 data1_node *node_abt, *node_atd, *node_atvs;
1111                 data1_mk_tag_data_oid (zei->dh, node_asd, "oid",
1112                                        oid, zei->nmem);
1113                 
1114                 node_abt = data1_mk_tag (zei->dh, zei->nmem,
1115                                          "attributesByType",
1116                                          0 /*attr */, node_asd);
1117                 node_atd = data1_mk_tag (zei->dh, zei->nmem,
1118                                          "attributeTypeDetails", 
1119                                          0 /* attr */, node_abt);
1120                 data1_mk_tag_data_int (zei->dh, node_atd,
1121                                        "type", 1, zei->nmem);
1122                 node_atvs = data1_mk_tag (zei->dh, zei->nmem, 
1123                                           "attributeValues",
1124                                           0 /* attr */, node_atd);
1125                 writeAttributeValueDetails (zei, zad, node_atvs, attset);
1126             }
1127         }
1128     }
1129     /* zebra info (private) */
1130     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1131                                  "zebraInfo", node_adinfo);
1132     node_list = data1_mk_tag_uni (zei->dh, zei->nmem,
1133                                  "attrlist", node_zebra);
1134     for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
1135     {
1136         struct oident oident;
1137         int oid[OID_SIZE];
1138         data1_node *node_attr;
1139         char index_type_str[2];
1140
1141         
1142         node_attr = data1_mk_tag (zei->dh, zei->nmem, "attr", 0 /* attr */,
1143                                   node_list);
1144
1145         index_type_str[0] = zsui->info.index_type;
1146         index_type_str[1] = '\0';
1147         data1_mk_tag_data_text (zei->dh, node_attr, "type",
1148                                 index_type_str, zei->nmem);
1149         if (zsui->info.which == ZEB_SU_SET_USE)
1150         {
1151             oident.proto = PROTO_Z3950;
1152             oident.oclass = CLASS_ATTSET;
1153             oident.value = (enum oid_value) zsui->info.u.su.set;
1154             oid_ent_to_oid (&oident, oid);
1155             
1156             data1_mk_tag_data_text (zei->dh, node_attr, "set",
1157                                     oident.desc, zei->nmem);
1158             data1_mk_tag_data_int (zei->dh, node_attr, "use",
1159                                    zsui->info.u.su.use, zei->nmem);
1160         }
1161         else if (zsui->info.which == ZEB_SU_STR)
1162         {
1163             data1_mk_tag_data_text (zei->dh, node_attr, "str",
1164                                     zsui->info.u.str, zei->nmem);
1165         }
1166         data1_mk_tag_data_int (zei->dh, node_attr, "ordinal",
1167                                zsui->info.ordinal, zei->nmem);
1168     }
1169     /* convert to "SGML" and write it */
1170 #if ZINFO_DEBUG
1171     data1_pr_tree (zei->dh, zad->data1_tree, stderr);
1172 #endif
1173     sgml_buf = data1_nodetoidsgml(zei->dh, zad->data1_tree,
1174                                   0, &sgml_len);
1175     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1176     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1177     drec->size[recInfo_storeData] = sgml_len;
1178     
1179     rec_put (zei->records, &drec);
1180 }
1181
1182 static void zebraExplain_writeDatabase (ZebraExplainInfo zei,
1183                                         struct zebDatabaseInfoB *zdi,
1184                                         int key_flush)
1185 {
1186     char *sgml_buf;
1187     int sgml_len;
1188     Record drec;
1189     data1_node *node_dbinfo, *node_count, *node_zebra;
1190     
1191     if (!zdi->dirty)
1192         return;
1193
1194     zdi->dirty = 0;
1195 #if ZINFO_DEBUG
1196     yaz_log(YLOG_LOG, "zebraExplain_writeDatabase %s", zdi->databaseName);
1197 #endif
1198     drec = createRecord (zei->records, &zdi->sysno);
1199     if (!drec)
1200         return;
1201     assert (zdi->data1_database);
1202
1203     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
1204                                     "/databaseInfo");
1205
1206     assert (node_dbinfo);
1207     zebraExplain_updateCommonInfo (zei, node_dbinfo);
1208     zebraExplain_updateAccessInfo (zei, node_dbinfo, zdi->accessInfo);
1209
1210     /* extract *searchable* keys from it. We do this here, because
1211        record count, etc. is affected */
1212     if (key_flush)
1213         (*zei->updateFunc)(zei->updateHandle, drec, zdi->data1_database);
1214     /* record count */
1215     node_count = data1_mk_tag_uni (zei->dh, zei->nmem,
1216                                  "recordCount", node_dbinfo);
1217     data1_mk_tag_data_zint (zei->dh, node_count, "recordCountActual",
1218                             zdi->recordCount, zei->nmem);
1219
1220     /* zebra info (private) */
1221     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1222                                  "zebraInfo", node_dbinfo);
1223     data1_mk_tag_data_zint (zei->dh, node_zebra,
1224                            "recordBytes", zdi->recordBytes, zei->nmem);
1225
1226     data1_mk_tag_data_zint(zei->dh, node_zebra,
1227                            "ordinalDatabase", zdi->ordinalDatabase, zei->nmem);
1228
1229     /* convert to "SGML" and write it */
1230 #if ZINFO_DEBUG
1231     data1_pr_tree (zei->dh, zdi->data1_database, stderr);
1232 #endif
1233     sgml_buf = data1_nodetoidsgml(zei->dh, zdi->data1_database,
1234                                   0, &sgml_len);
1235     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1236     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1237     drec->size[recInfo_storeData] = sgml_len;
1238     
1239     rec_put (zei->records, &drec);
1240 }
1241
1242 static void writeAttributeValues (ZebraExplainInfo zei,
1243                                   data1_node *node_values,
1244                                   data1_attset *attset)
1245 {
1246     data1_att *atts;
1247     data1_attset_child *c;
1248
1249     if (!attset)
1250         return;
1251
1252     for (c = attset->children; c; c = c->next)
1253         writeAttributeValues (zei, node_values, c->child);
1254     for (atts = attset->atts; atts; atts = atts->next)
1255     {
1256         data1_node *node_value;
1257         
1258         node_value = data1_mk_tag (zei->dh, zei->nmem, "attributeValue",
1259                                    0 /* attr */, node_values);
1260         data1_mk_tag_data_text (zei->dh, node_value, "name",
1261                                 atts->name, zei->nmem);
1262         node_value = data1_mk_tag (zei->dh, zei->nmem, "value",
1263                                    0 /* attr */, node_value);
1264         data1_mk_tag_data_int (zei->dh, node_value, "numeric",
1265                                atts->value, zei->nmem);
1266     }
1267 }
1268
1269
1270 static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
1271                                             zebAccessObject o,
1272                                             int key_flush)
1273 {
1274     char *sgml_buf;
1275     int sgml_len;
1276     Record drec;
1277     data1_node *node_root, *node_attinfo, *node_attributes, *node_atttype;
1278     data1_node *node_values;
1279     struct oident *entp;
1280     struct data1_attset *attset = NULL;
1281     
1282     if ((entp = oid_getentbyoid (o->oid)))
1283         attset = data1_attset_search_id (zei->dh, entp->value);
1284             
1285 #if ZINFO_DEBUG
1286     yaz_log(YLOG_LOG, "zebraExplain_writeAttributeSet %s",
1287           attset ? attset->name : "<unknown>");    
1288 #endif
1289
1290     drec = createRecord (zei->records, &o->sysno);
1291     if (!drec)
1292         return;
1293     node_root =
1294         data1_read_sgml (zei->dh, zei->nmem,
1295                          "<explain><attributeSetInfo>AttributeSetInfo\n"
1296                          "</></>\n" );
1297
1298     node_attinfo = data1_search_tag (zei->dh, node_root,
1299                                    "/attributeSetInfo");
1300
1301     assert (node_attinfo);
1302     zebraExplain_initCommonInfo (zei, node_attinfo);
1303     zebraExplain_updateCommonInfo (zei, node_attinfo);
1304
1305     data1_mk_tag_data_oid (zei->dh, node_attinfo,
1306                             "oid", o->oid, zei->nmem);
1307     if (attset && attset->name)
1308         data1_mk_tag_data_text (zei->dh, node_attinfo,
1309                                 "name", attset->name, zei->nmem);
1310     
1311     node_attributes = data1_mk_tag_uni (zei->dh, zei->nmem,
1312                                       "attributes", node_attinfo);
1313     node_atttype = data1_mk_tag_uni (zei->dh, zei->nmem,
1314                                    "attributeType", node_attributes);
1315     data1_mk_tag_data_text (zei->dh, node_atttype,
1316                             "name", "Use", zei->nmem);
1317     data1_mk_tag_data_text (zei->dh, node_atttype,
1318                             "description", "Use Attribute", zei->nmem);
1319     data1_mk_tag_data_int (zei->dh, node_atttype,
1320                            "type", 1, zei->nmem);
1321     node_values = data1_mk_tag (zei->dh, zei->nmem,
1322                                 "attributeValues", 0 /* attr */, node_atttype);
1323     if (attset)
1324         writeAttributeValues (zei, node_values, attset);
1325
1326     /* extract *searchable* keys from it. We do this here, because
1327        record count, etc. is affected */
1328     if (key_flush)
1329         (*zei->updateFunc)(zei->updateHandle, drec, node_root);
1330     /* convert to "SGML" and write it */
1331 #if ZINFO_DEBUG
1332     data1_pr_tree (zei->dh, node_root, stderr);
1333 #endif
1334     sgml_buf = data1_nodetoidsgml(zei->dh, node_root, 0, &sgml_len);
1335     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1336     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1337     drec->size[recInfo_storeData] = sgml_len;
1338     
1339     rec_put (zei->records, &drec);
1340 }
1341
1342 static void zebraExplain_writeTarget (ZebraExplainInfo zei, int key_flush)
1343 {
1344     struct zebDatabaseInfoB *zdi;
1345     data1_node *node_tgtinfo, *node_list, *node_zebra;
1346     Record trec;
1347     int sgml_len;
1348     char *sgml_buf;
1349
1350     if (!zei->dirty)
1351         return;
1352     zei->dirty = 0;
1353
1354     trec = rec_get_root(zei->records);
1355     xfree (trec->info[recInfo_storeData]);
1356
1357     node_tgtinfo = data1_search_tag (zei->dh, zei->data1_target,
1358                                      "/targetInfo");
1359     assert (node_tgtinfo);
1360
1361     zebraExplain_updateCommonInfo (zei, node_tgtinfo);
1362     zebraExplain_updateAccessInfo (zei, node_tgtinfo, zei->accessInfo);
1363
1364     /* convert to "SGML" and write it */
1365     if (key_flush)
1366         (*zei->updateFunc)(zei->updateHandle, trec, zei->data1_target);
1367
1368     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1369                                  "zebraInfo", node_tgtinfo);
1370     data1_mk_tag_data_text (zei->dh, node_zebra, "version",
1371                                ZEBRAVER, zei->nmem);
1372     node_list = data1_mk_tag (zei->dh, zei->nmem,
1373                               "databaseList", 0 /* attr */, node_zebra);
1374     for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
1375     {
1376         data1_node *node_db;
1377         node_db = data1_mk_tag (zei->dh, zei->nmem,
1378                                 "database", 0 /* attr */, node_list);
1379         data1_mk_tag_data_text (zei->dh, node_db, "name",
1380                                 zdi->databaseName, zei->nmem);
1381         data1_mk_tag_data_zint (zei->dh, node_db, "id",
1382                                 zdi->sysno, zei->nmem);
1383         data1_mk_tag_data_zint (zei->dh, node_db, "attributeDetailsId",
1384                                 zdi->attributeDetails->sysno, zei->nmem);
1385     }
1386     data1_mk_tag_data_int (zei->dh, node_zebra, "ordinalSU",
1387                            zei->ordinalSU, zei->nmem);
1388
1389     data1_mk_tag_data_int (zei->dh, node_zebra, "ordinalDatabase",
1390                            zei->ordinalDatabase, zei->nmem);
1391
1392     data1_mk_tag_data_zint (zei->dh, node_zebra, "runNumber",
1393                             zei->runNumber, zei->nmem);
1394
1395 #if ZINFO_DEBUG
1396     data1_pr_tree (zei->dh, zei->data1_target, stderr);
1397 #endif
1398     sgml_buf = data1_nodetoidsgml(zei->dh, zei->data1_target,
1399                                   0, &sgml_len);
1400     trec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1401     memcpy (trec->info[recInfo_storeData], sgml_buf, sgml_len);
1402     trec->size[recInfo_storeData] = sgml_len;
1403     
1404     rec_put (zei->records, &trec);
1405 }
1406
1407 int zebraExplain_lookup_attr_su_any_index(ZebraExplainInfo zei,
1408                                           int set, int use)
1409 {
1410     struct zebSUInfoB *zsui;
1411
1412     assert (zei->curDatabaseInfo);
1413     for (zsui = zei->curDatabaseInfo->attributeDetails->SUInfo;
1414          zsui; zsui=zsui->next)
1415         if (zsui->info.which == ZEB_SU_SET_USE &&
1416             zsui->info.u.su.use == use && zsui->info.u.su.set == set)
1417             return zsui->info.ordinal;
1418     return -1;
1419 }
1420
1421 int zebraExplain_lookup_attr_su(ZebraExplainInfo zei, int index_type,
1422                                 int set, int use)
1423 {
1424     struct zebSUInfoB *zsui;
1425
1426     assert (zei->curDatabaseInfo);
1427     for (zsui = zei->curDatabaseInfo->attributeDetails->SUInfo;
1428          zsui; zsui=zsui->next)
1429         if (zsui->info.index_type == index_type &&
1430             zsui->info.which == ZEB_SU_SET_USE &&
1431             zsui->info.u.su.use == use && zsui->info.u.su.set == set)
1432             return zsui->info.ordinal;
1433     return -1;
1434 }
1435
1436 int zebraExplain_lookup_attr_str(ZebraExplainInfo zei, int index_type,
1437                                  const char *str)
1438 {
1439     struct zebSUInfoB *zsui;
1440
1441     assert (zei->curDatabaseInfo);
1442     for (zsui = zei->curDatabaseInfo->attributeDetails->SUInfo;
1443          zsui; zsui=zsui->next)
1444         if (zsui->info.index_type == index_type &&
1445             zsui->info.which == ZEB_SU_STR && !strcmp(zsui->info.u.str, str))
1446             return zsui->info.ordinal;
1447     return -1;
1448 }
1449
1450 int zebraExplain_trav_ord(ZebraExplainInfo zei, void *handle,
1451                           int (*f)(void *handle, int ord))
1452 {
1453     struct zebDatabaseInfoB *zdb = zei->curDatabaseInfo;
1454     if (zdb)
1455     {
1456         struct zebSUInfoB *zsui = zdb->attributeDetails->SUInfo;
1457         for ( ;zsui; zsui = zsui->next)
1458             (*f)(handle,  zsui->info.ordinal);
1459     }
1460     return 0;
1461 }
1462                           
1463 int zebraExplain_lookup_ord (ZebraExplainInfo zei, int ord,
1464                              int *index_type, 
1465                              const char **db,
1466                              int *set, int *use,
1467                              const char **string_index)
1468 {
1469     struct zebDatabaseInfoB *zdb;
1470
1471     if (set)
1472         *set = -1;
1473     if (use)
1474         *use = -1;
1475     if (index_type)
1476         *index_type = 0;
1477     if (string_index)
1478         *string_index = 0;
1479
1480     for (zdb = zei->databaseInfo; zdb; zdb = zdb->next)
1481     {
1482         struct zebSUInfoB *zsui;
1483
1484         if (zdb->attributeDetails->readFlag)
1485             zebraExplain_readAttributeDetails (zei, zdb->attributeDetails);
1486             
1487         for (zsui = zdb->attributeDetails->SUInfo; zsui; zsui = zsui->next)
1488             if (zsui->info.ordinal == ord)
1489             {
1490                 if (db)
1491                     *db = zdb->databaseName;
1492                 if (zsui->info.which == ZEB_SU_SET_USE)
1493                 {
1494                     if (set)
1495                         *set = zsui->info.u.su.set;
1496                     if (use)
1497                         *use = zsui->info.u.su.use;
1498                 }
1499
1500                 if (zsui->info.which == ZEB_SU_STR)
1501                     if (string_index)
1502                         *string_index = zsui->info.u.str;
1503
1504                 if (index_type)
1505                     *index_type = zsui->info.index_type;
1506                 return 0;
1507             }
1508     }
1509     return -1;
1510 }
1511
1512 zebAccessObject zebraExplain_announceOid (ZebraExplainInfo zei,
1513                                           zebAccessObject *op,
1514                                           Odr_oid *oid)
1515 {
1516     zebAccessObject ao;
1517     
1518     for (ao = *op; ao; ao = ao->next)
1519         if (!oid_oidcmp (oid, ao->oid))
1520             break;
1521     if (!ao)
1522     {
1523         ao = (zebAccessObject) nmem_malloc (zei->nmem, sizeof(*ao));
1524         ao->handle = NULL;
1525         ao->sysno = 0;
1526         ao->oid = odr_oiddup_nmem (zei->nmem, oid);
1527         ao->next = *op;
1528         *op = ao;
1529     }
1530     return ao;
1531 }
1532
1533 void zebraExplain_addAttributeSet (ZebraExplainInfo zei, int set)
1534 {
1535     oident oe;
1536     int oid[OID_SIZE];
1537
1538     oe.proto = PROTO_Z3950;
1539     oe.oclass = CLASS_ATTSET;
1540     oe.value = (enum oid_value) set;
1541
1542     if (oid_ent_to_oid (&oe, oid))
1543     {
1544         zebraExplain_announceOid (zei, &zei->accessInfo->attributeSetIds, oid);
1545         zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
1546                                   accessInfo->attributeSetIds, oid);
1547     }
1548 }
1549
1550 int zebraExplain_add_attr_su(ZebraExplainInfo zei, int index_type,
1551                              int set, int use)
1552 {
1553     struct zebSUInfoB *zsui;
1554
1555     assert (zei->curDatabaseInfo);
1556     zebraExplain_addAttributeSet (zei, set);
1557     zsui = (struct zebSUInfoB *) nmem_malloc (zei->nmem, sizeof(*zsui));
1558     zsui->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
1559     zei->curDatabaseInfo->attributeDetails->SUInfo = zsui;
1560     zei->curDatabaseInfo->attributeDetails->dirty = 1;
1561     zei->dirty = 1;
1562     zsui->info.index_type = index_type;
1563     zsui->info.which = ZEB_SU_SET_USE;
1564     zsui->info.u.su.set = set;
1565     zsui->info.u.su.use = use;
1566     zsui->info.ordinal = (zei->ordinalSU)++;
1567     return zsui->info.ordinal;
1568 }
1569
1570 int zebraExplain_add_attr_str(ZebraExplainInfo zei, int index_type,
1571                               const char *index_name)
1572 {
1573     struct zebSUInfoB *zsui;
1574
1575     assert (zei->curDatabaseInfo);
1576     zsui = (struct zebSUInfoB *) nmem_malloc (zei->nmem, sizeof(*zsui));
1577     zsui->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
1578     zei->curDatabaseInfo->attributeDetails->SUInfo = zsui;
1579     zei->curDatabaseInfo->attributeDetails->dirty = 1;
1580     zei->dirty = 1;
1581     zsui->info.index_type = index_type;
1582     zsui->info.which = ZEB_SU_STR;
1583     zsui->info.u.str = nmem_strdup(zei->nmem, index_name);
1584     zsui->info.ordinal = (zei->ordinalSU)++;
1585     return zsui->info.ordinal;
1586 }
1587
1588 void zebraExplain_addSchema (ZebraExplainInfo zei, Odr_oid *oid)
1589 {
1590     zebraExplain_announceOid (zei, &zei->accessInfo->schemas, oid);
1591     zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
1592                               accessInfo->schemas, oid);
1593 }
1594
1595 void zebraExplain_recordBytesIncrement (ZebraExplainInfo zei, int adjust_num)
1596 {
1597     assert (zei->curDatabaseInfo);
1598
1599     if (adjust_num)
1600     {
1601         zei->curDatabaseInfo->recordBytes += adjust_num;
1602         zei->curDatabaseInfo->dirty = 1;
1603     }
1604 }
1605
1606 void zebraExplain_recordCountIncrement (ZebraExplainInfo zei, int adjust_num)
1607 {
1608     assert (zei->curDatabaseInfo);
1609
1610     if (adjust_num)
1611     {
1612         zei->curDatabaseInfo->recordCount += adjust_num;
1613         zei->curDatabaseInfo->dirty = 1;
1614     }
1615 }
1616
1617 zint zebraExplain_runNumberIncrement (ZebraExplainInfo zei, int adjust_num)
1618 {
1619     if (adjust_num)
1620     {
1621         zei->dirty = 1;
1622     }
1623     return zei->runNumber += adjust_num;
1624 }
1625
1626 RecordAttr *rec_init_attr (ZebraExplainInfo zei, Record rec)
1627 {
1628     RecordAttr *recordAttr;
1629
1630     if (rec->info[recInfo_attr])
1631         return (RecordAttr *) rec->info[recInfo_attr];
1632     recordAttr = (RecordAttr *) xmalloc (sizeof(*recordAttr));
1633     rec->info[recInfo_attr] = (char *) recordAttr;
1634     rec->size[recInfo_attr] = sizeof(*recordAttr);
1635     
1636     recordAttr->recordSize = 0;
1637     recordAttr->recordOffset = 0;
1638     recordAttr->runNumber = zei->runNumber;
1639     recordAttr->staticrank = 0;
1640     return recordAttr;
1641 }
1642
1643 static void att_loadset(void *p, const char *n, const char *name)
1644 {
1645     data1_handle dh = (data1_handle) p;
1646     if (!data1_get_attset (dh, name))
1647         yaz_log(YLOG_WARN, "Directive attset failed for %s", name);
1648 }
1649
1650 int zebraExplain_get_database_ord(ZebraExplainInfo zei)
1651 {
1652     if (!zei->curDatabaseInfo)
1653         return -1;
1654     return zei->curDatabaseInfo->ordinalDatabase;
1655 }
1656
1657 void zebraExplain_loadAttsets (data1_handle dh, Res res)
1658 {
1659     res_trav(res, "attset", dh, att_loadset);
1660 }
1661
1662 /*
1663      zebraExplain_addSU adds to AttributeDetails for a database and
1664      adds attributeSet (in AccessInfo area) to DatabaseInfo if it doesn't
1665      exist for the database.
1666
1667      If the database doesn't exist globally (in TargetInfo) an 
1668      AttributeSetInfo must be added (globally).
1669  */