@@ -91,7 +91,8 @@ static HeapScanDesc heap_beginscan_internal(Relation relation,
91
91
bool temp_snap );
92
92
static BlockNumber heap_parallelscan_nextpage (HeapScanDesc scan );
93
93
static 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 );
95
96
static XLogRecPtr log_heap_update (Relation reln , Buffer oldbuf ,
96
97
Buffer newbuf , HeapTuple oldtup ,
97
98
HeapTuple newtup , HeapTuple old_key_tup ,
@@ -1062,7 +1063,7 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
1062
1063
(
1063
1064
(tupleDesc )-> attrs [(attnum ) - 1 ]-> attcacheoff >= 0 ?
1064
1065
(
1065
- fetchatt (( tupleDesc ) -> attrs [ (attnum ) - 1 ] ,
1066
+ fetchatt (tupleDesc , (attnum ) - 1 ,
1066
1067
(char * ) (tup )-> t_data + (tup )-> t_data -> t_hoff +
1067
1068
(tupleDesc )-> attrs [(attnum ) - 1 ]-> attcacheoff )
1068
1069
)
@@ -2393,8 +2394,8 @@ ReleaseBulkInsertStatePin(BulkInsertState bistate)
2393
2394
* within the tuple data is NOT reflected into *tup.
2394
2395
*/
2395
2396
Oid
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 )
2398
2399
{
2399
2400
TransactionId xid = GetCurrentTransactionId ();
2400
2401
HeapTuple heaptup ;
@@ -2409,7 +2410,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
2409
2410
* Note: below this point, heaptup is the data we actually intend to store
2410
2411
* into the relation; tup is the caller's original untoasted data.
2411
2412
*/
2412
- heaptup = heap_prepare_insert (relation , tup , xid , cid , options );
2413
+ heaptup = heap_prepare_insert (relation , tup , tupdesc , xid , cid , options );
2413
2414
2414
2415
/*
2415
2416
* 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,
2569
2570
return HeapTupleGetOid (tup );
2570
2571
}
2571
2572
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
+
2572
2603
/*
2573
2604
* Subroutine for heap_insert(). Prepares a tuple for insertion. This sets the
2574
2605
* tuple header fields, assigns an OID, and toasts the tuple if necessary.
@@ -2577,9 +2608,11 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
2577
2608
* the original tuple.
2578
2609
*/
2579
2610
static 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 )
2582
2613
{
2614
+ bool * recompress ;
2615
+
2583
2616
/*
2584
2617
* For now, parallel operations are required to be strictly read-only.
2585
2618
* 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,
2637
2670
Assert (!HeapTupleHasExternal (tup ));
2638
2671
return tup ;
2639
2672
}
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 ;
2644
2691
}
2645
2692
2646
2693
/*
@@ -2677,6 +2724,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
2677
2724
heaptuples = palloc (ntuples * sizeof (HeapTuple ));
2678
2725
for (i = 0 ; i < ntuples ; i ++ )
2679
2726
heaptuples [i ] = heap_prepare_insert (relation , tuples [i ],
2727
+ RelationGetDescr (relation ),
2680
2728
xid , cid , options );
2681
2729
2682
2730
/*
@@ -2938,7 +2986,8 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
2938
2986
Oid
2939
2987
simple_heap_insert (Relation relation , HeapTuple tup )
2940
2988
{
2941
- return heap_insert (relation , tup , GetCurrentCommandId (true), 0 , NULL );
2989
+ return heap_insert (relation , tup , RelationGetDescr (relation ),
2990
+ GetCurrentCommandId (true), 0 , NULL );
2942
2991
}
2943
2992
2944
2993
/*
@@ -3459,7 +3508,8 @@ simple_heap_delete(Relation relation, ItemPointer tid)
3459
3508
* See comments for struct HeapUpdateFailureData for additional info.
3460
3509
*/
3461
3510
HTSU_Result
3462
- heap_update (Relation relation , ItemPointer otid , HeapTuple newtup ,
3511
+ heap_update (Relation relation , ItemPointer otid ,
3512
+ HeapTuple newtup , TupleDesc newtupdesc ,
3463
3513
CommandId cid , Snapshot crosscheck , bool wait ,
3464
3514
HeapUpdateFailureData * hufd , LockTupleMode * lockmode )
3465
3515
{
@@ -3500,6 +3550,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
3500
3550
infomask2_old_tuple ,
3501
3551
infomask_new_tuple ,
3502
3552
infomask2_new_tuple ;
3553
+ bool * recompress ;
3503
3554
3504
3555
Assert (ItemPointerIsValid (otid ));
3505
3556
@@ -3963,11 +4014,21 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
3963
4014
Assert (!HeapTupleHasExternal (& oldtup ));
3964
4015
Assert (!HeapTupleHasExternal (newtup ));
3965
4016
need_toast = false;
4017
+ recompress = NULL ;
3966
4018
}
3967
4019
else
4020
+ {
4021
+ recompress = heap_tuple_needs_recompression (newtup , newtupdesc ,
4022
+ RelationGetDescr (relation ));
4023
+
3968
4024
need_toast = (HeapTupleHasExternal (& oldtup ) ||
3969
4025
HeapTupleHasExternal (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
+ }
3971
4032
3972
4033
pagefree = PageGetHeapFreeSpace (page );
3973
4034
@@ -4068,8 +4129,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
4068
4129
if (need_toast )
4069
4130
{
4070
4131
/* 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 );
4072
4134
newtupsize = MAXALIGN (heaptup -> t_len );
4135
+ pfree (recompress );
4073
4136
}
4074
4137
else
4075
4138
heaptup = newtup ;
@@ -4453,7 +4516,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
4453
4516
HeapUpdateFailureData hufd ;
4454
4517
LockTupleMode lockmode ;
4455
4518
4456
- result = heap_update (relation , otid , tup ,
4519
+ result = heap_update (relation , otid , tup , RelationGetDescr ( relation ),
4457
4520
GetCurrentCommandId (true), InvalidSnapshot ,
4458
4521
true /* wait for commit */ ,
4459
4522
& hufd , & lockmode );
0 commit comments