aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c23
-rw-r--r--src/backend/executor/execScan.c108
-rw-r--r--src/backend/executor/nodeIndexscan.c14
-rw-r--r--src/backend/executor/nodeSeqscan.c4
-rw-r--r--src/backend/executor/nodeTidscan.c14
5 files changed, 127 insertions, 36 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index e1178cd6a69..9c4b6e74819 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.199 2003/01/23 05:10:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.200 2003/02/03 15:07:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -612,9 +612,11 @@ InitPlan(QueryDesc *queryDesc)
tupType = ExecGetTupType(planstate);
/*
- * Initialize the junk filter if needed. SELECT and INSERT queries
- * need a filter if there are any junk attrs in the tlist. UPDATE and
- * DELETE always need one, since there's always a junk 'ctid'
+ * Initialize the junk filter if needed. SELECT and INSERT queries need a
+ * filter if there are any junk attrs in the tlist. INSERT and SELECT
+ * INTO also need a filter if the top plan node is a scan node that's not
+ * doing projection (else we'll be scribbling on the scan tuple!) UPDATE
+ * and DELETE always need a filter, since there's always a junk 'ctid'
* attribute present --- no need to look first.
*/
{
@@ -635,6 +637,19 @@ InitPlan(QueryDesc *queryDesc)
break;
}
}
+ if (!junk_filter_needed &&
+ (operation == CMD_INSERT || do_select_into))
+ {
+ if (IsA(planstate, SeqScanState) ||
+ IsA(planstate, IndexScanState) ||
+ IsA(planstate, TidScanState) ||
+ IsA(planstate, SubqueryScanState) ||
+ IsA(planstate, FunctionScanState))
+ {
+ if (planstate->ps_ProjInfo == NULL)
+ junk_filter_needed = true;
+ }
+ }
break;
case CMD_UPDATE:
case CMD_DELETE:
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;
+}
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index ad8680d0ff4..6d95b111c01 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.77 2003/01/12 22:01:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.78 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -583,12 +583,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
ExecInitScanTupleSlot(estate, &indexstate->ss);
/*
- * Initialize result tuple type and projection info.
- */
- ExecAssignResultTypeFromTL(&indexstate->ss.ps);
- ExecAssignProjectionInfo(&indexstate->ss.ps);
-
- /*
* Initialize index-specific scan state
*/
indexstate->iss_NumIndices = 0;
@@ -918,6 +912,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indexstate->iss_ScanDescs = scanDescs;
/*
+ * Initialize result tuple type and projection info.
+ */
+ ExecAssignResultTypeFromTL(&indexstate->ss.ps);
+ ExecAssignScanProjectionInfo(&indexstate->ss);
+
+ /*
* all done.
*/
return indexstate;
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 713dd76234d..47d2e4eb497 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.42 2003/01/12 22:01:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.43 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -232,7 +232,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate)
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ps);
- ExecAssignProjectionInfo(&scanstate->ps);
+ ExecAssignScanProjectionInfo(scanstate);
return scanstate;
}
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 3a51057f282..e1a2165709e 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.31 2003/01/12 22:01:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.32 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -384,12 +384,6 @@ ExecInitTidScan(TidScan *node, EState *estate)
ExecInitScanTupleSlot(estate, &tidstate->ss);
/*
- * Initialize result tuple type and projection info.
- */
- ExecAssignResultTypeFromTL(&tidstate->ss.ps);
- ExecAssignProjectionInfo(&tidstate->ss.ps);
-
- /*
* get the tid node information
*/
tidList = (ItemPointerData *) palloc(length(node->tideval) * sizeof(ItemPointerData));
@@ -439,6 +433,12 @@ ExecInitTidScan(TidScan *node, EState *estate)
tidstate->ss.ps.chgParam = execParam;
/*
+ * Initialize result tuple type and projection info.
+ */
+ ExecAssignResultTypeFromTL(&tidstate->ss.ps);
+ ExecAssignScanProjectionInfo(&tidstate->ss);
+
+ /*
* all done.
*/
return tidstate;