• Tom Lane's avatar
    Don't assume that a tuple's header size is unchanged during toasting. · 039680af
    Tom Lane authored
    This assumption can be wrong when the toaster is passed a raw on-disk
    tuple, because the tuple might pre-date an ALTER TABLE ADD COLUMN operation
    that added columns without rewriting the table.  In such a case the tuple's
    natts value is smaller than what we expect from the tuple descriptor, and
    so its t_hoff value could be smaller too.  In fact, the tuple might not
    have a null bitmap at all, and yet our current opinion of it is that it
    contains some trailing nulls.
    
    In such a situation, toast_insert_or_update did the wrong thing, because
    to save a few lines of code it would use the old t_hoff value as the offset
    where heap_fill_tuple should start filling data.  This did not leave enough
    room for the new nulls bitmap, with the result that the first few bytes of
    data could be overwritten with null flag bits, as in a recent report from
    Hubert Depesz Lubaczewski.
    
    The particular case reported requires ALTER TABLE ADD COLUMN followed by
    CREATE TABLE AS SELECT * FROM ... or INSERT ... SELECT * FROM ..., and
    further requires that there be some out-of-line toasted fields in one of
    the tuples to be copied; else we'll not reach the troublesome code.
    The problem can only manifest in this form in 8.4 and later, because
    before commit a77eaa6a, CREATE TABLE AS or
    INSERT/SELECT wouldn't result in raw disk tuples getting passed directly
    to heap_insert --- there would always have been at least a junkfilter in
    between, and that would reconstitute the tuple header with an up-to-date
    t_natts and hence t_hoff.  But I'm backpatching the tuptoaster change all
    the way anyway, because I'm not convinced there are no older code paths
    that present a similar risk.
    039680af
tuptoaster.c 51 KB