aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/common/heaptuple.c178
-rw-r--r--src/backend/commands/portalcmds.c13
-rw-r--r--src/backend/executor/execTuples.c139
-rw-r--r--src/backend/executor/nodeFunctionscan.c15
-rw-r--r--src/backend/executor/nodeMaterial.c44
-rw-r--r--src/backend/executor/tstoreReceiver.c4
-rw-r--r--src/backend/tcop/pquery.c12
-rw-r--r--src/backend/utils/sort/tuplestore.c130
8 files changed, 438 insertions, 97 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 9d77ab2779d..7ec314379ba 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.106 2006/03/05 15:58:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.107 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1295,6 +1295,8 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
{
if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract system attribute from virtual tuple");
+ if (slot->tts_mintuple) /* internal error */
+ elog(ERROR, "cannot extract system attribute from minimal tuple");
return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
}
@@ -1479,6 +1481,8 @@ slot_attisnull(TupleTableSlot *slot, int attnum)
{
if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract system attribute from virtual tuple");
+ if (slot->tts_mintuple) /* internal error */
+ elog(ERROR, "cannot extract system attribute from minimal tuple");
return heap_attisnull(tuple, attnum);
}
@@ -1505,9 +1509,8 @@ slot_attisnull(TupleTableSlot *slot, int attnum)
return heap_attisnull(tuple, attnum);
}
-/* ----------------
- * heap_freetuple
- * ----------------
+/*
+ * heap_freetuple
*/
void
heap_freetuple(HeapTuple htup)
@@ -1516,6 +1519,173 @@ heap_freetuple(HeapTuple htup)
}
+/*
+ * heap_form_minimal_tuple
+ * construct a MinimalTuple from the given values[] and isnull[] arrays,
+ * which are of the length indicated by tupleDescriptor->natts
+ *
+ * This is exactly like heap_form_tuple() except that the result is a
+ * "minimal" tuple lacking a HeapTupleData header as well as room for system
+ * columns.
+ *
+ * The result is allocated in the current memory context.
+ */
+MinimalTuple
+heap_form_minimal_tuple(TupleDesc tupleDescriptor,
+ Datum *values,
+ bool *isnull)
+{
+ MinimalTuple tuple; /* return tuple */
+ unsigned long len;
+ int hoff;
+ bool hasnull = false;
+ Form_pg_attribute *att = tupleDescriptor->attrs;
+ int numberOfAttributes = tupleDescriptor->natts;
+ int i;
+
+ if (numberOfAttributes > MaxTupleAttributeNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_COLUMNS),
+ errmsg("number of columns (%d) exceeds limit (%d)",
+ numberOfAttributes, MaxTupleAttributeNumber)));
+
+ /*
+ * Check for nulls and embedded tuples; expand any toasted attributes in
+ * embedded tuples. This preserves the invariant that toasting can only
+ * go one level deep.
+ *
+ * We can skip calling toast_flatten_tuple_attribute() if the attribute
+ * couldn't possibly be of composite type. All composite datums are
+ * varlena and have alignment 'd'; furthermore they aren't arrays. Also,
+ * if an attribute is already toasted, it must have been sent to disk
+ * already and so cannot contain toasted attributes.
+ */
+ for (i = 0; i < numberOfAttributes; i++)
+ {
+ if (isnull[i])
+ hasnull = true;
+ else if (att[i]->attlen == -1 &&
+ att[i]->attalign == 'd' &&
+ att[i]->attndims == 0 &&
+ !VARATT_IS_EXTENDED(values[i]))
+ {
+ values[i] = toast_flatten_tuple_attribute(values[i],
+ att[i]->atttypid,
+ att[i]->atttypmod);
+ }
+ }
+
+ /*
+ * Determine total space needed
+ */
+ len = offsetof(MinimalTupleData, t_bits);
+
+ if (hasnull)
+ len += BITMAPLEN(numberOfAttributes);
+
+ if (tupleDescriptor->tdhasoid)
+ len += sizeof(Oid);
+
+ hoff = len = MAXALIGN(len); /* align user data safely */
+
+ len += heap_compute_data_size(tupleDescriptor, values, isnull);
+
+ /*
+ * Allocate and zero the space needed.
+ */
+ tuple = (MinimalTuple) palloc0(len);
+
+ /*
+ * And fill in the information.
+ */
+ tuple->t_len = len;
+ tuple->t_natts = numberOfAttributes;
+ tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
+
+ if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
+ tuple->t_infomask = HEAP_HASOID;
+
+ heap_fill_tuple(tupleDescriptor,
+ values,
+ isnull,
+ (char *) tuple + hoff,
+ &tuple->t_infomask,
+ (hasnull ? tuple->t_bits : NULL));
+
+ return tuple;
+}
+
+/*
+ * heap_free_minimal_tuple
+ */
+void
+heap_free_minimal_tuple(MinimalTuple mtup)
+{
+ pfree(mtup);
+}
+
+/*
+ * heap_copy_minimal_tuple
+ * copy a MinimalTuple
+ *
+ * The result is allocated in the current memory context.
+ */
+MinimalTuple
+heap_copy_minimal_tuple(MinimalTuple mtup)
+{
+ MinimalTuple result;
+
+ result = (MinimalTuple) palloc(mtup->t_len);
+ memcpy(result, mtup, mtup->t_len);
+ return result;
+}
+
+/*
+ * heap_tuple_from_minimal_tuple
+ * create a HeapTuple by copying from a MinimalTuple;
+ * system columns are filled with zeroes
+ *
+ * The result is allocated in the current memory context.
+ * The HeapTuple struct, tuple header, and tuple data are all allocated
+ * as a single palloc() block.
+ */
+HeapTuple
+heap_tuple_from_minimal_tuple(MinimalTuple mtup)
+{
+ HeapTuple result;
+ uint32 len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
+
+ result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
+ result->t_len = len;
+ ItemPointerSetInvalid(&(result->t_self));
+ result->t_tableOid = InvalidOid;
+ result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
+ memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
+ memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_natts));
+ return result;
+}
+
+/*
+ * minimal_tuple_from_heap_tuple
+ * create a MinimalTuple by copying from a HeapTuple
+ *
+ * The result is allocated in the current memory context.
+ */
+MinimalTuple
+minimal_tuple_from_heap_tuple(HeapTuple htup)
+{
+ MinimalTuple result;
+ uint32 len;
+
+ Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
+ len = htup->t_len - MINIMAL_TUPLE_OFFSET;
+ result = (MinimalTuple) palloc(len);
+ memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
+ result->t_len = len;
+ return result;
+}
+
+
/* ----------------
* heap_addheader
*
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 403b5c70645..c4c55c9cf3c 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.46 2006/03/05 15:58:24 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.47 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -411,17 +411,8 @@ PersistHoldablePortal(Portal portal)
for (store_pos = 0; store_pos < portal->portalPos; store_pos++)
{
- HeapTuple tup;
- bool should_free;
-
- tup = tuplestore_gettuple(portal->holdStore, true,
- &should_free);
-
- if (tup == NULL)
+ if (!tuplestore_advance(portal->holdStore, true))
elog(ERROR, "unexpected end of tuple stream");
-
- if (should_free)
- pfree(tup);
}
}
}
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 971822525f0..f03d738619d 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.94 2006/06/16 18:42:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.95 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,6 +25,8 @@
* TABLE CREATE/DELETE
* ExecCreateTupleTable - create a new tuple table
* ExecDropTupleTable - destroy a table
+ * MakeSingleTupleTableSlot - make a single-slot table
+ * ExecDropSingleTupleTableSlot - destroy same
*
* SLOT RESERVATION
* ExecAllocTableSlot - find an available slot in the table
@@ -32,9 +34,11 @@
* SLOT ACCESSORS
* ExecSetSlotDescriptor - set a slot's tuple descriptor
* ExecStoreTuple - store a physical tuple in the slot
+ * ExecStoreMinimalTuple - store a minimal physical tuple in the slot
* ExecClearTuple - clear contents of a slot
* ExecStoreVirtualTuple - mark slot as containing a virtual tuple
* ExecCopySlotTuple - build a physical tuple from a slot
+ * ExecCopySlotMinimalTuple - build a minimal physical tuple from a slot
* ExecMaterializeSlot - convert virtual to physical storage
* ExecCopySlot - copy one slot's contents to another
*
@@ -150,6 +154,7 @@ ExecCreateTupleTable(int tableSize)
slot->tts_nvalid = 0;
slot->tts_values = NULL;
slot->tts_isnull = NULL;
+ slot->tts_mintuple = NULL;
}
return newtable;
@@ -227,6 +232,7 @@ MakeSingleTupleTableSlot(TupleDesc tupdesc)
slot->tts_nvalid = 0;
slot->tts_values = NULL;
slot->tts_isnull = NULL;
+ slot->tts_mintuple = NULL;
ExecSetSlotDescriptor(slot, tupdesc);
@@ -405,7 +411,12 @@ ExecStoreTuple(HeapTuple tuple,
* Free any old physical tuple belonging to the slot.
*/
if (slot->tts_shouldFree)
- heap_freetuple(slot->tts_tuple);
+ {
+ if (slot->tts_mintuple)
+ heap_free_minimal_tuple(slot->tts_mintuple);
+ else
+ heap_freetuple(slot->tts_tuple);
+ }
/*
* Store the new tuple into the specified slot.
@@ -413,6 +424,7 @@ ExecStoreTuple(HeapTuple tuple,
slot->tts_isempty = false;
slot->tts_shouldFree = shouldFree;
slot->tts_tuple = tuple;
+ slot->tts_mintuple = NULL;
/* Mark extracted state invalid */
slot->tts_nvalid = 0;
@@ -439,6 +451,63 @@ ExecStoreTuple(HeapTuple tuple,
}
/* --------------------------------
+ * ExecStoreMinimalTuple
+ *
+ * Like ExecStoreTuple, but insert a "minimal" tuple into the slot.
+ *
+ * No 'buffer' parameter since minimal tuples are never stored in relations.
+ * --------------------------------
+ */
+TupleTableSlot *
+ExecStoreMinimalTuple(MinimalTuple mtup,
+ TupleTableSlot *slot,
+ bool shouldFree)
+{
+ /*
+ * sanity checks
+ */
+ Assert(mtup != NULL);
+ Assert(slot != NULL);
+ Assert(slot->tts_tupleDescriptor != NULL);
+
+ /*
+ * Free any old physical tuple belonging to the slot.
+ */
+ if (slot->tts_shouldFree)
+ {
+ if (slot->tts_mintuple)
+ heap_free_minimal_tuple(slot->tts_mintuple);
+ else
+ heap_freetuple(slot->tts_tuple);
+ }
+
+ /*
+ * Drop the pin on the referenced buffer, if there is one.
+ */
+ if (BufferIsValid(slot->tts_buffer))
+ ReleaseBuffer(slot->tts_buffer);
+
+ slot->tts_buffer = InvalidBuffer;
+
+ /*
+ * Store the new tuple into the specified slot.
+ */
+ slot->tts_isempty = false;
+ slot->tts_shouldFree = shouldFree;
+ slot->tts_tuple = &slot->tts_minhdr;
+ slot->tts_mintuple = mtup;
+
+ slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
+ slot->tts_minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
+ /* no need to set t_self or t_tableOid since we won't allow access */
+
+ /* Mark extracted state invalid */
+ slot->tts_nvalid = 0;
+
+ return slot;
+}
+
+/* --------------------------------
* ExecClearTuple
*
* This function is used to clear out a slot in the tuple table.
@@ -458,9 +527,15 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
* Free the old physical tuple if necessary.
*/
if (slot->tts_shouldFree)
- heap_freetuple(slot->tts_tuple);
+ {
+ if (slot->tts_mintuple)
+ heap_free_minimal_tuple(slot->tts_mintuple);
+ else
+ heap_freetuple(slot->tts_tuple);
+ }
slot->tts_tuple = NULL;
+ slot->tts_mintuple = NULL;
slot->tts_shouldFree = false;
/*
@@ -540,10 +615,10 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
/* --------------------------------
* ExecCopySlotTuple
- * Obtain a copy of a slot's physical tuple. The copy is
+ * Obtain a copy of a slot's regular physical tuple. The copy is
* palloc'd in the current memory context.
*
- * This works even if the slot contains a virtual tuple;
+ * This works even if the slot contains a virtual or minimal tuple;
* however the "system columns" of the result will not be meaningful.
* --------------------------------
*/
@@ -560,7 +635,12 @@ ExecCopySlotTuple(TupleTableSlot *slot)
* If we have a physical tuple then just copy it.
*/
if (slot->tts_tuple)
- return heap_copytuple(slot->tts_tuple);
+ {
+ if (slot->tts_mintuple)
+ return heap_tuple_from_minimal_tuple(slot->tts_mintuple);
+ else
+ return heap_copytuple(slot->tts_tuple);
+ }
/*
* Otherwise we need to build a tuple from the Datum array.
@@ -571,11 +651,46 @@ ExecCopySlotTuple(TupleTableSlot *slot)
}
/* --------------------------------
+ * ExecCopySlotMinimalTuple
+ * Obtain a copy of a slot's minimal physical tuple. The copy is
+ * palloc'd in the current memory context.
+ * --------------------------------
+ */
+MinimalTuple
+ExecCopySlotMinimalTuple(TupleTableSlot *slot)
+{
+ /*
+ * sanity checks
+ */
+ Assert(slot != NULL);
+ Assert(!slot->tts_isempty);
+
+ /*
+ * If we have a physical tuple then just copy it.
+ */
+ if (slot->tts_tuple)
+ {
+ if (slot->tts_mintuple)
+ return heap_copy_minimal_tuple(slot->tts_mintuple);
+ else
+ return minimal_tuple_from_heap_tuple(slot->tts_tuple);
+ }
+
+ /*
+ * Otherwise we need to build a tuple from the Datum array.
+ */
+ return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
+ slot->tts_values,
+ slot->tts_isnull);
+}
+
+/* --------------------------------
* ExecFetchSlotTuple
- * Fetch the slot's physical tuple.
+ * Fetch the slot's regular physical tuple.
*
* If the slot contains a virtual tuple, we convert it to physical
* form. The slot retains ownership of the physical tuple.
+ * Likewise, if it contains a minimal tuple we convert to regular form.
*
* The difference between this and ExecMaterializeSlot() is that this
* does not guarantee that the contained tuple is local storage.
@@ -592,9 +707,9 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
Assert(!slot->tts_isempty);
/*
- * If we have a physical tuple then just return it.
+ * If we have a regular physical tuple then just return it.
*/
- if (slot->tts_tuple)
+ if (slot->tts_tuple && slot->tts_mintuple == NULL)
return slot->tts_tuple;
/*
@@ -629,10 +744,10 @@ ExecMaterializeSlot(TupleTableSlot *slot)
Assert(!slot->tts_isempty);
/*
- * If we have a physical tuple, and it's locally palloc'd, we have nothing
- * to do.
+ * If we have a regular physical tuple, and it's locally palloc'd,
+ * we have nothing to do.
*/
- if (slot->tts_tuple && slot->tts_shouldFree)
+ if (slot->tts_tuple && slot->tts_shouldFree && slot->tts_mintuple == NULL)
return slot->tts_tuple;
/*
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 0c77e821690..90ab0188743 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.39 2006/06/16 18:42:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.40 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,8 +48,6 @@ FunctionNext(FunctionScanState *node)
EState *estate;
ScanDirection direction;
Tuplestorestate *tuplestorestate;
- bool should_free;
- HeapTuple heapTuple;
/*
* get information from the estate and scan state
@@ -86,14 +84,11 @@ FunctionNext(FunctionScanState *node)
/*
* Get the next tuple from tuplestore. Return NULL if no more tuples.
*/
- heapTuple = tuplestore_getheaptuple(tuplestorestate,
- ScanDirectionIsForward(direction),
- &should_free);
slot = node->ss.ss_ScanTupleSlot;
- if (heapTuple)
- return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
- else
- return ExecClearTuple(slot);
+ (void) tuplestore_gettupleslot(tuplestorestate,
+ ScanDirectionIsForward(direction),
+ slot);
+ return slot;
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index eca769a86cc..94a07013854 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.54 2006/03/05 15:58:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.55 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,8 +44,6 @@ ExecMaterial(MaterialState *node)
ScanDirection dir;
bool forward;
Tuplestorestate *tuplestorestate;
- HeapTuple heapTuple = NULL;
- bool should_free = false;
bool eof_tuplestore;
TupleTableSlot *slot;
@@ -80,27 +78,25 @@ ExecMaterial(MaterialState *node)
{
/*
* When reversing direction at tuplestore EOF, the first
- * getheaptuple call will fetch the last-added tuple; but we want
+ * gettupleslot call will fetch the last-added tuple; but we want
* to return the one before that, if possible. So do an extra
* fetch.
*/
- heapTuple = tuplestore_getheaptuple(tuplestorestate,
- forward,
- &should_free);
- if (heapTuple == NULL)
+ if (!tuplestore_advance(tuplestorestate, forward))
return NULL; /* the tuplestore must be empty */
- if (should_free)
- heap_freetuple(heapTuple);
}
eof_tuplestore = false;
}
+ /*
+ * If we can fetch another tuple from the tuplestore, return it.
+ */
+ slot = node->ss.ps.ps_ResultTupleSlot;
if (!eof_tuplestore)
{
- heapTuple = tuplestore_getheaptuple(tuplestorestate,
- forward,
- &should_free);
- if (heapTuple == NULL && forward)
+ if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
+ return slot;
+ if (forward)
eof_tuplestore = true;
}
@@ -128,26 +124,26 @@ ExecMaterial(MaterialState *node)
node->eof_underlying = true;
return NULL;
}
- heapTuple = ExecFetchSlotTuple(outerslot);
- should_free = false;
/*
- * Append returned tuple to tuplestore, too. NOTE: because the
+ * Append returned tuple to tuplestore. NOTE: because the
* tuplestore is certainly in EOF state, its read position will move
* forward over the added tuple. This is what we want.
*/
if (tuplestorestate)
- tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
+ tuplestore_puttupleslot(tuplestorestate, outerslot);
+
+ /*
+ * And return a copy of the tuple. (XXX couldn't we just return
+ * the outerslot?)
+ */
+ return ExecCopySlot(slot, outerslot);
}
/*
- * Return the obtained tuple, if any.
+ * Nothing left ...
*/
- slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
- if (heapTuple)
- return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
- else
- return ExecClearTuple(slot);
+ return ExecClearTuple(slot);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c
index dffc8899b23..8ebf5b7fd1d 100644
--- a/src/backend/executor/tstoreReceiver.c
+++ b/src/backend/executor/tstoreReceiver.c
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.16 2006/03/05 15:58:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.17 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -45,7 +45,7 @@ tstoreReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
TStoreState *myState = (TStoreState *) self;
MemoryContext oldcxt = MemoryContextSwitchTo(myState->cxt);
- tuplestore_puttuple(myState->tstore, ExecFetchSlotTuple(slot));
+ tuplestore_puttupleslot(myState->tstore, slot);
MemoryContextSwitchTo(oldcxt);
}
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 060ce567922..c79d0eae18d 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.101 2006/03/05 15:58:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.102 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -911,21 +911,17 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
for (;;)
{
MemoryContext oldcontext;
- HeapTuple tup;
- bool should_free;
+ bool ok;
oldcontext = MemoryContextSwitchTo(portal->holdContext);
- tup = tuplestore_getheaptuple(portal->holdStore, forward,
- &should_free);
+ ok = tuplestore_gettupleslot(portal->holdStore, forward, slot);
MemoryContextSwitchTo(oldcontext);
- if (tup == NULL)
+ if (!ok)
break;
- ExecStoreTuple(tup, slot, InvalidBuffer, should_free);
-
(*dest->receiveSlot) (slot, dest);
ExecClearTuple(slot);
diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c
index 6ff6b72082c..a2ed330ccc6 100644
--- a/src/backend/utils/sort/tuplestore.c
+++ b/src/backend/utils/sort/tuplestore.c
@@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.27 2006/03/05 15:58:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.28 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -195,6 +195,7 @@ struct Tuplestorestate
static Tuplestorestate *tuplestore_begin_common(bool randomAccess,
bool interXact,
int maxKBytes);
+static void tuplestore_puttuple_common(Tuplestorestate *state, void *tuple);
static void dumptuples(Tuplestorestate *state);
static unsigned int getlen(Tuplestorestate *state, bool eofOK);
static void *copytup_heap(Tuplestorestate *state, void *tup);
@@ -304,15 +305,45 @@ tuplestore_ateof(Tuplestorestate *state)
* If the read status is currently "AT EOF" then it remains so (the read
* pointer advances along with the write pointer); otherwise the read
* pointer is unchanged. This is for the convenience of nodeMaterial.c.
+ *
+ * tuplestore_puttupleslot() is a convenience routine to collect data from
+ * a TupleTableSlot without an extra copy operation.
*/
void
-tuplestore_puttuple(Tuplestorestate *state, void *tuple)
+tuplestore_puttupleslot(Tuplestorestate *state,
+ TupleTableSlot *slot)
+{
+ MinimalTuple tuple;
+
+ /*
+ * Form a MinimalTuple in working memory
+ */
+ tuple = ExecCopySlotMinimalTuple(slot);
+ USEMEM(state, GetMemoryChunkSpace(tuple));
+
+ tuplestore_puttuple_common(state, (void *) tuple);
+}
+
+/*
+ * "Standard" case to copy from a HeapTuple. This is actually now somewhat
+ * deprecated, but not worth getting rid of in view of the number of callers.
+ * (Consider adding something that takes a tupdesc+values/nulls arrays so
+ * that we can use heap_form_minimal_tuple() and avoid a copy step.)
+ */
+void
+tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
{
/*
* Copy the tuple. (Must do this even in WRITEFILE case.)
*/
tuple = COPYTUP(state, tuple);
+ tuplestore_puttuple_common(state, (void *) tuple);
+}
+
+static void
+tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
+{
switch (state->status)
{
case TSS_INMEM:
@@ -389,7 +420,7 @@ tuplestore_puttuple(Tuplestorestate *state, void *tuple)
* Returns NULL if no more tuples. If should_free is set, the
* caller must pfree the returned tuple when done with it.
*/
-void *
+static void *
tuplestore_gettuple(Tuplestorestate *state, bool forward,
bool *should_free)
{
@@ -526,6 +557,59 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
}
/*
+ * tuplestore_gettupleslot - exported function to fetch a MinimalTuple
+ *
+ * If successful, put tuple in slot and return TRUE; else, clear the slot
+ * and return FALSE.
+ */
+bool
+tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
+ TupleTableSlot *slot)
+{
+ MinimalTuple tuple;
+ bool should_free;
+
+ tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);
+
+ if (tuple)
+ {
+ ExecStoreMinimalTuple(tuple, slot, should_free);
+ return true;
+ }
+ else
+ {
+ ExecClearTuple(slot);
+ return false;
+ }
+}
+
+/*
+ * tuplestore_advance - exported function to adjust position without fetching
+ *
+ * We could optimize this case to avoid palloc/pfree overhead, but for the
+ * moment it doesn't seem worthwhile.
+ */
+bool
+tuplestore_advance(Tuplestorestate *state, bool forward)
+{
+ void *tuple;
+ bool should_free;
+
+ tuple = tuplestore_gettuple(state, forward, &should_free);
+
+ if (tuple)
+ {
+ if (should_free)
+ pfree(tuple);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*
* dumptuples - remove tuples from memory and write to tape
*
* As a side effect, we must set readpos and markpos to the value
@@ -672,34 +756,31 @@ getlen(Tuplestorestate *state, bool eofOK)
/*
* Routines specialized for HeapTuple case
+ *
+ * The stored form is actually a MinimalTuple, but for largely historical
+ * reasons we allow COPYTUP to work from a HeapTuple.
+ *
+ * Since MinimalTuple already has length in its first word, we don't need
+ * to write that separately.
*/
static void *
copytup_heap(Tuplestorestate *state, void *tup)
{
- HeapTuple tuple = (HeapTuple) tup;
+ MinimalTuple tuple;
- tuple = heap_copytuple(tuple);
+ tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);
USEMEM(state, GetMemoryChunkSpace(tuple));
return (void *) tuple;
}
-/*
- * We don't bother to write the HeapTupleData part of the tuple.
- */
-
static void
writetup_heap(Tuplestorestate *state, void *tup)
{
- HeapTuple tuple = (HeapTuple) tup;
- unsigned int tuplen;
+ MinimalTuple tuple = (MinimalTuple) tup;
+ unsigned int tuplen = tuple->t_len;
- tuplen = tuple->t_len + sizeof(tuplen);
- if (BufFileWrite(state->myfile, (void *) &tuplen,
- sizeof(tuplen)) != sizeof(tuplen))
- elog(ERROR, "write failed");
- if (BufFileWrite(state->myfile, (void *) tuple->t_data,
- tuple->t_len) != (size_t) tuple->t_len)
+ if (BufFileWrite(state->myfile, (void *) tuple, tuplen) != (size_t) tuplen)
elog(ERROR, "write failed");
if (state->randomAccess) /* need trailing length word? */
if (BufFileWrite(state->myfile, (void *) &tuplen,
@@ -707,23 +788,20 @@ writetup_heap(Tuplestorestate *state, void *tup)
elog(ERROR, "write failed");
FREEMEM(state, GetMemoryChunkSpace(tuple));
- heap_freetuple(tuple);
+ heap_free_minimal_tuple(tuple);
}
static void *
readtup_heap(Tuplestorestate *state, unsigned int len)
{
- unsigned int tuplen = len - sizeof(unsigned int) + HEAPTUPLESIZE;
- HeapTuple tuple = (HeapTuple) palloc(tuplen);
+ MinimalTuple tuple = (MinimalTuple) palloc(len);
+ unsigned int tuplen;
USEMEM(state, GetMemoryChunkSpace(tuple));
- /* reconstruct the HeapTupleData portion */
- tuple->t_len = len - sizeof(unsigned int);
- ItemPointerSetInvalid(&(tuple->t_self));
- tuple->t_data = (HeapTupleHeader) (((char *) tuple) + HEAPTUPLESIZE);
/* read in the tuple proper */
- if (BufFileRead(state->myfile, (void *) tuple->t_data,
- tuple->t_len) != (size_t) tuple->t_len)
+ tuple->t_len = len;
+ if (BufFileRead(state->myfile, (void *) ((char *) tuple + sizeof(int)),
+ len - sizeof(int)) != (size_t) (len - sizeof(int)))
elog(ERROR, "unexpected end of data");
if (state->randomAccess) /* need trailing length word? */
if (BufFileRead(state->myfile, (void *) &tuplen,