diff options
Diffstat (limited to 'src/backend/executor/execUtils.c')
-rw-r--r-- | src/backend/executor/execUtils.c | 198 |
1 files changed, 121 insertions, 77 deletions
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 * |