Test case for bug 460
[idzebra-moved-to-github.git] / index / zsets.c
1 /* $Id: zsets.c,v 1.49.2.5 2006-01-19 13:32:46 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <assert.h>
26 #ifdef WIN32
27 #include <io.h>
28 #else
29 #include <unistd.h>
30 #endif
31
32 #include "index.h"
33 #include <rstemp.h>
34
35 #define SORT_IDX_ENTRYSIZE 64
36 #define ZSET_SORT_MAX_LEVEL 3
37
38 struct zebra_set_term_entry {
39     int reg_type;
40     char *db;
41     int set;
42     int use;
43     char *term;
44 };
45 struct zebra_set {
46     char *name;
47     RSET rset;
48     NMEM nmem;
49     int hits;
50     int num_bases;
51     char **basenames;
52     Z_RPNQuery *rpn;
53     Z_SortKeySpecList *sortSpec;
54     struct zset_sort_info *sort_info;
55     struct zebra_set_term_entry *term_entries;
56     int term_entries_max;
57     struct zebra_set *next;
58     int locked;
59
60     int cache_position;  /* last position */
61     RSFD cache_rfd;      /* rfd (NULL if not existing) */
62     int cache_psysno;
63 };
64
65 struct zset_sort_entry {
66     int sysno;
67     int score;
68     char buf[ZSET_SORT_MAX_LEVEL][SORT_IDX_ENTRYSIZE];
69 };
70
71 struct zset_sort_info {
72     int max_entries;
73     int num_entries;
74     struct zset_sort_entry *all_entries;
75     struct zset_sort_entry **entries;
76 };
77
78 ZebraSet resultSetAddRPN (ZebraHandle zh, NMEM m,
79                           Z_RPNQuery *rpn, int num_bases,
80                           char **basenames, 
81                           const char *setname)
82 {
83     ZebraSet zebraSet;
84     int i;
85
86     zh->errCode = 0;
87     zh->errString = NULL;
88     zh->hits = 0;
89
90     zebraSet = resultSetAdd (zh, setname, 1);
91     if (!zebraSet)
92         return 0;
93     zebraSet->locked = 1;
94     zebraSet->rpn = 0;
95     zebraSet->nmem = m;
96     
97     zebraSet->num_bases = num_bases;
98     zebraSet->basenames = 
99         nmem_malloc (zebraSet->nmem, num_bases * sizeof(*zebraSet->basenames));
100     for (i = 0; i<num_bases; i++)
101         zebraSet->basenames[i] = nmem_strdup (zebraSet->nmem, basenames[i]);
102
103
104     zebraSet->rset = rpn_search (zh, zebraSet->nmem, rpn,
105                                  zebraSet->num_bases,
106                                  zebraSet->basenames, zebraSet->name,
107                                  zebraSet);
108     zh->hits = zebraSet->hits;
109     if (zebraSet->rset)
110         zebraSet->rpn = rpn;
111     zebraSet->locked = 0;
112     return zebraSet;
113 }
114
115 void resultSetAddTerm (ZebraHandle zh, ZebraSet s, int reg_type,
116                        const char *db, int set,
117                        int use, const char *term)
118 {
119     if (!s->nmem)
120         s->nmem = nmem_create ();
121     if (!s->term_entries)
122     {
123         int i;
124         s->term_entries_max = 1000;
125         s->term_entries =
126             nmem_malloc (s->nmem, s->term_entries_max * 
127                          sizeof(*s->term_entries));
128         for (i = 0; i < s->term_entries_max; i++)
129             s->term_entries[i].term = 0;
130     }
131     if (s->hits < s->term_entries_max)
132     {
133         s->term_entries[s->hits].reg_type = reg_type;
134         s->term_entries[s->hits].db = nmem_strdup (s->nmem, db);
135         s->term_entries[s->hits].set = set;
136         s->term_entries[s->hits].use = use;
137         s->term_entries[s->hits].term = nmem_strdup (s->nmem, term);
138     }
139     (s->hits)++;
140 }
141
142
143 int zebra_resultSetTerms (ZebraHandle zh, const char *setname, 
144                           int no, int *count, 
145                           int *type, char *out, size_t *len)
146 {
147     ZebraSet s = resultSetGet (zh, setname);
148     int no_max = 0;
149
150     if (count)
151         *count = 0;
152     if (!s || !s->rset)
153         return 0;
154     no_max = s->rset->no_rset_terms;
155     if (no < 0 || no >= no_max)
156         return 0;
157     if (count)
158         *count = s->rset->rset_terms[no]->count;
159     if (type)
160         *type = s->rset->rset_terms[no]->type;
161     
162     if (out)
163     {
164         char *inbuf = s->rset->rset_terms[no]->name;
165         size_t inleft = strlen(inbuf);
166         size_t outleft = *len - 1;
167         int converted = 0;
168
169         if (zh->iconv_from_utf8 != 0)
170         {
171             char *outbuf = out;
172             size_t ret;
173             
174             ret = yaz_iconv(zh->iconv_from_utf8, &inbuf, &inleft,
175                         &outbuf, &outleft);
176             if (ret == (size_t)(-1))
177                 *len = 0;
178             else
179                 *len = outbuf - out;
180             converted = 1;
181         }
182         if (!converted)
183         {
184             if (inleft > outleft)
185                 inleft = outleft;
186             *len = inleft;
187             memcpy (out, inbuf, *len);
188         }
189         out[*len] = 0;
190     }
191     return no_max;
192 }
193
194
195 ZebraSet resultSetAdd (ZebraHandle zh, const char *name, int ov)
196 {
197     ZebraSet s;
198     int i;
199
200     for (s = zh->sets; s; s = s->next)
201         if (!strcmp (s->name, name))
202             break;
203     if (s)
204     {
205         yaz_log (LOG_DEBUG, "updating result set %s", name);
206         if (!ov || s->locked)
207             return NULL;
208         if (s->rset)
209         {
210             if (s->cache_rfd)
211                 rset_close(s->rset, s->cache_rfd);
212             rset_delete (s->rset);
213         }
214         if (s->nmem)
215             nmem_destroy (s->nmem);
216     }
217     else
218     {
219         const char *sort_max_str = zebra_get_resource(zh, "sortmax", "1000");
220
221         yaz_log (LOG_DEBUG, "adding result set %s", name);
222         s = (ZebraSet) xmalloc (sizeof(*s));
223         s->next = zh->sets;
224         zh->sets = s;
225         s->name = (char *) xmalloc (strlen(name)+1);
226         strcpy (s->name, name);
227
228         s->sort_info = (struct zset_sort_info *)
229             xmalloc (sizeof(*s->sort_info));
230         s->sort_info->max_entries = atoi(sort_max_str);
231         if (s->sort_info->max_entries < 2)
232             s->sort_info->max_entries = 2;
233
234         s->sort_info->entries = (struct zset_sort_entry **)
235             xmalloc (sizeof(*s->sort_info->entries) *
236                      s->sort_info->max_entries);
237         s->sort_info->all_entries = (struct zset_sort_entry *)
238             xmalloc (sizeof(*s->sort_info->all_entries) *
239                      s->sort_info->max_entries);
240         for (i = 0; i < s->sort_info->max_entries; i++)
241             s->sort_info->entries[i] = s->sort_info->all_entries + i;
242     }
243     s->locked = 0;
244     s->term_entries = 0;
245     s->hits = 0;
246     s->rset = 0;
247     s->nmem = 0;
248     s->rpn = 0;
249     s->sortSpec = 0;
250     s->cache_position = 0;
251     s->cache_rfd = 0;
252     return s;
253 }
254
255 ZebraSet resultSetGet (ZebraHandle zh, const char *name)
256 {
257     ZebraSet s;
258
259     for (s = zh->sets; s; s = s->next)
260         if (!strcmp (s->name, name))
261         {
262             if (!s->term_entries && !s->rset && s->rpn)
263             {
264                 NMEM nmem = nmem_create ();
265                 yaz_log (LOG_LOG, "research %s", name);
266                 s->rset =
267                     rpn_search (zh, nmem, s->rpn, s->num_bases,
268                                 s->basenames, s->name, s);
269                 if (s->rset && s->sortSpec)
270                 {
271                     int sort_status;
272                     yaz_log (LOG_LOG, "resort %s", name);
273                     resultSetSortSingle (zh, nmem, s, s->rset, s->sortSpec,
274                                          &sort_status);
275                 }
276                 nmem_destroy (nmem);
277             }
278             return s;
279         }
280     return NULL;
281 }
282
283 void resultSetInvalidate (ZebraHandle zh)
284 {
285     ZebraSet s = zh->sets;
286     
287     for (; s; s = s->next)
288     {
289         if (s->rset)
290         {
291             if (s->cache_rfd)
292                 rset_close(s->rset, s->cache_rfd);
293             rset_delete (s->rset);
294         }
295         s->rset = 0;
296         s->cache_rfd = 0;
297         s->cache_position = 0;
298     }
299 }
300
301 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
302 {
303     ZebraSet * ss = &zh->sets;
304     int i;
305     
306     if (statuses)
307         for (i = 0; i<num; i++)
308             statuses[i] = Z_DeleteStatus_resultSetDidNotExist;
309     zh->errCode = 0;
310     zh->errString = NULL;
311     while (*ss)
312     {
313         int i = -1;
314         ZebraSet s = *ss;
315         if (num >= 0)
316         {
317             for (i = 0; i<num; i++)
318                 if (!strcmp (s->name, names[i]))
319                 {
320                     if (statuses)
321                         statuses[i] = Z_DeleteStatus_success;
322                     i = -1;
323                     break;
324                 }
325         }
326         if (i < 0)
327         {
328             *ss = s->next;
329             
330             xfree (s->sort_info->all_entries);
331             xfree (s->sort_info->entries);
332             xfree (s->sort_info);
333             
334             if (s->nmem)
335                 nmem_destroy (s->nmem);
336             if (s->rset)
337             {
338                 if (s->cache_rfd)
339                     rset_close (s->rset, s->cache_rfd);
340                 rset_delete (s->rset);
341             }
342             xfree (s->name);
343             xfree (s);
344         }
345         else
346             ss = &s->next;
347     }
348 }
349
350 ZebraPosSet zebraPosSetCreate (ZebraHandle zh, const char *name, 
351                                int num, int *positions)
352 {
353     ZebraSet sset;
354     ZebraPosSet sr = 0;
355     RSET rset;
356     int i;
357     struct zset_sort_info *sort_info;
358
359     if (!(sset = resultSetGet (zh, name)))
360         return NULL;
361     if (!(rset = sset->rset))
362     {
363         if (!sset->term_entries)
364             return 0;
365         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
366         for (i = 0; i<num; i++)
367         {
368             sr[i].sysno = 0;
369             sr[i].score = -1;
370             sr[i].term = 0;
371             sr[i].db = 0;
372
373             if (positions[i] <= sset->term_entries_max)
374             {
375                 sr[i].term = sset->term_entries[positions[i]-1].term;
376                 sr[i].db = sset->term_entries[positions[i]-1].db;
377             }
378         }
379     }
380     else
381     {
382         sr = (ZebraPosSet) xmalloc (sizeof(*sr) * num);
383         for (i = 0; i<num; i++)
384         {
385             sr[i].sysno = 0;
386             sr[i].score = -1;
387             sr[i].term = 0;
388             sr[i].db = 0;
389         }
390         sort_info = sset->sort_info;
391         if (sort_info)
392         {
393             int position;
394             
395             for (i = 0; i<num; i++)
396             {
397                 position = positions[i];
398                 if (position > 0 && position <= sort_info->num_entries)
399                 {
400                     yaz_log (LOG_DEBUG, "got pos=%d (sorted)", position);
401                     sr[i].sysno = sort_info->entries[position-1]->sysno;
402                     sr[i].score = sort_info->entries[position-1]->score;
403                 }
404             }
405         }
406         /* did we really get all entries using sort ? */
407         for (i = 0; i<num; i++)
408         {
409             if (!sr[i].sysno)
410                 break;
411         }
412         if (i < num) /* nope, get the rest, unsorted - sorry */
413         {
414             int position = 0;
415             int num_i = 0;
416             int psysno = 0;
417             int term_index;
418             RSFD rfd;
419             struct it_key key;
420             
421             if (sort_info)
422                 position = sort_info->num_entries;
423             while (num_i < num && positions[num_i] < position)
424                 num_i++;
425             
426             if (sset->cache_rfd && 
427                 num_i < num && positions[num_i] > sset->cache_position)
428             {
429                 position = sset->cache_position;
430                 rfd = sset->cache_rfd;
431                 psysno = sset->cache_psysno;
432             } 
433             else
434             {
435                 if (sset->cache_rfd)
436                     rset_close(rset, sset->cache_rfd);
437                 rfd = rset_open (rset, RSETF_READ);
438             }
439             while (num_i < num && rset_read (rset, rfd, &key, &term_index))
440             {
441                 if (key.sysno != psysno)
442                 {
443                     psysno = key.sysno;
444                     if (sort_info)
445                     {
446                         /* determine we alreay have this in our set */
447                         for (i = sort_info->num_entries; --i >= 0; )
448                             if (psysno == sort_info->entries[i]->sysno)
449                                 break;
450                         if (i >= 0)
451                             continue;
452                     }
453                     position++;
454                     assert (num_i < num);
455                     if (position == positions[num_i])
456                     {
457                         sr[num_i].sysno = psysno;
458                         yaz_log (LOG_DEBUG, "got pos=%d (unsorted)", position);
459                         sr[num_i].score = -1;
460                         num_i++;
461                     }
462                 }
463             }
464             sset->cache_position = position;
465             sset->cache_psysno = psysno;
466             sset->cache_rfd = rfd;
467         }
468     }
469     return sr;
470 }
471
472 void zebraPosSetDestroy (ZebraHandle zh, ZebraPosSet records, int num)
473 {
474     xfree (records);
475 }
476
477 struct sortKeyInfo {
478     int relation;
479     int attrUse;
480     int numerical;
481 };
482
483 void resultSetInsertSort (ZebraHandle zh, ZebraSet sset,
484                           struct sortKeyInfo *criteria, int num_criteria,
485                           int sysno)
486 {
487     struct zset_sort_entry this_entry;
488     struct zset_sort_entry *new_entry = NULL;
489     struct zset_sort_info *sort_info = sset->sort_info;
490     int i, j;
491
492     sortIdx_sysno (zh->reg->sortIdx, sysno);
493     for (i = 0; i<num_criteria; i++)
494     {
495         sortIdx_type (zh->reg->sortIdx, criteria[i].attrUse);
496         sortIdx_read (zh->reg->sortIdx, this_entry.buf[i]);
497     }
498     i = sort_info->num_entries;
499     while (--i >= 0)
500     {
501         int rel = 0;
502         for (j = 0; j<num_criteria; j++)
503         {
504             if (criteria[j].numerical)
505             {
506                 double diff = atof(this_entry.buf[j]) -
507                               atof(sort_info->entries[i]->buf[j]);
508                 rel = 0;
509                 if (diff > 0.0)
510                     rel = 1;
511                 else if (diff < 0.0)
512                     rel = -1;
513             }
514             else
515             {
516                 rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
517                           SORT_IDX_ENTRYSIZE);
518             }
519             if (rel)
520                 break;
521         }       
522         if (!rel)
523             break;
524         if (criteria[j].relation == 'A')
525         {
526             if (rel > 0)
527                 break;
528         }
529         else if (criteria[j].relation == 'D')
530         {
531             if (rel < 0)
532                 break;
533         }
534     }
535     ++i;
536     j = sort_info->max_entries;
537     if (i == j)
538         return;
539
540     if (sort_info->num_entries == j)
541         --j;
542     else
543         j = (sort_info->num_entries)++;
544     new_entry = sort_info->entries[j];
545     while (j != i)
546     {
547         sort_info->entries[j] = sort_info->entries[j-1];
548         --j;
549     }
550     sort_info->entries[i] = new_entry;
551     assert (new_entry);
552     for (i = 0; i<num_criteria; i++)
553         memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
554     new_entry->sysno = sysno;
555     new_entry->score = -1;
556 }
557
558 void resultSetInsertRank(ZebraHandle zh, struct zset_sort_info *sort_info,
559                          int sysno, int score, int relation)
560 {
561     struct zset_sort_entry *new_entry = NULL;
562     int i, j;
563
564     i = sort_info->num_entries;
565     while (--i >= 0)
566     {
567         int rel = 0;
568
569         rel = score - sort_info->entries[i]->score;
570
571         if (relation == 'D')
572         {
573             if (rel >= 0)
574                 break;
575         }
576         else if (relation == 'A')
577         {
578             if (rel <= 0)
579                 break;
580         }
581     }
582     ++i;
583     j = sort_info->max_entries;
584     if (i == j)
585         return;
586
587     if (sort_info->num_entries == j)
588         --j;
589     else
590         j = (sort_info->num_entries)++;
591     
592     new_entry = sort_info->entries[j];
593     while (j != i)
594     {
595         sort_info->entries[j] = sort_info->entries[j-1];
596         --j;
597     }
598     sort_info->entries[i] = new_entry;
599     assert (new_entry);
600     new_entry->sysno = sysno;
601     new_entry->score = score;
602 }
603
604
605 static Z_RPNQuery *copy_RPNQuery(Z_RPNQuery *src, NMEM nmem)
606 {
607     Z_RPNQuery *dst = 0;
608     ODR encode = odr_createmem(ODR_ENCODE);
609     ODR decode = odr_createmem(ODR_DECODE);
610
611     if (z_RPNQuery(encode, &src, 0, 0))
612     {
613         int len;
614         char *buf = odr_getbuf(encode, &len, 0);
615
616         if (buf)
617         {
618             odr_setbuf(decode, buf, len, 0);
619             z_RPNQuery(decode, &dst, 0, 0);
620         }
621     }
622     nmem_transfer(nmem, decode->mem);
623     odr_destroy(encode);
624     odr_destroy(decode);
625     return dst;
626 }
627
628 static Z_SortKeySpecList *copy_SortKeySpecList(Z_SortKeySpecList *src, NMEM nmem)
629 {
630     Z_SortKeySpecList *dst = 0;
631     ODR encode = odr_createmem(ODR_ENCODE);
632     ODR decode = odr_createmem(ODR_DECODE);
633
634     if (z_SortKeySpecList(encode, &src, 0, 0))
635     {
636         int len;
637         char *buf = odr_getbuf(encode, &len, 0);
638
639         if (buf)
640         {
641             odr_setbuf(decode, buf, len, 0);
642             z_SortKeySpecList(decode, &dst, 0, 0);
643         }
644     }
645     nmem_transfer(nmem, decode->mem);
646     odr_destroy(encode);
647     odr_destroy(decode);
648     return dst;
649 }
650
651 ZebraSet resultSetClone(ZebraHandle zh, const char *setname,
652                         ZebraSet rset)
653 {
654     ZebraSet nset;
655     int i;
656
657     nset = resultSetAdd(zh, setname, 1);
658     if (!nset)
659         return 0;
660
661     nset->nmem = nmem_create();
662
663     nset->num_bases = rset->num_bases;
664     nset->basenames = 
665         nmem_malloc (nset->nmem, nset->num_bases * sizeof(*rset->basenames));
666     for (i = 0; i<rset->num_bases; i++)
667         nset->basenames[i] = nmem_strdup(nset->nmem, rset->basenames[i]);
668
669     if (rset->rset)
670         nset->rset = rset_dup(rset->rset);
671     if (rset->rpn)
672         nset->rpn = copy_RPNQuery(rset->rpn, nset->nmem);
673     return nset;
674 }
675
676 void resultSetSort (ZebraHandle zh, NMEM nmem,
677                     int num_input_setnames, const char **input_setnames,
678                     const char *output_setname,
679                     Z_SortKeySpecList *sort_sequence, int *sort_status)
680 {
681     ZebraSet sset;
682     RSET rset;
683
684     if (num_input_setnames == 0)
685     {
686         zh->errCode = 208;
687         return ;
688     }
689     if (num_input_setnames > 1)
690     {
691         zh->errCode = 230;
692         return;
693     }
694     yaz_log (LOG_DEBUG, "result set sort input=%s output=%s",
695           *input_setnames, output_setname);
696     sset = resultSetGet (zh, input_setnames[0]);
697     if (!sset)
698     {
699         zh->errCode = 30;
700         zh->errString = nmem_strdup (nmem, input_setnames[0]);
701         return;
702     }
703     if (!(rset = sset->rset))
704     {
705         zh->errCode = 30;
706         zh->errString = nmem_strdup (nmem, input_setnames[0]);
707         return;
708     }
709     if (strcmp (output_setname, input_setnames[0]))
710         sset = resultSetClone(zh, output_setname, sset);
711     sset->sortSpec = copy_SortKeySpecList(sort_sequence, sset->nmem);
712     resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
713 }
714
715 void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
716                           ZebraSet sset, RSET rset,
717                           Z_SortKeySpecList *sort_sequence, int *sort_status)
718 {
719     int kno = 0;
720     int i, psysno = 0;
721     struct it_key key;
722     struct sortKeyInfo sort_criteria[3];
723     int num_criteria;
724     int term_index;
725     RSFD rfd;
726
727     sset->sort_info->num_entries = 0;
728
729     sset->hits = 0;
730     num_criteria = sort_sequence->num_specs;
731     if (num_criteria > 3)
732         num_criteria = 3;
733     for (i = 0; i < num_criteria; i++)
734     {
735         Z_SortKeySpec *sks = sort_sequence->specs[i];
736         Z_SortKey *sk;
737
738         if (*sks->sortRelation == Z_SortKeySpec_ascending)
739             sort_criteria[i].relation = 'A';
740         else if (*sks->sortRelation == Z_SortKeySpec_descending)
741             sort_criteria[i].relation = 'D';
742         else
743         {
744             zh->errCode = 214;
745             return;
746         }
747         if (sks->sortElement->which == Z_SortElement_databaseSpecific)
748         {
749             zh->errCode = 210;
750             return;
751         }
752         else if (sks->sortElement->which != Z_SortElement_generic)
753         {
754             zh->errCode = 237;
755             return;
756         }       
757         sk = sks->sortElement->u.generic;
758         switch (sk->which)
759         {
760         case Z_SortKey_sortField:
761             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
762             zh->errCode = 207;
763             return;
764         case Z_SortKey_elementSpec:
765             yaz_log (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
766             zh->errCode = 207;
767             return;
768         case Z_SortKey_sortAttributes:
769             yaz_log (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
770             sort_criteria[i].attrUse =
771                 zebra_maps_sort (zh->reg->zebra_maps,
772                                  sk->u.sortAttributes,
773                                  &sort_criteria[i].numerical);
774             yaz_log (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
775             if (sort_criteria[i].attrUse == -1)
776             {
777                 zh->errCode = 116;
778                 return;
779             }
780             if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
781             {
782                 zh->errCode = 207;
783                 return;
784             }
785             break;
786         }
787     }
788     rfd = rset_open (rset, RSETF_READ);
789     while (rset_read (rset, rfd, &key, &term_index))
790     {
791         kno++;
792         if (key.sysno != psysno)
793         {
794             (sset->hits)++;
795             psysno = key.sysno;
796             resultSetInsertSort (zh, sset,
797                                  sort_criteria, num_criteria, psysno);
798         }
799     }
800     rset_close (rset, rfd);
801
802     yaz_log (LOG_LOG, "%d keys, %d sysnos, sort", kno, sset->hits);
803     for (i = 0; i < rset->no_rset_terms; i++)
804         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
805                  rset->rset_terms[i]->name,
806                  rset->rset_terms[i]->nn,
807                  rset->rset_terms[i]->flags,
808                  rset->rset_terms[i]->count);
809
810     *sort_status = Z_SortResponse_success;
811 }
812
813 RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
814 {
815     ZebraSet s;
816
817     if ((s = resultSetGet (zh, resultSetId)))
818         return s->rset;
819     return NULL;
820 }
821
822 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
823 {
824     int kno = 0;
825     struct it_key key;
826     RSFD rfd;
827     int term_index, i;
828     ZebraRankClass rank_class;
829     struct rank_control *rc;
830     struct zset_sort_info *sort_info;
831     const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
832
833     sort_info = zebraSet->sort_info;
834     sort_info->num_entries = 0;
835     zebraSet->hits = 0;
836     rfd = rset_open (rset, RSETF_READ);
837
838     rank_class = zebraRankLookup (zh, rank_handler_name);
839     if (!rank_class)
840     {
841         yaz_log (LOG_WARN, "No such rank handler: %s", rank_handler_name);
842         return;
843     }
844     rc = rank_class->control;
845
846     if (rset_read (rset, rfd, &key, &term_index))
847     {
848         int psysno = key.sysno;
849         int score;
850         void *handle =
851             (*rc->begin) (zh->reg, rank_class->class_handle, rset);
852         (zebraSet->hits)++;
853         do
854         {
855             kno++;
856             if (key.sysno != psysno)
857             {
858                 score = (*rc->calc) (handle, psysno);
859
860                 resultSetInsertRank (zh, sort_info, psysno, score, 'A');
861                 (zebraSet->hits)++;
862                 psysno = key.sysno;
863             }
864             (*rc->add) (handle, key.seqno, term_index);
865         }
866         while (rset_read (rset, rfd, &key, &term_index));
867         score = (*rc->calc) (handle, psysno);
868         resultSetInsertRank (zh, sort_info, psysno, score, 'A');
869         (*rc->end) (zh->reg, handle);
870     }
871     rset_close (rset, rfd);
872
873     yaz_log (LOG_LOG, "%d keys, %d sysnos, rank", kno, zebraSet->hits);
874     for (i = 0; i < rset->no_rset_terms; i++)
875         yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
876                  rset->rset_terms[i]->name,
877                  rset->rset_terms[i]->nn,
878                  rset->rset_terms[i]->flags,
879                  rset->rset_terms[i]->count);
880     
881 }
882
883 ZebraRankClass zebraRankLookup (ZebraHandle zh, const char *name)
884 {
885     ZebraRankClass p = zh->reg->rank_classes;
886     while (p && strcmp (p->control->name, name))
887         p = p->next;
888     if (p && !p->init_flag)
889     {
890         if (p->control->create)
891             p->class_handle = (*p->control->create)(zh);
892         p->init_flag = 1;
893     }
894     return p;
895 }
896
897 void zebraRankInstall (struct zebra_register *reg, struct rank_control *ctrl)
898 {
899     ZebraRankClass p = (ZebraRankClass) xmalloc (sizeof(*p));
900     p->control = (struct rank_control *) xmalloc (sizeof(*p->control));
901     memcpy (p->control, ctrl, sizeof(*p->control));
902     p->control->name = xstrdup (ctrl->name);
903     p->init_flag = 0;
904     p->next = reg->rank_classes;
905     reg->rank_classes = p;
906 }
907
908 void zebraRankDestroy (struct zebra_register *reg)
909 {
910     ZebraRankClass p = reg->rank_classes;
911     while (p)
912     {
913         ZebraRankClass p_next = p->next;
914         if (p->init_flag && p->control->destroy)
915             (*p->control->destroy)(reg, p->class_handle);
916         xfree (p->control->name);
917         xfree (p->control);
918         xfree (p);
919         p = p_next;
920     }
921     reg->rank_classes = NULL;
922 }