Fix for bug #866. 7.3 contains new logic for avoiding redundant calls to

the index AM when we know we are fetching a unique row.  However, this
logic did not consider the possibility that it would be asked to fetch
backwards.  Also fix mark/restore to work correctly in this scenario.
This commit is contained in:
Tom Lane 2003-01-08 19:41:40 +00:00
parent 9270f1cdaa
commit cbca6c4896
3 changed files with 58 additions and 11 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.36 2002/09/04 20:31:09 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.37 2003/01/08 19:41:40 tgl Exp $
*
* NOTES
* many of the old access method routines have been turned into
@ -107,6 +107,9 @@ RelationGetIndexScan(Relation indexRelation,
/* mark cached function lookup data invalid; it will be set later */
scan->fn_getnext.fn_oid = InvalidOid;
scan->unique_tuple_pos = 0;
scan->unique_tuple_mark = 0;
pgstat_initstats(&scan->xs_pgstat_info, indexRelation);
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.62 2002/09/04 20:31:09 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.63 2003/01/08 19:41:40 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
@ -308,6 +308,8 @@ index_rescan(IndexScanDesc scan, ScanKey key)
scan->kill_prior_tuple = false; /* for safety */
scan->keys_are_unique = false; /* may be set by amrescan */
scan->got_tuple = false;
scan->unique_tuple_pos = 0;
scan->unique_tuple_mark = 0;
OidFunctionCall2(procedure,
PointerGetDatum(scan),
@ -360,6 +362,8 @@ index_markpos(IndexScanDesc scan)
SCAN_CHECKS;
GET_SCAN_PROCEDURE(markpos, ammarkpos);
scan->unique_tuple_mark = scan->unique_tuple_pos;
OidFunctionCall1(procedure, PointerGetDatum(scan));
}
@ -376,7 +380,13 @@ index_restrpos(IndexScanDesc scan)
GET_SCAN_PROCEDURE(restrpos, amrestrpos);
scan->kill_prior_tuple = false; /* for safety */
scan->got_tuple = false;
/*
* We do not reset got_tuple; so if the scan is actually being
* short-circuited by index_getnext, the effective position restoration
* is done by restoring unique_tuple_pos.
*/
scan->unique_tuple_pos = scan->unique_tuple_mark;
OidFunctionCall1(procedure, PointerGetDatum(scan));
}
@ -398,6 +408,32 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
SCAN_CHECKS;
/*
* Can skip entering the index AM if we already got a tuple and it
* must be unique. Instead, we need a "short circuit" path that
* just keeps track of logical scan position (before/on/after tuple).
*
* Note that we hold the pin on the single tuple's buffer throughout
* the scan once we are in this state.
*/
if (scan->keys_are_unique && scan->got_tuple)
{
if (ScanDirectionIsForward(direction))
{
if (scan->unique_tuple_pos <= 0)
scan->unique_tuple_pos++;
}
else if (ScanDirectionIsBackward(direction))
{
if (scan->unique_tuple_pos >= 0)
scan->unique_tuple_pos--;
}
if (scan->unique_tuple_pos == 0)
return heapTuple;
else
return NULL;
}
/* Release any previously held pin */
if (BufferIsValid(scan->xs_cbuf))
{
@ -408,13 +444,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
/* just make sure this is false... */
scan->kill_prior_tuple = false;
/*
* Can skip entering the index AM if we already got a tuple and it
* must be unique.
*/
if (scan->keys_are_unique && scan->got_tuple)
return NULL;
for (;;)
{
bool found;
@ -475,6 +504,12 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
/* Success exit */
scan->got_tuple = true;
/*
* If we just fetched a known-unique tuple, then subsequent calls will
* go through the short-circuit code above. unique_tuple_pos has been
* initialized to 0, which is the correct state ("on row").
*/
pgstat_count_index_getnext(&scan->xs_pgstat_info);
return heapTuple;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: relscan.h,v 1.29 2002/09/04 20:31:37 momjian Exp $
* $Id: relscan.h,v 1.30 2003/01/08 19:41:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -70,6 +70,15 @@ typedef struct IndexScanDescData
FmgrInfo fn_getnext; /* cached lookup info for AM's getnext fn */
/*
* If keys_are_unique and got_tuple are both true, we stop calling the
* index AM; it is then necessary for index_getnext to keep track of
* the logical scan position for itself. It does that using
* unique_tuple_pos: -1 = before row, 0 = on row, +1 = after row.
*/
int unique_tuple_pos; /* logical position */
int unique_tuple_mark; /* logical marked position */
PgStat_Info xs_pgstat_info; /* statistics collector hook */
} IndexScanDescData;