1/*-
2 * Copyright (c) 1990, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Mike Olson.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#if defined(LIBC_SCCS) && !defined(lint)
34static char sccsid[] = "@(#)bt_utils.c	8.8 (Berkeley) 7/20/94";
35#endif /* LIBC_SCCS and not lint */
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <sys/param.h>
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include <db.h>
46#include "btree.h"
47
48/*
49 * __bt_ret --
50 *	Build return key/data pair.
51 *
52 * Parameters:
53 *	t:	tree
54 *	e:	key/data pair to be returned
55 *	key:	user's key structure (NULL if not to be filled in)
56 *	rkey:	memory area to hold key
57 *	data:	user's data structure (NULL if not to be filled in)
58 *	rdata:	memory area to hold data
59 *       copy:	always copy the key/data item
60 *
61 * Returns:
62 *	RET_SUCCESS, RET_ERROR.
63 */
64int
65__bt_ret(BTREE *t, EPG *e, DBT *key, DBT *rkey, DBT *data, DBT *rdata, int copy)
66{
67	BLEAF *bl;
68	void *p;
69
70	bl = GETBLEAF(e->page, e->index);
71
72	/*
73	 * We must copy big keys/data to make them contigous.  Otherwise,
74	 * leave the page pinned and don't copy unless the user specified
75	 * concurrent access.
76	 */
77	if (key == NULL)
78		goto dataonly;
79
80	if (bl->flags & P_BIGKEY) {
81		if (__ovfl_get(t, bl->bytes,
82		    &key->size, &rkey->data, &rkey->size))
83			return (RET_ERROR);
84		key->data = rkey->data;
85	} else if (copy || F_ISSET(t, B_DB_LOCK)) {
86		if (bl->ksize > rkey->size) {
87			p = realloc(rkey->data, bl->ksize);
88			if (p == NULL)
89				return (RET_ERROR);
90			rkey->data = p;
91			rkey->size = bl->ksize;
92		}
93		memmove(rkey->data, bl->bytes, bl->ksize);
94		key->size = bl->ksize;
95		key->data = rkey->data;
96	} else {
97		key->size = bl->ksize;
98		key->data = bl->bytes;
99	}
100
101dataonly:
102	if (data == NULL)
103		return (RET_SUCCESS);
104
105	if (bl->flags & P_BIGDATA) {
106		if (__ovfl_get(t, bl->bytes + bl->ksize,
107		    &data->size, &rdata->data, &rdata->size))
108			return (RET_ERROR);
109		data->data = rdata->data;
110	} else if (copy || F_ISSET(t, B_DB_LOCK)) {
111		/* Use +1 in case the first record retrieved is 0 length. */
112		if (bl->dsize + 1 > rdata->size) {
113			p = realloc(rdata->data, bl->dsize + 1);
114			if (p == NULL)
115				return (RET_ERROR);
116			rdata->data = p;
117			rdata->size = bl->dsize + 1;
118		}
119		memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
120		data->size = bl->dsize;
121		data->data = rdata->data;
122	} else {
123		data->size = bl->dsize;
124		data->data = bl->bytes + bl->ksize;
125	}
126
127	return (RET_SUCCESS);
128}
129
130/*
131 * __BT_CMP -- Compare a key to a given record.
132 *
133 * Parameters:
134 *	t:	tree
135 *	k1:	DBT pointer of first arg to comparison
136 *	e:	pointer to EPG for comparison
137 *
138 * Returns:
139 *	< 0 if k1 is < record
140 *	= 0 if k1 is = record
141 *	> 0 if k1 is > record
142 */
143int
144__bt_cmp(BTREE *t, const DBT *k1, EPG *e)
145{
146	BINTERNAL *bi;
147	BLEAF *bl;
148	DBT k2;
149	PAGE *h;
150	void *bigkey;
151
152	/*
153	 * The left-most key on internal pages, at any level of the tree, is
154	 * guaranteed by the following code to be less than any user key.
155	 * This saves us from having to update the leftmost key on an internal
156	 * page when the user inserts a new key in the tree smaller than
157	 * anything we've yet seen.
158	 */
159	h = e->page;
160	if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
161		return (1);
162
163	bigkey = NULL;
164	if (h->flags & P_BLEAF) {
165		bl = GETBLEAF(h, e->index);
166		if (bl->flags & P_BIGKEY)
167			bigkey = bl->bytes;
168		else {
169			k2.data = bl->bytes;
170			k2.size = bl->ksize;
171		}
172	} else {
173		bi = GETBINTERNAL(h, e->index);
174		if (bi->flags & P_BIGKEY)
175			bigkey = bi->bytes;
176		else {
177			k2.data = bi->bytes;
178			k2.size = bi->ksize;
179		}
180	}
181
182	if (bigkey) {
183		if (__ovfl_get(t, bigkey,
184		    &k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
185			return (RET_ERROR);
186		k2.data = t->bt_rdata.data;
187	}
188	return ((*t->bt_cmp)(k1, &k2));
189}
190
191/*
192 * __BT_DEFCMP -- Default comparison routine.
193 *
194 * Parameters:
195 *	a:	DBT #1
196 *	b:	DBT #2
197 *
198 * Returns:
199 *	< 0 if a is < b
200 *	= 0 if a is = b
201 *	> 0 if a is > b
202 */
203int
204__bt_defcmp(const DBT *a, const DBT *b)
205{
206	size_t len;
207	u_char *p1, *p2;
208
209	/*
210	 * XXX
211	 * If a size_t doesn't fit in an int, this routine can lose.
212	 * What we need is an integral type which is guaranteed to be
213	 * larger than a size_t, and there is no such thing.
214	 */
215	len = MIN(a->size, b->size);
216	for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
217		if (*p1 != *p2)
218			return ((int)*p1 - (int)*p2);
219	return ((int)a->size - (int)b->size);
220}
221
222/*
223 * __BT_DEFPFX -- Default prefix routine.
224 *
225 * Parameters:
226 *	a:	DBT #1
227 *	b:	DBT #2
228 *
229 * Returns:
230 *	Number of bytes needed to distinguish b from a.
231 */
232size_t
233__bt_defpfx(const DBT *a, const DBT *b)
234{
235	u_char *p1, *p2;
236	size_t cnt, len;
237
238	cnt = 1;
239	len = MIN(a->size, b->size);
240	for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
241		if (*p1 != *p2)
242			return (cnt);
243
244	/* a->size must be <= b->size, or they wouldn't be in this order. */
245	return (a->size < b->size ? a->size + 1 : a->size);
246}
247