disable-zoom configure option
[yazpp-moved-to-github.git] / src / yaz-z-server-sr.cpp
1 /*
2  * Copyright (c) 2000-2001, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-z-server-sr.cpp,v 1.5 2002-10-09 12:50:26 adam Exp $
6  *
7  */
8
9 #include <yaz/log.h>
10 #include <yaz++/z-server.h>
11
12 Z_Records *Yaz_Facility_Retrieval::pack_records (Yaz_Z_Server *s,
13                                                  const char *resultSetName,
14                                                  int start, int xnum,
15                                                  Z_RecordComposition *comp,
16                                                  int *next, int *pres,
17                                                  int *format)
18 {
19     int recno, total_length = 0, toget = xnum, dumped_records = 0;
20     Z_Records *records =
21         (Z_Records *) odr_malloc (odr_encode(), sizeof(*records));
22     Z_NamePlusRecordList *reclist =
23         (Z_NamePlusRecordList *) odr_malloc (odr_encode(), sizeof(*reclist));
24     Z_NamePlusRecord **list =
25         (Z_NamePlusRecord **) odr_malloc (odr_encode(), sizeof(*list) * toget);
26
27     records->which = Z_Records_DBOSD;
28     records->u.databaseOrSurDiagnostics = reclist;
29     reclist->num_records = 0;
30     reclist->records = list;
31     *pres = Z_PRES_SUCCESS;
32     *next = 0;
33
34     yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
35     yaz_log(LOG_LOG, "pms=%d, mrs=%d", m_preferredMessageSize,
36             m_maximumRecordSize);
37     for (recno = start; reclist->num_records < toget; recno++)
38     {
39         Z_NamePlusRecord *this_rec =
40             (Z_NamePlusRecord *) odr_malloc (odr_encode(), sizeof(*this_rec));
41         this_rec->databaseName = 0;
42         this_rec->which = Z_NamePlusRecord_databaseRecord;
43         this_rec->u.databaseRecord = 0;
44
45         int this_length = 0;
46
47         sr_record (resultSetName, recno, format, comp, this_rec, records);
48
49         if (records->which != Z_Records_DBOSD)
50         {
51             *pres = Z_PRES_FAILURE;
52             return records;
53         }
54
55         if (this_rec->which == Z_NamePlusRecord_databaseRecord &&
56             this_rec->u.databaseRecord == 0)
57         {   // handler did not return a record..
58             create_surrogateDiagnostics(odr_encode(), this_rec, 0, 14, 0);
59         }
60         /*
61          * we get the number of bytes allocated on the stream before any
62          * allocation done by the backend - this should give us a reasonable
63          * idea of the total size of the data so far.
64          */
65         total_length = odr_total(odr_encode()) - dumped_records;
66         this_length = odr_total(odr_encode()) - total_length;
67         yaz_log(LOG_LOG, "  fetched record, len=%d, total=%d",
68                 this_length, total_length);
69         if (this_length + total_length > m_preferredMessageSize)
70         {
71             /* record is small enough, really */
72             if (this_length <= m_preferredMessageSize)
73             {
74                 yaz_log(LOG_LOG, "  Dropped last normal-sized record");
75                 *pres = Z_PRES_PARTIAL_2;
76                 break;
77             }
78             if (this_length >= m_maximumRecordSize)
79             {   /* too big entirely */
80                 yaz_log(LOG_LOG, "Record > maxrcdsz");
81                 reclist->records[reclist->num_records] = this_rec;
82                 create_surrogateDiagnostics(odr_encode(), this_rec,
83                                             this_rec->databaseName, 17, 0);
84                 reclist->num_records++;
85                 *next = recno + 1;
86                 dumped_records += this_length;
87                 continue;
88             }
89             else /* record can only be fetched by itself */
90             {
91                 yaz_log(LOG_LOG, "  Record > prefmsgsz");
92                 if (toget > 1)
93                 {
94                     yaz_log(LOG_DEBUG, "  Dropped it");
95                     reclist->records[reclist->num_records] = this_rec;
96                     create_surrogateDiagnostics(odr_encode(), this_rec,
97                                                 this_rec->databaseName,
98                                                 16, 0);
99                     reclist->num_records++;
100                     // *next = freq.last_in_set ? 0 : recno + 1;
101                     *next = recno + 1;
102                     dumped_records += this_length;
103                     continue;
104                 }
105             }
106         }
107         reclist->records[reclist->num_records] = this_rec;
108         reclist->num_records++;
109         *next = recno + 1;
110     }
111     return records;
112 }
113
114 void Yaz_Facility_Retrieval::fetch_via_piggyback (Yaz_Z_Server *s,
115                                                   Z_SearchRequest *req,
116                                                   Z_SearchResponse *res)
117 {
118     bool_t *sr = (bool_t *)odr_malloc (odr_encode(), sizeof(*sr));
119     *sr = 1;
120     
121     int toget = 0;
122     
123     Z_RecordComposition comp, *compp = 0;
124     int hits = *res->resultCount;
125     
126     int *nulint = (int *)odr_malloc (odr_encode(), sizeof(*nulint));
127     *nulint = 0;
128     
129     comp.which = Z_RecordComp_simple;
130     /* how many records does the user agent want, then? */
131     if (hits <= *req->smallSetUpperBound)
132     {
133         toget = hits;
134         if ((comp.u.simple = req->smallSetElementSetNames))
135             compp = &comp;
136     }
137     else if (hits < *req->largeSetLowerBound)
138     {
139         toget = *req->mediumSetPresentNumber;
140         if (toget > hits)
141             toget = hits;
142         if ((comp.u.simple = req->mediumSetElementSetNames))
143             compp = &comp;
144     }
145     
146     if (toget && !res->records)
147     {
148         res->presentStatus = (int *) odr_malloc (odr_encode(), sizeof(int));
149         *res->presentStatus = Z_PRES_SUCCESS;
150         res->records =
151             pack_records(s, req->resultSetName, 1, toget, compp, 
152                          res->nextResultSetPosition,
153                          res->presentStatus,
154                          req->preferredRecordSyntax);
155         if (!res->records)
156             return;
157         if (res->records->which == Z_Records_DBOSD)
158             *res->numberOfRecordsReturned =
159                 res->records->u.databaseOrSurDiagnostics->num_records;
160         res->searchStatus = sr;
161         res->resultSetStatus = 0;
162     }
163     else
164     {
165         if (hits)
166             *res->nextResultSetPosition = 1;
167         res->numberOfRecordsReturned = nulint;
168         res->searchStatus = sr;
169         res->resultSetStatus = 0;
170         res->presentStatus = 0;
171     }
172 }
173
174 void Yaz_Facility_Retrieval::fetch_via_present (Yaz_Z_Server *s,
175                                                 Z_PresentRequest *req,
176                                                 Z_PresentResponse *res)
177 {
178     res->records =
179         pack_records (s, req->resultSetId,*req->resultSetStartPoint, 
180                       *req->numberOfRecordsRequested,
181                       req->recordComposition,
182                       res->nextResultSetPosition,
183                       res->presentStatus,
184                       req->preferredRecordSyntax);
185     if (res->records->which == Z_Records_DBOSD)
186         *res->numberOfRecordsReturned =
187             res->records->u.databaseOrSurDiagnostics->num_records;
188 }
189
190 int Yaz_Facility_Retrieval::init(Yaz_Z_Server *s, Z_InitRequest *initRequest,
191                                  Z_InitResponse *initResponse)
192 {
193     Z_Options *req = initRequest->options;
194     Z_Options *res = initResponse->options;
195     
196     if (ODR_MASK_GET(req, Z_Options_search))
197         ODR_MASK_SET(res, Z_Options_search);
198     if (ODR_MASK_GET(req, Z_Options_present))
199         ODR_MASK_SET(res, Z_Options_present);
200     m_preferredMessageSize = *initRequest->preferredMessageSize;
201     m_maximumRecordSize = *initRequest->maximumRecordSize;
202     return sr_init (initRequest, initResponse);
203 }
204
205 ODR Yaz_Facility_Retrieval::odr_encode()
206 {
207     return m_odr_encode;
208 }
209
210 ODR Yaz_Facility_Retrieval::odr_decode()
211 {
212     return m_odr_decode;
213 }
214
215 int Yaz_Facility_Retrieval::recv(Yaz_Z_Server *s, Z_APDU *apdu_request)
216 {   
217     Z_APDU *apdu_response;
218     m_odr_encode = s->odr_encode();
219     m_odr_decode = s->odr_decode();
220     switch (apdu_request->which)
221     {
222     case Z_APDU_searchRequest:
223         yaz_log (LOG_LOG, "got SearchRequest p=%p", this);
224         apdu_response = s->create_Z_PDU(Z_APDU_searchResponse);
225         s->transfer_referenceId(apdu_request, apdu_response);
226         sr_search (apdu_request->u.searchRequest,
227                        apdu_response->u.searchResponse);
228         if (!apdu_response->u.searchResponse->records)
229         {
230             fetch_via_piggyback(s, apdu_request->u.searchRequest,
231                                 apdu_response->u.searchResponse);
232         }
233         s->send_Z_PDU(apdu_response);
234         return 1;
235     case Z_APDU_presentRequest:
236         yaz_log (LOG_LOG, "got PresentRequest p=%p", this);
237         apdu_response = s->create_Z_PDU(Z_APDU_presentResponse);
238         s->transfer_referenceId(apdu_request, apdu_response);
239         sr_present (apdu_request->u.presentRequest,
240                     apdu_response->u.presentResponse);
241         if (!apdu_response->u.presentResponse->records)
242             fetch_via_present(s, apdu_request->u.presentRequest,
243                               apdu_response->u.presentResponse);
244         s->send_Z_PDU(apdu_response);
245         return 1;
246     }
247     return 0;
248 }