*
* 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 $
*
*/
switch (nodeTag(plan))
{
case T_IndexScan:
+ if (ScanDirectionIsBackward(((IndexScan *)plan)->indxorderdir))
+ appendStringInfo(str, " Backward");
appendStringInfo(str, " using ");
i = 0;
foreach(l, ((IndexScan *) plan)->indxid)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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;
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 &&
}
indexstate->iss_NumIndices = numIndices;
+ if (ScanDirectionIsBackward(node->indxorderdir))
+ indexPtr = numIndices;
indexstate->iss_IndexPtr = indexPtr;
indexstate->iss_ScanKeys = scanKeys;
indexstate->iss_NumScanKeys = numScanKeys;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
newnode->indxid = listCopy(from->indxid);
Node_Copy(from, newnode, indxqual);
Node_Copy(from, newnode, indxqualorig);
+ newnode->indxorderdir = from->indxorderdir;
return newnode;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
*
* 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
appendStringInfo(str, " :indxqualorig ");
_outNode(str, node->indxqualorig);
+ appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir);
}
/*
*
*
* 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
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
node->indxid = indxid;
node->indxqual = indxqual;
node->indxqualorig = indxqualorig;
+ node->indxorderdir = NoMovementScanDirection;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/*****************************************************************************
}
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);
}
/* ----------
- * Support function for need_sortplan
+ * Support function for get scan direction to omit sortplan
* ----------
*/
static TargetEntry *
* 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;
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;
* ----------
*/
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
* ----------
*/
if (length(sortcls) > 8)
- return TRUE;
+ return nodir;
/* ----------
* The choosen Index must be a btree
if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)
{
heap_close(indexRel);
- return TRUE;
+ return nodir;
}
heap_close(indexRel);
* Could this happen?
* ----------
*/
- return TRUE;
+ return nodir;
}
if (nodeTag(tle->expr) != T_Var)
{
* cannot be the indexed attribute
* ----------
*/
- return TRUE;
+ return nodir;
}
var = (Var *) (tle->expr);
* that of the index
* ----------
*/
- return TRUE;
+ return nodir;
}
if (var->varattno != index_tup->indkey[key_no])
* It isn't the indexed attribute.
* ----------
*/
- return TRUE;
+ return nodir;
}
if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid)
* 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++;
* Index matches ORDER BY - sort not required
* ----------
*/
- return FALSE;
+ return dir;
}
*
* 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 $
*
*-------------------------------------------------------------------------
*/
List *indxid;
List *indxqual;
List *indxqualorig;
+ ScanDirection indxorderdir;
IndexScanState *indxstate;
} IndexScan;