Index: src/backend/access/gist/gistget.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/gist/gistget.c,v retrieving revision 1.55 diff -c -r1.55 gistget.c *** src/backend/access/gist/gistget.c 14 Jan 2006 22:03:35 -0000 1.55 --- src/backend/access/gist/gistget.c 20 Feb 2006 00:41:03 -0000 *************** *** 96,102 **** gistgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); GISTScanOpaque so; ItemPointerData tid; bool res; --- 96,102 ---- gistgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_CHAR(1); GISTScanOpaque so; ItemPointerData tid; bool res; Index: src/backend/access/hash/hash.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/hash/hash.c,v retrieving revision 1.86 diff -c -r1.86 hash.c *** src/backend/access/hash/hash.c 11 Feb 2006 23:31:33 -0000 1.86 --- src/backend/access/hash/hash.c 20 Feb 2006 00:41:04 -0000 *************** *** 164,170 **** hashgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; Page page; --- 164,170 ---- hashgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_CHAR(1); HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; Page page; Index: src/backend/access/heap/heapam.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/heap/heapam.c,v retrieving revision 1.206 diff -c -r1.206 heapam.c *** src/backend/access/heap/heapam.c 11 Jan 2006 08:43:11 -0000 1.206 --- src/backend/access/heap/heapam.c 20 Feb 2006 00:41:05 -0000 *************** *** 172,178 **** * 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 == 0 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 --- 172,179 ---- * 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 *************** *** 189,200 **** */ static void heapgettup(HeapScanDesc scan, ! int dir, int nkeys, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); Snapshot snapshot = scan->rs_snapshot; BlockNumber page; Page dp; int lines; --- 190,202 ---- */ static void heapgettup(HeapScanDesc scan, ! ScanDirection dir, int nkeys, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); Snapshot snapshot = scan->rs_snapshot; + bool backward = ScanDirectionIsBackward(dir); BlockNumber page; Page dp; int lines; *************** *** 205,211 **** /* * calculate next starting lineoff, given scan direction */ ! if (dir > 0) { /* * forward scan direction --- 207,213 ---- /* * calculate next starting lineoff, given scan direction */ ! if (ScanDirectionIsForward(dir)) { /* * forward scan direction *************** *** 242,248 **** linesleft = lines - lineoff + 1; } ! else if (dir < 0) { /* * reverse scan direction --- 244,250 ---- linesleft = lines - lineoff + 1; } ! else if (backward) { /* * reverse scan direction *************** *** 352,358 **** * otherwise move to the next item on the page */ --linesleft; ! if (dir < 0) { --lpp; /* move back in this page's ItemId array */ --lineoff; --- 354,360 ---- * otherwise move to the next item on the page */ --linesleft; ! if (backward) { --lpp; /* move back in this page's ItemId array */ --lineoff; *************** *** 373,379 **** /* * return NULL if we've exhausted all the pages */ ! if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); --- 375,381 ---- /* * return NULL if we've exhausted all the pages */ ! if ((backward) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); *************** *** 384,390 **** return; } ! page = (dir < 0) ? (page - 1) : (page + 1); heapgetpage(scan, page); --- 386,392 ---- return; } ! page = (backward) ? (page - 1) : (page + 1); heapgetpage(scan, page); *************** *** 393,399 **** dp = (Page) BufferGetPage(scan->rs_cbuf); lines = PageGetMaxOffsetNumber((Page) dp); linesleft = lines; ! if (dir < 0) { lineoff = lines; lpp = PageGetItemId(dp, lines); --- 395,401 ---- dp = (Page) BufferGetPage(scan->rs_cbuf); lines = PageGetMaxOffsetNumber((Page) dp); linesleft = lines; ! if (backward) { lineoff = lines; lpp = PageGetItemId(dp, lines); *************** *** 421,431 **** */ static void heapgettup_pagemode(HeapScanDesc scan, ! int dir, int nkeys, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); BlockNumber page; Page dp; int lines; --- 423,434 ---- */ static void heapgettup_pagemode(HeapScanDesc scan, ! ScanDirection dir, int nkeys, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); + bool backward = ScanDirectionIsBackward(dir); BlockNumber page; Page dp; int lines; *************** *** 437,443 **** /* * calculate next starting lineindex, given scan direction */ ! if (dir > 0) { /* * forward scan direction --- 440,446 ---- /* * calculate next starting lineindex, given scan direction */ ! if (ScanDirectionIsForward(dir)) { /* * forward scan direction *************** *** 471,477 **** linesleft = lines - lineindex; } ! else if (dir < 0) { /* * reverse scan direction --- 474,480 ---- linesleft = lines - lineindex; } ! else if (backward) { /* * reverse scan direction *************** *** 584,590 **** * otherwise move to the next item on the page */ --linesleft; ! if (dir < 0) { --lineindex; } --- 587,593 ---- * otherwise move to the next item on the page */ --linesleft; ! if (backward) { --lineindex; } *************** *** 602,608 **** /* * return NULL if we've exhausted all the pages */ ! if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); --- 605,611 ---- /* * return NULL if we've exhausted all the pages */ ! if ((backward) ? (page == 0) : (page + 1 >= scan->rs_nblocks)) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); *************** *** 613,626 **** return; } ! page = (dir < 0) ? (page - 1) : (page + 1); heapgetpage(scan, page); dp = (Page) BufferGetPage(scan->rs_cbuf); lines = scan->rs_ntuples; linesleft = lines; ! if (dir < 0) lineindex = lines - 1; else lineindex = 0; --- 616,629 ---- return; } ! page = (backward) ? (page - 1) : (page + 1); heapgetpage(scan, page); dp = (Page) BufferGetPage(scan->rs_cbuf); lines = scan->rs_ntuples; linesleft = lines; ! if (backward) lineindex = lines - 1; else lineindex = 0; *************** *** 988,995 **** #ifdef HEAPDEBUGALL #define HEAPDEBUG_1 \ ! elog(DEBUG2, "heap_getnext([%s,nkeys=%d],dir=%d) called", \ ! RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, (int) direction) #define HEAPDEBUG_2 \ elog(DEBUG2, "heap_getnext returning EOS") #define HEAPDEBUG_3 \ --- 991,998 ---- #ifdef HEAPDEBUGALL #define HEAPDEBUG_1 \ ! elog(DEBUG2, "heap_getnext([%s,nkeys=%d],dir=%c) called", \ ! RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, direction) #define HEAPDEBUG_2 \ elog(DEBUG2, "heap_getnext returning EOS") #define HEAPDEBUG_3 \ *************** *** 1008,1022 **** HEAPDEBUG_1; /* heap_getnext( info ) */ - /* - * Note: we depend here on the -1/0/1 encoding of ScanDirection. - */ if (scan->rs_pageatatime) ! heapgettup_pagemode(scan, (int) direction, ! scan->rs_nkeys, scan->rs_key); else ! heapgettup(scan, (int) direction, ! scan->rs_nkeys, scan->rs_key); if (scan->rs_ctup.t_data == NULL) { --- 1011,1020 ---- HEAPDEBUG_1; /* heap_getnext( info ) */ if (scan->rs_pageatatime) ! heapgettup_pagemode(scan, direction, scan->rs_nkeys, scan->rs_key); else ! heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key); if (scan->rs_ctup.t_data == NULL) { *************** *** 2745,2757 **** { scan->rs_cindex = scan->rs_mindex; heapgettup_pagemode(scan, ! 0, /* "no movement" */ 0, /* needn't recheck scan keys */ NULL); } else heapgettup(scan, ! 0, /* "no movement" */ 0, /* needn't recheck scan keys */ NULL); } --- 2743,2755 ---- { scan->rs_cindex = scan->rs_mindex; heapgettup_pagemode(scan, ! NoMovementScanDirection, /* "no movement" */ 0, /* needn't recheck scan keys */ NULL); } else heapgettup(scan, ! NoMovementScanDirection, /* "no movement" */ 0, /* needn't recheck scan keys */ NULL); } Index: src/backend/access/nbtree/nbtree.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v retrieving revision 1.141 diff -c -r1.141 nbtree.c *** src/backend/access/nbtree/nbtree.c 14 Feb 2006 17:20:01 -0000 1.141 --- src/backend/access/nbtree/nbtree.c 20 Feb 2006 00:41:06 -0000 *************** *** 233,239 **** btgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; Page page; OffsetNumber offnum; --- 233,239 ---- btgettuple(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ! ScanDirection dir = (ScanDirection) PG_GETARG_CHAR(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; Page page; OffsetNumber offnum; Index: src/backend/executor/execMain.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/executor/execMain.c,v retrieving revision 1.266 diff -c -r1.266 execMain.c *** src/backend/executor/execMain.c 19 Feb 2006 00:04:26 -0000 1.266 --- src/backend/executor/execMain.c 20 Feb 2006 00:41:07 -0000 *************** *** 218,224 **** /* * run plan */ ! if (direction == NoMovementScanDirection) result = NULL; else result = ExecutePlan(estate, --- 218,224 ---- /* * run plan */ ! if (ScanDirectionIsNoMovement(direction)) result = NULL; else result = ExecutePlan(estate, Index: src/backend/nodes/outfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v retrieving revision 1.268 diff -c -r1.268 outfuncs.c *** src/backend/nodes/outfuncs.c 19 Feb 2006 00:04:26 -0000 1.268 --- src/backend/nodes/outfuncs.c 20 Feb 2006 00:41:07 -0000 *************** *** 356,362 **** WRITE_NODE_FIELD(indexqualorig); WRITE_NODE_FIELD(indexstrategy); WRITE_NODE_FIELD(indexsubtype); ! WRITE_ENUM_FIELD(indexorderdir, ScanDirection); } static void --- 356,362 ---- WRITE_NODE_FIELD(indexqualorig); WRITE_NODE_FIELD(indexstrategy); WRITE_NODE_FIELD(indexsubtype); ! WRITE_CHAR_FIELD(indexorderdir); } static void *************** *** 1041,1047 **** WRITE_NODE_FIELD(indexclauses); WRITE_NODE_FIELD(indexquals); WRITE_BOOL_FIELD(isjoininner); ! WRITE_ENUM_FIELD(indexscandir, ScanDirection); WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); WRITE_FLOAT_FIELD(indexselectivity, "%.4f"); WRITE_FLOAT_FIELD(rows, "%.0f"); --- 1041,1047 ---- WRITE_NODE_FIELD(indexclauses); WRITE_NODE_FIELD(indexquals); WRITE_BOOL_FIELD(isjoininner); ! WRITE_CHAR_FIELD(indexscandir); WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); WRITE_FLOAT_FIELD(indexselectivity, "%.4f"); WRITE_FLOAT_FIELD(rows, "%.0f"); Index: src/backend/tcop/pquery.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/tcop/pquery.c,v retrieving revision 1.98 diff -c -r1.98 pquery.c *** src/backend/tcop/pquery.c 22 Nov 2005 18:17:21 -0000 1.98 --- src/backend/tcop/pquery.c 20 Feb 2006 00:41:08 -0000 *************** *** 795,801 **** nprocessed = queryDesc->estate->es_processed; } ! if (direction != NoMovementScanDirection) { long oldPos; --- 795,801 ---- nprocessed = queryDesc->estate->es_processed; } ! if (!ScanDirectionIsNoMovement(direction)) { long oldPos; *************** *** 837,843 **** nprocessed = queryDesc->estate->es_processed; } ! if (direction != NoMovementScanDirection) { if (nprocessed > 0 && portal->atEnd) { --- 837,843 ---- nprocessed = queryDesc->estate->es_processed; } ! if (!ScanDirectionIsNoMovement(direction)) { if (nprocessed > 0 && portal->atEnd) { *************** *** 890,902 **** (*dest->rStartup) (dest, CMD_SELECT, portal->tupDesc); ! if (direction == NoMovementScanDirection) { /* do nothing except start/stop the destination */ } else { ! bool forward = (direction == ForwardScanDirection); for (;;) { --- 890,902 ---- (*dest->rStartup) (dest, CMD_SELECT, portal->tupDesc); ! if (ScanDirectionIsNoMovement(direction)) { /* do nothing except start/stop the destination */ } else { ! bool forward = (ScanDirectionIsForward(direction)); for (;;) { Index: src/include/access/sdir.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/access/sdir.h,v retrieving revision 1.17 diff -c -r1.17 sdir.h *** src/include/access/sdir.h 31 Dec 2004 22:03:21 -0000 1.17 --- src/include/access/sdir.h 20 Feb 2006 00:41:09 -0000 *************** *** 15,38 **** #define SDIR_H ! /* ! * 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 ! */ ! typedef enum ScanDirection ! { ! BackwardScanDirection = -1, ! NoMovementScanDirection = 0, ! ForwardScanDirection = 1 ! } ScanDirection; /* * ScanDirectionIsValid * True iff scan direction is valid. */ #define ScanDirectionIsValid(direction) \ ! ((bool) (BackwardScanDirection <= (direction) && \ ! (direction) <= ForwardScanDirection)) /* * ScanDirectionIsBackward --- 15,33 ---- #define SDIR_H ! typedef char ScanDirection; ! #define BackwardScanDirection ((ScanDirection) 'b') ! #define NoMovementScanDirection ((ScanDirection) 'n') ! #define ForwardScanDirection ((ScanDirection) 'f') /* * ScanDirectionIsValid * True iff scan direction is valid. */ #define ScanDirectionIsValid(direction) \ ! ((bool) (BackwardScanDirection == (direction) || \ ! NoMovementScanDirection == (direction) || \ ! ForwardScanDirection == (direction))) /* * ScanDirectionIsBackward