~ubuntu-branches/ubuntu/saucy/postgresql-8.4/saucy

« back to all changes in this revision

Viewing changes to src/backend/access/heap/tuptoaster.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2011-12-02 14:46:33 UTC
  • mfrom: (13.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20111202144633-azdcoyqh7sduwr15
Tags: 8.4.10-1
* New upstream bug fix release:
  - Fix bugs in information_schema.referential_constraints view.
    This view was being insufficiently careful about matching the
    foreign-key constraint to the depended-on primary or unique key
    constraint. That could result in failure to show a foreign key
    constraint at all, or showing it multiple times, or claiming that
    it depends on a different constraint than the one it really does.
    Since the view definition is installed by initdb, merely upgrading
    will not fix the problem. If you need to fix this in an existing
    installation, you can (as a superuser) drop the information_schema
    schema then re-create it by sourcing
    "SHAREDIR/information_schema.sql". (Run pg_config --sharedir if
    you're uncertain where "SHAREDIR" is.) This must be repeated in
    each database to be fixed.
  - Fix incorrect replay of WAL records for GIN index updates.
    This could result in transiently failing to find index entries
    after a crash, or on a hot-standby server. The problem would be
    repaired by the next "VACUUM" of the index, however.
  - Fix TOAST-related data corruption during CREATE TABLE dest AS
    SELECT - FROM src or INSERT INTO dest SELECT * FROM src.
    If a table has been modified by "ALTER TABLE ADD COLUMN", attempts
    to copy its data verbatim to another table could produce corrupt
    results in certain corner cases. The problem can only manifest in
    this precise form in 8.4 and later, but we patched earlier versions
    as well in case there are other code paths that could trigger the
    same bug.
  - Fix race condition during toast table access from stale syscache
    entries.
  - Track dependencies of functions on items used in parameter default
    expressions. Previously, a referenced object could be dropped without
    having dropped or modified the function, leading to misbehavior when the
    function was used. Note that merely installing this update will not fix
    the missing dependency entries; to do that, you'd need to "CREATE OR
    REPLACE" each such function afterwards. If you have functions whose
    defaults depend on non-built-in objects, doing so is recommended.
  - Allow inlining of set-returning SQL functions with multiple OUT
    parameters.
  - Make DatumGetInetP() unpack inet datums that have a 1-byte header,
    and add a new macro, DatumGetInetPP(), that does not.
  - Improve locale support in money type's input and output.
    Aside from not supporting all standard lc_monetary formatting
    options, the input and output functions were inconsistent, meaning
    there were locales in which dumped money values could not be
    re-read.
  - Don't let transform_null_equals affect CASE foo WHEN NULL ...
    constructs. transform_null_equals is only supposed to affect foo = NULL
    expressions written directly by the user, not equality checks
    generated internally by this form of CASE.
  - Change foreign-key trigger creation order to better support
    self-referential foreign keys. For a cascading foreign key that
    references its own table, a row update will fire both the ON UPDATE
    trigger and the CHECK trigger as one event. The ON UPDATE trigger must
    execute first, else the CHECK will check a non-final state of the row
    and possibly throw an inappropriate error. However, the firing order of
    these triggers is determined by their names, which generally sort in
    creation order since the triggers have auto-generated names following
    the convention "RI_ConstraintTrigger_NNNN". A proper fix would require
    modifying that convention, which we will do in 9.2, but it seems risky
    to change it in existing releases. So this patch just changes the
    creation order of the triggers. Users encountering this type of error
    should drop and re-create the foreign key constraint to get its triggers
    into the right order.
  - Avoid floating-point underflow while tracking buffer allocation
    rate.
  - Preserve blank lines within commands in psql's command history.
    The former behavior could cause problems if an empty line was
    removed from within a string literal, for example.
  - Fix pg_dump to dump user-defined casts between auto-generated
    types, such as table rowtypes.
  - Use the preferred version of xsubpp to build PL/Perl, not
    necessarily the operating system's main copy.
  - Fix incorrect coding in "contrib/dict_int" and "contrib/dict_xsyn".
  - Honor query cancel interrupts promptly in pgstatindex().
  - Ensure VPATH builds properly install all server header files.
  - Shorten file names reported in verbose error messages.
    Regular builds have always reported just the name of the C file
    containing the error message call, but VPATH builds formerly
    reported an absolute path name.

Show diffs side-by-side

added added

removed removed

Lines of Context:
592
592
        if (newtup->t_data->t_infomask & HEAP_HASOID)
593
593
                hoff += sizeof(Oid);
594
594
        hoff = MAXALIGN(hoff);
595
 
        Assert(hoff == newtup->t_data->t_hoff);
596
595
        /* now convert to a limit on the tuple data size */
597
596
        maxDataLen = TOAST_TUPLE_TARGET - hoff;
598
597
 
852
851
        {
853
852
                HeapTupleHeader olddata = newtup->t_data;
854
853
                HeapTupleHeader new_data;
855
 
                int32           new_len;
 
854
                int32           new_header_len;
856
855
                int32           new_data_len;
 
856
                int32           new_tuple_len;
857
857
 
858
858
                /*
859
 
                 * Calculate the new size of the tuple.  Header size should not
860
 
                 * change, but data size might.
 
859
                 * Calculate the new size of the tuple.
 
860
                 *
 
861
                 * Note: we used to assume here that the old tuple's t_hoff must equal
 
862
                 * the new_header_len value, but that was incorrect.  The old tuple
 
863
                 * might have a smaller-than-current natts, if there's been an ALTER
 
864
                 * TABLE ADD COLUMN since it was stored; and that would lead to a
 
865
                 * different conclusion about the size of the null bitmap, or even
 
866
                 * whether there needs to be one at all.
861
867
                 */
862
 
                new_len = offsetof(HeapTupleHeaderData, t_bits);
 
868
                new_header_len = offsetof(HeapTupleHeaderData, t_bits);
863
869
                if (has_nulls)
864
 
                        new_len += BITMAPLEN(numAttrs);
 
870
                        new_header_len += BITMAPLEN(numAttrs);
865
871
                if (olddata->t_infomask & HEAP_HASOID)
866
 
                        new_len += sizeof(Oid);
867
 
                new_len = MAXALIGN(new_len);
868
 
                Assert(new_len == olddata->t_hoff);
 
872
                        new_header_len += sizeof(Oid);
 
873
                new_header_len = MAXALIGN(new_header_len);
869
874
                new_data_len = heap_compute_data_size(tupleDesc,
870
875
                                                                                          toast_values, toast_isnull);
871
 
                new_len += new_data_len;
 
876
                new_tuple_len = new_header_len + new_data_len;
872
877
 
873
878
                /*
874
879
                 * Allocate and zero the space needed, and fill HeapTupleData fields.
875
880
                 */
876
 
                result_tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + new_len);
877
 
                result_tuple->t_len = new_len;
 
881
                result_tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + new_tuple_len);
 
882
                result_tuple->t_len = new_tuple_len;
878
883
                result_tuple->t_self = newtup->t_self;
879
884
                result_tuple->t_tableOid = newtup->t_tableOid;
880
885
                new_data = (HeapTupleHeader) ((char *) result_tuple + HEAPTUPLESIZE);
881
886
                result_tuple->t_data = new_data;
882
887
 
883
888
                /*
884
 
                 * Put the existing tuple header and the changed values into place
 
889
                 * Copy the existing tuple header, but adjust natts and t_hoff.
885
890
                 */
886
 
                memcpy(new_data, olddata, olddata->t_hoff);
 
891
                memcpy(new_data, olddata, offsetof(HeapTupleHeaderData, t_bits));
 
892
                HeapTupleHeaderSetNatts(new_data, numAttrs);
 
893
                new_data->t_hoff = new_header_len;
 
894
                if (olddata->t_infomask & HEAP_HASOID)
 
895
                        HeapTupleHeaderSetOid(new_data, HeapTupleHeaderGetOid(olddata));
887
896
 
 
897
                /* Copy over the data, and fill the null bitmap if needed */
888
898
                heap_fill_tuple(tupleDesc,
889
899
                                                toast_values,
890
900
                                                toast_isnull,
891
 
                                                (char *) new_data + olddata->t_hoff,
 
901
                                                (char *) new_data + new_header_len,
892
902
                                                new_data_len,
893
903
                                                &(new_data->t_infomask),
894
904
                                                has_nulls ? new_data->t_bits : NULL);
917
927
 
918
928
 
919
929
/* ----------
 
930
 * toast_flatten_tuple -
 
931
 *
 
932
 *      "Flatten" a tuple to contain no out-of-line toasted fields.
 
933
 *      (This does not eliminate compressed or short-header datums.)
 
934
 * ----------
 
935
 */
 
936
HeapTuple
 
937
toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
 
938
{
 
939
        HeapTuple       new_tuple;
 
940
        Form_pg_attribute *att = tupleDesc->attrs;
 
941
        int                     numAttrs = tupleDesc->natts;
 
942
        int                     i;
 
943
        Datum           toast_values[MaxTupleAttributeNumber];
 
944
        bool            toast_isnull[MaxTupleAttributeNumber];
 
945
        bool            toast_free[MaxTupleAttributeNumber];
 
946
 
 
947
        /*
 
948
         * Break down the tuple into fields.
 
949
         */
 
950
        Assert(numAttrs <= MaxTupleAttributeNumber);
 
951
        heap_deform_tuple(tup, tupleDesc, toast_values, toast_isnull);
 
952
 
 
953
        memset(toast_free, 0, numAttrs * sizeof(bool));
 
954
 
 
955
        for (i = 0; i < numAttrs; i++)
 
956
        {
 
957
                /*
 
958
                 * Look at non-null varlena attributes
 
959
                 */
 
960
                if (!toast_isnull[i] && att[i]->attlen == -1)
 
961
                {
 
962
                        struct varlena *new_value;
 
963
 
 
964
                        new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
 
965
                        if (VARATT_IS_EXTERNAL(new_value))
 
966
                        {
 
967
                                new_value = toast_fetch_datum(new_value);
 
968
                                toast_values[i] = PointerGetDatum(new_value);
 
969
                                toast_free[i] = true;
 
970
                        }
 
971
                }
 
972
        }
 
973
 
 
974
        /*
 
975
         * Form the reconfigured tuple.
 
976
         */
 
977
        new_tuple = heap_form_tuple(tupleDesc, toast_values, toast_isnull);
 
978
 
 
979
        /*
 
980
         * Be sure to copy the tuple's OID and identity fields.  We also make a
 
981
         * point of copying visibility info, just in case anybody looks at those
 
982
         * fields in a syscache entry.
 
983
         */
 
984
        if (tupleDesc->tdhasoid)
 
985
                HeapTupleSetOid(new_tuple, HeapTupleGetOid(tup));
 
986
 
 
987
        new_tuple->t_self = tup->t_self;
 
988
        new_tuple->t_tableOid = tup->t_tableOid;
 
989
 
 
990
        new_tuple->t_data->t_choice = tup->t_data->t_choice;
 
991
        new_tuple->t_data->t_ctid = tup->t_data->t_ctid;
 
992
        new_tuple->t_data->t_infomask &= ~HEAP_XACT_MASK;
 
993
        new_tuple->t_data->t_infomask |=
 
994
                tup->t_data->t_infomask & HEAP_XACT_MASK;
 
995
        new_tuple->t_data->t_infomask2 &= ~HEAP2_XACT_MASK;
 
996
        new_tuple->t_data->t_infomask2 |=
 
997
                tup->t_data->t_infomask2 & HEAP2_XACT_MASK;
 
998
 
 
999
        /*
 
1000
         * Free allocated temp values
 
1001
         */
 
1002
        for (i = 0; i < numAttrs; i++)
 
1003
                if (toast_free[i])
 
1004
                        pfree(DatumGetPointer(toast_values[i]));
 
1005
 
 
1006
        return new_tuple;
 
1007
}
 
1008
 
 
1009
 
 
1010
/* ----------
920
1011
 * toast_flatten_tuple_attribute -
921
1012
 *
922
1013
 *      If a Datum is of composite type, "flatten" it to contain no toasted fields.
935
1026
        TupleDesc       tupleDesc;
936
1027
        HeapTupleHeader olddata;
937
1028
        HeapTupleHeader new_data;
938
 
        int32           new_len;
 
1029
        int32           new_header_len;
939
1030
        int32           new_data_len;
 
1031
        int32           new_tuple_len;
940
1032
        HeapTupleData tmptup;
941
1033
        Form_pg_attribute *att;
942
1034
        int                     numAttrs;
1007
1099
        }
1008
1100
 
1009
1101
        /*
1010
 
         * Calculate the new size of the tuple.  Header size should not change,
1011
 
         * but data size might.
 
1102
         * Calculate the new size of the tuple.
 
1103
         *
 
1104
         * This should match the reconstruction code in toast_insert_or_update.
1012
1105
         */
1013
 
        new_len = offsetof(HeapTupleHeaderData, t_bits);
 
1106
        new_header_len = offsetof(HeapTupleHeaderData, t_bits);
1014
1107
        if (has_nulls)
1015
 
                new_len += BITMAPLEN(numAttrs);
 
1108
                new_header_len += BITMAPLEN(numAttrs);
1016
1109
        if (olddata->t_infomask & HEAP_HASOID)
1017
 
                new_len += sizeof(Oid);
1018
 
        new_len = MAXALIGN(new_len);
1019
 
        Assert(new_len == olddata->t_hoff);
 
1110
                new_header_len += sizeof(Oid);
 
1111
        new_header_len = MAXALIGN(new_header_len);
1020
1112
        new_data_len = heap_compute_data_size(tupleDesc,
1021
1113
                                                                                  toast_values, toast_isnull);
1022
 
        new_len += new_data_len;
 
1114
        new_tuple_len = new_header_len + new_data_len;
1023
1115
 
1024
 
        new_data = (HeapTupleHeader) palloc0(new_len);
 
1116
        new_data = (HeapTupleHeader) palloc0(new_tuple_len);
1025
1117
 
1026
1118
        /*
1027
 
         * Put the tuple header and the changed values into place
 
1119
         * Copy the existing tuple header, but adjust natts and t_hoff.
1028
1120
         */
1029
 
        memcpy(new_data, olddata, olddata->t_hoff);
1030
 
 
1031
 
        HeapTupleHeaderSetDatumLength(new_data, new_len);
1032
 
 
 
1121
        memcpy(new_data, olddata, offsetof(HeapTupleHeaderData, t_bits));
 
1122
        HeapTupleHeaderSetNatts(new_data, numAttrs);
 
1123
        new_data->t_hoff = new_header_len;
 
1124
        if (olddata->t_infomask & HEAP_HASOID)
 
1125
                HeapTupleHeaderSetOid(new_data, HeapTupleHeaderGetOid(olddata));
 
1126
 
 
1127
        /* Reset the datum length field, too */
 
1128
        HeapTupleHeaderSetDatumLength(new_data, new_tuple_len);
 
1129
 
 
1130
        /* Copy over the data, and fill the null bitmap if needed */
1033
1131
        heap_fill_tuple(tupleDesc,
1034
1132
                                        toast_values,
1035
1133
                                        toast_isnull,
1036
 
                                        (char *) new_data + olddata->t_hoff,
 
1134
                                        (char *) new_data + new_header_len,
1037
1135
                                        new_data_len,
1038
1136
                                        &(new_data->t_infomask),
1039
1137
                                        has_nulls ? new_data->t_bits : NULL);