aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execScan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execScan.c')
-rw-r--r--src/backend/executor/execScan.c108
1 files changed, 92 insertions, 16 deletions
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index 6944e03e9bc..9352c79d81e 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -12,19 +12,20 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.23 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <sys/file.h>
-
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/memutils.h"
+static bool tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc);
+
+
/* ----------------------------------------------------------------
* ExecScan
*
@@ -50,6 +51,7 @@ ExecScan(ScanState *node,
EState *estate;
ExprContext *econtext;
List *qual;
+ ProjectionInfo *projInfo;
ExprDoneCond isDone;
TupleTableSlot *resultSlot;
@@ -59,6 +61,7 @@ ExecScan(ScanState *node,
estate = node->ps.state;
econtext = node->ps.ps_ExprContext;
qual = node->ps.qual;
+ projInfo = node->ps.ps_ProjInfo;
/*
* Check to see if we're still projecting out tuples from a previous
@@ -67,7 +70,8 @@ ExecScan(ScanState *node,
*/
if (node->ps.ps_TupFromTlist)
{
- resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
+ Assert(projInfo); /* can't get here if not projecting */
+ resultSlot = ExecProject(projInfo, &isDone);
if (isDone == ExprMultipleResult)
return resultSlot;
/* Done with that source tuple... */
@@ -101,10 +105,13 @@ ExecScan(ScanState *node,
*/
if (TupIsNull(slot))
{
- return ExecStoreTuple(NULL,
- node->ps.ps_ProjInfo->pi_slot,
- InvalidBuffer,
- true);
+ if (projInfo)
+ return ExecStoreTuple(NULL,
+ projInfo->pi_slot,
+ InvalidBuffer,
+ true);
+ else
+ return slot;
}
/*
@@ -123,16 +130,27 @@ ExecScan(ScanState *node,
{
/*
* Found a satisfactory scan tuple.
- *
- * Form a projection tuple, store it in the result tuple slot and
- * return it --- unless we find we can project no tuples from
- * this scan tuple, in which case continue scan.
*/
- resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
- if (isDone != ExprEndResult)
+ if (projInfo)
{
- node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return resultSlot;
+ /*
+ * Form a projection tuple, store it in the result tuple slot
+ * and return it --- unless we find we can project no tuples
+ * from this scan tuple, in which case continue scan.
+ */
+ resultSlot = ExecProject(projInfo, &isDone);
+ if (isDone != ExprEndResult)
+ {
+ node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
+ return resultSlot;
+ }
+ }
+ else
+ {
+ /*
+ * Here, we aren't projecting, so just return scan tuple.
+ */
+ return slot;
}
}
@@ -142,3 +160,61 @@ ExecScan(ScanState *node,
ResetExprContext(econtext);
}
}
+
+/*
+ * ExecAssignScanProjectionInfo
+ * Set up projection info for a scan node, if necessary.
+ *
+ * We can avoid a projection step if the requested tlist exactly matches
+ * the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
+ * Note that this case occurs not only for simple "SELECT * FROM ...", but
+ * also in most cases where there are joins or other processing nodes above
+ * the scan node, because the planner will preferentially generate a matching
+ * tlist.
+ *
+ * ExecAssignScanType must have been called already.
+ */
+void
+ExecAssignScanProjectionInfo(ScanState *node)
+{
+ Scan *scan = (Scan *) node->ps.plan;
+
+ if (tlist_matches_tupdesc(scan->plan.targetlist,
+ scan->scanrelid,
+ node->ss_ScanTupleSlot->ttc_tupleDescriptor))
+ node->ps.ps_ProjInfo = NULL;
+ else
+ ExecAssignProjectionInfo(&node->ps);
+}
+
+static bool
+tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc)
+{
+ int numattrs = tupdesc->natts;
+ int attrno;
+
+ for (attrno = 1; attrno <= numattrs; attrno++)
+ {
+ Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
+ Var *var;
+
+ if (tlist == NIL)
+ return false; /* tlist too short */
+ var = (Var *) ((TargetEntry *) lfirst(tlist))->expr;
+ if (!var || !IsA(var, Var))
+ return false; /* tlist item not a Var */
+ Assert(var->varno == varno);
+ if (var->varattno != attrno)
+ return false; /* out of order */
+ Assert(var->vartype == att_tup->atttypid);
+ Assert(var->vartypmod == att_tup->atttypmod);
+ Assert(var->varlevelsup == 0);
+
+ tlist = lnext(tlist);
+ }
+
+ if (tlist)
+ return false; /* tlist too long */
+
+ return true;
+}