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