@@ -220,7 +220,11 @@ heap_tuple_untoast_attr(struct varlena * attr)
220220 */
221221attr = heap_tuple_fetch_attr (attr );
222222/* 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 */
224228}
225229else if (VARATT_IS_COMPRESSED (attr ))
226230{
@@ -439,6 +443,10 @@ toast_datum_size(Datum value)
439443{
440444result = EOH_get_flat_size (DatumGetEOHP (value ));
441445}
446+ else if (VARATT_IS_EXTERNAL_EXTENDED (attr ))
447+ {
448+ result = VARSIZE_ANY (attr );
449+ }
442450else if (VARATT_IS_SHORT (attr ))
443451{
444452result = VARSIZE_SHORT (attr );
@@ -672,6 +680,8 @@ toast_insert_or_update(Relation rel, TupleDesc newtupdesc, HeapTuple newtup,
672680 */
673681if (att [i ]-> attlen == -1 )
674682{
683+ bool need_compress = false;
684+
675685/*
676686 * If the table's attribute says PLAIN always, force it so.
677687 */
@@ -688,37 +698,65 @@ toast_insert_or_update(Relation rel, TupleDesc newtupdesc, HeapTuple newtup,
688698 */
689699if (VARATT_IS_EXTERNAL (new_value ))
690700{
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+ }
694706else
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 ))
705707{
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 )
710714{
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 ;
715717toast_values [i ]= PointerGetDatum (new_value );
716718toast_free [i ]= true;
719+ need_change = true;
717720need_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;
719730}
720731}
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+ }
722760}
723761
724762/*
@@ -1254,9 +1292,33 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup,
12541292if (VARATT_IS_EXTERNAL (new_value )||
12551293VARATT_IS_COMPRESSED (new_value ))
12561294{
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+ }
12601322}
12611323}
12621324}