diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 23 | ||||
-rw-r--r-- | src/backend/executor/execScan.c | 108 | ||||
-rw-r--r-- | src/backend/executor/nodeIndexscan.c | 14 | ||||
-rw-r--r-- | src/backend/executor/nodeSeqscan.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeTidscan.c | 14 |
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; |