aboutsummaryrefslogtreecommitdiff
path: root/src/include/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-03-30 04:08:43 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-03-30 04:08:43 +0000
commit793d5662e88e65b798bad5cbc7046ce05cec7ac1 (patch)
tree8c7924e74deb9103d0c032e91565154f070728fb /src/include/executor
parenta576994e72113290a621cfb69d4e756bd01f39af (diff)
downloadpostgresql-793d5662e88e65b798bad5cbc7046ce05cec7ac1.tar.gz
postgresql-793d5662e88e65b798bad5cbc7046ce05cec7ac1.zip
Fix an oversight in the support for storing/retrieving "minimal tuples" in
TupleTableSlots. We have functions for retrieving a minimal tuple from a slot after storing a regular tuple in it, or vice versa; but these were implemented by converting the internal storage from one format to the other. The problem with that is it invalidates any pass-by-reference Datums that were already fetched from the slot, since they'll be pointing into the just-freed version of the tuple. The known problem cases involve fetching both a whole-row variable and a pass-by-reference value from a slot that is fed from a tuplestore or tuplesort object. The added regression tests illustrate some simple cases, but there may be other failure scenarios traceable to the same bug. Note that the added tests probably only fail on unpatched code if it's built with --enable-cassert; otherwise the bug leads to fetching from freed memory, which will not have been overwritten without additional conditions. Fix by allowing a slot to contain both formats simultaneously; which turns out not to complicate the logic much at all, if anything it seems less contorted than before. Back-patch to 8.2, where minimal tuples were introduced.
Diffstat (limited to 'src/include/executor')
-rw-r--r--src/include/executor/tuptable.h32
1 files changed, 22 insertions, 10 deletions
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index 1cd624b0859..d712106c524 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.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/executor/tuptable.h,v 1.40 2009/01/01 17:23:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.41 2009/03/30 04:08:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,6 +49,14 @@
* else need to be "materialized" into physical tuples. Note also that a
* virtual tuple does not have any "system columns".
*
+ * It is also possible for a TupleTableSlot to hold both physical and minimal
+ * copies of a tuple. This is done when the slot is requested to provide
+ * the format other than the one it currently holds. (Originally we attempted
+ * to handle such requests by replacing one format with the other, but that
+ * had the fatal defect of invalidating any pass-by-reference Datums pointing
+ * into the existing slot contents.) Both copies must contain identical data
+ * payloads when this is the case.
+ *
* The Datum/isnull arrays of a TupleTableSlot serve double duty. When the
* slot contains a virtual tuple, they are the authoritative data. When the
* slot contains a physical tuple, the arrays contain data extracted from
@@ -91,12 +99,12 @@
*
* tts_mintuple must always be NULL if the slot does not hold a "minimal"
* tuple. When it does, tts_mintuple points to the actual MinimalTupleData
- * object (the thing to be pfree'd if tts_shouldFree is true). In this case
- * tts_tuple points at tts_minhdr and the fields of that are set correctly
+ * object (the thing to be pfree'd if tts_shouldFreeMin is true). If the slot
+ * has only a minimal and not also a regular physical tuple, then tts_tuple
+ * points at tts_minhdr and the fields of that struct are set correctly
* for access to the minimal tuple; in particular, tts_minhdr.t_data points
- * MINIMAL_TUPLE_OFFSET bytes before tts_mintuple. (tts_mintuple is therefore
- * redundant, but for code simplicity we store it explicitly anyway.) This
- * case otherwise behaves identically to the regular-physical-tuple case.
+ * MINIMAL_TUPLE_OFFSET bytes before tts_mintuple. This allows column
+ * extraction to treat the case identically to regular physical tuples.
*
* tts_slow/tts_off are saved state for slot_deform_tuple, and should not
* be touched by any other code.
@@ -106,20 +114,24 @@ typedef struct TupleTableSlot
{
NodeTag type; /* vestigial ... allows IsA tests */
bool tts_isempty; /* true = slot is empty */
- bool tts_shouldFree; /* should pfree tuple? */
+ bool tts_shouldFree; /* should pfree tts_tuple? */
+ bool tts_shouldFreeMin; /* should pfree tts_mintuple? */
bool tts_slow; /* saved state for slot_deform_tuple */
- HeapTuple tts_tuple; /* physical tuple, or NULL if none */
+ HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
MemoryContext tts_mcxt; /* slot itself is in this context */
Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
int tts_nvalid; /* # of valid values in tts_values */
Datum *tts_values; /* current per-attribute values */
bool *tts_isnull; /* current per-attribute isnull flags */
- MinimalTuple tts_mintuple; /* set if it's a minimal tuple, else NULL */
- HeapTupleData tts_minhdr; /* workspace if it's a minimal tuple */
+ MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
+ HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
long tts_off; /* saved state for slot_deform_tuple */
} TupleTableSlot;
+#define TTS_HAS_PHYSICAL_TUPLE(slot) \
+ ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
+
/*
* Tuple table data structure: an array of TupleTableSlots.
*/