aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c19
-rw-r--r--src/backend/executor/execTuples.c47
-rw-r--r--src/backend/executor/nodeSubqueryscan.c8
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;
}