1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 2013 Oracle and/or its affiliates. All rights reserved.
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 BKEYDATA *bk;
33 BOVERFLOW *bo;
34 DB *dbp;
35 HEAPHDR *hdr;
36 HOFFPAGE ho;
37 u_int32_t len;
38 u_int8_t *hk;
39 void *data;
40
41 if (F_ISSET(dbt, DB_DBT_READONLY))
42 return (0);
43 dbp = dbc->dbp;
44
45 switch (TYPE(h)) {
46 case P_HASH_UNSORTED:
47 case P_HASH:
48 hk = P_ENTRY(dbp, h, indx);
49 if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
50 memcpy(&ho, hk, sizeof(HOFFPAGE));
51 return (__db_goff(dbc, dbt,
52 ho.tlen, ho.pgno, memp, memsize));
53 }
54 len = LEN_HKEYDATA(dbp, h, dbp->pgsize, indx);
55 data = HKEYDATA_DATA(hk);
56 break;
57 case P_HEAP:
58 hdr = (HEAPHDR *)P_ENTRY(dbp, h, indx);
59 if (F_ISSET(hdr,(HEAP_RECSPLIT | HEAP_RECFIRST)))
60 return (__heapc_gsplit(dbc, dbt, memp, memsize));
61 len = hdr->size;
62 data = (u_int8_t *)hdr + sizeof(HEAPHDR);
63 break;
64 case P_LBTREE:
65 case P_LDUP:
66 case P_LRECNO:
67 bk = GET_BKEYDATA(dbp, h, indx);
68 if (B_TYPE(bk->type) == B_OVERFLOW) {
69 bo = (BOVERFLOW *)bk;
70 return (__db_goff(dbc, dbt,
71 bo->tlen, bo->pgno, memp, memsize));
72 }
73 len = bk->len;
74 data = bk->data;
75 break;
76 default:
77 return (__db_pgfmt(dbp->env, h->pgno));
78 }
79
80 return (__db_retcopy(dbp->env, dbt, data, len, memp, memsize));
81 }
82
83 /*
84 * __db_retcopy --
85 * Copy the returned data into the user's DBT, handling special flags.
86 *
87 * PUBLIC: int __db_retcopy __P((ENV *, DBT *,
88 * PUBLIC: void *, u_int32_t, void **, u_int32_t *));
89 */
90 int
__db_retcopy(env,dbt,data,len,memp,memsize)91 __db_retcopy(env, dbt, data, len, memp, memsize)
92 ENV *env;
93 DBT *dbt;
94 void *data;
95 u_int32_t len;
96 void **memp;
97 u_int32_t *memsize;
98 {
99 int ret;
100
101 if (F_ISSET(dbt, DB_DBT_READONLY))
102 return (0);
103 ret = 0;
104
105 /* If returning a partial record, reset the length. */
106 if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
107 data = (u_int8_t *)data + dbt->doff;
108 if (len > dbt->doff) {
109 len -= dbt->doff;
110 if (len > dbt->dlen)
111 len = dbt->dlen;
112 } else
113 len = 0;
114 }
115
116 /*
117 * Allocate memory to be owned by the application: DB_DBT_MALLOC,
118 * DB_DBT_REALLOC.
119 *
120 * !!!
121 * We always allocate memory, even if we're copying out 0 bytes. This
122 * guarantees consistency, i.e., the application can always free memory
123 * without concern as to how many bytes of the record were requested.
124 *
125 * Use the memory specified by the application: DB_DBT_USERMEM.
126 *
127 * !!!
128 * If the length we're going to copy is 0, the application-supplied
129 * memory pointer is allowed to be NULL.
130 */
131 if (F_ISSET(dbt, DB_DBT_USERCOPY)) {
132 dbt->size = len;
133 return (len == 0 ? 0 : env->dbt_usercopy(dbt, 0, data,
134 len, DB_USERCOPY_SETDATA));
135
136 } else if (F_ISSET(dbt, DB_DBT_MALLOC))
137 ret = __os_umalloc(env, len, &dbt->data);
138 else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
139 if (dbt->data == NULL || dbt->size == 0 || dbt->size < len)
140 ret = __os_urealloc(env, len, &dbt->data);
141 } else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
142 if (len != 0 && (dbt->data == NULL || dbt->ulen < len))
143 ret = DB_BUFFER_SMALL;
144 } else if (memp == NULL || memsize == NULL)
145 ret = EINVAL;
146 else {
147 if (len != 0 && (*memsize == 0 || *memsize < len)) {
148 if ((ret = __os_realloc(env, len, memp)) == 0)
149 *memsize = len;
150 else
151 *memsize = 0;
152 }
153 if (ret == 0)
154 dbt->data = *memp;
155 }
156
157 if (ret == 0 && len != 0)
158 memcpy(dbt->data, data, len);
159
160 /*
161 * Return the length of the returned record in the DBT size field.
162 * This satisfies the requirement that if we're using user memory
163 * and insufficient memory was provided, return the amount necessary
164 * in the size field.
165 */
166 dbt->size = len;
167
168 return (ret);
169 }
170