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