* case where the first key determines the comparison result. Note that
* for a pass-by-reference datatype, datum1 points into the "tuple" storage.
*
+ * There is one special case: when the sort support infrastructure provides an
+ * "abbreviated key" representation, where the key is (typically) a pass by
+ * value proxy for a pass by reference type. In this case, the abbreviated key
+ * is stored in datum1 in place of the actual first key column.
+ *
* When sorting single Datums, the data value is represented directly by
- * datum1/isnull1. If the datatype is pass-by-reference and isnull1 is false,
- * then datum1 points to a separately palloc'd data value that is also pointed
- * to by the "tuple" pointer; otherwise "tuple" is NULL. There is one special
- * case: when the sort support infrastructure provides an "abbreviated key"
- * representation, where the key is (typically) a pass by value proxy for a
- * pass by reference type.
+ * datum1/isnull1 for pass by value types (or null values). If the datatype is
+ * pass-by-reference and isnull1 is false, then "tuple" points to a separately
+ * palloc'd data value, otherwise "tuple" is NULL. The value of datum1 is then
+ * either the same pointer as "tuple", or is an abbreviated key value as
+ * described above. Accordingly, "tuple" is always used in preference to
+ * datum1 as the authoritative value for pass-by-reference cases.
*
* While building initial runs, tupindex holds the tuple's run number. During
* merge passes, we re-use it to hold the input tape number that each tuple in
state->copytup = copytup_datum;
state->writetup = writetup_datum;
state->readtup = readtup_datum;
+ state->abbrevNext = 10;
state->datumType = datumType;
- /* Prepare SortSupport data */
- state->onlyKey = (SortSupport) palloc0(sizeof(SortSupportData));
-
- state->onlyKey->ssup_cxt = CurrentMemoryContext;
- state->onlyKey->ssup_collation = sortCollation;
- state->onlyKey->ssup_nulls_first = nullsFirstFlag;
- /*
- * Conversion to abbreviated representation infeasible in the Datum case.
- * It must be possible to subsequently fetch original datum values within
- * tuplesort_getdatum(), which would require special-case preservation of
- * original values.
- */
- state->onlyKey->abbreviate = false;
-
- PrepareSortSupportFromOrderingOp(sortOperator, state->onlyKey);
-
/* lookup necessary attributes of the datum type */
get_typlenbyval(datumType, &typlen, &typbyval);
state->datumTypeLen = typlen;
state->datumTypeByVal = typbyval;
+ /* Prepare SortSupport data */
+ state->sortKeys = (SortSupport) palloc0(sizeof(SortSupportData));
+
+ state->sortKeys->ssup_cxt = CurrentMemoryContext;
+ state->sortKeys->ssup_collation = sortCollation;
+ state->sortKeys->ssup_nulls_first = nullsFirstFlag;
+
+ /* abbreviation is possible here only for by-reference types */
+ state->sortKeys->abbreviate = !typbyval;
+
+ PrepareSortSupportFromOrderingOp(sortOperator, state->sortKeys);
+
+ /*
+ * The "onlyKey" optimization cannot be used with abbreviated keys, since
+ * tie-breaker comparisons may be required. Typically, the optimization is
+ * only of value to pass-by-value types anyway, whereas abbreviated keys
+ * are typically only of value to pass-by-reference types.
+ */
+ if (!state->sortKeys->abbrev_converter)
+ state->onlyKey = state->sortKeys;
+
MemoryContextSwitchTo(oldcontext);
return state;
SortTuple stup;
/*
- * If it's a pass-by-reference value, copy it into memory we control, and
- * decrease availMem. Then call the common code.
+ * Pass-by-value types or null values are just stored directly in
+ * stup.datum1 (and stup.tuple is not used and set to NULL).
+ *
+ * Non-null pass-by-reference values need to be copied into memory we
+ * control, and possibly abbreviated. The copied value is pointed to by
+ * stup.tuple and is treated as the canonical copy (e.g. to return via
+ * tuplesort_getdatum or when writing to tape); stup.datum1 gets the
+ * abbreviated value if abbreviation is happening, otherwise it's identical
+ * to stup.tuple.
*/
+
if (isNull || state->datumTypeByVal)
{
stup.datum1 = val;
}
else
{
- stup.datum1 = datumCopy(val, false, state->datumTypeLen);
+ Datum original = datumCopy(val, false, state->datumTypeLen);
+
stup.isnull1 = false;
- stup.tuple = DatumGetPointer(stup.datum1);
+ stup.tuple = DatumGetPointer(original);
USEMEM(state, GetMemoryChunkSpace(stup.tuple));
+
+ if (!state->sortKeys->abbrev_converter)
+ {
+ stup.datum1 = original;
+ }
+ else if (!consider_abort_common(state))
+ {
+ /* Store abbreviated key representation */
+ stup.datum1 = state->sortKeys->abbrev_converter(original,
+ state->sortKeys);
+ }
+ else
+ {
+ /* Abort abbreviation */
+ int i;
+
+ stup.datum1 = original;
+
+ /*
+ * Set state to be consistent with never trying abbreviation.
+ *
+ * Alter datum1 representation in already-copied tuples, so as to
+ * ensure a consistent representation (current tuple was just handled).
+ * Note that we rely on all tuples copied so far actually being
+ * contained within memtuples array.
+ */
+ for (i = 0; i < state->memtupcount; i++)
+ {
+ SortTuple *mtup = &state->memtuples[i];
+
+ mtup->datum1 = PointerGetDatum(mtup->tuple);
+ }
+ }
}
puttuple_common(state, &stup);
}
else
{
+ /* use stup.tuple because stup.datum1 may be an abbreviation */
+
if (should_free)
- *val = stup.datum1;
+ *val = PointerGetDatum(stup.tuple);
else
- *val = datumCopy(stup.datum1, false, state->datumTypeLen);
+ *val = datumCopy(PointerGetDatum(stup.tuple), false, state->datumTypeLen);
*isNull = false;
}
static int
comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
{
- return ApplySortComparator(a->datum1, a->isnull1,
- b->datum1, b->isnull1,
- state->onlyKey);
+ int compare;
+
+ compare = ApplySortComparator(a->datum1, a->isnull1,
+ b->datum1, b->isnull1,
+ state->sortKeys);
+ if (compare != 0)
+ return compare;
+
+ /* if we have abbreviations, then "tuple" has the original value */
+
+ if (state->sortKeys->abbrev_converter)
+ compare = ApplySortAbbrevFullComparator(PointerGetDatum(a->tuple), a->isnull1,
+ PointerGetDatum(b->tuple), b->isnull1,
+ state->sortKeys);
+
+ return compare;
}
static void
}
else
{
- waddr = DatumGetPointer(stup->datum1);
- tuplen = datumGetSize(stup->datum1, false, state->datumTypeLen);
+ waddr = stup->tuple;
+ tuplen = datumGetSize(PointerGetDatum(stup->tuple), false, state->datumTypeLen);
Assert(tuplen != 0);
}