aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execAmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execAmi.c')
-rw-r--r--src/backend/executor/execAmi.c73
1 files changed, 68 insertions, 5 deletions
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 1de3f5a778e..9b2e32576e1 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.99 2008/10/04 21:56:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.100 2008/10/17 22:10:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,6 +42,12 @@
#include "executor/nodeValuesscan.h"
#include "executor/nodeCtescan.h"
#include "executor/nodeWorktablescan.h"
+#include "nodes/nodeFuncs.h"
+#include "utils/syscache.h"
+
+
+static bool TargetListSupportsBackwardScan(List *targetlist);
+static bool IndexSupportsBackwardScan(Oid indexid);
/*
@@ -390,7 +396,8 @@ ExecSupportsBackwardScan(Plan *node)
{
case T_Result:
if (outerPlan(node) != NULL)
- return ExecSupportsBackwardScan(outerPlan(node));
+ return ExecSupportsBackwardScan(outerPlan(node)) &&
+ TargetListSupportsBackwardScan(node->targetlist);
else
return false;
@@ -403,29 +410,85 @@ ExecSupportsBackwardScan(Plan *node)
if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
return false;
}
+ /* need not check tlist because Append doesn't evaluate it */
return true;
}
case T_SeqScan:
- case T_IndexScan:
case T_TidScan:
case T_FunctionScan:
case T_ValuesScan:
case T_CteScan:
case T_WorkTableScan:
- return true;
+ return TargetListSupportsBackwardScan(node->targetlist);
+
+ case T_IndexScan:
+ return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) &&
+ TargetListSupportsBackwardScan(node->targetlist);
case T_SubqueryScan:
- return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
+ return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
+ TargetListSupportsBackwardScan(node->targetlist);
case T_Material:
case T_Sort:
+ /* these don't evaluate tlist */
return true;
case T_Limit:
+ /* doesn't evaluate tlist */
return ExecSupportsBackwardScan(outerPlan(node));
default:
return false;
}
}
+
+/*
+ * If the tlist contains set-returning functions, we can't support backward
+ * scan, because the TupFromTlist code is direction-ignorant.
+ */
+static bool
+TargetListSupportsBackwardScan(List *targetlist)
+{
+ if (expression_returns_set((Node *) targetlist))
+ return false;
+ return true;
+}
+
+/*
+ * An IndexScan node supports backward scan only if the index's AM does.
+ */
+static bool
+IndexSupportsBackwardScan(Oid indexid)
+{
+ bool result;
+ HeapTuple ht_idxrel;
+ HeapTuple ht_am;
+ Form_pg_class idxrelrec;
+ Form_pg_am amrec;
+
+ /* Fetch the pg_class tuple of the index relation */
+ ht_idxrel = SearchSysCache(RELOID,
+ ObjectIdGetDatum(indexid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ht_idxrel))
+ elog(ERROR, "cache lookup failed for relation %u", indexid);
+ idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
+
+ /* Fetch the pg_am tuple of the index' access method */
+ ht_am = SearchSysCache(AMOID,
+ ObjectIdGetDatum(idxrelrec->relam),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ht_am))
+ elog(ERROR, "cache lookup failed for access method %u",
+ idxrelrec->relam);
+ amrec = (Form_pg_am) GETSTRUCT(ht_am);
+
+ result = amrec->amcanbackward;
+
+ ReleaseSysCache(ht_idxrel);
+ ReleaseSysCache(ht_am);
+
+ return result;
+}