diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 0b750e72a7d53408b95a4cf5728f6ac720b65892..eeacff56c9d82a0d09eb7d953cea0d64f378a8c8 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.204 2005/11/26 03:03:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.205 2005/11/26 05:03:06 tgl Exp $ * * * INTERFACE ROUTINES @@ -194,9 +194,7 @@ heapgettup(HeapScanDesc scan, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); - ItemPointer tid = &(tuple->t_self); Snapshot snapshot = scan->rs_snapshot; - BlockNumber pages = scan->rs_nblocks; BlockNumber page; Page dp; int lines; @@ -204,52 +202,45 @@ heapgettup(HeapScanDesc scan, int linesleft; ItemId lpp; - if (!scan->rs_inited) - { - /* - * return null immediately if relation is empty - */ - if (pages == 0) - { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; - } - } - else - { - /* resuming scan from tuple indicated by scan->rs_ctup.t_self */ - Assert(ItemPointerIsValid(tid)); - } - /* * calculate next starting lineoff, given scan direction */ - if (dir == 0) + if (dir > 0) { /* - * ``no movement'' scan direction: refetch prior tuple + * forward scan direction */ if (!scan->rs_inited) { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; + /* + * return null immediately if relation is empty + */ + if (scan->rs_nblocks == 0) + { + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; + } + page = 0; /* first page */ + heapgetpage(scan, page); + lineoff = FirstOffsetNumber; /* first offnum */ + scan->rs_inited = true; + } + else + { + /* continue from previously returned page/tuple */ + page = scan->rs_cblock; /* current page */ + lineoff = /* next offnum */ + OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self))); } - page = ItemPointerGetBlockNumber(tid); - if (page != scan->rs_cblock) - heapgetpage(scan, page); + LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - /* Since the tuple was previously fetched, needn't lock page here */ dp = (Page) BufferGetPage(scan->rs_cbuf); - lineoff = ItemPointerGetOffsetNumber(tid); - lpp = PageGetItemId(dp, lineoff); - - tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); - tuple->t_len = ItemIdGetLength(lpp); + lines = PageGetMaxOffsetNumber(dp); + /* page and lineoff now reference the physically next tid */ - return; + linesleft = lines - lineoff + 1; } else if (dir < 0) { @@ -257,12 +248,24 @@ heapgettup(HeapScanDesc scan, * reverse scan direction */ if (!scan->rs_inited) - page = pages - 1; /* final page */ - else - page = ItemPointerGetBlockNumber(tid); /* current page */ - - if (page != scan->rs_cblock) + { + /* + * return null immediately if relation is empty + */ + if (scan->rs_nblocks == 0) + { + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; + } + page = scan->rs_nblocks - 1; /* final page */ heapgetpage(scan, page); + } + else + { + /* continue from previously returned page/tuple */ + page = scan->rs_cblock; /* current page */ + } LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); @@ -271,53 +274,44 @@ heapgettup(HeapScanDesc scan, if (!scan->rs_inited) { - lineoff = lines; /* final offnum */ + lineoff = lines; /* final offnum */ scan->rs_inited = true; } else { - lineoff = /* previous offnum */ - OffsetNumberPrev(ItemPointerGetOffsetNumber(tid)); + lineoff = /* previous offnum */ + OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self))); } /* page and lineoff now reference the physically previous tid */ + + linesleft = lineoff; } else { /* - * forward scan direction + * ``no movement'' scan direction: refetch prior tuple */ if (!scan->rs_inited) { - page = 0; /* first page */ - lineoff = FirstOffsetNumber; /* first offnum */ - scan->rs_inited = true; - } - else - { - page = ItemPointerGetBlockNumber(tid); /* current page */ - lineoff = /* next offnum */ - OffsetNumberNext(ItemPointerGetOffsetNumber(tid)); + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; } + page = ItemPointerGetBlockNumber(&(tuple->t_self)); if (page != scan->rs_cblock) heapgetpage(scan, page); - LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - + /* Since the tuple was previously fetched, needn't lock page here */ dp = (Page) BufferGetPage(scan->rs_cbuf); - lines = PageGetMaxOffsetNumber(dp); - /* page and lineoff now reference the physically next tid */ - } + lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self)); + lpp = PageGetItemId(dp, lineoff); - /* 'dir' is now non-zero */ + tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); + tuple->t_len = ItemIdGetLength(lpp); - /* - * calculate number of remaining items to check on this page - */ - if (dir < 0) - linesleft = lineoff; - else - linesleft = lines - lineoff + 1; + return; + } /* * advance the scan until we find a qualifying tuple or run out of stuff @@ -379,7 +373,7 @@ heapgettup(HeapScanDesc scan, /* * return NULL if we've exhausted all the pages */ - if ((dir < 0) ? (page == 0) : (page + 1 >= pages)) + if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); @@ -432,8 +426,6 @@ heapgettup_pagemode(HeapScanDesc scan, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); - ItemPointer tid = &(tuple->t_self); - BlockNumber pages = scan->rs_nblocks; BlockNumber page; Page dp; int lines; @@ -442,56 +434,42 @@ heapgettup_pagemode(HeapScanDesc scan, int linesleft; ItemId lpp; - if (!scan->rs_inited) - { - /* - * return null immediately if relation is empty - */ - if (pages == 0) - { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; - } - } - else - { - /* resuming scan from tuple indicated by scan->rs_ctup.t_self */ - Assert(ItemPointerIsValid(tid)); - } - /* * calculate next starting lineindex, given scan direction */ - if (dir == 0) + if (dir > 0) { /* - * ``no movement'' scan direction: refetch prior tuple + * forward scan direction */ if (!scan->rs_inited) { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; - } - - page = ItemPointerGetBlockNumber(tid); - if (page != scan->rs_cblock) + /* + * return null immediately if relation is empty + */ + if (scan->rs_nblocks == 0) + { + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; + } + page = 0; /* first page */ heapgetpage(scan, page); + lineindex = 0; + scan->rs_inited = true; + } + else + { + /* continue from previously returned page/tuple */ + page = scan->rs_cblock; /* current page */ + lineindex = scan->rs_cindex + 1; + } - /* Since the tuple was previously fetched, needn't lock page here */ dp = (Page) BufferGetPage(scan->rs_cbuf); - lineoff = ItemPointerGetOffsetNumber(tid); - lpp = PageGetItemId(dp, lineoff); - - tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); - tuple->t_len = ItemIdGetLength(lpp); - - /* check that rs_cindex is in sync */ - Assert(scan->rs_cindex < scan->rs_ntuples); - Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]); + lines = scan->rs_ntuples; + /* page and lineindex now reference the next visible tid */ - return; + linesleft = lines - lineindex; } else if (dir < 0) { @@ -499,12 +477,24 @@ heapgettup_pagemode(HeapScanDesc scan, * reverse scan direction */ if (!scan->rs_inited) - page = pages - 1; /* final page */ - else - page = ItemPointerGetBlockNumber(tid); /* current page */ - - if (page != scan->rs_cblock) + { + /* + * return null immediately if relation is empty + */ + if (scan->rs_nblocks == 0) + { + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; + } + page = scan->rs_nblocks - 1; /* final page */ heapgetpage(scan, page); + } + else + { + /* continue from previously returned page/tuple */ + page = scan->rs_cblock; /* current page */ + } dp = (Page) BufferGetPage(scan->rs_cbuf); lines = scan->rs_ntuples; @@ -519,41 +509,39 @@ heapgettup_pagemode(HeapScanDesc scan, lineindex = scan->rs_cindex - 1; } /* page and lineindex now reference the previous visible tid */ + + linesleft = lineindex + 1; } else { /* - * forward scan direction + * ``no movement'' scan direction: refetch prior tuple */ if (!scan->rs_inited) { - page = 0; /* first page */ - lineindex = 0; - scan->rs_inited = true; - } - else - { - page = ItemPointerGetBlockNumber(tid); /* current page */ - lineindex = scan->rs_cindex + 1; + Assert(!BufferIsValid(scan->rs_cbuf)); + tuple->t_data = NULL; + return; } + page = ItemPointerGetBlockNumber(&(tuple->t_self)); if (page != scan->rs_cblock) heapgetpage(scan, page); + /* Since the tuple was previously fetched, needn't lock page here */ dp = (Page) BufferGetPage(scan->rs_cbuf); - lines = scan->rs_ntuples; - /* page and lineindex now reference the next visible tid */ - } + lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self)); + lpp = PageGetItemId(dp, lineoff); - /* 'dir' is now non-zero */ + tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); + tuple->t_len = ItemIdGetLength(lpp); - /* - * calculate number of remaining items to check on this page - */ - if (dir < 0) - linesleft = lineindex + 1; - else - linesleft = lines - lineindex; + /* check that rs_cindex is in sync */ + Assert(scan->rs_cindex < scan->rs_ntuples); + Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]); + + return; + } /* * advance the scan until we find a qualifying tuple or run out of stuff @@ -614,7 +602,7 @@ heapgettup_pagemode(HeapScanDesc scan, /* * return NULL if we've exhausted all the pages */ - if ((dir < 0) ? (page == 0) : (page + 1 >= pages)) + if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); @@ -2743,6 +2731,7 @@ heap_restrpos(HeapScanDesc scan) ReleaseBuffer(scan->rs_cbuf); scan->rs_cbuf = InvalidBuffer; scan->rs_cblock = InvalidBlockNumber; + scan->rs_inited = false; } else {