e90ef028b7bd06bfbe82bdcf89a009ed8b7860e4
[yaz-moved-to-github.git] / src / zoom-record-cache.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file zoom-record-cache.c
7  * \brief Implements ZOOM record caching
8  */
9
10 #include <assert.h>
11 #include <string.h>
12 #include <errno.h>
13 #include "zoom-p.h"
14
15 #include <yaz/diagbib1.h>
16 #include <yaz/shptr.h>
17
18 #if SHPTR
19 YAZ_SHPTR_TYPE(WRBUF)
20 #endif
21
22 struct ZOOM_record_p {
23     ODR odr;
24 #if SHPTR
25     struct WRBUF_shptr *record_wrbuf;
26 #else
27     WRBUF wrbuf;
28 #endif
29
30     Z_NamePlusRecord *npr;
31     const char *schema;
32
33     const char *diag_uri;
34     const char *diag_message;
35     const char *diag_details;
36     const char *diag_set;
37 };
38
39 struct ZOOM_record_cache_p {
40     struct ZOOM_record_p rec;
41     char *elementSetName;
42     char *syntax;
43     char *schema;
44     int pos;
45     ZOOM_record_cache next;
46 };
47
48
49 static int strcmp_null(const char *v1, const char *v2)
50 {
51     if (!v1 && !v2)
52         return 0;
53     if (!v1 || !v2)
54         return -1;
55     return strcmp(v1, v2);
56 }
57
58 static size_t record_hash(int pos)
59 {
60     if (pos < 0)
61         pos = 0;
62     return pos % RECORD_HASH_SIZE;
63 }
64
65 void ZOOM_record_cache_add(ZOOM_resultset r, Z_NamePlusRecord *npr, 
66                            int pos,
67                            const char *syntax, const char *elementSetName,
68                            const char *schema,
69                            Z_SRW_diagnostic *diag)
70 {
71     ZOOM_record_cache rc = 0;
72     
73     ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
74     ZOOM_connection_put_event(r->connection, event);
75
76     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
77     {
78         if (pos == rc->pos 
79             && strcmp_null(r->schema, rc->schema) == 0
80             && strcmp_null(elementSetName,rc->elementSetName) == 0
81             && strcmp_null(syntax, rc->syntax) == 0)
82             break;
83     }
84     if (!rc)
85     {
86         rc = (ZOOM_record_cache) odr_malloc(r->odr, sizeof(*rc));
87         rc->rec.odr = 0;
88 #if SHPTR
89         YAZ_SHPTR_INC(r->record_wrbuf);
90         rc->rec.record_wrbuf = r->record_wrbuf;
91 #else
92         rc->rec.wrbuf = 0;
93 #endif
94         rc->elementSetName = odr_strdup_null(r->odr, elementSetName);
95         
96         rc->syntax = odr_strdup_null(r->odr, syntax);
97         
98         rc->schema = odr_strdup_null(r->odr, r->schema);
99
100         rc->pos = pos;
101         rc->next = r->record_hash[record_hash(pos)];
102         r->record_hash[record_hash(pos)] = rc;
103     }
104     rc->rec.npr = npr;
105     rc->rec.schema = odr_strdup_null(r->odr, schema);
106     rc->rec.diag_set = 0;
107     rc->rec.diag_uri = 0;
108     rc->rec.diag_message = 0;
109     rc->rec.diag_details = 0;
110     if (diag)
111     {
112         if (diag->uri)
113         {
114             char *cp;
115             rc->rec.diag_set = odr_strdup(r->odr, diag->uri);
116             if ((cp = strrchr(rc->rec.diag_set, '/')))
117                 *cp = '\0';
118             rc->rec.diag_uri = odr_strdup(r->odr, diag->uri);
119         }
120         rc->rec.diag_message = odr_strdup_null(r->odr, diag->message);            
121         rc->rec.diag_details = odr_strdup_null(r->odr, diag->details);
122     }
123 }
124
125 ZOOM_record ZOOM_record_cache_lookup(ZOOM_resultset r, int pos,
126                                      const char *syntax,
127                                      const char *elementSetName)
128 {
129     ZOOM_record_cache rc;
130     
131     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
132     {
133         if (pos == rc->pos)
134         {
135             if (strcmp_null(r->schema, rc->schema))
136                 continue;
137             if (strcmp_null(elementSetName,rc->elementSetName))
138                 continue;
139             if (strcmp_null(syntax, rc->syntax))
140                 continue;
141             return &rc->rec;
142         }
143     }
144     return 0;
145 }
146
147 ZOOM_API(ZOOM_record)
148     ZOOM_record_clone(ZOOM_record srec)
149 {
150     char *buf;
151     int size;
152     ODR odr_enc;
153     ZOOM_record nrec;
154
155     odr_enc = odr_createmem(ODR_ENCODE);
156     if (!z_NamePlusRecord(odr_enc, &srec->npr, 0, 0))
157         return 0;
158     buf = odr_getbuf(odr_enc, &size, 0);
159     
160     nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
161     nrec->odr = odr_createmem(ODR_DECODE);
162 #if SHPTR
163     nrec->record_wrbuf = 0;
164 #else
165     nrec->wrbuf = 0;
166 #endif
167     odr_setbuf(nrec->odr, buf, size, 0);
168     z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
169     
170     nrec->schema = odr_strdup_null(nrec->odr, srec->schema);
171     nrec->diag_uri = odr_strdup_null(nrec->odr, srec->diag_uri);
172     nrec->diag_message = odr_strdup_null(nrec->odr, srec->diag_message);
173     nrec->diag_details = odr_strdup_null(nrec->odr, srec->diag_details);
174     nrec->diag_set = odr_strdup_null(nrec->odr, srec->diag_set);
175     odr_destroy(odr_enc);
176     return nrec;
177 }
178
179 static void ZOOM_record_release(ZOOM_record rec)
180 {
181     if (!rec)
182         return;
183
184 #if SHPTR
185     if (rec->record_wrbuf)
186         YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
187 #else
188     if (rec->wrbuf)
189         wrbuf_destroy(rec->wrbuf);
190 #endif
191
192     if (rec->odr)
193         odr_destroy(rec->odr);
194 }
195
196 ZOOM_API(void)
197     ZOOM_resultset_cache_reset(ZOOM_resultset r)
198 {
199     int i;
200     for (i = 0; i<RECORD_HASH_SIZE; i++)
201     {
202         ZOOM_record_cache rc;
203         for (rc = r->record_hash[i]; rc; rc = rc->next)
204         {
205             ZOOM_record_release(&rc->rec);
206         }
207         r->record_hash[i] = 0;
208     }
209 }
210
211
212 ZOOM_API(const char *)
213     ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
214 {
215     WRBUF wrbuf;
216     
217     if (len)
218         *len = 0; /* default return */
219         
220     if (!rec || !rec->npr)
221         return 0;
222
223 #if SHPTR
224     if (!rec->record_wrbuf)
225     {
226         WRBUF w = wrbuf_alloc();
227         YAZ_SHPTR_INIT(rec->record_wrbuf, w);
228     }
229     wrbuf = rec->record_wrbuf->ptr;
230 #else
231     if (!rec->wrbuf)
232         rec->wrbuf = wrbuf_alloc();
233     wrbuf = rec->wrbuf;
234 #endif
235     return ZOOM_npr_format(rec->npr, rec->schema, wrbuf, type_spec, len);
236 }
237
238 ZOOM_API(int)
239     ZOOM_record_error(ZOOM_record rec, const char **cp,
240                       const char **addinfo, const char **diagset)
241 {
242     Z_NamePlusRecord *npr;
243     
244     if (!rec)
245         return 0;
246
247     npr = rec->npr;
248     if (rec->diag_uri)
249     {
250         if (cp)
251             *cp = rec->diag_message;
252         if (addinfo)
253             *addinfo = rec->diag_details;
254         if (diagset)
255             *diagset = rec->diag_set;
256         return ZOOM_uri_to_code(rec->diag_uri);
257     }
258     if (npr && npr->which == Z_NamePlusRecord_surrogateDiagnostic)
259     {
260         Z_DiagRec *diag_rec = npr->u.surrogateDiagnostic;
261         int error = YAZ_BIB1_UNSPECIFIED_ERROR;
262         const char *add = 0;
263
264         if (diag_rec->which == Z_DiagRec_defaultFormat)
265         {
266             Z_DefaultDiagFormat *ddf = diag_rec->u.defaultFormat;
267             oid_class oclass;
268     
269             error = *ddf->condition;
270             switch (ddf->which)
271             {
272             case Z_DefaultDiagFormat_v2Addinfo:
273                 add = ddf->u.v2Addinfo;
274                 break;
275             case Z_DefaultDiagFormat_v3Addinfo:
276                 add = ddf->u.v3Addinfo;
277                 break;
278             }
279             if (diagset)
280                 *diagset =
281                     yaz_oid_to_string(yaz_oid_std(),
282                                       ddf->diagnosticSetId, &oclass);
283         }
284         else
285         {
286             if (diagset)
287                 *diagset = "Bib-1";
288         }
289         if (addinfo)
290             *addinfo = add ? add : "";
291         if (cp)
292             *cp = diagbib1_str(error);
293         return error;
294     }
295     return 0;
296 }
297
298 ZOOM_API(void)
299     ZOOM_record_destroy(ZOOM_record rec)
300 {
301     ZOOM_record_release(rec);
302     xfree(rec);
303 }
304
305 /*
306  * Local variables:
307  * c-basic-offset: 4
308  * c-file-style: "Stroustrup"
309  * indent-tabs-mode: nil
310  * End:
311  * vim: shiftwidth=4 tabstop=8 expandtab
312  */
313