GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/db/recno/rec_put.c Lines: 0 99 0.0 %
Date: 2017-11-13 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rec_put.c,v 1.11 2007/08/08 07:16:50 ray Exp $	*/
2
3
/*-
4
 * Copyright (c) 1990, 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the University nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include <sys/types.h>
33
34
#include <errno.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
39
#include <db.h>
40
#include "recno.h"
41
42
/*
43
 * __REC_PUT -- Add a recno item to the tree.
44
 *
45
 * Parameters:
46
 *	dbp:	pointer to access method
47
 *	key:	key
48
 *	data:	data
49
 *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
50
 *
51
 * Returns:
52
 *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
53
 *	already in the tree and R_NOOVERWRITE specified.
54
 */
55
int
56
__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
57
{
58
	BTREE *t;
59
	DBT fdata, tdata;
60
	recno_t nrec;
61
	int status;
62
	void *tp;
63
64
	t = dbp->internal;
65
66
	/* Toss any page pinned across calls. */
67
	if (t->bt_pinned != NULL) {
68
		mpool_put(t->bt_mp, t->bt_pinned, 0);
69
		t->bt_pinned = NULL;
70
	}
71
72
	/*
73
	 * If using fixed-length records, and the record is long, return
74
	 * EINVAL.  If it's short, pad it out.  Use the record data return
75
	 * memory, it's only short-term.
76
	 */
77
	if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
78
		if (data->size > t->bt_reclen)
79
			goto einval;
80
81
		if (t->bt_rdata.size < t->bt_reclen) {
82
			tp = realloc(t->bt_rdata.data, t->bt_reclen);
83
			if (tp == NULL)
84
				return (RET_ERROR);
85
			t->bt_rdata.data = tp;
86
			t->bt_rdata.size = t->bt_reclen;
87
		}
88
		memmove(t->bt_rdata.data, data->data, data->size);
89
		memset((char *)t->bt_rdata.data + data->size,
90
		    t->bt_bval, t->bt_reclen - data->size);
91
		fdata.data = t->bt_rdata.data;
92
		fdata.size = t->bt_reclen;
93
	} else {
94
		fdata.data = data->data;
95
		fdata.size = data->size;
96
	}
97
98
	switch (flags) {
99
	case R_CURSOR:
100
		if (!F_ISSET(&t->bt_cursor, CURS_INIT))
101
			goto einval;
102
		nrec = t->bt_cursor.rcursor;
103
		break;
104
	case R_SETCURSOR:
105
		if ((nrec = *(recno_t *)key->data) == 0)
106
			goto einval;
107
		break;
108
	case R_IAFTER:
109
		if ((nrec = *(recno_t *)key->data) == 0) {
110
			nrec = 1;
111
			flags = R_IBEFORE;
112
		}
113
		break;
114
	case 0:
115
	case R_IBEFORE:
116
		if ((nrec = *(recno_t *)key->data) == 0)
117
			goto einval;
118
		break;
119
	case R_NOOVERWRITE:
120
		if ((nrec = *(recno_t *)key->data) == 0)
121
			goto einval;
122
		if (nrec <= t->bt_nrecs)
123
			return (RET_SPECIAL);
124
		break;
125
	default:
126
einval:		errno = EINVAL;
127
		return (RET_ERROR);
128
	}
129
130
	/*
131
	 * Make sure that records up to and including the put record are
132
	 * already in the database.  If skipping records, create empty ones.
133
	 */
134
	if (nrec > t->bt_nrecs) {
135
		if (!F_ISSET(t, R_EOF | R_INMEM) &&
136
		    t->bt_irec(t, nrec) == RET_ERROR)
137
			return (RET_ERROR);
138
		if (nrec > t->bt_nrecs + 1) {
139
			if (F_ISSET(t, R_FIXLEN)) {
140
				if ((tdata.data =
141
				    (void *)malloc(t->bt_reclen)) == NULL)
142
					return (RET_ERROR);
143
				tdata.size = t->bt_reclen;
144
				memset(tdata.data, t->bt_bval, tdata.size);
145
			} else {
146
				tdata.data = NULL;
147
				tdata.size = 0;
148
			}
149
			while (nrec > t->bt_nrecs + 1)
150
				if (__rec_iput(t,
151
				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
152
					return (RET_ERROR);
153
			if (F_ISSET(t, R_FIXLEN))
154
				free(tdata.data);
155
		}
156
	}
157
158
	if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
159
		return (status);
160
161
	if (flags == R_SETCURSOR)
162
		t->bt_cursor.rcursor = nrec;
163
164
	F_SET(t, R_MODIFIED);
165
	return (__rec_ret(t, NULL, nrec, key, NULL));
166
}
167
168
/*
169
 * __REC_IPUT -- Add a recno item to the tree.
170
 *
171
 * Parameters:
172
 *	t:	tree
173
 *	nrec:	record number
174
 *	data:	data
175
 *
176
 * Returns:
177
 *	RET_ERROR, RET_SUCCESS
178
 */
179
int
180
__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
181
{
182
	DBT tdata;
183
	EPG *e;
184
	PAGE *h;
185
	indx_t idx, nxtindex;
186
	pgno_t pg;
187
	u_int32_t nbytes;
188
	int dflags, status;
189
	char *dest, db[NOVFLSIZE];
190
191
	/*
192
	 * If the data won't fit on a page, store it on indirect pages.
193
	 *
194
	 * XXX
195
	 * If the insert fails later on, these pages aren't recovered.
196
	 */
197
	if (data->size > t->bt_ovflsize) {
198
		if (__ovfl_put(t, data, &pg) == RET_ERROR)
199
			return (RET_ERROR);
200
		tdata.data = db;
201
		tdata.size = NOVFLSIZE;
202
		*(pgno_t *)db = pg;
203
		*(u_int32_t *)(db + sizeof(pgno_t)) = data->size;
204
		dflags = P_BIGDATA;
205
		data = &tdata;
206
	} else
207
		dflags = 0;
208
209
	/* __rec_search pins the returned page. */
210
	if ((e = __rec_search(t, nrec,
211
	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
212
	    SINSERT : SEARCH)) == NULL)
213
		return (RET_ERROR);
214
215
	h = e->page;
216
	idx = e->index;
217
218
	/*
219
	 * Add the specified key/data pair to the tree.  The R_IAFTER and
220
	 * R_IBEFORE flags insert the key after/before the specified key.
221
	 *
222
	 * Pages are split as required.
223
	 */
224
	switch (flags) {
225
	case R_IAFTER:
226
		++idx;
227
		break;
228
	case R_IBEFORE:
229
		break;
230
	default:
231
		if (nrec < t->bt_nrecs &&
232
		    __rec_dleaf(t, h, idx) == RET_ERROR) {
233
			mpool_put(t->bt_mp, h, 0);
234
			return (RET_ERROR);
235
		}
236
		break;
237
	}
238
239
	/*
240
	 * If not enough room, split the page.  The split code will insert
241
	 * the key and data and unpin the current page.  If inserting into
242
	 * the offset array, shift the pointers up.
243
	 */
244
	nbytes = NRLEAFDBT(data->size);
245
	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
246
		status = __bt_split(t, h, NULL, data, dflags, nbytes, idx);
247
		if (status == RET_SUCCESS)
248
			++t->bt_nrecs;
249
		return (status);
250
	}
251
252
	if (idx < (nxtindex = NEXTINDEX(h)))
253
		memmove(h->linp + idx + 1, h->linp + idx,
254
		    (nxtindex - idx) * sizeof(indx_t));
255
	h->lower += sizeof(indx_t);
256
257
	h->linp[idx] = h->upper -= nbytes;
258
	dest = (char *)h + h->upper;
259
	WR_RLEAF(dest, data, dflags);
260
261
	++t->bt_nrecs;
262
	F_SET(t, B_MODIFIED);
263
	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
264
265
	return (RET_SUCCESS);
266
}