xref: /freebsd/lib/libc/db/recno/rec_get.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 
34 #include <errno.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <db.h>
42 #include "recno.h"
43 
44 /*
45  * __REC_GET -- Get a record from the btree.
46  *
47  * Parameters:
48  *	dbp:	pointer to access method
49  *	key:	key to find
50  *	data:	data to return
51  *	flag:	currently unused
52  *
53  * Returns:
54  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
55  */
56 int
57 __rec_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
58 {
59 	BTREE *t;
60 	EPG *e;
61 	recno_t nrec;
62 	int status;
63 
64 	t = dbp->internal;
65 
66 	/* Toss any page pinned across calls. */
67 	if (t->bt_pinned != NULL) {
68 		mpool_put(t->bt_mp, t->bt_pinned, 0);
69 		t->bt_pinned = NULL;
70 	}
71 
72 	/* Get currently doesn't take any flags, and keys of 0 are illegal. */
73 	if (flags || (nrec = *(recno_t *)key->data) == 0) {
74 		errno = EINVAL;
75 		return (RET_ERROR);
76 	}
77 
78 	/*
79 	 * If we haven't seen this record yet, try to find it in the
80 	 * original file.
81 	 */
82 	if (nrec > t->bt_nrecs) {
83 		if (F_ISSET(t, R_EOF | R_INMEM))
84 			return (RET_SPECIAL);
85 		if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
86 			return (status);
87 	}
88 
89 	--nrec;
90 	if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
91 		return (RET_ERROR);
92 
93 	status = __rec_ret(t, e, 0, NULL, data);
94 	if (F_ISSET(t, B_DB_LOCK))
95 		mpool_put(t->bt_mp, e->page, 0);
96 	else
97 		t->bt_pinned = e->page;
98 	return (status);
99 }
100 
101 /*
102  * __REC_FPIPE -- Get fixed length records from a pipe.
103  *
104  * Parameters:
105  *	t:	tree
106  *	cnt:	records to read
107  *
108  * Returns:
109  *	RET_ERROR, RET_SUCCESS
110  */
111 int
112 __rec_fpipe(BTREE *t, recno_t top)
113 {
114 	DBT data;
115 	recno_t nrec;
116 	size_t len;
117 	int ch;
118 	u_char *p;
119 
120 	if (t->bt_rdata.size < t->bt_reclen) {
121 		t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
122 		if (t->bt_rdata.data == NULL)
123 			return (RET_ERROR);
124 		t->bt_rdata.size = t->bt_reclen;
125 	}
126 	data.data = t->bt_rdata.data;
127 	data.size = t->bt_reclen;
128 
129 	for (nrec = t->bt_nrecs; nrec < top;) {
130 		len = t->bt_reclen;
131 		for (p = t->bt_rdata.data;; *p++ = ch)
132 			if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
133 				if (ch != EOF)
134 					*p = ch;
135 				if (len != 0)
136 					memset(p, t->bt_bval, len);
137 				if (__rec_iput(t,
138 				    nrec, &data, 0) != RET_SUCCESS)
139 					return (RET_ERROR);
140 				++nrec;
141 				break;
142 			}
143 		if (ch == EOF)
144 			break;
145 	}
146 	if (nrec < top) {
147 		F_SET(t, R_EOF);
148 		return (RET_SPECIAL);
149 	}
150 	return (RET_SUCCESS);
151 }
152 
153 /*
154  * __REC_VPIPE -- Get variable length records from a pipe.
155  *
156  * Parameters:
157  *	t:	tree
158  *	cnt:	records to read
159  *
160  * Returns:
161  *	RET_ERROR, RET_SUCCESS
162  */
163 int
164 __rec_vpipe(BTREE *t, recno_t top)
165 {
166 	DBT data;
167 	recno_t nrec;
168 	size_t len;
169 	size_t sz;
170 	int bval, ch;
171 	u_char *p;
172 
173 	bval = t->bt_bval;
174 	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
175 		for (p = t->bt_rdata.data,
176 		    sz = t->bt_rdata.size;; *p++ = ch, --sz) {
177 			if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
178 				data.data = t->bt_rdata.data;
179 				data.size = p - (u_char *)t->bt_rdata.data;
180 				if (ch == EOF && data.size == 0)
181 					break;
182 				if (__rec_iput(t, nrec, &data, 0)
183 				    != RET_SUCCESS)
184 					return (RET_ERROR);
185 				break;
186 			}
187 			if (sz == 0) {
188 				len = p - (u_char *)t->bt_rdata.data;
189 				t->bt_rdata.size += (sz = 256);
190 				t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_rdata.size);
191 				if (t->bt_rdata.data == NULL)
192 					return (RET_ERROR);
193 				p = (u_char *)t->bt_rdata.data + len;
194 			}
195 		}
196 		if (ch == EOF)
197 			break;
198 	}
199 	if (nrec < top) {
200 		F_SET(t, R_EOF);
201 		return (RET_SPECIAL);
202 	}
203 	return (RET_SUCCESS);
204 }
205 
206 /*
207  * __REC_FMAP -- Get fixed length records from a file.
208  *
209  * Parameters:
210  *	t:	tree
211  *	cnt:	records to read
212  *
213  * Returns:
214  *	RET_ERROR, RET_SUCCESS
215  */
216 int
217 __rec_fmap(BTREE *t, recno_t top)
218 {
219 	DBT data;
220 	recno_t nrec;
221 	u_char *sp, *ep, *p;
222 	size_t len;
223 
224 	if (t->bt_rdata.size < t->bt_reclen) {
225 		t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
226 		if (t->bt_rdata.data == NULL)
227 			return (RET_ERROR);
228 		t->bt_rdata.size = t->bt_reclen;
229 	}
230 	data.data = t->bt_rdata.data;
231 	data.size = t->bt_reclen;
232 
233 	sp = (u_char *)t->bt_cmap;
234 	ep = (u_char *)t->bt_emap;
235 	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
236 		if (sp >= ep) {
237 			F_SET(t, R_EOF);
238 			return (RET_SPECIAL);
239 		}
240 		len = t->bt_reclen;
241 		for (p = t->bt_rdata.data;
242 		    sp < ep && len > 0; *p++ = *sp++, --len);
243 		if (len != 0)
244 			memset(p, t->bt_bval, len);
245 		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
246 			return (RET_ERROR);
247 	}
248 	t->bt_cmap = (caddr_t)sp;
249 	return (RET_SUCCESS);
250 }
251 
252 /*
253  * __REC_VMAP -- Get variable length records from a file.
254  *
255  * Parameters:
256  *	t:	tree
257  *	cnt:	records to read
258  *
259  * Returns:
260  *	RET_ERROR, RET_SUCCESS
261  */
262 int
263 __rec_vmap(BTREE *t, recno_t top)
264 {
265 	DBT data;
266 	u_char *sp, *ep;
267 	recno_t nrec;
268 	int bval;
269 
270 	sp = (u_char *)t->bt_cmap;
271 	ep = (u_char *)t->bt_emap;
272 	bval = t->bt_bval;
273 
274 	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
275 		if (sp >= ep) {
276 			F_SET(t, R_EOF);
277 			return (RET_SPECIAL);
278 		}
279 		for (data.data = sp; sp < ep && *sp != bval; ++sp);
280 		data.size = sp - (u_char *)data.data;
281 		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
282 			return (RET_ERROR);
283 		++sp;
284 	}
285 	t->bt_cmap = (caddr_t)sp;
286 	return (RET_SUCCESS);
287 }
288