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