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