146131Smao /*- 246131Smao * Copyright (c) 1990 The Regents of the University of California. 346131Smao * All rights reserved. 446131Smao * 546131Smao * This code is derived from software contributed to Berkeley by 646131Smao * Mike Olson. 746131Smao * 846131Smao * %sccs.include.redist.c% 946131Smao */ 1046131Smao 1146131Smao #if defined(LIBC_SCCS) && !defined(lint) 12*46561Sbostic static char sccsid[] = "@(#)bt_put.c 5.3 (Berkeley) 02/22/91"; 1346131Smao #endif /* LIBC_SCCS and not lint */ 1446131Smao 1546131Smao #include <sys/types.h> 1646131Smao #include <db.h> 17*46561Sbostic #include <stdlib.h> 18*46561Sbostic #include <string.h> 1946131Smao #include "btree.h" 2046131Smao 2146131Smao /* 2246131Smao * _BT_INSERT -- Insert a new user datum in the btree. 2346131Smao * 2446131Smao * This routine is called by bt_put, the public interface, once the 2546131Smao * location for the new item is known. We do the work here, and 2646131Smao * handle splits if necessary. 2746131Smao * 2846131Smao * Parameters: 2946131Smao * t -- btree in which to do the insertion. 3046131Smao * item -- BTITEM describing location of new datum 3146131Smao * key -- key to insert 3246131Smao * data -- data associated with key 3346131Smao * flag -- magic cookie passed recursively to bt_put if we 3446131Smao * have to do a split 3546131Smao * 3646131Smao * Returns: 3746131Smao * RET_SUCCESS, RET_ERROR. 3846131Smao */ 3946131Smao 4046131Smao int 4146131Smao _bt_insert(t, item, key, data, flag) 4246131Smao BTREE_P t; 4346131Smao BTITEM *item; 4446131Smao DBT *key; 4546131Smao DBT *data; 4646131Smao int flag; 4746131Smao { 4846131Smao index_t index; 4946131Smao BTHEADER *h; 5046131Smao DATUM *d; 5146131Smao int nbytes; 5246131Smao int status; 5346131Smao pgno_t pgno; 5446131Smao int keysize, datasize; 5546131Smao int bigkey, bigdata; 5646131Smao 5746131Smao if (_bt_getpage(t, item->bti_pgno) == RET_ERROR) 5846131Smao return (RET_ERROR); 5946131Smao h = t->bt_curpage; 6046131Smao 6146131Smao if (TOOBIG(t, data->size)) { 6246131Smao bigdata = TRUE; 6346131Smao datasize = sizeof(pgno_t); 6446131Smao } else { 6546131Smao bigdata = FALSE; 6646131Smao datasize = data->size; 6746131Smao } 6846131Smao 6946131Smao if (TOOBIG(t, key->size)) { 7046131Smao bigkey = TRUE; 7146131Smao keysize = sizeof(pgno_t); 7246131Smao } else { 7346131Smao bigkey = FALSE; 7446131Smao keysize = key->size; 7546131Smao } 7646131Smao 7746131Smao nbytes = keysize + datasize + (sizeof(DATUM) - sizeof(char)); 7846131Smao nbytes = LONGALIGN(nbytes) + sizeof(index_t); 7946131Smao 8046131Smao /* if there's not enough room here, split the page */ 8146131Smao if ((h->h_upper - h->h_lower) < nbytes) { 8246131Smao if (_bt_split(t) == RET_ERROR) 8346131Smao return (RET_ERROR); 8446131Smao 8546454Smao /* okay, try again (empty the stack first, though) */ 8646454Smao while (_bt_pop((BTREE) t) != P_NONE) 8746454Smao continue; 8846454Smao 8946131Smao return (bt_put((BTREE) t, key, data, flag)); 9046131Smao } 9146131Smao 9246131Smao /* put together a leaf page datum from the key/data pair */ 9346131Smao index = item->bti_index; 9446131Smao nbytes = keysize + datasize + (sizeof(DATUM) - sizeof(char)); 9546131Smao 9646131Smao if ((d = (DATUM *) malloc((unsigned) nbytes)) == (DATUM *) NULL) 9746131Smao return (RET_ERROR); 9846131Smao 9946131Smao d->d_ksize = keysize; 10046131Smao d->d_dsize = datasize; 10146131Smao d->d_flags = 0; 10246131Smao 10346131Smao if (bigkey) { 10446131Smao if (_bt_indirect(t, key, &pgno) == RET_ERROR) 10546131Smao return (RET_ERROR); 10646131Smao (void) bcopy((char *) &pgno, &(d->d_bytes[0]), sizeof(pgno)); 10746131Smao d->d_flags |= D_BIGKEY; 10846131Smao if (_bt_getpage(t, item->bti_pgno) == RET_ERROR) 10946131Smao return (RET_ERROR); 11046131Smao } else { 11146131Smao if (d->d_ksize > 0) { 11246131Smao (void) bcopy((char *) key->data, 11346131Smao (char *) &(d->d_bytes[0]), 11446131Smao (int) d->d_ksize); 11546131Smao } 11646131Smao } 11746131Smao 11846131Smao if (bigdata) { 11946131Smao if (_bt_indirect(t, data, &pgno) == RET_ERROR) 12046131Smao return (RET_ERROR); 12146131Smao (void) bcopy((char *) &pgno, 12246131Smao &(d->d_bytes[keysize]), 12346131Smao sizeof(pgno)); 12446131Smao d->d_flags |= D_BIGDATA; 12546131Smao if (_bt_getpage(t, item->bti_pgno) == RET_ERROR) 12646131Smao return (RET_ERROR); 12746131Smao } else { 12846131Smao if (d->d_dsize > 0) { 12946131Smao (void) bcopy((char *) data->data, 13046131Smao (char *) &(d->d_bytes[keysize]), 13146131Smao (int) d->d_dsize); 13246131Smao } 13346131Smao } 13446131Smao 13546131Smao /* do the insertion */ 13646131Smao status = _bt_insertat(t, (char *) d, index); 13746131Smao 13846131Smao (void) free((char *) d); 13946131Smao 14046131Smao return (status); 14146131Smao } 14246131Smao 14346131Smao /* 14446131Smao * _BT_INSERTI -- Insert IDATUM on current page in the btree. 14546131Smao * 14646131Smao * This routine handles insertions to internal pages after splits 14746131Smao * lower in the tree. On entry, t->bt_curpage is the page to get 14846131Smao * the new IDATUM. We are also given pgno, the page number of the 14946131Smao * IDATUM that is immediately left of the new IDATUM's position. 15046131Smao * This guarantees that the IDATUM for the right half of the page 15146131Smao * after a split goes next to the IDATUM for its left half. 15246131Smao * 15346131Smao * Parameters: 15446131Smao * t -- tree in which to do insertion. 15546131Smao * id -- new IDATUM to insert 15646131Smao * pgno -- page number of IDATUM left of id's position 15746131Smao * 15846131Smao * Returns: 15946131Smao * RET_SUCCESS, RET_ERROR. 16046131Smao */ 16146131Smao 16246131Smao int 16346131Smao _bt_inserti(t, id, pgno) 16446131Smao BTREE_P t; 16546131Smao IDATUM *id; 16646131Smao pgno_t pgno; 16746131Smao { 16846131Smao BTHEADER *h = t->bt_curpage; 16946131Smao index_t next, i; 17046131Smao IDATUM *idx; 17146131Smao char *key; 17246131Smao pgno_t chain; 17346131Smao int free_key; 17446131Smao int ignore; 17546131Smao 17646131Smao if (id->i_flags & D_BIGKEY) { 17746131Smao free_key = TRUE; 17846131Smao bcopy(&(id->i_bytes[0]), (char *) &chain, sizeof(chain)); 17946131Smao if (_bt_getbig(t, chain, &key, &ignore) == RET_ERROR) 18046131Smao return (RET_ERROR); 18146131Smao } else { 18246131Smao free_key = FALSE; 18346131Smao key = &(id->i_bytes[0]); 18446131Smao } 18546131Smao i = _bt_binsrch(t, key); 18646131Smao 18746131Smao next = NEXTINDEX(h); 18846131Smao while (i < next && _bt_cmp(t, key, i) >= 0) 18946131Smao i++; 19046131Smao 19146131Smao if (free_key) 19246131Smao (void) free(key); 19346131Smao 19446131Smao /* okay, now we're close; find adjacent IDATUM */ 19546131Smao for (;;) { 19646131Smao idx = (IDATUM *) GETDATUM(h,i); 19746131Smao if (idx->i_pgno == pgno) { 19846131Smao i++; 19946131Smao break; 20046131Smao } 20146131Smao --i; 20246131Smao } 20346131Smao 20446131Smao /* correctly positioned, do the insertion */ 20546131Smao return (_bt_insertat(t, (char *) id, i)); 20646131Smao } 20746131Smao 20846131Smao /* 20946131Smao * _BT_INSERTAT -- Insert a datum at a given location on the current page. 21046131Smao * 21146131Smao * This routine does insertions on both leaf and internal pages. 21246131Smao * 21346131Smao * Parameters: 21446131Smao * t -- tree in which to do insertion. 21546131Smao * p -- DATUM or IDATUM to insert. 21646131Smao * index -- index in line pointer array to put this item. 21746131Smao * 21846131Smao * Returns: 21946131Smao * RET_SUCCESS, RET_ERROR. 22046131Smao * 22146131Smao * Side Effects: 22246131Smao * Will rearrange line pointers to make space for the new 22346131Smao * entry. This means that any scans currently active are 22446131Smao * invalid after this. 22546131Smao * 22646131Smao * Warnings: 22746131Smao * There must be sufficient room for the new item on the page. 22846131Smao */ 22946131Smao 23046131Smao int 23146131Smao _bt_insertat(t, p, index) 23246131Smao BTREE_P t; 23346131Smao char *p; 23446131Smao index_t index; 23546131Smao { 23646131Smao IDATUM *id = (IDATUM *) p; 23746131Smao DATUM *d = (DATUM *) p; 23846131Smao BTHEADER *h; 23946131Smao CURSOR *c; 24046131Smao index_t nxtindex; 24146131Smao char *src, *dest; 24246131Smao int nbytes; 24346131Smao 24446131Smao /* insertion may confuse an active scan. fix it. */ 24546131Smao c = &(t->bt_cursor); 24646131Smao if (t->bt_flags & BTF_SEQINIT && t->bt_curpage->h_pgno == c->c_pgno) 24746131Smao if (_bt_fixscan(t, index, d, INSERT) == RET_ERROR) 24846131Smao return (RET_ERROR); 24946131Smao 25046131Smao h = t->bt_curpage; 25146131Smao nxtindex = (index_t) NEXTINDEX(h); 25246131Smao 25346131Smao /* 25446131Smao * If we're inserting at the middle of the line pointer array, 25546131Smao * copy pointers that will follow the new one up on the page. 25646131Smao */ 25746131Smao 25846131Smao if (index < nxtindex) { 25946131Smao src = (char *) &(h->h_linp[index]); 26046131Smao dest = (char *) &(h->h_linp[index + 1]); 26146131Smao nbytes = (h->h_lower - (src - ((char *) h))) 26246131Smao + sizeof(h->h_linp[0]); 26346131Smao (void) bcopy(src, dest, nbytes); 26446131Smao } 26546131Smao 26646131Smao /* compute size and copy data to page */ 26746131Smao if (h->h_flags & F_LEAF) { 26846131Smao nbytes = d->d_ksize + d->d_dsize 26946131Smao + (sizeof(DATUM) - sizeof(char)); 27046131Smao } else { 27146131Smao nbytes = id->i_size + (sizeof(IDATUM) - sizeof(char)); 27246131Smao } 27346131Smao dest = (((char *) h) + h->h_upper) - LONGALIGN(nbytes); 27446131Smao (void) bcopy((char *) p, dest, nbytes); 27546131Smao 27646131Smao /* update statistics */ 27746131Smao dest -= (int) h; 27846131Smao h->h_linp[index] = (index_t) dest; 27946131Smao h->h_upper = (index_t) dest; 28046131Smao h->h_lower += sizeof(index_t); 28146131Smao 28246131Smao /* we're done */ 28346131Smao h->h_flags |= F_DIRTY; 28446131Smao 28546131Smao return (RET_SUCCESS); 28646131Smao } 287