1 /*-
2 * Copyright (c) 1996, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file LICENSE for license information.
5 *
6 * $Id$
7 */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12 #include "dbinc/db_page.h"
13 #include "dbinc/db_am.h"
14 #include "dbinc/heap.h"
15
16 /*
17 * __db_ret --
18 * Build return DBT.
19 *
20 * PUBLIC: int __db_ret __P((DBC *,
21 * PUBLIC: PAGE *, u_int32_t, DBT *, void **, u_int32_t *));
22 */
23 int
__db_ret(dbc,h,indx,dbt,memp,memsize)24 __db_ret(dbc, h, indx, dbt, memp, memsize)
25 DBC *dbc;
26 PAGE *h;
27 u_int32_t indx;
28 DBT *dbt;
29 void **memp;
30 u_int32_t *memsize;
31 {
32 BBLOB bl;
33 BKEYDATA *bk;
34 BOVERFLOW *bo;
35 DB *dbp;
36 ENV *env;
37 HBLOB hblob;
38 HEAPBLOBHDR bhdr;
39 HEAPHDR *hdr;
40 db_seq_t blob_id;
41 int ret;
42 HOFFPAGE ho;
43 off_t blob_size;
44 u_int32_t len;
45 u_int8_t *hk;
46 void *data;
47
48 if (F_ISSET(dbt, DB_DBT_READONLY))
49 return (0);
50 ret = 0;
51 dbp = dbc->dbp;
52 env = dbp->env;
53
54 switch (TYPE(h)) {
55 case P_HASH_UNSORTED:
56 case P_HASH:
57 hk = P_ENTRY(dbp, h, indx);
58 if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
59 memcpy(&ho, hk, sizeof(HOFFPAGE));
60 return (__db_goff(dbc, dbt,
61 ho.tlen, ho.pgno, memp, memsize));
62 } else if (HPAGE_PTYPE(hk) == H_BLOB) {
63 /* Get the record instead of the blob item. */
64 if (F_ISSET(dbt, DB_DBT_BLOB_REC)) {
65 data = P_ENTRY(dbp, h, indx);
66 len = HBLOB_SIZE;
67 break;
68 }
69 memcpy(&hblob, hk, HBLOB_SIZE);
70 blob_id = (db_seq_t)hblob.id;
71 GET_BLOB_SIZE(env, hblob, blob_size, ret);
72 if (ret != 0)
73 return (ret);
74 return (__blob_get(
75 dbc, dbt, blob_id, blob_size, memp, memsize));
76 }
77 len = LEN_HKEYDATA(dbp, h, dbp->pgsize, indx);
78 data = HKEYDATA_DATA(hk);
79 break;
80 case P_HEAP:
81 hdr = (HEAPHDR *)P_ENTRY(dbp, h, indx);
82 if (F_ISSET(hdr,(HEAP_RECSPLIT | HEAP_RECFIRST)))
83 return (__heapc_gsplit(dbc, dbt, memp, memsize));
84 else if (F_ISSET(hdr, HEAP_RECBLOB)) {
85 /* Get the record instead of the blob item. */
86 if (F_ISSET(dbt, DB_DBT_BLOB_REC)) {
87 data = P_ENTRY(dbp, h, indx);
88 len = HEAPBLOBREC_SIZE;
89 break;
90 }
91 memcpy(&bhdr, hdr, HEAPBLOBREC_SIZE);
92 blob_id = (db_seq_t)bhdr.id;
93 GET_BLOB_SIZE(env, bhdr, blob_size, ret);
94 if (ret != 0)
95 return (ret);
96 return (__blob_get(
97 dbc, dbt, blob_id, blob_size, memp, memsize));
98 }
99 len = hdr->size;
100 data = (u_int8_t *)hdr + sizeof(HEAPHDR);
101 break;
102 case P_LBTREE:
103 case P_LDUP:
104 case P_LRECNO:
105 bk = GET_BKEYDATA(dbp, h, indx);
106 if (B_TYPE(bk->type) == B_OVERFLOW) {
107 bo = (BOVERFLOW *)bk;
108 return (__db_goff(dbc, dbt,
109 bo->tlen, bo->pgno, memp, memsize));
110 } else if (B_TYPE(bk->type) == B_BLOB) {
111 /* Get the record instead of the blob item. */
112 if (F_ISSET(dbt, DB_DBT_BLOB_REC)) {
113 data = P_ENTRY(dbp, h, indx);
114 len = BBLOB_SIZE;
115 break;
116 }
117 memcpy(&bl, bk, BBLOB_SIZE);
118 blob_id = (db_seq_t)bl.id;
119 GET_BLOB_SIZE(env, bl, blob_size, ret);
120 if (ret != 0)
121 return (ret);
122 return (__blob_get(
123 dbc, dbt, blob_id, blob_size, memp, memsize));
124 }
125 len = bk->len;
126 data = bk->data;
127 break;
128 default:
129 return (__db_pgfmt(dbp->env, h->pgno));
130 }
131
132 return (__db_retcopy(dbp->env, dbt, data, len, memp, memsize));
133 }
134
135 /*
136 * __db_retcopy --
137 * Copy the returned data into the user's DBT, handling special flags.
138 *
139 * PUBLIC: int __db_retcopy __P((ENV *, DBT *,
140 * PUBLIC: void *, u_int32_t, void **, u_int32_t *));
141 */
142 int
__db_retcopy(env,dbt,data,len,memp,memsize)143 __db_retcopy(env, dbt, data, len, memp, memsize)
144 ENV *env;
145 DBT *dbt;
146 void *data;
147 u_int32_t len;
148 void **memp;
149 u_int32_t *memsize;
150 {
151 int ret;
152
153 if (F_ISSET(dbt, DB_DBT_READONLY))
154 return (0);
155 ret = 0;
156
157 /* If returning a partial record, reset the length. */
158 if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
159 data = (u_int8_t *)data + dbt->doff;
160 if (len > dbt->doff) {
161 len -= dbt->doff;
162 if (len > dbt->dlen)
163 len = dbt->dlen;
164 } else
165 len = 0;
166 }
167
168 /*
169 * Allocate memory to be owned by the application: DB_DBT_MALLOC,
170 * DB_DBT_REALLOC.
171 *
172 * !!!
173 * We always allocate memory, even if we're copying out 0 bytes. This
174 * guarantees consistency, i.e., the application can always free memory
175 * without concern as to how many bytes of the record were requested.
176 *
177 * Use the memory specified by the application: DB_DBT_USERMEM.
178 *
179 * !!!
180 * If the length we're going to copy is 0, the application-supplied
181 * memory pointer is allowed to be NULL.
182 */
183 if (F_ISSET(dbt, DB_DBT_USERCOPY)) {
184 dbt->size = len;
185 return (len == 0 ? 0 : env->dbt_usercopy(dbt, 0, data,
186 len, DB_USERCOPY_SETDATA));
187
188 } else if (F_ISSET(dbt, DB_DBT_MALLOC))
189 ret = __os_umalloc(env, len, &dbt->data);
190 else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
191 if (dbt->data == NULL || dbt->size == 0 || dbt->size < len)
192 ret = __os_urealloc(env, len, &dbt->data);
193 } else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
194 if (len != 0 && (dbt->data == NULL || dbt->ulen < len))
195 ret = DB_BUFFER_SMALL;
196 } else if (memp == NULL || memsize == NULL)
197 ret = USR_ERR(env, EINVAL);
198 else {
199 if (len != 0 && (*memsize == 0 || *memsize < len)) {
200 if ((ret = __os_realloc(env, len, memp)) == 0)
201 *memsize = len;
202 else
203 *memsize = 0;
204 }
205 if (ret == 0)
206 dbt->data = *memp;
207 }
208
209 if (ret == 0 && len != 0)
210 memcpy(dbt->data, data, len);
211
212 /*
213 * Return the length of the returned record in the DBT size field.
214 * This satisfies the requirement that if we're using user memory
215 * and insufficient memory was provided, return the amount necessary
216 * in the size field.
217 */
218 dbt->size = len;
219
220 return (ret);
221 }
222
223 /*
224 * __db_dbt_clone --
225 * Clone a DBT from another DBT.
226 * The input dest DBT must be a zero initialized DBT that will be populated.
227 * The function does not allocate a dest DBT to allow for cloning into stack
228 * or locally allocated variables. It is the callers responsibility to free
229 * the memory allocated in dest->data.
230 *
231 * PUBLIC: int __db_dbt_clone __P((ENV *, DBT *, const DBT *));
232 */
233 int
__db_dbt_clone(env,dest,src)234 __db_dbt_clone(env, dest, src)
235 ENV *env;
236 DBT *dest;
237 const DBT *src;
238 {
239 u_int32_t err_flags;
240 int ret;
241
242 DB_ASSERT(env, dest->data == NULL);
243
244 ret = 0;
245
246 /* The function does not support the following DBT flags. */
247 err_flags = DB_DBT_MALLOC | DB_DBT_REALLOC |
248 DB_DBT_MULTIPLE | DB_DBT_PARTIAL;
249 if (F_ISSET(src, err_flags)) {
250 __db_errx(env, DB_STR("0758",
251 "Unsupported flags when cloning the DBT."));
252 return (EINVAL);
253 }
254
255 if ((ret = __os_malloc(env, src->size, &dest->data)) != 0)
256 return (ret);
257
258 memcpy(dest->data, src->data, src->size);
259 dest->ulen = src->size;
260 dest->size = src->size;
261 dest->flags = DB_DBT_USERMEM;
262
263 return (ret);
264 }
265
266 /*
267 * __db_dbt_clone_free --
268 * Free a DBT cloned by __db_dbt_clone
269 *
270 * PUBLIC: int __db_dbt_clone_free __P((ENV *, DBT *));
271 */
272 int
__db_dbt_clone_free(env,dbt)273 __db_dbt_clone_free(env, dbt)
274 ENV *env;
275 DBT *dbt;
276 {
277 /* Currently only DB_DBT_USERMEM is supported. */
278 if (dbt->flags != DB_DBT_USERMEM) {
279 __db_errx(env, DB_STR("0759",
280 "Unsupported flags when freeing the cloned DBT."));
281 return (EINVAL);
282 }
283
284 if (dbt->data != NULL)
285 __os_free(env, dbt->data);
286 dbt->size = dbt->ulen = 0;
287
288 return (0);
289 }
290