Server produces diagnostic "Unsupported Attribute Set" when appropriate.
[idzebra-moved-to-github.git] / index / zrpn.c
1 /*
2  * Copyright (C) 1994-1997, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zrpn.c,v $
7  * Revision 1.69  1997-10-29 12:05:02  adam
8  * Server produces diagnostic "Unsupported Attribute Set" when appropriate.
9  *
10  * Revision 1.68  1997/10/27 14:33:06  adam
11  * Moved towards generic character mapping depending on "structure"
12  * field in abstract syntax file. Fixed a few memory leaks. Fixed
13  * bug with negative integers when doing searches with relational
14  * operators.
15  *
16  * Revision 1.67  1997/09/29 09:06:10  adam
17  * Removed one static var in order to make this module thread safe.
18  *
19  * Revision 1.66  1997/09/25 14:58:03  adam
20  * Windows NT port.
21  *
22  * Revision 1.65  1997/09/22 12:39:06  adam
23  * Added get_pos method for the ranked result sets.
24  *
25  * Revision 1.64  1997/09/18 08:59:20  adam
26  * Extra generic handle for the character mapping routines.
27  *
28  * Revision 1.63  1997/09/17 12:19:18  adam
29  * Zebra version corresponds to YAZ version 1.4.
30  * Changed Zebra server so that it doesn't depend on global common_resource.
31  *
32  * Revision 1.62  1997/09/05 15:30:09  adam
33  * Changed prototype for chr_map_input - added const.
34  * Added support for C++, headers uses extern "C" for public definitions.
35  *
36  * Revision 1.61  1997/02/10 10:21:14  adam
37  * Bug fix: in search terms character (^) wasn't observed.
38  *
39  * Revision 1.60  1997/01/31 11:10:34  adam
40  * Bug fix: Leading and trailing white space weren't removed in scan tokens.
41  *
42  * Revision 1.59  1997/01/17 11:31:46  adam
43  * Bug fix: complete phrase search didn't work.
44  *
45  * Revision 1.58  1996/12/23 15:30:45  adam
46  * Work on truncation.
47  * Bug fix: result sets weren't deleted after server shut down.
48  *
49  * Revision 1.57  1996/11/11 13:38:02  adam
50  * Added proximity support in search.
51  *
52  * Revision 1.56  1996/11/08 11:10:32  adam
53  * Buffers used during file match got bigger.
54  * Compressed ISAM support everywhere.
55  * Bug fixes regarding masking characters in queries.
56  * Redesigned Regexp-2 queries.
57  *
58  * Revision 1.55  1996/11/04 14:07:44  adam
59  * Moved truncation code to trunc.c.
60  *
61  * Revision 1.54  1996/10/29 14:09:52  adam
62  * Use of cisam system - enabled if setting isamc is 1.
63  *
64  * Revision 1.53  1996/06/26 09:21:43  adam
65  * Bug fix: local attribute set wasn't obeyed in scan.
66  *
67  * Revision 1.52  1996/06/17  14:26:20  adam
68  * Function gen_regular_rel changed to handle negative numbers.
69  *
70  * Revision 1.51  1996/06/11 10:54:15  quinn
71  * Relevance work
72  *
73  * Revision 1.50  1996/06/07  08:51:53  adam
74  * Bug fix: Character mapping was broken (introducued by last revision).
75  *
76  * Revision 1.49  1996/06/04  10:18:11  adam
77  * Search/scan uses character mapping module.
78  *
79  * Revision 1.48  1996/05/28  15:15:01  adam
80  * Bug fix: Didn't handle unknown database correctly.
81  *
82  * Revision 1.47  1996/05/15  18:36:28  adam
83  * Function trans_term transforms unsearchable characters to blanks.
84  *
85  * Revision 1.46  1996/05/15  11:57:56  adam
86  * Fixed bug introduced by set/field mapping in search operations.
87  *
88  * Revision 1.45  1996/05/14  11:34:00  adam
89  * Scan support in multiple registers/databases.
90  *
91  * Revision 1.44  1996/05/14  06:16:44  adam
92  * Compact use/set bytes used in search service.
93  *
94  * Revision 1.43  1996/05/09 09:54:43  adam
95  * Server supports maps from one logical attributes to a list of physical
96  * attributes.
97  * The extraction process doesn't make space consuming 'any' keys.
98  *
99  * Revision 1.42  1996/05/09  07:28:56  quinn
100  * Work towards phrases and multiple registers
101  *
102  * Revision 1.41  1996/03/20  09:36:43  adam
103  * Function dict_lookup_grep got extra parameter, init_pos, which marks
104  * from which position in pattern approximate pattern matching should occur.
105  * Approximate pattern matching is used in relevance=re-2.
106  *
107  * Revision 1.40  1996/02/02  13:44:44  adam
108  * The public dictionary functions simply use char instead of Dict_char
109  * to represent search strings. Dict_char is used internally only.
110  *
111  * Revision 1.39  1996/01/03  16:22:13  quinn
112  * operator->roperator
113  *
114  * Revision 1.38  1995/12/11  09:12:55  adam
115  * The rec_get function returns NULL if record doesn't exist - will
116  * happen in the server if the result set records have been deleted since
117  * the creation of the set (i.e. the search).
118  * The server saves a result temporarily if it is 'volatile', i.e. the
119  * set is register dependent.
120  *
121  * Revision 1.37  1995/12/06  15:05:28  adam
122  * More verbose in count_set.
123  *
124  * Revision 1.36  1995/12/06  12:41:27  adam
125  * New command 'stat' for the index program.
126  * Filenames can be read from stdin by specifying '-'.
127  * Bug fix/enhancement of the transformation from terms to regular
128  * expressons in the search engine.
129  *
130  * Revision 1.35  1995/11/27  09:29:00  adam
131  * Bug fixes regarding conversion to regular expressions.
132  *
133  * Revision 1.34  1995/11/16  17:00:56  adam
134  * Better logging of rpn query.
135  *
136  * Revision 1.33  1995/11/01  13:58:28  quinn
137  * Moving data1 to yaz/retrieval
138  *
139  * Revision 1.32  1995/10/27  14:00:11  adam
140  * Implemented detection of database availability.
141  *
142  * Revision 1.31  1995/10/17  18:02:10  adam
143  * New feature: databases. Implemented as prefix to words in dictionary.
144  *
145  * Revision 1.30  1995/10/16  09:32:38  adam
146  * More work on relational op.
147  *
148  * Revision 1.29  1995/10/13  16:01:49  adam
149  * Work on relations.
150  *
151  * Revision 1.28  1995/10/13  12:26:43  adam
152  * Optimization of truncation.
153  *
154  * Revision 1.27  1995/10/12  17:07:22  adam
155  * Truncation works.
156  *
157  * Revision 1.26  1995/10/12  12:40:54  adam
158  * Bug fixes in rpn_prox.
159  *
160  * Revision 1.25  1995/10/10  13:59:24  adam
161  * Function rset_open changed its wflag parameter to general flags.
162  *
163  * Revision 1.24  1995/10/09  16:18:37  adam
164  * Function dict_lookup_grep got extra client data parameter.
165  *
166  * Revision 1.23  1995/10/06  16:33:37  adam
167  * Use attribute mappings.
168  *
169  * Revision 1.22  1995/10/06  15:07:39  adam
170  * Structure 'local-number' handled.
171  *
172  * Revision 1.21  1995/10/06  13:52:06  adam
173  * Bug fixes. Handler may abort further scanning.
174  *
175  * Revision 1.20  1995/10/06  11:06:33  adam
176  * Scan entries include 'occurrences' now.
177  *
178  * Revision 1.19  1995/10/06  10:43:56  adam
179  * Scan added. 'occurrences' in scan entries not set yet.
180  *
181  * Revision 1.18  1995/10/04  16:57:20  adam
182  * Key input and merge sort in one pass.
183  *
184  * Revision 1.17  1995/10/04  12:55:17  adam
185  * Bug fix in ranked search. Use=Any keys inserted.
186  *
187  * Revision 1.16  1995/10/02  16:24:40  adam
188  * Use attribute actually used in search requests.
189  *
190  * Revision 1.15  1995/10/02  15:18:52  adam
191  * New member in recRetrieveCtrl: diagnostic.
192  *
193  * Revision 1.14  1995/09/28  12:10:32  adam
194  * Bug fixes. Field prefix used in queries.
195  *
196  * Revision 1.13  1995/09/18  14:17:50  adam
197  * Minor changes.
198  *
199  * Revision 1.12  1995/09/15  14:45:21  adam
200  * Retrieve control.
201  * Work on truncation.
202  *
203  * Revision 1.11  1995/09/14  11:53:27  adam
204  * First work on regular expressions/truncations.
205  *
206  * Revision 1.10  1995/09/11  15:23:26  adam
207  * More work on relevance search.
208  *
209  * Revision 1.9  1995/09/11  13:09:35  adam
210  * More work on relevance feedback.
211  *
212  * Revision 1.8  1995/09/08  14:52:27  adam
213  * Minor changes. Dictionary is lower case now.
214  *
215  * Revision 1.7  1995/09/07  13:58:36  adam
216  * New parameter: result-set file descriptor (RSFD) to support multiple
217  * positions within the same result-set.
218  * Boolean operators: and, or, not implemented.
219  * Result-set references.
220  *
221  * Revision 1.6  1995/09/06  16:11:18  adam
222  * Option: only one word key per file.
223  *
224  * Revision 1.5  1995/09/06  10:33:04  adam
225  * More work on present. Some log messages removed.
226  *
227  * Revision 1.4  1995/09/05  15:28:40  adam
228  * More work on search engine.
229  *
230  * Revision 1.3  1995/09/04  15:20:22  adam
231  * Minor changes.
232  *
233  * Revision 1.2  1995/09/04  12:33:43  adam
234  * Various cleanup. YAZ util used instead.
235  *
236  * Revision 1.1  1995/09/04  09:10:40  adam
237  * More work on index add/del/update.
238  * Merge sort implemented.
239  * Initial work on z39 server.
240  *
241  */
242 #include <stdio.h>
243 #include <assert.h>
244 #ifdef WINDOWS
245 #include <io.h>
246 #else
247 #include <unistd.h>
248 #endif
249 #include <ctype.h>
250
251 #include "zserver.h"
252
253 #include <charmap.h>
254 #include <rstemp.h>
255 #include <rsnull.h>
256 #include <rsbool.h>
257 #include <rsrel.h>
258
259 struct rpn_char_map_info {
260     ZebraMaps zm;
261     int reg_type;
262 };
263
264 static const char **rpn_char_map_handler (void *vp, const char **from, int len)
265 {
266     struct rpn_char_map_info *p = vp;
267     return zebra_maps_input (p->zm, p->reg_type, from, len);
268 }
269
270 static void rpn_char_map_prepare (ZServerInfo *zi, int reg_type,
271                                   struct rpn_char_map_info *map_info)
272 {
273     map_info->zm = zi->zebra_maps;
274     map_info->reg_type = reg_type;
275     dict_grep_cmap (zi->dict, map_info, rpn_char_map_handler);
276 }
277
278 typedef struct {
279     int type;
280     int major;
281     int minor;
282     Z_AttributesPlusTerm *zapt;
283 } AttrType;
284
285 static int attr_find (AttrType *src, oid_value *attributeSetP)
286 {
287     while (src->major < src->zapt->num_attributes)
288     {
289         Z_AttributeElement *element;
290
291         element = src->zapt->attributeList[src->major];
292         if (src->type == *element->attributeType)
293         {
294             switch (element->which) 
295             {
296             case Z_AttributeValue_numeric:
297                 ++(src->major);
298                 if (element->attributeSet && attributeSetP)
299                 {
300                     oident *attrset;
301
302                     attrset = oid_getentbyoid (element->attributeSet);
303                     *attributeSetP = attrset->value;
304                 }
305                 return *element->value.numeric;
306                 break;
307             case Z_AttributeValue_complex:
308                 if (src->minor >= element->value.complex->num_list ||
309                     element->value.complex->list[src->minor]->which !=  
310                     Z_StringOrNumeric_numeric)
311                     break;
312                 ++(src->minor);
313                 if (element->attributeSet && attributeSetP)
314                 {
315                     oident *attrset;
316
317                     attrset = oid_getentbyoid (element->attributeSet);
318                     *attributeSetP = attrset->value;
319                 }
320                 return *element->value.complex->list[src->minor-1]->u.numeric;
321             default:
322                 assert (0);
323             }
324         }
325         ++(src->major);
326     }
327     return -1;
328 }
329
330 static void attr_init (AttrType *src, Z_AttributesPlusTerm *zapt,
331                        int type)
332 {
333     src->zapt = zapt;
334     src->type = type;
335     src->major = 0;
336     src->minor = 0;
337 }
338
339 #define TERM_COUNT        
340        
341 struct grep_info {        
342 #ifdef TERM_COUNT        
343     int *term_no;        
344 #endif        
345     ISAM_P *isam_p_buf;        
346     int isam_p_size;        
347     int isam_p_indx;        
348 };        
349
350 static void add_isam_p (const char *info, struct grep_info *p)
351 {
352     if (p->isam_p_indx == p->isam_p_size)
353     {
354         ISAM_P *new_isam_p_buf;
355 #ifdef TERM_COUNT        
356         int *new_term_no;        
357 #endif        
358         
359         p->isam_p_size = 2*p->isam_p_size + 100;
360         new_isam_p_buf = xmalloc (sizeof(*new_isam_p_buf) *
361                                   p->isam_p_size);
362         if (p->isam_p_buf)
363         {
364             memcpy (new_isam_p_buf, p->isam_p_buf,
365                     p->isam_p_indx * sizeof(*p->isam_p_buf));
366             xfree (p->isam_p_buf);
367         }
368         p->isam_p_buf = new_isam_p_buf;
369
370 #ifdef TERM_COUNT
371         new_term_no = xmalloc (sizeof(*new_term_no) *
372                                   p->isam_p_size);
373         if (p->term_no)
374         {
375             memcpy (new_term_no, p->isam_p_buf,
376                     p->isam_p_indx * sizeof(*p->term_no));
377             xfree (p->term_no);
378         }
379         p->term_no = new_term_no;
380 #endif
381     }
382     assert (*info == sizeof(*p->isam_p_buf));
383     memcpy (p->isam_p_buf + p->isam_p_indx, info+1, sizeof(*p->isam_p_buf));
384     (p->isam_p_indx)++;
385 }
386
387 static int grep_handle (char *name, const char *info, void *p)
388 {
389     add_isam_p (info, p);
390     return 0;
391 }
392
393 static int term_pre (ZebraMaps zebra_maps, int reg_type, const char **src,
394                      const char *ct1, const char *ct2)
395 {
396     const char *s1, *s0 = *src;
397     const char **map;
398
399     /* skip white space */
400     while (*s0)
401     {
402         if (ct1 && strchr (ct1, *s0))
403             break;
404         if (ct2 && strchr (ct2, *s0))
405             break;
406         s1 = s0;
407         map = zebra_maps_input (zebra_maps, reg_type, &s1, strlen(s1));
408         if (**map != *CHR_SPACE)
409             break;
410         s0 = s1;
411     }
412     *src = s0;
413     return *s0;
414 }
415
416 static int term_100 (ZebraMaps zebra_maps, int reg_type,
417                      const char **src, char *dst, int space_split)
418 {
419     const char *s0, *s1;
420     const char **map;
421     int i = 0;
422
423     if (!term_pre (zebra_maps, reg_type, src, NULL, NULL))
424         return 0;
425     s0 = *src;
426     while (*s0)
427     {
428         s1 = s0;
429         map = zebra_maps_input (zebra_maps, reg_type, &s0, strlen(s0));
430         if (space_split && **map == *CHR_SPACE)
431             break;
432         while (s1 < s0)
433         {
434             if (!isalnum (*s1) && *s1 != '-')
435                 dst[i++] = '\\';
436             dst[i++] = *s1++;
437         }
438     }
439     dst[i] = '\0';
440     *src = s0;
441     return i;
442 }
443
444 static int term_101 (ZebraMaps zebra_maps, int reg_type,
445                      const char **src, char *dst, int space_split)
446 {
447     const char *s0, *s1;
448     const char **map;
449     int i = 0;
450
451     if (!term_pre (zebra_maps, reg_type, src, "#", "#"))
452         return 0;
453     s0 = *src;
454     while (*s0)
455     {
456         if (*s0 == '#')
457         {
458             dst[i++] = '.';
459             dst[i++] = '*';
460             s0++;
461         }
462         else
463         {
464             s1 = s0;
465             map = zebra_maps_input (zebra_maps, reg_type, &s0, strlen(s0));
466             if (space_split && **map == *CHR_SPACE)
467                 break;
468             while (s1 < s0)
469             {
470                 if (!isalnum (*s1))
471                     dst[i++] = '\\';
472                 dst[i++] = *s1++;
473             }
474         }
475     }
476     dst[i] = '\0';
477     *src = s0;
478     return i;
479 }
480
481
482 static int term_103 (ZebraMaps zebra_maps, int reg_type, const char **src,
483                      char *dst, int *errors, int space_split)
484 {
485     int i = 0;
486     const char *s0, *s1;
487     const char **map;
488
489     if (!term_pre (zebra_maps, reg_type, src, "^\\()[].*+?|", "("))
490         return 0;
491     s0 = *src;
492     if (errors && *s0 == '+' && s0[1] && s0[2] == '+' && s0[3] &&
493         isdigit (s0[1]))
494     {
495         *errors = s0[1] - '0';
496         s0 += 3;
497         if (*errors > 3)
498             *errors = 3;
499     }
500     while (*s0)
501     {
502         if (strchr ("^\\()[].*+?|-", *s0))
503             dst[i++] = *s0++;
504         else
505         {
506             s1 = s0;
507             map = zebra_maps_input (zebra_maps, reg_type, &s0, strlen(s0));
508             if (**map == *CHR_SPACE)
509                 break;
510             while (s1 < s0)
511             {
512                 if (!isalnum (*s1))
513                     dst[i++] = '\\';
514                 dst[i++] = *s1++;
515             }
516         }
517     }
518     dst[i] = '\0';
519     *src = s0;
520     return i;
521 }
522
523 static int term_102 (ZebraMaps zebra_maps, int reg_type, const char **src,
524                      char *dst, int space_split)
525 {
526     return term_103 (zebra_maps, reg_type, src, dst, NULL, space_split);
527 }
528
529 /* gen_regular_rel - generate regular expression from relation
530  *  val:     border value (inclusive)
531  *  islt:    1 if <=; 0 if >=.
532  */
533 static void gen_regular_rel (char *dst, int val, int islt)
534 {
535     int dst_p;
536     int w, d, i;
537     int pos = 0;
538     char numstr[20];
539
540     logf (LOG_DEBUG, "gen_regular_rel. val=%d, islt=%d", val, islt);
541     if (val >= 0)
542     {
543         if (islt)
544             strcpy (dst, "(-[0-9]+|(");
545         else
546             strcpy (dst, "((");
547     } 
548     else
549     {
550         if (!islt)
551         {
552             strcpy (dst, "([0-9]+|-(");
553             dst_p = strlen (dst);
554             islt = 1;
555         }
556         else
557         {
558             strcpy (dst, "((-");
559             islt = 0;
560         }
561         val = -val;
562     }
563     dst_p = strlen (dst);
564     sprintf (numstr, "%d", val);
565     for (w = strlen(numstr); --w >= 0; pos++)
566     {
567         d = numstr[w];
568         if (pos > 0)
569         {
570             if (islt)
571             {
572                 if (d == '0')
573                     continue;
574                 d--;
575             } 
576             else
577             {
578                 if (d == '9')
579                     continue;
580                 d++;
581             }
582         }
583         
584         strcpy (dst + dst_p, numstr);
585         dst_p = strlen(dst) - pos - 1;
586
587         if (islt)
588         {
589             if (d != '0')
590             {
591                 dst[dst_p++] = '[';
592                 dst[dst_p++] = '0';
593                 dst[dst_p++] = '-';
594                 dst[dst_p++] = d;
595                 dst[dst_p++] = ']';
596             }
597             else
598                 dst[dst_p++] = d;
599         }
600         else
601         {
602             if (d != '9')
603             { 
604                 dst[dst_p++] = '[';
605                 dst[dst_p++] = d;
606                 dst[dst_p++] = '-';
607                 dst[dst_p++] = '9';
608                 dst[dst_p++] = ']';
609             }
610             else
611                 dst[dst_p++] = d;
612         }
613         for (i = 0; i<pos; i++)
614         {
615             dst[dst_p++] = '[';
616             dst[dst_p++] = '0';
617             dst[dst_p++] = '-';
618             dst[dst_p++] = '9';
619             dst[dst_p++] = ']';
620         }
621         dst[dst_p++] = '|';
622     }
623     dst[dst_p] = '\0';
624     if (islt)
625     {
626         for (i=1; i<pos; i++)
627             strcat (dst, "[0-9]?");
628     }
629     else
630     {
631         for (i = 0; i <= pos; i++)
632             strcat (dst, "[0-9]");
633         strcat (dst, "[0-9]*");
634     }
635     strcat (dst, "))");
636 }
637
638 static int relational_term (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
639                             const char **term_sub,
640                             char *term_dict,
641                             oid_value attributeSet,
642                             struct grep_info *grep_info,
643                             int *max_pos,
644                             int reg_type)
645 {
646     AttrType relation;
647     int relation_value;
648     int term_value;
649     int r;
650     char *term_tmp = term_dict + strlen(term_dict);
651
652     attr_init (&relation, zapt, 2);
653     relation_value = attr_find (&relation, NULL);
654
655     logf (LOG_DEBUG, "relation value=%d", relation_value);
656     switch (relation_value)
657     {
658     case 1:
659         if (!term_100 (zi->zebra_maps, reg_type, term_sub, term_tmp, 1))
660             return 0;
661         term_value = atoi (term_tmp);
662         logf (LOG_DEBUG, "Relation <");
663         gen_regular_rel (term_tmp, term_value-1, 1);
664         break;
665     case 2:
666         if (!term_100 (zi->zebra_maps, reg_type, term_sub, term_tmp, 1))
667             return 0;
668         term_value = atoi (term_tmp);
669         logf (LOG_DEBUG, "Relation <=");
670         gen_regular_rel (term_tmp, term_value, 1);
671         break;
672     case 4:
673         if (!term_100 (zi->zebra_maps, reg_type, term_sub, term_tmp, 1))
674             return 0;
675         term_value = atoi (term_tmp);
676         logf (LOG_DEBUG, "Relation >=");
677         gen_regular_rel (term_tmp, term_value, 0);
678         break;
679     case 5:
680         if (!term_100 (zi->zebra_maps, reg_type, term_sub, term_tmp, 1))
681             return 0;
682         term_value = atoi (term_tmp);
683         logf (LOG_DEBUG, "Relation >");
684         gen_regular_rel (term_tmp, term_value+1, 0);
685         break;
686     default:
687         return 0;
688     }
689     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
690     r = dict_lookup_grep (zi->dict, term_dict, 0, grep_info, max_pos,
691                           0, grep_handle);
692     if (r)
693         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
694     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
695     return 1;
696 }
697
698 static int field_term (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
699                        const char **term_sub, 
700                        oid_value attributeSet, struct grep_info *grep_info,
701                        int reg_type, int complete_flag,
702                        int num_bases, char **basenames)
703 {
704     char term_dict[2*IT_MAX_WORD+2];
705     int j, r, base_no;
706     AttrType truncation;
707     int truncation_value;
708     AttrType use;
709     int use_value;
710     oid_value curAttributeSet = attributeSet;
711     const char *termp;
712     struct rpn_char_map_info rcmi;
713     int space_split = complete_flag ? 0 : 1;
714
715     rpn_char_map_prepare (zi, reg_type, &rcmi);
716     attr_init (&use, zapt, 1);
717     use_value = attr_find (&use, &curAttributeSet);
718     logf (LOG_DEBUG, "field_term, use value %d", use_value);
719     attr_init (&truncation, zapt, 5);
720     truncation_value = attr_find (&truncation, NULL);
721     logf (LOG_DEBUG, "truncation value %d", truncation_value);
722
723     if (use_value == -1)
724         use_value = 1016;
725
726     for (base_no = 0; base_no < num_bases; base_no++)
727     {
728         attent attp;
729         data1_local_attribute *local_attr;
730         int max_pos, prefix_len = 0;
731
732         termp = *term_sub;
733         if ((r=att_getentbyatt (zi, &attp, curAttributeSet, use_value)))
734         {
735             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
736                   curAttributeSet, use_value, r);
737             if (r == -1)
738                 zi->errCode = 114;
739             else
740                 zi->errCode = 121;
741             return -1;
742         }
743         if (zebTargetInfo_curDatabase (zi->zti, basenames[base_no]))
744         {
745             zi->errCode = 109; /* Database unavailable */
746             zi->errString = basenames[base_no];
747             return -1;
748         }
749         for (local_attr = attp.local_attributes; local_attr;
750              local_attr = local_attr->next)
751         {
752             int ord;
753
754             ord = zebTargetInfo_lookupSU (zi->zti, attp.attset_ordinal,
755                                           local_attr->local);
756             if (ord < 0)
757                 continue;
758             if (prefix_len)
759                 term_dict[prefix_len++] = '|';
760             else
761                 term_dict[prefix_len++] = '(';
762             term_dict[prefix_len++] = 1;
763             term_dict[prefix_len++] = ord;
764         }
765         if (!prefix_len)
766         {
767             zi->errCode = 114;
768             return -1;
769         }
770         term_dict[prefix_len++] = ')';        
771         term_dict[prefix_len++] = 1;
772         term_dict[prefix_len++] = reg_type;
773         logf (LOG_LOG, "reg_type = %d", term_dict[prefix_len-1]);
774         term_dict[prefix_len] = '\0';
775         if (!relational_term (zi, zapt, &termp, term_dict,
776                               attributeSet, grep_info, &max_pos, reg_type))
777         {
778             j = prefix_len;
779             switch (truncation_value)
780             {
781             case -1:         /* not specified */
782             case 100:        /* do not truncate */
783                 term_dict[j++] = '(';   
784                 if (!term_100 (zi->zebra_maps, reg_type,
785                                &termp, term_dict + j, space_split))
786                     return 0;
787                 strcat (term_dict, ")");
788                 r = dict_lookup_grep (zi->dict, term_dict, 0, grep_info,
789                                       &max_pos, 0, grep_handle);
790                 if (r)
791                     logf (LOG_WARN, "dict_lookup_grep err, trunc=none:%d", r);
792                 break;
793             case 1:          /* right truncation */
794                 term_dict[j++] = '(';
795                 if (!term_100 (zi->zebra_maps, reg_type,
796                                &termp, term_dict + j, space_split))
797                     return 0;
798                 strcat (term_dict, ".*)");
799                 dict_lookup_grep (zi->dict, term_dict, 0, grep_info,
800                                   &max_pos, 0, grep_handle);
801                 break;
802             case 2:          /* left truncation */
803             case 3:          /* left&right truncation */
804                 zi->errCode = 120;
805                 return -1;
806             case 101:        /* process # in term */
807                 term_dict[j++] = '(';
808                 if (!term_101 (zi->zebra_maps, reg_type,
809                                &termp, term_dict + j, space_split))
810                     return 0;
811                 strcat (term_dict, ")");
812                 r = dict_lookup_grep (zi->dict, term_dict, 0, grep_info,
813                                       &max_pos, 0, grep_handle);
814                 if (r)
815                     logf (LOG_WARN, "dict_lookup_grep err, trunc=#: %d", r);
816                 break;
817             case 102:        /* Regexp-1 */
818                 term_dict[j++] = '(';
819                 if (!term_102 (zi->zebra_maps, reg_type,
820                                &termp, term_dict + j, space_split))
821                     return 0;
822                 strcat (term_dict, ")");
823                 logf (LOG_DEBUG, "Regexp-1 tolerance=%d", r);
824                 r = dict_lookup_grep (zi->dict, term_dict, 0, grep_info,
825                                       &max_pos, 0, grep_handle);
826                 if (r)
827                     logf (LOG_WARN, "dict_lookup_grep err, trunc=regular: %d",
828                           r);
829                 break;
830              case 103:       /* Regexp-2 */
831                 r = 1;
832                 term_dict[j++] = '(';
833                 if (!term_103 (zi->zebra_maps, reg_type,
834                                &termp, term_dict + j, &r, space_split))
835                     return 0;
836                 strcat (term_dict, ")");
837                 logf (LOG_DEBUG, "Regexp-2 tolerance=%d", r);
838                 r = dict_lookup_grep (zi->dict, term_dict, r, grep_info,
839                                       &max_pos, 2, grep_handle);
840                 if (r)
841                     logf (LOG_WARN, "dict_lookup_grep err, trunc=eregular: %d",
842                           r);
843                 break;
844             }
845         }
846     }
847     *term_sub = termp;
848     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
849     return 1;
850 }
851
852 static void trans_term (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
853                         char *termz)
854 {
855     size_t sizez;
856     Z_Term *term = zapt->term;
857
858     sizez = term->u.general->len;
859     if (sizez > IT_MAX_WORD-1)
860         sizez = IT_MAX_WORD-1;
861     memcpy (termz, term->u.general->buf, sizez);
862     termz[sizez] = '\0';
863 }
864
865 static void trans_scan_term (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
866                              char *termz, int reg_type)
867 {
868     Z_Term *term = zapt->term;
869     const char **map;
870     const char *cp = (const char *) term->u.general->buf;
871     const char *cp_end = cp + term->u.general->len;
872     const char *src;
873     int i = 0;
874     const char *space_map = NULL;
875     int len;
876     
877     while ((len = (cp_end - cp)) > 0)
878     {
879         map = zebra_maps_input (zi->zebra_maps, reg_type, &cp, len);
880         if (**map == *CHR_SPACE)
881             space_map = *map;
882         else
883         {
884             if (i && space_map)
885                 for (src = space_map; *src; src++)
886                     termz[i++] = *src;
887             space_map = NULL;
888             for (src = *map; *src; src++)
889                 termz[i++] = *src;
890         }
891     }
892     termz[i] = '\0';
893 }
894
895 static RSET rpn_search_APT_relevance (ZServerInfo *zi, 
896                                       Z_AttributesPlusTerm *zapt,
897                                       oid_value attributeSet,
898                                       int reg_type, int complete_flag,
899                                       int num_bases, char **basenames)
900 {
901     rset_relevance_parms parms;
902     char termz[IT_MAX_WORD+1];
903     const char *termp = termz;
904     struct grep_info grep_info;
905     RSET result;
906     int term_index = 0;
907     int r;
908
909     parms.key_size = sizeof(struct it_key);
910     parms.max_rec = 1000;
911     parms.cmp = key_compare_it;
912     parms.get_pos = key_get_pos;
913     parms.is = zi->isam;
914     parms.isc = zi->isamc;
915     parms.no_terms = 0;
916
917     if (zapt->term->which != Z_Term_general)
918     {
919         zi->errCode = 124;
920         return NULL;
921     }
922     trans_term (zi, zapt, termz);
923
924 #ifdef TERM_COUNT
925     grep_info.term_no = 0;
926 #endif
927     grep_info.isam_p_indx = 0;
928     grep_info.isam_p_size = 0;
929     grep_info.isam_p_buf = NULL;
930     while (1)
931     {
932         r = field_term (zi, zapt, &termp, attributeSet, &grep_info,
933                         reg_type, complete_flag, num_bases, basenames);
934         if (r <= 0)
935             break;
936 #ifdef TERM_COUNT
937         for (; term_index < grep_info.isam_p_indx; term_index++)
938             grep_info.term_no[term_index] = parms.no_terms;
939         parms.no_terms++;
940 #endif
941     }
942     parms.term_no = grep_info.term_no;
943     parms.isam_positions = grep_info.isam_p_buf;
944     parms.no_isam_positions = grep_info.isam_p_indx;
945     if (grep_info.isam_p_indx > 0)
946         result = rset_create (rset_kind_relevance, &parms);
947     else
948         result = rset_create (rset_kind_null, NULL);
949 #ifdef TERM_COUNT
950     xfree(grep_info.term_no);
951 #endif
952     xfree (grep_info.isam_p_buf);
953     return result;
954 }
955
956 static RSET rpn_proximity (ZServerInfo *zi, RSET rset1, RSET rset2,
957                            int ordered,
958                            int exclusion, int relation, int distance)
959 {
960     int i;
961     RSFD rsfd1, rsfd2;
962     int  more1, more2;
963     struct it_key buf1, buf2;
964     RSFD rsfd_result;
965     RSET result;
966     rset_temp_parms parms;
967     
968     rsfd1 = rset_open (rset1, RSETF_READ|RSETF_SORT_SYSNO);
969     more1 = rset_read (rset1, rsfd1, &buf1);
970     
971     rsfd2 = rset_open (rset2, RSETF_READ|RSETF_SORT_SYSNO);
972     more2 = rset_read (rset2, rsfd2, &buf2);
973
974     parms.key_size = sizeof (struct it_key);
975     parms.temp_path = res_get (zi->res, "setTmpDir");
976     result = rset_create (rset_kind_temp, &parms);
977     rsfd_result = rset_open (result, RSETF_WRITE|RSETF_SORT_SYSNO);
978    
979     logf (LOG_DEBUG, "rpn_proximity  excl=%d ord=%d rel=%d dis=%d",
980           exclusion, ordered, relation, distance);
981     while (more1 && more2)
982     {
983         int cmp = key_compare_it (&buf1, &buf2);
984         if (cmp < -1)
985             more1 = rset_read (rset1, rsfd1, &buf1);
986         else if (cmp > 1)
987             more2 = rset_read (rset2, rsfd2, &buf2);
988         else
989         {
990             int sysno = buf1.sysno;
991             int seqno[500];
992             int n = 0;
993
994             seqno[n++] = buf1.seqno;
995             while ((more1 = rset_read (rset1, rsfd1, &buf1)) &&
996                    sysno == buf1.sysno)
997                 if (n < 500)
998                     seqno[n++] = buf1.seqno;
999             do
1000             {
1001                 for (i = 0; i<n; i++)
1002                 {
1003                     int diff = buf2.seqno - seqno[i];
1004                     int excl = exclusion;
1005                     if (!ordered && diff < 0)
1006                         diff = -diff;
1007                     switch (relation)
1008                     {
1009                     case 1:      /* < */
1010                         if (diff < distance)
1011                             excl = !excl;
1012                         break;
1013                     case 2:      /* <= */
1014                         if (diff <= distance)
1015                             excl = !excl;
1016                         break;
1017                     case 3:      /* == */
1018                         if (diff == distance)
1019                             excl = !excl;
1020                         break;
1021                     case 4:      /* >= */
1022                         if (diff >= distance)
1023                             excl = !excl;
1024                         break;
1025                     case 5:      /* > */
1026                         if (diff > distance)
1027                             excl = !excl;
1028                         break;
1029                     case 6:      /* != */
1030                         if (diff != distance)
1031                             excl = !excl;
1032                         break;
1033                     }
1034                     if (excl)
1035                         rset_write (result, rsfd_result, &buf2);
1036                 }
1037             } while ((more2 = rset_read (rset2, rsfd2, &buf2)) &&
1038                       sysno == buf2.sysno);
1039         }
1040     }
1041     rset_close (result, rsfd_result);
1042     rset_close (rset1, rsfd1);
1043     rset_close (rset2, rsfd2);
1044     return result;
1045 }
1046
1047 static RSET rpn_prox (ZServerInfo *zi, RSET *rset, int rset_no)
1048 {
1049     int i;
1050     RSFD *rsfd;
1051     int  *more;
1052     struct it_key **buf;
1053     RSFD rsfd_result;
1054     RSET result;
1055     rset_temp_parms parms;
1056     
1057     rsfd = xmalloc (sizeof(*rsfd)*rset_no);
1058     more = xmalloc (sizeof(*more)*rset_no);
1059     buf = xmalloc (sizeof(*buf)*rset_no);
1060
1061     for (i = 0; i<rset_no; i++)
1062     {
1063         buf[i] = xmalloc (sizeof(**buf));
1064         rsfd[i] = rset_open (rset[i], RSETF_READ|RSETF_SORT_SYSNO);
1065         if (!(more[i] = rset_read (rset[i], rsfd[i], buf[i])))
1066         {
1067             while (i >= 0)
1068             {
1069                 rset_close (rset[i], rsfd[i]);
1070                 xfree (buf[i]);
1071                 --i;
1072             }
1073             xfree (rsfd);
1074             xfree (more);
1075             xfree (buf);
1076             return rset_create (rset_kind_null, NULL);
1077         }
1078     }
1079     parms.key_size = sizeof (struct it_key);
1080     parms.temp_path = res_get (zi->res, "setTmpDir");
1081     result = rset_create (rset_kind_temp, &parms);
1082     rsfd_result = rset_open (result, RSETF_WRITE|RSETF_SORT_SYSNO);
1083     
1084     while (*more)
1085     {
1086         for (i = 1; i<rset_no; i++)
1087         {
1088             int cmp;
1089             
1090             if (!more[i])
1091             {
1092                 *more = 0;
1093                 break;
1094             }
1095             cmp = key_compare_it (buf[i], buf[i-1]);
1096             if (cmp > 1)
1097             {
1098                 more[i-1] = rset_read (rset[i-1], rsfd[i-1], buf[i-1]);
1099                 break;
1100             }
1101             else if (cmp == 1)
1102             {
1103                 if (buf[i-1]->seqno+1 != buf[i]->seqno)
1104                 {
1105                     more[i-1] = rset_read (rset[i-1], rsfd[i-1], buf[i-1]);
1106                     break;
1107                 }
1108             }
1109             else
1110             {
1111                 more[i] = rset_read (rset[i], rsfd[i], buf[i]);
1112                 break;
1113             }
1114         }
1115         if (i == rset_no)
1116         {
1117             rset_write (result, rsfd_result, buf[0]);
1118             more[0] = rset_read (*rset, *rsfd, *buf);
1119         }
1120     }
1121     
1122     for (i = 0; i<rset_no; i++)
1123     {
1124         rset_close (rset[i], rsfd[i]);
1125         xfree (buf[i]);
1126     }
1127     rset_close (result, rsfd_result);
1128     xfree (buf);
1129     xfree (more);
1130     xfree (rsfd);
1131     return result;
1132 }
1133
1134 static RSET rpn_search_APT_phrase (ZServerInfo *zi,
1135                                    Z_AttributesPlusTerm *zapt,
1136                                    oid_value attributeSet,
1137                                    int reg_type, int complete_flag,
1138                                    int num_bases, char **basenames)
1139 {
1140     char termz[IT_MAX_WORD+1];
1141     const char *termp = termz;
1142     RSET rset[60], result;
1143     int i, r, rset_no = 0;
1144     struct grep_info grep_info;
1145
1146     if (zapt->term->which != Z_Term_general)
1147     {
1148         zi->errCode = 124;
1149         return NULL;
1150     }
1151     trans_term (zi, zapt, termz);
1152
1153 #ifdef TERM_COUNT
1154     grep_info.term_no = 0;
1155 #endif
1156     grep_info.isam_p_size = 0;
1157     grep_info.isam_p_buf = NULL;
1158
1159     while (1)
1160     { 
1161         logf (LOG_LOG, "APT_phrase termp=%s", termp);
1162         grep_info.isam_p_indx = 0;
1163         r = field_term (zi, zapt, &termp, attributeSet, &grep_info,
1164                         reg_type, complete_flag, num_bases, basenames);
1165         if (r < 1)
1166             break;
1167         rset[rset_no] = rset_trunc (zi, grep_info.isam_p_buf,
1168                                     grep_info.isam_p_indx);
1169         assert (rset[rset_no]);
1170         if (++rset_no >= sizeof(rset)/sizeof(*rset))
1171             break;
1172     }
1173 #ifdef TERM_COUNT
1174     xfree(grep_info.term_no);
1175 #endif
1176     xfree (grep_info.isam_p_buf);
1177     if (rset_no == 0)
1178         return rset_create (rset_kind_null, NULL);
1179     else if (rset_no == 1)
1180         return (rset[0]);
1181     result = rpn_prox (zi, rset, rset_no);
1182     for (i = 0; i<rset_no; i++)
1183         rset_delete (rset[i]);
1184     return result;
1185 }
1186
1187 static RSET rpn_search_APT_local (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
1188                                   oid_value attributeSet)
1189 {
1190     RSET result;
1191     RSFD rsfd;
1192     struct it_key key;
1193     rset_temp_parms parms;
1194     char termz[IT_MAX_WORD+1];
1195
1196     if (zapt->term->which != Z_Term_general)
1197     {
1198         zi->errCode = 124;
1199         return NULL;
1200     }
1201     parms.key_size = sizeof (struct it_key);
1202     parms.temp_path = res_get (zi->res, "setTmpDir");
1203     result = rset_create (rset_kind_temp, &parms);
1204     rsfd = rset_open (result, RSETF_WRITE|RSETF_SORT_SYSNO);
1205
1206     trans_term (zi, zapt, termz);
1207
1208     key.sysno = atoi (termz);
1209     if (key.sysno <= 0)
1210         key.sysno = 1;
1211     rset_write (result, rsfd, &key);
1212     rset_close (result, rsfd);
1213     return result;
1214 }
1215
1216 static RSET rpn_search_APT (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
1217                             oid_value attributeSet,
1218                             int num_bases, char **basenames)
1219 {
1220     int reg_type;
1221     char *search_type = NULL;
1222     int complete_flag;
1223
1224     zebra_maps_attr (zi->zebra_maps, zapt, &reg_type, &search_type,
1225                      &complete_flag);
1226     
1227     logf (LOG_DEBUG, "reg_type=%c", reg_type);
1228     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
1229     logf (LOG_DEBUG, "search_type=%s", search_type);
1230     if (!strcmp (search_type, "phrase"))
1231     {
1232         return rpn_search_APT_phrase (zi, zapt, attributeSet,
1233                                       reg_type, complete_flag,
1234                                       num_bases, basenames);
1235     }
1236     else if (!strcmp (search_type, "ranked"))
1237     {
1238         return rpn_search_APT_relevance (zi, zapt, attributeSet,
1239                                          reg_type, complete_flag,
1240                                          num_bases, basenames);
1241     }
1242     else if (!strcmp (search_type, "local"))
1243     {
1244         return rpn_search_APT_local (zi, zapt, attributeSet);
1245     }
1246     zi->errCode = 118;
1247     return NULL;
1248 }
1249
1250 static RSET rpn_search_ref (ZServerInfo *zi, Z_ResultSetId *resultSetId)
1251 {
1252     ZServerSet *s;
1253
1254     if (!(s = resultSetGet (zi, resultSetId)))
1255         return rset_create (rset_kind_null, NULL);
1256     return s->rset;
1257 }
1258
1259 static RSET rpn_search_structure (ZServerInfo *zi, Z_RPNStructure *zs,
1260                                   oid_value attributeSet,
1261                                   int num_bases, char **basenames)
1262 {
1263     RSET r = NULL;
1264     if (zs->which == Z_RPNStructure_complex)
1265     {
1266         Z_Operator *zop = zs->u.complex->roperator;
1267         rset_bool_parms bool_parms;
1268         int soft = 0;
1269          
1270
1271         bool_parms.rset_l = rpn_search_structure (zi, zs->u.complex->s1,
1272                                                   attributeSet,
1273                                                   num_bases, basenames);
1274         if (bool_parms.rset_l == NULL)
1275             return NULL;
1276         if (rset_is_ranked(bool_parms.rset_l))
1277             soft = 1;
1278         bool_parms.rset_r = rpn_search_structure (zi, zs->u.complex->s2,
1279                                                   attributeSet,
1280                                                   num_bases, basenames);
1281         if (bool_parms.rset_r == NULL)
1282         {
1283             rset_delete (bool_parms.rset_l);
1284             return NULL;
1285         }
1286         if (rset_is_ranked(bool_parms.rset_r))
1287             soft = 1;
1288         bool_parms.key_size = sizeof(struct it_key);
1289         bool_parms.cmp = key_compare_it;
1290
1291         switch (zop->which)
1292         {
1293         case Z_Operator_and:
1294             r = rset_create (soft ? rset_kind_sand:rset_kind_and, &bool_parms);
1295             break;
1296         case Z_Operator_or:
1297             r = rset_create (soft ? rset_kind_sor:rset_kind_or, &bool_parms);
1298             break;
1299         case Z_Operator_and_not:
1300             r = rset_create (soft ? rset_kind_snot:rset_kind_not, &bool_parms);
1301             break;
1302         case Z_Operator_prox:
1303             if (zop->u.prox->which != Z_ProxCode_known)
1304             {
1305                 zi->errCode = 132;
1306                 return NULL;
1307             }
1308             if (*zop->u.prox->proximityUnitCode != Z_ProxUnit_word)
1309             {
1310                 char *val = odr_malloc (zi->odr, 16);
1311                 zi->errCode = 132;
1312                 zi->errString = val;
1313                 sprintf (val, "%d", *zop->u.prox->proximityUnitCode);
1314                 return NULL;
1315             }
1316             r = rpn_proximity (zi, bool_parms.rset_l, bool_parms.rset_r,
1317                                *zop->u.prox->ordered,
1318                                (!zop->u.prox->exclusion ? 0 :
1319                                          *zop->u.prox->exclusion),
1320                                *zop->u.prox->relationType,
1321                                *zop->u.prox->distance);
1322             break;
1323         default:
1324             zi->errCode = 110;
1325             return NULL;
1326         }
1327     }
1328     else if (zs->which == Z_RPNStructure_simple)
1329     {
1330         if (zs->u.simple->which == Z_Operand_APT)
1331         {
1332             logf (LOG_DEBUG, "rpn_search_APT");
1333             r = rpn_search_APT (zi, zs->u.simple->u.attributesPlusTerm,
1334                                 attributeSet, num_bases, basenames);
1335         }
1336         else if (zs->u.simple->which == Z_Operand_resultSetId)
1337         {
1338             logf (LOG_DEBUG, "rpn_search_ref");
1339             r = rpn_search_ref (zi, zs->u.simple->u.resultSetId);
1340         }
1341         else
1342         {
1343             zi->errCode = 3;
1344             return NULL;
1345         }
1346     }
1347     else
1348     {
1349         zi->errCode = 3;
1350         return NULL;
1351     }
1352     return r;
1353 }
1354
1355 void count_set_save (ZServerInfo *zi, RSET *r, int *count)
1356 {
1357     int psysno = 0;
1358     int kno = 0;
1359     struct it_key key;
1360     RSFD rfd, wfd;
1361     RSET w;
1362     rset_temp_parms parms;
1363     int maxResultSetSize = atoi (res_get_def (zi->res,
1364                                         "maxResultSetSize", "400"));
1365     logf (LOG_DEBUG, "count_set_save");
1366     *count = 0;
1367     parms.key_size = sizeof(struct it_key);
1368     parms.temp_path = res_get (zi->res, "setTmpDir");
1369     w = rset_create (rset_kind_temp, &parms);
1370     wfd = rset_open (w, RSETF_WRITE|RSETF_SORT_SYSNO);
1371     rfd = rset_open (*r, RSETF_READ|RSETF_SORT_SYSNO);
1372     while (rset_read (*r, rfd, &key))
1373     {
1374         if (key.sysno != psysno)
1375         {
1376             if (*count < maxResultSetSize)
1377                 rset_write (w, wfd, &key);
1378             (*count)++;
1379             psysno = key.sysno;
1380         }
1381         kno++;
1382     }
1383     rset_close (*r, rfd);
1384     rset_delete (*r);
1385     rset_close (w, wfd);
1386     *r = w;
1387     logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *count);
1388 }
1389
1390 static void count_set (RSET r, int *count)
1391 {
1392     int psysno = 0;
1393     int kno = 0;
1394     struct it_key key;
1395     RSFD rfd;
1396
1397     logf (LOG_DEBUG, "count_set");
1398     *count = 0;
1399     rfd = rset_open (r, RSETF_READ|RSETF_SORT_SYSNO);
1400     while (rset_read (r, rfd, &key))
1401     {
1402         if (key.sysno != psysno)
1403         {
1404             psysno = key.sysno;
1405             (*count)++;
1406         }
1407         kno++;
1408     }
1409     rset_close (r, rfd);
1410     logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *count);
1411 }
1412
1413 int rpn_search (ZServerInfo *zi,
1414                 Z_RPNQuery *rpn, int num_bases, char **basenames, 
1415                 const char *setname, int *hits)
1416 {
1417     RSET rset;
1418     oident *attrset;
1419     oid_value attributeSet;
1420
1421     zlog_rpn (rpn);
1422
1423     zi->errCode = 0;
1424     zi->errString = NULL;
1425
1426     attrset = oid_getentbyoid (rpn->attributeSetId);
1427     attributeSet = attrset->value;
1428     rset = rpn_search_structure (zi, rpn->RPNStructure, attributeSet,
1429                                  num_bases, basenames);
1430     if (!rset)
1431         return zi->errCode;
1432     if (rset_is_volatile(rset))
1433         count_set_save(zi, &rset,hits);
1434     else
1435         count_set (rset, hits);
1436     resultSetAdd (zi, setname, 1, rset);
1437     if (zi->errCode)
1438         logf (LOG_DEBUG, "search error: %d", zi->errCode);
1439     return zi->errCode;
1440 }
1441
1442 struct scan_info_entry {
1443     char *term;
1444     ISAM_P isam_p;
1445 };
1446
1447 struct scan_info {
1448     struct scan_info_entry *list;
1449     ODR odr;
1450     int before, after;
1451     char prefix[20];
1452 };
1453
1454 static int scan_handle (char *name, const char *info, int pos, void *client)
1455 {
1456     int len_prefix, idx;
1457     struct scan_info *scan_info = client;
1458
1459     len_prefix = strlen(scan_info->prefix);
1460     if (memcmp (name, scan_info->prefix, len_prefix))
1461         return 1;
1462     if (pos > 0)
1463         idx = scan_info->after - pos + scan_info->before;
1464     else
1465         idx = - pos - 1;
1466     scan_info->list[idx].term = odr_malloc (scan_info->odr,
1467                                             strlen(name + len_prefix)+1);
1468     strcpy (scan_info->list[idx].term, name + len_prefix);
1469     assert (*info == sizeof(ISAM_P));
1470     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAM_P));
1471     return 0;
1472 }
1473
1474
1475 static void scan_term_untrans (ZServerInfo *zi, int reg_type,
1476                                char **dstp, const char *src)
1477 {    
1478     char *dst = odr_malloc (zi->odr, strlen(src)*2+1);
1479     *dstp = dst;
1480
1481     while (*src)
1482     {
1483         const char *cp = zebra_maps_output (zi->zebra_maps, reg_type, &src);
1484         while (*cp)
1485             *dst++ = *cp++;
1486     }
1487     *dst = '\0';
1488 }
1489
1490 int rpn_scan (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
1491               oid_value attributeset,
1492               int num_bases, char **basenames,
1493               int *position, int *num_entries, struct scan_entry **list,
1494               int *status)
1495 {
1496     int i;
1497     int pos = *position;
1498     int num = *num_entries;
1499     int before;
1500     int after;
1501     int base_no;
1502     char termz[IT_MAX_WORD+20];
1503     AttrType use;
1504     int use_value;
1505     struct scan_info *scan_info_array;
1506     struct scan_entry *glist;
1507     int ords[32], ord_no = 0;
1508     int ptr[32];
1509
1510     int reg_type;
1511     char *search_type = NULL;
1512     int complete_flag;
1513
1514     logf (LOG_DEBUG, "scan, position = %d, num = %d", pos, num);
1515
1516     if (attributeset == VAL_NONE)
1517         attributeset = VAL_BIB1;
1518         
1519     attr_init (&use, zapt, 1);
1520     use_value = attr_find (&use, &attributeset);
1521     logf (LOG_DEBUG, "use value %d", use_value);
1522
1523     if (zebra_maps_attr (zi->zebra_maps, zapt, &reg_type, &search_type,
1524                          &complete_flag))
1525     {
1526         zi->errCode = 113;
1527         return zi->errCode;
1528     }
1529
1530     if (use_value == -1)
1531         use_value = 1016;
1532     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
1533     {
1534         int r;
1535         attent attp;
1536         data1_local_attribute *local_attr;
1537
1538         if ((r=att_getentbyatt (zi, &attp, attributeset, use_value)))
1539         {
1540             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
1541                   attributeset, use_value);
1542             if (r == -1)
1543                 zi->errCode = 114;
1544             else
1545                 zi->errCode = 121;
1546         }
1547         if (zebTargetInfo_curDatabase (zi->zti, basenames[base_no]))
1548         {
1549             zi->errString = basenames[base_no];
1550             return zi->errCode = 109; /* Database unavailable */
1551         }
1552         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
1553              local_attr = local_attr->next)
1554         {
1555             int ord;
1556
1557             ord = zebTargetInfo_lookupSU (zi->zti, attp.attset_ordinal,
1558                                           local_attr->local);
1559             if (ord > 0)
1560                 ords[ord_no++] = ord;
1561         }
1562     }
1563     if (ord_no == 0)
1564         return zi->errCode = 113;
1565     before = pos-1;
1566     after = 1+num-pos;
1567     scan_info_array = odr_malloc (zi->odr, ord_no * sizeof(*scan_info_array));
1568     for (i = 0; i < ord_no; i++)
1569     {
1570         int j, prefix_len = 0;
1571         int before_tmp = before, after_tmp = after;
1572         struct scan_info *scan_info = scan_info_array + i;
1573         struct rpn_char_map_info rcmi;
1574
1575         rpn_char_map_prepare (zi, reg_type, &rcmi);
1576
1577         scan_info->before = before;
1578         scan_info->after = after;
1579         scan_info->odr = zi->odr;
1580
1581         scan_info->list = odr_malloc (zi->odr, (before+after)*
1582                                       sizeof(*scan_info->list));
1583         for (j = 0; j<before+after; j++)
1584             scan_info->list[j].term = NULL;
1585         termz[prefix_len++] = ords[i];
1586         termz[prefix_len++] = reg_type;
1587         termz[prefix_len] = 0;
1588         strcpy (scan_info->prefix, termz);
1589
1590         trans_scan_term (zi, zapt, termz+prefix_len, reg_type);
1591                     
1592         dict_scan (zi->dict, termz, &before_tmp, &after_tmp, scan_info,
1593                    scan_handle);
1594     }
1595     glist = odr_malloc (zi->odr, (before+after)*sizeof(*glist));
1596     for (i = 0; i < ord_no; i++)
1597         ptr[i] = before;
1598     
1599     *status = BEND_SCAN_SUCCESS;
1600     for (i = 0; i<after; i++)
1601     {
1602         int j, j0 = -1;
1603         const char *mterm = NULL;
1604         const char *tst;
1605         RSET rset;
1606         
1607         for (j = 0; j < ord_no; j++)
1608         {
1609             if (ptr[j] < before+after &&
1610                 (tst=scan_info_array[j].list[ptr[j]].term) &&
1611                 (!mterm || strcmp (tst, mterm) < 0))
1612             {
1613                 j0 = j;
1614                 mterm = tst;
1615             }
1616         }
1617         if (j0 == -1)
1618             break;
1619         scan_term_untrans (zi, reg_type, &glist[i+before].term, mterm);
1620         rset = rset_trunc (zi, &scan_info_array[j0].list[ptr[j0]].isam_p, 1);
1621
1622         ptr[j0]++;
1623         for (j = j0+1; j<ord_no; j++)
1624         {
1625             if (ptr[j] < before+after &&
1626                 (tst=scan_info_array[j].list[ptr[j]].term) &&
1627                 !strcmp (tst, mterm))
1628             {
1629                 rset_bool_parms bool_parms;
1630                 RSET rset2;
1631
1632                 rset2 =
1633                    rset_trunc (zi, &scan_info_array[j].list[ptr[j]].isam_p, 1);
1634
1635                 bool_parms.key_size = sizeof(struct it_key);
1636                 bool_parms.cmp = key_compare_it;
1637                 bool_parms.rset_l = rset;
1638                 bool_parms.rset_r = rset2;
1639               
1640                 rset = rset_create (rset_kind_or, &bool_parms);
1641
1642                 ptr[j]++;
1643             }
1644         }
1645         count_set (rset, &glist[i+before].occurrences);
1646         rset_delete (rset);
1647     }
1648     if (i < after)
1649     {
1650         *num_entries -= (after-i);
1651         *status = BEND_SCAN_PARTIAL;
1652     }
1653
1654     for (i = 0; i<ord_no; i++)
1655         ptr[i] = 0;
1656
1657     for (i = 0; i<before; i++)
1658     {
1659         int j, j0 = -1;
1660         const char *mterm = NULL;
1661         const char *tst;
1662         RSET rset;
1663         
1664         for (j = 0; j <ord_no; j++)
1665         {
1666             if (ptr[j] < before &&
1667                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
1668                 (!mterm || strcmp (tst, mterm) > 0))
1669             {
1670                 j0 = j;
1671                 mterm = tst;
1672             }
1673         }
1674         if (j0 == -1)
1675             break;
1676
1677         scan_term_untrans (zi, reg_type, &glist[before-1-i].term, mterm);
1678
1679         rset = rset_trunc
1680                (zi, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1);
1681
1682         ptr[j0]++;
1683
1684         for (j = j0+1; j<ord_no; j++)
1685         {
1686             if (ptr[j] < before &&
1687                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
1688                 !strcmp (tst, mterm))
1689             {
1690                 rset_bool_parms bool_parms;
1691                 RSET rset2;
1692
1693                 rset2 = rset_trunc (zi,
1694                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1);
1695
1696                 bool_parms.key_size = sizeof(struct it_key);
1697                 bool_parms.cmp = key_compare_it;
1698                 bool_parms.rset_l = rset;
1699                 bool_parms.rset_r = rset2;
1700               
1701                 rset = rset_create (rset_kind_or, &bool_parms);
1702
1703                 ptr[j]++;
1704             }
1705         }
1706         count_set (rset, &glist[before-1-i].occurrences);
1707         rset_delete (rset);
1708     }
1709     i = before-i;
1710     if (i)
1711     {
1712         *status = BEND_SCAN_PARTIAL;
1713         *position -= i;
1714         *num_entries -= i;
1715     }
1716     *list = glist + i;               /* list is set to first 'real' entry */
1717     
1718     logf (LOG_DEBUG, "position = %d, num_entries = %d",
1719           *position, *num_entries);
1720     if (zi->errCode)
1721         logf (LOG_DEBUG, "scan error: %d", zi->errCode);
1722     return zi->errCode;
1723 }
1724