diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index 584f101dd9..1c57cc515e 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -133,8 +133,6 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, Assert(numAttrs <= MaxHeapAttributeNumber); heap_deform_tuple(newtup, tupleDesc, toast_values, toast_isnull); - if (oldtup != NULL) - heap_deform_tuple(oldtup, tupleDesc, toast_oldvalues, toast_oldisnull); /* ---------- * Prepare for toasting @@ -143,6 +141,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, ttc.ttc_rel = rel; ttc.ttc_values = toast_values; ttc.ttc_isnull = toast_isnull; + ttc.ttc_attr = toast_attr; if (oldtup == NULL) { ttc.ttc_oldvalues = NULL; @@ -150,10 +149,10 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, } else { + heap_deform_tuple(oldtup, tupleDesc, toast_oldvalues, toast_oldisnull); ttc.ttc_oldvalues = toast_oldvalues; ttc.ttc_oldisnull = toast_oldisnull; } - ttc.ttc_attr = toast_attr; toast_tuple_init(&ttc); /* ---------- diff --git a/src/backend/access/table/toast_helper.c b/src/backend/access/table/toast_helper.c index 739b6ae990..ca5d6f5fc6 100644 --- a/src/backend/access/table/toast_helper.c +++ b/src/backend/access/table/toast_helper.c @@ -48,62 +48,11 @@ toast_tuple_init(ToastTupleContext *ttc) for (i = 0; i < numAttrs; i++) { - Form_pg_attribute att = TupleDescAttr(tupleDesc, i); - struct varlena *old_value; - struct varlena *new_value; + Form_pg_attribute att; ttc->ttc_attr[i].tai_colflags = 0; ttc->ttc_attr[i].tai_oldexternal = NULL; - if (ttc->ttc_oldvalues != NULL) - { - /* - * For UPDATE get the old and new values of this attribute - */ - old_value = - (struct varlena *) DatumGetPointer(ttc->ttc_oldvalues[i]); - new_value = - (struct varlena *) DatumGetPointer(ttc->ttc_values[i]); - - /* - * If the old value is stored on disk, check if it has changed so - * we have to delete it later. - */ - if (att->attlen == -1 && !ttc->ttc_oldisnull[i] && - VARATT_IS_EXTERNAL_ONDISK(old_value)) - { - if (ttc->ttc_isnull[i] || - !VARATT_IS_EXTERNAL_ONDISK(new_value) || - memcmp((char *) old_value, (char *) new_value, - VARSIZE_EXTERNAL(old_value)) != 0) - { - /* - * The old external stored value isn't needed any more - * after the update - */ - ttc->ttc_attr[i].tai_colflags |= TOASTCOL_NEEDS_DELETE_OLD; - ttc->ttc_flags |= TOAST_NEEDS_DELETE_OLD; - } - else - { - /* - * This attribute isn't changed by this update so we reuse - * the original reference to the old value in the new - * tuple. - */ - ttc->ttc_attr[i].tai_colflags |= TOASTCOL_IGNORE; - continue; - } - } - } - else - { - /* - * For INSERT simply get the new value - */ - new_value = (struct varlena *) DatumGetPointer(ttc->ttc_values[i]); - } - /* * Handle NULL attributes */ @@ -114,11 +63,19 @@ toast_tuple_init(ToastTupleContext *ttc) continue; } + att = TupleDescAttr(tupleDesc, i); /* * Now look at varlena attributes */ if (att->attlen == -1) { + struct varlena *new_value; + + /* + * For INSERT simply get the new value + */ + new_value = (struct varlena *) DatumGetPointer(ttc->ttc_values[i]); + /* * If the table's attribute says PLAIN always, force it so. */ @@ -158,6 +115,56 @@ toast_tuple_init(ToastTupleContext *ttc) ttc->ttc_attr[i].tai_colflags |= TOASTCOL_IGNORE; } } + + if (ttc->ttc_oldvalues != NULL) + { + for (i = 0; i < numAttrs; i++) + { + Form_pg_attribute att = TupleDescAttr(tupleDesc, i); + struct varlena *old_value; + + /* + * For UPDATE get the old value of this attribute + */ + old_value = + (struct varlena *) DatumGetPointer(ttc->ttc_oldvalues[i]); + + /* + * If the old value is stored on disk, check if it has changed so + * we have to delete it later. + */ + if (att->attlen == -1 && !ttc->ttc_oldisnull[i] && + VARATT_IS_EXTERNAL_ONDISK(old_value)) + { + struct varlena *new_value; + + new_value = + (struct varlena *) DatumGetPointer(ttc->ttc_values[i]); + + if (ttc->ttc_isnull[i] || + !VARATT_IS_EXTERNAL_ONDISK(new_value) || + memcmp((char *) old_value, (char *) new_value, + VARSIZE_EXTERNAL(old_value)) != 0) + { + /* + * The old external stored value isn't needed any more + * after the update + */ + ttc->ttc_attr[i].tai_colflags |= TOASTCOL_NEEDS_DELETE_OLD; + ttc->ttc_flags |= TOAST_NEEDS_DELETE_OLD; + } + else + { + /* + * This attribute isn't changed by this update so we reuse + * the original reference to the old value in the new + * tuple. + */ + ttc->ttc_attr[i].tai_colflags |= TOASTCOL_IGNORE; + } + } + } + } }