elog(ERROR, "missing row in percentile_disc");
/*
- * Note: we *cannot* clean up the tuplesort object here, because the value
- * to be returned is allocated inside its sortcontext. We could use
- * datumCopy to copy it out of there, but it doesn't seem worth the
- * trouble, since the cleanup callback will clear the tuplesort later.
+ * Note: we could clean up the tuplesort object here, but it doesn't seem
+ * worth the trouble, since the cleanup callback will clear the tuplesort
+ * later.
*/
/* We shouldn't have stored any nulls, but do the right thing anyway */
}
/*
- * Note: we *cannot* clean up the tuplesort object here, because the value
- * to be returned may be allocated inside its sortcontext. We could use
- * datumCopy to copy it out of there, but it doesn't seem worth the
- * trouble, since the cleanup callback will clear the tuplesort later.
+ * Note: we could clean up the tuplesort object here, but it doesn't seem
+ * worth the trouble, since the cleanup callback will clear the tuplesort
+ * later.
*/
PG_RETURN_DATUM(val);
pfree(DatumGetPointer(last_val));
/*
- * Note: we *cannot* clean up the tuplesort object here, because the value
- * to be returned is allocated inside its sortcontext. We could use
- * datumCopy to copy it out of there, but it doesn't seem worth the
- * trouble, since the cleanup callback will clear the tuplesort later.
+ * Note: we could clean up the tuplesort object here, but it doesn't seem
+ * worth the trouble, since the cleanup callback will clear the tuplesort
+ * later.
*/
if (mode_freq)
* direction into *stup. Returns FALSE if no more tuples.
* If *should_free is set, the caller must pfree stup.tuple when done with it.
* Otherwise, caller should not use tuple following next call here.
+ *
+ * Note: Public tuplesort fetch routine callers cannot rely on tuple being
+ * allocated in their own memory context when should_free is TRUE. It may be
+ * necessary to create a new copy of the tuple to meet the requirements of
+ * public fetch routine callers.
*/
static bool
tuplesort_gettuple_common(Tuplesortstate *state, bool forward,
* NULL value in leading attribute will set abbreviated value to zeroed
* representation, which caller may rely on in abbreviated inequality check.
*
- * The slot receives a copied tuple (sometimes allocated in caller memory
- * context) that will stay valid regardless of future manipulations of the
- * tuplesort's state.
+ * The slot receives a tuple that's been copied into the caller's memory
+ * context, so that it will stay valid regardless of future manipulations of
+ * the tuplesort's state (up to and including deleting the tuplesort).
+ * This differs from similar routines for other types of tuplesorts.
*/
bool
tuplesort_gettupleslot(Tuplesortstate *state, bool forward,
if (state->sortKeys->abbrev_converter && abbrev)
*abbrev = stup.datum1;
- if (!should_free)
- {
- stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple);
- should_free = true;
- }
- ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, should_free);
+ /*
+ * Callers rely on tuple being in their own memory context, which is
+ * not guaranteed by tuplesort_gettuple_common(), even when should_free
+ * is set to TRUE. We must always copy here, since our interface does
+ * not allow callers to opt into arrangement where tuple memory can go
+ * away on the next call here, or after tuplesort_end() is called.
+ */
+ ExecStoreMinimalTuple(heap_copy_minimal_tuple((MinimalTuple) stup.tuple),
+ slot, true);
+
+ /*
+ * Free local copy if needed. It would be very invasive to get
+ * tuplesort_gettuple_common() to allocate tuple in caller's context
+ * for us, so we just do this instead.
+ */
+ if (should_free)
+ pfree(stup.tuple);
+
return true;
}
else
* Returns NULL if no more tuples. If *should_free is set, the
* caller must pfree the returned tuple when done with it.
* If it is not set, caller should not use tuple following next
- * call here.
+ * call here. It's never okay to use it after tuplesort_end().
*/
HeapTuple
tuplesort_getheaptuple(Tuplesortstate *state, bool forward, bool *should_free)
* Returns NULL if no more tuples. If *should_free is set, the
* caller must pfree the returned tuple when done with it.
* If it is not set, caller should not use tuple following next
- * call here.
+ * call here. It's never okay to use it after tuplesort_end().
*/
IndexTuple
tuplesort_getindextuple(Tuplesortstate *state, bool forward,
* Returns FALSE if no more datums.
*
* If the Datum is pass-by-ref type, the returned value is freshly palloc'd
- * and is now owned by the caller.
+ * in caller's context, and is now owned by the caller (this differs from
+ * similar routines for other types of tuplesorts).
*
* Caller may optionally be passed back abbreviated value (on TRUE return
* value) when abbreviation was used, which can be used to cheaply avoid
return false;
}
+ /* Ensure we copy into caller's memory context */
+ MemoryContextSwitchTo(oldcontext);
+
/* Record abbreviated key for caller */
if (state->sortKeys->abbrev_converter && abbrev)
*abbrev = stup.datum1;
}
else
{
- /* use stup.tuple because stup.datum1 may be an abbreviation */
+ /*
+ * Callers rely on datum being in their own memory context, which is
+ * not guaranteed by tuplesort_gettuple_common(), even when should_free
+ * is set to TRUE. We must always copy here, since our interface does
+ * not allow callers to opt into arrangement where tuple memory can go
+ * away on the next call here, or after tuplesort_end() is called.
+ *
+ * Use stup.tuple because stup.datum1 may be an abbreviation.
+ */
+ *val = datumCopy(PointerGetDatum(stup.tuple), false, state->datumTypeLen);
+ *isNull = false;
+ /*
+ * Free local copy if needed. It would be very invasive to get
+ * tuplesort_gettuple_common() to allocate tuple in caller's context
+ * for us, so we just do this instead.
+ */
if (should_free)
- *val = PointerGetDatum(stup.tuple);
- else
- *val = datumCopy(PointerGetDatum(stup.tuple), false, state->datumTypeLen);
- *isNull = false;
+ pfree(stup.tuple);
}
- MemoryContextSwitchTo(oldcontext);
-
return true;
}