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