diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index e2cd79ec54..fbe07b6fa6 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2462,63 +2462,65 @@ reform_and_rewrite_tuple(HeapTuple tuple, TupleDesc oldTupDesc = RelationGetDescr(OldHeap); TupleDesc newTupDesc = RelationGetDescr(NewHeap); HeapTuple copiedTuple; + const int numAttrs = newTupDesc->natts; int i; bool values_free[MaxTupleAttributeNumber]; + bool has_detoasted_values = false; - memset(values_free, 0, newTupDesc->natts * sizeof(bool)); + memset(values_free, 0, numAttrs * sizeof(bool)); heap_deform_tuple(tuple, oldTupDesc, values, isnull); - for (i = 0; i < newTupDesc->natts; i++) + for (i = 0; i < numAttrs; i++) { - /* Be sure to null out any dropped columns */ - if (TupleDescAttr(newTupDesc, i)->attisdropped) - isnull[i] = true; - else if (!isnull[i] && TupleDescAttr(newTupDesc, i)->attlen == -1) + if (!isnull[i]) { - /* - * Use this opportunity to force recompression of any data that's - * compressed with some TOAST compression method other than the - * one configured for the column. We don't actually need to - * perform the compression here; we just need to decompress. That - * will trigger recompression later on. - */ - struct varlena *new_value; - ToastCompressionId cmid; - char cmethod; - char targetmethod; - - new_value = (struct varlena *) DatumGetPointer(values[i]); - cmid = toast_get_compression_id(new_value); - - /* nothing to be done for uncompressed data */ - if (cmid == TOAST_INVALID_COMPRESSION_ID) - continue; - - /* convert existing compression id to compression method */ - switch (cmid) - { - case TOAST_PGLZ_COMPRESSION_ID: - cmethod = TOAST_PGLZ_COMPRESSION; - break; - case TOAST_LZ4_COMPRESSION_ID: - cmethod = TOAST_LZ4_COMPRESSION; - break; - default: - elog(ERROR, "invalid compression method id %d", cmid); - cmethod = '\0'; /* keep compiler quiet */ - } - - /* figure out what the target method is */ - targetmethod = TupleDescAttr(newTupDesc, i)->attcompression; - if (!CompressionMethodIsValid(targetmethod)) - targetmethod = default_toast_compression; - - /* if compression method doesn't match then detoast the value */ - if (targetmethod != cmethod) - { - values[i] = PointerGetDatum(detoast_attr(new_value)); - values_free[i] = true; + const Form_pg_attribute attr = TupleDescAttr(newTupDesc, i); + + /* Be sure to null out any dropped columns */ + if (attr->attisdropped) + isnull[i] = true; + else if (attr->attlen == -1) + { + /* + * Use this opportunity to force recompression of any data that's + * compressed with some TOAST compression method other than the + * one configured for the column. We don't actually need to + * perform the compression here; we just need to decompress. That + * will trigger recompression later on. + */ + const struct varlena *new_value; + ToastCompressionId cmid; + char cmethod; + + new_value = (struct varlena *) DatumGetPointer(values[i]); + cmid = toast_get_compression_id(new_value); + + /* convert existing compression id to compression method */ + switch (cmid) + { + /* nothing to be done for uncompressed data */ + case TOAST_INVALID_COMPRESSION_ID: + continue; + break; + case TOAST_PGLZ_COMPRESSION_ID: + cmethod = TOAST_PGLZ_COMPRESSION; + break; + case TOAST_LZ4_COMPRESSION_ID: + cmethod = TOAST_LZ4_COMPRESSION; + break; + default: + elog(ERROR, "invalid compression method id %d", cmid); + cmethod = '\0'; /* keep compiler quiet */ + } + + /* if compression method doesn't match or is invalid then detoast the value */ + if (cmethod != attr->attcompression) + { + values[i] = PointerGetDatum(detoast_attr(new_value)); + values_free[i] = true; + has_detoasted_values = true; + } } } } @@ -2529,10 +2531,11 @@ reform_and_rewrite_tuple(HeapTuple tuple, rewrite_heap_tuple(rwstate, tuple, copiedTuple); /* Free any value detoasted previously */ - for (i = 0; i < newTupDesc->natts; i++) + if (has_detoasted_values) { - if (values_free[i]) - pfree(DatumGetPointer(values[i])); + for (i = 0; i < numAttrs; i++) + if (values_free[i]) + pfree(DatumGetPointer(values[i])); } heap_freetuple(copiedTuple);