@@ -109,6 +109,8 @@ static void index_update_stats(Relation rel,
109109static void IndexCheckExclusion (Relation heapRelation ,
110110Relation indexRelation ,
111111IndexInfo * indexInfo );
112+ static inline int64 itemptr_encode (ItemPointer itemptr );
113+ static inline void itemptr_decode (ItemPointer itemptr ,int64 encoded );
112114static bool validate_index_callback (ItemPointer itemptr ,void * opaque );
113115static void validate_index_heapscan (Relation heapRelation ,
114116Relation indexRelation ,
@@ -2832,7 +2834,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28322834ivinfo .num_heap_tuples = heapRelation -> rd_rel -> reltuples ;
28332835ivinfo .strategy = NULL ;
28342836
2835- state .tuplesort = tuplesort_begin_datum (TIDOID ,TIDLessOperator ,
2837+ /*
2838+ * Encode TIDs as int8 values for the sort, rather than directly sorting
2839+ * item pointers. This can be significantly faster, primarily because TID
2840+ * is a pass-by-reference type on all platforms, whereas int8 is
2841+ * pass-by-value on most platforms.
2842+ */
2843+ state .tuplesort = tuplesort_begin_datum (INT8OID ,Int8LessOperator ,
28362844InvalidOid , false,
28372845maintenance_work_mem ,
28382846false);
@@ -2871,15 +2879,56 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28712879heap_close (heapRelation ,NoLock );
28722880}
28732881
2882+ /*
2883+ * itemptr_encode - Encode ItemPointer as int64/int8
2884+ *
2885+ * This representation must produce values encoded as int64 that sort in the
2886+ * same order as their corresponding original TID values would (using the
2887+ * default int8 opclass to produce a result equivalent to the default TID
2888+ * opclass).
2889+ *
2890+ * As noted in validate_index(), this can be significantly faster.
2891+ */
2892+ static inline int64
2893+ itemptr_encode (ItemPointer itemptr )
2894+ {
2895+ BlockNumber block = ItemPointerGetBlockNumber (itemptr );
2896+ OffsetNumber offset = ItemPointerGetOffsetNumber (itemptr );
2897+ int64 encoded ;
2898+
2899+ /*
2900+ * Use the 16 least significant bits for the offset. 32 adjacent bits are
2901+ * used for the block number. Since remaining bits are unused, there
2902+ * cannot be negative encoded values (We assume a two's complement
2903+ * representation).
2904+ */
2905+ encoded = ((uint64 )block <<16 ) | (uint16 )offset ;
2906+
2907+ return encoded ;
2908+ }
2909+
2910+ /*
2911+ * itemptr_decode - Decode int64/int8 representation back to ItemPointer
2912+ */
2913+ static inline void
2914+ itemptr_decode (ItemPointer itemptr ,int64 encoded )
2915+ {
2916+ BlockNumber block = (BlockNumber ) (encoded >>16 );
2917+ OffsetNumber offset = (OffsetNumber ) (encoded & 0xFFFF );
2918+
2919+ ItemPointerSet (itemptr ,block ,offset );
2920+ }
2921+
28742922/*
28752923 * validate_index_callback - bulkdelete callback to collect the index TIDs
28762924 */
28772925static bool
28782926validate_index_callback (ItemPointer itemptr ,void * opaque )
28792927{
28802928v_i_state * state = (v_i_state * )opaque ;
2929+ int64 encoded = itemptr_encode (itemptr );
28812930
2882- tuplesort_putdatum (state -> tuplesort ,PointerGetDatum ( itemptr ), false);
2931+ tuplesort_putdatum (state -> tuplesort ,Int64GetDatum ( encoded ), false);
28832932state -> itups += 1 ;
28842933return false;/* never actually delete anything */
28852934}
@@ -2911,6 +2960,7 @@ validate_index_heapscan(Relation heapRelation,
29112960
29122961/* state variables for the merge */
29132962ItemPointer indexcursor = NULL ;
2963+ ItemPointerData decoded ;
29142964bool tuplesort_empty = false;
29152965
29162966/*
@@ -3020,13 +3070,26 @@ validate_index_heapscan(Relation heapRelation,
30203070 */
30213071if (ItemPointerGetBlockNumber (indexcursor )== root_blkno )
30223072in_index [ItemPointerGetOffsetNumber (indexcursor )- 1 ]= true;
3023- pfree (indexcursor );
30243073}
30253074
30263075tuplesort_empty = !tuplesort_getdatum (state -> tuplesort , true,
30273076& ts_val ,& ts_isnull );
30283077Assert (tuplesort_empty || !ts_isnull );
3029- indexcursor = (ItemPointer )DatumGetPointer (ts_val );
3078+ if (!tuplesort_empty )
3079+ {
3080+ itemptr_decode (& decoded ,DatumGetInt64 (ts_val ));
3081+ indexcursor = & decoded ;
3082+
3083+ /* If int8 is pass-by-ref, free (encoded) TID Datum memory */
3084+ #ifndef USE_FLOAT8_BYVAL
3085+ pfree (DatumGetPointer (ts_val ));
3086+ #endif
3087+ }
3088+ else
3089+ {
3090+ /* Be tidy */
3091+ indexcursor = NULL ;
3092+ }
30303093}
30313094
30323095/*