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[] = "@(#)rec_delete.c 5.4 (Berkeley) 11/13/92"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/types.h> 16 17 #include <db.h> 18 #include <errno.h> 19 #include <stdio.h> 20 #include <string.h> 21 22 #include "recno.h" 23 24 static int rec_rdelete __P((BTREE *, recno_t)); 25 26 /* 27 * __REC_DELETE -- Delete the item(s) referenced by a key. 28 * 29 * Parameters: 30 * dbp: pointer to access method 31 * key: key to delete 32 * flags: R_CURSOR if deleting what the cursor references 33 * 34 * Returns: 35 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 36 */ 37 int 38 __rec_delete(dbp, key, flags) 39 const DB *dbp; 40 const DBT *key; 41 u_int flags; 42 { 43 BTREE *t; 44 recno_t nrec; 45 int status; 46 47 t = dbp->internal; 48 switch(flags) { 49 case 0: 50 if ((nrec = *(recno_t *)key->data) == 0) 51 goto einval; 52 if (nrec > t->bt_nrecs) 53 return (RET_SPECIAL); 54 --nrec; 55 status = rec_rdelete(t, nrec); 56 break; 57 case R_CURSOR: 58 if (!ISSET(t, BTF_SEQINIT)) 59 goto einval; 60 if (t->bt_nrecs == 0) 61 return (RET_SPECIAL); 62 status = rec_rdelete(t, t->bt_rcursor - 1); 63 if (status == RET_SUCCESS) 64 --t->bt_rcursor; 65 break; 66 default: 67 einval: errno = EINVAL; 68 return (RET_ERROR); 69 } 70 71 if (status == RET_SUCCESS) 72 SET(t, BTF_MODIFIED); 73 return (status); 74 } 75 76 /* 77 * REC_RDELETE -- Delete the data matching the specified key. 78 * 79 * Parameters: 80 * tree: tree 81 * nrec: record to delete 82 * 83 * Returns: 84 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 85 */ 86 static int 87 rec_rdelete(t, nrec) 88 BTREE *t; 89 recno_t nrec; 90 { 91 EPG *e; 92 PAGE *h; 93 int status; 94 95 /* Find the record; __rec_search pins the page. */ 96 if ((e = __rec_search(t, nrec, SDELETE)) == NULL) { 97 mpool_put(t->bt_mp, e->page, 0); 98 return (RET_ERROR); 99 } 100 101 /* Delete the record. */ 102 h = e->page; 103 status = __rec_dleaf(t, h, e->index); 104 if (status != RET_SUCCESS) { 105 mpool_put(t->bt_mp, h, 0); 106 return (status); 107 } 108 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 109 return (RET_SUCCESS); 110 } 111 112 /* 113 * __REC_DLEAF -- Delete a single record from a recno leaf page. 114 * 115 * Parameters: 116 * t: tree 117 * index: index on current page to delete 118 * 119 * Returns: 120 * RET_SUCCESS, RET_ERROR. 121 */ 122 int 123 __rec_dleaf(t, h, index) 124 BTREE *t; 125 PAGE *h; 126 int index; 127 { 128 register RLEAF *rl; 129 register index_t *ip, offset; 130 register size_t nbytes; 131 register int cnt; 132 char *from; 133 void *to; 134 135 /* 136 * Delete a record from a recno leaf page. Internal records are never 137 * deleted from internal pages, regardless of the records that caused 138 * them to be added being deleted. Pages made empty by deletion are 139 * not reclaimed. They are, however, made available for reuse. 140 * 141 * Pack the remaining entries at the end of the page, shift the indices 142 * down, overwriting the deleted record and its index. If the record 143 * uses overflow pages, make them available for reuse. 144 */ 145 to = rl = GETRLEAF(h, index); 146 if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR) 147 return (RET_ERROR); 148 nbytes = NRLEAF(rl); 149 150 /* 151 * Compress the key/data pairs. Compress and adjust the [BR]LEAF 152 * offsets. Reset the headers. 153 */ 154 from = (char *)h + h->upper; 155 bcopy(from, from + nbytes, (char *)to - from); 156 h->upper += nbytes; 157 158 offset = h->linp[index]; 159 for (cnt = &h->linp[index] - (ip = &h->linp[0]); cnt--; ++ip) 160 if (ip[0] < offset) 161 ip[0] += nbytes; 162 for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip) 163 ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1]; 164 h->lower -= sizeof(index_t); 165 --t->bt_nrecs; 166 return (RET_SUCCESS); 167 } 168