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