Thread: How to get last 10 rows in a table on a large database?

How to get last 10 rows in a table on a large database?

From
Alex@Icepick.com (Alex)
Date:
Hi,

Does anyone have a good idea to get the last 10 rows from a table? I
tried 

SELECT * FROM table ORDER BY datetime DESC LIMIT 10

But my table has over 1 million rows, so this takes forever.. anyone
has a better idea on how to do this? 

Alex
--
Alex van Es, P.O. Box 698, 7300 AR Apeldoorn, The Netherlands.
8 Webcams, doorbell, fridge, barcodescanner.. all connected to the internet.
Check http://www.icepick.com for details.. 
NEW! A Hyperwired cat.. http://www.blackie.com!


Re: [SQL] How to get last 10 rows in a table on a large database?

From
Stoyan Genov
Date:
Hi.
You should try this:begin transaction;    declare tbl_cur cursor for select * from table order by datetime ASC;
fetchforward 10 in tbl_cur;end transaction;
 

This is true if you want THE LAST 10 rows from the selection - you order it
in reverse and get the first 10. You are unable to say:begin transaction;    declare tbl_cur cursor for .... .....
moveforward all in tbl_cur;    fetch backward 10 in tbl_cur;    ...........end transaction;
 
because when you "move forward all" the result gets lost.

If something is unclear, do write back...

Stoyan Genov



Re: [SQL] How to get last 10 rows in a table on a large database?

From
Tom Lane
Date:
Alex@Icepick.com (Alex) writes:
> Does anyone have a good idea to get the last 10 rows from a table? I
> tried 
> SELECT * FROM table ORDER BY datetime DESC LIMIT 10
> But my table has over 1 million rows, so this takes forever.. anyone
> has a better idea on how to do this? 

FWIW, that query should work the way you want in 7.0 (assuming you have
an index on datetime).  6.5.* isn't bright enough to use an index for
ORDER BY DESC, though.  I think Stoyan's suggestion of declaring a
cursor is probably the best workaround for now --- or you could consult
the patches list archives for the patch that will make 6.5 use an index.
        regards, tom lane


Re: [SQL] How to get last 10 rows in a table on a large database?

From
Tom Lane
Date:
Stoyan Genov <genov@digsys.bg> writes:
> You are unable to say:
>     begin transaction;
>         declare tbl_cur cursor for .... .....
>         move forward all in tbl_cur;
>         fetch backward 10 in tbl_cur;
>         ...........
>     end transaction;
> because when you "move forward all" the result gets lost.

Huh?  It seems to work fine for me.

However, the "move" is a tad slow since the silly thing actually scans
over all the tuples in index order :-(.  This might not be a useful
solution for Alex's problem after all, because of the time taken by
the "move".
        regards, tom lane


Re: [SQL] How to get last 10 rows in a table on a large database?

From
Oleg Bartunov
Date:
On Sat, 6 Nov 1999, Tom Lane wrote:

> Date: Sat, 06 Nov 1999 13:12:27 -0500
> From: Tom Lane <tgl@sss.pgh.pa.us>
> To: Alex@Icepick.com
> Cc: pgsql-sql@postgreSQL.org
> Subject: Re: [SQL] How to get last 10 rows in a table on a large database? 
> 
> Alex@Icepick.com (Alex) writes:
> > Does anyone have a good idea to get the last 10 rows from a table? I
> > tried 
> > SELECT * FROM table ORDER BY datetime DESC LIMIT 10
> > But my table has over 1 million rows, so this takes forever.. anyone
> > has a better idea on how to do this? 
> 
> FWIW, that query should work the way you want in 7.0 (assuming you have
> an index on datetime).  6.5.* isn't bright enough to use an index for
> ORDER BY DESC, though.  I think Stoyan's suggestion of declaring a
> cursor is probably the best workaround for now --- or you could consult
> the patches list archives for the patch that will make 6.5 use an index.

I attached patch for 6.5.3 Hiroshi kindly made on my request. 
It applies cleanly and seems works ok.
Oleg




> 
>             regards, tom lane
> 
> ************
> 

_____________________________________________________________
Oleg Bartunov, sci.researcher, hostmaster of AstroNet,
Sternberg Astronomical Institute, Moscow University (Russia)
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(095)939-16-83, +007(095)939-23-83
*** backend/optimizer/plan/planner.c.org    Mon Aug  2 15:27:02 1999
--- backend/optimizer/plan/planner.c    Wed Nov  3 10:04:41 1999
***************
*** 39,45 **** static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,                List *groupClause,
AttrNumber*grpColIdx,                Plan *subplan);
 
! static bool need_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist, List *sortcls, Plan
*plannode); /*****************************************************************************
 
--- 39,45 ---- static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,                List *groupClause,
AttrNumber*grpColIdx,                Plan *subplan);
 
! static ScanDirection get_dir_to_omit_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist,
List*sortcls, Plan *plannode);  /*****************************************************************************
 
***************
*** 303,310 ****     }     else     {
!         if (parse->sortClause && need_sortplan(parse->sortClause, result_plan))
!             return (make_sortplan(tlist, parse->sortClause, result_plan));         else             return ((Plan *)
result_plan);    }
 
--- 303,319 ----     }     else     {
!         if (parse->sortClause)
!         {
!             ScanDirection    dir = get_dir_to_omit_sortplan(parse->sortClause, result_plan);
!             if (ScanDirectionIsNoMovement(dir))
!                 return (make_sortplan(tlist, parse->sortClause, result_plan));
!             else
!             { 
!                 ((IndexScan *)result_plan)->indxorderdir = dir;
!                 return ((Plan *) result_plan);
!             }
!         }         else             return ((Plan *) result_plan);     }
***************
*** 822,828 ****   /* ----------
!  * Support function for need_sortplan  * ----------  */ static TargetEntry *
--- 831,837 ----   /* ----------
!  * Support function for get scan direction to omit sortplan  * ----------  */ static TargetEntry *
***************
*** 845,855 ****  * Check if a user requested ORDER BY is already satisfied by  * the choosen index scan.  *
!  * Returns TRUE if sort is required, FALSE if can be omitted.  * ----------  */
! static bool
! need_sortplan(List *sortcls, Plan *plan) {     Relation    indexRel;     IndexScan  *indexScan;
--- 854,866 ----  * Check if a user requested ORDER BY is already satisfied by  * the choosen index scan.  *
!  * Returns the direction of Index scan to omit sort,
!  * if sort is required returns NoMovementScanDirection  
!  *  * ----------  */
! static ScanDirection
! get_dir_to_omit_sortplan(List *sortcls, Plan *plan) {     Relation    indexRel;     IndexScan  *indexScan;
***************
*** 858,870 ****     HeapTuple    htup;     Form_pg_index index_tup;     int            key_no = 0;      /* ----------
   * Must be an IndexScan      * ----------      */     if (nodeTag(plan) != T_IndexScan)
 
!         return TRUE;      indexScan = (IndexScan *) plan; 
--- 869,883 ----     HeapTuple    htup;     Form_pg_index index_tup;     int            key_no = 0;
+     ScanDirection   dir, nodir = NoMovementScanDirection; 
+     dir = nodir;     /* ----------      * Must be an IndexScan      * ----------      */     if (nodeTag(plan) !=
T_IndexScan)
!         return nodir;      indexScan = (IndexScan *) plan; 
***************
*** 873,888 ****      * ----------      */     if (plan->lefttree != NULL)
!         return TRUE;     if (plan->righttree != NULL)
!         return TRUE;      /* ----------      * Must be a single index scan      * ----------      */     if
(length(indexScan->indxid)!= 1)
 
!         return TRUE;      /* ----------      * Indices can only have up to 8 attributes. So an ORDER BY using
--- 886,901 ----      * ----------      */     if (plan->lefttree != NULL)
!         return nodir;     if (plan->righttree != NULL)
!         return nodir;      /* ----------      * Must be a single index scan      * ----------      */     if
(length(indexScan->indxid)!= 1)
 
!         return nodir;      /* ----------      * Indices can only have up to 8 attributes. So an ORDER BY using
***************
*** 890,896 ****      * ----------      */     if (length(sortcls) > 8)
!         return TRUE;      /* ----------      * The choosen Index must be a btree
--- 903,909 ----      * ----------      */     if (length(sortcls) > 8)
!         return nodir;      /* ----------      * The choosen Index must be a btree
***************
*** 902,908 ****     if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)     {
heap_close(indexRel);
!         return TRUE;     }     heap_close(indexRel); 
--- 915,921 ----     if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)     {
heap_close(indexRel);
!         return nodir;     }     heap_close(indexRel); 
***************
*** 937,943 ****              * Could this happen?              * ----------              */
!             return TRUE;         }         if (nodeTag(tle->expr) != T_Var)         {
--- 950,956 ----              * Could this happen?              * ----------              */
!             return nodir;         }         if (nodeTag(tle->expr) != T_Var)         {
***************
*** 946,952 ****              * cannot be the indexed attribute              * ----------              */
!             return TRUE;         }         var = (Var *) (tle->expr); 
--- 959,965 ----              * cannot be the indexed attribute              * ----------              */
!             return nodir;         }         var = (Var *) (tle->expr); 
***************
*** 957,963 ****              * that of the index              * ----------              */
!             return TRUE;         }          if (var->varattno != index_tup->indkey[key_no])
--- 970,976 ----              * that of the index              * ----------              */
!             return nodir;         }          if (var->varattno != index_tup->indkey[key_no])
***************
*** 966,972 ****              * It isn't the indexed attribute.              * ----------              */
!             return TRUE;         }          if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) !=
sortcl->opoid)
--- 979,985 ----              * It isn't the indexed attribute.              * ----------              */
!             return nodir;         }          if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) !=
sortcl->opoid)
***************
*** 975,981 ****              * Sort order isn't in ascending order.              * ----------              */
!             return TRUE;         }          key_no++;
--- 988,1006 ----              * Sort order isn't in ascending order.              * ----------              */
!             if (ScanDirectionIsForward(dir))
!                 return nodir;
!             dir = BackwardScanDirection;
!         }
!         else
!         {
!             /* ----------
!              * Sort order is in ascending order.
!              * ----------
!             */
!             if (ScanDirectionIsBackward(dir))
!                 return nodir;
!             dir = ForwardScanDirection;         }          key_no++;
***************
*** 985,989 ****      * Index matches ORDER BY - sort not required      * ----------      */
!     return FALSE; }
--- 1010,1014 ----      * Index matches ORDER BY - sort not required      * ----------      */
!     return dir; }
*** backend/executor/nodeIndexscan.c.org    Wed May 26 01:08:43 1999
--- backend/executor/nodeIndexscan.c    Wed Nov  3 10:04:41 1999
***************
*** 105,110 ****
--- 105,117 ----      */     estate = node->scan.plan.state;     direction = estate->es_direction;
+     if (ScanDirectionIsBackward(node->indxorderdir))
+     {
+         if (ScanDirectionIsForward(direction))
+             direction = BackwardScanDirection;
+         else if (ScanDirectionIsBackward(direction))
+             direction = ForwardScanDirection;
+     }       snapshot = estate->es_snapshot;     scanstate = node->scan.scanstate;     indexstate = node->indxstate;
***************
*** 322,327 ****
--- 329,336 ----     indxqual = node->indxqual;     numScanKeys = indexstate->iss_NumScanKeys;
indexstate->iss_IndexPtr= -1;
 
+     if (ScanDirectionIsBackward(node->indxorderdir))
+         indexstate->iss_IndexPtr = numIndices;      /* If this is re-scanning of PlanQual ... */     if
(estate->es_evTuple!= NULL &&
 
***************
*** 972,977 ****
--- 981,988 ----     }      indexstate->iss_NumIndices = numIndices;
+     if (ScanDirectionIsBackward(node->indxorderdir))
+         indexPtr = numIndices;     indexstate->iss_IndexPtr = indexPtr;     indexstate->iss_ScanKeys = scanKeys;
indexstate->iss_NumScanKeys= numScanKeys;
 
*** backend/optimizer/plan/createplan.c.org    Thu Jul 29 12:34:11 1999
--- backend/optimizer/plan/createplan.c    Wed Nov  3 10:04:41 1999
***************
*** 1040,1045 ****
--- 1040,1046 ----     node->indxid = indxid;     node->indxqual = indxqual;     node->indxqualorig = indxqualorig;
+     node->indxorderdir = NoMovementScanDirection;     node->scan.scanstate = (CommonScanState *) NULL;      return
node;
*** backend/nodes/copyfuncs.c.org    Wed May 26 07:41:11 1999
--- backend/nodes/copyfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 251,256 ****
--- 251,257 ----     newnode->indxid = listCopy(from->indxid);     Node_Copy(from, newnode, indxqual);
Node_Copy(from,newnode, indxqualorig);
 
+     newnode->indxorderdir = from->indxorderdir;      return newnode; }
*** backend/nodes/readfuncs.c.org    Wed May 26 01:09:11 1999
--- backend/nodes/readfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 546,551 ****
--- 546,556 ----     token = lsptok(NULL, &length);        /* eat :indxqualorig */     local_node->indxqualorig =
nodeRead(true);   /* now read it */ 
 
+     token = lsptok(NULL, &length);        /* eat :indxorderdir */
+     token = lsptok(NULL, &length);        /* get indxorderdir */
+ 
+     local_node->indxorderdir = atoi(token);
+      return local_node; } 
*** backend/nodes/outfuncs.c.org    Wed May 26 07:41:14 1999
--- backend/nodes/outfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 450,455 ****
--- 450,456 ----     appendStringInfo(str, " :indxqualorig ");     _outNode(str, node->indxqualorig); 
+     appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir); }  /*
*** backend/nodes/equalfuncs.c.org    Thu Jul 29 12:34:11 1999
--- backend/nodes/equalfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 527,532 ****
--- 527,535 ----     if (a->scan.scanrelid != b->scan.scanrelid)         return false; 
+     if (a->indxorderdir != b->indxorderdir)
+         return false;
+      if (!equali(a->indxid, b->indxid))         return false;     return true;
*** backend/commands/explain.c.org    Mon Aug  2 14:56:58 1999
--- backend/commands/explain.c    Wed Nov  3 10:04:41 1999
***************
*** 200,205 ****
--- 200,207 ----     switch (nodeTag(plan))     {         case T_IndexScan:
+             if (ScanDirectionIsBackward(((IndexScan *)plan)->indxorderdir))
+                 appendStringInfo(str, " Backward");             appendStringInfo(str, " using ");             i = 0;
          foreach(l, ((IndexScan *) plan)->indxid)
 
*** include/nodes/plannodes.h.org    Wed May 26 07:42:58 1999
--- include/nodes/plannodes.h    Wed Nov  3 10:04:41 1999
***************
*** 175,180 ****
--- 175,181 ----     List       *indxid;     List       *indxqual;     List       *indxqualorig;
+     ScanDirection    indxorderdir;     IndexScanState *indxstate; } IndexScan; 


> > You are unable to say:
> >     begin transaction;
> >         declare tbl_cur cursor for .... .....
> >         move forward all in tbl_cur;
> >         fetch backward 10 in tbl_cur;
> >         ...........
> >     end transaction;
> > because when you "move forward all" the result gets lost.
> 
> Huh?  It seems to work fine for me.

Well, it does not seem to work for me neither on the 6.4.2 nor on the 
6.5.(1|2)
version. I'll try 6.5.3 as well... 
Any ideas why this is so?

Regards,Stoyan Genov



> -----Original Message-----
> From: owner-pgsql-sql@postgreSQL.org [mailto:owner-pgsql-sql@postgreSQL.
> org]On Behalf Of Stoyan Genov
> Sent: Sunday, November 07, 1999 7:25 PM
> To: Tom Lane
> Cc: pgsql-sql@postgreSQL.org
> Subject: [SQL] Move forward all (Was Re: How to get last 10 rows in a
> table on a large database?)
> 
> 
> > > You are unable to say:
> > >     begin transaction;
> > >         declare tbl_cur cursor for .... .....
> > >         move forward all in tbl_cur;
> > >         fetch backward 10 in tbl_cur;
> > >         ...........
> > >     end transaction;
> > > because when you "move forward all" the result gets lost.
> > 
> > Huh?  It seems to work fine for me.
> 
> Well, it does not seem to work for me neither on the 6.4.2 nor on the 
> 6.5.(1|2)
> version. I'll try 6.5.3 as well... 
> Any ideas why this is so?
>

Doesn't your query have any qualification(WHERE clause) about
columns in index ?
If there's no qualification,PostgreSQL optimizer chooses sequential
scan(however current developing tree probably chooses Index scan
in case of ORDER BY).
In case of Index scan,"fetch backward .." after "move forward all" is
possible after 6.5 ,
But in case of sequential scan,maybe it's still impossible.

I knew the way to fix it but am not sure now.
Do you really want to make it possible ?
It isn't an appropriate way to get last rows because "move forward
all" takes very long time.

Regards.

Hiroshi Inoue
Inoue@tpf.co.jp


> > -----Original Message-----
> > From: owner-pgsql-sql@postgreSQL.org [mailto:owner-pgsql-sql@postgreSQL.
> > org]On Behalf Of Stoyan Genov
> > Sent: Sunday, November 07, 1999 7:25 PM
> > To: Tom Lane
> > Cc: pgsql-sql@postgreSQL.org
> > Subject: [SQL] Move forward all (Was Re: How to get last 10 rows in a
> > table on a large database?)
> > 
> > 
> > > > You are unable to say:
> > > >     begin transaction;
> > > >         declare tbl_cur cursor for .... .....
> > > >         move forward all in tbl_cur;
> > > >         fetch backward 10 in tbl_cur;
> > > >         ...........
> > > >     end transaction;
> > > > because when you "move forward all" the result gets lost.
> > > 
> > > Huh?  It seems to work fine for me.
> > 
> > Well, it does not seem to work for me neither on the 6.4.2 nor on the 
> > 6.5.(1|2)
> > version. I'll try 6.5.3 as well... 
> > Any ideas why this is so?
> >
> 
> Doesn't your query have any qualification(WHERE clause) about
> columns in index ?
> If there's no qualification,PostgreSQL optimizer chooses sequential
> scan(however current developing tree probably chooses Index scan
> in case of ORDER BY).
> In case of Index scan,"fetch backward .." after "move forward all" is
> possible after 6.5 ,
> But in case of sequential scan,maybe it's still impossible.

I have tested this - for a sequental scan it is still impossible (talking
6.4.2 and 6.5.* versions)

> I knew the way to fix it but am not sure now.
> Do you really want to make it possible ?
> It isn't an appropriate way to get last rows because "move forward
> all" takes very long time.
> 


Of course it is not an appropriate way to get the last rows like this.
The "right" way IMHO is to reverse the order in the query and to get the 
first
rows. 

It is just for the sake of truth...

> Regards.
> 
> Hiroshi Inoue
> Inoue@tpf.co.jp


Regards,
Stoyan Genov



Stoyan Genov wrote:

> > > > > You are unable to say:
> > > > >         begin transaction;
> > > > >                 declare tbl_cur cursor for .... .....
> > > > >                 move forward all in tbl_cur;
> > > > >                 fetch backward 10 in tbl_cur;
> > > > >                 ...........
> > > > >         end transaction;
> > > > > because when you "move forward all" the result gets lost.
> > > >
> > > > Huh?  It seems to work fine for me.
> > >
> > > Well, it does not seem to work for me neither on the 6.4.2 nor on the
> > > 6.5.(1|2)
> > > version. I'll try 6.5.3 as well...
> > > Any ideas why this is so?
> > >
> >
> > Doesn't your query have any qualification(WHERE clause) about
> > columns in index ?
> > If there's no qualification,PostgreSQL optimizer chooses sequential
> > scan(however current developing tree probably chooses Index scan
> > in case of ORDER BY).
> > In case of Index scan,"fetch backward .." after "move forward all" is
> > possible after 6.5 ,
> > But in case of sequential scan,maybe it's still impossible.
>
> I have tested this - for a sequental scan it is still impossible (talking
> 6.4.2 and 6.5.* versions)
>
> > I knew the way to fix it but am not sure now.
> > Do you really want to make it possible ?
> > It isn't an appropriate way to get last rows because "move forward
> > all" takes very long time.
> >
>
> Of course it is not an appropriate way to get the last rows like this.
> The "right" way IMHO is to reverse the order in the query and to get the
> first
> rows.
>
> It is just for the sake of truth...
>

OK Attached is a patch.
Could you apply to 6.5.3 ?

Regards.

Hiroshi Inoue
Inoue@tpf.co.jp




*** access/heap/heapam.c.orig    Mon Aug  2 14:56:36 1999
--- access/heap/heapam.c    Tue Nov  9 09:06:58 1999
***************
*** 833,842 ****
                  ReleaseBuffer(scan->rs_pbuf);
              scan->rs_ptup.t_data = NULL;
              scan->rs_pbuf = InvalidBuffer;
-             if (BufferIsValid(scan->rs_nbuf))
-                 ReleaseBuffer(scan->rs_nbuf);
-             scan->rs_ntup.t_data = NULL;
-             scan->rs_nbuf = InvalidBuffer;
              return NULL;
          }

--- 833,838 ----
***************
*** 915,924 ****
                  ReleaseBuffer(scan->rs_nbuf);
              scan->rs_ntup.t_data = NULL;
              scan->rs_nbuf = InvalidBuffer;
-             if (BufferIsValid(scan->rs_pbuf))
-                 ReleaseBuffer(scan->rs_pbuf);
-             scan->rs_ptup.t_data = NULL;
-             scan->rs_pbuf = InvalidBuffer;
              HEAPDEBUG_6;        /* heap_getnext returning EOS */
              return NULL;
          }
--- 911,916 ----


> >
> > > I knew the way to fix it but am not sure now.
> > > Do you really want to make it possible ?
> > > It isn't an appropriate way to get last rows because "move forward
> > > all" takes very long time.
> > >
> >
> > Of course it is not an appropriate way to get the last rows like this.
> > The "right" way IMHO is to reverse the order in the query and to get the
> > first
> > rows.
> >
> > It is just for the sake of truth...
> >
>
> OK Attached is a patch.
> Could you apply to 6.5.3 ?
>

Sorry the patch is not right for 6.5.3 .
Please apply the following patch to 6.5.3 .

Regards.

Hiroshi Inoue
Inoue@tpf.co.jp

*** access/heap/heapam.c.orig    Mon Aug  2 14:56:36 1999
--- access/heap/heapam.c    Tue Nov  9 12:59:48 1999
***************
*** 775,782 ****         if (scan->rs_ptup.t_data == scan->rs_ctup.t_data &&
BufferIsInvalid(scan->rs_pbuf))        {
 
-             if (BufferIsValid(scan->rs_nbuf))
-                 ReleaseBuffer(scan->rs_nbuf);             return NULL;         }

--- 775,780 ----
***************
*** 833,842 ****                 ReleaseBuffer(scan->rs_pbuf);             scan->rs_ptup.t_data = NULL;
scan->rs_pbuf= InvalidBuffer;
 
-             if (BufferIsValid(scan->rs_nbuf))
-                 ReleaseBuffer(scan->rs_nbuf);
-             scan->rs_ntup.t_data = NULL;
-             scan->rs_nbuf = InvalidBuffer;             return NULL;         }

--- 831,836 ----
***************
*** 855,862 ****         if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
BufferIsInvalid(scan->rs_nbuf))        {
 
-             if (BufferIsValid(scan->rs_pbuf))
-                 ReleaseBuffer(scan->rs_pbuf);             HEAPDEBUG_3;        /* heap_getnext returns NULL at end */
          return NULL;         }
 
--- 849,854 ----
***************
*** 915,924 ****                 ReleaseBuffer(scan->rs_nbuf);             scan->rs_ntup.t_data = NULL;
scan->rs_nbuf= InvalidBuffer;
 
-             if (BufferIsValid(scan->rs_pbuf))
-                 ReleaseBuffer(scan->rs_pbuf);
-             scan->rs_ptup.t_data = NULL;
-             scan->rs_pbuf = InvalidBuffer;             HEAPDEBUG_6;        /* heap_getnext returning EOS */
 return NULL;         }
 
--- 907,912 ----




> > >
> > > > I knew the way to fix it but am not sure now.
> > > > Do you really want to make it possible ?
> > > > It isn't an appropriate way to get last rows because "move forward
> > > > all" takes very long time.
> > > >
> > >
> > > Of course it is not an appropriate way to get the last rows like this.
> > > The "right" way IMHO is to reverse the order in the query and to get the
> > > first
> > > rows.
> > >
> > > It is just for the sake of truth...
> > >
> >
> > OK Attached is a patch.
> > Could you apply to 6.5.3 ?
> >
> 
> Sorry the patch is not right for 6.5.3 .
> Please apply the following patch to 6.5.3 .
> 
> Regards.
> 
> Hiroshi Inoue
> Inoue@tpf.co.jp
> 
> *** access/heap/heapam.c.orig    Mon Aug  2 14:56:36 1999
> --- access/heap/heapam.c    Tue Nov  9 12:59:48 1999
> ***************
> *** 775,782 ****
>           if (scan->rs_ptup.t_data == scan->rs_ctup.t_data &&
>               BufferIsInvalid(scan->rs_pbuf))
>           {
> -             if (BufferIsValid(scan->rs_nbuf))
> -                 ReleaseBuffer(scan->rs_nbuf);
>               return NULL;
>           }
> 
> --- 775,780 ----
> ***************
> *** 833,842 ****
>                   ReleaseBuffer(scan->rs_pbuf);
>               scan->rs_ptup.t_data = NULL;
>               scan->rs_pbuf = InvalidBuffer;
> -             if (BufferIsValid(scan->rs_nbuf))
> -                 ReleaseBuffer(scan->rs_nbuf);
> -             scan->rs_ntup.t_data = NULL;
> -             scan->rs_nbuf = InvalidBuffer;
>               return NULL;
>           }
> 
> --- 831,836 ----
> ***************
> *** 855,862 ****
>           if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
>               BufferIsInvalid(scan->rs_nbuf))
>           {
> -             if (BufferIsValid(scan->rs_pbuf))
> -                 ReleaseBuffer(scan->rs_pbuf);
>               HEAPDEBUG_3;        /* heap_getnext returns NULL at end */
>               return NULL;
>           }
> --- 849,854 ----
> ***************
> *** 915,924 ****
>                   ReleaseBuffer(scan->rs_nbuf);
>               scan->rs_ntup.t_data = NULL;
>               scan->rs_nbuf = InvalidBuffer;
> -             if (BufferIsValid(scan->rs_pbuf))
> -                 ReleaseBuffer(scan->rs_pbuf);
> -             scan->rs_ptup.t_data = NULL;
> -             scan->rs_pbuf = InvalidBuffer;
>               HEAPDEBUG_6;        /* heap_getnext returning EOS */
>               return NULL;
>           }
> --- 907,912 ----
> 
> 
> 
> ************
> 

I have applied the patch.
Now postgres 6.5.3 works fine (FETCH BACKWARD fetches
result after MOVE FORWARD ALL/FETCH FORWARD ALL).
Thank you very much.

Regards,
Stoyan Genov