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