@@ -147,13 +147,18 @@ booloptimize_bounded_sort = true;
147147 * case where the first key determines the comparison result. Note that
148148 * for a pass-by-reference datatype, datum1 points into the "tuple" storage.
149149 *
150+ * There is one special case: when the sort support infrastructure provides an
151+ * "abbreviated key" representation, where the key is (typically) a pass by
152+ * value proxy for a pass by reference type. In this case, the abbreviated key
153+ * is stored in datum1 in place of the actual first key column.
154+ *
150155 * When sorting single Datums, the data value is represented directly by
151- * datum1/isnull1. If the datatype is pass-by-reference and isnull1 is false,
152- *then datum1 points to a separately palloc'd data value that is also pointed
153- *to by the "tuple" pointer; otherwise "tuple" is NULL.There is one special
154- *case: when the sort support infrastructure provides an" abbreviated key"
155- *representation, where the key is(typically) a pass by value proxy for a
156- *pass by referencetype .
156+ * datum1/isnull1 for pass by value types (or null values). If the datatype is
157+ *pass-by-reference and isnull1 is false, then "tuple" points to a separately
158+ *palloc'd data value, otherwise "tuple" is NULL.The value of datum1 is then
159+ *either the same pointer as "tuple", or is an abbreviated key value as
160+ *described above. Accordingly, "tuple" isalways used in preference to
161+ *datum1 as the authoritative value for pass-by- referencecases .
157162 *
158163 * While building initial runs, tupindex holds the tuple's run number. During
159164 * merge passes, we re-use it to hold the input tape number that each tuple in
@@ -901,30 +906,36 @@ tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
901906state -> copytup = copytup_datum ;
902907state -> writetup = writetup_datum ;
903908state -> readtup = readtup_datum ;
909+ state -> abbrevNext = 10 ;
904910
905911state -> datumType = datumType ;
906912
907- /* Prepare SortSupport data */
908- state -> onlyKey = (SortSupport )palloc0 (sizeof (SortSupportData ));
909-
910- state -> onlyKey -> ssup_cxt = CurrentMemoryContext ;
911- state -> onlyKey -> ssup_collation = sortCollation ;
912- state -> onlyKey -> ssup_nulls_first = nullsFirstFlag ;
913- /*
914- * Conversion to abbreviated representation infeasible in the Datum case.
915- * It must be possible to subsequently fetch original datum values within
916- * tuplesort_getdatum(), which would require special-case preservation of
917- * original values.
918- */
919- state -> onlyKey -> abbreviate = false;
920-
921- PrepareSortSupportFromOrderingOp (sortOperator ,state -> onlyKey );
922-
923913/* lookup necessary attributes of the datum type */
924914get_typlenbyval (datumType ,& typlen ,& typbyval );
925915state -> datumTypeLen = typlen ;
926916state -> datumTypeByVal = typbyval ;
927917
918+ /* Prepare SortSupport data */
919+ state -> sortKeys = (SortSupport )palloc0 (sizeof (SortSupportData ));
920+
921+ state -> sortKeys -> ssup_cxt = CurrentMemoryContext ;
922+ state -> sortKeys -> ssup_collation = sortCollation ;
923+ state -> sortKeys -> ssup_nulls_first = nullsFirstFlag ;
924+
925+ /* abbreviation is possible here only for by-reference types */
926+ state -> sortKeys -> abbreviate = !typbyval ;
927+
928+ PrepareSortSupportFromOrderingOp (sortOperator ,state -> sortKeys );
929+
930+ /*
931+ * The "onlyKey" optimization cannot be used with abbreviated keys, since
932+ * tie-breaker comparisons may be required. Typically, the optimization is
933+ * only of value to pass-by-value types anyway, whereas abbreviated keys
934+ * are typically only of value to pass-by-reference types.
935+ */
936+ if (!state -> sortKeys -> abbrev_converter )
937+ state -> onlyKey = state -> sortKeys ;
938+
928939MemoryContextSwitchTo (oldcontext );
929940
930941return state ;
@@ -1307,9 +1318,17 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
13071318SortTuple stup ;
13081319
13091320/*
1310- * If it's a pass-by-reference value, copy it into memory we control, and
1311- * decrease availMem. Then call the common code.
1321+ * Pass-by-value types or null values are just stored directly in
1322+ * stup.datum1 (and stup.tuple is not used and set to NULL).
1323+ *
1324+ * Non-null pass-by-reference values need to be copied into memory we
1325+ * control, and possibly abbreviated. The copied value is pointed to by
1326+ * stup.tuple and is treated as the canonical copy (e.g. to return via
1327+ * tuplesort_getdatum or when writing to tape); stup.datum1 gets the
1328+ * abbreviated value if abbreviation is happening, otherwise it's identical
1329+ * to stup.tuple.
13121330 */
1331+
13131332if (isNull || state -> datumTypeByVal )
13141333{
13151334stup .datum1 = val ;
@@ -1318,10 +1337,44 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
13181337}
13191338else
13201339{
1321- stup .datum1 = datumCopy (val , false,state -> datumTypeLen );
1340+ Datum original = datumCopy (val , false,state -> datumTypeLen );
1341+
13221342stup .isnull1 = false;
1323- stup .tuple = DatumGetPointer (stup . datum1 );
1343+ stup .tuple = DatumGetPointer (original );
13241344USEMEM (state ,GetMemoryChunkSpace (stup .tuple ));
1345+
1346+ if (!state -> sortKeys -> abbrev_converter )
1347+ {
1348+ stup .datum1 = original ;
1349+ }
1350+ else if (!consider_abort_common (state ))
1351+ {
1352+ /* Store abbreviated key representation */
1353+ stup .datum1 = state -> sortKeys -> abbrev_converter (original ,
1354+ state -> sortKeys );
1355+ }
1356+ else
1357+ {
1358+ /* Abort abbreviation */
1359+ int i ;
1360+
1361+ stup .datum1 = original ;
1362+
1363+ /*
1364+ * Set state to be consistent with never trying abbreviation.
1365+ *
1366+ * Alter datum1 representation in already-copied tuples, so as to
1367+ * ensure a consistent representation (current tuple was just handled).
1368+ * Note that we rely on all tuples copied so far actually being
1369+ * contained within memtuples array.
1370+ */
1371+ for (i = 0 ;i < state -> memtupcount ;i ++ )
1372+ {
1373+ SortTuple * mtup = & state -> memtuples [i ];
1374+
1375+ mtup -> datum1 = PointerGetDatum (mtup -> tuple );
1376+ }
1377+ }
13251378}
13261379
13271380puttuple_common (state ,& stup );
@@ -1886,10 +1939,12 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward,
18861939}
18871940else
18881941{
1942+ /* use stup.tuple because stup.datum1 may be an abbreviation */
1943+
18891944if (should_free )
1890- * val = stup .datum1 ;
1945+ * val = PointerGetDatum ( stup .tuple ) ;
18911946else
1892- * val = datumCopy (stup .datum1 , false,state -> datumTypeLen );
1947+ * val = datumCopy (PointerGetDatum ( stup .tuple ) , false,state -> datumTypeLen );
18931948* isNull = false;
18941949}
18951950
@@ -3715,9 +3770,22 @@ readtup_index(Tuplesortstate *state, SortTuple *stup,
37153770static int
37163771comparetup_datum (const SortTuple * a ,const SortTuple * b ,Tuplesortstate * state )
37173772{
3718- return ApplySortComparator (a -> datum1 ,a -> isnull1 ,
3719- b -> datum1 ,b -> isnull1 ,
3720- state -> onlyKey );
3773+ int compare ;
3774+
3775+ compare = ApplySortComparator (a -> datum1 ,a -> isnull1 ,
3776+ b -> datum1 ,b -> isnull1 ,
3777+ state -> sortKeys );
3778+ if (compare != 0 )
3779+ return compare ;
3780+
3781+ /* if we have abbreviations, then "tuple" has the original value */
3782+
3783+ if (state -> sortKeys -> abbrev_converter )
3784+ compare = ApplySortAbbrevFullComparator (PointerGetDatum (a -> tuple ),a -> isnull1 ,
3785+ PointerGetDatum (b -> tuple ),b -> isnull1 ,
3786+ state -> sortKeys );
3787+
3788+ return compare ;
37213789}
37223790
37233791static void
@@ -3746,8 +3814,8 @@ writetup_datum(Tuplesortstate *state, int tapenum, SortTuple *stup)
37463814}
37473815else
37483816{
3749- waddr = DatumGetPointer ( stup -> datum1 ) ;
3750- tuplen = datumGetSize (stup -> datum1 , false,state -> datumTypeLen );
3817+ waddr = stup -> tuple ;
3818+ tuplen = datumGetSize (PointerGetDatum ( stup -> tuple ) , false,state -> datumTypeLen );
37513819Assert (tuplen != 0 );
37523820}
37533821