Re: Bug #866: Cursor scrolling broken in 7.3.1 (works in 7.2.1) - Mailing list pgsql-bugs

From Tom Lane
Subject Re: Bug #866: Cursor scrolling broken in 7.3.1 (works in 7.2.1)
Date
Msg-id 11917.1042055050@sss.pgh.pa.us
Whole thread Raw
In response to Bug #866: Cursor scrolling broken in 7.3.1 (works in 7.2.1)  (pgsql-bugs@postgresql.org)
List pgsql-bugs
If you need it right away, here is the patch for the unique-index
problem.  This will be in 7.3.2.

            regards, tom lane


*** src/backend/access/index/genam.c.orig    Wed Sep  4 17:30:07 2002
--- src/backend/access/index/genam.c    Wed Jan  8 14:25:44 2003
***************
*** 107,112 ****
--- 107,115 ----
      /* 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);

      /*
*** src/backend/access/index/indexam.c.orig    Wed Sep  4 17:30:08 2002
--- src/backend/access/index/indexam.c    Wed Jan  8 14:34:21 2003
***************
*** 308,313 ****
--- 308,315 ----
      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,365 ****
--- 362,369 ----
      SCAN_CHECKS;
      GET_SCAN_PROCEDURE(markpos, ammarkpos);

+     scan->unique_tuple_mark = scan->unique_tuple_pos;
+
      OidFunctionCall1(procedure, PointerGetDatum(scan));
  }

***************
*** 376,382 ****
      GET_SCAN_PROCEDURE(restrpos, amrestrpos);

      scan->kill_prior_tuple = false;        /* for safety */
!     scan->got_tuple = false;

      OidFunctionCall1(procedure, PointerGetDatum(scan));
  }
--- 380,392 ----
      GET_SCAN_PROCEDURE(restrpos, amrestrpos);

      scan->kill_prior_tuple = false;        /* for safety */
!
!     /*
!      * 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,403 ****
--- 408,439 ----

      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,420 ****
      /* 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;
--- 444,449 ----
***************
*** 474,479 ****
--- 503,514 ----

      /* 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);

*** src/include/access/relscan.h.orig    Wed Sep  4 17:31:07 2002
--- src/include/access/relscan.h    Wed Jan  8 14:11:13 2003
***************
*** 70,75 ****
--- 70,84 ----

      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;

pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: Bug #866: Cursor scrolling broken in 7.3.1 (works in 7.2.1)
Next
From: pgsql-bugs@postgresql.org
Date:
Subject: Bug #867: CLUSTER does not rebuild referential integrity triggers