]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libc/db/btree/bt_utils.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libc / db / btree / bt_utils.c
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)
34 static 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  */
64 int
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
101 dataonly:
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  */
143 int
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  */
203 int
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  */
232 size_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 }