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