xref: /csrg-svn/lib/libc/db/recno/rec_put.c (revision 50995)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)rec_put.c	5.1 (Berkeley) 09/04/91";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 #include <errno.h>
14 #include <db.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "../btree/btree.h"
19 
20 /*
21  * __REC_PUT -- Add a recno item to the tree.
22  *
23  * Parameters:
24  *	dbp:	pointer to access method
25  *	key:	key
26  *	data:	data
27  *	flag:	R_NOOVERWRITE
28  *
29  * Returns:
30  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
31  *	tree and R_NOOVERWRITE specified.
32  */
33 int
34 __rec_put(dbp, key, data, flags)
35 	const DB *dbp;
36 	const DBT *key, *data;
37 	u_int flags;
38 {
39 	BTREE *t;
40 	DBT tdata;
41 	recno_t nrec;
42 	int status;
43 
44 	if (flags &&
45 	    flags != R_IAFTER && flags != R_IBEFORE && flags != R_NOOVERWRITE ||
46 	    (nrec = *(recno_t *)key->data) == 0) {
47 		errno = EINVAL;
48 		return (RET_ERROR);
49 	}
50 
51 	/*
52 	 * If skipping records, either get them from the original file or
53 	 * create empty ones.
54 	 */
55 	t = dbp->internal;
56 	if (nrec > t->bt_nrecs && t->bt_irec(t, nrec) == RET_ERROR)
57 		return (RET_ERROR);
58 	if (nrec > t->bt_nrecs) {
59 		tdata.data = NULL;
60 		tdata.size = 0;
61 		while (nrec > t->bt_nrecs) {
62 			status = __rec_iput(t, nrec, &tdata, 0);
63 			if (status != RET_SUCCESS)
64 				return (RET_ERROR);
65 		}
66 	}
67 	--nrec;
68 	if ((status = __rec_iput(t, nrec, data, flags)) == RET_SUCCESS)
69 		SET(t, BTF_MODIFIED);
70 	return (status);
71 }
72 
73 /*
74  * __REC_IPUT -- Add a recno item to the tree.
75  *
76  * Parameters:
77  *	t:	tree
78  *	nrec:	record number
79  *	data:	data
80  *	flag:	R_NOOVERWRITE
81  *
82  * Returns:
83  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
84  *	tree and R_NOOVERWRITE specified.
85  */
86 int
87 __rec_iput(t, nrec, data, flags)
88 	BTREE *t;
89 	recno_t nrec;
90 	const DBT *data;
91 	u_int flags;
92 {
93 	DBT tdata;
94 	EPG *e;
95 	EPGNO *parent;
96 	PAGE *h;
97 	index_t index, nxtindex;
98 	pgno_t pg;
99 	size_t nbytes;
100 	int dflags, exact;
101 	char *dest, db[NOVFLSIZE];
102 
103 	/*
104 	 * If the data won't fit on a page, store it on indirect pages.
105 	 *
106 	 * XXX
107 	 * If the insert fails later on, these pages aren't recovered.
108 	 */
109 	if (data->size >= t->bt_minkeypage) {
110 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
111 			return (RET_ERROR);
112 		tdata.data = db;
113 		tdata.size = NOVFLSIZE;
114 		*(pgno_t *)db = pg;
115 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
116 		dflags = P_BIGDATA;
117 		data = &tdata;
118 	} else
119 		dflags = 0;
120 
121 	/* __rec_search pins the returned page. */
122 	if ((e = __rec_search(t, nrec, &exact)) == NULL)
123 		return (RET_ERROR);
124 
125 	h = e->page;
126 	index = e->index;
127 
128 	/*
129 	 * Add the specified key/data pair to the tree.  If an identical key
130 	 * is already in the tree, and R_NOOVERWRITE is set, an error is
131 	 * returned.  If R_NOOVERWRITE is not set, the key is either added (if
132 	 * duplicates are permitted) or an error is returned.  The R_IAFTER
133 	 * and R_IBEFORE flags insert the key after/before the specified key.
134 	 *
135 	 * Pages are split as required.
136 	 */
137 	switch (flags) {
138 	case R_IAFTER:
139 		if (!exact) {
140 			errno = EINVAL;
141 			goto err;
142 		}
143 		++index;
144 		break;
145 	case R_IBEFORE:
146 		if (!exact) {
147 			errno = EINVAL;
148 			goto err;
149 		}
150 		break;
151 	case R_NOOVERWRITE:
152 		if (!exact)
153 			break;
154 		BT_CLR(t);
155 		mpool_put(t->bt_mp, h, 0);
156 		return (RET_SPECIAL);
157 	default:
158 		if (!exact || NOTSET(t, BTF_NODUPS))
159 			break;
160 		if (__rec_dleaf(t, h, index) == RET_ERROR) {
161 err:			BT_CLR(t);
162 			mpool_put(t->bt_mp, h, 0);
163 			return (RET_ERROR);
164 		}
165 		break;
166 	}
167 
168 	/*
169 	 * If not enough room, split the page.  The split code will insert
170 	 * the key and data and unpin the current page.  If inserting into
171 	 * the offset array, shift the pointers up.
172 	 */
173 	nbytes = NRLEAFDBT(data->size);
174 	if (h->upper - h->lower < nbytes + sizeof(index_t))
175 		return (__bt_split(t, h, NULL, data, dflags, nbytes, index));
176 
177 	if (index < (nxtindex = NEXTINDEX(h)))
178 		bcopy(h->linp + index, h->linp + index + 1,
179 		    (nxtindex - index) * sizeof(index_t));
180 	h->lower += sizeof(index_t);
181 
182 	h->linp[index] = h->upper -= nbytes;
183 	dest = (char *)h + h->upper;
184 	WR_RLEAF(dest, data, dflags);
185 
186 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
187 
188 	/* Increment the count on all parent pages. */
189 	while  ((parent = BT_POP(t)) != NULL) {
190 		if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
191 			return (RET_ERROR);
192 		++GETRINTERNAL(h, parent->index)->nrecs;
193 		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
194 	}
195 	++t->bt_nrecs;
196 	return (RET_SUCCESS);
197 }
198