Furhter code reductions because of string attributes
[idzebra-moved-to-github.git] / index / zinfo.c
1 /* $Id: zinfo.c,v 1.65 2006-05-19 23:20:24 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     int (*updateFunc)(void *handle, Record drec, data1_node *n);
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     int (*updateFunc)(void *handle, Record drec, data1_node *n))
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     zei->attsets = NULL;
363     zei->res = res;
364     zei->categoryList = (struct zebraCategoryListInfo *)
365         nmem_malloc(zei->nmem, sizeof(*zei->categoryList));
366     zei->categoryList->sysno = 0;
367     zei->categoryList->dirty = 0;
368     zei->categoryList->data1_categoryList = NULL;
369
370     if ( atoi(res_get_def(res, "notimestamps", "0") )== 0)
371     {
372         time(&our_time);
373         tm = localtime(&our_time);
374         sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
375                  tm->tm_year+1900, tm->tm_mon+1,  tm->tm_mday,
376                  tm->tm_hour, tm->tm_min, tm->tm_sec);
377     } else {
378         sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
379                  0, 0, 0,  0, 0, 0);
380     }
381     zdip = &zei->databaseInfo;
382     trec = rec_get_root(records);      /* get "root" record */
383
384     zei->ordinalSU = 1;
385     zei->runNumber = 0;
386
387     zebraExplain_mergeAccessInfo(zei, 0, &zei->accessInfo);
388     if (trec)    /* targetInfo already exists ... */
389     {
390         data1_node *node_tgtinfo, *node_zebra, *node_list, *np;
391
392         zei->data1_target = read_sgml_rec(zei->dh, zei->nmem, trec);
393 #if 0
394         if (!zei->data1_target || !zei->data1_target->u.root.absyn)
395 #else
396         if (!zei->data1_target)
397 #endif
398         {
399             yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
400             nmem_destroy(zei->nmem);
401             return 0;
402         }
403 #if ZINFO_DEBUG
404         data1_pr_tree(zei->dh, zei->data1_target, stderr);
405 #endif
406         node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
407                                          "/targetInfo");
408         zebraExplain_mergeAccessInfo(zei, node_tgtinfo,
409                                       &zei->accessInfo);
410
411         node_zebra = data1_search_tag(zei->dh, node_tgtinfo->child,
412                                        "zebraInfo");
413         np = 0;
414         if (node_zebra)
415         {
416             node_list = data1_search_tag(zei->dh, node_zebra->child,
417                                           "databaseList");
418             if (node_list)
419                 np = node_list->child;
420         }
421         for(; np; np = np->next)
422         {
423             data1_node *node_name = NULL;
424             data1_node *node_id = NULL;
425             data1_node *node_aid = NULL;
426             data1_node *np2;
427             if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "database"))
428                 continue;
429             for(np2 = np->child; np2; np2 = np2->next)
430             {
431                 if (np2->which != DATA1N_tag)
432                     continue;
433                 if (!strcmp(np2->u.tag.tag, "name"))
434                     node_name = np2->child;
435                 else if (!strcmp(np2->u.tag.tag, "id"))
436                     node_id = np2->child;
437                 else if (!strcmp(np2->u.tag.tag, "attributeDetailsId"))
438                     node_aid = np2->child;
439             }
440             assert(node_id && node_name && node_aid);
441             
442             *zdip =(struct zebDatabaseInfoB *) 
443                 nmem_malloc(zei->nmem, sizeof(**zdip));
444             (*zdip)->readFlag = 1;
445             (*zdip)->dirty = 0;
446             (*zdip)->data1_database = NULL;
447             (*zdip)->recordCount = 0;
448             (*zdip)->recordBytes = 0;
449             zebraExplain_mergeAccessInfo (zei, 0, &(*zdip)->accessInfo);
450
451             (*zdip)->databaseName = (char *)
452                 nmem_malloc (zei->nmem, 1+node_name->u.data.len);
453             memcpy((*zdip)->databaseName, node_name->u.data.data,
454                    node_name->u.data.len);
455             (*zdip)->databaseName[node_name->u.data.len] = '\0';
456             (*zdip)->sysno = atoi_zn (node_id->u.data.data,
457                                       node_id->u.data.len);
458             (*zdip)->attributeDetails = (zebAttributeDetails)
459                 nmem_malloc (zei->nmem, sizeof(*(*zdip)->attributeDetails));
460             (*zdip)->attributeDetails->sysno = atoi_zn (node_aid->u.data.data,
461                                                         node_aid->u.data.len);
462             (*zdip)->attributeDetails->readFlag = 1;
463             (*zdip)->attributeDetails->dirty = 0;
464             (*zdip)->attributeDetails->SUInfo = NULL;
465
466             zdip = &(*zdip)->next;
467         }
468         if (node_zebra)
469         {
470             np = data1_search_tag(zei->dh, node_zebra->child,
471                                   "ordinalSU");
472             np = np->child;
473             assert (np && np->which == DATA1N_data);
474             zei->ordinalSU = atoi_n(np->u.data.data, np->u.data.len);
475             
476             np = data1_search_tag(zei->dh, node_zebra->child,
477                                   "ordinalDatabase");
478             np = np->child;
479             assert (np && np->which == DATA1N_data);
480             zei->ordinalDatabase = atoi_n(np->u.data.data, np->u.data.len);
481
482             np = data1_search_tag(zei->dh, node_zebra->child,
483                                    "runNumber");
484             np = np->child;
485             assert (np && np->which == DATA1N_data);
486             zei->runNumber = atoi_zn(np->u.data.data, np->u.data.len);
487             yaz_log(YLOG_DEBUG, "read runnumber=" ZINT_FORMAT, zei->runNumber);
488             *zdip = NULL;
489         }
490         rec_rm(&trec);
491     }
492     else  /* create initial targetInfo */
493     {
494         data1_node *node_tgtinfo;
495
496         *zdip = NULL;
497         if (writeFlag)
498         {
499             char *sgml_buf;
500             int sgml_len;
501
502             zei->data1_target =
503                 data1_read_sgml(zei->dh, zei->nmem,
504                                  "<explain><targetInfo>TargetInfo\n"
505                                  "<name>Zebra</>\n"
506                                  "<namedResultSets>1</>\n"
507                                  "<multipleDBSearch>1</>\n"
508                                  "<nicknames><name>Zebra</></>\n"
509                                  "</></>\n" );
510             if (!zei->data1_target)
511             {
512                 yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
513                 nmem_destroy(zei->nmem);
514                 return 0;
515             }
516             node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
517                                              "/targetInfo");
518             assert(node_tgtinfo);
519
520             zebraExplain_initCommonInfo(zei, node_tgtinfo);
521             zebraExplain_initAccessInfo(zei, node_tgtinfo);
522
523             /* write now because we want to be sure about the sysno */
524             trec = rec_new(records);
525             if (!trec)
526             {
527                 yaz_log(YLOG_FATAL, "Cannot create root Explain record");
528                 nmem_destroy(zei->nmem);
529                 return 0;
530             }
531             trec->info[recInfo_fileType] =
532                 rec_strdup("grs.sgml", &trec->size[recInfo_fileType]);
533             trec->info[recInfo_databaseName] =
534                 rec_strdup("IR-Explain-1", &trec->size[recInfo_databaseName]);
535             
536             sgml_buf = data1_nodetoidsgml(dh, zei->data1_target, 0, &sgml_len);
537             trec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
538             memcpy(trec->info[recInfo_storeData], sgml_buf, sgml_len);
539             trec->size[recInfo_storeData] = sgml_len;
540                 
541             rec_put(records, &trec);
542             rec_rm(&trec);
543         }
544         
545         zebraExplain_newDatabase(zei, "IR-Explain-1", 0);
546             
547         if (!zei->categoryList->dirty)
548         {
549             struct zebraCategoryListInfo *zcl = zei->categoryList;
550             data1_node *node_cl;
551             
552             zcl->dirty = 1;
553             zcl->data1_categoryList =
554                 data1_read_sgml(zei->dh, zei->nmem,
555                                  "<explain><categoryList>CategoryList\n"
556                                  "</></>\n");
557         
558             if (zcl->data1_categoryList)
559             {
560                 node_cl = data1_search_tag(zei->dh, zcl->data1_categoryList,
561                                             "/categoryList");
562                 assert(node_cl);
563                 zebraExplain_initCommonInfo(zei, node_cl);
564             }
565         }
566     }
567     return zei;
568 }
569
570 static void zebraExplain_readAttributeDetails(ZebraExplainInfo zei,
571                                                zebAttributeDetails zad)
572 {
573     Record rec;
574     struct zebSUInfoB **zsuip = &zad->SUInfo;
575     data1_node *node_adinfo, *node_zebra, *node_list, *np;
576
577     assert (zad->sysno);
578     rec = rec_get(zei->records, zad->sysno);
579
580     zad->data1_tree = read_sgml_rec(zei->dh, zei->nmem, rec);
581
582     node_adinfo = data1_search_tag(zei->dh, zad->data1_tree,
583                                     "/attributeDetails");
584     node_zebra = data1_search_tag(zei->dh, node_adinfo->child,
585                                  "zebraInfo");
586     node_list = data1_search_tag(zei->dh, node_zebra->child,
587                                   "attrlist");
588     for (np = node_list->child; np; np = np->next)
589     {
590         data1_node *node_str = NULL;
591         data1_node *node_ordinal = NULL;
592         data1_node *node_type = NULL;
593         data1_node *node_doc_occurrences = NULL;
594         data1_node *node_term_occurrences = NULL;
595         data1_node *np2;
596
597         if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "attr"))
598             continue;
599         for (np2 = np->child; np2; np2 = np2->next)
600         {
601             if (np2->which != DATA1N_tag || !np2->child ||
602                 np2->child->which != DATA1N_data)
603                 continue;
604             if (!strcmp(np2->u.tag.tag, "str"))
605                 node_str = np2->child;
606             else if (!strcmp(np2->u.tag.tag, "ordinal"))
607                 node_ordinal = np2->child;
608             else if (!strcmp(np2->u.tag.tag, "type"))
609                 node_type = np2->child;
610             else if (!strcmp(np2->u.tag.tag, "dococcurrences"))
611                 node_doc_occurrences = np2->child;
612             else if (!strcmp(np2->u.tag.tag, "termoccurrences"))
613                 node_term_occurrences = np2->child;
614             else
615             {
616                 yaz_log(YLOG_LOG, "Unknown tag '%s' in attributeDetails",
617                         np2->u.tag.tag);
618             }
619         }
620         assert(node_ordinal);
621
622         *zsuip = (struct zebSUInfoB *)
623             nmem_malloc(zei->nmem, sizeof(**zsuip));
624
625         if (node_type && node_type->u.data.len > 0)
626             (*zsuip)->info.index_type =  node_type->u.data.data[0];
627         else
628         {
629             yaz_log(YLOG_WARN, "Missing attribute 'type' in attribute info");
630             (*zsuip)->info.index_type = 'w';
631         }
632
633         if (node_doc_occurrences)
634         {
635             data1_node *np = node_doc_occurrences;
636             (*zsuip)->info.doc_occurrences = atoi_zn(np->u.data.data,
637                                                      np->u.data.len);
638         }
639         if (node_term_occurrences)
640         {
641             data1_node *np = node_term_occurrences;
642             (*zsuip)->info.term_occurrences = atoi_zn(np->u.data.data,
643                                                       np->u.data.len);
644         }
645         if (node_str)
646         {
647             (*zsuip)->info.which = ZEB_SU_STR;
648             
649             (*zsuip)->info.u.str = nmem_strdupn(zei->nmem,
650                                                 node_str->u.data.data,
651                                                 node_str->u.data.len);
652         }
653         else
654         {
655             yaz_log(YLOG_WARN, "Missing set/use/str in attribute info");
656             continue;
657         }
658         (*zsuip)->info.ordinal = atoi_n (node_ordinal->u.data.data,
659                                          node_ordinal->u.data.len);
660         zsuip = &(*zsuip)->next;
661     }
662     *zsuip = NULL;
663     zad->readFlag = 0;
664     rec_rm (&rec);
665 }
666
667 static void zebraExplain_readDatabase (ZebraExplainInfo zei,
668                                        struct zebDatabaseInfoB *zdi)
669 {
670     Record rec;
671     data1_node *node_dbinfo, *node_zebra, *np;
672
673     assert (zdi->sysno);
674     rec = rec_get (zei->records, zdi->sysno);
675
676     zdi->data1_database = read_sgml_rec (zei->dh, zei->nmem, rec);
677     
678     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
679                                     "/databaseInfo");
680     assert (node_dbinfo);
681     zebraExplain_mergeAccessInfo (zei, node_dbinfo, &zdi->accessInfo);
682
683     node_zebra = data1_search_tag (zei->dh, node_dbinfo->child,
684                                  "zebraInfo");
685     if (node_zebra
686         && (np = data1_search_tag (zei->dh, node_zebra->child,
687                                    "recordBytes")) 
688         && np->child && np->child->which == DATA1N_data)
689         zdi->recordBytes = atoi_zn (np->child->u.data.data,
690                                     np->child->u.data.len);
691
692     if (node_zebra
693         && (np = data1_search_tag (zei->dh, node_zebra->child,
694                                    "ordinalDatabase")) 
695         && np->child && np->child->which == DATA1N_data)
696         zdi->ordinalDatabase = atoi_n(np->child->u.data.data,
697                                       np->child->u.data.len);
698
699     if ((np = data1_search_tag (zei->dh, node_dbinfo->child,
700                                 "recordCount")) &&
701         (np = data1_search_tag (zei->dh, np->child,
702                                 "recordCountActual")) &&
703         np->child->which == DATA1N_data)
704     {
705         zdi->recordCount = atoi_zn (np->child->u.data.data,
706                                     np->child->u.data.len);
707     }
708     zdi->readFlag = 0;
709     rec_rm (&rec);
710 }
711
712 int zebraExplain_removeDatabase(ZebraExplainInfo zei, void *update_handle)
713 {
714     struct zebDatabaseInfoB **zdip = &zei->databaseInfo;
715
716     while (*zdip)
717     {
718         if (*zdip == zei->curDatabaseInfo)
719         {
720             struct zebDatabaseInfoB *zdi = *zdip;
721             Record rec;
722
723             zei->dirty = 1;
724             zei->updateHandle = update_handle;
725
726             if (zdi->attributeDetails)
727             {
728                 /* remove attribute details keys and delete it */
729                 zebAttributeDetails zad = zdi->attributeDetails;
730                 
731                 rec = rec_get(zei->records, zad->sysno);
732                 (*zei->updateFunc)(zei->updateHandle, rec, 0);
733                 rec_rm(&rec);
734             }
735             /* remove database record keys and delete it */
736             rec = rec_get (zei->records, zdi->sysno);
737             (*zei->updateFunc)(zei->updateHandle, rec, 0);
738             rec_rm(&rec);
739
740             /* remove from list */
741             *zdip = zdi->next;
742
743             /* current database is IR-Explain-1 */
744             return 0;
745         }
746         zdip = &(*zdip)->next;
747     }
748     return -1;
749 }
750
751 int zebraExplain_curDatabase (ZebraExplainInfo zei, const char *database)
752 {
753     struct zebDatabaseInfoB *zdi;
754     const char *database_n = strrchr (database, '/');
755
756     if (database_n)
757         database_n++;
758     else
759         database_n = database;
760     
761     assert (zei);
762     if (zei->curDatabaseInfo &&
763         !STRCASECMP (zei->curDatabaseInfo->databaseName, database))
764         return 0;
765     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
766     {
767         if (!STRCASECMP (zdi->databaseName, database_n))
768             break;
769     }
770     if (!zdi)
771         return -1;
772 #if ZINFO_DEBUG
773     yaz_log(YLOG_LOG, "zebraExplain_curDatabase: %s", database);
774 #endif
775     if (zdi->readFlag)
776     {
777 #if ZINFO_DEBUG
778         yaz_log(YLOG_LOG, "zebraExplain_readDatabase: %s", database);
779 #endif
780         zebraExplain_readDatabase (zei, zdi);
781     }
782     if (zdi->attributeDetails->readFlag)
783     {
784 #if ZINFO_DEBUG
785         yaz_log(YLOG_LOG, "zebraExplain_readAttributeDetails: %s", database);
786 #endif
787         zebraExplain_readAttributeDetails (zei, zdi->attributeDetails);
788     }
789     zei->curDatabaseInfo = zdi;
790     return 0;
791 }
792
793 static void zebraExplain_initCommonInfo (ZebraExplainInfo zei, data1_node *n)
794 {
795     data1_node *c = data1_mk_tag (zei->dh, zei->nmem, "commonInfo", 0, n);
796     data1_mk_tag_data_text (zei->dh, c, "dateAdded", zei->date, zei->nmem);
797     data1_mk_tag_data_text (zei->dh, c, "dateChanged", zei->date, zei->nmem);
798     data1_mk_tag_data_text (zei->dh, c, "languageCode", "EN", zei->nmem);
799 }
800
801 static void zebraExplain_updateCommonInfo (ZebraExplainInfo zei, data1_node *n)
802 {
803     data1_node *c = data1_search_tag (zei->dh, n->child, "commonInfo");
804     assert (c);
805     data1_mk_tag_data_text_uni (zei->dh, c, "dateChanged", zei->date,
806                                 zei->nmem);
807 }
808
809 static void zebraExplain_initAccessInfo (ZebraExplainInfo zei, data1_node *n)
810 {
811     data1_node *c = data1_mk_tag (zei->dh, zei->nmem, "accessInfo", 0, n);
812     data1_node *d = data1_mk_tag (zei->dh, zei->nmem, "unitSystems", 0, c);
813     data1_mk_tag_data_text (zei->dh, d, "string", "ISO", zei->nmem);
814 }
815
816 static void zebraExplain_updateAccessInfo (ZebraExplainInfo zei, data1_node *n,
817                                            zebAccessInfo accessInfo)
818 {
819     data1_node *c = data1_search_tag (zei->dh, n->child, "accessInfo");
820     data1_node *d;
821     zebAccessObject p;
822     
823     if (!c)
824     {
825         data1_pr_tree (zei->dh, n, stdout);
826         exit (0);
827         assert (c);
828     }
829
830     if ((p = accessInfo->attributeSetIds))
831     {
832         d = data1_mk_tag_uni (zei->dh, zei->nmem, "attributeSetIds", c);
833         for (; p; p = p->next)
834             data1_mk_tag_data_oid (zei->dh, d, "oid", p->oid, zei->nmem);
835     }
836     if ((p = accessInfo->schemas))
837     {
838         d = data1_mk_tag_uni (zei->dh, zei->nmem, "schemas", c);
839         for (; p; p = p->next)
840             data1_mk_tag_data_oid (zei->dh, d, "oid", p->oid, zei->nmem);
841     }
842 }
843
844 int zebraExplain_newDatabase (ZebraExplainInfo zei, const char *database,
845                               int explain_database)
846 {
847     struct zebDatabaseInfoB *zdi;
848     data1_node *node_dbinfo, *node_adinfo;
849     const char *database_n = strrchr (database, '/');
850
851     if (database_n)
852         database_n++;
853     else
854         database_n = database;
855
856 #if ZINFO_DEBUG
857     yaz_log(YLOG_LOG, "zebraExplain_newDatabase: %s", database);
858 #endif
859     assert (zei);
860     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
861     {
862         if (!STRCASECMP (zdi->databaseName, database_n))
863             break;
864     }
865     if (zdi)
866         return -1;
867     /* it's new really. make it */
868     zdi = (struct zebDatabaseInfoB *) nmem_malloc (zei->nmem, sizeof(*zdi));
869     zdi->next = zei->databaseInfo;
870     zei->databaseInfo = zdi;
871     zdi->sysno = 0;
872     zdi->recordCount = 0;
873     zdi->recordBytes = 0;
874     zdi->readFlag = 0;
875     zdi->databaseName = nmem_strdup (zei->nmem, database_n);
876
877     zdi->ordinalDatabase = zei->ordinalDatabase++;
878
879     zebraExplain_mergeAccessInfo (zei, 0, &zdi->accessInfo);
880     
881     assert (zei->dh);
882     assert (zei->nmem);
883
884     zdi->data1_database =
885         data1_read_sgml (zei->dh, zei->nmem, 
886                          "<explain><databaseInfo>DatabaseInfo\n"
887                          "</></>\n");
888     if (!zdi->data1_database)
889         return -2;
890
891     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
892                                     "/databaseInfo");
893     assert (node_dbinfo);
894
895     zebraExplain_initCommonInfo (zei, node_dbinfo);
896     zebraExplain_initAccessInfo (zei, node_dbinfo);
897
898     data1_mk_tag_data_text (zei->dh, node_dbinfo, "name",
899                                database, zei->nmem);
900     
901     if (explain_database)
902         data1_mk_tag_data_text (zei->dh, node_dbinfo, "explainDatabase",
903                                 "", zei->nmem);
904     
905     data1_mk_tag_data_text (zei->dh, node_dbinfo, "userFee",
906                             "0", zei->nmem);
907     
908     data1_mk_tag_data_text (zei->dh, node_dbinfo, "available",
909                             "1", zei->nmem);
910     
911 #if ZINFO_DEBUG
912     data1_pr_tree (zei->dh, zdi->data1_database, stderr);
913 #endif
914     zdi->dirty = 1;
915     zei->dirty = 1;
916     zei->curDatabaseInfo = zdi;
917
918     zdi->attributeDetails = (zebAttributeDetails)
919         nmem_malloc (zei->nmem, sizeof(*zdi->attributeDetails));
920     zdi->attributeDetails->readFlag = 0;
921     zdi->attributeDetails->sysno = 0;
922     zdi->attributeDetails->dirty = 1;
923     zdi->attributeDetails->SUInfo = NULL;
924     zdi->attributeDetails->data1_tree =
925         data1_read_sgml (zei->dh, zei->nmem,
926                          "<explain><attributeDetails>AttributeDetails\n"
927                          "</></>\n");
928
929     node_adinfo = data1_search_tag (zei->dh, zdi->attributeDetails->data1_tree,
930                                     "/attributeDetails");
931     assert (node_adinfo);
932
933     zebraExplain_initCommonInfo (zei, node_adinfo);
934
935     return 0;
936 }
937
938
939 static void zebraExplain_writeCategoryList (ZebraExplainInfo zei,
940                                             struct zebraCategoryListInfo *zcl,
941                                             int key_flush)
942 {
943     char *sgml_buf;
944     int sgml_len;
945     int i;
946     Record drec;
947     data1_node *node_ci, *node_categoryList;
948     SYSNO sysno = 0;
949     static char *category[] = {
950         "CategoryList",
951         "TargetInfo",
952         "DatabaseInfo",
953         "AttributeDetails",
954         NULL
955     };
956
957     assert (zcl);
958     if (!zcl->dirty)
959         return ;
960     zcl->dirty = 1;
961     node_categoryList = zcl->data1_categoryList;
962
963 #if ZINFO_DEBUG
964     yaz_log(YLOG_LOG, "zebraExplain_writeCategoryList");
965 #endif
966
967     drec = createRecord (zei->records, &sysno);
968     if (!drec)
969         return;
970     
971     node_ci = data1_search_tag (zei->dh, node_categoryList,
972                                 "/categoryList");
973     assert (node_ci);
974     node_ci = data1_mk_tag (zei->dh, zei->nmem, "categories", 0 /* attr */,
975                             node_ci);
976     assert (node_ci);
977     
978     for (i = 0; category[i]; i++)
979     {
980         data1_node *node_cat = data1_mk_tag (zei->dh, zei->nmem,  "category",
981                                              0 /* attr */, node_ci);
982
983         data1_mk_tag_data_text (zei->dh, node_cat, "name",
984                                 category[i], zei->nmem);
985     }
986     /* extract *searchable* keys from it. We do this here, because
987        record count, etc. is affected */
988     if (key_flush)
989         (*zei->updateFunc)(zei->updateHandle, drec, node_categoryList);
990
991     /* convert to "SGML" and write it */
992 #if ZINFO_DEBUG
993     data1_pr_tree (zei->dh, node_categoryList, stderr);
994 #endif
995     sgml_buf = data1_nodetoidsgml(zei->dh, node_categoryList, 0, &sgml_len);
996     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
997     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
998     drec->size[recInfo_storeData] = sgml_len;
999     
1000     rec_put (zei->records, &drec);
1001 }
1002
1003 static void zebraExplain_writeAttributeDetails (ZebraExplainInfo zei,
1004                                                 zebAttributeDetails zad,
1005                                                 const char *databaseName,
1006                                                 int key_flush)
1007 {
1008     char *sgml_buf;
1009     int sgml_len;
1010     Record drec;
1011     data1_node *node_adinfo, *node_list, *node_zebra;
1012     struct zebSUInfoB *zsui;
1013     
1014     if (!zad->dirty)
1015         return;
1016     
1017     zad->dirty = 0;
1018 #if ZINFO_DEBUG
1019     yaz_log(YLOG_LOG, "zebraExplain_writeAttributeDetails");    
1020 #endif
1021
1022     drec = createRecord (zei->records, &zad->sysno);
1023     if (!drec)
1024         return;
1025     assert (zad->data1_tree);
1026
1027     node_adinfo = data1_search_tag (zei->dh, zad->data1_tree,
1028                                    "/attributeDetails");
1029     zebraExplain_updateCommonInfo (zei, node_adinfo);
1030
1031     data1_mk_tag_data_text (zei->dh, node_adinfo, "name",
1032                             databaseName, zei->nmem);
1033
1034     /* extract *searchable* keys from it. We do this here, because
1035        record count, etc. is affected */
1036     if (key_flush)
1037         (*zei->updateFunc)(zei->updateHandle, drec, zad->data1_tree);
1038     /* zebra info (private) */
1039     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1040                                  "zebraInfo", node_adinfo);
1041     node_list = data1_mk_tag_uni (zei->dh, zei->nmem,
1042                                  "attrlist", node_zebra);
1043     for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
1044     {
1045         data1_node *node_attr;
1046         char index_type_str[2];
1047         
1048         node_attr = data1_mk_tag (zei->dh, zei->nmem, "attr", 0 /* attr */,
1049                                   node_list);
1050
1051         index_type_str[0] = zsui->info.index_type;
1052         index_type_str[1] = '\0';
1053         data1_mk_tag_data_text (zei->dh, node_attr, "type",
1054                                 index_type_str, zei->nmem);
1055         if (zsui->info.which == ZEB_SU_STR)
1056         {
1057             data1_mk_tag_data_text (zei->dh, node_attr, "str",
1058                                     zsui->info.u.str, zei->nmem);
1059         }
1060         data1_mk_tag_data_int (zei->dh, node_attr, "ordinal",
1061                                zsui->info.ordinal, zei->nmem);
1062
1063         data1_mk_tag_data_zint (zei->dh, node_attr, "dococcurrences",
1064                                 zsui->info.doc_occurrences, zei->nmem);
1065         data1_mk_tag_data_zint (zei->dh, node_attr, "termoccurrences",
1066                                 zsui->info.term_occurrences, zei->nmem);
1067     }
1068     /* convert to "SGML" and write it */
1069 #if ZINFO_DEBUG
1070     data1_pr_tree (zei->dh, zad->data1_tree, stderr);
1071 #endif
1072     sgml_buf = data1_nodetoidsgml(zei->dh, zad->data1_tree,
1073                                   0, &sgml_len);
1074     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1075     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1076     drec->size[recInfo_storeData] = sgml_len;
1077     
1078     rec_put (zei->records, &drec);
1079 }
1080
1081 static void zebraExplain_writeDatabase (ZebraExplainInfo zei,
1082                                         struct zebDatabaseInfoB *zdi,
1083                                         int key_flush)
1084 {
1085     char *sgml_buf;
1086     int sgml_len;
1087     Record drec;
1088     data1_node *node_dbinfo, *node_count, *node_zebra;
1089     
1090     if (!zdi->dirty)
1091         return;
1092
1093     zdi->dirty = 0;
1094 #if ZINFO_DEBUG
1095     yaz_log(YLOG_LOG, "zebraExplain_writeDatabase %s", zdi->databaseName);
1096 #endif
1097     drec = createRecord (zei->records, &zdi->sysno);
1098     if (!drec)
1099         return;
1100     assert (zdi->data1_database);
1101
1102     node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database,
1103                                     "/databaseInfo");
1104
1105     assert (node_dbinfo);
1106     zebraExplain_updateCommonInfo (zei, node_dbinfo);
1107     zebraExplain_updateAccessInfo (zei, node_dbinfo, zdi->accessInfo);
1108
1109     /* extract *searchable* keys from it. We do this here, because
1110        record count, etc. is affected */
1111     if (key_flush)
1112         (*zei->updateFunc)(zei->updateHandle, drec, zdi->data1_database);
1113     /* record count */
1114     node_count = data1_mk_tag_uni (zei->dh, zei->nmem,
1115                                  "recordCount", node_dbinfo);
1116     data1_mk_tag_data_zint (zei->dh, node_count, "recordCountActual",
1117                             zdi->recordCount, zei->nmem);
1118
1119     /* zebra info (private) */
1120     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1121                                  "zebraInfo", node_dbinfo);
1122     data1_mk_tag_data_zint (zei->dh, node_zebra,
1123                            "recordBytes", zdi->recordBytes, zei->nmem);
1124
1125     data1_mk_tag_data_zint(zei->dh, node_zebra,
1126                            "ordinalDatabase", zdi->ordinalDatabase, zei->nmem);
1127
1128     /* convert to "SGML" and write it */
1129 #if ZINFO_DEBUG
1130     data1_pr_tree (zei->dh, zdi->data1_database, stderr);
1131 #endif
1132     sgml_buf = data1_nodetoidsgml(zei->dh, zdi->data1_database,
1133                                   0, &sgml_len);
1134     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1135     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1136     drec->size[recInfo_storeData] = sgml_len;
1137     
1138     rec_put (zei->records, &drec);
1139 }
1140
1141 static void writeAttributeValues (ZebraExplainInfo zei,
1142                                   data1_node *node_values,
1143                                   data1_attset *attset)
1144 {
1145     data1_att *atts;
1146     data1_attset_child *c;
1147
1148     if (!attset)
1149         return;
1150
1151     for (c = attset->children; c; c = c->next)
1152         writeAttributeValues (zei, node_values, c->child);
1153     for (atts = attset->atts; atts; atts = atts->next)
1154     {
1155         data1_node *node_value;
1156         
1157         node_value = data1_mk_tag (zei->dh, zei->nmem, "attributeValue",
1158                                    0 /* attr */, node_values);
1159         data1_mk_tag_data_text (zei->dh, node_value, "name",
1160                                 atts->name, zei->nmem);
1161         node_value = data1_mk_tag (zei->dh, zei->nmem, "value",
1162                                    0 /* attr */, node_value);
1163         data1_mk_tag_data_int (zei->dh, node_value, "numeric",
1164                                atts->value, zei->nmem);
1165     }
1166 }
1167
1168
1169 static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
1170                                             zebAccessObject o,
1171                                             int key_flush)
1172 {
1173     char *sgml_buf;
1174     int sgml_len;
1175     Record drec;
1176     data1_node *node_root, *node_attinfo, *node_attributes, *node_atttype;
1177     data1_node *node_values;
1178     struct oident *entp;
1179     struct data1_attset *attset = NULL;
1180     
1181     if ((entp = oid_getentbyoid (o->oid)))
1182         attset = data1_attset_search_id (zei->dh, entp->value);
1183             
1184 #if ZINFO_DEBUG
1185     yaz_log(YLOG_LOG, "zebraExplain_writeAttributeSet %s",
1186           attset ? attset->name : "<unknown>");    
1187 #endif
1188
1189     drec = createRecord (zei->records, &o->sysno);
1190     if (!drec)
1191         return;
1192     node_root =
1193         data1_read_sgml (zei->dh, zei->nmem,
1194                          "<explain><attributeSetInfo>AttributeSetInfo\n"
1195                          "</></>\n" );
1196
1197     node_attinfo = data1_search_tag (zei->dh, node_root,
1198                                    "/attributeSetInfo");
1199
1200     assert (node_attinfo);
1201     zebraExplain_initCommonInfo (zei, node_attinfo);
1202     zebraExplain_updateCommonInfo (zei, node_attinfo);
1203
1204     data1_mk_tag_data_oid (zei->dh, node_attinfo,
1205                             "oid", o->oid, zei->nmem);
1206     if (attset && attset->name)
1207         data1_mk_tag_data_text (zei->dh, node_attinfo,
1208                                 "name", attset->name, zei->nmem);
1209     
1210     node_attributes = data1_mk_tag_uni (zei->dh, zei->nmem,
1211                                       "attributes", node_attinfo);
1212     node_atttype = data1_mk_tag_uni (zei->dh, zei->nmem,
1213                                    "attributeType", node_attributes);
1214     data1_mk_tag_data_text (zei->dh, node_atttype,
1215                             "name", "Use", zei->nmem);
1216     data1_mk_tag_data_text (zei->dh, node_atttype,
1217                             "description", "Use Attribute", zei->nmem);
1218     data1_mk_tag_data_int (zei->dh, node_atttype,
1219                            "type", 1, zei->nmem);
1220     node_values = data1_mk_tag (zei->dh, zei->nmem,
1221                                 "attributeValues", 0 /* attr */, node_atttype);
1222     if (attset)
1223         writeAttributeValues (zei, node_values, attset);
1224
1225     /* extract *searchable* keys from it. We do this here, because
1226        record count, etc. is affected */
1227     if (key_flush)
1228         (*zei->updateFunc)(zei->updateHandle, drec, node_root);
1229     /* convert to "SGML" and write it */
1230 #if ZINFO_DEBUG
1231     data1_pr_tree (zei->dh, node_root, stderr);
1232 #endif
1233     sgml_buf = data1_nodetoidsgml(zei->dh, node_root, 0, &sgml_len);
1234     drec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1235     memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
1236     drec->size[recInfo_storeData] = sgml_len;
1237     
1238     rec_put (zei->records, &drec);
1239 }
1240
1241 static void zebraExplain_writeTarget (ZebraExplainInfo zei, int key_flush)
1242 {
1243     struct zebDatabaseInfoB *zdi;
1244     data1_node *node_tgtinfo, *node_list, *node_zebra;
1245     Record trec;
1246     int sgml_len;
1247     char *sgml_buf;
1248
1249     if (!zei->dirty)
1250         return;
1251     zei->dirty = 0;
1252
1253     trec = rec_get_root(zei->records);
1254     xfree (trec->info[recInfo_storeData]);
1255
1256     node_tgtinfo = data1_search_tag (zei->dh, zei->data1_target,
1257                                      "/targetInfo");
1258     assert (node_tgtinfo);
1259
1260     zebraExplain_updateCommonInfo (zei, node_tgtinfo);
1261     zebraExplain_updateAccessInfo (zei, node_tgtinfo, zei->accessInfo);
1262
1263     /* convert to "SGML" and write it */
1264     if (key_flush)
1265         (*zei->updateFunc)(zei->updateHandle, trec, zei->data1_target);
1266
1267     node_zebra = data1_mk_tag_uni (zei->dh, zei->nmem,
1268                                  "zebraInfo", node_tgtinfo);
1269     data1_mk_tag_data_text (zei->dh, node_zebra, "version",
1270                                ZEBRAVER, zei->nmem);
1271     node_list = data1_mk_tag (zei->dh, zei->nmem,
1272                               "databaseList", 0 /* attr */, node_zebra);
1273     for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
1274     {
1275         data1_node *node_db;
1276         node_db = data1_mk_tag (zei->dh, zei->nmem,
1277                                 "database", 0 /* attr */, node_list);
1278         data1_mk_tag_data_text (zei->dh, node_db, "name",
1279                                 zdi->databaseName, zei->nmem);
1280         data1_mk_tag_data_zint (zei->dh, node_db, "id",
1281                                 zdi->sysno, zei->nmem);
1282         data1_mk_tag_data_zint (zei->dh, node_db, "attributeDetailsId",
1283                                 zdi->attributeDetails->sysno, zei->nmem);
1284     }
1285     data1_mk_tag_data_int (zei->dh, node_zebra, "ordinalSU",
1286                            zei->ordinalSU, zei->nmem);
1287
1288     data1_mk_tag_data_int (zei->dh, node_zebra, "ordinalDatabase",
1289                            zei->ordinalDatabase, zei->nmem);
1290
1291     data1_mk_tag_data_zint (zei->dh, node_zebra, "runNumber",
1292                             zei->runNumber, zei->nmem);
1293
1294 #if ZINFO_DEBUG
1295     data1_pr_tree (zei->dh, zei->data1_target, stderr);
1296 #endif
1297     sgml_buf = data1_nodetoidsgml(zei->dh, zei->data1_target,
1298                                   0, &sgml_len);
1299     trec->info[recInfo_storeData] = (char *) xmalloc (sgml_len);
1300     memcpy (trec->info[recInfo_storeData], sgml_buf, sgml_len);
1301     trec->size[recInfo_storeData] = sgml_len;
1302     
1303     rec_put (zei->records, &trec);
1304 }
1305
1306 int zebraExplain_lookup_attr_str(ZebraExplainInfo zei, int index_type,
1307                                  const char *str)
1308 {
1309     struct zebSUInfoB **zsui;
1310
1311     assert (zei->curDatabaseInfo);
1312     for (zsui = &zei->curDatabaseInfo->attributeDetails->SUInfo;
1313          *zsui; zsui = &(*zsui)->next)
1314         if ((*zsui)->info.index_type == index_type
1315             && (*zsui)->info.which == ZEB_SU_STR 
1316             && !yaz_matchstr((*zsui)->info.u.str, str))
1317         {
1318             struct zebSUInfoB *zsui_this = *zsui;
1319
1320             /* take it out of the list and move to front */
1321             *zsui = (*zsui)->next;
1322             zsui_this->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
1323             zei->curDatabaseInfo->attributeDetails->SUInfo = zsui_this;
1324
1325             return zsui_this->info.ordinal;
1326         }
1327     return -1;
1328 }
1329
1330 int zebraExplain_trav_ord(ZebraExplainInfo zei, void *handle,
1331                           int (*f)(void *handle, int ord))
1332 {
1333     struct zebDatabaseInfoB *zdb = zei->curDatabaseInfo;
1334     if (zdb)
1335     {
1336         struct zebSUInfoB *zsui = zdb->attributeDetails->SUInfo;
1337         for ( ;zsui; zsui = zsui->next)
1338             (*f)(handle,  zsui->info.ordinal);
1339     }
1340     return 0;
1341 }
1342
1343
1344 struct zebSUInfoB *zebraExplain_get_sui_info (ZebraExplainInfo zei, int ord,
1345                                               int dirty_mark,
1346                                               const char **db)
1347 {
1348     struct zebDatabaseInfoB *zdb;
1349
1350     for (zdb = zei->databaseInfo; zdb; zdb = zdb->next)
1351     {
1352         struct zebSUInfoB **zsui;
1353
1354         if (zdb->attributeDetails->readFlag)
1355             zebraExplain_readAttributeDetails (zei, zdb->attributeDetails);
1356
1357         for (zsui = &zdb->attributeDetails->SUInfo; *zsui;
1358              zsui = &(*zsui)->next)
1359             if ((*zsui)->info.ordinal == ord)
1360             {
1361                 struct zebSUInfoB *zsui_this = *zsui;
1362                 
1363                 /* take it out of the list and move to front */
1364                 *zsui = (*zsui)->next;
1365                 zsui_this->next = zdb->attributeDetails->SUInfo;
1366                 zdb->attributeDetails->SUInfo = zsui_this;
1367
1368                 if (dirty_mark)
1369                     zdb->attributeDetails->dirty = 1;
1370                 if (db)
1371                     *db = zdb->databaseName;
1372                 return zsui_this;
1373             }
1374     }
1375     return 0;
1376 }
1377
1378
1379
1380 int zebraExplain_ord_adjust_occurrences(ZebraExplainInfo zei, int ord,
1381                                         int term_delta, int doc_delta)
1382 {
1383     struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 1, 0);
1384     if (zsui)
1385     {
1386         zsui->info.term_occurrences += term_delta;
1387         zsui->info.doc_occurrences += doc_delta;
1388         return 0;
1389     }
1390     return -1;
1391 }
1392
1393 int zebraExplain_ord_get_occurrences(ZebraExplainInfo zei, int ord,
1394                                      zint *term_occurrences,
1395                                      zint *doc_occurrences)
1396 {
1397     struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
1398     if (zsui)
1399     {
1400         *term_occurrences = zsui->info.term_occurrences;
1401         *doc_occurrences = zsui->info.doc_occurrences;
1402         return 0;
1403     }
1404     return -1;
1405 }
1406
1407 zint zebraExplain_ord_get_doc_occurrences(ZebraExplainInfo zei, int ord)
1408 {
1409     struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
1410     if (zsui)
1411         return zsui->info.doc_occurrences;
1412     return 0;
1413 }
1414
1415 zint zebraExplain_ord_get_term_occurrences(ZebraExplainInfo zei, int ord)
1416 {
1417     struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
1418     if (zsui)
1419         return zsui->info.term_occurrences;
1420     return 0;
1421 }
1422
1423 int zebraExplain_lookup_ord(ZebraExplainInfo zei, int ord,
1424                             int *index_type, 
1425                             const char **db,
1426                             const char **string_index)
1427 {
1428     struct zebSUInfoB *zsui;
1429
1430     if (index_type)
1431         *index_type = 0;
1432     if (string_index)
1433         *string_index = 0;
1434
1435     zsui = zebraExplain_get_sui_info(zei, ord, 0, db);
1436     if (zsui)
1437     {
1438         if (zsui->info.which == ZEB_SU_STR)
1439             if (string_index)
1440                 *string_index = zsui->info.u.str;
1441         if (index_type)
1442             *index_type = zsui->info.index_type;
1443         return 0;
1444     }
1445     return -1;
1446 }
1447
1448
1449
1450 zebAccessObject zebraExplain_announceOid (ZebraExplainInfo zei,
1451                                           zebAccessObject *op,
1452                                           Odr_oid *oid)
1453 {
1454     zebAccessObject ao;
1455     
1456     for (ao = *op; ao; ao = ao->next)
1457         if (!oid_oidcmp (oid, ao->oid))
1458             break;
1459     if (!ao)
1460     {
1461         ao = (zebAccessObject) nmem_malloc (zei->nmem, sizeof(*ao));
1462         ao->handle = NULL;
1463         ao->sysno = 0;
1464         ao->oid = odr_oiddup_nmem (zei->nmem, oid);
1465         ao->next = *op;
1466         *op = ao;
1467     }
1468     return ao;
1469 }
1470
1471 void zebraExplain_addAttributeSet (ZebraExplainInfo zei, int set)
1472 {
1473     oident oe;
1474     int oid[OID_SIZE];
1475
1476     oe.proto = PROTO_Z3950;
1477     oe.oclass = CLASS_ATTSET;
1478     oe.value = (enum oid_value) set;
1479
1480     if (oid_ent_to_oid (&oe, oid))
1481     {
1482         zebraExplain_announceOid (zei, &zei->accessInfo->attributeSetIds, oid);
1483         zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
1484                                   accessInfo->attributeSetIds, oid);
1485     }
1486 }
1487
1488 struct zebSUInfoB *zebraExplain_add_sui_info(ZebraExplainInfo zei,
1489                                              int index_type)
1490 {
1491     struct zebSUInfoB *zsui;
1492
1493     assert (zei->curDatabaseInfo);
1494     zsui = (struct zebSUInfoB *) nmem_malloc (zei->nmem, sizeof(*zsui));
1495     zsui->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
1496     zei->curDatabaseInfo->attributeDetails->SUInfo = zsui;
1497     zei->curDatabaseInfo->attributeDetails->dirty = 1;
1498     zei->dirty = 1;
1499     zsui->info.index_type = index_type;
1500     zsui->info.doc_occurrences = 0;
1501     zsui->info.term_occurrences = 0;
1502     zsui->info.ordinal = (zei->ordinalSU)++;
1503     return zsui;
1504 }
1505
1506 int zebraExplain_add_attr_str(ZebraExplainInfo zei, int index_type,
1507                               const char *index_name)
1508 {
1509     struct zebSUInfoB *zsui = zebraExplain_add_sui_info(zei, index_type);
1510
1511     zsui->info.which = ZEB_SU_STR;
1512     zsui->info.u.str = nmem_strdup(zei->nmem, index_name);
1513     return zsui->info.ordinal;
1514 }
1515
1516 void zebraExplain_addSchema (ZebraExplainInfo zei, Odr_oid *oid)
1517 {
1518     zebraExplain_announceOid (zei, &zei->accessInfo->schemas, oid);
1519     zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
1520                               accessInfo->schemas, oid);
1521 }
1522
1523 void zebraExplain_recordBytesIncrement (ZebraExplainInfo zei, int adjust_num)
1524 {
1525     assert (zei->curDatabaseInfo);
1526
1527     if (adjust_num)
1528     {
1529         zei->curDatabaseInfo->recordBytes += adjust_num;
1530         zei->curDatabaseInfo->dirty = 1;
1531     }
1532 }
1533
1534 void zebraExplain_recordCountIncrement (ZebraExplainInfo zei, int adjust_num)
1535 {
1536     assert (zei->curDatabaseInfo);
1537
1538     if (adjust_num)
1539     {
1540         zei->curDatabaseInfo->recordCount += adjust_num;
1541         zei->curDatabaseInfo->dirty = 1;
1542     }
1543 }
1544
1545 zint zebraExplain_runNumberIncrement (ZebraExplainInfo zei, int adjust_num)
1546 {
1547     if (adjust_num)
1548     {
1549         zei->dirty = 1;
1550     }
1551     return zei->runNumber += adjust_num;
1552 }
1553
1554 RecordAttr *rec_init_attr (ZebraExplainInfo zei, Record rec)
1555 {
1556     RecordAttr *recordAttr;
1557
1558     if (rec->info[recInfo_attr])
1559         return (RecordAttr *) rec->info[recInfo_attr];
1560     recordAttr = (RecordAttr *) xmalloc (sizeof(*recordAttr));
1561     rec->info[recInfo_attr] = (char *) recordAttr;
1562     rec->size[recInfo_attr] = sizeof(*recordAttr);
1563     
1564     recordAttr->recordSize = 0;
1565     recordAttr->recordOffset = 0;
1566     recordAttr->runNumber = zei->runNumber;
1567     recordAttr->staticrank = 0;
1568     return recordAttr;
1569 }
1570
1571 static void att_loadset(void *p, const char *n, const char *name)
1572 {
1573     data1_handle dh = (data1_handle) p;
1574     if (!data1_get_attset (dh, name))
1575         yaz_log(YLOG_WARN, "Directive attset failed for %s", name);
1576 }
1577
1578 int zebraExplain_get_database_ord(ZebraExplainInfo zei)
1579 {
1580     if (!zei->curDatabaseInfo)
1581         return -1;
1582     return zei->curDatabaseInfo->ordinalDatabase;
1583 }
1584
1585 void zebraExplain_loadAttsets (data1_handle dh, Res res)
1586 {
1587     res_trav(res, "attset", dh, att_loadset);
1588 }
1589
1590 /*
1591      zebraExplain_addSU adds to AttributeDetails for a database and
1592      adds attributeSet (in AccessInfo area) to DatabaseInfo if it doesn't
1593      exist for the database.
1594
1595      If the database doesn't exist globally (in TargetInfo) an 
1596      AttributeSetInfo must be added (globally).
1597  */
1598 /*
1599  * Local variables:
1600  * c-basic-offset: 4
1601  * indent-tabs-mode: nil
1602  * End:
1603  * vim: shiftwidth=4 tabstop=8 expandtab
1604  */
1605