mirror of
https://github.com/postgres/postgres.git
synced 2025-08-28 18:48:04 +03:00
Commit of a *MAJOR* patch from Dan McGuirk <djm@indirect.com>
Changes: * Unique index capability works using the syntax 'create unique index'. * Duplicate OID's in the system tables are removed. I put little scripts called 'duplicate_oids' and 'find_oid' in include/catalog that help to find and remove duplicate OID's. I also moved 'unused_oids' from backend/catalog to include/catalog, since it has to be in the same directory as the include files in order to work. * The backend tries converting the name of a function or aggregate to all lowercase if the original name given doesn't work (mostly for compatibility with ODBC). * You can 'SELECT NULL' to your heart's content. * I put my _bt_updateitem fix in instead, which uses _bt_insertonpg so that even if the new key is so big that the page has to be split, everything still works. * All literal references to system catalog OID's have been replaced with references to define'd constants from the catalog header files. * I added a couple of node copy functions. I think this was a preliminary attempt to get rules to work.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.6 1996/11/05 10:35:29 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.7 1996/11/13 20:47:11 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -31,7 +31,10 @@ static OffsetNumber _bt_findsplitloc(Relation rel, Page page, OffsetNumber start
|
||||
static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
|
||||
static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem);
|
||||
static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem);
|
||||
|
||||
#if 0
|
||||
static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BTItem newItem);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _bt_doinsert() -- Handle insertion of a single btitem in the tree.
|
||||
@@ -41,7 +44,7 @@ static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BT
|
||||
* (xid, seqno) pair.
|
||||
*/
|
||||
InsertIndexResult
|
||||
_bt_doinsert(Relation rel, BTItem btitem)
|
||||
_bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, bool is_update)
|
||||
{
|
||||
ScanKey itup_scankey;
|
||||
IndexTuple itup;
|
||||
@@ -59,6 +62,31 @@ _bt_doinsert(Relation rel, BTItem btitem)
|
||||
|
||||
/* find the page containing this key */
|
||||
stack = _bt_search(rel, natts, itup_scankey, &buf);
|
||||
|
||||
/* if we're not allowing duplicates, make sure the key isn't */
|
||||
/* already in the node */
|
||||
if(index_is_unique && !is_update) {
|
||||
OffsetNumber offset;
|
||||
TupleDesc itupdesc;
|
||||
Page page;
|
||||
|
||||
itupdesc = RelationGetTupleDescriptor(rel);
|
||||
page = BufferGetPage(buf);
|
||||
|
||||
offset = _bt_binsrch(rel, buf, natts, itup_scankey, BT_DESCENT);
|
||||
|
||||
/* make sure the offset we're given points to an actual */
|
||||
/* key on the page before trying to compare it */
|
||||
if(!PageIsEmpty(page) &&
|
||||
offset <= PageGetMaxOffsetNumber(page)) {
|
||||
if(!_bt_compare(rel, itupdesc, page,
|
||||
natts, itup_scankey, offset)) {
|
||||
/* it is a duplicate */
|
||||
elog(WARN, "Cannot insert a duplicate key into a unique index.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blkno = BufferGetBlockNumber(buf);
|
||||
|
||||
/* trade in our read lock for a write lock */
|
||||
@@ -137,6 +165,10 @@ _bt_insertonpg(Relation rel,
|
||||
InsertIndexResult newres;
|
||||
BTItem new_item = (BTItem) NULL;
|
||||
BTItem lowLeftItem;
|
||||
OffsetNumber leftmost_offset;
|
||||
Page ppage;
|
||||
BTPageOpaque ppageop;
|
||||
BlockNumber bknum;
|
||||
|
||||
page = BufferGetPage(buf);
|
||||
itemsz = IndexTupleDSize(btitem->bti_itup)
|
||||
@@ -236,14 +268,67 @@ _bt_insertonpg(Relation rel,
|
||||
lowLeftItem =
|
||||
(BTItem) PageGetItem(page,
|
||||
PageGetItemId(page, P_FIRSTKEY));
|
||||
/* page must have right pointer after split */
|
||||
_bt_updateitem(rel, keysz, pbuf, stack->bts_btitem->bti_oid,
|
||||
lowLeftItem);
|
||||
|
||||
/* this method does not work--_bt_updateitem tries to */
|
||||
/* overwrite an entry with another entry that might be */
|
||||
/* bigger. if lowLeftItem is bigger, it corrupts the */
|
||||
/* parent page. instead, we have to delete the original */
|
||||
/* leftmost item from the parent, and insert the new one */
|
||||
/* with a regular _bt_insertonpg (it could cause a split */
|
||||
/* because it's bigger than what was there before). */
|
||||
/* --djm 8/21/96 */
|
||||
|
||||
/* _bt_updateitem(rel, keysz, pbuf, stack->bts_btitem->bti_oid,
|
||||
lowLeftItem); */
|
||||
|
||||
/* get the parent page */
|
||||
ppage = BufferGetPage(pbuf);
|
||||
ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
|
||||
|
||||
/* figure out which key is leftmost (if the parent page */
|
||||
/* is rightmost, too, it must be the root) */
|
||||
if(P_RIGHTMOST(ppageop)) {
|
||||
leftmost_offset = P_HIKEY;
|
||||
} else {
|
||||
leftmost_offset = P_FIRSTKEY;
|
||||
}
|
||||
PageIndexTupleDelete(ppage, leftmost_offset);
|
||||
|
||||
/* don't write anything out yet--we still have the write */
|
||||
/* lock, and now we call another _bt_insertonpg to */
|
||||
/* insert the correct leftmost key */
|
||||
|
||||
/* make a new leftmost item, using the tuple data from */
|
||||
/* lowLeftItem. point it to the left child. */
|
||||
/* update it on the stack at the same time. */
|
||||
bknum = BufferGetBlockNumber(buf);
|
||||
pfree(stack->bts_btitem);
|
||||
stack->bts_btitem = _bt_formitem(&(lowLeftItem->bti_itup));
|
||||
ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
|
||||
bknum, P_HIKEY);
|
||||
|
||||
/* unlock the children before doing this */
|
||||
_bt_relbuf(rel, buf, BT_WRITE);
|
||||
_bt_relbuf(rel, rbuf, BT_WRITE);
|
||||
|
||||
/* a regular _bt_binsrch should find the right place to */
|
||||
/* put the new entry, since it should be lower than any */
|
||||
/* other key on the page, therefore set afteritem to NULL */
|
||||
newskey = _bt_mkscankey(rel, &(stack->bts_btitem->bti_itup));
|
||||
newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
|
||||
keysz, newskey, stack->bts_btitem,
|
||||
NULL);
|
||||
|
||||
pfree(newres);
|
||||
pfree(newskey);
|
||||
|
||||
/* don't need the children anymore */
|
||||
/* we have now lost our lock on the parent buffer, and */
|
||||
/* need to get it back. */
|
||||
pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
|
||||
} else {
|
||||
_bt_relbuf(rel, buf, BT_WRITE);
|
||||
_bt_relbuf(rel, rbuf, BT_WRITE);
|
||||
}
|
||||
|
||||
newskey = _bt_mkscankey(rel, &(new_item->bti_itup));
|
||||
newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
|
||||
@@ -787,6 +872,8 @@ _bt_itemcmp(Relation rel,
|
||||
return (true);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* gone since updating in place doesn't work in general --djm 11/13/96 */
|
||||
/*
|
||||
* _bt_updateitem() -- updates the key of the item identified by the
|
||||
* oid with the key of newItem (done in place if
|
||||
@@ -804,9 +891,9 @@ _bt_updateitem(Relation rel,
|
||||
OffsetNumber maxoff;
|
||||
OffsetNumber i;
|
||||
ItemPointerData itemPtrData;
|
||||
BTItem item, itemCopy;
|
||||
BTItem item;
|
||||
IndexTuple oldIndexTuple, newIndexTuple;
|
||||
int newSize, oldSize, first;
|
||||
int first;
|
||||
|
||||
page = BufferGetPage(buf);
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
@@ -825,48 +912,18 @@ _bt_updateitem(Relation rel,
|
||||
elog(FATAL, "_bt_getstackbuf was lying!!");
|
||||
}
|
||||
|
||||
if(IndexTupleDSize(newItem->bti_itup) >
|
||||
IndexTupleDSize(item->bti_itup)) {
|
||||
elog(NOTICE, "trying to overwrite a smaller value with a bigger one in _bt_updateitem");
|
||||
elog(WARN, "this is not good.");
|
||||
}
|
||||
|
||||
oldIndexTuple = &(item->bti_itup);
|
||||
newIndexTuple = &(newItem->bti_itup);
|
||||
oldSize = DOUBLEALIGN(IndexTupleSize(oldIndexTuple));
|
||||
newSize = DOUBLEALIGN(IndexTupleSize(newIndexTuple));
|
||||
#ifdef NBTINSERT_PATCH_DEBUG
|
||||
printf("_bt_updateitem: newSize=%d, oldSize=%d\n", newSize, oldSize);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If new and old item have the same size do the update in place
|
||||
* and return.
|
||||
*/
|
||||
if (oldSize == newSize) {
|
||||
/* keep the original item pointer */
|
||||
ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
|
||||
CopyIndexTuple(newIndexTuple, &oldIndexTuple);
|
||||
ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If new and old items have different size the update in place
|
||||
* is not possible. In this case the old item is deleted and the
|
||||
* new one is inserted.
|
||||
* The new insertion should be done using _bt_insertonpg which
|
||||
* would also takes care of the page splitting if needed, but
|
||||
* unfortunately it doesn't work, so PageAddItem is used instead.
|
||||
* There is the possibility that there is not enough space in the
|
||||
* page and the item is not inserted.
|
||||
*/
|
||||
itemCopy = palloc(newSize);
|
||||
memmove((char *) itemCopy, (char *) newItem, newSize);
|
||||
itemCopy->bti_oid = item->bti_oid;
|
||||
newIndexTuple = &(itemCopy->bti_itup);
|
||||
ItemPointerCopy(&(oldIndexTuple->t_tid), &(newIndexTuple->t_tid));
|
||||
|
||||
/*
|
||||
* Get the offset number of the item then delete it and insert
|
||||
* the new item in the same place.
|
||||
*/
|
||||
i = OffsetNumberPrev(i);
|
||||
PageIndexTupleDelete(page, i);
|
||||
PageAddItem(page, (Item) itemCopy, newSize, i, LP_USED);
|
||||
pfree(itemCopy);
|
||||
}
|
||||
#endif
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.9 1996/11/05 10:35:32 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.10 1996/11/13 20:47:18 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains only the public interface routines.
|
||||
@@ -74,6 +74,7 @@ btbuild(Relation heap,
|
||||
Oid hrelid, irelid;
|
||||
Node *pred, *oldPred;
|
||||
void *spool;
|
||||
bool isunique;
|
||||
|
||||
/* note that this is a new btree */
|
||||
BuildingBtree = true;
|
||||
@@ -81,6 +82,9 @@ btbuild(Relation heap,
|
||||
pred = predInfo->pred;
|
||||
oldPred = predInfo->oldPred;
|
||||
|
||||
/* see if index is unique */
|
||||
isunique = IndexIsUniqueNoCache(RelationGetRelationId(index));
|
||||
|
||||
/* initialize the btree index metadata page (if this is a new index) */
|
||||
if (oldPred == NULL)
|
||||
_bt_metapinit(index);
|
||||
@@ -218,7 +222,7 @@ btbuild(Relation heap,
|
||||
if (FastBuild) {
|
||||
_bt_spool(index, btitem, spool);
|
||||
} else {
|
||||
res = _bt_doinsert(index, btitem);
|
||||
res = _bt_doinsert(index, btitem, isunique, false);
|
||||
}
|
||||
|
||||
pfree(btitem);
|
||||
@@ -289,7 +293,7 @@ btbuild(Relation heap,
|
||||
* return an InsertIndexResult to the caller.
|
||||
*/
|
||||
InsertIndexResult
|
||||
btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid)
|
||||
btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid, bool is_update)
|
||||
{
|
||||
BTItem btitem;
|
||||
IndexTuple itup;
|
||||
@@ -304,7 +308,9 @@ btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid)
|
||||
|
||||
btitem = _bt_formitem(itup);
|
||||
|
||||
res = _bt_doinsert(rel, btitem);
|
||||
res = _bt_doinsert(rel, btitem,
|
||||
IndexIsUnique(RelationGetRelationId(rel)), is_update);
|
||||
|
||||
pfree(btitem);
|
||||
pfree(itup);
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.8 1996/11/05 10:35:34 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.9 1996/11/13 20:47:20 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
static BTStack _bt_searchr(Relation rel, int keysz, ScanKey scankey, Buffer *bufP, BTStack stack_in);
|
||||
static OffsetNumber _bt_firsteq(Relation rel, TupleDesc itupdesc, Page page, Size keysz, ScanKey scankey, OffsetNumber offnum);
|
||||
static int _bt_compare(Relation rel, TupleDesc itupdesc, Page page, int keysz, ScanKey scankey, OffsetNumber offnum);
|
||||
int _bt_compare(Relation rel, TupleDesc itupdesc, Page page, int keysz, ScanKey scankey, OffsetNumber offnum);
|
||||
static bool _bt_twostep(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
|
||||
static RetrieveIndexResult _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
|
||||
|
||||
@@ -413,7 +413,7 @@ _bt_firsteq(Relation rel,
|
||||
* a new minimal key is inserted, the leftmost entry on the leftmost
|
||||
* page is less than all possible keys, by definition.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
_bt_compare(Relation rel,
|
||||
TupleDesc itupdesc,
|
||||
Page page,
|
||||
|
Reference in New Issue
Block a user