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