diff options
| author | Tom Lane | 2007-09-30 19:54:58 +0000 |
|---|---|---|
| committer | Tom Lane | 2007-09-30 19:54:58 +0000 |
| commit | 27b8922221ee94c679ca533912d43ed5e8457510 (patch) | |
| tree | 18c9b5f58a7d0f3275a95fcc0046317ffec100d0 /src/backend | |
| parent | 3ff0018c2ea4ad5587c83c3b56cb9d98bf7f0255 (diff) | |
Add an extra header byte to TOAST-pointer datums to represent their size
explicitly. This means a TOAST pointer takes 18 bytes instead of 17 --- still
smaller than in 8.2 --- which seems a good tradeoff to ensure we won't have
painted ourselves into a corner if we want to support multiple types of TOAST
pointer later on. Per discussion with Greg Stark.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/access/heap/tuptoaster.c | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 2d09b773614..d2f1dfafd4a 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.75 2007/09/26 23:29:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.76 2007/09/30 19:54:58 tgl Exp $ * * * INTERFACE ROUTINES @@ -52,6 +52,21 @@ #define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \ ((toast_pointer).va_extsize < (toast_pointer).va_rawsize - VARHDRSZ) +/* + * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum + * into a local "struct varatt_external" toast pointer. This should be + * just a memcpy, but some versions of gcc seem to produce broken code + * that assumes the datum contents are aligned. Introducing an explicit + * intermediate "varattrib_1b_e *" variable seems to fix it. + */ +#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \ +do { \ + varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \ + Assert(VARSIZE_ANY_EXHDR(attre) == sizeof(toast_pointer)); \ + memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \ +} while (0) + + static void toast_delete_datum(Relation rel, Datum value); static Datum toast_save_datum(Relation rel, Datum value, bool use_wal, bool use_fsm); @@ -172,7 +187,7 @@ heap_tuple_untoast_attr_slice(struct varlena *attr, { struct varatt_external toast_pointer; - memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); /* fast path for non-compressed external datums */ if (!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)) @@ -249,7 +264,7 @@ toast_raw_datum_size(Datum value) /* va_rawsize is the size of the original datum -- including header */ struct varatt_external toast_pointer; - memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); result = toast_pointer.va_rawsize; } else if (VARATT_IS_COMPRESSED(attr)) @@ -294,7 +309,7 @@ toast_datum_size(Datum value) */ struct varatt_external toast_pointer; - memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); result = toast_pointer.va_extsize; } else if (VARATT_IS_SHORT(attr)) @@ -470,9 +485,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, VARATT_IS_EXTERNAL(old_value)) { if (toast_isnull[i] || !VARATT_IS_EXTERNAL(new_value) || - memcmp(VARDATA_SHORT(old_value), - VARDATA_SHORT(new_value), - sizeof(struct varatt_external)) != 0) + memcmp((char *) old_value, (char *) new_value, + VARSIZE_EXTERNAL(old_value)) != 0) { /* * The old external stored value isn't needed any more @@ -1071,7 +1085,7 @@ toast_save_datum(Relation rel, Datum value, Datum t_values[3]; bool t_isnull[3]; CommandId mycid = GetCurrentCommandId(); - struct varlena *result; + varattrib_pointer *result; struct varatt_external toast_pointer; struct { @@ -1192,9 +1206,9 @@ toast_save_datum(Relation rel, Datum value, /* * Create the TOAST pointer value that we'll return */ - result = (struct varlena *) palloc(sizeof(varattrib_pointer)); - SET_VARSIZE_EXTERNAL(result); - memcpy(VARDATA_SHORT(result), &toast_pointer, sizeof(toast_pointer)); + result = (varattrib_pointer *) palloc(sizeof(varattrib_pointer)); + SET_VARSIZE_EXTERNAL(result, sizeof(varattrib_pointer)); + memcpy(VARDATA_EXTERNAL(result), &toast_pointer, sizeof(toast_pointer)); return PointerGetDatum(result); } @@ -1221,8 +1235,7 @@ toast_delete_datum(Relation rel, Datum value) return; /* Must copy to access aligned fields */ - memcpy(&toast_pointer, VARDATA_SHORT(attr), - sizeof(struct varatt_external)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); /* * Open the toast relation and its index @@ -1289,8 +1302,7 @@ toast_fetch_datum(struct varlena *attr) int32 chunksize; /* Must copy to access aligned fields */ - memcpy(&toast_pointer, VARDATA_SHORT(attr), - sizeof(struct varatt_external)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); ressize = toast_pointer.va_extsize; numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1; @@ -1452,8 +1464,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length) Assert(VARATT_IS_EXTERNAL(attr)); /* Must copy to access aligned fields */ - memcpy(&toast_pointer, VARDATA_SHORT(attr), - sizeof(struct varatt_external)); + VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); /* * It's nonsense to fetch slices of a compressed datum -- this isn't lo_* |
