diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 19 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 47 | ||||
-rw-r--r-- | src/backend/executor/nodeSubqueryscan.c | 8 |
3 files changed, 19 insertions, 55 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index c0ca58bbb4d..01e04d3b14e 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -5350,15 +5350,24 @@ ExecCleanTargetListLength(List *targetlist) * 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. + * + * Since fields of the result tuple might be multiply referenced in higher + * plan nodes, we have to force any read/write expanded values to read-only + * status. It's a bit annoying to have to do that for every projected + * expression; in the future, consider teaching the planner to detect + * actually-multiply-referenced Vars and insert an expression node that + * would do that only where really required. */ static bool ExecTargetList(List *targetlist, + TupleDesc tupdesc, ExprContext *econtext, Datum *values, bool *isnull, ExprDoneCond *itemIsDone, ExprDoneCond *isDone) { + Form_pg_attribute *att = tupdesc->attrs; MemoryContext oldContext; ListCell *tl; bool haveDoneSets; @@ -5384,6 +5393,10 @@ ExecTargetList(List *targetlist, &isnull[resind], &itemIsDone[resind]); + values[resind] = MakeExpandedObjectReadOnly(values[resind], + isnull[resind], + att[resind]->attlen); + if (itemIsDone[resind] != ExprSingleResult) { /* We have a set-valued expression in the tlist */ @@ -5437,6 +5450,10 @@ ExecTargetList(List *targetlist, &isnull[resind], &itemIsDone[resind]); + values[resind] = MakeExpandedObjectReadOnly(values[resind], + isnull[resind], + att[resind]->attlen); + if (itemIsDone[resind] == ExprEndResult) { /* @@ -5470,6 +5487,7 @@ ExecTargetList(List *targetlist, econtext, &isnull[resind], &itemIsDone[resind]); + /* no need for MakeExpandedObjectReadOnly */ } } @@ -5595,6 +5613,7 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) if (projInfo->pi_targetlist) { if (!ExecTargetList(projInfo->pi_targetlist, + slot->tts_tupleDescriptor, econtext, slot->tts_values, slot->tts_isnull, diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index dfe56226568..2b81f60a519 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -88,7 +88,6 @@ #include "nodes/nodeFuncs.h" #include "storage/bufmgr.h" #include "utils/builtins.h" -#include "utils/expandeddatum.h" #include "utils/lsyscache.h" #include "utils/typcache.h" @@ -813,52 +812,6 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) return ExecStoreTuple(newTuple, dstslot, InvalidBuffer, true); } -/* -------------------------------- - * ExecMakeSlotContentsReadOnly - * Mark any R/W expanded datums in the slot as read-only. - * - * This is needed when a slot that might contain R/W datum references is to be - * used as input for general expression evaluation. Since the expression(s) - * might contain more than one Var referencing the same R/W datum, we could - * get wrong answers if functions acting on those Vars thought they could - * modify the expanded value in-place. - * - * For notational reasons, we return the same slot passed in. - * -------------------------------- - */ -TupleTableSlot * -ExecMakeSlotContentsReadOnly(TupleTableSlot *slot) -{ - /* - * sanity checks - */ - Assert(slot != NULL); - Assert(slot->tts_tupleDescriptor != NULL); - Assert(!slot->tts_isempty); - - /* - * If the slot contains a physical tuple, it can't contain any expanded - * datums, because we flatten those when making a physical tuple. This - * might change later; but for now, we need do nothing unless the slot is - * virtual. - */ - if (slot->tts_tuple == NULL) - { - Form_pg_attribute *att = slot->tts_tupleDescriptor->attrs; - int attnum; - - for (attnum = 0; attnum < slot->tts_nvalid; attnum++) - { - slot->tts_values[attnum] = - MakeExpandedObjectReadOnly(slot->tts_values[attnum], - slot->tts_isnull[attnum], - att[attnum]->attlen); - } - } - - return slot; -} - /* ---------------------------------------------------------------- * convenience initialization routines diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 0304b15b158..9bafc626772 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -56,15 +56,7 @@ SubqueryNext(SubqueryScanState *node) * We just return the subplan's result slot, rather than expending extra * cycles for ExecCopySlot(). (Our own ScanTupleSlot is used only for * EvalPlanQual rechecks.) - * - * We do need to mark the slot contents read-only to prevent interference - * between different functions reading the same datum from the slot. It's - * a bit hokey to do this to the subplan's slot, but should be safe - * enough. */ - if (!TupIsNull(slot)) - slot = ExecMakeSlotContentsReadOnly(slot); - return slot; } |