On Fri, Feb 20, 2015 at 2:21 PM, Michael Paquier <michael.paqu...@gmail.com> wrote: > On Fri, Feb 20, 2015 at 2:14 PM, Tom Lane wrote: >> Michael Paquier writes: >>> Thanks for the clarifications and the review. Attached is a new set. >> >> I've reviewed and pushed the 0001 patch (you missed a few things :-(). > > My apologies. I completely forgot to check for any calls of offsetof > with the structures changed...
Attached are 3 more patches to improve the coverage (being careful this time with calls of offsetof and sizeof...): - 0001 covers varlena in c.h - 0002 covers HeapTupleHeaderData and MinimalTupleData, with things changed in code paths of reorderbuffer and decoder - 0003 changes RecordIOData, used in hstore, rowtypes and json functions Even with this set applied, the following things remain in backend code: $ git grep "VARIABLE LENGTH" | grep "[1]" access/nbtree/nbtutils.c: BTOneVacInfo vacuums[1]; /* VARIABLE LENGTH ARRAY */ access/transam/multixact.c: MultiXactId perBackendXactIds[1]; /* VARIABLE LENGTH ARRAY */ access/transam/twophase.c: GlobalTransaction prepXacts[1]; /* VARIABLE LENGTH ARRAY */ commands/tablespace.c: Oid tblSpcs[1]; /* VARIABLE LENGTH ARRAY */ commands/trigger.c: SetConstraintTriggerData trigstates[1]; /* VARIABLE LENGTH ARRAY */ executor/nodeAgg.c: AggStatePerGroupData pergroup[1]; /* VARIABLE LENGTH ARRAY */ optimizer/plan/setrefs.c: tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */ postmaster/checkpointer.c: CheckpointerRequest requests[1]; /* VARIABLE LENGTH ARRAY */ storage/ipc/pmsignal.c: sig_atomic_t PMChildFlags[1]; /* VARIABLE LENGTH ARRAY */ storage/ipc/procarray.c: int pgprocnos[1]; /* VARIABLE LENGTH ARRAY */ utils/adt/rowtypes.c: ColumnCompareData columns[1]; /* VARIABLE LENGTH ARRAY */ utils/cache/inval.c: SharedInvalidationMessage msgs[1]; /* VARIABLE LENGTH ARRAY */ utils/cache/typcache.c: EnumItem enum_values[1]; /* VARIABLE LENGTH ARRAY */ Regards, -- Michael
From 0e5ed0864a5b840e447ffdc2186b8d50c4b632b4 Mon Sep 17 00:00:00 2001 From: Michael Paquier <michael@otacoo.com> Date: Thu, 19 Feb 2015 14:02:14 +0900 Subject: [PATCH 1/3] Switch varlena to use FLEXIBLE_ARRAY_MEMBER As compilers normally complain about a flexible-array element not at the end of a structure (clang does, while gcc sometimes does not), this has needed some modifications in structures using bytea as such. This commit ensures as well that those structures have enough room to work as intended as well. --- src/backend/access/heap/tuptoaster.c | 4 ++-- src/backend/storage/large_object/inv_api.c | 8 ++++---- src/include/c.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index f8c1401..547f21f 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -1365,10 +1365,10 @@ toast_save_datum(Relation rel, Datum value, CommandId mycid = GetCurrentCommandId(true); struct varlena *result; struct varatt_external toast_pointer; - struct + union { struct varlena hdr; - char data[TOAST_MAX_CHUNK_SIZE]; /* make struct big enough */ + char data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ]; /* make struct big enough */ int32 align_it; /* ensure struct is aligned well enough */ } chunk_data; int32 chunk_size; diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index a19c401..2e877bc 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -562,10 +562,10 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) bool neednextpage; bytea *datafield; bool pfreeit; - struct + union { bytea hdr; - char data[LOBLKSIZE]; /* make struct big enough */ + char data[LOBLKSIZE + VARHDRSZ]; /* make struct big enough */ int32 align_it; /* ensure struct is aligned well enough */ } workbuf; char *workb = VARDATA(&workbuf.hdr); @@ -748,10 +748,10 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len) SysScanDesc sd; HeapTuple oldtuple; Form_pg_largeobject olddata; - struct + union { bytea hdr; - char data[LOBLKSIZE]; /* make struct big enough */ + char data[LOBLKSIZE + VARHDRSZ]; /* make struct big enough */ int32 align_it; /* ensure struct is aligned well enough */ } workbuf; char *workb = VARDATA(&workbuf.hdr); diff --git a/src/include/c.h b/src/include/c.h index 2de86f9..663d8f8 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -391,7 +391,7 @@ typedef struct struct varlena { char vl_len_[4]; /* Do not touch this field directly! */ - char vl_dat[1]; + char vl_dat[FLEXIBLE_ARRAY_MEMBER]; }; #define VARHDRSZ ((int32) sizeof(int32)) -- 2.3.0
From 3efab471b04755812aec5a45850f8a6bdcd49b79 Mon Sep 17 00:00:00 2001 From: Michael Paquier <michael@otacoo.com> Date: Fri, 20 Feb 2015 16:42:28 +0900 Subject: [PATCH 2/3] Switch HeapTupleHeaderData and MinimalTupleData to use flexible arrays This is some more hacking related to FLEXIBLE_ARRAY_MEMBER. --- contrib/file_fdw/file_fdw.c | 2 +- contrib/postgres_fdw/postgres_fdw.c | 3 ++- src/backend/access/heap/heapam.c | 12 ++++++------ src/backend/executor/nodeHash.c | 2 +- src/backend/optimizer/path/costsize.c | 7 ++++--- src/backend/optimizer/plan/planner.c | 6 ++++-- src/backend/optimizer/plan/subselect.c | 9 +++++---- src/backend/optimizer/prep/prepunion.c | 3 ++- src/backend/optimizer/util/plancat.c | 2 +- src/backend/replication/logical/decode.c | 24 +++++++++++------------ src/backend/replication/logical/reorderbuffer.c | 26 +++++++++++-------------- src/include/access/htup_details.h | 4 ++-- src/include/replication/reorderbuffer.h | 7 +++++-- 13 files changed, 56 insertions(+), 51 deletions(-) diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index d569760..4cc168f 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -932,7 +932,7 @@ estimate_size(PlannerInfo *root, RelOptInfo *baserel, int tuple_width; tuple_width = MAXALIGN(baserel->width) + - MAXALIGN(sizeof(HeapTupleHeaderData)); + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)); ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width); } diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index d76e739..f94d54a 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -519,7 +519,8 @@ postgresGetForeignRelSize(PlannerInfo *root, { baserel->pages = 10; baserel->tuples = - (10 * BLCKSZ) / (baserel->width + sizeof(HeapTupleHeaderData)); + (10 * BLCKSZ) / + (baserel->width + offsetof(HeapTupleHeaderData, t_bits)); } /* Estimate baserel size as best we can with local statistics. */ diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 46060bc1..15fff73 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -7351,7 +7351,7 @@ heap_xlog_insert(XLogReaderState *record) xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record); Buffer buffer; Page page; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7415,7 +7415,7 @@ heap_xlog_insert(XLogReaderState *record) data += SizeOfHeapHeader; htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), data, @@ -7469,7 +7469,7 @@ heap_xlog_multi_insert(XLogReaderState *record) BlockNumber blkno; Buffer buffer; Page page; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7548,7 +7548,7 @@ heap_xlog_multi_insert(XLogReaderState *record) newlen = xlhdr->datalen; Assert(newlen <= MaxHeapTupleSize); htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), (char *) tupdata, @@ -7618,7 +7618,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) uint16 prefixlen = 0, suffixlen = 0; char *newp; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7780,7 +7780,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) Assert(tuplen <= MaxHeapTupleSize); htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* * Reconstruct the new tuple using the prefix and/or suffix from the diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index abd70b3..4b922b9 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -439,7 +439,7 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, * don't count palloc overhead either. */ tupsize = HJTUPLE_OVERHEAD + - MAXALIGN(sizeof(MinimalTupleData)) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)) + MAXALIGN(tupwidth); inner_rel_bytes = ntuples * tupsize; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 020558b..dea45c0 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4036,11 +4036,11 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) /* * If we have a whole-row reference, estimate its width as the sum of - * per-column widths plus sizeof(HeapTupleHeaderData). + * per-column widths plus offsetof(HeapTupleHeaderData, t_bits). */ if (have_wholerow_var) { - int32 wholerow_width = sizeof(HeapTupleHeaderData); + int32 wholerow_width = offsetof(HeapTupleHeaderData, t_bits); if (reloid != InvalidOid) { @@ -4078,7 +4078,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) static double relation_byte_size(double tuples, int width) { - return tuples * (MAXALIGN(width) + MAXALIGN(sizeof(HeapTupleHeaderData))); + return tuples * (MAXALIGN(width) + + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits))); } /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5c4884f..1e6680c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -2755,7 +2755,8 @@ choose_hashed_grouping(PlannerInfo *root, */ /* Estimate per-hash-entry space at tuple width... */ - hashentrysize = MAXALIGN(path_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(path_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); /* plus space for pass-by-ref transition values... */ hashentrysize += agg_costs->transitionSpace; /* plus the per-hash-entry overhead */ @@ -2923,7 +2924,8 @@ choose_hashed_distinct(PlannerInfo *root, */ /* Estimate per-hash-entry space at tuple width... */ - hashentrysize = MAXALIGN(path_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(path_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); /* plus the per-hash-entry overhead */ hashentrysize += hash_agg_entry_size(0); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 78fb6b1..918a5cf 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -974,12 +974,13 @@ subplan_is_hashable(Plan *plan) /* * The estimated size of the subquery result must fit in work_mem. (Note: - * we use sizeof(HeapTupleHeaderData) here even though the tuples will - * actually be stored as MinimalTuples; this provides some fudge factor - * for hashtable overhead.) + * we use offsetof(HeapTupleHeaderData, t_bits) here even though the tuples + * will actually be stored as MinimalTuples; this provides some fudge + * factor for hashtable overhead.) */ subquery_size = plan->plan_rows * - (MAXALIGN(plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData))); + (MAXALIGN(plan->plan_width) + + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits))); if (subquery_size > work_mem * 1024L) return false; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 05f601e..b290a08 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -832,7 +832,8 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses, * Don't do it if it doesn't look like the hashtable will fit into * work_mem. */ - hashentrysize = MAXALIGN(input_plan->plan_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(input_plan->plan_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); if (hashentrysize * dNumGroups > work_mem * 1024L) return false; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index fb7db6d..4a0a377 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -508,7 +508,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths, int32 tuple_width; tuple_width = get_rel_data_width(rel, attr_widths); - tuple_width += sizeof(HeapTupleHeaderData); + tuple_width += offsetof(HeapTupleHeaderData, t_bits); tuple_width += sizeof(ItemIdData); /* note: integer division is intentional here */ density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width; diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 77c02ba..574f63b 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -765,21 +765,21 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) * transactions. */ tuple->tuple.t_tableOid = InvalidOid; - tuple->tuple.t_data = &tuple->header; + tuple->tuple.t_data = &tuple->t_data.header; tuple->tuple.t_len = datalen + offsetof(HeapTupleHeaderData, t_bits); - memset(&tuple->header, 0, sizeof(HeapTupleHeaderData)); + memset(&tuple->t_data.header, 0, offsetof(HeapTupleHeaderData, t_bits)); - memcpy((char *) &tuple->header + memcpy((char *) &tuple->t_data.header + offsetof(HeapTupleHeaderData, t_bits), (char *) data, datalen); data += datalen; - tuple->header.t_infomask = xlhdr->t_infomask; - tuple->header.t_infomask2 = xlhdr->t_infomask2; - tuple->header.t_hoff = xlhdr->t_hoff; + tuple->t_data.header.t_infomask = xlhdr->t_infomask; + tuple->t_data.header.t_infomask2 = xlhdr->t_infomask2; + tuple->t_data.header.t_hoff = xlhdr->t_hoff; } /* @@ -822,20 +822,20 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple) /* we can only figure this out after reassembling the transactions */ tuple->tuple.t_tableOid = InvalidOid; - tuple->tuple.t_data = &tuple->header; + tuple->tuple.t_data = &tuple->t_data.header; /* data is not stored aligned, copy to aligned storage */ memcpy((char *) &xlhdr, data, SizeOfHeapHeader); - memset(&tuple->header, 0, sizeof(HeapTupleHeaderData)); + memset(&tuple->t_data.header, 0, offsetof(HeapTupleHeaderData, t_bits)); - memcpy((char *) &tuple->header + offsetof(HeapTupleHeaderData, t_bits), + memcpy((char *) &tuple->t_data.header + offsetof(HeapTupleHeaderData, t_bits), data + SizeOfHeapHeader, datalen); - tuple->header.t_infomask = xlhdr.t_infomask; - tuple->header.t_infomask2 = xlhdr.t_infomask2; - tuple->header.t_hoff = xlhdr.t_hoff; + tuple->t_data.header.t_infomask = xlhdr.t_infomask; + tuple->t_data.header.t_infomask2 = xlhdr.t_infomask2; + tuple->t_data.header.t_hoff = xlhdr.t_hoff; } diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index bcd5896..3226405 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2014,14 +2014,12 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn, newtup = change->data.tp.newtuple; if (oldtup) - oldlen = offsetof(ReorderBufferTupleBuf, data) - +oldtup->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + oldlen = offsetof(ReorderBufferTupleBuf, t_data) + + oldtup->tuple.t_len; if (newtup) - newlen = offsetof(ReorderBufferTupleBuf, data) - +newtup->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + newlen = offsetof(ReorderBufferTupleBuf, t_data) + + newtup->tuple.t_len; sz += oldlen; sz += newlen; @@ -2262,27 +2260,25 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn, case REORDER_BUFFER_CHANGE_DELETE: if (change->data.tp.newtuple) { - Size len = offsetof(ReorderBufferTupleBuf, data) - +((ReorderBufferTupleBuf *) data)->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + Size len = offsetof(ReorderBufferTupleBuf, t_data) + + ((ReorderBufferTupleBuf *) data)->tuple.t_len; change->data.tp.newtuple = ReorderBufferGetTupleBuf(rb); memcpy(change->data.tp.newtuple, data, len); change->data.tp.newtuple->tuple.t_data = - &change->data.tp.newtuple->header; + &change->data.tp.newtuple->t_data.header; data += len; } if (change->data.tp.oldtuple) { - Size len = offsetof(ReorderBufferTupleBuf, data) - +((ReorderBufferTupleBuf *) data)->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + Size len = offsetof(ReorderBufferTupleBuf, t_data) + + ((ReorderBufferTupleBuf *) data)->tuple.t_len; change->data.tp.oldtuple = ReorderBufferGetTupleBuf(rb); memcpy(change->data.tp.oldtuple, data, len); change->data.tp.oldtuple->tuple.t_data = - &change->data.tp.oldtuple->header; + &change->data.tp.oldtuple->t_data.header; data += len; } break; @@ -2660,7 +2656,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn, */ tmphtup = heap_form_tuple(desc, attrs, isnull); Assert(newtup->tuple.t_len <= MaxHeapTupleSize); - Assert(&newtup->header == newtup->tuple.t_data); + Assert(&newtup->t_data.header == newtup->tuple.t_data); memcpy(newtup->tuple.t_data, tmphtup->t_data, tmphtup->t_len); newtup->tuple.t_len = tmphtup->t_len; diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index d2ad910..475377c 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -150,7 +150,7 @@ struct HeapTupleHeaderData /* ^ - 23 bytes - ^ */ - bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ /* MORE DATA FOLLOWS AT END OF STRUCT */ }; @@ -579,7 +579,7 @@ struct MinimalTupleData /* ^ - 23 bytes - ^ */ - bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ /* MORE DATA FOLLOWS AT END OF STRUCT */ }; diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 5a1d9a0..dcfe2b3 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -28,8 +28,11 @@ typedef struct ReorderBufferTupleBuf /* tuple, stored sequentially */ HeapTupleData tuple; - HeapTupleHeaderData header; - char data[MaxHeapTupleSize]; + union + { + HeapTupleHeaderData header; + char data[MaxHeapTupleSize]; + } t_data; } ReorderBufferTupleBuf; /* -- 2.3.0
From 2ca26a01e49ad79649f2db19b7cb2ef0983842fa Mon Sep 17 00:00:00 2001 From: Michael Paquier <michael@otacoo.com> Date: Fri, 20 Feb 2015 16:53:27 +0900 Subject: [PATCH 3/3] Switch RecordIOData to use FLEXIBLE_ARRAY_MEMBER This impacts hstore, json functions and rowtypes. --- contrib/hstore/hstore_io.c | 18 +++++++++--------- src/backend/utils/adt/jsonfuncs.c | 18 +++++++++--------- src/backend/utils/adt/rowtypes.c | 34 +++++++++++++++++----------------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c index 079f662..7d89867 100644 --- a/contrib/hstore/hstore_io.c +++ b/contrib/hstore/hstore_io.c @@ -747,7 +747,7 @@ typedef struct RecordIOData Oid record_type; int32 record_typmod; int ncolumns; - ColumnIOData columns[1]; /* VARIABLE LENGTH ARRAY */ + ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]; } RecordIOData; PG_FUNCTION_INFO_V1(hstore_from_record); @@ -805,8 +805,8 @@ hstore_from_record(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -816,8 +816,8 @@ hstore_from_record(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; @@ -990,8 +990,8 @@ hstore_populate_record(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -1001,8 +1001,8 @@ hstore_populate_record(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 3688163..a8cdeaa 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -216,7 +216,7 @@ typedef struct RecordIOData Oid record_type; int32 record_typmod; int ncolumns; - ColumnIOData columns[1]; /* VARIABLE LENGTH ARRAY */ + ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]; } RecordIOData; /* state for populate_recordset */ @@ -2148,8 +2148,8 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -2161,8 +2161,8 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, my_extra->record_typmod != tupTypmod)) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; @@ -2653,8 +2653,8 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -2664,8 +2664,8 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 3dc9a84..16d2b7f 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -43,7 +43,7 @@ typedef struct RecordIOData Oid record_type; int32 record_typmod; int ncolumns; - ColumnIOData columns[1]; /* VARIABLE LENGTH ARRAY */ + ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]; } RecordIOData; /* @@ -120,8 +120,8 @@ record_in(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -131,8 +131,8 @@ record_in(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; @@ -334,8 +334,8 @@ record_out(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -345,8 +345,8 @@ record_out(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; @@ -489,8 +489,8 @@ record_recv(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -500,8 +500,8 @@ record_recv(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; @@ -677,8 +677,8 @@ record_send(PG_FUNCTION_ARGS) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; @@ -688,8 +688,8 @@ record_send(PG_FUNCTION_ARGS) my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, - sizeof(RecordIOData) - sizeof(ColumnIOData) - + ncolumns * sizeof(ColumnIOData)); + offsetof(RecordIOData, columns) + + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; -- 2.3.0
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers