88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.62 2002/09/04 20:31:09 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.63 2003/01/08 19:41:40 tgl Exp $
1212 *
1313 * INTERFACE ROUTINES
1414 *index_open- open an index relation by relation OID
@@ -308,6 +308,8 @@ index_rescan(IndexScanDesc scan, ScanKey key)
308308scan -> kill_prior_tuple = false;/* for safety */
309309scan -> keys_are_unique = false;/* may be set by amrescan */
310310scan -> got_tuple = false;
311+ scan -> unique_tuple_pos = 0 ;
312+ scan -> unique_tuple_mark = 0 ;
311313
312314OidFunctionCall2 (procedure ,
313315PointerGetDatum (scan ),
@@ -360,6 +362,8 @@ index_markpos(IndexScanDesc scan)
360362SCAN_CHECKS ;
361363GET_SCAN_PROCEDURE (markpos ,ammarkpos );
362364
365+ scan -> unique_tuple_mark = scan -> unique_tuple_pos ;
366+
363367OidFunctionCall1 (procedure ,PointerGetDatum (scan ));
364368}
365369
@@ -376,7 +380,13 @@ index_restrpos(IndexScanDesc scan)
376380GET_SCAN_PROCEDURE (restrpos ,amrestrpos );
377381
378382scan -> kill_prior_tuple = false;/* for safety */
379- scan -> got_tuple = false;
383+
384+ /*
385+ * We do not reset got_tuple; so if the scan is actually being
386+ * short-circuited by index_getnext, the effective position restoration
387+ * is done by restoring unique_tuple_pos.
388+ */
389+ scan -> unique_tuple_pos = scan -> unique_tuple_mark ;
380390
381391OidFunctionCall1 (procedure ,PointerGetDatum (scan ));
382392}
@@ -398,6 +408,32 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
398408
399409SCAN_CHECKS ;
400410
411+ /*
412+ * Can skip entering the index AM if we already got a tuple and it
413+ * must be unique. Instead, we need a "short circuit" path that
414+ * just keeps track of logical scan position (before/on/after tuple).
415+ *
416+ * Note that we hold the pin on the single tuple's buffer throughout
417+ * the scan once we are in this state.
418+ */
419+ if (scan -> keys_are_unique && scan -> got_tuple )
420+ {
421+ if (ScanDirectionIsForward (direction ))
422+ {
423+ if (scan -> unique_tuple_pos <=0 )
424+ scan -> unique_tuple_pos ++ ;
425+ }
426+ else if (ScanDirectionIsBackward (direction ))
427+ {
428+ if (scan -> unique_tuple_pos >=0 )
429+ scan -> unique_tuple_pos -- ;
430+ }
431+ if (scan -> unique_tuple_pos == 0 )
432+ return heapTuple ;
433+ else
434+ return NULL ;
435+ }
436+
401437/* Release any previously held pin */
402438if (BufferIsValid (scan -> xs_cbuf ))
403439{
@@ -408,13 +444,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
408444/* just make sure this is false... */
409445scan -> kill_prior_tuple = false;
410446
411- /*
412- * Can skip entering the index AM if we already got a tuple and it
413- * must be unique.
414- */
415- if (scan -> keys_are_unique && scan -> got_tuple )
416- return NULL ;
417-
418447for (;;)
419448{
420449bool found ;
@@ -475,6 +504,12 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
475504/* Success exit */
476505scan -> got_tuple = true;
477506
507+ /*
508+ * If we just fetched a known-unique tuple, then subsequent calls will
509+ * go through the short-circuit code above. unique_tuple_pos has been
510+ * initialized to 0, which is the correct state ("on row").
511+ */
512+
478513pgstat_count_index_getnext (& scan -> xs_pgstat_info );
479514
480515return heapTuple ;