Rename source files
[idzebra-moved-to-github.git] / index / rpnscan.c
1 /* $Id: rpnscan.c,v 1.1 2006-09-21 08:56:52 adam Exp $
2    Copyright (C) 1995-2006
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25 #ifdef WIN32
26 #include <io.h>
27 #endif
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <ctype.h>
32
33 #include <yaz/diagbib1.h>
34 #include "index.h"
35 #include <zebra_xpath.h>
36 #include <attrfind.h>
37 #include <charmap.h>
38 #include <rset.h>
39
40 struct scan_info_entry {
41     char *term;
42     ISAM_P isam_p;
43 };
44
45 struct scan_info {
46     struct scan_info_entry *list;
47     ODR odr;
48     int before, after;
49     char prefix[20];
50 };
51
52 /* convert APT SCAN term to internal cmap */
53 static ZEBRA_RES trans_scan_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
54                                  char *termz, int reg_type)
55 {
56     char termz0[IT_MAX_WORD];
57
58     if (zapt_term_to_utf8(zh, zapt, termz0) == ZEBRA_FAIL)
59         return ZEBRA_FAIL;    /* error */
60     else
61     {
62         const char **map;
63         const char *cp = (const char *) termz0;
64         const char *cp_end = cp + strlen(cp);
65         const char *src;
66         int i = 0;
67         const char *space_map = NULL;
68         int len;
69             
70         while ((len = (cp_end - cp)) > 0)
71         {
72             map = zebra_maps_input(zh->reg->zebra_maps, reg_type, &cp, len, 0);
73             if (**map == *CHR_SPACE)
74                 space_map = *map;
75             else
76             {
77                 if (i && space_map)
78                     for (src = space_map; *src; src++)
79                         termz[i++] = *src;
80                 space_map = NULL;
81                 for (src = *map; *src; src++)
82                     termz[i++] = *src;
83             }
84         }
85         termz[i] = '\0';
86     }
87     return ZEBRA_OK;
88 }
89
90 static void count_set(ZebraHandle zh, RSET rset, zint *count)
91 {
92     zint psysno = 0;
93     struct it_key key;
94     RSFD rfd;
95
96     yaz_log(YLOG_DEBUG, "count_set");
97
98     rset->hits_limit = zh->approx_limit;
99
100     *count = 0;
101     rfd = rset_open(rset, RSETF_READ);
102     while (rset_read(rfd, &key,0 /* never mind terms */))
103     {
104         if (key.mem[0] != psysno)
105         {
106             psysno = key.mem[0];
107             if (rfd->counted_items >= rset->hits_limit)
108                 break;
109         }
110     }
111     rset_close (rfd);
112     *count = rset->hits_count;
113 }
114
115 static int scan_handle (char *name, const char *info, int pos, void *client)
116 {
117     int len_prefix, idx;
118     struct scan_info *scan_info = (struct scan_info *) client;
119
120     len_prefix = strlen(scan_info->prefix);
121     if (memcmp (name, scan_info->prefix, len_prefix))
122         return 1;
123     if (pos > 0)
124         idx = scan_info->after - pos + scan_info->before;
125     else
126         idx = - pos - 1;
127
128     /* skip special terms.. of no interest */
129     if (name[len_prefix] < 4)
130         return 1;
131
132     if (idx < 0)
133         return 0;
134     scan_info->list[idx].term = (char *)
135         odr_malloc(scan_info->odr, strlen(name + len_prefix)+1);
136     strcpy(scan_info->list[idx].term, name + len_prefix);
137     assert (*info == sizeof(ISAM_P));
138     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAM_P));
139     return 0;
140 }
141
142
143 #define RPN_MAX_ORDS 32
144
145 ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
146                    oid_value attributeset,
147                    int num_bases, char **basenames,
148                    int *position, int *num_entries, ZebraScanEntry **list,
149                    int *is_partial, RSET limit_set, int return_zero)
150 {
151     int i;
152     int pos = *position;
153     int num = *num_entries;
154     int before;
155     int after;
156     int base_no;
157     char termz[IT_MAX_WORD+20];
158     struct scan_info *scan_info_array;
159     ZebraScanEntry *glist;
160     int ords[RPN_MAX_ORDS], ord_no = 0;
161     int ptr[RPN_MAX_ORDS];
162
163     unsigned index_type;
164     char *search_type = NULL;
165     char rank_type[128];
166     int complete_flag;
167     int sort_flag;
168     NMEM rset_nmem = NULL; 
169     struct rset_key_control *kc = 0;
170
171     *list = 0;
172     *is_partial = 0;
173
174     if (attributeset == VAL_NONE)
175         attributeset = VAL_BIB1;
176
177     if (!limit_set)
178     {
179         AttrType termset;
180         int termset_value_numeric;
181         const char *termset_value_string;
182         attr_init_APT(&termset, zapt, 8);
183         termset_value_numeric =
184             attr_find_ex(&termset, NULL, &termset_value_string);
185         if (termset_value_numeric != -1)
186         {
187             char resname[32];
188             const char *termset_name = 0;
189             
190             if (termset_value_numeric != -2)
191             {
192                 
193                 sprintf(resname, "%d", termset_value_numeric);
194                 termset_name = resname;
195             }
196             else
197                 termset_name = termset_value_string;
198             
199             limit_set = resultSetRef (zh, termset_name);
200         }
201     }
202         
203     yaz_log(YLOG_DEBUG, "position = %d, num = %d set=%d",
204             pos, num, attributeset);
205         
206     if (zebra_maps_attr(zh->reg->zebra_maps, zapt, &index_type, &search_type,
207                         rank_type, &complete_flag, &sort_flag))
208     {
209         *num_entries = 0;
210         zebra_setError(zh, YAZ_BIB1_UNSUPP_ATTRIBUTE_TYPE, 0);
211         return ZEBRA_FAIL;
212     }
213     for (base_no = 0; base_no < num_bases && ord_no < RPN_MAX_ORDS; base_no++)
214     {
215         int ord;
216
217         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
218         {
219             zebra_setError(zh, YAZ_BIB1_DATABASE_UNAVAILABLE,
220                            basenames[base_no]);
221             *num_entries = 0;
222             return ZEBRA_FAIL;
223         }
224         if (zebra_apt_get_ord(zh, zapt, index_type, 0, attributeset, &ord) 
225             != ZEBRA_OK)
226             continue;
227         ords[ord_no++] = ord;
228     }
229     if (ord_no == 0)
230     {
231         *num_entries = 0;
232         return ZEBRA_FAIL;
233     }
234     /* prepare dictionary scanning */
235     if (num < 1)
236     {
237         *num_entries = 0;
238         return ZEBRA_OK;
239     }
240     before = pos-1;
241     if (before < 0)
242         before = 0;
243     after = 1+num-pos;
244     if (after < 0)
245         after = 0;
246     yaz_log(YLOG_DEBUG, "rpn_scan pos=%d num=%d before=%d "
247             "after=%d before+after=%d",
248             pos, num, before, after, before+after);
249     scan_info_array = (struct scan_info *)
250         odr_malloc(stream, ord_no * sizeof(*scan_info_array));
251     for (i = 0; i < ord_no; i++)
252     {
253         int j, prefix_len = 0;
254         int before_tmp = before, after_tmp = after;
255         struct scan_info *scan_info = scan_info_array + i;
256         struct rpn_char_map_info rcmi;
257
258         rpn_char_map_prepare (zh->reg, index_type, &rcmi);
259
260         scan_info->before = before;
261         scan_info->after = after;
262         scan_info->odr = stream;
263
264         scan_info->list = (struct scan_info_entry *)
265             odr_malloc(stream, (before+after) * sizeof(*scan_info->list));
266         for (j = 0; j<before+after; j++)
267             scan_info->list[j].term = NULL;
268
269         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
270         termz[prefix_len] = 0;
271         strcpy(scan_info->prefix, termz);
272
273         if (trans_scan_term(zh, zapt, termz+prefix_len, index_type) == 
274             ZEBRA_FAIL)
275             return ZEBRA_FAIL;
276         
277         dict_scan(zh->reg->dict, termz, &before_tmp, &after_tmp,
278                   scan_info, scan_handle);
279     }
280     glist = (ZebraScanEntry *)
281         odr_malloc(stream, (before+after)*sizeof(*glist));
282
283     rset_nmem = nmem_create();
284     kc = zebra_key_control_create(zh);
285
286     /* consider terms after main term */
287     for (i = 0; i < ord_no; i++)
288         ptr[i] = before;
289     
290     *is_partial = 0;
291     for (i = 0; i<after; i++)
292     {
293         int j, j0 = -1;
294         const char *mterm = NULL;
295         const char *tst;
296         RSET rset = 0;
297         int lo = i + pos-1; /* offset in result list */
298
299         /* find: j0 is the first of the minimal values */
300         for (j = 0; j < ord_no; j++)
301         {
302             if (ptr[j] < before+after && ptr[j] >= 0 &&
303                 (tst = scan_info_array[j].list[ptr[j]].term) &&
304                 (!mterm || strcmp (tst, mterm) < 0))
305             {
306                 j0 = j;
307                 mterm = tst;
308             }
309         }
310         if (j0 == -1)
311             break;  /* no value found, stop */
312
313         /* get result set for first one , but only if it's within bounds */
314         if (lo >= 0)
315         {
316             /* get result set for first term */
317             zebra_term_untrans_iconv(zh, stream->mem, index_type,
318                                      &glist[lo].term, mterm);
319             rset = rset_trunc(zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
320                               glist[lo].term, strlen(glist[lo].term),
321                               NULL, 0, zapt->term->which, rset_nmem, 
322                               kc, kc->scope, 0, index_type, 0 /* hits_limit */,
323                               0 /* term_ref_id_str */);
324         }
325         ptr[j0]++; /* move index for this set .. */
326         /* get result set for remaining scan terms */
327         for (j = j0+1; j<ord_no; j++)
328         {
329             if (ptr[j] < before+after && ptr[j] >= 0 &&
330                 (tst = scan_info_array[j].list[ptr[j]].term) &&
331                 !strcmp (tst, mterm))
332             {
333                 if (lo >= 0)
334                 {
335                     RSET rsets[2];
336                     
337                     rsets[0] = rset;
338                     rsets[1] =
339                         rset_trunc(
340                             zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
341                             glist[lo].term,
342                             strlen(glist[lo].term), NULL, 0,
343                             zapt->term->which,rset_nmem,
344                             kc, kc->scope, 0, index_type, 0 /* hits_limit */,
345                             0 /* term_ref_id_str */ );
346                     rset = rset_create_or(rset_nmem, kc,
347                                           kc->scope, 0 /* termid */,
348                                           2, rsets);
349                 }
350                 ptr[j]++;
351             }
352         }
353         if (lo >= 0)
354         {
355             zint count;
356             /* merge with limit_set if given */
357             if (limit_set)
358             {
359                 RSET rsets[2];
360                 rsets[0] = rset;
361                 rsets[1] = rset_dup(limit_set);
362                 
363                 rset = rset_create_and(rset_nmem, kc, kc->scope, 2, rsets);
364             }
365             /* count it */
366             count_set(zh, rset, &count);
367             glist[lo].occurrences = count;
368             rset_delete(rset);
369         }
370     }
371     if (i < after)
372     {
373         *num_entries -= (after-i);
374         *is_partial = 1;
375         if (*num_entries < 0)
376         {
377             (*kc->dec)(kc);
378             nmem_destroy(rset_nmem);
379             *num_entries = 0;
380             return ZEBRA_OK;
381         }
382     }
383     /* consider terms before main term */
384     for (i = 0; i<ord_no; i++)
385         ptr[i] = 0;
386     
387     for (i = 0; i<before; i++)
388     {
389         int j, j0 = -1;
390         const char *mterm = NULL;
391         const char *tst;
392         RSET rset;
393         int lo = before-1-i; /* offset in result list */
394         zint count;
395         
396         for (j = 0; j <ord_no; j++)
397         {
398             if (ptr[j] < before && ptr[j] >= 0 &&
399                 (tst = scan_info_array[j].list[before-1-ptr[j]].term) &&
400                 (!mterm || strcmp (tst, mterm) > 0))
401             {
402                 j0 = j;
403                     mterm = tst;
404             }
405         }
406         if (j0 == -1)
407             break;
408         
409         zebra_term_untrans_iconv(zh, stream->mem, index_type,
410                                  &glist[lo].term, mterm);
411         
412         rset = rset_trunc
413             (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
414              glist[lo].term, strlen(glist[lo].term),
415              NULL, 0, zapt->term->which, rset_nmem,
416              kc, kc->scope, 0, index_type, 0 /* hits_limit */,
417              0 /* term_ref_id_str */);
418         
419         ptr[j0]++;
420         
421         for (j = j0+1; j<ord_no; j++)
422         {
423             if (ptr[j] < before && ptr[j] >= 0 &&
424                 (tst = scan_info_array[j].list[before-1-ptr[j]].term) &&
425                 !strcmp (tst, mterm))
426             {
427                 RSET rsets[2];
428                 
429                 rsets[0] = rset;
430                 rsets[1] = rset_trunc(
431                     zh,
432                     &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
433                     glist[lo].term,
434                     strlen(glist[lo].term), NULL, 0,
435                     zapt->term->which, rset_nmem,
436                     kc, kc->scope, 0, index_type, 0 /* hits_limit */,
437                     0 /* term_ref_id_str */);
438                 rset = rset_create_or(rset_nmem, kc,
439                                       kc->scope, 0 /* termid */, 2, rsets);
440                 
441                 ptr[j]++;
442             }
443         }
444         if (limit_set)
445         {
446             RSET rsets[2];
447             rsets[0] = rset;
448             rsets[1] = rset_dup(limit_set);
449             
450             rset = rset_create_and(rset_nmem, kc, kc->scope, 2, rsets);
451         }
452         count_set(zh, rset, &count);
453         glist[lo].occurrences = count;
454         rset_delete (rset);
455     }
456     (*kc->dec)(kc);
457     nmem_destroy(rset_nmem);
458     i = before-i;
459     if (i)
460     {
461         *is_partial = 1;
462         *position -= i;
463         *num_entries -= i;
464         if (*num_entries <= 0)
465         {
466             *num_entries = 0;
467             return ZEBRA_OK;
468         }
469     }
470     
471     *list = glist + i;               /* list is set to first 'real' entry */
472     
473     yaz_log(YLOG_DEBUG, "position = %d, num_entries = %d",
474             *position, *num_entries);
475     return ZEBRA_OK;
476 }
477
478 /*
479  * Local variables:
480  * c-basic-offset: 4
481  * indent-tabs-mode: nil
482  * End:
483  * vim: shiftwidth=4 tabstop=8 expandtab
484  */
485