Update from db-2.3.12.
[kopensolaris-gnu/glibc.git] / db2 / db / db_ret.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
5  *      Sleepycat Software.  All rights reserved.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)db_ret.c      10.8 (Sleepycat) 10/25/97";
12 #endif /* not lint */
13
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #endif
22
23 #include "db_int.h"
24 #include "db_page.h"
25 #include "btree.h"
26 #include "hash.h"
27 #include "db_am.h"
28
29 /*
30  * __db_ret --
31  *      Build return DBT.
32  *
33  * PUBLIC: int __db_ret __P((DB *,
34  * PUBLIC:    PAGE *, u_int32_t, DBT *, void **, u_int32_t *));
35  */
36 int
37 __db_ret(dbp, h, indx, dbt, memp, memsize)
38         DB *dbp;
39         PAGE *h;
40         u_int32_t indx;
41         DBT *dbt;
42         void **memp;
43         u_int32_t *memsize;
44 {
45         BKEYDATA *bk;
46         HOFFPAGE ho;
47         BOVERFLOW *bo;
48         u_int32_t len;
49         u_int8_t *hk;
50         void *data;
51
52         switch (TYPE(h)) {
53         case P_HASH:
54                 hk = P_ENTRY(h, indx);
55                 if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
56                         memcpy(&ho, hk, sizeof(HOFFPAGE));
57                         return (__db_goff(dbp, dbt,
58                             ho.tlen, ho.pgno, memp, memsize));
59                 }
60                 len = LEN_HKEYDATA(h, dbp->pgsize, indx);
61                 data = HKEYDATA_DATA(hk);
62                 break;
63         case P_DUPLICATE:
64         case P_LBTREE:
65         case P_LRECNO:
66                 bk = GET_BKEYDATA(h, indx);
67                 if (B_TYPE(bk->type) == B_OVERFLOW) {
68                         bo = (BOVERFLOW *)bk;
69                         return (__db_goff(dbp, dbt,
70                             bo->tlen, bo->pgno, memp, memsize));
71                 }
72                 len = bk->len;
73                 data = bk->data;
74                 break;
75         default:
76                 return (__db_pgfmt(dbp, h->pgno));
77         }
78
79         return (__db_retcopy(dbt, data, len, memp, memsize,
80             F_ISSET(dbt, DB_DBT_INTERNAL) ? NULL : dbp->db_malloc));
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((DBT *,
88  * PUBLIC:    void *, u_int32_t, void **, u_int32_t *, void *(*)(size_t)));
89  */
90 int
91 __db_retcopy(dbt, data, len, memp, memsize, db_malloc)
92         DBT *dbt;
93         void *data;
94         u_int32_t len;
95         void **memp;
96         u_int32_t *memsize;
97         void *(*db_malloc) __P((size_t));
98 {
99         /* If returning a partial record, reset the length. */
100         if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
101                 data = (u_int8_t *)data + dbt->doff;
102                 if (len > dbt->doff) {
103                         len -= dbt->doff;
104                         if (len > dbt->dlen)
105                                 len = dbt->dlen;
106                 } else
107                         len = 0;
108         }
109
110         /*
111          * Return the length of the returned record in the DBT size field.
112          * This satisfies the requirement that if we're using user memory
113          * and insufficient memory was provided, return the amount necessary
114          * in the size field.
115          */
116         dbt->size = len;
117
118         /*
119          * Allocate any necessary memory.
120          *
121          * XXX: Never allocate 0 bytes.
122          */
123         if (F_ISSET(dbt, DB_DBT_MALLOC)) {
124                 dbt->data = db_malloc == NULL ?
125                     (void *)__db_malloc(len + 1) :
126                     (void *)db_malloc(len + 1);
127                 if (dbt->data == NULL)
128                         return (ENOMEM);
129         } else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
130                 if (dbt->ulen < len)
131                         return (ENOMEM);
132         } else if (memp == NULL || memsize == NULL) {
133                 return (EINVAL);
134         } else {
135                 if (*memsize == 0 || *memsize < len) {
136                         *memp = *memp == NULL ?
137                             (void *)__db_malloc(len + 1) :
138                             (void *)__db_realloc(*memp, len + 1);
139                         if (*memp == NULL) {
140                                 *memsize = 0;
141                                 return (ENOMEM);
142                         }
143                         *memsize = len + 1;
144                 }
145                 dbt->data = *memp;
146         }
147
148         memcpy(dbt->data, data, len);
149         return (0);
150 }