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