@@ -147,13 +147,18 @@ bool optimize_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 reference type .
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" is always used in preference to
161+ * datum1 as the authoritative value for pass-by- reference cases .
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,
901906 state -> copytup = copytup_datum ;
902907 state -> writetup = writetup_datum ;
903908 state -> readtup = readtup_datum ;
909+ state -> abbrevNext = 10 ;
904910
905911 state -> 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 */
924914 get_typlenbyval (datumType , & typlen , & typbyval );
925915 state -> datumTypeLen = typlen ;
926916 state -> 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+
928939 MemoryContextSwitchTo (oldcontext );
929940
930941 return state ;
@@ -1307,9 +1318,17 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
13071318 SortTuple 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+
13131332 if (isNull || state -> datumTypeByVal )
13141333 {
13151334 stup .datum1 = val ;
@@ -1318,10 +1337,44 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
13181337 }
13191338 else
13201339 {
1321- stup .datum1 = datumCopy (val , false, state -> datumTypeLen );
1340+ Datum original = datumCopy (val , false, state -> datumTypeLen );
1341+
13221342 stup .isnull1 = false;
1323- stup .tuple = DatumGetPointer (stup . datum1 );
1343+ stup .tuple = DatumGetPointer (original );
13241344 USEMEM (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
13271380 puttuple_common (state , & stup );
@@ -1886,10 +1939,12 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward,
18861939 }
18871940 else
18881941 {
1942+ /* use stup.tuple because stup.datum1 may be an abbreviation */
1943+
18891944 if (should_free )
1890- * val = stup .datum1 ;
1945+ * val = PointerGetDatum ( stup .tuple ) ;
18911946 else
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 }
37473815 else
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 );
37513819 Assert (tuplen != 0 );
37523820 }
37533821
0 commit comments