@@ -220,7 +220,11 @@ heap_tuple_untoast_attr(struct varlena * attr)
220
220
*/
221
221
attr = heap_tuple_fetch_attr (attr );
222
222
/* flatteners are not allowed to produce compressed/short output */
223
- Assert (!VARATT_IS_EXTENDED (attr ));
223
+ Assert (!VARATT_IS_EXTENDED (attr )|| VARATT_IS_EXTERNAL_EXTENDED (attr ));
224
+ }
225
+ else if (VARATT_IS_EXTERNAL_EXTENDED (attr ))
226
+ {
227
+ /* This is an extended datum --- return it */
224
228
}
225
229
else if (VARATT_IS_COMPRESSED (attr ))
226
230
{
@@ -439,6 +443,10 @@ toast_datum_size(Datum value)
439
443
{
440
444
result = EOH_get_flat_size (DatumGetEOHP (value ));
441
445
}
446
+ else if (VARATT_IS_EXTERNAL_EXTENDED (attr ))
447
+ {
448
+ result = VARSIZE_ANY (attr );
449
+ }
442
450
else if (VARATT_IS_SHORT (attr ))
443
451
{
444
452
result = VARSIZE_SHORT (attr );
@@ -672,6 +680,8 @@ toast_insert_or_update(Relation rel, TupleDesc newtupdesc, HeapTuple newtup,
672
680
*/
673
681
if (att [i ]-> attlen == -1 )
674
682
{
683
+ bool need_compress = false;
684
+
675
685
/*
676
686
* If the table's attribute says PLAIN always, force it so.
677
687
*/
@@ -688,37 +698,65 @@ toast_insert_or_update(Relation rel, TupleDesc newtupdesc, HeapTuple newtup,
688
698
*/
689
699
if (VARATT_IS_EXTERNAL (new_value ))
690
700
{
691
- toast_oldexternal [i ]= new_value ;
692
- if (att [i ]-> attstorage == 'p' )
693
- new_value = heap_tuple_untoast_attr (new_value );
701
+ if (VARATT_IS_EXTERNAL_EXPANDED (new_value ))
702
+ {
703
+ Assert (recompress [i ]);
704
+ need_compress = true;
705
+ }
694
706
else
695
- new_value = heap_tuple_fetch_attr (new_value );
696
- toast_values [i ]= PointerGetDatum (new_value );
697
- toast_free [i ]= true;
698
- need_change = true;
699
- need_free = true;
700
- }
701
-
702
- if (recompress [i ])
703
- {
704
- if (OidIsValid (att [i ]-> attcompression ))
705
707
{
706
- struct varlena * compressed_value = (struct varlena * )
707
- tuple_compress_attr (tupleDesc ,i ,
708
- PointerGetDatum (new_value ));
709
- if (compressed_value != new_value )
708
+ struct varlena * untoasted_value =
709
+ att [i ]-> attstorage == 'p'
710
+ ?heap_tuple_untoast_attr (new_value )
711
+ :heap_tuple_fetch_attr (new_value );
712
+
713
+ if (untoasted_value != new_value )
710
714
{
711
- new_value = compressed_value ;
712
- toast_oldexternal [i ]= NULL ;
713
- if (toast_free [i ])
714
- pfree (DatumGetPointer (toast_values [i ]));
715
+ toast_oldexternal [i ]= new_value ;
716
+ new_value = untoasted_value ;
715
717
toast_values [i ]= PointerGetDatum (new_value );
716
718
toast_free [i ]= true;
719
+ need_change = true;
717
720
need_free = true;
718
- Assert (!VARATT_IS_EXTERNAL (new_value ));
721
+ }
722
+
723
+ if (VARATT_IS_EXTERNAL_EXTENDED (new_value ))
724
+ {
725
+ Assert (recompress [i ]||
726
+ !OidIsValid (newtupdesc -> attrs [i ]-> attrelid ));
727
+
728
+ if (!recompress [i ]|| !OidIsValid (att [i ]-> attcompression ))
729
+ need_compress = true;
719
730
}
720
731
}
721
- need_change = true;
732
+ }
733
+
734
+ if (recompress [i ])
735
+ {
736
+ if (OidIsValid (att [i ]-> attcompression ))
737
+ need_compress = true;
738
+ else
739
+ need_change = true;
740
+ }
741
+
742
+ if (need_compress )
743
+ {
744
+ struct varlena * compressed_value = (struct varlena * )
745
+ tuple_compress_attr (tupleDesc ,i ,
746
+ PointerGetDatum (new_value ));
747
+
748
+ if (compressed_value != new_value )
749
+ {
750
+ new_value = compressed_value ;
751
+ toast_oldexternal [i ]= NULL ;
752
+ if (toast_free [i ])
753
+ pfree (DatumGetPointer (toast_values [i ]));
754
+ toast_values [i ]= PointerGetDatum (new_value );
755
+ toast_free [i ]= true;
756
+ need_free = true;
757
+ need_change = true;
758
+ Assert (!VARATT_IS_EXTERNAL (new_value ));
759
+ }
722
760
}
723
761
724
762
/*
@@ -1254,9 +1292,33 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup,
1254
1292
if (VARATT_IS_EXTERNAL (new_value )||
1255
1293
VARATT_IS_COMPRESSED (new_value ))
1256
1294
{
1257
- new_value = heap_tuple_untoast_attr (new_value );
1258
- toast_values [i ]= PointerGetDatum (new_value );
1259
- toast_free [i ]= true;
1295
+ struct varlena * untoasted_value =
1296
+ heap_tuple_untoast_attr (new_value );
1297
+ if (untoasted_value != new_value )
1298
+ {
1299
+ new_value = untoasted_value ;
1300
+ toast_values [i ]= PointerGetDatum (new_value );
1301
+ toast_free [i ]= true;
1302
+ }
1303
+ }
1304
+
1305
+ if (OidIsValid (att [i ]-> attcompression )||
1306
+ (att [i ]-> attlen == -1 &&
1307
+ OidIsValid (att [i ]-> attrelid )&&
1308
+ VARATT_IS_EXTERNAL_EXTENDED (DatumGetPointer (new_value ))))
1309
+ {
1310
+ void * compressed_value = DatumGetPointer (
1311
+ tuple_compress_attr (tupleDesc ,i ,
1312
+ PointerGetDatum (new_value )));
1313
+
1314
+ if (compressed_value != new_value )
1315
+ {
1316
+ if (toast_free [i ])
1317
+ pfree (DatumGetPointer (toast_values [i ]));
1318
+ new_value = compressed_value ;
1319
+ toast_values [i ]= PointerGetDatum (new_value );
1320
+ toast_free [i ]= true;
1321
+ }
1260
1322
}
1261
1323
}
1262
1324
}