150995Sbostic /*- 250995Sbostic * Copyright (c) 1990 The Regents of the University of California. 350995Sbostic * All rights reserved. 450995Sbostic * 550995Sbostic * This code is derived from software contributed to Berkeley by 650995Sbostic * Mike Olson. 750995Sbostic * 850995Sbostic * %sccs.include.redist.c% 950995Sbostic */ 1050995Sbostic 1150995Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*57988Sbostic static char sccsid[] = "@(#)rec_delete.c 5.6 (Berkeley) 02/14/93"; 1350995Sbostic #endif /* LIBC_SCCS and not lint */ 1450995Sbostic 1550995Sbostic #include <sys/types.h> 1656756Sbostic 1750995Sbostic #include <errno.h> 1850995Sbostic #include <stdio.h> 1950995Sbostic #include <string.h> 2056756Sbostic 2157933Sbostic #include <db.h> 2251088Sbostic #include "recno.h" 2350995Sbostic 2450995Sbostic static int rec_rdelete __P((BTREE *, recno_t)); 2550995Sbostic 2650995Sbostic /* 2750995Sbostic * __REC_DELETE -- Delete the item(s) referenced by a key. 2850995Sbostic * 2950995Sbostic * Parameters: 3050995Sbostic * dbp: pointer to access method 3150995Sbostic * key: key to delete 3250995Sbostic * flags: R_CURSOR if deleting what the cursor references 3350995Sbostic * 3450995Sbostic * Returns: 3550995Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 3650995Sbostic */ 3750995Sbostic int 3850995Sbostic __rec_delete(dbp, key, flags) 3950995Sbostic const DB *dbp; 4050995Sbostic const DBT *key; 4150995Sbostic u_int flags; 4250995Sbostic { 4350995Sbostic BTREE *t; 4450995Sbostic recno_t nrec; 4550995Sbostic int status; 4650995Sbostic 4750995Sbostic t = dbp->internal; 4850995Sbostic switch(flags) { 4950995Sbostic case 0: 5056756Sbostic if ((nrec = *(recno_t *)key->data) == 0) 5156756Sbostic goto einval; 5251088Sbostic if (nrec > t->bt_nrecs) 5351088Sbostic return (RET_SPECIAL); 5451088Sbostic --nrec; 5550995Sbostic status = rec_rdelete(t, nrec); 5650995Sbostic break; 5750995Sbostic case R_CURSOR: 5856756Sbostic if (!ISSET(t, BTF_SEQINIT)) 5956756Sbostic goto einval; 6056756Sbostic if (t->bt_nrecs == 0) 6151088Sbostic return (RET_SPECIAL); 6251088Sbostic status = rec_rdelete(t, t->bt_rcursor - 1); 6356756Sbostic if (status == RET_SUCCESS) 6451088Sbostic --t->bt_rcursor; 6550995Sbostic break; 6650995Sbostic default: 6756756Sbostic einval: errno = EINVAL; 6850995Sbostic return (RET_ERROR); 6950995Sbostic } 7050995Sbostic 7154281Sbostic if (status == RET_SUCCESS) 7250995Sbostic SET(t, BTF_MODIFIED); 7350995Sbostic return (status); 7450995Sbostic } 7550995Sbostic 7650995Sbostic /* 7750995Sbostic * REC_RDELETE -- Delete the data matching the specified key. 7850995Sbostic * 7950995Sbostic * Parameters: 8050995Sbostic * tree: tree 8150995Sbostic * nrec: record to delete 8250995Sbostic * 8350995Sbostic * Returns: 8450995Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 8550995Sbostic */ 8650995Sbostic static int 8750995Sbostic rec_rdelete(t, nrec) 8850995Sbostic BTREE *t; 8950995Sbostic recno_t nrec; 9050995Sbostic { 9150995Sbostic EPG *e; 9250995Sbostic PAGE *h; 9351088Sbostic int status; 9450995Sbostic 9551088Sbostic /* Find the record; __rec_search pins the page. */ 9651088Sbostic if ((e = __rec_search(t, nrec, SDELETE)) == NULL) { 9750995Sbostic mpool_put(t->bt_mp, e->page, 0); 9851088Sbostic return (RET_ERROR); 9950995Sbostic } 10050995Sbostic 10150995Sbostic /* Delete the record. */ 10250995Sbostic h = e->page; 10350995Sbostic status = __rec_dleaf(t, h, e->index); 10451088Sbostic if (status != RET_SUCCESS) { 10550995Sbostic mpool_put(t->bt_mp, h, 0); 10650995Sbostic return (status); 10750995Sbostic } 10851088Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 10950995Sbostic return (RET_SUCCESS); 11050995Sbostic } 11150995Sbostic 11250995Sbostic /* 11350995Sbostic * __REC_DLEAF -- Delete a single record from a recno leaf page. 11450995Sbostic * 11550995Sbostic * Parameters: 11650995Sbostic * t: tree 11750995Sbostic * index: index on current page to delete 11850995Sbostic * 11950995Sbostic * Returns: 12050995Sbostic * RET_SUCCESS, RET_ERROR. 12150995Sbostic */ 12250995Sbostic int 12350995Sbostic __rec_dleaf(t, h, index) 12450995Sbostic BTREE *t; 12550995Sbostic PAGE *h; 12650995Sbostic int index; 12750995Sbostic { 12850995Sbostic register RLEAF *rl; 129*57988Sbostic register indx_t *ip, offset; 13050995Sbostic register size_t nbytes; 13150995Sbostic register int cnt; 13250995Sbostic char *from; 13350995Sbostic void *to; 13450995Sbostic 13550995Sbostic /* 13650995Sbostic * Delete a record from a recno leaf page. Internal records are never 13750995Sbostic * deleted from internal pages, regardless of the records that caused 13850995Sbostic * them to be added being deleted. Pages made empty by deletion are 13950995Sbostic * not reclaimed. They are, however, made available for reuse. 14050995Sbostic * 14150995Sbostic * Pack the remaining entries at the end of the page, shift the indices 14250995Sbostic * down, overwriting the deleted record and its index. If the record 14350995Sbostic * uses overflow pages, make them available for reuse. 14450995Sbostic */ 14550995Sbostic to = rl = GETRLEAF(h, index); 14650995Sbostic if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR) 14750995Sbostic return (RET_ERROR); 14850995Sbostic nbytes = NRLEAF(rl); 14950995Sbostic 15050995Sbostic /* 15150995Sbostic * Compress the key/data pairs. Compress and adjust the [BR]LEAF 15250995Sbostic * offsets. Reset the headers. 15350995Sbostic */ 15450995Sbostic from = (char *)h + h->upper; 15550995Sbostic bcopy(from, from + nbytes, (char *)to - from); 15650995Sbostic h->upper += nbytes; 15750995Sbostic 15850995Sbostic offset = h->linp[index]; 15950995Sbostic for (cnt = &h->linp[index] - (ip = &h->linp[0]); cnt--; ++ip) 16050995Sbostic if (ip[0] < offset) 16150995Sbostic ip[0] += nbytes; 16250995Sbostic for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip) 16350995Sbostic ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1]; 164*57988Sbostic h->lower -= sizeof(indx_t); 16554281Sbostic --t->bt_nrecs; 16650995Sbostic return (RET_SUCCESS); 16750995Sbostic } 168