Extended the result set system. Added support for filtering/limits.
[idzebra-moved-to-github.git] / rset / rset.c
1 /* $Id: rset.c,v 1.45 2005-05-03 09:11:36 adam Exp $
2    Copyright (C) 1995-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 #include <stdio.h>
24 #include <string.h>
25 #include <idzebra/util.h>
26 #include <assert.h>
27 #include <yaz/nmem.h>
28 #include <rset.h>
29
30 static int log_level = 0;
31 static int log_level_initialized = 0;
32
33 /** \fn rfd_create_base(RSET rs)
34  *
35  * creates an rfd. Either allocates a new one, in which case the priv 
36  * pointer is null, and will have to be filled in, or picks up one 
37  * from the freelist, in which case the priv is already allocated,
38  * and presumably everything that hangs from it as well 
39  */
40 RSFD rfd_create_base(RSET rs)
41 {
42     RSFD rnew = rs->free_list;
43
44     if (rnew) 
45     {
46         rs->free_list = rnew->next;
47         assert(rnew->rset==rs);
48         yaz_log(log_level, "rfd_create_base (fl): rfd=%p rs=%p fl=%p priv=%p", 
49                 rnew, rs, rs->free_list, rnew->priv); 
50     } 
51     else
52     {
53         rnew = nmem_malloc(rs->nmem, sizeof(*rnew));
54         rnew->priv = 0;
55         rnew->rset = rs;
56         yaz_log(log_level, "rfd_create_base (new): rfd=%p rs=%p fl=%p priv=%p", 
57                 rnew, rs, rs->free_list, rnew->priv); 
58     }
59     rnew->next = rs->use_list;
60     rs->use_list = rnew;
61     return rnew;
62 }
63
64 /** \fn rfd_delete_base
65  *
66  * puts an rfd into the freelist of the rset. Only when the rset gets
67  * deleted, will all the nmem disappear */
68 void rfd_delete_base(RSFD rfd) 
69 {
70     RSFD *pfd;
71     RSET rs = rfd->rset;
72     yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
73             rfd, rs, rfd->priv, rs->free_list); 
74     for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
75         if (*pfd == rfd)
76         {
77             *pfd = (*pfd)->next;
78             rfd->next = rs->free_list;
79             rs->free_list = rfd;
80             return;
81         }
82     yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
83             rs->control->desc);
84 }
85
86 RSET rset_create_base(const struct rset_control *sel, 
87                       NMEM nmem, struct rset_key_control *kcontrol,
88                       int scope, TERMID term)
89 {
90     RSET rnew;
91     NMEM M;
92     /* assert(nmem); */ /* can not yet be used, api/t4 fails */
93     if (!log_level_initialized) 
94     {
95         log_level = yaz_log_module_level("rset");
96         log_level_initialized = 1;
97     }
98
99     if (nmem) 
100         M = nmem;
101     else
102         M = nmem_create();
103     rnew = (RSET) nmem_malloc(M, sizeof(*rnew));
104     yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rnew, nmem); 
105     rnew->nmem = M;
106     if (nmem)
107         rnew->my_nmem = 0;
108     else 
109         rnew->my_nmem = 1;
110     rnew->control = sel;
111     rnew->count = 1; /* refcount! */
112     rnew->priv = 0;
113     rnew->free_list = NULL;
114     rnew->use_list = NULL;
115     rnew->keycontrol = kcontrol;
116     (*kcontrol->inc)(kcontrol);
117     rnew->scope = scope;
118     rnew->term = term;
119     if (term)
120         term->rset = rnew;
121     return rnew;
122 }
123
124 void rset_delete (RSET rs)
125 {
126     (rs->count)--;
127     yaz_log(log_level, "rs_delete(%s), rs=%p, count=%d",
128             rs->control->desc, rs, rs->count); 
129     if (!rs->count)
130     {
131         if (rs->use_list)
132             yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
133                     rs->control->desc);
134         (*rs->control->f_delete)(rs);
135         (*rs->keycontrol->dec)(rs->keycontrol);
136         if (rs->my_nmem)
137             nmem_destroy(rs->nmem);
138     }
139 }
140
141 int rfd_is_last(RSFD rfd)
142 {
143     if (rfd->rset->use_list == rfd && rfd->next == 0)
144         return 1;
145     return 0;
146 }
147
148 RSET rset_dup (RSET rs)
149 {
150     (rs->count)++;
151     yaz_log(log_level, "rs_dup(%s), rs=%p, count=%d",
152             rs->control->desc, rs, rs->count); 
153     (*rs->keycontrol->inc)(rs->keycontrol);
154     return rs;
155 }
156
157 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
158                          const void *untilbuf)
159 {
160     int more = 1;
161     int cmp = rfd->rset->scope;
162     if (log_level)
163     {
164         yaz_log (log_level, "rset_default_forward starting '%s' (ct=%p rfd=%p)",
165                     rfd->rset->control->desc, rfd->rset, rfd);
166         /* key_logdump(log_level, untilbuf); */
167     }
168     while (cmp>=rfd->rset->scope && more)
169     {
170         if (log_level)  /* time-critical, check first */
171             yaz_log(log_level, "rset_default_forward looping m=%d c=%d",
172                     more, cmp);
173         more = rset_read(rfd, buf, term);
174         if (more)
175             cmp = (rfd->rset->keycontrol->cmp)(untilbuf, buf);
176     }
177     if (log_level)
178         yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
179                  more, cmp);
180
181     return more;
182 }
183
184 /** 
185  * rset_count uses rset_pos to get the total and returns that.
186  * This is ok for rsisamb/c/s, and for some other rsets, but in case of
187  * booleans etc it will give bad estimate, as nothing has been read
188  * from that rset
189  */
190 zint rset_count(RSET rs)
191 {
192     double cur, tot;
193     RSFD rfd = rset_open(rs, 0);
194     rset_pos(rfd, &cur, &tot);
195     rset_close(rfd);
196     return (zint) tot;
197 }
198
199
200 /** rset_get_no_terms is a getterms function for those that don't have any */
201 void rset_get_no_terms(RSET ct, TERMID *terms, int maxterms, int *curterm)
202 {
203     return;
204 }
205
206 /* rset_get_one_term gets that one term from an rset. Used by rsisamX */
207 void rset_get_one_term(RSET ct,TERMID *terms,int maxterms,int *curterm)
208 {
209     if (ct->term)
210     {
211         if (*curterm < maxterms)
212             terms[*curterm] = ct->term;
213         (*curterm)++;
214     }
215 }
216
217
218 TERMID rset_term_create (const char *name, int length, const char *flags,
219                                     int type, NMEM nmem)
220
221 {
222     TERMID t;
223     yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
224             name, length, flags, type, nmem);
225     t= (TERMID) nmem_malloc(nmem, sizeof(*t));
226     if (!name)
227         t->name = NULL;
228     else if (length == -1)
229         t->name = nmem_strdup(nmem, name);
230     else
231     {
232         t->name = (char*) nmem_malloc(nmem, length+1);
233         memcpy (t->name, name, length);
234         t->name[length] = '\0';
235     }
236     if (!flags)
237         t->flags = NULL;
238     else
239         t->flags = nmem_strdup(nmem, flags);
240     t->type = type;
241     t->rankpriv = 0;
242     t->rset = 0;
243     return t;
244 }