head 1.49; access; symbols Version_2_1:1.13 C_Demo_1:1.5; locks; strict; comment @ * @; 1.49 date 92.08.24.23.14.44; author mao; state Exp; branches; next 1.48; 1.48 date 92.08.11.21.31.54; author mer; state Exp; branches; next 1.47; 1.47 date 92.07.30.20.47.53; author mao; state Exp; branches; next 1.46; 1.46 date 92.07.30.18.46.32; author mao; state Exp; branches; next 1.45; 1.45 date 92.07.29.20.40.21; author mao; state Exp; branches; next 1.44; 1.44 date 92.07.13.10.13.58; author hong; state Exp; branches; next 1.43; 1.43 date 92.07.13.07.38.10; author hong; state Exp; branches; next 1.42; 1.42 date 92.05.28.20.19.27; author mer; state Exp; branches; next 1.41; 1.41 date 92.05.05.18.52.24; author mer; state Exp; branches; next 1.40; 1.40 date 92.03.25.17.28.27; author hong; state Exp; branches; next 1.39; 1.39 date 92.03.05.00.35.58; author hong; state Exp; branches; next 1.38; 1.38 date 92.02.26.22.40.49; author mer; state Exp; branches; next 1.37; 1.37 date 92.02.26.22.33.45; author mer; state Exp; branches; next 1.36; 1.36 date 92.02.19.01.51.53; author mer; state Exp; branches; next 1.35; 1.35 date 91.11.09.09.57.48; author hong; state Exp; branches; next 1.34; 1.34 date 91.11.08.15.49.33; author kemnitz; state Exp; branches; next 1.33; 1.33 date 91.10.08.01.09.15; author hong; state Exp; branches; next 1.32; 1.32 date 91.09.06.15.47.35; author mer; state Exp; branches; next 1.31; 1.31 date 91.08.25.13.27.46; author hong; state Exp; branches; next 1.30; 1.30 date 91.08.14.12.39.36; author mer; state Exp; branches; next 1.29; 1.29 date 91.08.12.14.31.23; author mer; state Exp; branches; next 1.28; 1.28 date 91.08.07.14.11.39; author sp; state Exp; branches; next 1.27; 1.27 date 91.08.06.16.29.51; author sp; state Exp; branches; next 1.26; 1.26 date 91.08.01.11.05.17; author mer; state Exp; branches; next 1.25; 1.25 date 91.07.22.22.20.43; author mao; state Exp; branches; next 1.24; 1.24 date 91.06.03.21.37.52; author kemnitz; state Exp; branches; next 1.23; 1.23 date 91.06.03.15.32.50; author kemnitz; state Exp; branches; next 1.22; 1.22 date 91.06.03.02.59.57; author kemnitz; state Exp; branches; next 1.21; 1.21 date 91.05.27.00.26.02; author kemnitz; state Exp; branches; next 1.20; 1.20 date 91.05.26.00.30.37; author kemnitz; state Exp; branches; next 1.19; 1.19 date 91.05.24.17.37.36; author hong; state Exp; branches; next 1.18; 1.18 date 91.05.24.12.55.41; author hong; state Exp; branches; next 1.17; 1.17 date 91.05.01.02.49.15; author cimarron; state Exp; branches; next 1.16; 1.16 date 91.04.28.09.17.12; author cimarron; state Exp; branches; next 1.15; 1.15 date 91.03.22.00.28.46; author mao; state Exp; branches; next 1.14; 1.14 date 91.03.20.20.54.36; author cimarron; state Exp; branches; next 1.13; 1.13 date 91.03.06.11.21.20; author hong; state Exp; branches; next 1.12; 1.12 date 91.02.25.18.14.29; author hong; state Exp; branches; next 1.11; 1.11 date 91.02.07.13.16.56; author hong; state Exp; branches; next 1.10; 1.10 date 91.02.06.18.17.36; author cimarron; state Exp; branches; next 1.9; 1.9 date 90.11.20.15.49.50; author sp; state Exp; branches; next 1.8; 1.8 date 90.09.25.16.13.57; author kemnitz; state Exp; branches; next 1.7; 1.7 date 90.03.31.19.57.29; author cimarron; state Exp; branches; next 1.6; 1.6 date 89.09.28.17.43.10; author hirohama; state Exp; branches; next 1.5; 1.5 date 89.09.05.16.56.46; author mao; state C_Demo_1; branches; next 1.4; 1.4 date 89.08.10.17.26.42; author hirohama; state Exp; branches; next 1.3; 1.3 date 89.08.09.18.12.44; author cimarron; state Exp; branches; next 1.2; 1.2 date 89.02.02.16.28.58; author dillon; state Stab; branches; next 1.1; 1.1 date 89.01.17.05.52.08; author cimarron; state Exp; branches; next ; desc @@ 1.49 log @fix cache invalidation at command boundaries when building indices @ text @/* ---------------------------------------------------------------- * FILE * heapam.c * * DESCRIPTION * heap access method code * * INTERFACE ROUTINES * heapgettup - fetch next heap tuple from a scan * heap_open - open a heap relation by relationId * heap_openr - open a heap relation by name * heap_close - close a heap relation * heap_beginscan - begin relation scan * heap_rescan - restart a relation scan * heap_endscan - end relation scan * heap_getnext - retrieve next tuple in scan * heap_fetch - retrive tuple with tid * heap_insert - insert tuple into a relation * heap_delete - delete a tuple from a relation * heap_replace - replace a tuple in a relation with another tuple * heap_markpos - mark scan position * heap_restrpos - restore position to marked location * * NOTES * This file contains the heap_ routines which implement * the POSTGRES heap access method used for all POSTGRES * relations. * * old comments: * struct relscan hints: (struct should be made AM independent?) * * rs_ctid is the tid of the last tuple returned by getnext. * rs_ptid and rs_ntid are the tids of the previous and next tuples * returned by getnext, respectively. NULL indicates an end of * scan (either direction); NON indicates an unknow value. * * possible combinations: * rs_p rs_c rs_n interpretation * NULL NULL NULL empty scan * NULL NULL NON at begining of scan * NULL NULL t1 at begining of scan (with cached tid) * NON NULL NULL at end of scan * t1 NULL NULL at end of scan (with cached tid) * NULL t1 NULL just returned only tuple * NULL t1 NON just returned first tuple * NULL t1 t2 returned first tuple (with cached tid) * NON t1 NULL just returned last tuple * t2 t1 NULL returned last tuple (with cached tid) * t1 t2 NON in the middle of a forward scan * NON t2 t1 in the middle of a reverse scan * ti tj tk in the middle of a scan (w cached tid) * * Here NULL is ...tup == NULL && ...buf == InvalidBuffer, * and NON is ...tup == NULL && ...buf == UnknownBuffer. * * Currently, the NONTID values are not cached with their actual * values by getnext. Values may be cached by markpos since it stores * all three tids. * * NOTE: the calls to elog() must stop. Should decide on an interface * between the general and specific AM calls. * * XXX probably do not need a free tuple routine for heaps. * Huh? Free tuple is not necessary for tuples returned by scans, but * is necessary for tuples which are returned by * RelationGetTupleByItemPointer. -hirohama * * IDENTIFICATION * $Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.48 1992/08/11 21:31:54 mer Exp mao $ * ---------------------------------------------------------------- */ #include #include #include "tmp/postgres.h" RcsId("$Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.48 1992/08/11 21:31:54 mer Exp mao $"); #include "access/att.h" #include "access/attnum.h" #include "access/heapam.h" #include "access/hio.h" #include "access/hrnd.h" #include "access/htup.h" #include "access/relscan.h" #include "access/skey.h" #include "access/tqual.h" #include "access/valid.h" #include "access/xcxt.h" #include "access/xact.h" #include "catalog/catname.h" #include "rules/rac.h" #include "rules/rlock.h" #include "storage/buf.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" #include "storage/itemid.h" #include "storage/itemptr.h" #include "storage/page.h" #include "storage/lmgr.h" #include "tcop/slaves.h" #include "tcop/tcopdebug.h" #include "tmp/miscadmin.h" #include "utils/memutils.h" #include "utils/fmgr.h" #include "utils/inval.h" #include "utils/log.h" #include "utils/mcxt.h" #include "utils/rel.h" #include "utils/relcache.h" /* If RANDOMINSERT is defined, random pages will be examined to see if there * is space for insertion. If it is not defined, the new tuple is always * appended to the end. * plai 8/7/90 */ #undef RANDOMINSERT static bool ImmediateInvalidation; extern HeapAccessStatistics heap_access_stats; /* ---------------------------------------------------------------- * heap support routines * ---------------------------------------------------------------- */ /* ---------------- * initsdesc - sdesc code common to heap_beginscan and heap_rescan * ---------------- */ void initsdesc(sdesc, relation, atend, nkeys, key) HeapScanDesc sdesc; Relation relation; int atend; unsigned nkeys; ScanKey key; { if (!RelationGetNumberOfBlocks(relation)) { /* ---------------- * relation is empty * ---------------- */ sdesc->rs_ntup = sdesc->rs_ctup = sdesc->rs_ptup = NULL; sdesc->rs_nbuf = sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer; } else if (atend) { /* ---------------- * reverse scan * ---------------- */ sdesc->rs_ntup = sdesc->rs_ctup = NULL; sdesc->rs_nbuf = sdesc->rs_cbuf = InvalidBuffer; sdesc->rs_ptup = NULL; sdesc->rs_pbuf = UnknownBuffer; } else { /* ---------------- * forward scan * ---------------- */ sdesc->rs_ctup = sdesc->rs_ptup = NULL; sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer; sdesc->rs_ntup = NULL; sdesc->rs_nbuf = UnknownBuffer; } /* invalid too */ /* we don't have a marked position... */ ItemPointerSetInvalid(&(sdesc->rs_mptid)); ItemPointerSetInvalid(&(sdesc->rs_mctid)); ItemPointerSetInvalid(&(sdesc->rs_mntid)); ItemPointerSetInvalid(&(sdesc->rs_mcd)); /* ---------------- * copy the scan key, if appropriate * ---------------- */ if (key != NULL) bcopy((char *)&key->data[0], (char *)&sdesc->rs_key.data[0], (int)nkeys * sizeof *key); } /* ---------------- * unpinsdesc - code common to heap_rescan and heap_endscan * ---------------- */ void unpinsdesc(sdesc) HeapScanDesc sdesc; { if (BufferIsValid(sdesc->rs_pbuf)) { ReleaseBuffer(sdesc->rs_pbuf); } /* ------------------------------------ * each scan will only pin a buffer once, so make sure not to * unpin them multiple times. * ------------------------------------ */ if (sdesc->rs_cbuf != sdesc->rs_pbuf && BufferIsValid(sdesc->rs_cbuf)) { ReleaseBuffer(sdesc->rs_cbuf); } if (sdesc->rs_nbuf != sdesc->rs_cbuf && sdesc->rs_nbuf != sdesc->rs_pbuf && BufferIsValid(sdesc->rs_nbuf)) { ReleaseBuffer(sdesc->rs_nbuf); } } #define initskip(PARALLEL_OK) ((ParallelExecutorEnabled() && PARALLEL_OK)? \ SlaveLocalInfoD.startpage:0) /* ------------------------------------------ * nextpage * * figure out the next page to scan after the current page * taking into account of possible adjustment of degrees of * parallelism * ------------------------------------------ */ int nextpage(page, dir, parallel_ok) int page; int dir; bool parallel_ok; { int skip; int nextpage; if (!ParallelExecutorEnabled() || !parallel_ok) return((dir<0)?page-1:page+1); nextpage = paradj_nextpage(page, dir); if (nextpage == NULLPAGE) { skip = SlaveLocalInfoD.nparallel; nextpage = (dir<0)?page-skip:page+skip; } return nextpage; } /* ---------------- * heapgettup - fetch next heap tuple * * routine used by heap_getnext() which does most of the * real work in scanning tuples. * ---------------- */ static HeapTuple heapgettup(relation, tid, dir, b, timeQual, nkeys, key, parallel_ok) Relation relation; ItemPointer tid; int dir; Buffer *b; TimeQual timeQual; ScanKeySize nkeys; ScanKey key; bool parallel_ok; { ItemId lpp; Page dp; int page; int lineoff; int pages; int lines; HeapTuple rtup; OffsetIndex offsetIndex; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_heapgettup); IncrHeapAccessStat(global_heapgettup); /* ---------------- * debugging stuff * * check validity of arguments, here and for other functions too * Note: no locking manipulations needed--this is a local function * ---------------- */ #ifdef HEAPDEBUGALL if (ItemPointerIsValid(tid)) { elog(DEBUG, "heapgettup(%.16s, tid=0x%x[%d,%d], dir=%d, ...)", RelationGetRelationName(relation), tid, tid->blockData, tid->positionData, dir); } else { elog(DEBUG, "heapgettup(%.16s, tid=0x%x, dir=%d, ...)", RelationGetRelationName(relation), tid, dir); } elog(DEBUG, "heapgettup(..., b=0x%x, timeQ=0x%x, nkeys=%d, key=0x%x", b, timeQual, nkeys, key); if (timeQual == SelfTimeQual) { elog(DEBUG, "heapgettup: relation(%c)=`%.16s', SelfTimeQual", relation->rd_rel->relkind, &relation->rd_rel->relname); } else { elog(DEBUG, "heapgettup: relation(%c)=`%.16s', timeQual=%d", relation->rd_rel->relkind, &relation->rd_rel->relname, timeQual); } #endif /* !defined(HEAPDEBUGALL) */ if (!ItemPointerIsValid(tid)) { Assert(!PointerIsValid(tid)); } /* ---------------- * return null immediately if relation is empty * ---------------- */ if (!(pages = relation->rd_nblocks)) return (NULL); /* ---------------- * calculate next starting lineoff, given scan direction * ---------------- */ if (!dir) { /* ---------------- * ``no movement'' scan direction * ---------------- */ /* assume it is a valid TID XXX */ if (ItemPointerIsValid(tid) == false) { *b = InvalidBuffer; return (NULL); } *b = RelationGetBufferWithBuffer(relation, ItemPointerGetBlockNumber(tid), *b); #ifndef NO_BUFFERISVALID if (!BufferIsValid(*b)) { elog(WARN, "heapgettup: failed ReadBuffer"); } #endif dp = (Page) BufferSimpleGetPage(*b); offsetIndex = ItemPointerSimpleGetOffsetIndex(tid); lpp = PageGetItemId(dp, offsetIndex); Assert(!ItemIdIsLock(lpp)); rtup = (HeapTuple)PageGetItem((Page) dp, lpp); return (rtup); } else if (dir < 0) { /* ---------------- * reverse scan direction * ---------------- */ if (ItemPointerIsValid(tid) == false) { tid = NULL; } page = (tid == NULL) ? pages - 1 - initskip(parallel_ok) : ItemPointerGetBlockNumber(tid); if (page < 0) { *b = InvalidBuffer; return (NULL); } *b = RelationGetBufferWithBuffer(relation, page, *b); #ifndef NO_BUFFERISVALID if (!BufferIsValid(*b)) { elog(WARN, "heapgettup: failed ReadBuffer"); } #endif dp = (Page) BufferSimpleGetPage(*b); lines = 1 + PageGetMaxOffsetIndex(dp); lineoff = (tid == NULL) ? lines - 1 : ItemPointerSimpleGetOffsetIndex(tid) - 1; /* page and lineoff now reference the physically previous tid */ } else { /* ---------------- * forward scan direction * ---------------- */ if (ItemPointerIsValid(tid) == false) { page = initskip(parallel_ok); lineoff = 0; } else { page = ItemPointerGetBlockNumber(tid); lineoff = 1 + ItemPointerSimpleGetOffsetIndex(tid); } if (page >= pages) { *b = InvalidBuffer; return (NULL); } /* page and lineoff now reference the physically next tid */ *b = RelationGetBufferWithBuffer(relation, page, *b); #ifndef NO_BUFFERISVALID if (!BufferIsValid(*b)) { elog(WARN, "heapgettup: failed ReadBuffer"); } #endif dp = (Page) BufferSimpleGetPage(*b); lines = 1 + PageGetMaxOffsetIndex(dp); } /* ---------------- * calculate line pointer and number of remaining items * to check on this page. * * hack hack hack: * lineoff becomes the number of additional lines left to check * ---------------- */ lpp = PageGetItemId(dp, lineoff); lineoff = (dir < 0) ? lineoff : lines - lineoff - 1; /* ---------------- * advance the scan until we find a qualifying tuple or * run out of stuff to scan * ---------------- */ for (;;) { while (lineoff >= 0) { /* ---------------- * if current tuple qualifies, return it. * ---------------- */ if ((rtup = heap_tuple_satisfies(lpp, relation, (PageHeader) dp, timeQual, nkeys, key)) != NULL) { return (rtup); } /* ---------------- * otherwise move to the next item on the page * ---------------- */ lineoff--; (dir < 0) ? lpp-- : lpp++; } /* ---------------- * if we get here, it means we've exhausted the items on * this page and it's time to move to the next.. * ---------------- */ page = nextpage(page, dir, parallel_ok); /* ---------------- * return NULL if we've exhausted all the pages.. * ---------------- */ if (page < 0 || page >= pages) { if (BufferIsValid(*b)) ReleaseBuffer(*b); *b = InvalidBuffer; return (NULL); } *b = ReleaseAndReadBuffer(*b, relation, page); #ifndef NO_BUFFERISVALID if (!BufferIsValid(*b)) { elog(WARN, "heapgettup: failed ReadBuffer"); } #endif dp = (Page) BufferSimpleGetPage(*b); lines = 1 + PageGetMaxOffsetIndex((Page) dp); lineoff = lines - 1; if (dir < 0) { lpp = PageGetItemId(dp, lineoff); } else if (dir > 0) { lpp = PageGetFirstItemId(dp); } } } /* ---------------- * doinsert * * routine used by heap_insert() which in turn calls * RelationPutHeapTuple() or RelationPutLongHeapTuple(). * ---------------- */ RuleLock doinsert_old(relation, tup) Relation relation; HeapTuple tup; { Buffer b; PageHeader dp; int pages; BlockIndexList list; Index index; BlockNumber blockIndex; /* ---------------- * ??? -cim * ---------------- */ ItemPointerSetInvalid(&tup->t_chain); /* ---------------- * ??? -cim * ---------------- */ if (tup->t_len > MAXTUPLEN || !(pages = RelationGetNumberOfBlocks(relation))) { RelationPutLongHeapTuple(relation, tup); /* ??? */ return ((RuleLock)NULL); } /* ---------------- * compute proper location if cluster--passed as argument? * ---------------- */ blockIndex = pages - 1; #ifdef DOCLUSTER blockIndex = getclusterblockindex(); #endif DOCLUSTER /* ---------------- * ??? -cim * ---------------- */ if (BlockNumberIsValid(blockIndex)) { if (RelationContainsUsableBlock(relation, blockIndex, tup->t_len, ClusteredNumberOfFailures)) { #ifdef RANDOMDEBUG elog(DEBUG, "clustered@@%d", blockIndex); #endif RANDOMDEBUG } else { blockIndex = InvalidBlockNumber; } } /* ---------------- * ??? -cim * ---------------- */ #ifdef DOCLUSTER if (!BlockNumberIsValid(blockIndex)) { list = RelationGetRandomBlockIndexList(relation, tup->t_oid); for (index = 0; BlockNumberIsValid(list[index]); index += 1) { if (RelationContainsUsableBlock(relation, list[index], tup->t_len, index)) { blockIndex = list[index]; #ifdef RANDOMDEBUG elog(DEBUG, "append@@%d", blockIndex); #endif RANDOMDEBUG break; } } } #endif /* ---------------- * ??? -cim * ---------------- */ if (BlockNumberIsValid(blockIndex)) { /* ---------------- * we've finally found a block with space * for our tuple, so insert it there. * ---------------- */ RelationPutHeapTuple(relation, blockIndex, tup); setclusterblockindex(blockIndex); } #ifdef DOCLUSTER else if (BlockNumberIsValid(list[0])) { /* ---------------- * ??? -cim * ---------------- */ RelationPutLongHeapTuple(relation, tup); setclusterblockindex(pages); /* XXX PutLong assumption */ } #endif else { /* ---------------- * ??? -cim * ---------------- */ b = ReadBuffer(relation, pages - 1); #ifndef NO_BUFFERISVALID if (!BufferIsValid(b)) { /* XXX L_SH better ??? */ elog(WARN, "aminsert: failed ReadBuffer"); } #endif dp = (PageHeader)BufferSimpleGetPage(b); if ((int)tup->t_len > PageGetFreeSpace((Page) dp)) { ReleaseBuffer(b); /* XXX there is a window in which the status can change */ RelationPutLongHeapTuple(relation, tup); } else { ReleaseBuffer(b); /* XXX there is a window in which the status can change */ RelationPutHeapTuple(relation, pages - 1, tup); } } return ((RuleLock)NULL); } RuleLock doinsert(relation, tup) Relation relation; HeapTuple tup; { RelationPutHeapTupleAtEnd(relation, tup); return(NULL); } /* * HeapScanIsValid is now a macro in relscan.h -cim 4/27/91 */ /* ---------------- * SetHeapAccessMethodImmediateInvalidation * ---------------- */ void SetHeapAccessMethodImmediateInvalidation(on) bool on; { ImmediateInvalidation = on; } /* ---------------------------------------------------------------- * heap access method interface * ---------------------------------------------------------------- */ /* ---------------- * heap_open - open a heap relation by relationId * * presently the relcache routines do all the work we need * to open/close heap relations. * ---------------- */ Relation heap_open(relationId) ObjectId relationId; { Relation r; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_open); IncrHeapAccessStat(global_open); r = (Relation) RelationIdGetRelation(relationId); if (RelationIsValid(r) && r->rd_rel->relkind == 'i') { elog(WARN, "%.16s is an index relation", &(r->rd_rel->relname.data[0])); } return (r); } /* ---------------- * heap_openr - open a heap relation by name * * presently the relcache routines do all the work we need * to open/close heap relations. * ---------------- */ Relation heap_openr(relationName) Name relationName; { Relation r; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_openr); IncrHeapAccessStat(global_openr); r = (Relation) RelationNameGetRelation(relationName); if (RelationIsValid(r) && r->rd_rel->relkind == 'i') { elog(WARN, "%.16s is an index relation", &(r->rd_rel->relname.data[0])); } return (r); } /* ---------------- * heap_close - close a heap relation * * presently the relcache routines do all the work we need * to open/close heap relations. * ---------------- */ void heap_close(relation) Relation relation; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_close); IncrHeapAccessStat(global_close); (void) RelationClose(relation); } /* ---------------- * heap_beginscan - begin relation scan * ---------------- */ HeapScanDesc heap_beginscan(relation, atend, timeQual, nkeys, key) Relation relation; int atend; TimeQual timeQual; unsigned nkeys; ScanKey key; { HeapScanDesc sdesc; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_beginscan); IncrHeapAccessStat(global_beginscan); /* ---------------- * sanity checks * ---------------- */ if (RelationIsValid(relation) == false) elog(WARN, "heap_beginscan: !RelationIsValid(relation)"); /* ---------------- * set relation level read lock * ---------------- */ RelationSetLockForRead(relation); /* XXX someday assert SelfTimeQual if relkind == 'u' */ if (relation->rd_rel->relkind == 'u') { timeQual = SelfTimeQual; } /* ---------------- * increment relation ref count while scanning relation * ---------------- */ RelationIncrementReferenceCount(relation); /* ---------------- * allocate and initialize scan descriptor * ---------------- */ sdesc = (HeapScanDesc) palloc(sizeof *sdesc + (nkeys - 1) * sizeof key->data); /* XXX */ relation->rd_nblocks = smgrnblocks(relation->rd_rel->relsmgr, relation); sdesc->rs_rd = relation; initsdesc(sdesc, relation, atend, nkeys, key); sdesc->rs_atend = atend; sdesc->rs_tr = timeQual; sdesc->rs_nkeys = (short)nkeys; sdesc->rs_parallel_ok = false; return (sdesc); } /* ---------------- * heap_rescan - restart a relation scan * ---------------- */ void heap_rescan(sdesc, scanFromEnd, key) HeapScanDesc sdesc; bool scanFromEnd; ScanKey key; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_rescan); IncrHeapAccessStat(global_rescan); /* Note: set relation level read lock is still set */ /* ---------------- * unpin scan buffers * ---------------- */ unpinsdesc(sdesc); /* ---------------- * reinitialize scan descriptor * ---------------- */ initsdesc(sdesc, sdesc->rs_rd, scanFromEnd, sdesc->rs_nkeys, key); sdesc->rs_atend = (Boolean) scanFromEnd; } /* ---------------- * heap_endscan - end relation scan * * See how to integrate with index scans. * Check handling if reldesc caching. * ---------------- */ void heap_endscan(sdesc) HeapScanDesc sdesc; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_endscan); IncrHeapAccessStat(global_endscan); /* Note: no locking manipulations needed */ /* ---------------- * unpin scan buffers * ---------------- */ unpinsdesc(sdesc); /* ---------------- * decrement relation reference count and free scan descriptor storage * ---------------- */ RelationDecrementReferenceCount(sdesc->rs_rd); /* ---------------- * Non 2-phase read locks on catalog relations * ---------------- */ if ( issystem(RelationGetRelationName(sdesc->rs_rd)) ) RelationUnsetLockForRead(sdesc->rs_rd); pfree((char *)sdesc); /* XXX */ } /* ---------------- * heap_getnext - retrieve next tuple in scan * * Fix to work with index relations. * ---------------- */ #ifdef HEAPDEBUGALL #define HEAPDEBUG_1 \ elog(DEBUG, "heap_getnext([%.16s,nkeys=%d],backw=%d,0x%x) called", \ &sdesc->rs_rd->rd_rel->relname, sdesc->rs_nkeys, backw, b) #define HEAPDEBUG_2 \ elog(DEBUG, "heap_getnext called with backw (no tracing yet)") #define HEAPDEBUG_3 \ elog(DEBUG, "heap_getnext returns NULL at end") #define HEAPDEBUG_4 \ elog(DEBUG, "heap_getnext valid buffer UNPIN'd") #define HEAPDEBUG_5 \ elog(DEBUG, "heap_getnext next tuple was cached") #define HEAPDEBUG_6 \ elog(DEBUG, "heap_getnext returning EOS") #define HEAPDEBUG_7 \ elog(DEBUG, "heap_getnext returning tuple"); #else #define HEAPDEBUG_1 #define HEAPDEBUG_2 #define HEAPDEBUG_3 #define HEAPDEBUG_4 #define HEAPDEBUG_5 #define HEAPDEBUG_6 #define HEAPDEBUG_7 #endif /* !defined(HEAPDEBUGALL) */ HeapTuple heap_getnext(scandesc, backw, b) HeapScanDesc scandesc; int backw; Buffer *b; { register HeapScanDesc sdesc = scandesc; Buffer localb; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_getnext); IncrHeapAccessStat(global_getnext); /* Note: no locking manipulations needed */ /* ---------------- * argument checks * ---------------- */ if (sdesc == NULL) elog(WARN, "heap_getnext: NULL relscan"); /* ---------------- * initialize return buffer to InvalidBuffer * ---------------- */ if (! PointerIsValid(b)) b = &localb; (*b) = InvalidBuffer; HEAPDEBUG_1; /* heap_getnext( info ) */ if (backw) { /* ---------------- * handle reverse scan * ---------------- */ HEAPDEBUG_2; /* heap_getnext called with backw */ if (sdesc->rs_ptup == sdesc->rs_ctup && BufferIsInvalid(sdesc->rs_pbuf)) { if (BufferIsValid(sdesc->rs_nbuf)) ReleaseBuffer(sdesc->rs_nbuf); return (NULL); } /* * Copy the "current" tuple/buffer * to "next". Pin/unpin the buffers * accordingly */ if (sdesc->rs_nbuf != sdesc->rs_cbuf) { if (BufferIsValid(sdesc->rs_nbuf)) ReleaseBuffer(sdesc->rs_nbuf); if (BufferIsValid(sdesc->rs_cbuf)) IncrBufferRefCount(sdesc->rs_cbuf); } sdesc->rs_ntup = sdesc->rs_ctup; sdesc->rs_nbuf = sdesc->rs_cbuf; if (sdesc->rs_ptup != NULL) { if (sdesc->rs_cbuf != sdesc->rs_pbuf) { if (BufferIsValid(sdesc->rs_cbuf)) ReleaseBuffer(sdesc->rs_cbuf); if (BufferIsValid(sdesc->rs_pbuf)) IncrBufferRefCount(sdesc->rs_pbuf); } sdesc->rs_ctup = sdesc->rs_ptup; sdesc->rs_cbuf = sdesc->rs_pbuf; } else { /* NONTUP */ ItemPointer iptr; iptr = (sdesc->rs_ctup != NULL) ? &(sdesc->rs_ctup->t_ctid) : (ItemPointer) NULL; if (BufferIsValid(sdesc->rs_cbuf)) ReleaseBuffer(sdesc->rs_cbuf); sdesc->rs_ctup = (HeapTuple) heapgettup(sdesc->rs_rd, iptr, -1, &(sdesc->rs_cbuf), sdesc->rs_tr, sdesc->rs_nkeys, &(sdesc->rs_key), sdesc->rs_parallel_ok); } if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf)) { if (BufferIsValid(sdesc->rs_pbuf)) ReleaseBuffer(sdesc->rs_pbuf); sdesc->rs_ptup = NULL; sdesc->rs_pbuf = InvalidBuffer; if (BufferIsValid(sdesc->rs_nbuf)) ReleaseBuffer(sdesc->rs_nbuf); sdesc->rs_ntup = NULL; sdesc->rs_nbuf = InvalidBuffer; return (NULL); } if (BufferIsValid(sdesc->rs_pbuf)) ReleaseBuffer(sdesc->rs_pbuf); sdesc->rs_ptup = NULL; sdesc->rs_pbuf = UnknownBuffer; } else { /* ---------------- * handle forward scan * ---------------- */ if (sdesc->rs_ctup == sdesc->rs_ntup && BufferIsInvalid(sdesc->rs_nbuf)) { if (BufferIsValid(sdesc->rs_pbuf)) ReleaseBuffer(sdesc->rs_pbuf); HEAPDEBUG_3; /* heap_getnext returns NULL at end */ return (NULL); } /* * Copy the "current" tuple/buffer * to "previous". Pin/unpin the buffers * accordingly */ if (sdesc->rs_pbuf != sdesc->rs_cbuf) { if (BufferIsValid(sdesc->rs_pbuf)) ReleaseBuffer(sdesc->rs_pbuf); if (BufferIsValid(sdesc->rs_cbuf)) IncrBufferRefCount(sdesc->rs_cbuf); } sdesc->rs_ptup = sdesc->rs_ctup; sdesc->rs_pbuf = sdesc->rs_cbuf; if (sdesc->rs_ntup != NULL) { if (sdesc->rs_cbuf != sdesc->rs_nbuf) { if (BufferIsValid(sdesc->rs_cbuf)) ReleaseBuffer(sdesc->rs_cbuf); if (BufferIsValid(sdesc->rs_nbuf)) IncrBufferRefCount(sdesc->rs_nbuf); } sdesc->rs_ctup = sdesc->rs_ntup; sdesc->rs_cbuf = sdesc->rs_nbuf; HEAPDEBUG_5; /* heap_getnext next tuple was cached */ } else { /* NONTUP */ ItemPointer iptr; iptr = (sdesc->rs_ctup != NULL) ? &sdesc->rs_ctup->t_ctid : (ItemPointer) NULL; if (BufferIsValid(sdesc->rs_cbuf)) ReleaseBuffer(sdesc->rs_cbuf); sdesc->rs_ctup = (HeapTuple) heapgettup(sdesc->rs_rd, iptr, 1, &sdesc->rs_cbuf, sdesc->rs_tr, sdesc->rs_nkeys, &sdesc->rs_key, sdesc->rs_parallel_ok); } if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf)) { if (BufferIsValid(sdesc->rs_nbuf)) ReleaseBuffer(sdesc->rs_nbuf); sdesc->rs_ntup = NULL; sdesc->rs_nbuf = InvalidBuffer; if (BufferIsValid(sdesc->rs_pbuf)) ReleaseBuffer(sdesc->rs_pbuf); sdesc->rs_ptup = NULL; sdesc->rs_pbuf = InvalidBuffer; HEAPDEBUG_6; /* heap_getnext returning EOS */ return (NULL); } if (BufferIsValid(sdesc->rs_nbuf)) ReleaseBuffer(sdesc->rs_nbuf); sdesc->rs_ntup = NULL; sdesc->rs_nbuf = UnknownBuffer; } /* ---------------- * if we get here it means we have a new current scan tuple, so * point to the proper return buffer and return the tuple. * ---------------- */ (*b) = sdesc->rs_cbuf; HEAPDEBUG_7; /* heap_getnext returning tuple */ return (sdesc->rs_ctup); } /* ---------------- * heap_fetch - retrive tuple with tid * * Currently ignores LP_IVALID during processing! * ---------------- */ HeapTuple heap_fetch(relation, timeQual, tid, b) Relation relation; TimeQual timeQual; ItemPointer tid; Buffer *b; { ItemId lp; Buffer buffer; PageHeader dp; HeapTuple tuple; OffsetIndex offsetIndex; HeapTuple heap_copytuple(); /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_fetch); IncrHeapAccessStat(global_fetch); /* * Note: This is collosally expensive - does two system calls per * indexscan tuple fetch. Not good, and since we should be doing * page level locking by the scanner anyway, it is commented out. */ /* RelationSetLockForTupleRead(relation, tid); */ /* ---------------- * get the buffer from the relation descriptor * Note that this does a buffer pin. * ---------------- */ buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); #ifndef NO_BUFFERISVALID if (!BufferIsValid(buffer)) { elog(WARN, "heap_fetch: %s relation: ReadBuffer(%lx) failed", &relation->rd_rel->relname, (long)tid); } #endif /* ---------------- * get the item line pointer corresponding to the requested tid * ---------------- */ dp = (PageHeader) BufferSimpleGetPage(buffer); offsetIndex = ItemPointerSimpleGetOffsetIndex(tid); lp = PageGetItemId(dp, offsetIndex); /* ---------------- * more sanity checks * ---------------- */ Assert(ItemIdIsUsed(lp)); Assert(!(ItemIdIsContinuation(lp) || ItemIdIsInternal(lp))); /* ---------------- * check time qualification of tid * ---------------- */ tuple = heap_tuple_satisfies(lp, relation, dp, timeQual, 0,(ScanKey)NULL); if (tuple == NULL) { ReleaseBuffer(buffer); return (NULL); } /* ---------------- * all checks passed, now either return a copy of the tuple * or pin the buffer page and return a pointer, depending on * whether caller gave us a valid b. * ---------------- */ if (PointerIsValid(b)) { *b = buffer; } else { tuple = heap_copytuple(tuple, buffer, relation); ReleaseBuffer(buffer); } return (tuple); /* Note: lots of commented code was removed from here. */ } /* ---------------- * heap_insert - insert tuple * * The assignment of t_min (and thus the others) should be * removed eventually. * * Currently places the tuple onto the last page. If there is no room, * it is placed on new pages. (Heap relations) * Note that concurrent inserts during a scan will probably have * unexpected results, though this will be fixed eventually. * * Fix to work with indexes. * ---------------- */ ObjectId heap_insert(relation, tup, off) Relation relation; HeapTuple tup; double *off; { RuleLock returnMe; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_insert); IncrHeapAccessStat(global_insert); /* ---------------- * set relation level read lock * ---------------- */ RelationSetLockForWrite(relation); if (off != NULL) *off = -1.0; /* XXX ignore off for now */ /* ---------------- * If the object id of this tuple has already been assigned, trust * the caller. There are a couple of ways this can happen. At initial * db creation, the backend program sets oids for tuples. When we * define an index, we set the oid. Finally, in the future, we may * allow users to set their own object ids in order to support a * persistent object store (objects need to contain pointers to one * another). * ---------------- */ if (!ObjectIdIsValid(tup->t_oid)) { tup->t_oid = newoid(); LastOidProcessed = tup->t_oid; } TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin)); tup->t_cmin = GetCurrentCommandId(); PointerStoreInvalidTransactionId((Pointer)&(tup->t_xmax)); tup->t_tmin = InvalidTime; tup->t_tmax = InvalidTime; returnMe = doinsert(relation, tup); if ( issystem(RelationGetRelationName(relation)) ) RelationUnsetLockForWrite(relation); /* ---------------- * invalidate caches * ---------------- */ SetRefreshWhenInvalidate(ImmediateInvalidation); RelationInvalidateHeapTuple(relation, tup); SetRefreshWhenInvalidate((bool)!ImmediateInvalidation); return(tup->t_oid); } /* ---------------- * heap_delete - delete a tuple * * Must decide how to handle errors. * ---------------- */ RuleLock heap_delete(relation, tid) Relation relation; ItemPointer tid; { ItemId lp; HeapTuple tp; PageHeader dp; Buffer b; long time(); char *fmgr(); /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_delete); IncrHeapAccessStat(global_delete); /* ---------------- * sanity check * ---------------- */ Assert(ItemPointerIsValid(tid)); /* ---------------- * set relation level write lock * ---------------- */ RelationSetLockForWrite(relation); b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); #ifndef NO_BUFFERISVALID if (!BufferIsValid(b)) { /* XXX L_SH better ??? */ elog(WARN, "heap_delete: failed ReadBuffer"); } #endif NO_BUFFERISVALID dp = (PageHeader) BufferSimpleGetPage(b); lp = PageGetItemId(dp, ItemPointerSimpleGetOffsetIndex(tid)); /* ---------------- * check that we're deleteing a valid item * ---------------- */ if (!(tp = heap_tuple_satisfies(lp, relation, dp, NowTimeQual, 0, (ScanKey) NULL))) { /* XXX call something else */ ReleaseBuffer(b); elog(WARN, "heap_delete: (am)invalid tid"); } /* ---------------- * get the tuple and lock tell the buffer manager we want * exclusive access to the page * ---------------- */ /* ---------------- * store transaction information of xact deleting the tuple * ---------------- */ TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax)); tp->t_cmax = GetCurrentCommandId(); ItemPointerSetInvalid(&tp->t_chain); /* ---------------- * invalidate caches * ---------------- */ SetRefreshWhenInvalidate(ImmediateInvalidation); RelationInvalidateHeapTuple(relation, tp); SetRefreshWhenInvalidate((bool)!ImmediateInvalidation); WriteBuffer(b); if ( issystem(RelationGetRelationName(relation)) ) RelationUnsetLockForWrite(relation); } /* ---------------- * heap_replace - replace a tuple * * Must decide how to handle errors. * * Fix arguments, work with indexes. * ---------------- */ RuleLock heap_replace(relation, otid, tup) Relation relation; ItemPointer otid; HeapTuple tup; { ItemId lp; HeapTuple tp; Page dp; Buffer buffer; BlockIndexList list; BlockNumber blockIndex; Index index; long time(); /* know C */ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_replace); IncrHeapAccessStat(global_replace); /* ---------------- * sanity checks * ---------------- */ Assert(ItemPointerIsValid(otid)); /* ---------------- * set relation level write lock * ---------------- */ RelationSetLockForWrite(relation); buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid)); #ifndef NO_BUFFERISVALID if (!BufferIsValid(buffer)) { /* XXX L_SH better ??? */ elog(WARN, "amreplace: failed ReadBuffer"); } #endif NO_BUFFERISVALID dp = (Page) BufferSimpleGetPage(buffer); lp = PageGetItemId(dp, ItemPointerSimpleGetOffsetIndex(otid)); /* ---------------- * logically delete old item * ---------------- */ tp = (HeapTuple) PageGetItem(dp, lp); Assert(HeapTupleIsValid(tp)); /* ----------------- * the following test should be able to catch all non-functional * update attempts and shut out all ghost tuples. * XXX In the future, Spyros may need to update the rule lock on a tuple * more than once within the same command and same transaction. * He will have to introduce a new flag to override the following check. * -- Wei * * ----------------- */ if (TupleUpdatedByCurXactAndCmd(tp)) { elog(NOTICE, "Non-functional update, only first update is performed"); if ( issystem(RelationGetRelationName(relation)) ) RelationUnsetLockForWrite(relation); ReleaseBuffer(buffer); return (RuleLock)NULL; } /* ---------------- * check that we're replacing a valid item - * * NOTE that this check must follow the non-functional update test * above as it can happen that we try to 'replace' the same tuple * twice in a single transaction. The second time around the * tuple will fail the NowTimeQual. We don't want to abort the * xact, we only want to flag the 'non-functional' NOTICE. -mer * ---------------- */ if (!heap_tuple_satisfies(lp, relation, (PageHeader)dp, NowTimeQual, (ScanKeySize)0, (ScanKey)NULL)) { ReleaseBuffer(buffer); elog(WARN, "heap_replace: (am)invalid otid"); } /* XXX order problems if not atomic assignment ??? */ tup->t_oid = tp->t_oid; TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin)); tup->t_cmin = GetCurrentCommandId(); PointerStoreInvalidTransactionId((Pointer)&(tup->t_xmax)); tup->t_tmin = InvalidTime; tup->t_tmax = InvalidTime; ItemPointerSetInvalid(&tup->t_chain); /* ---------------- * insert new item * ---------------- */ if ((int)tup->t_len <= PageGetFreeSpace((Page) dp)) { RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), tup); } else { /* ---------------- * new item won't fit on same page as old item, have to look * for a new place to put it. * ---------------- */ #ifdef RANDOMINSERT list = RelationGetRandomBlockIndexList(relation, tup->t_oid); blockIndex = InvalidBlockNumber; for (index = 0; BlockNumberIsValid(list[index]); index += 1) { if (RelationContainsUsableBlock(relation, list[index], tup->t_len, index)) { blockIndex = list[index]; #ifdef RANDOMDEBUG elog(DEBUG, "replace@@%d", blockIndex); #endif /* defined(RANDOMDEBUG) */ break; } } if (BlockNumberIsValid(blockIndex)) { RelationPutHeapTuple(relation, blockIndex, tup); /* should check if last block is usable plai 8/9/90 */ } else if (blockIndex = RelationGetNumberOfBlocks(relation) - 1, RelationContainsUsableBlock(relation, blockIndex, tup->t_len, index)) { RelationPutHeapTuple(relation, blockIndex, tup); } else { RelationPutLongHeapTuple(relation, tup); } #else /* RANDOMINSERT */ /* should check if last block is usable plai 8/9/90 */ if (blockIndex = RelationGetNumberOfBlocks(relation) - 1, RelationContainsUsableBlock(relation, blockIndex, tup->t_len, 0)) { RelationPutHeapTuple(relation, blockIndex, tup); } else { RelationPutLongHeapTuple(relation, tup); } #endif /* RANDOMINSERT */ } /* ---------------- * new item in place, now record transaction information * ---------------- */ TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax)); tp->t_cmax = GetCurrentCommandId(); tp->t_chain = tup->t_ctid; /* ---------------- * invalidate caches * ---------------- */ SetRefreshWhenInvalidate(ImmediateInvalidation); RelationInvalidateHeapTuple(relation, tp); SetRefreshWhenInvalidate((bool)!ImmediateInvalidation); WriteBuffer(buffer); if ( issystem(RelationGetRelationName(relation)) ) RelationUnsetLockForWrite(relation); return ((RuleLock)NULL); /* XXX */ } /* ---------------- * heap_markpos - mark scan position * * Note: * Should only one mark be maintained per scan at one time. * Check if this can be done generally--say calls to get the * next/previous tuple and NEVER pass struct scandesc to the * user AM's. Now, the mark is sent to the executor for safekeeping. * Probably can store this info into a GENERAL scan structure. * * May be best to change this call to store the marked position * (up to 2?) in the scan structure itself. * Fix to use the proper caching structure. * ---------------- */ void heap_markpos(sdesc) HeapScanDesc sdesc; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_markpos); IncrHeapAccessStat(global_markpos); /* Note: no locking manipulations needed */ if (sdesc->rs_ptup == NULL && BufferIsUnknown(sdesc->rs_pbuf)) { /* == NONTUP */ sdesc->rs_ptup = (HeapTuple) heapgettup(sdesc->rs_rd, (sdesc->rs_ctup == NULL) ? (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid, -1, &sdesc->rs_pbuf, sdesc->rs_tr, sdesc->rs_nkeys, &sdesc->rs_key, sdesc->rs_parallel_ok); } else if (sdesc->rs_ntup == NULL && BufferIsUnknown(sdesc->rs_nbuf)) { /* == NONTUP */ sdesc->rs_ntup = (HeapTuple) heapgettup(sdesc->rs_rd, (sdesc->rs_ctup == NULL) ? (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid, 1, &sdesc->rs_nbuf, sdesc->rs_tr, sdesc->rs_nkeys, &sdesc->rs_key, sdesc->rs_parallel_ok); } /* ---------------- * Should not unpin the buffer pages. They may still be in use. * ---------------- */ if (sdesc->rs_ptup != NULL) { sdesc->rs_mptid = sdesc->rs_ptup->t_ctid; } else { ItemPointerSetInvalid(&sdesc->rs_mptid); } if (sdesc->rs_ctup != NULL) { sdesc->rs_mctid = sdesc->rs_ctup->t_ctid; } else { ItemPointerSetInvalid(&sdesc->rs_mctid); } if (sdesc->rs_ntup != NULL) { sdesc->rs_mntid = sdesc->rs_ntup->t_ctid; } else { ItemPointerSetInvalid(&sdesc->rs_mntid); } } /* ---------------- * heap_restrpos - restore position to marked location * * Note: there are bad side effects here. If we were past the end * of a relation when heapmarkpos is called, then if the relation is * extended via insert, then the next call to heaprestrpos will set * cause the added tuples to be visible when the scan continues. * Problems also arise if the TID's are rearranged!!! * * XXX might be better to do direct access instead of * using the generality of heapgettup(). * * XXX It is very possible that when a scan is restored, that a tuple * XXX which previously qualified may fail for time range purposes, unless * XXX some form of locking exists (ie., portals currently can act funny. * ---------------- */ void heap_restrpos(sdesc) HeapScanDesc sdesc; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_restrpos); IncrHeapAccessStat(global_restrpos); /* XXX no amrestrpos checking that ammarkpos called */ /* Note: no locking manipulations needed */ if (BufferIsValid(sdesc->rs_pbuf)) { ReleaseBuffer(sdesc->rs_pbuf); } if (BufferIsValid(sdesc->rs_cbuf)) { ReleaseBuffer(sdesc->rs_cbuf); } if (BufferIsValid(sdesc->rs_nbuf)) { ReleaseBuffer(sdesc->rs_nbuf); } if (!ItemPointerIsValid(&sdesc->rs_mptid)) { sdesc->rs_ptup = NULL; sdesc->rs_pbuf = InvalidBuffer; } else { sdesc->rs_ptup = (HeapTuple) heapgettup(sdesc->rs_rd, &sdesc->rs_mptid, 0, &sdesc->rs_pbuf, NowTimeQual, 0, (ScanKey) NULL, sdesc->rs_parallel_ok); } if (!ItemPointerIsValid(&sdesc->rs_mctid)) { sdesc->rs_ctup = NULL; sdesc->rs_cbuf = InvalidBuffer; } else { sdesc->rs_ctup = (HeapTuple) heapgettup(sdesc->rs_rd, &sdesc->rs_mctid, 0, &sdesc->rs_cbuf, NowTimeQual, 0, (ScanKey) NULL, sdesc->rs_parallel_ok); } if (!ItemPointerIsValid(&sdesc->rs_mntid)) { sdesc->rs_ntup = NULL; sdesc->rs_nbuf = InvalidBuffer; } else { sdesc->rs_ntup = (HeapTuple) heapgettup(sdesc->rs_rd, &sdesc->rs_mntid, 0, &sdesc->rs_nbuf, NowTimeQual, 0, (ScanKey) NULL, sdesc->rs_parallel_ok); } } @ 1.48 log @fix xact abortion on non-functional updates @ text @d69 1 a69 1 * $Header: /private/mer/pg/src/access/heap/RCS/heapam.c,v 1.47 1992/07/30 20:47:53 mao Exp mer $ d79 1 a79 1 RcsId("$Header: /private/mer/pg/src/access/heap/RCS/heapam.c,v 1.47 1992/07/30 20:47:53 mao Exp mer $"); a1140 9 /* ---------------- * sanity checks * ---------------- */ Assert(RelationIsValid(relation)); Assert(relation->rd_rel->relkind == 'r'); /* Note: set tuple level read lock */ @ 1.47 log @invalidate caches on insert @ text @d69 1 a69 1 * $Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.46 1992/07/30 18:46:32 mao Exp mao $ d79 1 a79 1 RcsId("$Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.46 1992/07/30 18:46:32 mao Exp mao $"); d1443 1 a1443 1 * check that we're replacing a valid item a1445 7 if (!(tp = heap_tuple_satisfies(lp, relation, (PageHeader) dp, NowTimeQual, (ScanKeySize) 0, (ScanKey) NULL))) { ReleaseBuffer(buffer); elog(WARN, "heap_replace: (am)invalid otid"); } d1447 2 a1448 4 /* ---------------- * logically delete old item * ---------------- */ d1468 22 @ 1.46 log @be careful about the condition you check to determine whether you're doing heap_open on a heap. @ text @d69 1 a69 1 * $Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.45 1992/07/29 20:40:21 mao Exp mao $ d79 1 a79 1 RcsId("$Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.45 1992/07/29 20:40:21 mao Exp mao $"); d1287 8 @ 1.45 log @elog(WARN, ...) on heap_open{,r} of anything other than heap relations @ text @d69 1 a69 1 * $Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.44 1992/07/13 10:13:58 hong Exp mao $ d79 1 a79 1 RcsId("$Header: /private/mao/postgres/src/access/heap/RCS/heapam.c,v 1.44 1992/07/13 10:13:58 hong Exp mao $"); d676 3 a678 7 if (RelationIsValid(r) && r->rd_rel->relkind != 'r') { if (r->rd_rel->relkind == 'i') elog(WARN, "%.16s is an index relation", &(r->rd_rel->relname.data[0])); else elog(WARN, "%.16s is not a heap relation", &(r->rd_rel->relname.data[0])); d706 3 a708 7 if (RelationIsValid(r) && r->rd_rel->relkind != 'r') { if (r->rd_rel->relkind == 'i') elog(WARN, "%.16s is an index relation", &(r->rd_rel->relname.data[0])); else elog(WARN, "%.16s is not a heap relation", &(r->rd_rel->relname.data[0])); @ 1.44 log @prototyping @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.43 92/07/13 07:38:10 hong Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.43 92/07/13 07:38:10 hong Exp Locker: hong $"); d665 2 d674 12 a685 2 return (Relation) RelationIdGetRelation(relationId); d699 2 d708 12 a719 2 return (Relation) RelationNameGetRelation(relationName); @ 1.43 log @removed a redundant ReleaseBuffer() call @ text @d69 1 a69 1 * $Header: /home/postgres/hong/postgres/src/access/heap/RCS/heapam.c,v 1.42 1992/05/28 20:19:27 mer Exp $ d79 1 a79 1 RcsId("$Header: /home/postgres/hong/postgres/src/access/heap/RCS/heapam.c,v 1.42 1992/05/28 20:19:27 mer Exp $"); d1457 1 a1457 1 PointerStoreInvalidTransactionId(&(tup->t_xmax)); @ 1.42 log @transaction ids are now longs, need to pass address of in some cases @ text @d69 1 a69 1 * $Header: /private/mer/pg.latest/src/access/heap/RCS/heapam.c,v 1.41 1992/05/05 18:52:24 mer Exp mer $ d79 1 a79 1 RcsId("$Header: /private/mer/pg.latest/src/access/heap/RCS/heapam.c,v 1.41 1992/05/05 18:52:24 mer Exp mer $"); a454 1 ReleaseBuffer(*b); @ 1.41 log @return oid of new tuple from heap_insert() @ text @d69 1 a69 1 * $Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.40 1992/03/25 17:28:27 hong Exp mer $ d79 1 a79 1 RcsId("$Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.40 1992/03/25 17:28:27 hong Exp mer $"); d1262 1 a1262 1 TransactionIdStore(GetCurrentTransactionId(), (Pointer)tup->t_xmin); d1264 1 a1264 1 PointerStoreInvalidTransactionId((Pointer)tup->t_xmax); d1348 1 a1348 1 TransactionIdStore(GetCurrentTransactionId(), (Pointer)tp->t_xmax); d1456 1 a1456 1 TransactionIdStore(GetCurrentTransactionId(), (Pointer)tup->t_xmin); d1458 1 a1458 1 PointerStoreInvalidTransactionId((Pointer)tup->t_xmax); d1522 1 a1522 1 TransactionIdStore(GetCurrentTransactionId(), (Pointer)tp->t_xmax); @ 1.40 log @plugged more buffer leaks @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.39 92/03/05 00:35:58 hong Exp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.39 92/03/05 00:35:58 hong Exp $"); d1222 1 a1222 1 RuleLock d1273 1 a1273 1 return(returnMe); @ 1.39 log @cleaning up and whacking out buffer leaks @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.38 92/02/26 22:40:49 mer Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.38 92/02/26 22:40:49 mer Exp Locker: hong $"); d201 6 a206 1 if (BufferIsValid(sdesc->rs_cbuf)) { d210 3 a212 1 if (BufferIsValid(sdesc->rs_nbuf)) { d1451 1 @ 1.38 log @get rid of processing mode check. Handle define index problem differently @ text @d69 1 a69 1 * $Header: /u/mer/pg/src/access/heap/RCS/heapam.c,v 1.37 1992/02/26 22:33:45 mer Exp mer $ d79 1 a79 1 RcsId("$Header: /u/mer/pg/src/access/heap/RCS/heapam.c,v 1.37 1992/02/26 22:33:45 mer Exp mer $"); d198 1 a198 1 BufferPut(sdesc->rs_pbuf, L_UNPIN); d202 1 a202 1 BufferPut(sdesc->rs_cbuf, L_UNPIN); d206 1 a206 1 BufferPut(sdesc->rs_nbuf, L_UNPIN); d334 1 a334 1 elog(WARN, "heapgettup: failed RelationGetBuffer"); a344 2 if (BufferPut(*b, L_PIN) < 0) elog(WARN, "heapgettup: failed BufferPut"); d366 1 a366 1 elog(WARN, "heapgettup: failed RelationGetBuffer"); d399 1 a399 1 elog(WARN, "heapgettup: failed RelationGetBuffer"); a430 2 if (BufferPut(*b, L_PIN) < 0) elog(WARN, "heap_fetch: failed BufferPut"); d448 1 a448 3 if (BufferPut(*b, L_UN | L_SH) < 0) { elog(WARN, "heapgettup: failed BufferPut"); } d467 1 a467 1 elog(WARN, "heapgettup: failed RelationGetBuffer"); d596 1 a596 1 b = RelationGetBuffer(relation, pages - 1, L_UP); d600 1 a600 1 elog(WARN, "aminsert: failed RelationGetBuffer"); d606 1 a606 2 if (BufferPut(b, L_UN | L_UP) < 0) elog(WARN, "aminsert: failed BufferPut"); d610 1 a610 2 if (BufferPut(b, L_UN | L_UP) < 0) elog(WARN, "aminsert: failed BufferPut"); d940 2 a945 5 if (BufferIsValid(sdesc->rs_nbuf)) BufferPut(sdesc->rs_nbuf, L_UNPIN); */ /* d974 2 d993 4 d1012 2 a1018 8 if (BufferIsValid(sdesc->rs_pbuf)) { HEAPDEBUG_4; BufferPut(sdesc->rs_pbuf, L_UNPIN); } */ /* d1048 3 d1067 4 d1143 1 a1143 3 buffer = RelationGetBuffer(relation, ItemPointerGetBlockNumber(tid), L_SH); d1147 1 a1147 1 elog(WARN, "heap_fetch: %s relation: RelationGetBuffer(%lx) failed", d1178 1 a1178 2 if (BufferPut(buffer, L_UNPIN) < 0) elog(WARN, "heap_fetch: BufferPut failed"); d1193 1 a1193 3 if (BufferPut(buffer, L_UNPIN) < 0) { elog(WARN, "heap_fetch: BufferPut failed"); } d1307 1 a1307 1 b = RelationGetBuffer(relation, ItemPointerGetBlockNumber(tid), L_UP); d1311 1 a1311 1 elog(WARN, "heap_delete: failed RelationGetBuffer"); d1326 1 a1326 2 if (BufferPut(b, L_UN | L_UP) < 0) elog(WARN, "heap_delete: failed BufferPut"); a1336 4 /* XXX order problems if not atomic assignment ??? */ if (BufferPut(b, L_EX) < 0) elog(WARN, "heap_delete: failed BufferPut(L_EX)"); d1353 1 a1353 3 if (BufferPut(b, L_UN | L_EX | L_WRITE) < 0) { elog(WARN, "heap_delete: failed BufferPut(L_UN | L_WRITE)"); } d1401 1 a1401 3 buffer = RelationGetBuffer(relation, ItemPointerGetBlockNumber(otid), L_UP); d1405 1 a1405 1 elog(WARN, "amreplace: failed RelationGetBuffer"); d1419 1 a1419 3 /* XXX call something else */ if (BufferPut(buffer, L_UN | L_UP) < 0) elog(WARN, "heap_replace: failed BufferPut"); a1513 3 if (BufferPut(buffer, L_EX) < 0) { elog(WARN, "amreplace: failed BufferPut(L_EX)"); } d1526 1 a1526 3 if (BufferPut(buffer, L_UN | L_EX | L_WRITE) < 0) { elog(WARN, "heap_replace: failed BufferPut(L_UN | L_WRITE)"); } d1644 1 a1644 1 BufferPut(sdesc->rs_pbuf, L_UNPIN); d1647 1 a1647 1 BufferPut(sdesc->rs_cbuf, L_UNPIN); d1650 1 a1650 1 BufferPut(sdesc->rs_nbuf, L_UNPIN); @ 1.37 log @Don't check for multiple updates to same tup when bootstrapping. @ text @d69 1 a69 1 * $Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.36 1992/02/19 01:51:53 mer Exp mer $ d79 1 a79 1 RcsId("$Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.36 1992/02/19 01:51:53 mer Exp mer $"); a1456 2 * mer has introduced a disabling flag -- don't do it during bootstrap, * it screws up index definition. d1460 1 a1460 1 if (IsNormalProcessingMode() && TupleUpdatedByCurXactAndCmd(tp)) { @ 1.36 log @changes for the new abstime implementation @ text @d69 1 a69 1 * $Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.35 1991/11/09 09:57:48 hong Exp mer $ d79 1 a79 1 RcsId("$Header: /users/mer/pg/src/access/heap/RCS/heapam.c,v 1.35 1991/11/09 09:57:48 hong Exp mer $"); d1456 3 d1462 1 a1462 1 if (TupleUpdatedByCurXactAndCmd(tp)) { @ 1.35 log @changes to support adjustment of parallelism @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.34 91/11/08 15:49:33 kemnitz Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.34 91/11/08 15:49:33 kemnitz Exp Locker: hong $"); d89 1 a1356 1 /* tp->t_tmax = InvalidTime; */ a1537 1 /* tp->t_tmax = InvalidTime; */ @ 1.34 log @prototype checkin @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.33 91/10/08 01:09:15 hong Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.33 91/10/08 01:09:15 hong Exp Locker: hong $"); d227 1 d231 6 a236 10 if (SlaveLocalInfoD.paradjpending) if (page >= SlaveLocalInfoD.paradjpage) { SLAVE2_elog(DEBUG, "slave %d adjusting page skip to %d", MyPid, SlaveLocalInfoD.newparallel); SlaveLocalInfoD.nparallel = SlaveLocalInfoD.newparallel; SlaveLocalInfoD.paradjpending = false; return(SlaveLocalInfoD.paradjpage + SlaveInfoP[MyPid].groupPid); } skip = SlaveLocalInfoD.nparallel; return((dir<0)?page-skip:page+skip); @ 1.33 log @just added some debugging info statements @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.32 91/09/06 15:47:35 mer Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.32 91/09/06 15:47:35 mer Exp Locker: hong $"); d92 1 d257 1 a257 1 uint32 nkeys; d262 1 a262 1 PageHeader dp; d340 1 a340 1 dp = (PageHeader) BufferSimpleGetPage(*b); d346 1 a346 1 rtup = (HeapTuple)PageGetItem(dp, lpp); d374 1 a374 1 dp = (PageHeader) BufferSimpleGetPage(*b); d407 1 a407 1 dp = (PageHeader) BufferSimpleGetPage(*b); d433 1 a433 1 if ((rtup = heap_tuple_satisfies(lpp, relation, dp, d456 1 a456 1 } d478 2 a479 2 dp = (PageHeader) BufferSimpleGetPage(*b); lines = 1 + PageGetMaxOffsetIndex(dp); d613 1 a613 1 if ((int)tup->t_len > PageGetFreeSpace(dp)) { d1394 1 a1394 1 PageHeader dp; d1430 1 a1430 1 dp = (PageHeader) BufferSimpleGetPage(buffer); d1437 2 a1438 2 if (!(tp = heap_tuple_satisfies(lp, relation, dp, NowTimeQual, 0, (ScanKey) NULL))) { d1481 1 a1481 1 if ((int)tup->t_len <= PageGetFreeSpace(dp)) { @ 1.32 log @change calls to IsSystemRelation to issystem() -- the former does not work properly and will be killed sooon. @ text @d69 1 a69 1 * $Header: /users/mer/postgres/src/access/heap/RCS/heapam.c,v 1.31 1991/08/25 13:27:46 hong Exp mer $ d79 1 a79 1 RcsId("$Header: /users/mer/postgres/src/access/heap/RCS/heapam.c,v 1.31 1991/08/25 13:27:46 hong Exp mer $"); d106 1 d231 2 @ 1.31 log @added support for dynamic parallelism adjustment @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.30 91/08/14 12:39:36 mer Exp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.30 91/08/14 12:39:36 mer Exp $"); d856 1 a856 1 if ( IsSystemRelation(sdesc->rs_rd) ) d1270 1 a1270 1 if ( IsSystemRelation(relation) ) d1369 1 a1369 1 if ( IsSystemRelation(relation) ) d1460 1 a1460 1 if ( IsSystemRelation(relation) ) d1552 1 a1552 1 if ( IsSystemRelation(relation) ) @ 1.30 log @make locking on all system catalogs non 2 phase. @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.29 91/08/12 14:31:23 mer Exp Locker: mer $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.29 91/08/12 14:31:23 mer Exp Locker: mer $"); d105 1 d206 32 d247 1 a247 1 heapgettup(relation, tid, dir, b, timeQual, nkeys, key, pageskip, initskip) d255 1 a255 2 int pageskip; int initskip; d356 1 a356 1 pages - 1 - initskip : ItemPointerGetBlockNumber(tid); d382 1 a382 1 page = initskip; d454 1 a454 4 if (dir < 0) page -= pageskip; else page += pageskip; d782 1 a782 2 sdesc->pageskip = 1; sdesc->initskip = 0; a909 2 int pageskip; int initskip; a910 3 pageskip = scandesc->pageskip; initskip = scandesc->initskip; d991 1 a991 2 pageskip, initskip); d1065 1 a1065 2 pageskip, initskip); a1576 1 int pageskip, initskip; a1577 3 pageskip = sdesc->pageskip; initskip = sdesc->initskip; d1598 1 a1598 2 pageskip, initskip); d1611 1 a1611 2 pageskip, initskip); a1655 2 int pageskip, initskip; d1689 1 a1689 2 pageskip, initskip); d1704 1 a1704 2 pageskip, initskip); d1719 1 a1719 2 pageskip, initskip); @ 1.29 log @non 2-phase read locks on pg_type @ text @d69 1 a69 1 * $Header: /users/mer/postgres/src/access/heap/RCS/heapam.c,v 1.28 91/08/07 14:11:39 sp Exp Locker: mer $ d79 1 a79 1 RcsId("$Header: /users/mer/postgres/src/access/heap/RCS/heapam.c,v 1.28 91/08/07 14:11:39 sp Exp Locker: mer $"); d825 1 a825 1 * Non 2-phase read locks on pg_type d828 1 a828 1 if ( RelationGetRelationId(sdesc->rs_rd) == RelOid_pg_type ) d1207 2 d1247 6 a1252 1 return(doinsert(relation, tup)); d1348 2 d1439 2 d1530 3 @ 1.28 log @Now a buffer is pinned every time it is referenced in a scandesc (as "current", "previous", and/or "next"). @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.27 91/08/06 16:29:51 sp Exp Locker: sp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.27 91/08/06 16:29:51 sp Exp Locker: sp $"); d823 8 @ 1.27 log @heap_endscan was releasing all the buffers in scandesc, while only one of them was pinned. @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.26 91/08/01 11:05:17 mer Exp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.26 91/08/01 11:05:17 mer Exp $"); d193 3 a195 13 /*----------------------------- * NOTE: Currently we only pin the "current" buffer * (i.e the sdesc->rs_cbuf). * Both the "previous" (sdesc->rs_pbuf) and "next" * (sdesc->rs_nbuf) are NOT pinned! * Therefore, we must not unpin them. * See comments in 'heap_getnext'. *----------------------------- * * if (BufferIsValid(sdesc->rs_pbuf)) { * BufferPut(sdesc->rs_pbuf, L_UNPIN); * } */ d201 3 a203 5 /*----------------------------- * if (BufferIsValid(sdesc->rs_nbuf)) { * BufferPut(sdesc->rs_nbuf, L_UNPIN); * } */ a829 16 * * XXX: NOTE: -- sp 6/Aug/91 * Buffers are correctly pinned/unpinned for the 'current' tuple. * I.e. 'heapgettup' makes sure that 'scandesc.rs_cbuf' is * pinned, and if we cross page boundaries the previous buffer * is unpinned. * So, at any time we only have ONE buffer pinned (the current one). * The "previous" (scandesc.rs_pbuf) is NOT necessarily pinned!!!! * (but luckily enough to the best of my knowledge nobody uses it) * * Therefore, when we call heap_endscan we must only unpin the * "current" buffer and not the "previous" (or "next") one. * * If at a later time someone is going to use the "previous" tuple/buffer * we must change the code, so that the previous buffer is correctly * pinned and unpinned. d923 11 d938 6 d964 1 a964 2 if (sdesc->rs_ctup == NULL && ! BufferIsValid(sdesc->rs_cbuf)) d966 2 d973 2 d996 12 d1012 6 d1039 3 a1041 2 if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf)) { d1048 2 @ 1.26 log @cleanup lmgr.h include @ text @d69 1 a69 1 * $Header: access/heap/RCS/heapam.c,v 1.25 91/07/22 22:20:43 mao Exp Locker: mer $ d79 1 a79 1 RcsId("$Header: access/heap/RCS/heapam.c,v 1.25 91/07/22 22:20:43 mao Exp Locker: mer $"); d193 14 a206 3 if (BufferIsValid(sdesc->rs_pbuf)) { BufferPut(sdesc->rs_pbuf, L_UNPIN); } a208 3 } if (BufferIsValid(sdesc->rs_nbuf)) { BufferPut(sdesc->rs_nbuf, L_UNPIN); d210 6 d842 16 @ 1.25 log @jukebox storage manager installation @ text @d69 1 a69 1 * $Header: /users/mao/postgres/src/access/heap/RCS/heapam.c,v 1.24 1991/06/03 21:37:52 kemnitz Exp $ d79 1 a79 1 RcsId("$Header: /users/mao/postgres/src/access/heap/RCS/heapam.c,v 1.24 1991/06/03 21:37:52 kemnitz Exp $"); d103 1 a109 1 #include "utils/lmgr.h" @ 1.24 log @speed up heap_tuple_satisfies somewhat @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.23 91/06/03 15:32:50 kemnitz Exp Locker: kemnitz $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.23 91/06/03 15:32:50 kemnitz Exp Locker: kemnitz $"); d275 1 a275 1 if (!(pages = relation->rd_nblocks)) d742 1 a742 1 relation->rd_nblocks = FileGetNumberOfBlocks(relation->rd_fd); @ 1.23 log @heap_satisfies now is heap_tuple_satisfies (which returns a tuple) @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.22 91/06/03 02:59:57 kemnitz Exp Locker: kemnitz $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.22 91/06/03 02:59:57 kemnitz Exp Locker: kemnitz $"); d395 1 a395 1 if ((rtup = heap_tuple_satisfies(lpp, relation, *b, d1105 1 a1105 1 tuple = heap_tuple_satisfies(lp, relation, buffer, d1250 1 a1250 1 if (!(tp = heap_tuple_satisfies(lp, relation, b, d1352 1 a1352 1 if (!(tp = heap_tuple_satisfies(lp, relation, buffer, NowTimeQual, 0, @ 1.22 log @cleaned up interface to heap_satisfies @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.21 91/05/27 00:26:02 kemnitz Exp Locker: kemnitz $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.21 91/05/27 00:26:02 kemnitz Exp Locker: kemnitz $"); d385 1 a385 1 * advance the scan until we find a qualificating tuple or d395 2 a396 2 if (heap_satisfies(lpp, relation, *b, timeQual, nkeys, key)) { rtup = (HeapTuple) PageGetItem(dp, lpp); d1062 1 a1062 1 * page level locking by the scanner anyway, it is commented out. a1095 6 if (!ItemIdIsUsed(lp)) { elog(WARN, "heap_fetch: %s relation: unused tid (%ld,%d)", &relation->rd_rel->relname, ItemPointerGetBlockNumber(tid), ItemPointerSimpleGetOffsetNumber(tid)); } d1097 2 a1098 4 if (ItemIdIsContinuation(lp) || ItemIdIsInternal(lp)) { elog(WARN, "heap_fetch: %s relation--bad item pointer", &relation->rd_rel->relname); } d1104 6 a1109 1 if (! heap_satisfies(lp, relation, buffer, timeQual, 0,(ScanKey)NULL)) { a1111 1 a1120 1 tuple = (HeapTuple) PageGetItem(dp, lp); d1250 2 a1251 1 if (! heap_satisfies(lp, relation, b, NowTimeQual, 0, (ScanKey) NULL)) { d1265 1 a1265 1 tp = (HeapTuple) PageGetItem(dp, lp); d1352 2 a1353 2 if (! heap_satisfies(lp, relation, buffer, NowTimeQual, 0, (ScanKey) NULL)) { d1366 1 a1366 1 tp = (HeapTuple) PageGetItem(dp, lp); d1376 1 @ 1.21 log @fixed bogus comment. @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.20 91/05/26 00:30:37 kemnitz Exp Locker: kemnitz $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.20 91/05/26 00:30:37 kemnitz Exp Locker: kemnitz $"); d395 1 a395 1 if (heap_satisifies(lpp, *b, timeQual, nkeys, key)) { d1112 1 a1112 1 if (! heap_satisifies(lp, buffer, timeQual, 0,(ScanKey)NULL)) { d1255 1 a1255 1 if (! heap_satisifies(lp, b, NowTimeQual, 0, (ScanKey) NULL)) { d1356 3 a1358 2 if (! heap_satisifies(lp, buffer, NowTimeQual, 0, (ScanKey) NULL)) { @ 1.20 log @doinsert has been cleaned up somewhat. @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.19 91/05/24 17:37:36 hong Exp Locker: kemnitz $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.19 91/05/24 17:37:36 hong Exp Locker: kemnitz $"); d1061 2 a1062 2 * indexscan tuple fetch. Not good, and since we are doing page * level locking with the buffer pool, it is commented out. @ 1.19 log @combined ReleaseBuffer() and ReadBuffer() calls in sequential scans to cut down the number of calls to semops @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.18 91/05/24 12:55:41 hong Exp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.18 91/05/24 12:55:41 hong Exp $"); d462 1 a462 1 doinsert(relation, tup) d593 11 a1057 2 /* Pray that this cannot cause a deadlock */ RelationSetLockForTupleRead(relation, tid); d1059 8 d1069 1 d1072 1 d1113 1 a1113 1 if (BufferPut(buffer, L_UNLOCK) < 0) a1125 2 if (BufferPut(buffer, L_PIN) < 0) elog(WARN, "heap_fetch: BufferPut failed"); d1172 1 a1648 1 @ 1.18 log @changes to reduce the number of calls to buffer manager dramatically from one call per to tuple to one call per page @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.17 91/05/01 02:49:15 cimarron Exp $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.17 91/05/01 02:49:15 cimarron Exp $"); a418 2 if (BufferIsValid(*b)) ReleaseBuffer(*b); d436 1 a436 1 *b = RelationGetBuffer(relation, page, L_SH); @ 1.17 log @round II of converting simple functions to macros + code cleaning in general @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.16 91/04/28 09:17:12 cimarron Exp Locker: cimarron $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.16 91/04/28 09:17:12 cimarron Exp Locker: cimarron $"); d292 3 a294 3 *b = RelationGetBuffer(relation, ItemPointerGetBlockNumber(tid), L_SH); d329 1 a329 1 *b = RelationGetBuffer(relation, page, L_SH); d361 1 a361 1 *b = RelationGetBuffer(relation, page, L_SH); d419 2 d432 2 d907 1 d910 1 d958 1 d960 1 a960 1 HEAPDEBUG_4; /* heap_getnext valid buffer UNPIN'd */ d963 1 @ 1.16 log @Converted IsValid code into macros and added an improved NodeIsType scheme @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.15 91/03/22 00:28:46 mao Exp Locker: cimarron $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.15 91/03/22 00:28:46 mao Exp Locker: cimarron $"); a1625 177 /* ---------------------------------------------------------------- * obsolete heap access method interface * ---------------------------------------------------------------- */ ObjectId RelationNameCreateHeapRelation(relationName, archiveMode, numberOfAttributes, tupleDescriptor) Name relationName; ArchiveMode archiveMode; AttributeNumber numberOfAttributes; TupleDescriptor tupleDescriptor; { return heap_create(relationName, archiveMode, numberOfAttributes, tupleDescriptor); } Relation RelationNameCreateTemporaryRelation(relationName, numberOfAttributes, tupleDescriptor) Name relationName; AttributeNumber numberOfAttributes; TupleDescriptor tupleDescriptor; { return (heap_creatr(relationName, numberOfAttributes, tupleDescriptor)); } void RelationNameDestroyHeapRelation(relationName) Name relationName; { heap_destroy(relationName); } Relation ObjectIdOpenHeapRelation(relationId) ObjectId relationId; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_ObjectIdOpenHeapRelation); IncrHeapAccessStat(global_ObjectIdOpenHeapRelation); return (heap_open(relationId)); } Relation RelationNameOpenHeapRelation(relationName) Name relationName; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_RelationNameOpenHeapRelation); IncrHeapAccessStat(global_RelationNameOpenHeapRelation); return (heap_openr(relationName)); } void RelationCloseHeapRelation(relation) Relation relation; { /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_RelationCloseHeapRelation); IncrHeapAccessStat(global_RelationCloseHeapRelation); heap_close(relation); } HeapTuple RelationGetHeapTupleByItemPointer(relation, qual, heapItem, bufferOutP) Relation relation; TimeQual qual; ItemPointer heapItem; Buffer *bufferOutP; { return (heap_fetch(relation, qual, heapItem, bufferOutP)); } RuleLock RelationInsertHeapTuple(relation, heapTuple, offsetOutP) Relation relation; HeapTuple heapTuple; double *offsetOutP; { return (heap_insert(relation, heapTuple, offsetOutP)); } RuleLock RelationDeleteHeapTuple(relation, heapItem) Relation relation; ItemPointer heapItem; { return (heap_delete(relation, heapItem)); } RuleLock RelationReplaceHeapTuple(relation, heapItem, tuple, offsetOutP) Relation relation; ItemPointer heapItem; HeapTuple tuple; double *offsetOutP; { return (heap_replace(relation, heapItem, tuple, offsetOutP)); } Datum HeapTupleGetAttributeValue(tuple, buffer, attributeNumber, tupleDescriptor, attributeIsNullOutP) HeapTuple tuple; Buffer buffer; AttributeNumber attributeNumber; TupleDescriptor tupleDescriptor; Boolean *attributeIsNullOutP; { return PointerGetDatum(heap_getattr(tuple, buffer, attributeNumber, tupleDescriptor, attributeIsNullOutP)); } HeapScanDesc RelationBeginHeapScan(relation, startScanAtEnd, qual, numberOfKeys, key) Relation relation; Boolean startScanAtEnd; TimeQual qual; uint16 numberOfKeys; ScanKey key; { return heap_beginscan(relation, startScanAtEnd, qual, numberOfKeys, key); } void HeapScanRestart(scan, restartScanAtEnd, key) HeapScanDesc scan; bool restartScanAtEnd; ScanKey key; { heap_rescan(scan, restartScanAtEnd, key); } void HeapScanEnd(scan) HeapScanDesc scan; { heap_endscan(scan); } void HeapScanMarkPosition(scan) HeapScanDesc scan; { heap_markpos(scan); } void HeapScanRestorePosition(scan) HeapScanDesc scan; { heap_restrpos(scan); } HeapTuple HeapScanGetNextTuple(scan, backwards, bufferOutP) HeapScanDesc scan; Boolean backwards; Buffer *bufferOutP; { return (heap_getnext(scan, backwards, bufferOutP)); } @ 1.15 log @if the tuple passed in to heap_insert already has an oid, then don't assign a new one (this is to support bootstrap, index creation, and persistent object storage). @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.14 91/03/20 20:54:36 cimarron Exp Locker: mao $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.14 91/03/20 20:54:36 cimarron Exp Locker: mao $"); d591 2 a592 3 /* ---------------- * HeapScanIsValid * ---------------- a593 7 bool HeapScanIsValid(scan) HeapScanDesc scan; { return (bool) PointerIsValid(scan); } @ 1.14 log @fixed some problems with buffer ref counts in the TupleTable stuff @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.13 91/03/06 11:21:20 hong Exp Locker: cimarron $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.13 91/03/06 11:21:20 hong Exp Locker: cimarron $"); d1162 11 a1172 2 /* if (special) then don't */ if (!IsBootstrapProcessingMode()) { @ 1.13 log @cache # of blocks of a relation in reldesc @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.12 91/02/25 18:14:29 hong Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.12 91/02/25 18:14:29 hong Exp Locker: hong $"); d889 6 a894 4 if (!PointerIsValid(b)) { localb = InvalidBuffer; b = &localb; } d897 1 a897 1 d899 4 d906 4 a909 3 BufferIsInvalid(sdesc->rs_pbuf)) { return (NULL); } d911 1 a911 1 if (BufferIsValid(sdesc->rs_nbuf)) { a912 1 } d939 6 a944 6 !BufferIsValid(sdesc->rs_cbuf)) { sdesc->rs_ptup = NULL; sdesc->rs_pbuf = InvalidBuffer; *b = sdesc->rs_cbuf; return (NULL); } d950 4 d977 1 a977 1 a993 1 *b = sdesc->rs_cbuf; d1002 6 a1007 1 *b = sdesc->rs_cbuf; @ 1.12 log @check for non-functional updates in heap_replace(), this also solves the ghost tuple problem. @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.11 91/02/07 13:16:56 hong Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.11 91/02/07 13:16:56 hong Exp Locker: hong $"); d275 1 a275 1 if (!(pages = RelationGetNumberOfBlocks(relation))) d737 1 @ 1.11 log @gotten rid of a compile warning @ text @d69 1 a69 1 * $Header: RCS/heapam.c,v 1.10 91/02/06 18:17:36 cimarron Exp Locker: hong $ d79 1 a79 1 RcsId("$Header: RCS/heapam.c,v 1.10 91/02/06 18:17:36 cimarron Exp Locker: hong $"); d1330 13 @ 1.10 log @preliminary checkin for access method and system cache changes @ text @d69 1 a69 1 * $Header$ d79 1 a79 1 RcsId("$Header: RCS/access.c,v 1.28 90/11/20 15:50:04 sp Exp Locker: cimarron $"); d1017 1 @ 1.9 log @`struct tuple', 'struct ituple', and the `T_*' hash defines (defined in htup.h) are now obsolete and replaced by `HeapTuple', `IndexTuple', and `*AttributeNumber' (defined in htup.h and itup.h) @ text @d1 70 a70 3 /* * heapam.c -- * POSTGRES heap access method code. a72 1 #include "tmp/c.h" d74 2 a75 1 RcsId("$Header: RCS/heapam.c,v 1.8 90/09/25 16:13:57 kemnitz Exp Locker: sp $"); d77 4 d84 2 d90 2 d93 19 a113 1 #include "utils/log.h" d115 4 a118 5 /* * XXX Note that longer function names are preferred when called * from C. Thus, the code should eventually be incorporated into * the functions, below. Better yet might be to place the functions * into several files. d120 1 d122 473 d597 1 a597 1 HeapScanDesc scan; d599 2 a600 1 return ((bool)PointerIsValid(scan)); d603 7 a609 7 ObjectId RelationNameCreateHeapRelation(relationName, archiveMode, numberOfAttributes, tupleDescriptor) Name relationName; ArchiveMode archiveMode; AttributeNumber numberOfAttributes; TupleDescriptor tupleDescriptor; d611 1 a611 2 return (amcreate(relationName, archiveMode, numberOfAttributes, tupleDescriptor)); d614 11 d626 2 a627 5 RelationNameCreateTemporaryRelation(relationName, numberOfAttributes, tupleDescriptor) Name relationName; AttributeNumber numberOfAttributes; TupleDescriptor tupleDescriptor; d629 9 a637 1 return (amcreatr(relationName, numberOfAttributes, tupleDescriptor)); d640 29 d670 2 a671 5 RelationNameCreateVersionRelation(originalRelationName, versionRelationName, time) Name originalRelationName; Name versionRelationName; long time; d673 8 a680 1 amcreatv(originalRelationName, versionRelationName, time); d683 72 d756 4 a759 2 RelationNameDestroyHeapRelation(relationName) Name relationName; d761 21 a781 1 amdestroy(relationName); d784 7 d792 2 a793 3 RelationNameMergeRelations(oldRelationName, newRelationName) Name oldRelationName; Name newRelationName; d795 21 a815 1 ammergev(oldRelationName, newRelationName); d818 796 d1615 5 a1619 2 ObjectIdOpenHeapRelation(relationId) /* XXX should be RelationIdOpenHeapRelation */ ObjectId relationId; d1621 14 d1641 2 a1642 2 return (RelationIdGetRelation(relationId)); d1647 1 a1647 1 Name relationName; d1655 2 a1656 2 return (amopenr(relationName)); d1661 1 a1661 1 Relation relation; d1669 2 a1670 2 amclose (relation); d1675 4 a1678 4 Relation relation; TimeQual qual; ItemPointer heapItem; Buffer *bufferOutP; d1680 1 a1680 1 return (amgetunique(relation, qual, heapItem, bufferOutP)); d1685 3 a1687 3 Relation relation; HeapTuple heapTuple; double *offsetOutP; d1689 1 a1689 1 return (aminsert(relation, heapTuple, offsetOutP)); d1694 2 a1695 2 Relation relation; ItemPointer heapItem; d1697 1 a1697 1 return (amdelete(relation, heapItem)); a1699 51 void RelationPhysicallyDeleteHeapTuple(relation, heapItem) Relation relation; ItemPointer heapItem; { /* XXX start here */ /* ItemId lp; HeapTuple tp; PageHeader dp; Buffer b; long time(); char *fmgr(); b = RelationGetBuffer(relation, ItemPointerGetBlockNumber(heapItem), L_UP); if (!BufferIsValid(b)) { */ /* XXX L_SH better ??? */ /* elog(WARN, "heapdelete: failed RelationGetBuffer"); } dp = (PageHeader)BufferSimpleGetPage(b); lp = PageGetItemId(dp, ItemPointerSimpleGetOffsetIndex(heapItem)); if (!ItemIdHasValidHeapTupleForQualification(lp, b, NowTimeRange, 0, (ScanKey)NULL)) { */ /* XXX call something else */ /* if (BufferPut(b, L_UN | L_UP) < 0) elog(WARN, "heapdelete: failed BufferPut"); elog(WARN, "heapdelete: (am)invalid heapItem"); } tp = (HeapTuple)PageGetItem(dp, lp); */ /* XXX order problems if not atomic assignment ??? */ /* if (BufferPut(b, L_EX) < 0) elog(WARN, "heapdelete: failed BufferPut(L_EX)"); TransactionIdStore(GetCurrentTransactionId(), (Pointer)tp->t_xmax); tp->t_cmax = GetCurrentCommandId(); */ /* tp->t_tmax = InvalidTime; */ /* ItemPointerSetInvalid(&tp->t_chain); if (BufferPut(b, L_UN | L_EX | L_WRITE) < 0) elog(WARN, "heapdelete: failed BufferPut(L_UN | L_WRITE)"); } return (amdelete(relation, heapItem)); */ } d1702 4 a1705 4 Relation relation; ItemPointer heapItem; HeapTuple tuple; double *offsetOutP; d1707 1 a1707 1 return (amreplace(relation, heapItem, tuple, offsetOutP)); d1713 5 a1717 5 HeapTuple tuple; Buffer buffer; AttributeNumber attributeNumber; TupleDescriptor tupleDescriptor; Boolean *attributeIsNullOutP; d1719 3 a1721 2 return (PointerGetDatum(amgetattr(tuple, buffer, attributeNumber, tupleDescriptor, attributeIsNullOutP))); d1726 5 a1730 5 Relation relation; Boolean startScanAtEnd; TimeQual qual; uint16 numberOfKeys; ScanKey key; d1732 1 a1732 1 return (ambeginscan(relation, startScanAtEnd, qual, numberOfKeys, key)); d1737 3 a1739 3 HeapScanDesc scan; bool restartScanAtEnd; ScanKey key; d1741 1 a1741 1 amrescan(scan, restartScanAtEnd, key); d1746 1 a1746 1 HeapScanDesc scan; d1748 1 a1748 1 amendscan(scan); d1753 1 a1753 1 HeapScanDesc scan; d1755 1 a1755 1 ammarkpos(scan); d1760 1 a1760 1 HeapScanDesc scan; d1762 1 a1762 1 amrestrpos(scan); d1767 3 a1769 3 HeapScanDesc scan; Boolean backwards; Buffer *bufferOutP; d1771 1 a1771 1 return (amgetnext(scan, backwards, bufferOutP)); a1772 7 /* * XXX probably do not need a free tuple routine for heaps. * Huh? Free tuple is not necessary for tuples returned by scans, but * is necessary for tuples which are returned by RelationGetTupleByItemPointer. * -hirohama */ @ 1.8 log @Updating from revision 1.7 to revision 1.8 @ text @d8 1 a8 1 RcsId("$Header: RCS/heapam.c,v 1.8 90/08/13 16:38:55 cimarron Exp $"); d160 1 a160 1 struct tuple *tp; d184 1 a184 1 tp = (struct tuple *)PageGetItem(dp, lp); @ 1.7 log @added statistics gathering stuff @ text @d6 1 a6 1 #include "c.h" d8 1 a8 1 RcsId("$Header: RCS/heapam.c,v 1.6 89/09/28 17:43:10 hirohama Exp $"); d10 7 a16 9 #include "att.h" #include "attnum.h" #include "htup.h" #include "log.h" #include "rel.h" #include "relcache.h" #include "relscan.h" #include "skey.h" #include "tqual.h" d18 3 a20 1 #include "heapam.h" @ 1.6 log @TimeRange -> TimeQual @ text @d8 1 a8 1 RcsId("$Header: RCS/heapam.c,v 1.5 89/09/05 16:56:46 mao C_Demo_1 Locker: hirohama $"); d87 8 a94 1 return (RelationIdGetRelation(relationId)); d101 8 a108 1 return (amopenr(relationName)); d115 8 a122 1 amclose (relation); @ 1.5 log @Working version of C-only demo @ text @d8 2 d18 1 a21 2 RcsId("$Header: RCS/heapam.c,v 1.4 89/08/10 17:26:42 hirohama Exp $"); d105 1 a105 1 RelationGetHeapTupleByItemPointer(relation, range, heapItem, bufferOutP) d107 1 a107 1 TimeRange range; d111 1 a111 1 return (amgetunique(relation, range, heapItem, bufferOutP)); d154 1 a154 1 if (!ItemIdHasValidHeapTupleForQualification(lp, b, DefaultTimeRange, d206 1 a206 1 RelationBeginHeapScan(relation, startScanAtEnd, timer, numberOfKeys, key) d209 1 a209 1 TimeRange timer; d213 1 a213 2 return (ambeginscan(relation, startScanAtEnd, timer, numberOfKeys, key)); d257 3 @ 1.4 log @...CreateHeapRelation now returns relation id @ text @d19 1 a19 1 RcsId("$Header: heapam.c,v 1.3 89/08/09 18:12:44 hirohama Locked $"); @ 1.3 log @"retrieve(x=1)" @ text @d19 1 a19 1 RcsId("$Header: /usr6/postgres/cimarron/postgres3/src/access/heap/RCS/heapam.c,v 1.2 89/02/02 16:28:58 dillon Stab $"); d35 1 a35 1 void d43 2 a44 2 amcreate(relationName, archiveMode, numberOfAttributes, tupleDescriptor); @ 1.2 log @Txfer from old tree @ text @d19 1 a19 1 RcsId("$Header: heapam.c,v 1.12 88/07/27 18:20:30 dillon Locked $"); d30 1 a30 1 HeapScan scan; d204 1 a204 1 HeapScan d218 1 a218 1 HeapScan scan; d227 1 a227 1 HeapScan scan; d234 1 a234 1 HeapScan scan; d241 1 a241 1 HeapScan scan; d248 1 a248 1 HeapScan scan; @ 1.1 log @Initial revision @ text @a0 1 a1 26 * * POSTGRES Data Base Management System * * Copyright (c) 1988 Regents of the University of California * * Permission to use, copy, modify, and distribute this software and its * documentation for educational, research, and non-profit purposes and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of the University of California not be used in advertising * or publicity pertaining to distribution of the software without * specific, written prior permission. Permission to incorporate this * software into commercial products can be obtained from the Campus * Software Office, 295 Evans Hall, University of California, Berkeley, * Ca., 94720 provided only that the the requestor give the University * of California a free licence to any derived software for educational * and research purposes. The University of California makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ /* d19 1 a19 1 RcsId("$Header: heapam.c,v 1.1 88/11/11 16:35:32 postgres Exp $"); @