From 158fd5f1c4ab70f6db388e2bc7f4467b63d85457 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Mon, 9 Aug 1999 06:20:27 +0000
Subject: [PATCH] > >        Prevent sorting if result is already sorted > > >
 > was implemented by Jan Wieck. > > His work is for ascending order cases. >
 > > > Here is a patch to prevent sorting also in descending > > order cases.
 > > Because I had already changed _bt_first() to position > > backward
 correctly before v6.5,this patch would work. > > Hiroshi Inoue
 Inoue@tpf.co.jp

---
 src/backend/commands/explain.c          |  4 +-
 src/backend/executor/nodeIndexscan.c    | 13 ++++-
 src/backend/nodes/copyfuncs.c           |  3 +-
 src/backend/nodes/equalfuncs.c          |  5 +-
 src/backend/nodes/outfuncs.c            |  3 +-
 src/backend/nodes/readfuncs.c           |  7 ++-
 src/backend/optimizer/plan/createplan.c |  3 +-
 src/backend/optimizer/plan/planner.c    | 65 +++++++++++++++++--------
 src/include/nodes/plannodes.h           |  3 +-
 9 files changed, 78 insertions(+), 28 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 460fdcc1f91..31a8d9d3679 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 1994-5, Regents of the University of California
  *
- *	  $Id: explain.c,v 1.43 1999/07/17 20:16:52 momjian Exp $
+ *	  $Id: explain.c,v 1.44 1999/08/09 06:20:21 momjian Exp $
  *
  */
 
@@ -200,6 +200,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 	switch (nodeTag(plan))
 	{
 		case T_IndexScan:
+			if (ScanDirectionIsBackward(((IndexScan *)plan)->indxorderdir))
+				appendStringInfo(str, " Backward");
 			appendStringInfo(str, " using ");
 			i = 0;
 			foreach(l, ((IndexScan *) plan)->indxid)
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 0a35cf2cf8c..7be2f1b8c99 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.40 1999/07/16 04:58:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.41 1999/08/09 06:20:22 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -99,6 +99,13 @@ IndexNext(IndexScan *node)
 	 */
 	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;
@@ -316,6 +323,8 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
 	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 &&
@@ -966,6 +975,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
 	}
 
 	indexstate->iss_NumIndices = numIndices;
+	if (ScanDirectionIsBackward(node->indxorderdir))
+		indexPtr = numIndices;
 	indexstate->iss_IndexPtr = indexPtr;
 	indexstate->iss_ScanKeys = scanKeys;
 	indexstate->iss_NumScanKeys = numScanKeys;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index db97c2ed39b..ca2bd33a2c1 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.89 1999/07/27 03:51:07 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.90 1999/08/09 06:20:23 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -238,6 +238,7 @@ _copyIndexScan(IndexScan *from)
 	newnode->indxid = listCopy(from->indxid);
 	Node_Copy(from, newnode, indxqual);
 	Node_Copy(from, newnode, indxqualorig);
+	newnode->indxorderdir = from->indxorderdir;
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 576601faf57..337e63a6156 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.45 1999/07/29 02:45:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.46 1999/08/09 06:20:24 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -437,6 +437,9 @@ _equalIndexScan(IndexScan *a, IndexScan *b)
 	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;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 4272bf04cc5..5c9f4599deb 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: outfuncs.c,v 1.91 1999/07/24 23:21:07 tgl Exp $
+ *	$Id: outfuncs.c,v 1.92 1999/08/09 06:20:24 momjian Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -445,6 +445,7 @@ _outIndexScan(StringInfo str, IndexScan *node)
 	appendStringInfo(str, " :indxqualorig ");
 	_outNode(str, node->indxqualorig);
 
+	appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
 }
 
 /*
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e16398fb854..c49ad053f1b 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.70 1999/07/24 23:21:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.71 1999/08/09 06:20:24 momjian Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -532,6 +532,11 @@ _readIndexScan()
 	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;
 }
 
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d3d79f6ef8a..dbc6ac9d289 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.67 1999/08/09 01:01:42 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.68 1999/08/09 06:20:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1024,6 +1024,7 @@ make_indexscan(List *qptlist,
 	node->indxid = indxid;
 	node->indxqual = indxqual;
 	node->indxqualorig = indxqualorig;
+	node->indxorderdir = NoMovementScanDirection;
 	node->scan.scanstate = (CommonScanState *) NULL;
 
 	return node;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 41bb025e286..17ad449839b 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.61 1999/07/17 20:17:15 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.62 1999/08/09 06:20:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,7 @@ static List *make_subplanTargetList(Query *parse, List *tlist,
 static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,
 			   List *groupClause, AttrNumber *grpColIdx,
 			   Plan *subplan);
-static bool need_sortplan(List *sortcls, Plan *plan);
+static ScanDirection get_dir_to_omit_sortplan(List *sortcls, Plan *plan);
 static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
 
 /*****************************************************************************
@@ -303,8 +303,17 @@ union_planner(Query *parse)
 	}
 	else
 	{
-		if (parse->sortClause && need_sortplan(parse->sortClause, result_plan))
-			return (make_sortplan(tlist, parse->sortClause, result_plan));
+		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,7 +831,7 @@ pg_checkretval(Oid rettype, List *queryTreeList)
 
 
 /* ----------
- * Support function for need_sortplan
+ * Support function for get scan direction to omit sortplan
  * ----------
  */
 static TargetEntry *
@@ -845,11 +854,13 @@ get_matching_tle(Plan *plan, Resdom *resdom)
  * 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.
+ * Returns the direction of Index scan to omit sort,
+ * if sort is required returns NoMovementScanDirection  
+ *
  * ----------
  */
-static bool
-need_sortplan(List *sortcls, Plan *plan)
+static ScanDirection
+get_dir_to_omit_sortplan(List *sortcls, Plan *plan)
 {
 	Relation	indexRel;
 	IndexScan  *indexScan;
@@ -858,13 +869,15 @@ need_sortplan(List *sortcls, Plan *plan)
 	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 TRUE;
+		return nodir;
 
 	indexScan = (IndexScan *) plan;
 
@@ -873,16 +886,16 @@ need_sortplan(List *sortcls, Plan *plan)
 	 * ----------
 	 */
 	if (plan->lefttree != NULL)
-		return TRUE;
+		return nodir;
 	if (plan->righttree != NULL)
-		return TRUE;
+		return nodir;
 
 	/* ----------
 	 * Must be a single index scan
 	 * ----------
 	 */
 	if (length(indexScan->indxid) != 1)
-		return TRUE;
+		return nodir;
 
 	/* ----------
 	 * Indices can only have up to 8 attributes. So an ORDER BY using
@@ -890,7 +903,7 @@ need_sortplan(List *sortcls, Plan *plan)
 	 * ----------
 	 */
 	if (length(sortcls) > 8)
-		return TRUE;
+		return nodir;
 
 	/* ----------
 	 * The choosen Index must be a btree
@@ -902,7 +915,7 @@ need_sortplan(List *sortcls, Plan *plan)
 	if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)
 	{
 		heap_close(indexRel);
-		return TRUE;
+		return nodir;
 	}
 	heap_close(indexRel);
 
@@ -937,7 +950,7 @@ need_sortplan(List *sortcls, Plan *plan)
 			 * Could this happen?
 			 * ----------
 			 */
-			return TRUE;
+			return nodir;
 		}
 		if (nodeTag(tle->expr) != T_Var)
 		{
@@ -946,7 +959,7 @@ need_sortplan(List *sortcls, Plan *plan)
 			 * cannot be the indexed attribute
 			 * ----------
 			 */
-			return TRUE;
+			return nodir;
 		}
 		var = (Var *) (tle->expr);
 
@@ -957,7 +970,7 @@ need_sortplan(List *sortcls, Plan *plan)
 			 * that of the index
 			 * ----------
 			 */
-			return TRUE;
+			return nodir;
 		}
 
 		if (var->varattno != index_tup->indkey[key_no])
@@ -966,7 +979,7 @@ need_sortplan(List *sortcls, Plan *plan)
 			 * It isn't the indexed attribute.
 			 * ----------
 			 */
-			return TRUE;
+			return nodir;
 		}
 
 		if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid)
@@ -975,7 +988,19 @@ need_sortplan(List *sortcls, Plan *plan)
 			 * Sort order isn't in ascending order.
 			 * ----------
 			 */
-			return TRUE;
+			if (ScanDirectionIsForward(dir))
+				return nodir;
+			dir = BackwardScanDirection;
+		}
+		else
+		{
+			/* ----------
+			 * Sort order is in ascending order.
+			 * ----------
+			*/
+			if (ScanDirectionIsBackward(dir))
+				return nodir;
+			dir = ForwardScanDirection;
 		}
 
 		key_no++;
@@ -985,5 +1010,5 @@ need_sortplan(List *sortcls, Plan *plan)
 	 * Index matches ORDER BY - sort not required
 	 * ----------
 	 */
-	return FALSE;
+	return dir;
 }
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 3d319a66ff7..532be5196bf 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.28 1999/07/15 23:03:55 momjian Exp $
+ * $Id: plannodes.h,v 1.29 1999/08/09 06:20:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,6 +175,7 @@ typedef struct IndexScan
 	List	   *indxid;
 	List	   *indxqual;
 	List	   *indxqualorig;
+	ScanDirection	indxorderdir;
 	IndexScanState *indxstate;
 } IndexScan;
 
-- 
GitLab