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