Index: src/backend/executor/execQual.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/executor/execQual.c,v retrieving revision 1.243 diff -c -r1.243 execQual.c *** src/backend/executor/execQual.c 27 Mar 2009 18:30:21 -0000 1.243 --- src/backend/executor/execQual.c 1 Apr 2009 21:44:07 -0000 *************** *** 4987,4995 **** /* * 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) --- 4987,4992 ---- *************** *** 5116,5150 **** 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]; } } --- 5113,5159 ---- bool *isnull) { ExprContext *econtext = projInfo->pi_exprContext; /* ! * Assign simple Vars to result by direct extraction of fields from source ! * slots ... a mite ugly, but fast ... */ ! if (projInfo->pi_directMap) ! { ! /* especially simple case where vars go to output in order */ ! int *varSlotOffsets = projInfo->pi_varSlotOffsets; ! int *varNumbers = projInfo->pi_varNumbers; ! int numSimpleVars = projInfo->pi_numSimpleVars; ! int i; ! 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 { ! int *varSlotOffsets = projInfo->pi_varSlotOffsets; ! int *varNumbers = projInfo->pi_varNumbers; ! int *varOutputCols = projInfo->pi_varOutputCols; ! int numSimpleVars = projInfo->pi_numSimpleVars; ! int i; ! ! 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]; ! } } } *************** *** 5165,5170 **** --- 5174,5180 ---- ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) { TupleTableSlot *slot; + ExprContext *econtext = projInfo->pi_exprContext; /* * sanity checks *************** *** 5184,5212 **** ExecClearTuple(slot); /* * form a new result tuple (if possible); if successful, mark the result * slot as containing a valid virtual tuple */ ! if (projInfo->pi_isVarList) { ! /* simple Var list: this always succeeds with one result row */ ! if (isDone) ! *isDone = ExprSingleResult; ! ExecVariableList(projInfo, ! slot->tts_values, ! slot->tts_isnull); ! ExecStoreVirtualTuple(slot); ! } ! else ! { ! if (ExecTargetList(projInfo->pi_targetlist, ! projInfo->pi_exprContext, ! slot->tts_values, ! slot->tts_isnull, ! projInfo->pi_itemIsDone, ! isDone)) ! ExecStoreVirtualTuple(slot); } return slot; } --- 5194,5235 ---- ExecClearTuple(slot); /* + * Force extraction of all input values that we'll 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); + + ExecVariableList(projInfo, + slot->tts_values, + slot->tts_isnull); + + /* Assume single result row until proven otherwise */ + if (isDone) + *isDone = ExprSingleResult; + + /* * form a new result tuple (if possible); if successful, mark the result * slot as containing a valid virtual tuple */ ! if (projInfo->pi_targetlist) { ! if (!ExecTargetList(projInfo->pi_targetlist, ! projInfo->pi_exprContext, ! slot->tts_values, ! slot->tts_isnull, ! projInfo->pi_itemIsDone, ! isDone)) ! return slot; /* no result rows, return empty slot */ } + ExecStoreVirtualTuple(slot); + return slot; } Index: src/backend/executor/execUtils.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/executor/execUtils.c,v retrieving revision 1.157 diff -c -r1.157 execUtils.c *** src/backend/executor/execUtils.c 1 Jan 2009 17:23:41 -0000 1.157 --- src/backend/executor/execUtils.c 1 Apr 2009 21:44:07 -0000 *************** *** 46,51 **** --- 46,52 ---- #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,71 **** --- 67,73 ---- int NIndexTupleProcessed; + static bool get_last_attnums(Node *node, ProjectionInfo *projInfo); static void ShutdownExprContext(ExprContext *econtext); *************** *** 559,679 **** TupleDesc inputDesc) { ProjectionInfo *projInfo = makeNode(ProjectionInfo); ! int len; ! bool isVarList; ListCell *tl; - len = ExecTargetListLength(targetList); - - projInfo->pi_targetlist = targetList; projInfo->pi_exprContext = econtext; projInfo->pi_slot = slot; ! ! /* ! * 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.) ! */ ! isVarList = true; foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; ! Form_pg_attribute attr; ! 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) { ! 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; ! projInfo->pi_itemIsDone = NULL; /* not needed */ ! projInfo->pi_varSlotOffsets = varSlotOffsets = (int *) ! palloc0(len * sizeof(int)); ! projInfo->pi_varNumbers = varNumbers = (int *) ! palloc0(len * sizeof(int)); ! /* ! * 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) { - 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; ! Assert(resind >= 0 && resind < len); ! varNumbers[resind] = attnum; switch (variable->varno) { case INNER: ! varSlotOffsets[resind] = offsetof(ExprContext, ! ecxt_innertuple); ! lastInnerVar = Max(lastInnerVar, attnum); break; case OUTER: ! varSlotOffsets[resind] = offsetof(ExprContext, ! ecxt_outertuple); ! lastOuterVar = Max(lastOuterVar, attnum); break; default: ! varSlotOffsets[resind] = offsetof(ExprContext, ! ecxt_scantuple); ! lastScanVar = Max(lastScanVar, attnum); break; } } - projInfo->pi_lastInnerVar = lastInnerVar; - projInfo->pi_lastOuterVar = lastOuterVar; - projInfo->pi_lastScanVar = lastScanVar; } else - { projInfo->pi_itemIsDone = (ExprDoneCond *) palloc(len * sizeof(ExprDoneCond)); - projInfo->pi_varSlotOffsets = NULL; - projInfo->pi_varNumbers = NULL; - } return projInfo; } /* ---------------- * ExecAssignProjectionInfo * --- 561,716 ---- TupleDesc inputDesc) { ProjectionInfo *projInfo = makeNode(ProjectionInfo); ! int len = ExecTargetListLength(targetList); ! int *varSlotOffsets; ! int *varNumbers; ! int *varOutputCols; ! List *exprlist; ! int numSimpleVars; ! bool directMap; ListCell *tl; projInfo->pi_exprContext = econtext; projInfo->pi_slot = slot; ! projInfo->pi_varSlotOffsets = varSlotOffsets = (int *) ! palloc(len * sizeof(int)); ! projInfo->pi_varNumbers = varNumbers = (int *) ! palloc(len * sizeof(int)); ! projInfo->pi_varOutputCols = varOutputCols = (int *) ! palloc(len * sizeof(int)); ! projInfo->pi_lastInnerVar = 0; ! projInfo->pi_lastOuterVar = 0; ! projInfo->pi_lastScanVar = 0; ! ! /* ! * We separate the target list 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.) ! */ ! exprlist = NIL; ! numSimpleVars = 0; ! directMap = true; foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; ! bool isSimpleVar = false; ! if (variable != NULL && ! IsA(variable, Var) && ! variable->varattno > 0) { ! if (!inputDesc) ! isSimpleVar = true; /* can't check type, assume OK */ ! else if (variable->varattno <= inputDesc->natts) ! { ! Form_pg_attribute attr; ! attr = inputDesc->attrs[variable->varattno - 1]; ! if (!attr->attisdropped && variable->vartype == attr->atttypid) ! isSimpleVar = true; ! } ! } ! if (isSimpleVar) { TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; ! AttrNumber attnum = variable->varattno; ! varNumbers[numSimpleVars] = attnum; ! varOutputCols[numSimpleVars] = tle->resno; ! if (tle->resno != numSimpleVars+1) ! directMap = false; switch (variable->varno) { case INNER: ! varSlotOffsets[numSimpleVars] = offsetof(ExprContext, ! ecxt_innertuple); ! if (projInfo->pi_lastInnerVar < attnum) ! projInfo->pi_lastInnerVar = attnum; break; case OUTER: ! varSlotOffsets[numSimpleVars] = offsetof(ExprContext, ! ecxt_outertuple); ! if (projInfo->pi_lastOuterVar < attnum) ! projInfo->pi_lastOuterVar = attnum; break; default: ! 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); + get_last_attnums((Node *) variable, projInfo); } } + 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)); return projInfo; } + 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 with respect to 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 * Index: src/include/nodes/execnodes.h =================================================================== RCS file: /cvsroot/pgsql/src/include/nodes/execnodes.h,v retrieving revision 1.202 diff -c -r1.202 execnodes.h *** src/include/nodes/execnodes.h 21 Mar 2009 00:04:40 -0000 1.202 --- src/include/nodes/execnodes.h 1 Apr 2009 21:44:07 -0000 *************** *** 201,216 **** * * 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. * ! * targetlist target list for projection * 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 * varSlotOffsets array indicating which slot each simple Var is from ! * varNumbers array indicating 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) --- 201,225 ---- * * The planner very often produces tlists that consist entirely of * simple Var references (lower levels of a plan tree almost always ! * 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, and the Vars are processed using the ! * varSlotOffsets/varNumbers/varOutputCols arrays. ! * ! * 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 fields 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 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 input attr numbers of simple Vars ! * varOutputCols array indicating 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,231 **** ExprContext *pi_exprContext; TupleTableSlot *pi_slot; ExprDoneCond *pi_itemIsDone; ! bool pi_isVarList; int *pi_varSlotOffsets; int *pi_varNumbers; int pi_lastInnerVar; int pi_lastOuterVar; int pi_lastScanVar; --- 232,242 ---- ExprContext *pi_exprContext; TupleTableSlot *pi_slot; ExprDoneCond *pi_itemIsDone; ! bool pi_directMap; ! int pi_numSimpleVars; int *pi_varSlotOffsets; int *pi_varNumbers; + int *pi_varOutputCols; int pi_lastInnerVar; int pi_lastOuterVar; int pi_lastScanVar;