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