150995Sbostic /*-
261207Sbostic * Copyright (c) 1990, 1993
361207Sbostic * The Regents of the University of California. 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*66195Sbostic static char sccsid[] = "@(#)rec_delete.c 8.4 (Berkeley) 02/21/94";
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
__rec_delete(dbp,key,flags)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;
4864461Sbostic
4964461Sbostic /* Toss any page pinned across calls. */
5064461Sbostic if (t->bt_pinned != NULL) {
5164461Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0);
5264461Sbostic t->bt_pinned = NULL;
5364461Sbostic }
5464461Sbostic
5550995Sbostic switch(flags) {
5650995Sbostic case 0:
5756756Sbostic if ((nrec = *(recno_t *)key->data) == 0)
5856756Sbostic goto einval;
5951088Sbostic if (nrec > t->bt_nrecs)
6051088Sbostic return (RET_SPECIAL);
6151088Sbostic --nrec;
6250995Sbostic status = rec_rdelete(t, nrec);
6350995Sbostic break;
6450995Sbostic case R_CURSOR:
6560052Sbostic if (!ISSET(t, B_SEQINIT))
6656756Sbostic goto einval;
6756756Sbostic if (t->bt_nrecs == 0)
6851088Sbostic return (RET_SPECIAL);
6951088Sbostic status = rec_rdelete(t, t->bt_rcursor - 1);
7056756Sbostic if (status == RET_SUCCESS)
7151088Sbostic --t->bt_rcursor;
7250995Sbostic break;
7350995Sbostic default:
7456756Sbostic einval: errno = EINVAL;
7550995Sbostic return (RET_ERROR);
7650995Sbostic }
7750995Sbostic
7854281Sbostic if (status == RET_SUCCESS)
7960052Sbostic SET(t, B_MODIFIED | R_MODIFIED);
8050995Sbostic return (status);
8150995Sbostic }
8250995Sbostic
8350995Sbostic /*
8450995Sbostic * REC_RDELETE -- Delete the data matching the specified key.
8550995Sbostic *
8650995Sbostic * Parameters:
8750995Sbostic * tree: tree
8850995Sbostic * nrec: record to delete
8950995Sbostic *
9050995Sbostic * Returns:
9150995Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
9250995Sbostic */
9350995Sbostic static int
rec_rdelete(t,nrec)9450995Sbostic rec_rdelete(t, nrec)
9550995Sbostic BTREE *t;
9650995Sbostic recno_t nrec;
9750995Sbostic {
9850995Sbostic EPG *e;
9950995Sbostic PAGE *h;
10051088Sbostic int status;
10150995Sbostic
10251088Sbostic /* Find the record; __rec_search pins the page. */
10366140Sbostic if ((e = __rec_search(t, nrec, SDELETE)) == NULL)
10451088Sbostic return (RET_ERROR);
10550995Sbostic
10650995Sbostic /* Delete the record. */
10750995Sbostic h = e->page;
10850995Sbostic status = __rec_dleaf(t, h, e->index);
10951088Sbostic if (status != RET_SUCCESS) {
11050995Sbostic mpool_put(t->bt_mp, h, 0);
11150995Sbostic return (status);
11250995Sbostic }
11351088Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY);
11450995Sbostic return (RET_SUCCESS);
11550995Sbostic }
11650995Sbostic
11750995Sbostic /*
11850995Sbostic * __REC_DLEAF -- Delete a single record from a recno leaf page.
11950995Sbostic *
12050995Sbostic * Parameters:
12150995Sbostic * t: tree
12250995Sbostic * index: index on current page to delete
12350995Sbostic *
12450995Sbostic * Returns:
12550995Sbostic * RET_SUCCESS, RET_ERROR.
12650995Sbostic */
12750995Sbostic int
__rec_dleaf(t,h,index)12850995Sbostic __rec_dleaf(t, h, index)
12950995Sbostic BTREE *t;
13050995Sbostic PAGE *h;
131*66195Sbostic indx_t index;
13250995Sbostic {
13350995Sbostic register RLEAF *rl;
134*66195Sbostic register indx_t *ip, cnt, offset;
13550995Sbostic register size_t nbytes;
13650995Sbostic char *from;
13750995Sbostic void *to;
13850995Sbostic
13950995Sbostic /*
14050995Sbostic * Delete a record from a recno leaf page. Internal records are never
14150995Sbostic * deleted from internal pages, regardless of the records that caused
14250995Sbostic * them to be added being deleted. Pages made empty by deletion are
14350995Sbostic * not reclaimed. They are, however, made available for reuse.
14450995Sbostic *
14550995Sbostic * Pack the remaining entries at the end of the page, shift the indices
14650995Sbostic * down, overwriting the deleted record and its index. If the record
14750995Sbostic * uses overflow pages, make them available for reuse.
14850995Sbostic */
14950995Sbostic to = rl = GETRLEAF(h, index);
15050995Sbostic if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
15150995Sbostic return (RET_ERROR);
15250995Sbostic nbytes = NRLEAF(rl);
15350995Sbostic
15450995Sbostic /*
15550995Sbostic * Compress the key/data pairs. Compress and adjust the [BR]LEAF
15650995Sbostic * offsets. Reset the headers.
15750995Sbostic */
15850995Sbostic from = (char *)h + h->upper;
15958015Sbostic memmove(from + nbytes, from, (char *)to - from);
16050995Sbostic h->upper += nbytes;
16150995Sbostic
16250995Sbostic offset = h->linp[index];
16350995Sbostic for (cnt = &h->linp[index] - (ip = &h->linp[0]); cnt--; ++ip)
16450995Sbostic if (ip[0] < offset)
16550995Sbostic ip[0] += nbytes;
16650995Sbostic for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
16750995Sbostic ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
16857988Sbostic h->lower -= sizeof(indx_t);
16954281Sbostic --t->bt_nrecs;
17050995Sbostic return (RET_SUCCESS);
17150995Sbostic }
172