@@ -91,7 +91,8 @@ static HeapScanDesc heap_beginscan_internal(Relation relation,
9191bool temp_snap );
9292static BlockNumber heap_parallelscan_nextpage (HeapScanDesc scan );
9393static HeapTuple heap_prepare_insert (Relation relation ,HeapTuple tup ,
94- TransactionId xid ,CommandId cid ,int options );
94+ TupleDesc tupdesc ,TransactionId xid ,
95+ CommandId cid ,int options );
9596static XLogRecPtr log_heap_update (Relation reln ,Buffer oldbuf ,
9697Buffer newbuf ,HeapTuple oldtup ,
9798HeapTuple newtup ,HeapTuple old_key_tup ,
@@ -1062,7 +1063,7 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
10621063 (
10631064 (tupleDesc )-> attrs [(attnum )- 1 ]-> attcacheoff >=0 ?
10641065 (
1065- fetchatt (( tupleDesc ) -> attrs [ (attnum )- 1 ] ,
1066+ fetchatt (tupleDesc , (attnum )- 1 ,
10661067(char * ) (tup )-> t_data + (tup )-> t_data -> t_hoff +
10671068(tupleDesc )-> attrs [(attnum )- 1 ]-> attcacheoff )
10681069 )
@@ -2393,8 +2394,8 @@ ReleaseBulkInsertStatePin(BulkInsertState bistate)
23932394 * within the tuple data is NOT reflected into *tup.
23942395 */
23952396Oid
2396- heap_insert (Relation relation ,HeapTuple tup ,CommandId cid ,
2397- int options ,BulkInsertState bistate )
2397+ heap_insert (Relation relation ,HeapTuple tup ,TupleDesc tupdesc ,
2398+ CommandId cid , int options ,BulkInsertState bistate )
23982399{
23992400TransactionId xid = GetCurrentTransactionId ();
24002401HeapTuple heaptup ;
@@ -2409,7 +2410,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
24092410 * Note: below this point, heaptup is the data we actually intend to store
24102411 * into the relation; tup is the caller's original untoasted data.
24112412 */
2412- heaptup = heap_prepare_insert (relation ,tup ,xid ,cid ,options );
2413+ heaptup = heap_prepare_insert (relation ,tup ,tupdesc , xid ,cid ,options );
24132414
24142415/*
24152416 * Find buffer to insert this tuple into. If the page is all visible,
@@ -2569,6 +2570,36 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
25692570return HeapTupleGetOid (tup );
25702571}
25712572
2573+ static inline bool *
2574+ heap_tuple_needs_recompression (HeapTuple tup ,TupleDesc td1 ,TupleDesc td2 )
2575+ {
2576+ AttrNumber natts = td1 -> natts ;
2577+ AttrNumber att ;
2578+ bool * recompress = NULL ;
2579+
2580+ if (td1 == td2 )
2581+ return NULL ;
2582+
2583+ if (!td1 -> tdcmroutines && !td2 -> tdcmroutines )
2584+ return NULL ;
2585+
2586+ for (att = 1 ;att <=natts ;att ++ )
2587+ {
2588+ if (heap_attisnull (tup ,att ))
2589+ continue ;
2590+
2591+ if (td1 -> attrs [att - 1 ]-> attcompression !=
2592+ td2 -> attrs [att - 1 ]-> attcompression )
2593+ {
2594+ if (!recompress )
2595+ recompress = palloc0 (sizeof (bool )* natts );
2596+ recompress [att - 1 ]= true;
2597+ }
2598+ }
2599+
2600+ return recompress ;
2601+ }
2602+
25722603/*
25732604 * Subroutine for heap_insert(). Prepares a tuple for insertion. This sets the
25742605 * tuple header fields, assigns an OID, and toasts the tuple if necessary.
@@ -2577,9 +2608,11 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
25772608 * the original tuple.
25782609 */
25792610static HeapTuple
2580- heap_prepare_insert (Relation relation ,HeapTuple tup ,TransactionId xid ,
2581- CommandId cid ,int options )
2611+ heap_prepare_insert (Relation relation ,HeapTuple tup ,TupleDesc tupdesc ,
2612+ TransactionId xid , CommandId cid ,int options )
25822613{
2614+ bool * recompress ;
2615+
25832616/*
25842617 * For now, parallel operations are required to be strictly read-only.
25852618 * Unlike heap_update() and heap_delete(), an insert should never create a
@@ -2637,10 +2670,24 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
26372670Assert (!HeapTupleHasExternal (tup ));
26382671return tup ;
26392672}
2640- else if (HeapTupleHasExternal (tup )|| tup -> t_len > TOAST_TUPLE_THRESHOLD )
2641- return toast_insert_or_update (relation ,tup ,NULL ,options );
2642- else
2643- return tup ;
2673+
2674+ recompress = heap_tuple_needs_recompression (tup ,tupdesc ,
2675+ RelationGetDescr (relation ));
2676+
2677+ if (HeapTupleHasExternal (tup )|| tup -> t_len > TOAST_TUPLE_THRESHOLD ||
2678+ recompress )
2679+ {
2680+ if (!recompress )
2681+ recompress = palloc0 (sizeof (bool )* RelationGetDescr (relation )-> natts );
2682+
2683+ tup = toast_insert_or_update (relation ,tupdesc ,tup ,NULL ,options ,
2684+ recompress );
2685+ }
2686+
2687+ if (recompress )
2688+ pfree (recompress );
2689+
2690+ return tup ;
26442691}
26452692
26462693/*
@@ -2677,6 +2724,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
26772724heaptuples = palloc (ntuples * sizeof (HeapTuple ));
26782725for (i = 0 ;i < ntuples ;i ++ )
26792726heaptuples [i ]= heap_prepare_insert (relation ,tuples [i ],
2727+ RelationGetDescr (relation ),
26802728xid ,cid ,options );
26812729
26822730/*
@@ -2938,7 +2986,8 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
29382986Oid
29392987simple_heap_insert (Relation relation ,HeapTuple tup )
29402988{
2941- return heap_insert (relation ,tup ,GetCurrentCommandId (true),0 ,NULL );
2989+ return heap_insert (relation ,tup ,RelationGetDescr (relation ),
2990+ GetCurrentCommandId (true),0 ,NULL );
29422991}
29432992
29442993/*
@@ -3459,7 +3508,8 @@ simple_heap_delete(Relation relation, ItemPointer tid)
34593508 * See comments for struct HeapUpdateFailureData for additional info.
34603509 */
34613510HTSU_Result
3462- heap_update (Relation relation ,ItemPointer otid ,HeapTuple newtup ,
3511+ heap_update (Relation relation ,ItemPointer otid ,
3512+ HeapTuple newtup ,TupleDesc newtupdesc ,
34633513CommandId cid ,Snapshot crosscheck ,bool wait ,
34643514HeapUpdateFailureData * hufd ,LockTupleMode * lockmode )
34653515{
@@ -3500,6 +3550,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
35003550infomask2_old_tuple ,
35013551infomask_new_tuple ,
35023552infomask2_new_tuple ;
3553+ bool * recompress ;
35033554
35043555Assert (ItemPointerIsValid (otid ));
35053556
@@ -3963,11 +4014,21 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
39634014Assert (!HeapTupleHasExternal (& oldtup ));
39644015Assert (!HeapTupleHasExternal (newtup ));
39654016need_toast = false;
4017+ recompress = NULL ;
39664018}
39674019else
4020+ {
4021+ recompress = heap_tuple_needs_recompression (newtup ,newtupdesc ,
4022+ RelationGetDescr (relation ));
4023+
39684024need_toast = (HeapTupleHasExternal (& oldtup )||
39694025HeapTupleHasExternal (newtup )||
3970- newtup -> t_len > TOAST_TUPLE_THRESHOLD );
4026+ newtup -> t_len > TOAST_TUPLE_THRESHOLD )||
4027+ recompress ;
4028+
4029+ if (need_toast && !recompress )
4030+ recompress = palloc0 (sizeof (bool )* RelationGetDescr (relation )-> natts );
4031+ }
39714032
39724033pagefree = PageGetHeapFreeSpace (page );
39734034
@@ -4068,8 +4129,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
40684129if (need_toast )
40694130{
40704131/* Note we always use WAL and FSM during updates */
4071- heaptup = toast_insert_or_update (relation ,newtup ,& oldtup ,0 );
4132+ heaptup = toast_insert_or_update (relation ,newtupdesc ,newtup ,
4133+ & oldtup ,0 ,recompress );
40724134newtupsize = MAXALIGN (heaptup -> t_len );
4135+ pfree (recompress );
40734136}
40744137else
40754138heaptup = newtup ;
@@ -4453,7 +4516,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
44534516HeapUpdateFailureData hufd ;
44544517LockTupleMode lockmode ;
44554518
4456- result = heap_update (relation ,otid ,tup ,
4519+ result = heap_update (relation ,otid ,tup ,RelationGetDescr ( relation ),
44574520GetCurrentCommandId (true),InvalidSnapshot ,
44584521 true/* wait for commit */ ,
44594522& hufd ,& lockmode );