*             tuple as indicated by "dir"; return the next tuple in scan->rs_ctup,
  *             or set scan->rs_ctup.t_data = NULL if no more tuples.
  *
- * dir == NoMovementScanDirection means "re-fetch the tuple indicated
- * by scan->rs_ctup".
- *
  * Note: the reason nkeys/key are passed separately, even though they are
  * kept in the scan descriptor, is that the caller may not want us to check
  * the scankeys.
 
                linesleft = lines - lineoff + 1;
        }
-       else if (backward)
+       else
        {
                /* backward parallel scan not supported */
                Assert(scan->rs_base.rs_parallel == NULL);
 
                linesleft = lineoff;
        }
-       else
-       {
-               /*
-                * ``no movement'' scan direction: refetch prior tuple
-                */
-               if (!scan->rs_inited)
-               {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
-               }
-
-               block = ItemPointerGetBlockNumber(&(tuple->t_self));
-               if (block != scan->rs_cblock)
-                       heapgetpage((TableScanDesc) scan, block);
-
-               /* Since the tuple was previously fetched, needn't lock page here */
-               page = BufferGetPage(scan->rs_cbuf);
-               TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-               lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
-               lpp = PageGetItemId(page, lineoff);
-               Assert(ItemIdIsNormal(lpp));
-
-               tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
-               tuple->t_len = ItemIdGetLength(lpp);
-
-               return;
-       }
 
        /*
         * advance the scan until we find a qualifying tuple or run out of stuff
 
                linesleft = lines - lineindex;
        }
-       else if (backward)
+       else
        {
                /* backward parallel scan not supported */
                Assert(scan->rs_base.rs_parallel == NULL);
 
                linesleft = lineindex + 1;
        }
-       else
-       {
-               /*
-                * ``no movement'' scan direction: refetch prior tuple
-                */
-               if (!scan->rs_inited)
-               {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
-               }
-
-               block = ItemPointerGetBlockNumber(&(tuple->t_self));
-               if (block != scan->rs_cblock)
-                       heapgetpage((TableScanDesc) scan, block);
-
-               /* Since the tuple was previously fetched, needn't lock page here */
-               page = BufferGetPage(scan->rs_cbuf);
-               TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-               lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
-               lpp = PageGetItemId(page, lineoff);
-               Assert(ItemIdIsNormal(lpp));
-
-               tuple->t_data = (HeapTupleHeader) PageGetItem(page, 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]);
-
-               return;
-       }
 
        /*
         * advance the scan until we find a qualifying tuple or run out of stuff
 
                        case BackwardScanDirection:
                                scandir = "Backward";
                                break;
-                       case NoMovementScanDirection:
-                               scandir = "NoMovement";
-                               break;
                        case ForwardScanDirection:
                                scandir = "Forward";
                                break;
 
         * extract necessary information from index scan node
         */
        estate = node->ss.ps.state;
-       direction = estate->es_direction;
-       /* flip direction if this is an overall backward scan */
-       if (ScanDirectionIsBackward(((IndexOnlyScan *) node->ss.ps.plan)->indexorderdir))
-       {
-               if (ScanDirectionIsForward(direction))
-                       direction = BackwardScanDirection;
-               else if (ScanDirectionIsBackward(direction))
-                       direction = ForwardScanDirection;
-       }
+
+       /*
+        * Determine which direction to scan the index in based on the plan's scan
+        * direction and the current direction of execution.
+        */
+       direction = ScanDirectionCombine(estate->es_direction,
+                                                                        ((IndexOnlyScan *) node->ss.ps.plan)->indexorderdir);
        scandesc = node->ioss_ScanDesc;
        econtext = node->ss.ps.ps_ExprContext;
        slot = node->ss.ss_ScanTupleSlot;
 
         * extract necessary information from index scan node
         */
        estate = node->ss.ps.state;
-       direction = estate->es_direction;
-       /* flip direction if this is an overall backward scan */
-       if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
-       {
-               if (ScanDirectionIsForward(direction))
-                       direction = BackwardScanDirection;
-               else if (ScanDirectionIsBackward(direction))
-                       direction = ForwardScanDirection;
-       }
+
+       /*
+        * Determine which direction to scan the index in based on the plan's scan
+        * direction and the current direction of execution.
+        */
+       direction = ScanDirectionCombine(estate->es_direction,
+                                                                        ((IndexScan *) node->ss.ps.plan)->indexorderdir);
        scandesc = node->iss_ScanDesc;
        econtext = node->ss.ps.ps_ExprContext;
        slot = node->ss.ss_ScanTupleSlot;
 
                                                                  orderbyclauses,
                                                                  orderbyclausecols,
                                                                  useful_pathkeys,
-                                                                 index_is_ordered ?
-                                                                 ForwardScanDirection :
-                                                                 NoMovementScanDirection,
+                                                                 ForwardScanDirection,
                                                                  index_only_scan,
                                                                  outer_relids,
                                                                  loop_count,
                                                                          orderbyclauses,
                                                                          orderbyclausecols,
                                                                          useful_pathkeys,
-                                                                         index_is_ordered ?
-                                                                         ForwardScanDirection :
-                                                                         NoMovementScanDirection,
+                                                                         ForwardScanDirection,
                                                                          index_only_scan,
                                                                          outer_relids,
                                                                          loop_count,
 
        /* it should be a base rel... */
        Assert(baserelid > 0);
        Assert(best_path->path.parent->rtekind == RTE_RELATION);
+       /* check the scan direction is valid */
+       Assert(best_path->indexscandir == ForwardScanDirection ||
+                  best_path->indexscandir == BackwardScanDirection);
 
        /*
         * Extract the index qual expressions (stripped of RestrictInfos) from the
 
  * 'indexorderbycols' is an integer list of index column numbers (zero based)
  *                     the ordering operators can be used with.
  * 'pathkeys' describes the ordering of the path.
- * 'indexscandir' is ForwardScanDirection or BackwardScanDirection
- *                     for an ordered index, or NoMovementScanDirection for
- *                     an unordered index.
+ * 'indexscandir' is either ForwardScanDirection or BackwardScanDirection.
  * 'indexonly' is true if an index-only scan is wanted.
  * 'required_outer' is the set of outer relids for a parameterized path.
  * 'loop_count' is the number of repetitions of the indexscan to factor into
 
 
 
 /*
- * ScanDirection was an int8 for no apparent reason. I kept the original
- * values because I'm not sure if I'll break anything otherwise.  -ay 2/95
+ * Defines the direction for scanning a table or an index.  Scans are never
+ * invoked using NoMovementScanDirectionScans.  For convenience, we use the
+ * values -1 and 1 for backward and forward scans.  This allows us to perform
+ * a few mathematical tricks such as what is done in ScanDirectionCombine.
  */
 typedef enum ScanDirection
 {
        ForwardScanDirection = 1
 } ScanDirection;
 
+/*
+ * Determine the net effect of two direction specifications.
+ * This relies on having ForwardScanDirection = +1, BackwardScanDirection = -1,
+ * and will probably not do what you want if applied to any other values.
+ */
+#define ScanDirectionCombine(a, b)  ((a) * (b))
+
 /*
  * ScanDirectionIsValid
  *             True iff scan direction is valid.
 
 {
        slot->tts_tableOid = RelationGetRelid(sscan->rs_rd);
 
+       /* We don't expect actual scans using NoMovementScanDirection */
+       Assert(direction == ForwardScanDirection ||
+                  direction == BackwardScanDirection);
+
        /*
         * We don't expect direct calls to table_scan_getnextslot with valid
         * CheckXidAlive for catalog or regular tables.  See detailed comments in
        /* Ensure table_beginscan_tidrange() was used. */
        Assert((sscan->rs_flags & SO_TYPE_TIDRANGESCAN) != 0);
 
+       /* We don't expect actual scans using NoMovementScanDirection */
+       Assert(direction == ForwardScanDirection ||
+                  direction == BackwardScanDirection);
+
        return sscan->rs_rd->rd_tableam->scan_getnextslot_tidrange(sscan,
                                                                                                                           direction,
                                                                                                                           slot);
 
  * on which index column each ORDER BY can be used with.)
  *
  * 'indexscandir' is one of:
- *             ForwardScanDirection: forward scan of an ordered index
+ *             ForwardScanDirection: forward scan of an index
  *             BackwardScanDirection: backward scan of an ordered index
- *             NoMovementScanDirection: scan of an unordered index, or don't care
- * (The executor doesn't care whether it gets ForwardScanDirection or
- * NoMovementScanDirection for an indexscan, but the planner wants to
- * distinguish ordered from unordered indexes for building pathkeys.)
+ * Unordered indexes will always have an indexscandir of ForwardScanDirection.
  *
  * 'indextotalcost' and 'indexselectivity' are saved in the IndexPath so that
  * we need not recompute them when considering using the same index in a