aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/execQual.c150
-rw-r--r--src/backend/executor/execUtils.c198
-rw-r--r--src/include/nodes/execnodes.h27
3 files changed, 223 insertions, 152 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index d66bf4da822..21a9eb1753c 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.243 2009/03/27 18:30:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.244 2009/04/02 22:39:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4966,6 +4966,7 @@ ExecCleanTargetListLength(List *targetlist)
* prepared to deal with sets of result tuples. Otherwise, a return
* of *isDone = ExprMultipleResult signifies a set element, and a return
* of *isDone = ExprEndResult signifies end of the set of tuple.
+ * We assume that *isDone has been initialized to ExprSingleResult by caller.
*/
static bool
ExecTargetList(List *targetlist,
@@ -4987,9 +4988,6 @@ ExecTargetList(List *targetlist,
/*
* evaluate all the expressions in the target list
*/
- if (isDone)
- *isDone = ExprSingleResult; /* until proven otherwise */
-
haveDoneSets = false; /* any exhausted set exprs in tlist? */
foreach(tl, targetlist)
@@ -5105,50 +5103,6 @@ ExecTargetList(List *targetlist,
}
/*
- * ExecVariableList
- * Evaluates a simple-Variable-list projection.
- *
- * Results are stored into the passed values and isnull arrays.
- */
-static void
-ExecVariableList(ProjectionInfo *projInfo,
- Datum *values,
- bool *isnull)
-{
- ExprContext *econtext = projInfo->pi_exprContext;
- int *varSlotOffsets = projInfo->pi_varSlotOffsets;
- int *varNumbers = projInfo->pi_varNumbers;
- int i;
-
- /*
- * Force extraction of all input values that we need.
- */
- if (projInfo->pi_lastInnerVar > 0)
- slot_getsomeattrs(econtext->ecxt_innertuple,
- projInfo->pi_lastInnerVar);
- if (projInfo->pi_lastOuterVar > 0)
- slot_getsomeattrs(econtext->ecxt_outertuple,
- projInfo->pi_lastOuterVar);
- if (projInfo->pi_lastScanVar > 0)
- slot_getsomeattrs(econtext->ecxt_scantuple,
- projInfo->pi_lastScanVar);
-
- /*
- * Assign to result by direct extraction of fields from source slots ... a
- * mite ugly, but fast ...
- */
- for (i = list_length(projInfo->pi_targetlist) - 1; i >= 0; i--)
- {
- char *slotptr = ((char *) econtext) + varSlotOffsets[i];
- TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
- int varNumber = varNumbers[i] - 1;
-
- values[i] = varSlot->tts_values[varNumber];
- isnull[i] = varSlot->tts_isnull[varNumber];
- }
-}
-
-/*
* ExecProject
*
* projects a tuple based on projection info and stores
@@ -5165,6 +5119,8 @@ TupleTableSlot *
ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
{
TupleTableSlot *slot;
+ ExprContext *econtext;
+ int numSimpleVars;
/*
* sanity checks
@@ -5175,6 +5131,11 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
* get the projection info we want
*/
slot = projInfo->pi_slot;
+ econtext = projInfo->pi_exprContext;
+
+ /* Assume single result row until proven otherwise */
+ if (isDone)
+ *isDone = ExprSingleResult;
/*
* Clear any former contents of the result slot. This makes it safe for
@@ -5184,29 +5145,84 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
ExecClearTuple(slot);
/*
- * form a new result tuple (if possible); if successful, mark the result
- * slot as containing a valid virtual tuple
+ * Force extraction of all input values that we'll need. The
+ * Var-extraction loops below depend on this, and we are also prefetching
+ * all attributes that will be referenced in the generic expressions.
+ */
+ if (projInfo->pi_lastInnerVar > 0)
+ slot_getsomeattrs(econtext->ecxt_innertuple,
+ projInfo->pi_lastInnerVar);
+ if (projInfo->pi_lastOuterVar > 0)
+ slot_getsomeattrs(econtext->ecxt_outertuple,
+ projInfo->pi_lastOuterVar);
+ if (projInfo->pi_lastScanVar > 0)
+ slot_getsomeattrs(econtext->ecxt_scantuple,
+ projInfo->pi_lastScanVar);
+
+ /*
+ * Assign simple Vars to result by direct extraction of fields from source
+ * slots ... a mite ugly, but fast ...
*/
- if (projInfo->pi_isVarList)
+ numSimpleVars = projInfo->pi_numSimpleVars;
+ if (numSimpleVars > 0)
{
- /* simple Var list: this always succeeds with one result row */
- if (isDone)
- *isDone = ExprSingleResult;
- ExecVariableList(projInfo,
- slot->tts_values,
- slot->tts_isnull);
- ExecStoreVirtualTuple(slot);
+ Datum *values = slot->tts_values;
+ bool *isnull = slot->tts_isnull;
+ int *varSlotOffsets = projInfo->pi_varSlotOffsets;
+ int *varNumbers = projInfo->pi_varNumbers;
+ int i;
+
+ if (projInfo->pi_directMap)
+ {
+ /* especially simple case where vars go to output in order */
+ for (i = 0; i < numSimpleVars; i++)
+ {
+ char *slotptr = ((char *) econtext) + varSlotOffsets[i];
+ TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
+ int varNumber = varNumbers[i] - 1;
+
+ values[i] = varSlot->tts_values[varNumber];
+ isnull[i] = varSlot->tts_isnull[varNumber];
+ }
+ }
+ else
+ {
+ /* we have to pay attention to varOutputCols[] */
+ int *varOutputCols = projInfo->pi_varOutputCols;
+
+ for (i = 0; i < numSimpleVars; i++)
+ {
+ char *slotptr = ((char *) econtext) + varSlotOffsets[i];
+ TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
+ int varNumber = varNumbers[i] - 1;
+ int varOutputCol = varOutputCols[i] - 1;
+
+ values[varOutputCol] = varSlot->tts_values[varNumber];
+ isnull[varOutputCol] = varSlot->tts_isnull[varNumber];
+ }
+ }
}
- else
+
+ /*
+ * If there are any generic expressions, evaluate them. It's possible
+ * that there are set-returning functions in such expressions; if so
+ * and we have reached the end of the set, we return the result slot,
+ * which we already marked empty.
+ */
+ if (projInfo->pi_targetlist)
{
- if (ExecTargetList(projInfo->pi_targetlist,
- projInfo->pi_exprContext,
- slot->tts_values,
- slot->tts_isnull,
- projInfo->pi_itemIsDone,
- isDone))
- ExecStoreVirtualTuple(slot);
+ if (!ExecTargetList(projInfo->pi_targetlist,
+ econtext,
+ slot->tts_values,
+ slot->tts_isnull,
+ projInfo->pi_itemIsDone,
+ isDone))
+ return slot; /* no more result rows, return empty slot */
}
- return slot;
+ /*
+ * Successfully formed a result row. Mark the result slot as containing a
+ * valid virtual tuple.
+ */
+ return ExecStoreVirtualTuple(slot);
}
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 995e1477e3a..4b3d92d48b8 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.157 2009/01/01 17:23:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.158 2009/04/02 22:39:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,6 +46,7 @@
#include "access/heapam.h"
#include "catalog/index.h"
#include "executor/execdebug.h"
+#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
@@ -66,6 +67,7 @@ int NIndexTupleInserted;
int NIndexTupleProcessed;
+static bool get_last_attnums(Node *node, ProjectionInfo *projInfo);
static void ShutdownExprContext(ExprContext *econtext);
@@ -559,121 +561,163 @@ ExecBuildProjectionInfo(List *targetList,
TupleDesc inputDesc)
{
ProjectionInfo *projInfo = makeNode(ProjectionInfo);
- int len;
- bool isVarList;
+ int len = ExecTargetListLength(targetList);
+ int *workspace;
+ int *varSlotOffsets;
+ int *varNumbers;
+ int *varOutputCols;
+ List *exprlist;
+ int numSimpleVars;
+ bool directMap;
ListCell *tl;
- len = ExecTargetListLength(targetList);
-
- projInfo->pi_targetlist = targetList;
projInfo->pi_exprContext = econtext;
projInfo->pi_slot = slot;
+ /* since these are all int arrays, we need do just one palloc */
+ workspace = (int *) palloc(len * 3 * sizeof(int));
+ projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
+ projInfo->pi_varNumbers = varNumbers = workspace + len;
+ projInfo->pi_varOutputCols = varOutputCols = workspace + len * 2;
+ projInfo->pi_lastInnerVar = 0;
+ projInfo->pi_lastOuterVar = 0;
+ projInfo->pi_lastScanVar = 0;
/*
- * Determine whether the target list consists entirely of simple Var
- * references (ie, references to non-system attributes) that match the
- * input. If so, we can use the simpler ExecVariableList instead of
- * ExecTargetList. (Note: if there is a type mismatch then ExecEvalVar
- * will probably throw an error at runtime, but we leave that to it.)
+ * We separate the target list elements into simple Var references and
+ * expressions which require the full ExecTargetList machinery. To be
+ * a simple Var, a Var has to be a user attribute and not mismatch the
+ * inputDesc. (Note: if there is a type mismatch then ExecEvalVar will
+ * probably throw an error at runtime, but we leave that to it.)
*/
- isVarList = true;
+ exprlist = NIL;
+ numSimpleVars = 0;
+ directMap = true;
foreach(tl, targetList)
{
GenericExprState *gstate = (GenericExprState *) lfirst(tl);
Var *variable = (Var *) gstate->arg->expr;
- Form_pg_attribute attr;
+ bool isSimpleVar = false;
- if (variable == NULL ||
- !IsA(variable, Var) ||
- variable->varattno <= 0)
- {
- isVarList = false;
- break;
- }
- if (!inputDesc)
- continue; /* can't check type, assume OK */
- if (variable->varattno > inputDesc->natts)
+ if (variable != NULL &&
+ IsA(variable, Var) &&
+ variable->varattno > 0)
{
- isVarList = false;
- break;
- }
- attr = inputDesc->attrs[variable->varattno - 1];
- if (attr->attisdropped || variable->vartype != attr->atttypid)
- {
- isVarList = false;
- break;
- }
- }
- projInfo->pi_isVarList = isVarList;
-
- if (isVarList)
- {
- int *varSlotOffsets;
- int *varNumbers;
- AttrNumber lastInnerVar = 0;
- AttrNumber lastOuterVar = 0;
- AttrNumber lastScanVar = 0;
+ if (!inputDesc)
+ isSimpleVar = true; /* can't check type, assume OK */
+ else if (variable->varattno <= inputDesc->natts)
+ {
+ Form_pg_attribute attr;
- projInfo->pi_itemIsDone = NULL; /* not needed */
- projInfo->pi_varSlotOffsets = varSlotOffsets = (int *)
- palloc0(len * sizeof(int));
- projInfo->pi_varNumbers = varNumbers = (int *)
- palloc0(len * sizeof(int));
+ attr = inputDesc->attrs[variable->varattno - 1];
+ if (!attr->attisdropped && variable->vartype == attr->atttypid)
+ isSimpleVar = true;
+ }
+ }
- /*
- * Set up the data needed by ExecVariableList. The slots in which the
- * variables can be found at runtime are denoted by the offsets of
- * their slot pointers within the econtext. This rather grotty
- * representation is needed because the caller may not have given us
- * the real econtext yet (see hacks in nodeSubplan.c).
- */
- foreach(tl, targetList)
+ if (isSimpleVar)
{
- GenericExprState *gstate = (GenericExprState *) lfirst(tl);
- Var *variable = (Var *) gstate->arg->expr;
- AttrNumber attnum = variable->varattno;
TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
- AttrNumber resind = tle->resno - 1;
+ AttrNumber attnum = variable->varattno;
- Assert(resind >= 0 && resind < len);
- varNumbers[resind] = attnum;
+ varNumbers[numSimpleVars] = attnum;
+ varOutputCols[numSimpleVars] = tle->resno;
+ if (tle->resno != numSimpleVars+1)
+ directMap = false;
switch (variable->varno)
{
case INNER:
- varSlotOffsets[resind] = offsetof(ExprContext,
- ecxt_innertuple);
- lastInnerVar = Max(lastInnerVar, attnum);
+ varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
+ ecxt_innertuple);
+ if (projInfo->pi_lastInnerVar < attnum)
+ projInfo->pi_lastInnerVar = attnum;
break;
case OUTER:
- varSlotOffsets[resind] = offsetof(ExprContext,
- ecxt_outertuple);
- lastOuterVar = Max(lastOuterVar, attnum);
+ varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
+ ecxt_outertuple);
+ if (projInfo->pi_lastOuterVar < attnum)
+ projInfo->pi_lastOuterVar = attnum;
break;
default:
- varSlotOffsets[resind] = offsetof(ExprContext,
- ecxt_scantuple);
- lastScanVar = Max(lastScanVar, attnum);
+ varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
+ ecxt_scantuple);
+ if (projInfo->pi_lastScanVar < attnum)
+ projInfo->pi_lastScanVar = attnum;
break;
}
+ numSimpleVars++;
+ }
+ else
+ {
+ /* Not a simple variable, add it to generic targetlist */
+ exprlist = lappend(exprlist, gstate);
+ /* Examine expr to include contained Vars in lastXXXVar counts */
+ get_last_attnums((Node *) variable, projInfo);
}
- projInfo->pi_lastInnerVar = lastInnerVar;
- projInfo->pi_lastOuterVar = lastOuterVar;
- projInfo->pi_lastScanVar = lastScanVar;
}
+ projInfo->pi_targetlist = exprlist;
+ projInfo->pi_numSimpleVars = numSimpleVars;
+ projInfo->pi_directMap = directMap;
+
+ if (exprlist == NIL)
+ projInfo->pi_itemIsDone = NULL; /* not needed */
else
- {
projInfo->pi_itemIsDone = (ExprDoneCond *)
palloc(len * sizeof(ExprDoneCond));
- projInfo->pi_varSlotOffsets = NULL;
- projInfo->pi_varNumbers = NULL;
- }
return projInfo;
}
+/*
+ * get_last_attnums: expression walker for ExecBuildProjectionInfo
+ *
+ * Update the lastXXXVar counts to be at least as large as the largest
+ * attribute numbers found in the expression
+ */
+static bool
+get_last_attnums(Node *node, ProjectionInfo *projInfo)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Var))
+ {
+ Var *variable = (Var *) node;
+ AttrNumber attnum = variable->varattno;
+
+ switch (variable->varno)
+ {
+ case INNER:
+ if (projInfo->pi_lastInnerVar < attnum)
+ projInfo->pi_lastInnerVar = attnum;
+ break;
+
+ case OUTER:
+ if (projInfo->pi_lastOuterVar < attnum)
+ projInfo->pi_lastOuterVar = attnum;
+ break;
+
+ default:
+ if (projInfo->pi_lastScanVar < attnum)
+ projInfo->pi_lastScanVar = attnum;
+ break;
+ }
+ return false;
+ }
+ /*
+ * Don't examine the arguments of Aggrefs or WindowFuncs, because those
+ * do not represent expressions to be evaluated within the overall
+ * targetlist's econtext.
+ */
+ if (IsA(node, Aggref))
+ return false;
+ if (IsA(node, WindowFunc))
+ return false;
+ return expression_tree_walker(node, get_last_attnums,
+ (void *) projInfo);
+}
+
/* ----------------
* ExecAssignProjectionInfo
*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 996efa8f87d..cb293a0be55 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.202 2009/03/21 00:04:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.203 2009/04/02 22:39:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -201,16 +201,25 @@ typedef struct ReturnSetInfo
*
* The planner very often produces tlists that consist entirely of
* simple Var references (lower levels of a plan tree almost always
- * look like that). So we have an optimization to handle that case
- * with minimum overhead.
+ * look like that). And top-level tlists are often mostly Vars too.
+ * We therefore optimize execution of simple-Var tlist entries.
+ * The pi_targetlist list actually contains only the tlist entries that
+ * aren't simple Vars, while those that are Vars are processed using the
+ * varSlotOffsets/varNumbers/varOutputCols arrays.
*
- * targetlist target list for projection
+ * The lastXXXVar fields are used to optimize fetching of fields from
+ * input tuples: they let us do a slot_getsomeattrs() call to ensure
+ * that all needed attributes are extracted in one pass.
+ *
+ * targetlist target list for projection (non-Var expressions only)
* exprContext expression context in which to evaluate targetlist
* slot slot to place projection result in
- * itemIsDone workspace for ExecProject
- * isVarList TRUE if simple-Var-list optimization applies
+ * itemIsDone workspace array for ExecProject
+ * directMap true if varOutputCols[] is an identity map
+ * numSimpleVars number of simple Vars found in original tlist
* varSlotOffsets array indicating which slot each simple Var is from
- * varNumbers array indicating attr numbers of simple Vars
+ * varNumbers array containing input attr numbers of simple Vars
+ * varOutputCols array containing output attr numbers of simple Vars
* lastInnerVar highest attnum from inner tuple slot (0 if none)
* lastOuterVar highest attnum from outer tuple slot (0 if none)
* lastScanVar highest attnum from scan tuple slot (0 if none)
@@ -223,9 +232,11 @@ typedef struct ProjectionInfo
ExprContext *pi_exprContext;
TupleTableSlot *pi_slot;
ExprDoneCond *pi_itemIsDone;
- bool pi_isVarList;
+ bool pi_directMap;
+ int pi_numSimpleVars;
int *pi_varSlotOffsets;
int *pi_varNumbers;
+ int *pi_varOutputCols;
int pi_lastInnerVar;
int pi_lastOuterVar;
int pi_lastScanVar;