xref: /original-bsd/lib/libc/db/btree/updutils.c (revision 9b54769b)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Olson.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)updutils.c	5.2 (Berkeley) 02/22/91";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <sys/types.h>
16 #include <db.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include "btree.h"
20 
21 /*
22  *  _BT_FIXSCAN -- Adjust a scan to cope with a change in tree structure.
23  *
24  *	If the user has an active scan on the database, and we delete an
25  *	item from the page the cursor is pointing at, we need to figure
26  *	out what to do about it.  Basically, the solution is to point
27  *	"between" keys in the tree, using the CRSR_BEFORE flag.  The
28  *	requirement is that the user should not miss any data in the
29  *	tree during a scan, just because he happened to do some deletions
30  *	or insertions while it was active.
31  *
32  *	In order to guarantee that the scan progresses properly, we need
33  *	to save the key of any deleted item we were pointing at, so that
34  *	we can check later insertions against it.
35  *
36  *	Parameters:
37  *		t -- tree to adjust
38  *		index -- index of item at which change was made
39  *		newd -- new datum (for insertions only)
40  *		op -- operation (DELETE or INSERT) causing change
41  *
42  *	Returns:
43  *		RET_SUCCESS, RET_ERROR (errno is set).
44  *
45  *	Side Effects:
46  *		None.
47  */
48 
49 int
_bt_fixscan(t,index,newd,op)50 _bt_fixscan(t, index, newd, op)
51 	BTREE_P t;
52 	index_t index;
53 	DATUM *newd;
54 	int op;
55 {
56 	CURSOR *c;
57 	DATUM *d;
58 
59 	c = &(t->bt_cursor);
60 
61 	if (op == DELETE) {
62 		if (index < c->c_index)
63 			c->c_index--;
64 		else if (index == c->c_index) {
65 			if (!(c->c_flags & CRSR_BEFORE)) {
66 				if (_bt_crsrkey(t) == RET_ERROR)
67 					return (RET_ERROR);
68 				c->c_flags |= CRSR_BEFORE;
69 			}
70 		}
71 	} else {
72 		/*
73 		 *  If we previously deleted the object at this location,
74 		 *  and now we're inserting a new one, we need to do the
75 		 *  right thing -- the cursor should come either before
76 		 *  or after the new item, depending on the key that was
77 		 *  here, and the new one.
78 		 */
79 
80 		if (c->c_flags & CRSR_BEFORE) {
81 			if (index <= c->c_index) {
82 				char *tmp;
83 				int itmp;
84 				pgno_t chain;
85 				int r;
86 
87 				d = (DATUM *) GETDATUM(t->bt_curpage, index);
88 				if (d->d_flags & D_BIGKEY) {
89 					bcopy(&(newd->d_bytes[0]),
90 					      (char *) &chain,
91 					      sizeof(chain));
92 					if (_bt_getbig(t, chain, &tmp, &itmp)
93 					     == RET_ERROR)
94 						return (RET_ERROR);
95 				} else
96 					tmp = &(newd->d_bytes[0]);
97 
98 				r = (*(t->bt_compare))(tmp, c->c_key);
99 				if (r < 0)
100 					c->c_index++;
101 
102 				if (d->d_flags & D_BIGKEY)
103 					(void) free (tmp);
104 			}
105 		} else if (index <= c->c_index)
106 			c->c_index++;
107 	}
108 	return (RET_SUCCESS);
109 }
110 
111 /*
112  *  _BT_CRSRKEY -- Save a copy of the key of the record that the cursor
113  *		   is pointing to.  The record is about to be deleted.
114  *
115  *	Parameters:
116  *		t -- btree
117  *
118  *	Returns:
119  *		RET_SUCCESS, RET_ERROR.
120  *
121  *	Side Effects:
122  *		Allocates memory for the copy which should be released when
123  *		it is no longer needed.
124  */
125 
126 int
_bt_crsrkey(t)127 _bt_crsrkey(t)
128 	BTREE_P t;
129 {
130 	CURSOR *c;
131 	DATUM *d;
132 	pgno_t pgno;
133 	int ignore;
134 
135 	c = &(t->bt_cursor);
136 	d = (DATUM *) GETDATUM(t->bt_curpage, c->c_index);
137 
138 	if (d->d_flags & D_BIGKEY) {
139 		bcopy(&(d->d_bytes[0]), (char *) &pgno, sizeof(pgno));
140 		return (_bt_getbig(t, pgno, &(c->c_key), &ignore));
141 	} else {
142 		if ((c->c_key = (char *) malloc(d->d_ksize)) == (char *) NULL)
143 			return (RET_ERROR);
144 
145 		bcopy(&(d->d_bytes[0]), c->c_key, (size_t) (d->d_ksize));
146 	}
147 	return (RET_SUCCESS);
148 }
149