Expanding the use of FLEXIBLE_ARRAY_MEMBER for declarations like foo[1]
Hi,
In a lot of places in the code we have many structures doing
declarations of the type foo[1] to emulate variable length arrays.
Attached are a set of patches aimed at replacing that with
FLEXIBLE_ARRAY_MEMBER to prevent potential failures that could be
caused by compiler optimizations and improve report of static code
analyzers of the type Coverity (idea by Tom, patches from me):
- 0001 uses FLEXIBLE_ARRAY_MEMBER in a bunch of trivial places (at
least check-world does not complain)
- 0002 does the same for catalog tables
- 0003 changes varlena in c.h. This is done as a separate patch
because this needs some other modifications as variable-length things
need to be placed at the end of structures, because of:
-- rolpassword that should be placed as the last field of pg_authid
(and shouldn't there be CATALOG_VARLEN here??)
-- inv_api.c uses bytea in an internal structure without putting it at
the end of the structure. For clarity I think that we should just use
a bytea pointer and do a sufficient allocation for the duration of the
lobj manipulation.
-- Similarly, tuptoaster.c needed to be patched for toast_save_datum
There are as well couple of things that are not changed on purpose:
- in namespace.h for FuncCandidateList. I tried manipulating it but it
resulted in allocation overflow in PortalHeapMemory
- I don't think that the t_bits fields in htup_details.h should be
updated either.
Regards,
--
Michael
Attachments:
0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchtext/x-diff; charset=US-ASCII; name=0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchDownload
From f3389a945811e1db19eb5debc9e41b84fed0a9f5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 02:44:10 +0900
Subject: [PATCH 1/3] First cut with FLEXIBLE_ARRAY_MEMBER
This is targetted to prevent false positive errors that static code
analyzers may do by assuming that some structures have an unvarying
size.
---
contrib/cube/cubedata.h | 7 +++----
contrib/intarray/_int.h | 4 ++--
contrib/ltree/ltree.h | 14 +++++++-------
contrib/pg_trgm/trgm.h | 2 +-
src/bin/pg_dump/dumputils.h | 2 +-
src/include/access/gin_private.h | 4 ++--
src/include/access/gist_private.h | 5 +++--
src/include/access/heapam_xlog.h | 2 +-
src/include/access/htup_details.h | 4 ++--
src/include/access/spgist_private.h | 10 +++++-----
src/include/access/xact.h | 8 ++++----
src/include/c.h | 4 ++--
src/include/commands/dbcommands.h | 4 ++--
src/include/commands/tablespace.h | 2 +-
src/include/executor/hashjoin.h | 2 +-
src/include/nodes/bitmapset.h | 2 +-
src/include/nodes/params.h | 2 +-
src/include/nodes/tidbitmap.h | 2 +-
src/include/postgres.h | 9 +++++----
src/include/postmaster/syslogger.h | 2 +-
src/include/replication/walsender_private.h | 2 +-
src/include/storage/bufpage.h | 3 ++-
src/include/storage/fsm_internals.h | 2 +-
src/include/storage/standby.h | 4 ++--
src/include/tsearch/dicts/regis.h | 2 +-
src/include/tsearch/dicts/spell.h | 6 +++---
src/include/tsearch/ts_type.h | 6 +++---
src/include/utils/catcache.h | 2 +-
src/include/utils/datetime.h | 5 +++--
src/include/utils/geo_decls.h | 3 ++-
src/include/utils/jsonb.h | 2 +-
src/include/utils/relmapper.h | 2 +-
src/include/utils/varbit.h | 3 ++-
33 files changed, 69 insertions(+), 64 deletions(-)
diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h
index 5d44e11..3535847 100644
--- a/contrib/cube/cubedata.h
+++ b/contrib/cube/cubedata.h
@@ -23,11 +23,10 @@ typedef struct NDBOX
unsigned int header;
/*
- * Variable length array. The lower left coordinates for each dimension
- * come first, followed by upper right coordinates unless the point flag
- * is set.
+ * The lower left coordinates for each dimension come first, followed
+ * by upper right coordinates unless the point flag is set.
*/
- double x[1];
+ double x[FLEXIBLE_ARRAY_MEMBER];
} NDBOX;
#define POINT_BIT 0x80000000
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
index 7f93206..d524f0f 100644
--- a/contrib/intarray/_int.h
+++ b/contrib/intarray/_int.h
@@ -73,7 +73,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} GISTTYPE;
#define ALLISTRUE 0x04
@@ -133,7 +133,7 @@ typedef struct QUERYTYPE
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of ITEMs */
- ITEM items[1]; /* variable length array */
+ ITEM items[FLEXIBLE_ARRAY_MEMBER];
} QUERYTYPE;
#define HDRSIZEQT offsetof(QUERYTYPE, items)
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index 1b1305b..c604357 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -10,7 +10,7 @@
typedef struct
{
uint16 len;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} ltree_level;
#define LEVEL_HDRSIZE (offsetof(ltree_level,name))
@@ -20,7 +20,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint16 numlevel;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree;
#define LTREE_HDRSIZE MAXALIGN( offsetof(ltree, data) )
@@ -34,7 +34,7 @@ typedef struct
int32 val;
uint16 len;
uint8 flag;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} lquery_variant;
#define LVAR_HDRSIZE MAXALIGN(offsetof(lquery_variant, name))
@@ -51,7 +51,7 @@ typedef struct
uint16 numvar;
uint16 low;
uint16 high;
- char variants[1];
+ char variants[FLEXIBLE_ARRAY_MEMBER];
} lquery_level;
#define LQL_HDRSIZE MAXALIGN( offsetof(lquery_level,variants) )
@@ -72,7 +72,7 @@ typedef struct
uint16 numlevel;
uint16 firstgood;
uint16 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} lquery;
#define LQUERY_HDRSIZE MAXALIGN( offsetof(lquery, data) )
@@ -107,7 +107,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltxtquery;
#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32))
@@ -208,7 +208,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree_gist;
#define LTG_ONENODE 0x01
diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h
index ed649b8..f030558 100644
--- a/contrib/pg_trgm/trgm.h
+++ b/contrib/pg_trgm/trgm.h
@@ -63,7 +63,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint8 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} TRGM;
#define TRGMHDRSIZE (VARHDRSZ + sizeof(uint8))
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index a39c1b6..94476a9 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -38,7 +38,7 @@ typedef struct SimpleOidList
typedef struct SimpleStringListCell
{
struct SimpleStringListCell *next;
- char val[1]; /* VARIABLE LENGTH FIELD */
+ char val[FLEXIBLE_ARRAY_MEMBER];
} SimpleStringListCell;
typedef struct SimpleStringList
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index bda7c28..8968993 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -389,7 +389,7 @@ typedef struct
{
ItemPointerData first; /* first item in this posting list (unpacked) */
uint16 nbytes; /* number of bytes that follow */
- unsigned char bytes[1]; /* varbyte encoded items (variable length) */
+ unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]; /* varbyte encoded items */
} GinPostingList;
#define SizeOfGinPostingList(plist) (offsetof(GinPostingList, bytes) + SHORTALIGN((plist)->nbytes) )
@@ -527,7 +527,7 @@ typedef struct
ItemPointerData rrightbound; /* new right bound of right page */
/* FOLLOWS: new compressed posting lists of left and right page */
- char newdata[1];
+ char newdata[FLEXIBLE_ARRAY_MEMBER];
} ginxlogSplitDataLeaf;
typedef struct
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 382826e..36f5257 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -47,7 +47,7 @@ typedef struct
{
BlockNumber prev;
uint32 freespace;
- char tupledata[1];
+ char tupledata[FLEXIBLE_ARRAY_MEMBER];
} GISTNodeBufferPage;
#define BUFFER_PAGE_DATA_OFFSET MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))
@@ -131,7 +131,8 @@ typedef struct GISTSearchItem
/* we must store parentlsn to detect whether a split occurred */
GISTSearchHeapItem heap; /* heap info, if heap tuple */
} data;
- double distances[1]; /* array with numberOfOrderBys entries */
+ double distances[FLEXIBLE_ARRAY_MEMBER]; /* array with numberOfOrderBys
+ * entries */
} GISTSearchItem;
#define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber)
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index a2ed2a0..f0f89de 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -132,7 +132,7 @@ typedef struct xl_heap_multi_insert
{
uint8 flags;
uint16 ntuples;
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_multi_insert;
#define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets)
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index d2ad910..0225b17 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[1]; /* 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[1]; /* bitmap of NULLs */
/* MORE DATA FOLLOWS AT END OF STRUCT */
};
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index f11d8ef..0492ef6 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -426,7 +426,7 @@ typedef struct spgxlogMoveLeafs
* the dead tuple from the source
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogMoveLeafs;
#define SizeOfSpgxlogMoveLeafs offsetof(spgxlogMoveLeafs, offsets)
@@ -534,7 +534,7 @@ typedef struct spgxlogPickSplit
* list of leaf tuples, length nInsert (unaligned!)
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogPickSplit;
#define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets)
@@ -558,7 +558,7 @@ typedef struct spgxlogVacuumLeaf
* tuple numbers to insert in nextOffset links
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumLeaf;
#define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets)
@@ -571,7 +571,7 @@ typedef struct spgxlogVacuumRoot
spgxlogState stateSrc;
/* offsets of tuples to delete follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRoot;
#define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets)
@@ -583,7 +583,7 @@ typedef struct spgxlogVacuumRedirect
TransactionId newestRedirectXid; /* newest XID of removed redirects */
/* offsets of redirect tuples to make placeholders follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRedirect;
#define SizeOfSpgxlogVacuumRedirect offsetof(spgxlogVacuumRedirect, offsets)
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8205504..9b95f10 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -118,7 +118,7 @@ typedef struct xl_xact_assignment
{
TransactionId xtop; /* assigned XID's top-level XID */
int nsubxacts; /* number of subtransaction XIDs */
- TransactionId xsub[1]; /* assigned subxids */
+ TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */
} xl_xact_assignment;
#define MinSizeOfXactAssignment offsetof(xl_xact_assignment, xsub)
@@ -128,7 +128,7 @@ typedef struct xl_xact_commit_compact
TimestampTz xact_time; /* time of commit */
int nsubxacts; /* number of subtransaction XIDs */
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
- TransactionId subxacts[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_commit_compact;
#define MinSizeOfXactCommitCompact offsetof(xl_xact_commit_compact, subxacts)
@@ -143,7 +143,7 @@ typedef struct xl_xact_commit
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
/* Array of RelFileNode(s) to drop at commit */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
/* ARRAY OF SHARED INVALIDATION MESSAGES FOLLOWS */
} xl_xact_commit;
@@ -171,7 +171,7 @@ typedef struct xl_xact_abort
int nrels; /* number of RelFileNodes */
int nsubxacts; /* number of subtransaction XIDs */
/* Array of RelFileNode(s) to drop at abort */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF ABORTED SUBTRANSACTION XIDs FOLLOWS */
} xl_xact_abort;
diff --git a/src/include/c.h b/src/include/c.h
index b187520..bbd0d53 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -424,7 +424,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- int16 values[1]; /* VARIABLE LENGTH ARRAY */
+ int16 values[FLEXIBLE_ARRAY_MEMBER];
} int2vector; /* VARIABLE LENGTH STRUCT */
typedef struct
@@ -435,7 +435,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- Oid values[1]; /* VARIABLE LENGTH ARRAY */
+ Oid values[FLEXIBLE_ARRAY_MEMBER];
} oidvector; /* VARIABLE LENGTH STRUCT */
/*
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index cb7cc0e..be1cac2 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -26,7 +26,7 @@ typedef struct xl_dbase_create_rec_old
{
/* Records copying of a single subdirectory incl. contents */
Oid db_id;
- char src_path[1]; /* VARIABLE LENGTH STRING */
+ char src_path[FLEXIBLE_ARRAY_MEMBER];
/* dst_path follows src_path */
} xl_dbase_create_rec_old;
@@ -34,7 +34,7 @@ typedef struct xl_dbase_drop_rec_old
{
/* Records dropping of a single subdirectory incl. contents */
Oid db_id;
- char dir_path[1]; /* VARIABLE LENGTH STRING */
+ char dir_path[FLEXIBLE_ARRAY_MEMBER];
} xl_dbase_drop_rec_old;
typedef struct xl_dbase_create_rec
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index e8b9bc4..9e40e31 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -25,7 +25,7 @@
typedef struct xl_tblspc_create_rec
{
Oid ts_id;
- char ts_path[1]; /* VARIABLE LENGTH STRING */
+ char ts_path[FLEXIBLE_ARRAY_MEMBER];
} xl_tblspc_create_rec;
typedef struct xl_tblspc_drop_rec
diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h
index e79df71..71099b1 100644
--- a/src/include/executor/hashjoin.h
+++ b/src/include/executor/hashjoin.h
@@ -114,7 +114,7 @@ typedef struct HashMemoryChunkData
struct HashMemoryChunkData *next; /* pointer to the next chunk (linked list) */
- char data[1]; /* buffer allocated at the end */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* buffer allocated at the end */
} HashMemoryChunkData;
typedef struct HashMemoryChunkData *HashMemoryChunk;
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 5f45f4d..1adabc3 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -32,7 +32,7 @@ typedef int32 signedbitmapword; /* must be the matching signed type */
typedef struct Bitmapset
{
int nwords; /* number of words in array */
- bitmapword words[1]; /* really [nwords] */
+ bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */
} Bitmapset; /* VARIABLE LENGTH STRUCT */
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index 5b096c5..0ad7ef0 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -71,7 +71,7 @@ typedef struct ParamListInfoData
ParserSetupHook parserSetup; /* parser setup hook */
void *parserSetupArg;
int numParams; /* number of ParamExternDatas following */
- ParamExternData params[1]; /* VARIABLE LENGTH ARRAY */
+ ParamExternData params[1];
} ParamListInfoData;
diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h
index fb62c9e..bfbc0fb 100644
--- a/src/include/nodes/tidbitmap.h
+++ b/src/include/nodes/tidbitmap.h
@@ -41,7 +41,7 @@ typedef struct
int ntuples; /* -1 indicates lossy result */
bool recheck; /* should the tuples be rechecked? */
/* Note: recheck is always true if ntuples < 0 */
- OffsetNumber offsets[1]; /* VARIABLE LENGTH ARRAY */
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} TBMIterateResult; /* VARIABLE LENGTH STRUCT */
/* function prototypes in nodes/tidbitmap.c */
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 082c75b..482e676 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -117,20 +117,20 @@ typedef union
struct /* Normal varlena (4-byte length) */
{
uint32 va_header;
- char va_data[1];
+ char va_data[FLEXIBLE_ARRAY_MEMBER];
} va_4byte;
struct /* Compressed-in-line format */
{
uint32 va_header;
uint32 va_rawsize; /* Original data size (excludes header) */
- char va_data[1]; /* Compressed data */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Compressed data */
} va_compressed;
} varattrib_4b;
typedef struct
{
uint8 va_header;
- char va_data[1]; /* Data begins here */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */
} varattrib_1b;
/* TOAST pointers are a subset of varattrib_1b with an identifying tag byte */
@@ -138,7 +138,8 @@ typedef struct
{
uint8 va_header; /* Always 0x80 or 0x01 */
uint8 va_tag; /* Type of datum */
- char va_data[1]; /* Data (of the type indicated by va_tag) */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data (of the type
+ * indicated by va_tag) */
} varattrib_1b_e;
/*
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 602b13c..89a535c 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -48,7 +48,7 @@ typedef struct
int32 pid; /* writer's pid */
char is_last; /* last chunk of message? 't' or 'f' ('T' or
* 'F' for CSV case) */
- char data[1]; /* data payload starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data payload starts here */
} PipeProtoHeader;
typedef union
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 8867750..02faad8 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -88,7 +88,7 @@ typedef struct
*/
bool sync_standbys_defined;
- WalSnd walsnds[1]; /* VARIABLE LENGTH ARRAY */
+ WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
} WalSndCtlData;
extern WalSndCtlData *WalSndCtl;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index f693032..b7dbd6f 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -156,7 +156,8 @@ typedef struct PageHeaderData
LocationIndex pd_special; /* offset to start of special space */
uint16 pd_pagesize_version;
TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
- ItemIdData pd_linp[1]; /* beginning of line pointer array */
+ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* beginning of line pointer
+ * array */
} PageHeaderData;
typedef PageHeaderData *PageHeader;
diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h
index 1decd90..26340b4 100644
--- a/src/include/storage/fsm_internals.h
+++ b/src/include/storage/fsm_internals.h
@@ -39,7 +39,7 @@ typedef struct
* NonLeafNodesPerPage elements are upper nodes, and the following
* LeafNodesPerPage elements are leaf nodes. Unused nodes are zero.
*/
- uint8 fp_nodes[1];
+ uint8 fp_nodes[FLEXIBLE_ARRAY_MEMBER];
} FSMPageData;
typedef FSMPageData *FSMPage;
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index c32c963..7626c4c 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -60,7 +60,7 @@ extern void StandbyReleaseOldLocks(int nxids, TransactionId *xids);
typedef struct xl_standby_locks
{
int nlocks; /* number of entries in locks array */
- xl_standby_lock locks[1]; /* VARIABLE LENGTH ARRAY */
+ xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER];
} xl_standby_locks;
/*
@@ -75,7 +75,7 @@ typedef struct xl_running_xacts
TransactionId oldestRunningXid; /* *not* oldestXmin */
TransactionId latestCompletedXid; /* so we can set xmax */
- TransactionId xids[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId xids[FLEXIBLE_ARRAY_MEMBER];
} xl_running_xacts;
#define MinSizeOfXactRunningXacts offsetof(xl_running_xacts, xids)
diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h
index 081a502..ddf5b60 100644
--- a/src/include/tsearch/dicts/regis.h
+++ b/src/include/tsearch/dicts/regis.h
@@ -21,7 +21,7 @@ typedef struct RegisNode
len:16,
unused:14;
struct RegisNode *next;
- unsigned char data[1];
+ unsigned char data[FLEXIBLE_ARRAY_MEMBER];
} RegisNode;
#define RNHDRSZ (offsetof(RegisNode,data))
diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h
index a75552b..e512532 100644
--- a/src/include/tsearch/dicts/spell.h
+++ b/src/include/tsearch/dicts/spell.h
@@ -49,7 +49,7 @@ typedef struct
typedef struct SPNode
{
uint32 length;
- SPNodeData data[1];
+ SPNodeData data[FLEXIBLE_ARRAY_MEMBER];
} SPNode;
#define SPNHDRSZ (offsetof(SPNode,data))
@@ -70,7 +70,7 @@ typedef struct spell_struct
int len;
} d;
} p;
- char word[1]; /* variable length, null-terminated */
+ char word[FLEXIBLE_ARRAY_MEMBER];
} SPELL;
#define SPELLHDRSZ (offsetof(SPELL, word))
@@ -120,7 +120,7 @@ typedef struct AffixNode
{
uint32 isvoid:1,
length:31;
- AffixNodeData data[1];
+ AffixNodeData data[FLEXIBLE_ARRAY_MEMBER];
} AffixNode;
#define ANHRDSZ (offsetof(AffixNode, data))
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 1cdfa82..ce919a2 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -63,7 +63,7 @@ typedef uint16 WordEntryPos;
typedef struct
{
uint16 npos;
- WordEntryPos pos[1]; /* variable length */
+ WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER];
} WordEntryPosVector;
@@ -82,7 +82,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- WordEntry entries[1]; /* variable length */
+ WordEntry entries[FLEXIBLE_ARRAY_MEMBER];
/* lexemes follow the entries[] array */
} TSVectorData;
@@ -233,7 +233,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of QueryItems */
- char data[1]; /* data starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data starts here */
} TSQueryData;
typedef TSQueryData *TSQuery;
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index 8084785..f5361f9 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -147,7 +147,7 @@ typedef struct catclist
uint32 hash_value; /* hash value for lookup keys */
HeapTupleData tuple; /* header for tuple holding keys */
int n_members; /* number of member tuples */
- CatCTup *members[1]; /* members --- VARIABLE LENGTH ARRAY */
+ CatCTup *members[FLEXIBLE_ARRAY_MEMBER]; /* members */
} CatCList; /* VARIABLE LENGTH STRUCT */
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 8912ba5..d36f297 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -219,7 +219,7 @@ typedef struct TimeZoneAbbrevTable
{
Size tblsize; /* size in bytes of TimeZoneAbbrevTable */
int numabbrevs; /* number of entries in abbrevs[] array */
- datetkn abbrevs[1]; /* VARIABLE LENGTH ARRAY */
+ datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER];
/* DynamicZoneAbbrev(s) may follow the abbrevs[] array */
} TimeZoneAbbrevTable;
@@ -227,7 +227,8 @@ typedef struct TimeZoneAbbrevTable
typedef struct DynamicZoneAbbrev
{
pg_tz *tz; /* NULL if not yet looked up */
- char zone[1]; /* zone name (var length, NUL-terminated) */
+ char zone[FLEXIBLE_ARRAY_MEMBER]; /* zone name (var length,
+ * NUL-terminated) */
} DynamicZoneAbbrev;
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0b6d3c3..63885f3 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -80,7 +80,8 @@ typedef struct
int32 npts;
int32 closed; /* is this a closed polygon? */
int32 dummy; /* padding to make it double align */
- Point p[1]; /* variable length array of POINTs */
+ Point p[FLEXIBLE_ARRAY_MEMBER]; /* variable length array
+ * of POINTs */
} PATH;
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index 887eb9b..9d1770e 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -194,7 +194,7 @@ typedef struct JsonbContainer
{
uint32 header; /* number of elements or key/value pairs, and
* flags */
- JEntry children[1]; /* variable length */
+ JEntry children[FLEXIBLE_ARRAY_MEMBER];
/* the data for each child node follows. */
} JsonbContainer;
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 420310d..73b4905 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -29,7 +29,7 @@ typedef struct xl_relmap_update
Oid dbid; /* database ID, or 0 for shared map */
Oid tsid; /* database's tablespace, or pg_global */
int32 nbytes; /* size of relmap data */
- char data[1]; /* VARIABLE LENGTH ARRAY */
+ char data[FLEXIBLE_ARRAY_MEMBER];
} xl_relmap_update;
#define MinSizeOfRelmapUpdate offsetof(xl_relmap_update, data)
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index 8afc3b1..bd5bf52 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -26,7 +26,8 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 bit_len; /* number of valid bits */
- bits8 bit_dat[1]; /* bit string, most sig. byte first */
+ bits8 bit_dat[FLEXIBLE_ARRAY_MEMBER]; /* bit string, most sig.
+ * byte first */
} VarBit;
/*
--
2.3.0
0002-Use-FLEXIBLE_ARRAY_MEMBER-in-catalog-tables.patchtext/x-diff; charset=US-ASCII; name=0002-Use-FLEXIBLE_ARRAY_MEMBER-in-catalog-tables.patchDownload
From b607e5be3ff1099d7f0374bafb7a2b497a8860fd Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 03:12:39 +0900
Subject: [PATCH 2/3] Use FLEXIBLE_ARRAY_MEMBER in catalog tables
---
src/include/catalog/pg_attribute.h | 6 +++---
src/include/catalog/pg_class.h | 5 +++--
src/include/catalog/pg_constraint.h | 12 ++++++------
src/include/catalog/pg_database.h | 2 +-
src/include/catalog/pg_db_role_setting.h | 3 ++-
src/include/catalog/pg_default_acl.h | 3 ++-
src/include/catalog/pg_event_trigger.h | 3 ++-
src/include/catalog/pg_extension.h | 6 ++++--
src/include/catalog/pg_foreign_data_wrapper.h | 4 ++--
src/include/catalog/pg_foreign_server.h | 4 ++--
src/include/catalog/pg_foreign_table.h | 2 +-
src/include/catalog/pg_language.h | 2 +-
src/include/catalog/pg_largeobject_metadata.h | 2 +-
src/include/catalog/pg_namespace.h | 2 +-
src/include/catalog/pg_pltemplate.h | 2 +-
src/include/catalog/pg_policy.h | 3 ++-
src/include/catalog/pg_proc.h | 14 +++++++++-----
src/include/catalog/pg_statistic.h | 10 +++++-----
src/include/catalog/pg_tablespace.h | 5 +++--
src/include/catalog/pg_type.h | 2 +-
src/include/catalog/pg_user_mapping.h | 2 +-
21 files changed, 53 insertions(+), 41 deletions(-)
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 87a3462..73bcefe 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -157,13 +157,13 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
/* NOTE: The following fields are not present in tuple descriptors. */
/* Column-level access permissions */
- aclitem attacl[1];
+ aclitem attacl[FLEXIBLE_ARRAY_MEMBER];
/* Column-level options */
- text attoptions[1];
+ text attoptions[FLEXIBLE_ARRAY_MEMBER];
/* Column-level FDW options */
- text attfdwoptions[1];
+ text attfdwoptions[FLEXIBLE_ARRAY_MEMBER];
#endif
} FormData_pg_attribute;
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 8b4c35c..9516d5d 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -74,8 +74,9 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* NOTE: These fields are not present in a relcache entry's rd_rel field. */
- aclitem relacl[1]; /* access permissions */
- text reloptions[1]; /* access-method-specific options */
+ aclitem relacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
+ text reloptions[FLEXIBLE_ARRAY_MEMBER]; /* access-method-specific
+ * options */
#endif
} FormData_pg_class;
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 6f32ac8..2100203 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -98,36 +98,36 @@ CATALOG(pg_constraint,2606)
* Columns of conrelid that the constraint applies to, if known (this is
* NULL for trigger constraints)
*/
- int16 conkey[1];
+ int16 conkey[FLEXIBLE_ARRAY_MEMBER];
/*
* If a foreign key, the referenced columns of confrelid
*/
- int16 confkey[1];
+ int16 confkey[FLEXIBLE_ARRAY_MEMBER];
/*
* If a foreign key, the OIDs of the PK = FK equality operators for each
* column of the constraint
*/
- Oid conpfeqop[1];
+ Oid conpfeqop[FLEXIBLE_ARRAY_MEMBER];
/*
* If a foreign key, the OIDs of the PK = PK equality operators for each
* column of the constraint (i.e., equality for the referenced columns)
*/
- Oid conppeqop[1];
+ Oid conppeqop[FLEXIBLE_ARRAY_MEMBER];
/*
* If a foreign key, the OIDs of the FK = FK equality operators for each
* column of the constraint (i.e., equality for the referencing columns)
*/
- Oid conffeqop[1];
+ Oid conffeqop[FLEXIBLE_ARRAY_MEMBER];
/*
* If an exclusion constraint, the OIDs of the exclusion operators for
* each column of the constraint
*/
- Oid conexclop[1];
+ Oid conexclop[FLEXIBLE_ARRAY_MEMBER];
/*
* If a check constraint, nodeToString representation of expression
diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h
index 1045139..92e331e 100644
--- a/src/include/catalog/pg_database.h
+++ b/src/include/catalog/pg_database.h
@@ -45,7 +45,7 @@ CATALOG(pg_database,1262) BKI_SHARED_RELATION BKI_ROWTYPE_OID(1248) BKI_SCHEMA_M
Oid dattablespace; /* default table space for this DB */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem datacl[1]; /* access permissions */
+ aclitem datacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
#endif
} FormData_pg_database;
diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h
index 9717569..ff931a9 100644
--- a/src/include/catalog/pg_db_role_setting.h
+++ b/src/include/catalog/pg_db_role_setting.h
@@ -38,7 +38,8 @@ CATALOG(pg_db_role_setting,2964) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
Oid setrole; /* role */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- text setconfig[1]; /* GUC settings to apply at login */
+ text setconfig[FLEXIBLE_ARRAY_MEMBER]; /* GUC settings to apply
+ * at login */
#endif
} FormData_pg_db_role_setting;
diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h
index 0b5c554..dec4e32 100644
--- a/src/include/catalog/pg_default_acl.h
+++ b/src/include/catalog/pg_default_acl.h
@@ -34,7 +34,8 @@ CATALOG(pg_default_acl,826)
char defaclobjtype; /* see DEFACLOBJ_xxx constants below */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem defaclacl[1]; /* permissions to add at CREATE time */
+ aclitem defaclacl[FLEXIBLE_ARRAY_MEMBER]; /* permissions to add
+ * at CREATE time */
#endif
} FormData_pg_default_acl;
diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h
index ca81a81..bb6c1aa 100644
--- a/src/include/catalog/pg_event_trigger.h
+++ b/src/include/catalog/pg_event_trigger.h
@@ -38,7 +38,8 @@ CATALOG(pg_event_trigger,3466)
* session_replication_role */
#ifdef CATALOG_VARLEN
- text evttags[1]; /* command TAGs this event trigger targets */
+ text evttags[FLEXIBLE_ARRAY_MEMBER]; /* command TAGs this event
+ * trigger targets */
#endif
} FormData_pg_event_trigger;
diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h
index f45d6cb..ff54dbc 100644
--- a/src/include/catalog/pg_extension.h
+++ b/src/include/catalog/pg_extension.h
@@ -38,8 +38,10 @@ CATALOG(pg_extension,3079)
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* extversion should never be null, but the others can be. */
text extversion; /* extension version name */
- Oid extconfig[1]; /* dumpable configuration tables */
- text extcondition[1]; /* WHERE clauses for config tables */
+ Oid extconfig[FLEXIBLE_ARRAY_MEMBER]; /* dumpable configuration
+ * tables */
+ text extcondition[FLEXIBLE_ARRAY_MEMBER]; /* WHERE clauses for
+ * config tables */
#endif
} FormData_pg_extension;
diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h
index 1c7db04..091ea38 100644
--- a/src/include/catalog/pg_foreign_data_wrapper.h
+++ b/src/include/catalog/pg_foreign_data_wrapper.h
@@ -36,8 +36,8 @@ CATALOG(pg_foreign_data_wrapper,2328)
Oid fdwvalidator; /* option validation function, or 0 if none */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem fdwacl[1]; /* access permissions */
- text fdwoptions[1]; /* FDW options */
+ aclitem fdwacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
+ text fdwoptions[FLEXIBLE_ARRAY_MEMBER]; /* FDW options */
#endif
} FormData_pg_foreign_data_wrapper;
diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h
index 7ac6fd9..3c28d57 100644
--- a/src/include/catalog/pg_foreign_server.h
+++ b/src/include/catalog/pg_foreign_server.h
@@ -35,8 +35,8 @@ CATALOG(pg_foreign_server,1417)
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text srvtype;
text srvversion;
- aclitem srvacl[1]; /* access permissions */
- text srvoptions[1]; /* FDW-specific options */
+ aclitem srvacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
+ text srvoptions[FLEXIBLE_ARRAY_MEMBER]; /* FDW-specific options */
#endif
} FormData_pg_foreign_server;
diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h
index 2e6b947..727214c 100644
--- a/src/include/catalog/pg_foreign_table.h
+++ b/src/include/catalog/pg_foreign_table.h
@@ -32,7 +32,7 @@ CATALOG(pg_foreign_table,3118) BKI_WITHOUT_OIDS
Oid ftserver; /* OID of foreign server */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- text ftoptions[1]; /* FDW-specific options */
+ text ftoptions[FLEXIBLE_ARRAY_MEMBER]; /* FDW-specific options */
#endif
} FormData_pg_foreign_table;
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index b82cca2..c7b10fc 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -39,7 +39,7 @@ CATALOG(pg_language,2612)
Oid lanvalidator; /* Optional validation function */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem lanacl[1]; /* Access privileges */
+ aclitem lanacl[FLEXIBLE_ARRAY_MEMBER]; /* Access privileges */
#endif
} FormData_pg_language;
diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h
index 033f7bd..85658d2 100644
--- a/src/include/catalog/pg_largeobject_metadata.h
+++ b/src/include/catalog/pg_largeobject_metadata.h
@@ -33,7 +33,7 @@ CATALOG(pg_largeobject_metadata,2995)
Oid lomowner; /* OID of the largeobject owner */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem lomacl[1]; /* access permissions */
+ aclitem lomacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
#endif
} FormData_pg_largeobject_metadata;
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index 2c8887c..e1258a8 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -39,7 +39,7 @@ CATALOG(pg_namespace,2615)
Oid nspowner;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem nspacl[1];
+ aclitem nspacl[FLEXIBLE_ARRAY_MEMBER];
#endif
} FormData_pg_namespace;
diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h
index c5e6554..def9cea 100644
--- a/src/include/catalog/pg_pltemplate.h
+++ b/src/include/catalog/pg_pltemplate.h
@@ -39,7 +39,7 @@ CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
text tmplinline; /* name of anonymous-block handler, or NULL */
text tmplvalidator; /* name of validator function, or NULL */
text tmpllibrary; /* path of shared library */
- aclitem tmplacl[1]; /* access privileges for template */
+ aclitem tmplacl[FLEXIBLE_ARRAY_MEMBER]; /* access privileges for template */
#endif
} FormData_pg_pltemplate;
diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h
index ae71f3f..87b1b5f 100644
--- a/src/include/catalog/pg_policy.h
+++ b/src/include/catalog/pg_policy.h
@@ -25,7 +25,8 @@ CATALOG(pg_policy,3256)
char polcmd; /* One of ACL_*_CHR, or '*' for all */
#ifdef CATALOG_VARLEN
- Oid polroles[1]; /* Roles associated with policy, not-NULL */
+ Oid polroles[FLEXIBLE_ARRAY_MEMBER]; /* Roles associated
+ * with policy, not-NULL */
pg_node_tree polqual; /* Policy quals. */
pg_node_tree polwithcheck; /* WITH CHECK quals. */
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 9edfdb8..1efae3f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -61,15 +61,19 @@ CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81) BKI_SCHEMA_MACRO
oidvector proargtypes; /* parameter types (excludes OUT params) */
#ifdef CATALOG_VARLEN
- Oid proallargtypes[1]; /* all param types (NULL if IN only) */
- char proargmodes[1]; /* parameter modes (NULL if IN only) */
- text proargnames[1]; /* parameter names (NULL if no names) */
+ Oid proallargtypes[FLEXIBLE_ARRAY_MEMBER]; /* all param types
+ * (NULL if IN only) */
+ char proargmodes[FLEXIBLE_ARRAY_MEMBER]; /* parameter modes
+ * (NULL if IN only) */
+ text proargnames[FLEXIBLE_ARRAY_MEMBER]; /* parameter names
+ * (NULL if no names) */
pg_node_tree proargdefaults;/* list of expression trees for argument
* defaults (NULL if none) */
text prosrc; /* procedure source text */
text probin; /* secondary procedure info (can be NULL) */
- text proconfig[1]; /* procedure-local GUC settings */
- aclitem proacl[1]; /* access permissions */
+ text proconfig[FLEXIBLE_ARRAY_MEMBER]; /* procedure-local GUC
+ * settings */
+ aclitem proacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
#endif
} FormData_pg_proc;
diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h
index 62a00fe..a9c695a 100644
--- a/src/include/catalog/pg_statistic.h
+++ b/src/include/catalog/pg_statistic.h
@@ -97,11 +97,11 @@ CATALOG(pg_statistic,2619) BKI_WITHOUT_OIDS
Oid staop5;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- float4 stanumbers1[1];
- float4 stanumbers2[1];
- float4 stanumbers3[1];
- float4 stanumbers4[1];
- float4 stanumbers5[1];
+ float4 stanumbers1[FLEXIBLE_ARRAY_MEMBER];
+ float4 stanumbers2[FLEXIBLE_ARRAY_MEMBER];
+ float4 stanumbers3[FLEXIBLE_ARRAY_MEMBER];
+ float4 stanumbers4[FLEXIBLE_ARRAY_MEMBER];
+ float4 stanumbers5[FLEXIBLE_ARRAY_MEMBER];
/*
* Values in these arrays are values of the column's data type, or of some
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 24b1d8f..3868d0b 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -34,8 +34,9 @@ CATALOG(pg_tablespace,1213) BKI_SHARED_RELATION
Oid spcowner; /* owner of tablespace */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- aclitem spcacl[1]; /* access permissions */
- text spcoptions[1]; /* per-tablespace options */
+ aclitem spcacl[FLEXIBLE_ARRAY_MEMBER]; /* access permissions */
+ text spcoptions[FLEXIBLE_ARRAY_MEMBER]; /* per-tablespace
+ * options */
#endif
} FormData_pg_tablespace;
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 0a900dd..cda6a22 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -221,7 +221,7 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
/*
* Access permissions
*/
- aclitem typacl[1];
+ aclitem typacl[FLEXIBLE_ARRAY_MEMBER];
#endif
} FormData_pg_type;
diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h
index 3e76e99..5237be3 100644
--- a/src/include/catalog/pg_user_mapping.h
+++ b/src/include/catalog/pg_user_mapping.h
@@ -33,7 +33,7 @@ CATALOG(pg_user_mapping,1418)
Oid umserver; /* server of this mapping */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
- text umoptions[1]; /* user mapping options */
+ text umoptions[FLEXIBLE_ARRAY_MEMBER]; /* user mapping options */
#endif
} FormData_pg_user_mapping;
--
2.3.0
0003-Update-varlena-in-c.h-to-use-FLEXIBLE_ARRAY_MEMBER.patchtext/x-diff; charset=US-ASCII; name=0003-Update-varlena-in-c.h-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
From ad8f54cdb5776146f17d1038bb295b5f13b549f1 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 03:53:38 +0900
Subject: [PATCH 3/3] Update varlena in c.h to use FLEXIBLE_ARRAY_MEMBER
Places using a variable-length variable not at the end of a structure
are changed with workaround, without impacting what those features do.
---
src/backend/access/heap/tuptoaster.c | 16 ++++++------
src/backend/storage/large_object/inv_api.c | 40 ++++++++++++++----------------
src/include/c.h | 2 +-
src/include/catalog/pg_authid.h | 8 +++---
4 files changed, 31 insertions(+), 35 deletions(-)
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index f8c1401..a8f178c 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -1365,12 +1365,7 @@ toast_save_datum(Relation rel, Datum value,
CommandId mycid = GetCurrentCommandId(true);
struct varlena *result;
struct varatt_external toast_pointer;
- struct
- {
- struct varlena hdr;
- char data[TOAST_MAX_CHUNK_SIZE]; /* make struct big enough */
- int32 align_it; /* ensure struct is aligned well enough */
- } chunk_data;
+ struct varlena *chunk_data;
int32 chunk_size;
int32 chunk_seq = 0;
char *data_p;
@@ -1381,6 +1376,9 @@ toast_save_datum(Relation rel, Datum value,
Assert(!VARATT_IS_EXTERNAL(value));
+ chunk_data = (struct varlena *)
+ palloc(MAXALIGN(TOAST_MAX_CHUNK_SIZE + VARHDRSZ));
+
/*
* Open the toast relation and its indexes. We can use the index to check
* uniqueness of the OID we assign to the toasted item, even though it has
@@ -1523,7 +1521,7 @@ toast_save_datum(Relation rel, Datum value,
* Initialize constant parts of the tuple data
*/
t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);
- t_values[2] = PointerGetDatum(&chunk_data);
+ t_values[2] = PointerGetDatum(chunk_data);
t_isnull[0] = false;
t_isnull[1] = false;
t_isnull[2] = false;
@@ -1546,8 +1544,8 @@ toast_save_datum(Relation rel, Datum value,
* Build a tuple and store it
*/
t_values[1] = Int32GetDatum(chunk_seq++);
- SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ);
- memcpy(VARDATA(&chunk_data), data_p, chunk_size);
+ SET_VARSIZE(chunk_data, chunk_size + VARHDRSZ);
+ memcpy(VARDATA(chunk_data), data_p, chunk_size);
toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
heap_insert(toastrel, toasttup, mycid, options, NULL);
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index a19c401..b44fae7 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -562,13 +562,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
bool neednextpage;
bytea *datafield;
bool pfreeit;
- struct
- {
- bytea hdr;
- char data[LOBLKSIZE]; /* make struct big enough */
- int32 align_it; /* ensure struct is aligned well enough */
- } workbuf;
- char *workb = VARDATA(&workbuf.hdr);
+ bytea *workbuf;
+ char *workb;
HeapTuple newtup;
Datum values[Natts_pg_largeobject];
bool nulls[Natts_pg_largeobject];
@@ -591,6 +586,9 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
errmsg("invalid large object write request size: %d",
nbytes)));
+ workbuf = (bytea *) palloc(MAXALIGN(LOBLKSIZE + VARHDRSZ));
+ workb = VARDATA(workbuf);
+
open_lo_relation();
indstate = CatalogOpenIndexes(lo_heap_r);
@@ -664,7 +662,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
off += n;
/* compute valid length of new page */
len = (len >= off) ? len : off;
- SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
+ SET_VARSIZE(workbuf, len + VARHDRSZ);
/*
* Form and insert updated tuple
@@ -672,7 +670,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
memset(replace, false, sizeof(replace));
- values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
+ values[Anum_pg_largeobject_data - 1] = PointerGetDatum(workbuf);
replace[Anum_pg_largeobject_data - 1] = true;
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
values, nulls, replace);
@@ -708,7 +706,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
obj_desc->offset += n;
/* compute valid length of new page */
len = off + n;
- SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
+ SET_VARSIZE(workbuf, len + VARHDRSZ);
/*
* Form and insert updated tuple
@@ -717,7 +715,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
memset(nulls, false, sizeof(nulls));
values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
- values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
+ values[Anum_pg_largeobject_data - 1] = PointerGetDatum(workbuf);
newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
simple_heap_insert(lo_heap_r, newtup);
CatalogIndexInsert(indstate, newtup);
@@ -748,13 +746,8 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
SysScanDesc sd;
HeapTuple oldtuple;
Form_pg_largeobject olddata;
- struct
- {
- bytea hdr;
- char data[LOBLKSIZE]; /* make struct big enough */
- int32 align_it; /* ensure struct is aligned well enough */
- } workbuf;
- char *workb = VARDATA(&workbuf.hdr);
+ bytea *workbuf;
+ char *workb;
HeapTuple newtup;
Datum values[Natts_pg_largeobject];
bool nulls[Natts_pg_largeobject];
@@ -776,6 +769,9 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
errmsg_internal("invalid large object truncation target: " INT64_FORMAT,
len)));
+ workbuf = (bytea *) palloc(MAXALIGN(LOBLKSIZE + VARHDRSZ));
+ workb = VARDATA(workbuf);
+
open_lo_relation();
indstate = CatalogOpenIndexes(lo_heap_r);
@@ -834,7 +830,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
MemSet(workb + pagelen, 0, off - pagelen);
/* compute length of new page */
- SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
+ SET_VARSIZE(workbuf, off + VARHDRSZ);
/*
* Form and insert updated tuple
@@ -842,7 +838,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
memset(replace, false, sizeof(replace));
- values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
+ values[Anum_pg_largeobject_data - 1] = PointerGetDatum(workbuf);
replace[Anum_pg_largeobject_data - 1] = true;
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
values, nulls, replace);
@@ -873,7 +869,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
MemSet(workb, 0, off);
/* compute length of new page */
- SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
+ SET_VARSIZE(workbuf, off + VARHDRSZ);
/*
* Form and insert new tuple
@@ -882,7 +878,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
memset(nulls, false, sizeof(nulls));
values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
- values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
+ values[Anum_pg_largeobject_data - 1] = PointerGetDatum(workbuf);
newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
simple_heap_insert(lo_heap_r, newtup);
CatalogIndexInsert(indstate, newtup);
diff --git a/src/include/c.h b/src/include/c.h
index bbd0d53..36ec468 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))
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
index e01e6aa..d8789a5 100644
--- a/src/include/catalog/pg_authid.h
+++ b/src/include/catalog/pg_authid.h
@@ -56,8 +56,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
/* remaining fields may be null; use heap_getattr to read them! */
- text rolpassword; /* password, if any */
timestamptz rolvaliduntil; /* password expiration time, if any */
+#ifdef CATALOG_VARLEN
+ text rolpassword; /* password, if any */
+#endif
} FormData_pg_authid;
#undef timestamptz
@@ -85,8 +87,8 @@ typedef FormData_pg_authid *Form_pg_authid;
#define Anum_pg_authid_rolreplication 8
#define Anum_pg_authid_rolbypassrls 9
#define Anum_pg_authid_rolconnlimit 10
-#define Anum_pg_authid_rolpassword 11
-#define Anum_pg_authid_rolvaliduntil 12
+#define Anum_pg_authid_rolvaliduntil 11
+#define Anum_pg_authid_rolpassword 12
/* ----------------
* initial contents of pg_authid
--
2.3.0
On 2015-02-17 05:51:22 +0900, Michael Paquier wrote:
- 0002 does the same for catalog tables
- 0003 changes varlena in c.h. This is done as a separate patch
because this needs some other modifications as variable-length things
need to be placed at the end of structures, because of:
-- rolpassword that should be placed as the last field of pg_authid
(and shouldn't there be CATALOG_VARLEN here??)
Yes, there should.
-- inv_api.c uses bytea in an internal structure without putting it at
the end of the structure. For clarity I think that we should just use
a bytea pointer and do a sufficient allocation for the duration of the
lobj manipulation.
Hm. I don't really see the problem tbh.
There's actually is a reason the bytea is at the beginning - the other
fields are *are* the data part of the bytea (which is just the varlena
header).
-- Similarly, tuptoaster.c needed to be patched for toast_save_datum
I'm not a big fan of these two changes. This adds some not that small
memory allocations to a somewhat hot path. Without a big win in
clarity. And it doesn't seem to have anything to do with with
FLEXIBLE_ARRAY_MEMBER.
There are as well couple of things that are not changed on purpose:
- in namespace.h for FuncCandidateList. I tried manipulating it but it
resulted in allocation overflow in PortalHeapMemory
Did you change the allocation in FuncnameGetCandidates()? Note the -
sizeof(Oid) there.
- I don't think that the t_bits fields in htup_details.h should be
updated either.
Why not? Any not broken code should already use MinHeapTupleSize and
similar macros.
Generally it's worthwhile to check the code you changed for
sizeof(changed_struct) and similar things. Because this very well could
add bugs. And not all of them will result in a outright visibile error
like the FuncnameGetCandidates() one.
--- 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[1]; /* 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[1]; /* bitmap of NULLs *//* MORE DATA FOLLOWS AT END OF STRUCT */
};
This sees like overeager search/replace.
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index 5b096c5..0ad7ef0 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -71,7 +71,7 @@ typedef struct ParamListInfoData ParserSetupHook parserSetup; /* parser setup hook */ void *parserSetupArg; int numParams; /* number of ParamExternDatas following */ - ParamExternData params[1]; /* VARIABLE LENGTH ARRAY */ + ParamExternData params[1]; } ParamListInfoData;
Eh?
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 87a3462..73bcefe 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -157,13 +157,13 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK /* NOTE: The following fields are not present in tuple descriptors. *//* Column-level access permissions */ - aclitem attacl[1]; + aclitem attacl[FLEXIBLE_ARRAY_MEMBER];/* Column-level options */ - text attoptions[1]; + text attoptions[FLEXIBLE_ARRAY_MEMBER];/* Column-level FDW options */ - text attfdwoptions[1]; + text attfdwoptions[FLEXIBLE_ARRAY_MEMBER]; #endif } FormData_pg_attribute;
Ugh. This really isn't C at all anymore - these structs wouldn't compile
if you removed the #ifdef. Maybe we should instead a 'textarray' type
for genbki's benefit?
Generally the catalog changes are much less clearly a benefit imo.
From ad8f54cdb5776146f17d1038bb295b5f13b549f1 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 03:53:38 +0900
Subject: [PATCH 3/3] Update varlena in c.h to use FLEXIBLE_ARRAY_MEMBERPlaces using a variable-length variable not at the end of a structure
are changed with workaround, without impacting what those features do.
I vote for rejecting most of this, except a (corrected version) of the
pg_authid change. Which doesn't really belong to the rest of the patch
anyway ;)x
#define VARHDRSZ ((int32) sizeof(int32)) diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index e01e6aa..d8789a5 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -56,8 +56,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC int32 rolconnlimit; /* max connections allowed (-1=no limit) *//* remaining fields may be null; use heap_getattr to read them! */ - text rolpassword; /* password, if any */ timestamptz rolvaliduntil; /* password expiration time, if any */ +#ifdef CATALOG_VARLEN + text rolpassword; /* password, if any */ +#endif } FormData_pg_authid;
That change IIRC is wrong, because it'll make rolvaliduntil until NOT
NULL (any column that's fixed width and has only fixed with columns
before it is marked as such).
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@2ndquadrant.com> writes:
On 2015-02-17 05:51:22 +0900, Michael Paquier wrote:
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index e01e6aa..d8789a5 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -56,8 +56,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC int32 rolconnlimit; /* max connections allowed (-1=no limit) *//* remaining fields may be null; use heap_getattr to read them! */ - text rolpassword; /* password, if any */ timestamptz rolvaliduntil; /* password expiration time, if any */ +#ifdef CATALOG_VARLEN + text rolpassword; /* password, if any */ +#endif } FormData_pg_authid;
That change IIRC is wrong, because it'll make rolvaliduntil until NOT
NULL (any column that's fixed width and has only fixed with columns
before it is marked as such).
You were muttering about a BKI_FORCE_NOT_NULL option ... for symmetry,
maybe we could add BKI_FORCE_NULL as well, and then use that for cases
like this? Also, if we want to insist that these fields be accessed
through heap_getattr, I'd be inclined to put them inside the "#ifdef
CATALOG_VARLEN" to enforce that.
I'm generally -1 on reordering any catalog columns as part of this patch.
There should be zero user-visible change from it IMO. However, if we
stick both those columns inside the ifdef, we don't need to reorder.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Feb 17, 2015 at 9:02 AM, Andres Freund wrote:
On 2015-02-17 05:51:22 +0900, Michael Paquier wrote:
-- inv_api.c uses bytea in an internal structure without putting it at
the end of the structure. For clarity I think that we should just use
a bytea pointer and do a sufficient allocation for the duration of the
lobj manipulation.Hm. I don't really see the problem tbh.
There's actually is a reason the bytea is at the beginning - the other
fields are *are* the data part of the bytea (which is just the varlena
header).-- Similarly, tuptoaster.c needed to be patched for toast_save_datum
I'm not a big fan of these two changes. This adds some not that small
memory allocations to a somewhat hot path. Without a big win in
clarity. And it doesn't seem to have anything to do with with
FLEXIBLE_ARRAY_MEMBER.
We could replace those palloc calls with a simple buffer that has a
predefined size, but this somewhat reduces the readability of the
code.
There are as well couple of things that are not changed on purpose:
- in namespace.h for FuncCandidateList. I tried manipulating it but it
resulted in allocation overflow in PortalHeapMemoryDid you change the allocation in FuncnameGetCandidates()? Note the -
sizeof(Oid) there.
Yeah. Missed it.
- I don't think that the t_bits fields in htup_details.h should be
updated either.Why not? Any not broken code should already use MinHeapTupleSize and
similar macros.
Changing t_bits impacts HeapTupleHeaderData, ReorderBufferTupleBuf and
similarly a couple of redo routines in heapam.c using
HeapTupleHeaderData in a couple of structures not placing it at the
end (compiler complains). We could use for each of them a buffer that
has enough room with sizeof(HeapTupleHeaderData) + MaxHeapTupleSize,
but wouldn't it reduce the readability of the current code? Opinions
welcome.
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h[...]
Generally the catalog changes are much less clearly a benefit imo.
OK, let's drop them then.
From ad8f54cdb5776146f17d1038bb295b5f13b549f1 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 03:53:38 +0900
Subject: [PATCH 3/3] Update varlena in c.h to use FLEXIBLE_ARRAY_MEMBERPlaces using a variable-length variable not at the end of a structure
are changed with workaround, without impacting what those features do.I vote for rejecting most of this, except a (corrected version) of the
pg_authid change. Which doesn't really belong to the rest of the patch
anyway ;)x
Changing bytea to use FLEXIBLE_ARRAY_MEMBER requires those changes, or
at least some changes in this area as something with
FLEXIBLE_ARRAY_MEMBER can only be placed at the end of a structure.
But I guess that we can do fine as well by replacing those structures
with some buffers with a pre-defined size. I'll draft an additional
patch on top of 0001 with all those less-trivial changes implemented.
#define VARHDRSZ ((int32) sizeof(int32)) diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index e01e6aa..d8789a5 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -56,8 +56,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC int32 rolconnlimit; /* max connections allowed (-1=no limit) *//* remaining fields may be null; use heap_getattr to read them! */ - text rolpassword; /* password, if any */ timestamptz rolvaliduntil; /* password expiration time, if any */ +#ifdef CATALOG_VARLEN + text rolpassword; /* password, if any */ +#endif } FormData_pg_authid;That change IIRC is wrong, because it'll make rolvaliduntil until NOT
NULL (any column that's fixed width and has only fixed with columns
before it is marked as such).
This sounds better as a separate patch...
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-02-18 17:15:18 +0900, Michael Paquier wrote:
- I don't think that the t_bits fields in htup_details.h should be
updated either.Why not? Any not broken code should already use MinHeapTupleSize and
similar macros.Changing t_bits impacts HeapTupleHeaderData, ReorderBufferTupleBuf and
similarly a couple of redo routines in heapam.c using
HeapTupleHeaderData in a couple of structures not placing it at the
end (compiler complains).
The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.
Code embedding structs using *either* [FLEXIBLE_ARRAY_MEMBER] or [1] for
variable length obviously has to take care where the variable length
part goes. And that what the structs you removed where doing - that's
where the t_bits et al go:
{
...
HeapTupleHeaderData header;
char data[MaxHeapTupleSize];
...
}
the 'data' bit is just the t_bits + data together. And similar in
- struct
- {
- struct varlena hdr;
- char data[TOAST_MAX_CHUNK_SIZE]; /* make struct big enough */
- int32 align_it; /* ensure struct is aligned well enough */
- } chunk_data;
The 'data' is where the varlena's vl_dat stuff is stored.
Places using a variable-length variable not at the end of a structure
are changed with workaround, without impacting what those features do.I vote for rejecting most of this, except a (corrected version) of the
pg_authid change. Which doesn't really belong to the rest of the patch
anyway ;)xChanging bytea to use FLEXIBLE_ARRAY_MEMBER requires those changes, or
at least some changes in this area as something with
FLEXIBLE_ARRAY_MEMBER can only be placed at the end of a structure.
Again, I think you're confusing things that may not be be done in a
single struct, and structs that are embedded in other places.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-02-16 21:34:57 -0500, Tom Lane wrote:
Andres Freund <andres@2ndquadrant.com> writes:
On 2015-02-17 05:51:22 +0900, Michael Paquier wrote:
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index e01e6aa..d8789a5 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -56,8 +56,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC int32 rolconnlimit; /* max connections allowed (-1=no limit) *//* remaining fields may be null; use heap_getattr to read them! */ - text rolpassword; /* password, if any */ timestamptz rolvaliduntil; /* password expiration time, if any */ +#ifdef CATALOG_VARLEN + text rolpassword; /* password, if any */ +#endif } FormData_pg_authid;That change IIRC is wrong, because it'll make rolvaliduntil until NOT
NULL (any column that's fixed width and has only fixed with columns
before it is marked as such).You were muttering about a BKI_FORCE_NOT_NULL option ... for symmetry,
maybe we could add BKI_FORCE_NULL as well, and then use that for cases
like this?
Yea, I guess it'd not be too hard.
Also, if we want to insist that these fields be accessed
through heap_getattr, I'd be inclined to put them inside the "#ifdef
CATALOG_VARLEN" to enforce that.
That we definitely should do. It's imo just a small bug that it was
omitted here. I'll fix it, but not backpatch unless you prefer?
I'm generally -1 on reordering any catalog columns as part of this patch.
There should be zero user-visible change from it IMO. However, if we
stick both those columns inside the ifdef, we don't need to reorder.
Agreed.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@2ndquadrant.com> writes:
On 2015-02-16 21:34:57 -0500, Tom Lane wrote:
Also, if we want to insist that these fields be accessed
through heap_getattr, I'd be inclined to put them inside the "#ifdef
CATALOG_VARLEN" to enforce that.
That we definitely should do. It's imo just a small bug that it was
omitted here. I'll fix it, but not backpatch unless you prefer?
Agreed, that's really independent of FLEXIBLE_ARRAY_MEMBER, so fix
it as its own patch. I also agree that back-patching is probably
not appropriate.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Feb 18, 2015 at 10:09 PM, Andres Freund <andres@2ndquadrant.com> wrote:
On 2015-02-18 17:15:18 +0900, Michael Paquier wrote:
- I don't think that the t_bits fields in htup_details.h should be
updated either.Why not? Any not broken code should already use MinHeapTupleSize and
similar macros.Changing t_bits impacts HeapTupleHeaderData, ReorderBufferTupleBuf and
similarly a couple of redo routines in heapam.c using
HeapTupleHeaderData in a couple of structures not placing it at the
end (compiler complains).The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.
clang does complain on my OSX laptop regarding that ;)
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-02-19 07:10:19 +0900, Michael Paquier wrote:
On Wed, Feb 18, 2015 at 10:09 PM, Andres Freund <andres@2ndquadrant.com> wrote:
On 2015-02-18 17:15:18 +0900, Michael Paquier wrote:
- I don't think that the t_bits fields in htup_details.h should be
updated either.Why not? Any not broken code should already use MinHeapTupleSize and
similar macros.Changing t_bits impacts HeapTupleHeaderData, ReorderBufferTupleBuf and
similarly a couple of redo routines in heapam.c using
HeapTupleHeaderData in a couple of structures not placing it at the
end (compiler complains).The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.clang does complain on my OSX laptop regarding that ;)
I think that then puts the idea of doing it for those structs pretty
much to bed.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Michael Paquier <michael.paquier@gmail.com> writes:
On Wed, Feb 18, 2015 at 10:09 PM, Andres Freund <andres@2ndquadrant.com> wrote:
The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.
clang does complain on my OSX laptop regarding that ;)
I'm a bit astonished that gcc doesn't consider this an error. Sure seems
like it should. (Has anyone tried it on recent gcc?) I am entirely
opposed to Andreas' claim that we ought to consider compilers that do warn
to be broken; if anything it's the other way around.
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Feb 19, 2015 at 7:29 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
On Wed, Feb 18, 2015 at 10:09 PM, Andres Freund <andres@2ndquadrant.com> wrote:
The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.clang does complain on my OSX laptop regarding that ;)
I'm a bit astonished that gcc doesn't consider this an error. Sure seems
like it should. (Has anyone tried it on recent gcc?)
Just tried with gcc 4.9.2 on an ArchLinux bix and it does not complain
after switching the declaration of varlena declaration from [1] to
FLEXIBLE_ARRAY_MEMBER in c.h on HEAD. But it does with clang 3.5.1 on
the same box.
I am entirely
opposed to Andreas' claim that we ought to consider compilers that do warn
to be broken; if anything it's the other way around.
I'm on board with that.
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?
AFAIK, switching a bunch of things to use FLEXIBLE_ARRAY_MEMBER has
put a couple of things in light that could be revisited:
1) tuptoaster.c, with this declaration of varlena:
struct
{
struct varlena hdr;
char data[TOAST_MAX_CHUNK_SIZE]; /* make
struct big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} chunk_data;
2) inv_api.c with this thing:
struct
{
bytea hdr;
char data[LOBLKSIZE]; /* make struct
big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} workbuf;
3) heapam.c in three places with HeapTupleHeaderData:
struct
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;
4) pg_authid.h with its use of relpasswd.
5) reorderbuffer.h with its use of HeapTupleHeaderData:
typedef struct ReorderBufferTupleBuf
{
/* position in preallocated list */
slist_node node;
/* tuple, stored sequentially */
HeapTupleData tuple;
HeapTupleHeaderData header;
char data[MaxHeapTupleSize];
} ReorderBufferTupleBuf;
Those issues can be grouped depending on where foo[1] is switched to
FLEXIBLE_ARRAY_MEMBER, so I will try to get a set of patches depending
on that.
Regards,
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Michael Paquier <michael.paquier@gmail.com> writes:
On Thu, Feb 19, 2015 at 7:29 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?
AFAIK, switching a bunch of things to use FLEXIBLE_ARRAY_MEMBER has
put a couple of things in light that could be revisited:
1) tuptoaster.c, with this declaration of varlena:
struct
{
struct varlena hdr;
char data[TOAST_MAX_CHUNK_SIZE]; /* make
struct big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} chunk_data;
I'm pretty sure that thing ought to be a union, not a struct.
2) inv_api.c with this thing:
struct
{
bytea hdr;
char data[LOBLKSIZE]; /* make struct
big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} workbuf;
And probably this too.
3) heapam.c in three places with HeapTupleHeaderData:
struct
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;
And this, though I'm not sure if we'd have to change the size of the
padding data[] member.
5) reorderbuffer.h with its use of HeapTupleHeaderData:
Hmm. Andres will have to answer for that one ;-)
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 19/02/15 15:00, Tom Lane wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
On Thu, Feb 19, 2015 at 7:29 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?AFAIK, switching a bunch of things to use FLEXIBLE_ARRAY_MEMBER has
put a couple of things in light that could be revisited:
1) tuptoaster.c, with this declaration of varlena:
struct
{
struct varlena hdr;
char data[TOAST_MAX_CHUNK_SIZE]; /* make
struct big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} chunk_data;I'm pretty sure that thing ought to be a union, not a struct.
2) inv_api.c with this thing:
struct
{
bytea hdr;
char data[LOBLKSIZE]; /* make struct
big enough */
int32 align_it; /* ensure struct is
aligned well enough */
} workbuf;And probably this too.
3) heapam.c in three places with HeapTupleHeaderData:
struct
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;And this, though I'm not sure if we'd have to change the size of the
padding data[] member.5) reorderbuffer.h with its use of HeapTupleHeaderData:
Hmm. Andres will have to answer for that one ;-)
regards, tom lane
Curious, has this problem been raised with the gcc maintainers?
Is this still a problem with gcc 5.0 (which is due to be released soon)?
Cheers,
Gavin
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Feb 19, 2015 at 11:00 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
On Thu, Feb 19, 2015 at 7:29 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?AFAIK, switching a bunch of things to use FLEXIBLE_ARRAY_MEMBER has
put a couple of things in light that could be revisited:
1) tuptoaster.c, with this declaration of varlena:
struct
...
} chunk_data;I'm pretty sure that thing ought to be a union, not a struct.
2) inv_api.c with this thing:
...And probably this too.
Sounds good to me, but with an additional VARHDRSZ to give enough room
IMO (or toast_save_datum explodes).
3) heapam.c in three places with HeapTupleHeaderData:
struct
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;And this, though I'm not sure if we'd have to change the size of the
padding data[] member.
Here I think that we should add sizeof(HeapTupleHeaderData) to ensure
that there is enough room
5) reorderbuffer.h with its use of HeapTupleHeaderData:
Hmm. Andres will have to answer for that one ;-)
Surely. This impacts decode.c and reorder.c at quick glance.
So, attached are a new set of patches:
1) 0001 is more or less the same as upthread, changing trivial places
with foo[1]. I have checked as well calls to sizeof for the structures
impacted:
1-1) In dumputils.c, I guess that the call of sizeof with
SimpleStringListCell should be changed as follows:
cell = (SimpleStringListCell *)
- pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
+ pg_malloc(sizeof(SimpleStringListCell));
1-2) sizeof(ParamListInfoData) is present in a couple of places,
assuming that sizeof(ParamListInfoData) has the equivalent of 1
parameter, like prepare.c, functions.c, spi.c and postgres.c:
- /* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo)
palloc(sizeof(ParamListInfoData) +
- (num_params - 1) * sizeof(ParamExternData));
+ num_params * sizeof(ParamExternData));
1-3) FuncCandidateList in namespace.c (thanks Andres!):
newResult = (FuncCandidateList)
- palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
- + effective_nargs * sizeof(Oid));
+ palloc(sizeof(struct _FuncCandidateList) +
+ effective_nargs * sizeof(Oid));
I imagine that we do not want for those palloc calls to use ifdef
FLEXIBLE_ARRAY_MEMBER to save some memory for code readability even if
compiler does not support flexible-array length, right?
2) 0002 fixes pg_authid to use CATALOG_VARLEN, this is needed for 0003.
3) 0003 switches varlena in c.h to use FLEXIBLE_ARRAY_MEMBER, with
necessary tweaks added for tuptoaster.c and inv_api.c
4) 0004 is some preparatory work before switching HeapTupleHeaderData
and MinimalTupleData, changing the struct declarations to union in
heapam.c with enough room ensured for processing.
Regards,
--
Michael
Attachments:
0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchDownload
From 509e9e28e523624881b2584ce05c78fc422cff44 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 02:44:10 +0900
Subject: [PATCH 1/4] First cut with FLEXIBLE_ARRAY_MEMBER
This is targetted to prevent false positive errors that static code
analyzers may do by assuming that some structures have an unvarying
size.
---
contrib/cube/cubedata.h | 7 +++----
contrib/intarray/_int.h | 4 ++--
contrib/ltree/ltree.h | 14 +++++++-------
contrib/pg_trgm/trgm.h | 2 +-
src/backend/catalog/namespace.c | 4 ++--
src/backend/commands/prepare.c | 4 ++--
src/backend/executor/functions.c | 3 +--
src/backend/executor/spi.c | 3 +--
src/backend/nodes/params.c | 3 +--
src/backend/tcop/postgres.c | 3 +--
src/bin/pg_dump/dumputils.c | 3 +--
src/bin/pg_dump/dumputils.h | 2 +-
src/include/access/gin_private.h | 2 +-
src/include/access/gist_private.h | 5 +++--
src/include/access/heapam_xlog.h | 2 +-
src/include/access/spgist_private.h | 10 +++++-----
src/include/access/xact.h | 8 ++++----
src/include/c.h | 4 ++--
src/include/catalog/namespace.h | 4 ++--
src/include/commands/dbcommands.h | 4 ++--
src/include/commands/tablespace.h | 2 +-
src/include/executor/hashjoin.h | 2 +-
src/include/nodes/bitmapset.h | 4 ++--
src/include/nodes/params.h | 2 +-
src/include/nodes/tidbitmap.h | 2 +-
src/include/postgres.h | 9 +++++----
src/include/postmaster/syslogger.h | 2 +-
src/include/replication/walsender_private.h | 2 +-
src/include/storage/bufpage.h | 3 ++-
src/include/storage/fsm_internals.h | 2 +-
src/include/storage/standby.h | 4 ++--
src/include/tsearch/dicts/regis.h | 2 +-
src/include/tsearch/dicts/spell.h | 6 +++---
src/include/tsearch/ts_type.h | 6 +++---
src/include/utils/catcache.h | 4 ++--
src/include/utils/datetime.h | 5 +++--
src/include/utils/geo_decls.h | 5 +++--
src/include/utils/jsonb.h | 2 +-
src/include/utils/relmapper.h | 2 +-
src/include/utils/varbit.h | 3 ++-
40 files changed, 80 insertions(+), 80 deletions(-)
diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h
index 5d44e11..3535847 100644
--- a/contrib/cube/cubedata.h
+++ b/contrib/cube/cubedata.h
@@ -23,11 +23,10 @@ typedef struct NDBOX
unsigned int header;
/*
- * Variable length array. The lower left coordinates for each dimension
- * come first, followed by upper right coordinates unless the point flag
- * is set.
+ * The lower left coordinates for each dimension come first, followed
+ * by upper right coordinates unless the point flag is set.
*/
- double x[1];
+ double x[FLEXIBLE_ARRAY_MEMBER];
} NDBOX;
#define POINT_BIT 0x80000000
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
index 7f93206..d524f0f 100644
--- a/contrib/intarray/_int.h
+++ b/contrib/intarray/_int.h
@@ -73,7 +73,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} GISTTYPE;
#define ALLISTRUE 0x04
@@ -133,7 +133,7 @@ typedef struct QUERYTYPE
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of ITEMs */
- ITEM items[1]; /* variable length array */
+ ITEM items[FLEXIBLE_ARRAY_MEMBER];
} QUERYTYPE;
#define HDRSIZEQT offsetof(QUERYTYPE, items)
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index 1b1305b..c604357 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -10,7 +10,7 @@
typedef struct
{
uint16 len;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} ltree_level;
#define LEVEL_HDRSIZE (offsetof(ltree_level,name))
@@ -20,7 +20,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint16 numlevel;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree;
#define LTREE_HDRSIZE MAXALIGN( offsetof(ltree, data) )
@@ -34,7 +34,7 @@ typedef struct
int32 val;
uint16 len;
uint8 flag;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} lquery_variant;
#define LVAR_HDRSIZE MAXALIGN(offsetof(lquery_variant, name))
@@ -51,7 +51,7 @@ typedef struct
uint16 numvar;
uint16 low;
uint16 high;
- char variants[1];
+ char variants[FLEXIBLE_ARRAY_MEMBER];
} lquery_level;
#define LQL_HDRSIZE MAXALIGN( offsetof(lquery_level,variants) )
@@ -72,7 +72,7 @@ typedef struct
uint16 numlevel;
uint16 firstgood;
uint16 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} lquery;
#define LQUERY_HDRSIZE MAXALIGN( offsetof(lquery, data) )
@@ -107,7 +107,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltxtquery;
#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32))
@@ -208,7 +208,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree_gist;
#define LTG_ONENODE 0x01
diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h
index ed649b8..f030558 100644
--- a/contrib/pg_trgm/trgm.h
+++ b/contrib/pg_trgm/trgm.h
@@ -63,7 +63,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint8 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} TRGM;
#define TRGMHDRSIZE (VARHDRSZ + sizeof(uint8))
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index bfb4fdc..1ee0755 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1075,8 +1075,8 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
*/
effective_nargs = Max(pronargs, nargs);
newResult = (FuncCandidateList)
- palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
- + effective_nargs * sizeof(Oid));
+ palloc(sizeof(struct _FuncCandidateList) +
+ effective_nargs * sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 71b08f0..d36e1be 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -383,10 +383,10 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
/* Prepare the expressions for execution */
exprstates = (List *) ExecPrepareExpr((Expr *) params, estate);
- /* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo)
palloc(sizeof(ParamListInfoData) +
- (num_params - 1) * sizeof(ParamExternData));
+ num_params * sizeof(ParamExternData));
+
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 84be37c..a1ab662 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -896,9 +896,8 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
if (fcache->paramLI == NULL)
{
- /* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (nargs - 1) * sizeof(ParamExternData));
+ nargs * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 4b86e91..12406b3 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2290,9 +2290,8 @@ _SPI_convert_params(int nargs, Oid *argtypes,
{
int i;
- /* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (nargs - 1) * sizeof(ParamExternData));
+ nargs * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c
index 2f2f5ed..3107de8 100644
--- a/src/backend/nodes/params.c
+++ b/src/backend/nodes/params.c
@@ -40,9 +40,8 @@ copyParamList(ParamListInfo from)
if (from == NULL || from->numParams <= 0)
return NULL;
- /* sizeof(ParamListInfoData) includes the first array element */
size = sizeof(ParamListInfoData) +
- (from->numParams - 1) * sizeof(ParamExternData);
+ from->numParams * sizeof(ParamExternData);
retval = (ParamListInfo) palloc(size);
retval->paramFetch = NULL;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 28af40c..22fbc83 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1619,9 +1619,8 @@ exec_bind_message(StringInfo input_message)
{
int paramno;
- /* sizeof(ParamListInfoData) includes the first array element */
params = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (numParams - 1) * sizeof(ParamExternData));
+ numParams * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
params->paramFetch = NULL;
params->paramFetchArg = NULL;
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 095c507..892d3fa 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -1217,8 +1217,7 @@ simple_string_list_append(SimpleStringList *list, const char *val)
SimpleStringListCell *cell;
/* this calculation correctly accounts for the null trailing byte */
- cell = (SimpleStringListCell *)
- pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
+ cell = (SimpleStringListCell *) pg_malloc(sizeof(SimpleStringListCell));
cell->next = NULL;
strcpy(cell->val, val);
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index a39c1b6..94476a9 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -38,7 +38,7 @@ typedef struct SimpleOidList
typedef struct SimpleStringListCell
{
struct SimpleStringListCell *next;
- char val[1]; /* VARIABLE LENGTH FIELD */
+ char val[FLEXIBLE_ARRAY_MEMBER];
} SimpleStringListCell;
typedef struct SimpleStringList
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index bda7c28..d3abbc0 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -389,7 +389,7 @@ typedef struct
{
ItemPointerData first; /* first item in this posting list (unpacked) */
uint16 nbytes; /* number of bytes that follow */
- unsigned char bytes[1]; /* varbyte encoded items (variable length) */
+ unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]; /* varbyte encoded items */
} GinPostingList;
#define SizeOfGinPostingList(plist) (offsetof(GinPostingList, bytes) + SHORTALIGN((plist)->nbytes) )
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 382826e..36f5257 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -47,7 +47,7 @@ typedef struct
{
BlockNumber prev;
uint32 freespace;
- char tupledata[1];
+ char tupledata[FLEXIBLE_ARRAY_MEMBER];
} GISTNodeBufferPage;
#define BUFFER_PAGE_DATA_OFFSET MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))
@@ -131,7 +131,8 @@ typedef struct GISTSearchItem
/* we must store parentlsn to detect whether a split occurred */
GISTSearchHeapItem heap; /* heap info, if heap tuple */
} data;
- double distances[1]; /* array with numberOfOrderBys entries */
+ double distances[FLEXIBLE_ARRAY_MEMBER]; /* array with numberOfOrderBys
+ * entries */
} GISTSearchItem;
#define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber)
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index a2ed2a0..f0f89de 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -132,7 +132,7 @@ typedef struct xl_heap_multi_insert
{
uint8 flags;
uint16 ntuples;
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_multi_insert;
#define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets)
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index f11d8ef..0492ef6 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -426,7 +426,7 @@ typedef struct spgxlogMoveLeafs
* the dead tuple from the source
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogMoveLeafs;
#define SizeOfSpgxlogMoveLeafs offsetof(spgxlogMoveLeafs, offsets)
@@ -534,7 +534,7 @@ typedef struct spgxlogPickSplit
* list of leaf tuples, length nInsert (unaligned!)
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogPickSplit;
#define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets)
@@ -558,7 +558,7 @@ typedef struct spgxlogVacuumLeaf
* tuple numbers to insert in nextOffset links
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumLeaf;
#define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets)
@@ -571,7 +571,7 @@ typedef struct spgxlogVacuumRoot
spgxlogState stateSrc;
/* offsets of tuples to delete follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRoot;
#define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets)
@@ -583,7 +583,7 @@ typedef struct spgxlogVacuumRedirect
TransactionId newestRedirectXid; /* newest XID of removed redirects */
/* offsets of redirect tuples to make placeholders follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRedirect;
#define SizeOfSpgxlogVacuumRedirect offsetof(spgxlogVacuumRedirect, offsets)
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8205504..9b95f10 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -118,7 +118,7 @@ typedef struct xl_xact_assignment
{
TransactionId xtop; /* assigned XID's top-level XID */
int nsubxacts; /* number of subtransaction XIDs */
- TransactionId xsub[1]; /* assigned subxids */
+ TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */
} xl_xact_assignment;
#define MinSizeOfXactAssignment offsetof(xl_xact_assignment, xsub)
@@ -128,7 +128,7 @@ typedef struct xl_xact_commit_compact
TimestampTz xact_time; /* time of commit */
int nsubxacts; /* number of subtransaction XIDs */
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
- TransactionId subxacts[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_commit_compact;
#define MinSizeOfXactCommitCompact offsetof(xl_xact_commit_compact, subxacts)
@@ -143,7 +143,7 @@ typedef struct xl_xact_commit
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
/* Array of RelFileNode(s) to drop at commit */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
/* ARRAY OF SHARED INVALIDATION MESSAGES FOLLOWS */
} xl_xact_commit;
@@ -171,7 +171,7 @@ typedef struct xl_xact_abort
int nrels; /* number of RelFileNodes */
int nsubxacts; /* number of subtransaction XIDs */
/* Array of RelFileNode(s) to drop at abort */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF ABORTED SUBTRANSACTION XIDs FOLLOWS */
} xl_xact_abort;
diff --git a/src/include/c.h b/src/include/c.h
index b187520..bbd0d53 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -424,7 +424,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- int16 values[1]; /* VARIABLE LENGTH ARRAY */
+ int16 values[FLEXIBLE_ARRAY_MEMBER];
} int2vector; /* VARIABLE LENGTH STRUCT */
typedef struct
@@ -435,7 +435,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- Oid values[1]; /* VARIABLE LENGTH ARRAY */
+ Oid values[FLEXIBLE_ARRAY_MEMBER];
} oidvector; /* VARIABLE LENGTH STRUCT */
/*
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index d2e5198..cf5f7d0 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -34,8 +34,8 @@ typedef struct _FuncCandidateList
int nvargs; /* number of args to become variadic array */
int ndargs; /* number of defaulted args */
int *argnumbers; /* args' positional indexes, if named call */
- Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
-} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
+ Oid args[FLEXIBLE_ARRAY_MEMBER]; /* arg types */
+} *FuncCandidateList;
/*
* Structure for xxxOverrideSearchPath functions
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index cb7cc0e..be1cac2 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -26,7 +26,7 @@ typedef struct xl_dbase_create_rec_old
{
/* Records copying of a single subdirectory incl. contents */
Oid db_id;
- char src_path[1]; /* VARIABLE LENGTH STRING */
+ char src_path[FLEXIBLE_ARRAY_MEMBER];
/* dst_path follows src_path */
} xl_dbase_create_rec_old;
@@ -34,7 +34,7 @@ typedef struct xl_dbase_drop_rec_old
{
/* Records dropping of a single subdirectory incl. contents */
Oid db_id;
- char dir_path[1]; /* VARIABLE LENGTH STRING */
+ char dir_path[FLEXIBLE_ARRAY_MEMBER];
} xl_dbase_drop_rec_old;
typedef struct xl_dbase_create_rec
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index e8b9bc4..9e40e31 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -25,7 +25,7 @@
typedef struct xl_tblspc_create_rec
{
Oid ts_id;
- char ts_path[1]; /* VARIABLE LENGTH STRING */
+ char ts_path[FLEXIBLE_ARRAY_MEMBER];
} xl_tblspc_create_rec;
typedef struct xl_tblspc_drop_rec
diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h
index e79df71..71099b1 100644
--- a/src/include/executor/hashjoin.h
+++ b/src/include/executor/hashjoin.h
@@ -114,7 +114,7 @@ typedef struct HashMemoryChunkData
struct HashMemoryChunkData *next; /* pointer to the next chunk (linked list) */
- char data[1]; /* buffer allocated at the end */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* buffer allocated at the end */
} HashMemoryChunkData;
typedef struct HashMemoryChunkData *HashMemoryChunk;
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 5f45f4d..3a556ee 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -32,8 +32,8 @@ typedef int32 signedbitmapword; /* must be the matching signed type */
typedef struct Bitmapset
{
int nwords; /* number of words in array */
- bitmapword words[1]; /* really [nwords] */
-} Bitmapset; /* VARIABLE LENGTH STRUCT */
+ bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */
+} Bitmapset;
/* result of bms_subset_compare */
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index 5b096c5..a0f7dd0 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -71,7 +71,7 @@ typedef struct ParamListInfoData
ParserSetupHook parserSetup; /* parser setup hook */
void *parserSetupArg;
int numParams; /* number of ParamExternDatas following */
- ParamExternData params[1]; /* VARIABLE LENGTH ARRAY */
+ ParamExternData params[FLEXIBLE_ARRAY_MEMBER];
} ParamListInfoData;
diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h
index fb62c9e..bfbc0fb 100644
--- a/src/include/nodes/tidbitmap.h
+++ b/src/include/nodes/tidbitmap.h
@@ -41,7 +41,7 @@ typedef struct
int ntuples; /* -1 indicates lossy result */
bool recheck; /* should the tuples be rechecked? */
/* Note: recheck is always true if ntuples < 0 */
- OffsetNumber offsets[1]; /* VARIABLE LENGTH ARRAY */
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} TBMIterateResult; /* VARIABLE LENGTH STRUCT */
/* function prototypes in nodes/tidbitmap.c */
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 082c75b..482e676 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -117,20 +117,20 @@ typedef union
struct /* Normal varlena (4-byte length) */
{
uint32 va_header;
- char va_data[1];
+ char va_data[FLEXIBLE_ARRAY_MEMBER];
} va_4byte;
struct /* Compressed-in-line format */
{
uint32 va_header;
uint32 va_rawsize; /* Original data size (excludes header) */
- char va_data[1]; /* Compressed data */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Compressed data */
} va_compressed;
} varattrib_4b;
typedef struct
{
uint8 va_header;
- char va_data[1]; /* Data begins here */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */
} varattrib_1b;
/* TOAST pointers are a subset of varattrib_1b with an identifying tag byte */
@@ -138,7 +138,8 @@ typedef struct
{
uint8 va_header; /* Always 0x80 or 0x01 */
uint8 va_tag; /* Type of datum */
- char va_data[1]; /* Data (of the type indicated by va_tag) */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data (of the type
+ * indicated by va_tag) */
} varattrib_1b_e;
/*
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 602b13c..89a535c 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -48,7 +48,7 @@ typedef struct
int32 pid; /* writer's pid */
char is_last; /* last chunk of message? 't' or 'f' ('T' or
* 'F' for CSV case) */
- char data[1]; /* data payload starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data payload starts here */
} PipeProtoHeader;
typedef union
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 8867750..02faad8 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -88,7 +88,7 @@ typedef struct
*/
bool sync_standbys_defined;
- WalSnd walsnds[1]; /* VARIABLE LENGTH ARRAY */
+ WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
} WalSndCtlData;
extern WalSndCtlData *WalSndCtl;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index f693032..b7dbd6f 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -156,7 +156,8 @@ typedef struct PageHeaderData
LocationIndex pd_special; /* offset to start of special space */
uint16 pd_pagesize_version;
TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
- ItemIdData pd_linp[1]; /* beginning of line pointer array */
+ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* beginning of line pointer
+ * array */
} PageHeaderData;
typedef PageHeaderData *PageHeader;
diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h
index 1decd90..26340b4 100644
--- a/src/include/storage/fsm_internals.h
+++ b/src/include/storage/fsm_internals.h
@@ -39,7 +39,7 @@ typedef struct
* NonLeafNodesPerPage elements are upper nodes, and the following
* LeafNodesPerPage elements are leaf nodes. Unused nodes are zero.
*/
- uint8 fp_nodes[1];
+ uint8 fp_nodes[FLEXIBLE_ARRAY_MEMBER];
} FSMPageData;
typedef FSMPageData *FSMPage;
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index c32c963..7626c4c 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -60,7 +60,7 @@ extern void StandbyReleaseOldLocks(int nxids, TransactionId *xids);
typedef struct xl_standby_locks
{
int nlocks; /* number of entries in locks array */
- xl_standby_lock locks[1]; /* VARIABLE LENGTH ARRAY */
+ xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER];
} xl_standby_locks;
/*
@@ -75,7 +75,7 @@ typedef struct xl_running_xacts
TransactionId oldestRunningXid; /* *not* oldestXmin */
TransactionId latestCompletedXid; /* so we can set xmax */
- TransactionId xids[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId xids[FLEXIBLE_ARRAY_MEMBER];
} xl_running_xacts;
#define MinSizeOfXactRunningXacts offsetof(xl_running_xacts, xids)
diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h
index 081a502..ddf5b60 100644
--- a/src/include/tsearch/dicts/regis.h
+++ b/src/include/tsearch/dicts/regis.h
@@ -21,7 +21,7 @@ typedef struct RegisNode
len:16,
unused:14;
struct RegisNode *next;
- unsigned char data[1];
+ unsigned char data[FLEXIBLE_ARRAY_MEMBER];
} RegisNode;
#define RNHDRSZ (offsetof(RegisNode,data))
diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h
index a75552b..e512532 100644
--- a/src/include/tsearch/dicts/spell.h
+++ b/src/include/tsearch/dicts/spell.h
@@ -49,7 +49,7 @@ typedef struct
typedef struct SPNode
{
uint32 length;
- SPNodeData data[1];
+ SPNodeData data[FLEXIBLE_ARRAY_MEMBER];
} SPNode;
#define SPNHDRSZ (offsetof(SPNode,data))
@@ -70,7 +70,7 @@ typedef struct spell_struct
int len;
} d;
} p;
- char word[1]; /* variable length, null-terminated */
+ char word[FLEXIBLE_ARRAY_MEMBER];
} SPELL;
#define SPELLHDRSZ (offsetof(SPELL, word))
@@ -120,7 +120,7 @@ typedef struct AffixNode
{
uint32 isvoid:1,
length:31;
- AffixNodeData data[1];
+ AffixNodeData data[FLEXIBLE_ARRAY_MEMBER];
} AffixNode;
#define ANHRDSZ (offsetof(AffixNode, data))
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 1cdfa82..ce919a2 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -63,7 +63,7 @@ typedef uint16 WordEntryPos;
typedef struct
{
uint16 npos;
- WordEntryPos pos[1]; /* variable length */
+ WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER];
} WordEntryPosVector;
@@ -82,7 +82,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- WordEntry entries[1]; /* variable length */
+ WordEntry entries[FLEXIBLE_ARRAY_MEMBER];
/* lexemes follow the entries[] array */
} TSVectorData;
@@ -233,7 +233,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of QueryItems */
- char data[1]; /* data starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data starts here */
} TSQueryData;
typedef TSQueryData *TSQuery;
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index 8084785..da261e8 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -147,8 +147,8 @@ typedef struct catclist
uint32 hash_value; /* hash value for lookup keys */
HeapTupleData tuple; /* header for tuple holding keys */
int n_members; /* number of member tuples */
- CatCTup *members[1]; /* members --- VARIABLE LENGTH ARRAY */
-} CatCList; /* VARIABLE LENGTH STRUCT */
+ CatCTup *members[FLEXIBLE_ARRAY_MEMBER]; /* members */
+} CatCList;
typedef struct catcacheheader
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 8912ba5..d36f297 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -219,7 +219,7 @@ typedef struct TimeZoneAbbrevTable
{
Size tblsize; /* size in bytes of TimeZoneAbbrevTable */
int numabbrevs; /* number of entries in abbrevs[] array */
- datetkn abbrevs[1]; /* VARIABLE LENGTH ARRAY */
+ datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER];
/* DynamicZoneAbbrev(s) may follow the abbrevs[] array */
} TimeZoneAbbrevTable;
@@ -227,7 +227,8 @@ typedef struct TimeZoneAbbrevTable
typedef struct DynamicZoneAbbrev
{
pg_tz *tz; /* NULL if not yet looked up */
- char zone[1]; /* zone name (var length, NUL-terminated) */
+ char zone[FLEXIBLE_ARRAY_MEMBER]; /* zone name (var length,
+ * NUL-terminated) */
} DynamicZoneAbbrev;
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0b6d3c3..a0f779b 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -80,7 +80,8 @@ typedef struct
int32 npts;
int32 closed; /* is this a closed polygon? */
int32 dummy; /* padding to make it double align */
- Point p[1]; /* variable length array of POINTs */
+ Point p[FLEXIBLE_ARRAY_MEMBER]; /* variable length array
+ * of POINTs */
} PATH;
@@ -115,7 +116,7 @@ typedef struct
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 npts;
BOX boundbox;
- Point p[1]; /* variable length array of POINTs */
+ Point p[FLEXIBLE_ARRAY_MEMBER];
} POLYGON;
/*---------------------------------------------------------------------
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index 887eb9b..9d1770e 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -194,7 +194,7 @@ typedef struct JsonbContainer
{
uint32 header; /* number of elements or key/value pairs, and
* flags */
- JEntry children[1]; /* variable length */
+ JEntry children[FLEXIBLE_ARRAY_MEMBER];
/* the data for each child node follows. */
} JsonbContainer;
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 420310d..73b4905 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -29,7 +29,7 @@ typedef struct xl_relmap_update
Oid dbid; /* database ID, or 0 for shared map */
Oid tsid; /* database's tablespace, or pg_global */
int32 nbytes; /* size of relmap data */
- char data[1]; /* VARIABLE LENGTH ARRAY */
+ char data[FLEXIBLE_ARRAY_MEMBER];
} xl_relmap_update;
#define MinSizeOfRelmapUpdate offsetof(xl_relmap_update, data)
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index 8afc3b1..bd5bf52 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -26,7 +26,8 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 bit_len; /* number of valid bits */
- bits8 bit_dat[1]; /* bit string, most sig. byte first */
+ bits8 bit_dat[FLEXIBLE_ARRAY_MEMBER]; /* bit string, most sig.
+ * byte first */
} VarBit;
/*
--
2.3.0
0002-Add-forgotten-CATALOG_VARLEN-pg_authid.patchapplication/x-patch; name=0002-Add-forgotten-CATALOG_VARLEN-pg_authid.patchDownload
From 0a0b6b58224c8f1b361dbf202a2d8ab0e300a2e3 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 13:40:59 +0900
Subject: [PATCH 2/4] Add forgotten CATALOG_VARLEN pg_authid
The laste two fields of this catalog table, rolvaliduntil and rolpassword
can be null, but were not marked as such.
---
src/include/catalog/pg_authid.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
index e01e6aa..5b34288 100644
--- a/src/include/catalog/pg_authid.h
+++ b/src/include/catalog/pg_authid.h
@@ -55,9 +55,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC
bool rolbypassrls; /* allowed to bypass row level security? */
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
- /* remaining fields may be null; use heap_getattr to read them! */
+#ifdef CATALOG_VARLEN
text rolpassword; /* password, if any */
timestamptz rolvaliduntil; /* password expiration time, if any */
+#endif
} FormData_pg_authid;
#undef timestamptz
--
2.3.0
0003-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0003-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
From a62c4cc8ede6600f8ae636dfe9f56c6fd119c638 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 14:02:14 +0900
Subject: [PATCH 3/4] 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 bbd0d53..36ec468 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
0004-Replace-some-struct-declarations-with-union-in-heapa.patchapplication/x-patch; name=0004-Replace-some-struct-declarations-with-union-in-heapa.patchDownload
From cd2016bdd021785daf42ba83919c3175db6337ed Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 14:29:57 +0900
Subject: [PATCH 4/4] Replace some struct declarations with union in heapam.c
To ensure that there is enough room for operations, add a size equivalent
to the tuple header data.
---
src/backend/access/heap/heapam.c | 12 ++++++------
src/include/access/htup_details.h | 2 ++
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 46060bc1..c4b825d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7351,10 +7351,10 @@ 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];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
HeapTupleHeader htup;
xl_heap_header xlhdr;
@@ -7469,10 +7469,10 @@ heap_xlog_multi_insert(XLogReaderState *record)
BlockNumber blkno;
Buffer buffer;
Page page;
- struct
+ union
{
HeapTupleHeaderData hdr;
- char data[MaxHeapTupleSize];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
HeapTupleHeader htup;
uint32 newlen;
@@ -7618,10 +7618,10 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
uint16 prefixlen = 0,
suffixlen = 0;
char *newp;
- struct
+ union
{
HeapTupleHeaderData hdr;
- char data[MaxHeapTupleSize];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
xl_heap_header xlhdr;
uint32 newlen;
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index d2ad910..2da4f42 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -155,6 +155,8 @@ struct HeapTupleHeaderData
/* MORE DATA FOLLOWS AT END OF STRUCT */
};
+#define SizeOfHeapTupleHeaderData MAXALIGN(sizeof(HeapTupleHeaderData))
+
/* typedef appears in tupbasics.h */
/*
--
2.3.0
Michael Paquier <michael.paquier@gmail.com> writes:
1-2) sizeof(ParamListInfoData) is present in a couple of places, assuming that sizeof(ParamListInfoData) has the equivalent of 1 parameter, like prepare.c, functions.c, spi.c and postgres.c: - /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + - (num_params - 1) * sizeof(ParamExternData)); + num_params * sizeof(ParamExternData)); 1-3) FuncCandidateList in namespace.c (thanks Andres!): newResult = (FuncCandidateList) - palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid) - + effective_nargs * sizeof(Oid)); + palloc(sizeof(struct _FuncCandidateList) + + effective_nargs * sizeof(Oid)); I imagine that we do not want for those palloc calls to use ifdef FLEXIBLE_ARRAY_MEMBER to save some memory for code readability even if compiler does not support flexible-array length, right?
These are just wrong. As a general rule, we do not want to *ever* take
sizeof() a struct that contains a flexible array: the results will not
be consistent across platforms. The right thing is to use offsetof()
instead. See the helpful comment autoconf provides:
/* Define to nothing if C supports flexible array members, and to 1 if it does
not. That way, with a declaration like `struct s { int n; double
d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99
compilers. When computing the size of such an object, don't use 'sizeof
(struct s)' as it overestimates the size. Use 'offsetof (struct s, d)'
instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with
MSVC and with C++ compilers. */
#define FLEXIBLE_ARRAY_MEMBER /**/
This point is actually the main reason we've not done this change long
since. People did not feel like running around to make sure there were
no overlooked uses of sizeof().
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Feb 19, 2015 at 2:58 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
1-2) sizeof(ParamListInfoData) is present in a couple of places, assuming that sizeof(ParamListInfoData) has the equivalent of 1 parameter, like prepare.c, functions.c, spi.c and postgres.c: - /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + - (num_params - 1) * sizeof(ParamExternData)); + num_params * sizeof(ParamExternData)); 1-3) FuncCandidateList in namespace.c (thanks Andres!): newResult = (FuncCandidateList) - palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid) - + effective_nargs * sizeof(Oid)); + palloc(sizeof(struct _FuncCandidateList) + + effective_nargs * sizeof(Oid)); I imagine that we do not want for those palloc calls to use ifdef FLEXIBLE_ARRAY_MEMBER to save some memory for code readability even if compiler does not support flexible-array length, right?These are just wrong. As a general rule, we do not want to *ever* take
sizeof() a struct that contains a flexible array: the results will not
be consistent across platforms. The right thing is to use offsetof()
instead. See the helpful comment autoconf provides:[...]
And I had this one in front of my eyes a couple of hours ago... Thanks.
This point is actually the main reason we've not done this change long
since. People did not feel like running around to make sure there were
no overlooked uses of sizeof().
Thanks for the clarifications and the review. Attached is a new set.
--
Michael
Attachments:
0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0001-First-cut-with-FLEXIBLE_ARRAY_MEMBER.patchDownload
From ca92019afc1db4da147ebb5c436164a787f7fa62 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 16 Feb 2015 02:44:10 +0900
Subject: [PATCH 1/4] First cut with FLEXIBLE_ARRAY_MEMBER
This is targetted to prevent false positive errors that static code
analyzers may do by assuming that some structures have an unvarying
size.
---
contrib/cube/cubedata.h | 7 +++----
contrib/intarray/_int.h | 4 ++--
contrib/ltree/ltree.h | 14 +++++++-------
contrib/pg_trgm/trgm.h | 2 +-
src/backend/catalog/namespace.c | 4 ++--
src/backend/commands/prepare.c | 6 +++---
src/backend/executor/functions.c | 6 +++---
src/backend/executor/spi.c | 5 ++---
src/backend/nodes/params.c | 5 ++---
src/backend/tcop/postgres.c | 5 ++---
src/bin/pg_dump/dumputils.c | 3 +--
src/bin/pg_dump/dumputils.h | 2 +-
src/include/access/gin_private.h | 2 +-
src/include/access/gist_private.h | 5 +++--
src/include/access/heapam_xlog.h | 2 +-
src/include/access/spgist_private.h | 10 +++++-----
src/include/access/xact.h | 8 ++++----
src/include/c.h | 4 ++--
src/include/catalog/namespace.h | 4 ++--
src/include/commands/dbcommands.h | 4 ++--
src/include/commands/tablespace.h | 2 +-
src/include/executor/hashjoin.h | 2 +-
src/include/nodes/bitmapset.h | 4 ++--
src/include/nodes/params.h | 2 +-
src/include/nodes/tidbitmap.h | 2 +-
src/include/postgres.h | 9 +++++----
src/include/postmaster/syslogger.h | 2 +-
src/include/replication/walsender_private.h | 2 +-
src/include/storage/bufpage.h | 3 ++-
src/include/storage/fsm_internals.h | 2 +-
src/include/storage/standby.h | 4 ++--
src/include/tsearch/dicts/regis.h | 2 +-
src/include/tsearch/dicts/spell.h | 6 +++---
src/include/tsearch/ts_type.h | 6 +++---
src/include/utils/catcache.h | 4 ++--
src/include/utils/datetime.h | 5 +++--
src/include/utils/geo_decls.h | 5 +++--
src/include/utils/jsonb.h | 2 +-
src/include/utils/relmapper.h | 2 +-
src/include/utils/varbit.h | 3 ++-
40 files changed, 86 insertions(+), 85 deletions(-)
diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h
index 5d44e11..3535847 100644
--- a/contrib/cube/cubedata.h
+++ b/contrib/cube/cubedata.h
@@ -23,11 +23,10 @@ typedef struct NDBOX
unsigned int header;
/*
- * Variable length array. The lower left coordinates for each dimension
- * come first, followed by upper right coordinates unless the point flag
- * is set.
+ * The lower left coordinates for each dimension come first, followed
+ * by upper right coordinates unless the point flag is set.
*/
- double x[1];
+ double x[FLEXIBLE_ARRAY_MEMBER];
} NDBOX;
#define POINT_BIT 0x80000000
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
index 7f93206..d524f0f 100644
--- a/contrib/intarray/_int.h
+++ b/contrib/intarray/_int.h
@@ -73,7 +73,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} GISTTYPE;
#define ALLISTRUE 0x04
@@ -133,7 +133,7 @@ typedef struct QUERYTYPE
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of ITEMs */
- ITEM items[1]; /* variable length array */
+ ITEM items[FLEXIBLE_ARRAY_MEMBER];
} QUERYTYPE;
#define HDRSIZEQT offsetof(QUERYTYPE, items)
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index 1b1305b..c604357 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -10,7 +10,7 @@
typedef struct
{
uint16 len;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} ltree_level;
#define LEVEL_HDRSIZE (offsetof(ltree_level,name))
@@ -20,7 +20,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint16 numlevel;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree;
#define LTREE_HDRSIZE MAXALIGN( offsetof(ltree, data) )
@@ -34,7 +34,7 @@ typedef struct
int32 val;
uint16 len;
uint8 flag;
- char name[1];
+ char name[FLEXIBLE_ARRAY_MEMBER];
} lquery_variant;
#define LVAR_HDRSIZE MAXALIGN(offsetof(lquery_variant, name))
@@ -51,7 +51,7 @@ typedef struct
uint16 numvar;
uint16 low;
uint16 high;
- char variants[1];
+ char variants[FLEXIBLE_ARRAY_MEMBER];
} lquery_level;
#define LQL_HDRSIZE MAXALIGN( offsetof(lquery_level,variants) )
@@ -72,7 +72,7 @@ typedef struct
uint16 numlevel;
uint16 firstgood;
uint16 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} lquery;
#define LQUERY_HDRSIZE MAXALIGN( offsetof(lquery, data) )
@@ -107,7 +107,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltxtquery;
#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32))
@@ -208,7 +208,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint32 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} ltree_gist;
#define LTG_ONENODE 0x01
diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h
index ed649b8..f030558 100644
--- a/contrib/pg_trgm/trgm.h
+++ b/contrib/pg_trgm/trgm.h
@@ -63,7 +63,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
uint8 flag;
- char data[1];
+ char data[FLEXIBLE_ARRAY_MEMBER];
} TRGM;
#define TRGMHDRSIZE (VARHDRSZ + sizeof(uint8))
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index bfb4fdc..d47b523 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1075,8 +1075,8 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
*/
effective_nargs = Max(pronargs, nargs);
newResult = (FuncCandidateList)
- palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
- + effective_nargs * sizeof(Oid));
+ palloc(offsetof(struct _FuncCandidateList, args) +
+ effective_nargs * sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 71b08f0..36e21c1 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -383,10 +383,10 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
/* Prepare the expressions for execution */
exprstates = (List *) ExecPrepareExpr((Expr *) params, estate);
- /* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo)
- palloc(sizeof(ParamListInfoData) +
- (num_params - 1) * sizeof(ParamExternData));
+ palloc(offsetof(ParamListInfoData, params) +
+ num_params * sizeof(ParamExternData));
+
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 84be37c..6c3eff7 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -896,9 +896,9 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
if (fcache->paramLI == NULL)
{
- /* sizeof(ParamListInfoData) includes the first array element */
- paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (nargs - 1) * sizeof(ParamExternData));
+ paramLI = (ParamListInfo)
+ palloc(offsetof(ParamListInfoData, params) +
+ nargs * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 4b86e91..d101fcd 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2290,9 +2290,8 @@ _SPI_convert_params(int nargs, Oid *argtypes,
{
int i;
- /* sizeof(ParamListInfoData) includes the first array element */
- paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (nargs - 1) * sizeof(ParamExternData));
+ paramLI = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) +
+ nargs * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
paramLI->paramFetch = NULL;
paramLI->paramFetchArg = NULL;
diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c
index 2f2f5ed..fb803f8 100644
--- a/src/backend/nodes/params.c
+++ b/src/backend/nodes/params.c
@@ -40,9 +40,8 @@ copyParamList(ParamListInfo from)
if (from == NULL || from->numParams <= 0)
return NULL;
- /* sizeof(ParamListInfoData) includes the first array element */
- size = sizeof(ParamListInfoData) +
- (from->numParams - 1) * sizeof(ParamExternData);
+ size = offsetof(ParamListInfoData, params) +
+ from->numParams * sizeof(ParamExternData);
retval = (ParamListInfo) palloc(size);
retval->paramFetch = NULL;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 28af40c..33720e8 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1619,9 +1619,8 @@ exec_bind_message(StringInfo input_message)
{
int paramno;
- /* sizeof(ParamListInfoData) includes the first array element */
- params = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (numParams - 1) * sizeof(ParamExternData));
+ params = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) +
+ numParams * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
params->paramFetch = NULL;
params->paramFetchArg = NULL;
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 095c507..892d3fa 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -1217,8 +1217,7 @@ simple_string_list_append(SimpleStringList *list, const char *val)
SimpleStringListCell *cell;
/* this calculation correctly accounts for the null trailing byte */
- cell = (SimpleStringListCell *)
- pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
+ cell = (SimpleStringListCell *) pg_malloc(sizeof(SimpleStringListCell));
cell->next = NULL;
strcpy(cell->val, val);
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index a39c1b6..94476a9 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -38,7 +38,7 @@ typedef struct SimpleOidList
typedef struct SimpleStringListCell
{
struct SimpleStringListCell *next;
- char val[1]; /* VARIABLE LENGTH FIELD */
+ char val[FLEXIBLE_ARRAY_MEMBER];
} SimpleStringListCell;
typedef struct SimpleStringList
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index bda7c28..d3abbc0 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -389,7 +389,7 @@ typedef struct
{
ItemPointerData first; /* first item in this posting list (unpacked) */
uint16 nbytes; /* number of bytes that follow */
- unsigned char bytes[1]; /* varbyte encoded items (variable length) */
+ unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]; /* varbyte encoded items */
} GinPostingList;
#define SizeOfGinPostingList(plist) (offsetof(GinPostingList, bytes) + SHORTALIGN((plist)->nbytes) )
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 382826e..36f5257 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -47,7 +47,7 @@ typedef struct
{
BlockNumber prev;
uint32 freespace;
- char tupledata[1];
+ char tupledata[FLEXIBLE_ARRAY_MEMBER];
} GISTNodeBufferPage;
#define BUFFER_PAGE_DATA_OFFSET MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))
@@ -131,7 +131,8 @@ typedef struct GISTSearchItem
/* we must store parentlsn to detect whether a split occurred */
GISTSearchHeapItem heap; /* heap info, if heap tuple */
} data;
- double distances[1]; /* array with numberOfOrderBys entries */
+ double distances[FLEXIBLE_ARRAY_MEMBER]; /* array with numberOfOrderBys
+ * entries */
} GISTSearchItem;
#define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber)
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index a2ed2a0..f0f89de 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -132,7 +132,7 @@ typedef struct xl_heap_multi_insert
{
uint8 flags;
uint16 ntuples;
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} xl_heap_multi_insert;
#define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets)
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index f11d8ef..0492ef6 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -426,7 +426,7 @@ typedef struct spgxlogMoveLeafs
* the dead tuple from the source
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogMoveLeafs;
#define SizeOfSpgxlogMoveLeafs offsetof(spgxlogMoveLeafs, offsets)
@@ -534,7 +534,7 @@ typedef struct spgxlogPickSplit
* list of leaf tuples, length nInsert (unaligned!)
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogPickSplit;
#define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets)
@@ -558,7 +558,7 @@ typedef struct spgxlogVacuumLeaf
* tuple numbers to insert in nextOffset links
*----------
*/
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumLeaf;
#define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets)
@@ -571,7 +571,7 @@ typedef struct spgxlogVacuumRoot
spgxlogState stateSrc;
/* offsets of tuples to delete follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRoot;
#define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets)
@@ -583,7 +583,7 @@ typedef struct spgxlogVacuumRedirect
TransactionId newestRedirectXid; /* newest XID of removed redirects */
/* offsets of redirect tuples to make placeholders follow */
- OffsetNumber offsets[1];
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} spgxlogVacuumRedirect;
#define SizeOfSpgxlogVacuumRedirect offsetof(spgxlogVacuumRedirect, offsets)
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8205504..9b95f10 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -118,7 +118,7 @@ typedef struct xl_xact_assignment
{
TransactionId xtop; /* assigned XID's top-level XID */
int nsubxacts; /* number of subtransaction XIDs */
- TransactionId xsub[1]; /* assigned subxids */
+ TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */
} xl_xact_assignment;
#define MinSizeOfXactAssignment offsetof(xl_xact_assignment, xsub)
@@ -128,7 +128,7 @@ typedef struct xl_xact_commit_compact
TimestampTz xact_time; /* time of commit */
int nsubxacts; /* number of subtransaction XIDs */
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
- TransactionId subxacts[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER];
} xl_xact_commit_compact;
#define MinSizeOfXactCommitCompact offsetof(xl_xact_commit_compact, subxacts)
@@ -143,7 +143,7 @@ typedef struct xl_xact_commit
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
/* Array of RelFileNode(s) to drop at commit */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
/* ARRAY OF SHARED INVALIDATION MESSAGES FOLLOWS */
} xl_xact_commit;
@@ -171,7 +171,7 @@ typedef struct xl_xact_abort
int nrels; /* number of RelFileNodes */
int nsubxacts; /* number of subtransaction XIDs */
/* Array of RelFileNode(s) to drop at abort */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER];
/* ARRAY OF ABORTED SUBTRANSACTION XIDs FOLLOWS */
} xl_xact_abort;
diff --git a/src/include/c.h b/src/include/c.h
index b187520..bbd0d53 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -424,7 +424,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- int16 values[1]; /* VARIABLE LENGTH ARRAY */
+ int16 values[FLEXIBLE_ARRAY_MEMBER];
} int2vector; /* VARIABLE LENGTH STRUCT */
typedef struct
@@ -435,7 +435,7 @@ typedef struct
Oid elemtype;
int dim1;
int lbound1;
- Oid values[1]; /* VARIABLE LENGTH ARRAY */
+ Oid values[FLEXIBLE_ARRAY_MEMBER];
} oidvector; /* VARIABLE LENGTH STRUCT */
/*
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index d2e5198..cf5f7d0 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -34,8 +34,8 @@ typedef struct _FuncCandidateList
int nvargs; /* number of args to become variadic array */
int ndargs; /* number of defaulted args */
int *argnumbers; /* args' positional indexes, if named call */
- Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
-} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
+ Oid args[FLEXIBLE_ARRAY_MEMBER]; /* arg types */
+} *FuncCandidateList;
/*
* Structure for xxxOverrideSearchPath functions
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index cb7cc0e..be1cac2 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -26,7 +26,7 @@ typedef struct xl_dbase_create_rec_old
{
/* Records copying of a single subdirectory incl. contents */
Oid db_id;
- char src_path[1]; /* VARIABLE LENGTH STRING */
+ char src_path[FLEXIBLE_ARRAY_MEMBER];
/* dst_path follows src_path */
} xl_dbase_create_rec_old;
@@ -34,7 +34,7 @@ typedef struct xl_dbase_drop_rec_old
{
/* Records dropping of a single subdirectory incl. contents */
Oid db_id;
- char dir_path[1]; /* VARIABLE LENGTH STRING */
+ char dir_path[FLEXIBLE_ARRAY_MEMBER];
} xl_dbase_drop_rec_old;
typedef struct xl_dbase_create_rec
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index e8b9bc4..9e40e31 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -25,7 +25,7 @@
typedef struct xl_tblspc_create_rec
{
Oid ts_id;
- char ts_path[1]; /* VARIABLE LENGTH STRING */
+ char ts_path[FLEXIBLE_ARRAY_MEMBER];
} xl_tblspc_create_rec;
typedef struct xl_tblspc_drop_rec
diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h
index e79df71..71099b1 100644
--- a/src/include/executor/hashjoin.h
+++ b/src/include/executor/hashjoin.h
@@ -114,7 +114,7 @@ typedef struct HashMemoryChunkData
struct HashMemoryChunkData *next; /* pointer to the next chunk (linked list) */
- char data[1]; /* buffer allocated at the end */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* buffer allocated at the end */
} HashMemoryChunkData;
typedef struct HashMemoryChunkData *HashMemoryChunk;
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 5f45f4d..3a556ee 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -32,8 +32,8 @@ typedef int32 signedbitmapword; /* must be the matching signed type */
typedef struct Bitmapset
{
int nwords; /* number of words in array */
- bitmapword words[1]; /* really [nwords] */
-} Bitmapset; /* VARIABLE LENGTH STRUCT */
+ bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */
+} Bitmapset;
/* result of bms_subset_compare */
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index 5b096c5..a0f7dd0 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -71,7 +71,7 @@ typedef struct ParamListInfoData
ParserSetupHook parserSetup; /* parser setup hook */
void *parserSetupArg;
int numParams; /* number of ParamExternDatas following */
- ParamExternData params[1]; /* VARIABLE LENGTH ARRAY */
+ ParamExternData params[FLEXIBLE_ARRAY_MEMBER];
} ParamListInfoData;
diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h
index fb62c9e..bfbc0fb 100644
--- a/src/include/nodes/tidbitmap.h
+++ b/src/include/nodes/tidbitmap.h
@@ -41,7 +41,7 @@ typedef struct
int ntuples; /* -1 indicates lossy result */
bool recheck; /* should the tuples be rechecked? */
/* Note: recheck is always true if ntuples < 0 */
- OffsetNumber offsets[1]; /* VARIABLE LENGTH ARRAY */
+ OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
} TBMIterateResult; /* VARIABLE LENGTH STRUCT */
/* function prototypes in nodes/tidbitmap.c */
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 082c75b..482e676 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -117,20 +117,20 @@ typedef union
struct /* Normal varlena (4-byte length) */
{
uint32 va_header;
- char va_data[1];
+ char va_data[FLEXIBLE_ARRAY_MEMBER];
} va_4byte;
struct /* Compressed-in-line format */
{
uint32 va_header;
uint32 va_rawsize; /* Original data size (excludes header) */
- char va_data[1]; /* Compressed data */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Compressed data */
} va_compressed;
} varattrib_4b;
typedef struct
{
uint8 va_header;
- char va_data[1]; /* Data begins here */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */
} varattrib_1b;
/* TOAST pointers are a subset of varattrib_1b with an identifying tag byte */
@@ -138,7 +138,8 @@ typedef struct
{
uint8 va_header; /* Always 0x80 or 0x01 */
uint8 va_tag; /* Type of datum */
- char va_data[1]; /* Data (of the type indicated by va_tag) */
+ char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data (of the type
+ * indicated by va_tag) */
} varattrib_1b_e;
/*
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 602b13c..89a535c 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -48,7 +48,7 @@ typedef struct
int32 pid; /* writer's pid */
char is_last; /* last chunk of message? 't' or 'f' ('T' or
* 'F' for CSV case) */
- char data[1]; /* data payload starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data payload starts here */
} PipeProtoHeader;
typedef union
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 8867750..02faad8 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -88,7 +88,7 @@ typedef struct
*/
bool sync_standbys_defined;
- WalSnd walsnds[1]; /* VARIABLE LENGTH ARRAY */
+ WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
} WalSndCtlData;
extern WalSndCtlData *WalSndCtl;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index f693032..b7dbd6f 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -156,7 +156,8 @@ typedef struct PageHeaderData
LocationIndex pd_special; /* offset to start of special space */
uint16 pd_pagesize_version;
TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
- ItemIdData pd_linp[1]; /* beginning of line pointer array */
+ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* beginning of line pointer
+ * array */
} PageHeaderData;
typedef PageHeaderData *PageHeader;
diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h
index 1decd90..26340b4 100644
--- a/src/include/storage/fsm_internals.h
+++ b/src/include/storage/fsm_internals.h
@@ -39,7 +39,7 @@ typedef struct
* NonLeafNodesPerPage elements are upper nodes, and the following
* LeafNodesPerPage elements are leaf nodes. Unused nodes are zero.
*/
- uint8 fp_nodes[1];
+ uint8 fp_nodes[FLEXIBLE_ARRAY_MEMBER];
} FSMPageData;
typedef FSMPageData *FSMPage;
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index c32c963..7626c4c 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -60,7 +60,7 @@ extern void StandbyReleaseOldLocks(int nxids, TransactionId *xids);
typedef struct xl_standby_locks
{
int nlocks; /* number of entries in locks array */
- xl_standby_lock locks[1]; /* VARIABLE LENGTH ARRAY */
+ xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER];
} xl_standby_locks;
/*
@@ -75,7 +75,7 @@ typedef struct xl_running_xacts
TransactionId oldestRunningXid; /* *not* oldestXmin */
TransactionId latestCompletedXid; /* so we can set xmax */
- TransactionId xids[1]; /* VARIABLE LENGTH ARRAY */
+ TransactionId xids[FLEXIBLE_ARRAY_MEMBER];
} xl_running_xacts;
#define MinSizeOfXactRunningXacts offsetof(xl_running_xacts, xids)
diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h
index 081a502..ddf5b60 100644
--- a/src/include/tsearch/dicts/regis.h
+++ b/src/include/tsearch/dicts/regis.h
@@ -21,7 +21,7 @@ typedef struct RegisNode
len:16,
unused:14;
struct RegisNode *next;
- unsigned char data[1];
+ unsigned char data[FLEXIBLE_ARRAY_MEMBER];
} RegisNode;
#define RNHDRSZ (offsetof(RegisNode,data))
diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h
index a75552b..e512532 100644
--- a/src/include/tsearch/dicts/spell.h
+++ b/src/include/tsearch/dicts/spell.h
@@ -49,7 +49,7 @@ typedef struct
typedef struct SPNode
{
uint32 length;
- SPNodeData data[1];
+ SPNodeData data[FLEXIBLE_ARRAY_MEMBER];
} SPNode;
#define SPNHDRSZ (offsetof(SPNode,data))
@@ -70,7 +70,7 @@ typedef struct spell_struct
int len;
} d;
} p;
- char word[1]; /* variable length, null-terminated */
+ char word[FLEXIBLE_ARRAY_MEMBER];
} SPELL;
#define SPELLHDRSZ (offsetof(SPELL, word))
@@ -120,7 +120,7 @@ typedef struct AffixNode
{
uint32 isvoid:1,
length:31;
- AffixNodeData data[1];
+ AffixNodeData data[FLEXIBLE_ARRAY_MEMBER];
} AffixNode;
#define ANHRDSZ (offsetof(AffixNode, data))
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 1cdfa82..ce919a2 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -63,7 +63,7 @@ typedef uint16 WordEntryPos;
typedef struct
{
uint16 npos;
- WordEntryPos pos[1]; /* variable length */
+ WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER];
} WordEntryPosVector;
@@ -82,7 +82,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size;
- WordEntry entries[1]; /* variable length */
+ WordEntry entries[FLEXIBLE_ARRAY_MEMBER];
/* lexemes follow the entries[] array */
} TSVectorData;
@@ -233,7 +233,7 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 size; /* number of QueryItems */
- char data[1]; /* data starts here */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* data starts here */
} TSQueryData;
typedef TSQueryData *TSQuery;
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index 8084785..da261e8 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -147,8 +147,8 @@ typedef struct catclist
uint32 hash_value; /* hash value for lookup keys */
HeapTupleData tuple; /* header for tuple holding keys */
int n_members; /* number of member tuples */
- CatCTup *members[1]; /* members --- VARIABLE LENGTH ARRAY */
-} CatCList; /* VARIABLE LENGTH STRUCT */
+ CatCTup *members[FLEXIBLE_ARRAY_MEMBER]; /* members */
+} CatCList;
typedef struct catcacheheader
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 8912ba5..d36f297 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -219,7 +219,7 @@ typedef struct TimeZoneAbbrevTable
{
Size tblsize; /* size in bytes of TimeZoneAbbrevTable */
int numabbrevs; /* number of entries in abbrevs[] array */
- datetkn abbrevs[1]; /* VARIABLE LENGTH ARRAY */
+ datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER];
/* DynamicZoneAbbrev(s) may follow the abbrevs[] array */
} TimeZoneAbbrevTable;
@@ -227,7 +227,8 @@ typedef struct TimeZoneAbbrevTable
typedef struct DynamicZoneAbbrev
{
pg_tz *tz; /* NULL if not yet looked up */
- char zone[1]; /* zone name (var length, NUL-terminated) */
+ char zone[FLEXIBLE_ARRAY_MEMBER]; /* zone name (var length,
+ * NUL-terminated) */
} DynamicZoneAbbrev;
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0b6d3c3..a0f779b 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -80,7 +80,8 @@ typedef struct
int32 npts;
int32 closed; /* is this a closed polygon? */
int32 dummy; /* padding to make it double align */
- Point p[1]; /* variable length array of POINTs */
+ Point p[FLEXIBLE_ARRAY_MEMBER]; /* variable length array
+ * of POINTs */
} PATH;
@@ -115,7 +116,7 @@ typedef struct
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 npts;
BOX boundbox;
- Point p[1]; /* variable length array of POINTs */
+ Point p[FLEXIBLE_ARRAY_MEMBER];
} POLYGON;
/*---------------------------------------------------------------------
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index 887eb9b..9d1770e 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -194,7 +194,7 @@ typedef struct JsonbContainer
{
uint32 header; /* number of elements or key/value pairs, and
* flags */
- JEntry children[1]; /* variable length */
+ JEntry children[FLEXIBLE_ARRAY_MEMBER];
/* the data for each child node follows. */
} JsonbContainer;
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 420310d..73b4905 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -29,7 +29,7 @@ typedef struct xl_relmap_update
Oid dbid; /* database ID, or 0 for shared map */
Oid tsid; /* database's tablespace, or pg_global */
int32 nbytes; /* size of relmap data */
- char data[1]; /* VARIABLE LENGTH ARRAY */
+ char data[FLEXIBLE_ARRAY_MEMBER];
} xl_relmap_update;
#define MinSizeOfRelmapUpdate offsetof(xl_relmap_update, data)
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index 8afc3b1..bd5bf52 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -26,7 +26,8 @@ typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int32 bit_len; /* number of valid bits */
- bits8 bit_dat[1]; /* bit string, most sig. byte first */
+ bits8 bit_dat[FLEXIBLE_ARRAY_MEMBER]; /* bit string, most sig.
+ * byte first */
} VarBit;
/*
--
2.3.0
0002-Add-forgotten-CATALOG_VARLEN-pg_authid.patchapplication/x-patch; name=0002-Add-forgotten-CATALOG_VARLEN-pg_authid.patchDownload
From a30ec54acc9bcc997a3a5f5d5c731cbc3b0b21e2 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 13:40:59 +0900
Subject: [PATCH 2/4] Add forgotten CATALOG_VARLEN pg_authid
The laste two fields of this catalog table, rolvaliduntil and rolpassword
can be null, but were not marked as such.
---
src/include/catalog/pg_authid.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
index e01e6aa..5b34288 100644
--- a/src/include/catalog/pg_authid.h
+++ b/src/include/catalog/pg_authid.h
@@ -55,9 +55,10 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC
bool rolbypassrls; /* allowed to bypass row level security? */
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
- /* remaining fields may be null; use heap_getattr to read them! */
+#ifdef CATALOG_VARLEN
text rolpassword; /* password, if any */
timestamptz rolvaliduntil; /* password expiration time, if any */
+#endif
} FormData_pg_authid;
#undef timestamptz
--
2.3.0
0003-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0003-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
From d59e066f252fbe9697bc9ef5b9ded0442e853797 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 14:02:14 +0900
Subject: [PATCH 3/4] 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 bbd0d53..36ec468 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
0004-Replace-some-struct-declarations-with-union-in-heapa.patchapplication/x-patch; name=0004-Replace-some-struct-declarations-with-union-in-heapa.patchDownload
From f41eea583f806cd8bbb4f604ee81b49c81f69cbe Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Thu, 19 Feb 2015 14:29:57 +0900
Subject: [PATCH 4/4] Replace some struct declarations with union in heapam.c
To ensure that there is enough room for operations, add a size equivalent
to the tuple header data.
---
src/backend/access/heap/heapam.c | 12 ++++++------
src/include/access/htup_details.h | 2 ++
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 46060bc1..c4b825d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7351,10 +7351,10 @@ 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];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
HeapTupleHeader htup;
xl_heap_header xlhdr;
@@ -7469,10 +7469,10 @@ heap_xlog_multi_insert(XLogReaderState *record)
BlockNumber blkno;
Buffer buffer;
Page page;
- struct
+ union
{
HeapTupleHeaderData hdr;
- char data[MaxHeapTupleSize];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
HeapTupleHeader htup;
uint32 newlen;
@@ -7618,10 +7618,10 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
uint16 prefixlen = 0,
suffixlen = 0;
char *newp;
- struct
+ union
{
HeapTupleHeaderData hdr;
- char data[MaxHeapTupleSize];
+ char data[SizeOfHeapTupleHeaderData + MaxHeapTupleSize];
} tbuf;
xl_heap_header xlhdr;
uint32 newlen;
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index d2ad910..2da4f42 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -155,6 +155,8 @@ struct HeapTupleHeaderData
/* MORE DATA FOLLOWS AT END OF STRUCT */
};
+#define SizeOfHeapTupleHeaderData MAXALIGN(sizeof(HeapTupleHeaderData))
+
/* typedef appears in tupbasics.h */
/*
--
2.3.0
On Thu, Feb 19, 2015 at 3:57 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Thu, Feb 19, 2015 at 2:58 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
1-2) sizeof(ParamListInfoData) is present in a couple of places, assuming that sizeof(ParamListInfoData) has the equivalent of 1 parameter, like prepare.c, functions.c, spi.c and postgres.c: - /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + - (num_params - 1) * sizeof(ParamExternData)); + num_params * sizeof(ParamExternData)); 1-3) FuncCandidateList in namespace.c (thanks Andres!): newResult = (FuncCandidateList) - palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid) - + effective_nargs * sizeof(Oid)); + palloc(sizeof(struct _FuncCandidateList) + + effective_nargs * sizeof(Oid)); I imagine that we do not want for those palloc calls to use ifdef FLEXIBLE_ARRAY_MEMBER to save some memory for code readability even if compiler does not support flexible-array length, right?These are just wrong. As a general rule, we do not want to *ever* take
sizeof() a struct that contains a flexible array: the results will not
be consistent across platforms. The right thing is to use offsetof()
instead. See the helpful comment autoconf provides:[...]
And I had this one in front of my eyes a couple of hours ago... Thanks.
This point is actually the main reason we've not done this change long
since. People did not feel like running around to make sure there were
no overlooked uses of sizeof().Thanks for the clarifications and the review. Attached is a new set.
Grr. Completely forgot to use offsetof in dumputils.c as well. Patch
that can be applied on top of 0001 is attached.
--
Michael
Attachments:
dumputils-fix.patchapplication/x-patch; name=dumputils-fix.patchDownload
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 892d3fa..3459adc 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -1217,7 +1217,7 @@ simple_string_list_append(SimpleStringList *list, const char *val)
SimpleStringListCell *cell;
/* this calculation correctly accounts for the null trailing byte */
- cell = (SimpleStringListCell *) pg_malloc(sizeof(SimpleStringListCell));
+ cell = (SimpleStringListCell *) pg_malloc(offsetof(SimpleStringListCell, val));
cell->next = NULL;
strcpy(cell->val, val);
On 2015-02-18 17:29:27 -0500, Tom Lane wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
On Wed, Feb 18, 2015 at 10:09 PM, Andres Freund <andres@2ndquadrant.com> wrote:
The compiler will complain if you use a FLEXIBLE_ARRAY_MEMBER in the
middle of a struct but not when when you embed a struct that uses it
into the middle another struct. At least gcc doesn't and I think it'd be
utterly broken if another compiler did that. If there's a compiler that
does so, we need to make it define FLEXIBLE_ARRAY_MEMBER to 1.clang does complain on my OSX laptop regarding that ;)
I'm a bit astonished that gcc doesn't consider this an error. Sure seems
like it should.
Why? The flexible arrary stuff tells the compiler that it doesn't have
to worry about space for the array - it seems alright that it actually
doesn't. There's pretty much no way you can do that sensibly if the
variable length array itself is somewhere in the middle of a struct -
but if you embed the whole struct somewhere you have to take care
yourself. And e.g. the varlena cases Michael has shown do just that?
(Has anyone tried it on recent gcc?)
Yes.
Moreover, if we have any code that is assuming such cases are okay, it
probably needs a second look. Isn't this situation effectively assuming
that a variable-length array is fixed-length?
Not really. If you have
struct varlena hdr;
char data[TOAST_MAX_CHUNK_SIZE]; /* make struct big enough */
the variable length part is preallocated in the data?
You're right that many of these structs could just be replaced with a
union though.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-02-18 21:00:43 -0500, Tom Lane wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
3) heapam.c in three places with HeapTupleHeaderData:
struct
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
} tbuf;And this, though I'm not sure if we'd have to change the size of the
padding data[] member.
I don't think so.
/*
* MaxHeapTupleSize is the maximum allowed size of a heap tuple, including
* header and MAXALIGN alignment padding. Basically it's BLCKSZ minus the
* other stuff that has to be on a disk page. Since heap pages use no
* "special space", there's no deduction for that.
...
#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData)))
5) reorderbuffer.h with its use of HeapTupleHeaderData:
Hmm. Andres will have to answer for that one ;-)
That should be fairly uncomplicated to replace.
...
/* tuple, stored sequentially */
HeapTupleData tuple;
HeapTupleHeaderData header;
char data[MaxHeapTupleSize];
probably can just be replaced by a union of data and header part - as
quoted above MaxHeapTupleSize actually contains space for the
header. It's a bit annoying because potentially some output plugin might
reference .header - but they can just be changed to reference
tuple.t_data instead.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Michael Paquier <michael.paquier@gmail.com> 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 :-().
Let's see how unhappy the buildfarm is with this before we start on
the rest of them.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
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...
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Feb 20, 2015 at 2:21 PM, Michael Paquier
<michael.paquier@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
Attachments:
0001-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0001-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
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
0002-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchapplication/x-patch; name=0002-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchDownload
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
0003-Switch-RecordIOData-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0003-Switch-RecordIOData-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
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
On Fri, Feb 20, 2015 at 4:59 PM, Michael Paquier wrote:
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 functionsEven with this set applied, the following things remain in backend code:
$ git grep "VARIABLE LENGTH" | grep "[1]"
[stuff]
Attached is a new series. 0001 and 0002 are the same, 0003 and 0004
the backend structures listed previously. I noticed as well that
indexed_tlist in setrefs.c meritates some attention.
Regards,
--
Michael
Attachments:
0001-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0001-Switch-varlena-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
From 072c0b80f00a5ca460391279a955f5e95f22d439 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/4] 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
0002-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchapplication/x-patch; name=0002-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchDownload
From 58aa911e66a5509fd9e4d6ff3b36c76745b3db7f 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/4] 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
0003-Switch-RecordIOData-to-use-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0003-Switch-RecordIOData-to-use-FLEXIBLE_ARRAY_MEMBER.patchDownload
From 03ace39d9d9effb97e8b7fcdcfac456892a6333e 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/4] 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 +++++++++---------
2 files changed, 18 insertions(+), 18 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;
--
2.3.0
0004-Switch-remaining-structures-to-FLEXIBLE_ARRAY_MEMBER.patchapplication/x-patch; name=0004-Switch-remaining-structures-to-FLEXIBLE_ARRAY_MEMBER.patchDownload
From 0cda8f44d1e0f9b03c23bba8f206e6eb15e3e662 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Fri, 20 Feb 2015 19:35:53 +0900
Subject: [PATCH 4/4] Switch remaining structures to FLEXIBLE_ARRAY_MEMBER in
backend code
---
src/backend/access/nbtree/nbtutils.c | 4 ++--
src/backend/access/transam/multixact.c | 4 ++--
src/backend/access/transam/twophase.c | 9 +++------
src/backend/commands/tablespace.c | 2 +-
src/backend/commands/trigger.c | 10 +++++-----
src/backend/executor/nodeAgg.c | 14 +++++++-------
src/backend/postmaster/checkpointer.c | 2 +-
src/backend/storage/ipc/pmsignal.c | 2 +-
src/backend/storage/ipc/procarray.c | 5 ++---
src/backend/utils/cache/inval.c | 12 ++++++------
src/backend/utils/cache/typcache.c | 2 +-
11 files changed, 31 insertions(+), 35 deletions(-)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 43e048c..379dac9 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -1836,7 +1836,7 @@ typedef struct BTVacInfo
BTCycleId cycle_ctr; /* cycle ID most recently assigned */
int num_vacuums; /* number of currently active VACUUMs */
int max_vacuums; /* allocated length of vacuums[] array */
- BTOneVacInfo vacuums[1]; /* VARIABLE LENGTH ARRAY */
+ BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER];
} BTVacInfo;
static BTVacInfo *btvacinfo;
@@ -1984,7 +1984,7 @@ BTreeShmemSize(void)
{
Size size;
- size = offsetof(BTVacInfo, vacuums[0]);
+ size = offsetof(BTVacInfo, vacuums);
size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
return size;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index b2cf770..e3db6f8 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -258,7 +258,7 @@ typedef struct MultiXactStateData
* stored in pg_control and used as truncation point for pg_multixact. At
* checkpoint or restartpoint, unneeded segments are removed.
*/
- MultiXactId perBackendXactIds[1]; /* VARIABLE LENGTH ARRAY */
+ MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER];
} MultiXactStateData;
/*
@@ -1745,7 +1745,7 @@ MultiXactShmemSize(void)
Size size;
#define SHARED_MULTIXACT_STATE_SIZE \
- add_size(sizeof(MultiXactStateData), \
+ add_size(offsetof(MultiXactStateData, perBackendXactIds), \
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6c7029e..6edc227 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -134,12 +134,9 @@ typedef struct TwoPhaseStateData
/* Number of valid prepXacts entries. */
int numPrepXacts;
- /*
- * There are max_prepared_xacts items in this array, but C wants a
- * fixed-size array.
- */
- GlobalTransaction prepXacts[1]; /* VARIABLE LENGTH ARRAY */
-} TwoPhaseStateData; /* VARIABLE LENGTH STRUCT */
+ /* There are max_prepared_xacts items in this array */
+ GlobalTransaction prepXacts[FLEXIBLE_ARRAY_MEMBER];
+} TwoPhaseStateData;
static TwoPhaseStateData *TwoPhaseState;
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index e098b9f..03cc8fe 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -1088,7 +1088,7 @@ GetDefaultTablespace(char relpersistence)
typedef struct
{
int numSpcs;
- Oid tblSpcs[1]; /* VARIABLE LENGTH ARRAY */
+ Oid tblSpcs[FLEXIBLE_ARRAY_MEMBER];
} temp_tablespaces_extra;
/* check_hook: validate new temp_tablespaces */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 5c1c1be..4223398 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3005,7 +3005,7 @@ typedef struct SetConstraintStateData
bool all_isdeferred;
int numstates; /* number of trigstates[] entries in use */
int numalloc; /* allocated size of trigstates[] */
- SetConstraintTriggerData trigstates[1]; /* VARIABLE LENGTH ARRAY */
+ SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER];
} SetConstraintStateData;
typedef SetConstraintStateData *SetConstraintState;
@@ -4398,8 +4398,8 @@ SetConstraintStateCreate(int numalloc)
*/
state = (SetConstraintState)
MemoryContextAllocZero(TopTransactionContext,
- sizeof(SetConstraintStateData) +
- (numalloc - 1) *sizeof(SetConstraintTriggerData));
+ offsetof(SetConstraintStateData, trigstates) +
+ numalloc *sizeof(SetConstraintTriggerData));
state->numalloc = numalloc;
@@ -4440,8 +4440,8 @@ SetConstraintStateAddItem(SetConstraintState state,
newalloc = Max(newalloc, 8); /* in case original has size 0 */
state = (SetConstraintState)
repalloc(state,
- sizeof(SetConstraintStateData) +
- (newalloc - 1) *sizeof(SetConstraintTriggerData));
+ offsetof(SetConstraintStateData, trigstates) +
+ newalloc * sizeof(SetConstraintTriggerData));
state->numalloc = newalloc;
Assert(state->numstates < state->numalloc);
}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 8079d97..9ff0eff 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -297,9 +297,9 @@ typedef struct AggHashEntryData *AggHashEntry;
typedef struct AggHashEntryData
{
TupleHashEntryData shared; /* common header for hash table entries */
- /* per-aggregate transition status array - must be last! */
- AggStatePerGroupData pergroup[1]; /* VARIABLE LENGTH ARRAY */
-} AggHashEntryData; /* VARIABLE LENGTH STRUCT */
+ /* per-aggregate transition status array */
+ AggStatePerGroupData pergroup[FLEXIBLE_ARRAY_MEMBER];
+} AggHashEntryData;
static void initialize_aggregates(AggState *aggstate,
@@ -941,8 +941,8 @@ build_hash_table(AggState *aggstate)
Assert(node->aggstrategy == AGG_HASHED);
Assert(node->numGroups > 0);
- entrysize = sizeof(AggHashEntryData) +
- (aggstate->numaggs - 1) * sizeof(AggStatePerGroupData);
+ entrysize = offsetof(AggHashEntryData, pergroup) +
+ aggstate->numaggs * sizeof(AggStatePerGroupData);
aggstate->hashtable = BuildTupleHashTable(node->numCols,
node->grpColIdx,
@@ -1013,8 +1013,8 @@ hash_agg_entry_size(int numAggs)
Size entrysize;
/* This must match build_hash_table */
- entrysize = sizeof(AggHashEntryData) +
- (numAggs - 1) * sizeof(AggStatePerGroupData);
+ entrysize = offsetof(AggHashEntryData, pergroup) +
+ numAggs * sizeof(AggStatePerGroupData);
entrysize = MAXALIGN(entrysize);
/* Account for hashtable overhead (assuming fill factor = 1) */
entrysize += 3 * sizeof(void *);
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 237be12..cfad08d 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -130,7 +130,7 @@ typedef struct
int num_requests; /* current # of requests */
int max_requests; /* allocated array size */
- CheckpointerRequest requests[1]; /* VARIABLE LENGTH ARRAY */
+ CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER];
} CheckpointerShmemStruct;
static CheckpointerShmemStruct *CheckpointerShmem;
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index 0c89eb7..ea3fe20 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -66,7 +66,7 @@ struct PMSignalData
/* per-child-process flags */
int num_child_flags; /* # of entries in PMChildFlags[] */
int next_child_flag; /* next slot to try to assign */
- sig_atomic_t PMChildFlags[1]; /* VARIABLE LENGTH ARRAY */
+ sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER];
};
NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index a1ebc72..39846d6 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -91,10 +91,9 @@ typedef struct ProcArrayStruct
TransactionId replication_slot_catalog_xmin;
/*
- * We declare pgprocnos[] as 1 entry because C wants a fixed-size array,
- * but actually it is maxProcs entries long.
+ * Number of procs with maxProcs entries.
*/
- int pgprocnos[1]; /* VARIABLE LENGTH ARRAY */
+ int pgprocnos[FLEXIBLE_ARRAY_MEMBER];
} ProcArrayStruct;
static ProcArrayStruct *procArray;
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 0f2192c..8826a5d 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -122,8 +122,8 @@ typedef struct InvalidationChunk
struct InvalidationChunk *next; /* list link */
int nitems; /* # items currently stored in chunk */
int maxitems; /* size of allocated array in this chunk */
- SharedInvalidationMessage msgs[1]; /* VARIABLE LENGTH ARRAY */
-} InvalidationChunk; /* VARIABLE LENGTH STRUCTURE */
+ SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER];
+} InvalidationChunk;
typedef struct InvalidationListHeader
{
@@ -225,8 +225,8 @@ AddInvalidationMessage(InvalidationChunk **listHdr,
#define FIRSTCHUNKSIZE 32
chunk = (InvalidationChunk *)
MemoryContextAlloc(CurTransactionContext,
- sizeof(InvalidationChunk) +
- (FIRSTCHUNKSIZE - 1) *sizeof(SharedInvalidationMessage));
+ offsetof(InvalidationChunk, msgs) +
+ FIRSTCHUNKSIZE * sizeof(SharedInvalidationMessage));
chunk->nitems = 0;
chunk->maxitems = FIRSTCHUNKSIZE;
chunk->next = *listHdr;
@@ -239,8 +239,8 @@ AddInvalidationMessage(InvalidationChunk **listHdr,
chunk = (InvalidationChunk *)
MemoryContextAlloc(CurTransactionContext,
- sizeof(InvalidationChunk) +
- (chunksize - 1) *sizeof(SharedInvalidationMessage));
+ offsetof(InvalidationChunk, msgs) +
+ chunksize * sizeof(SharedInvalidationMessage));
chunk->nitems = 0;
chunk->maxitems = chunksize;
chunk->next = *listHdr;
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 82b6668..0492718 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -93,7 +93,7 @@ typedef struct TypeCacheEnumData
Oid bitmap_base; /* OID corresponding to bit 0 of bitmapset */
Bitmapset *sorted_values; /* Set of OIDs known to be in order */
int num_values; /* total number of values in enum */
- EnumItem enum_values[1]; /* VARIABLE LENGTH ARRAY */
+ EnumItem enum_values[FLEXIBLE_ARRAY_MEMBER];
} TypeCacheEnumData;
/*
--
2.3.0
On Fri, Feb 20, 2015 at 8:57 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
Attached is a new series. 0001 and 0002 are the same, 0003 and 0004
the backend structures listed previously. I noticed as well that
indexed_tlist in setrefs.c meritates some attention.
And after all those commits attached is a patch changing
HeapTupleHeaderData, using the following macro to track the size of
the structure:
#define SizeofHeapTupleHeader offsetof(HeapTupleHeaderData, t_bits)
Regards,
--
Michael
Attachments:
0001-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchtext/x-diff; charset=US-ASCII; name=0001-Switch-HeapTupleHeaderData-and-MinimalTupleData-to-u.patchDownload
From 3951d103d5bff49f300c89e34d2fa7bd893b9fd4 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Fri, 20 Feb 2015 16:42:28 +0900
Subject: [PATCH] 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 | 2 +-
src/backend/access/common/heaptuple.c | 2 +-
src/backend/access/heap/heapam.c | 56 ++++++++++++-------------
src/backend/access/heap/tuptoaster.c | 10 ++---
src/backend/catalog/toasting.c | 2 +-
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 | 30 ++++++-------
src/backend/replication/logical/reorderbuffer.c | 26 +++++-------
src/backend/utils/adt/trigfuncs.c | 6 +--
src/include/access/htup_details.h | 10 +++--
src/include/access/tuptoaster.h | 2 +-
src/include/replication/reorderbuffer.h | 7 +++-
18 files changed, 95 insertions(+), 89 deletions(-)
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index d569760..4368897 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(SizeofHeapTupleHeader);
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..8bb1c80 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -519,7 +519,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
{
baserel->pages = 10;
baserel->tuples =
- (10 * BLCKSZ) / (baserel->width + sizeof(HeapTupleHeaderData));
+ (10 * BLCKSZ) / (baserel->width + SizeofHeapTupleHeader);
}
/* Estimate baserel size as best we can with local statistics. */
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 867035d..66db9c6 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -694,7 +694,7 @@ heap_form_tuple(TupleDesc tupleDescriptor,
/*
* Determine total space needed
*/
- len = offsetof(HeapTupleHeaderData, t_bits);
+ len = SizeofHeapTupleHeader;
if (hasnull)
len += BITMAPLEN(numberOfAttributes);
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 46060bc1..00f3b94 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2186,8 +2186,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
XLogRegisterBufData(0,
- (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits),
- heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits));
+ (char *) heaptup->t_data + SizeofHeapTupleHeader,
+ heaptup->t_len - SizeofHeapTupleHeader);
recptr = XLogInsert(RM_HEAP_ID, info);
@@ -2460,9 +2460,9 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
tuphdr->t_hoff = heaptup->t_data->t_hoff;
/* write bitmap [+ padding] [+ oid] + data */
- datalen = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);
+ datalen = heaptup->t_len - SizeofHeapTupleHeader;
memcpy(scratchptr,
- (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits),
+ (char *) heaptup->t_data + SizeofHeapTupleHeader,
datalen);
tuphdr->datalen = datalen;
scratchptr += datalen;
@@ -2904,9 +2904,9 @@ l1:
XLogRegisterData((char *) &xlhdr, SizeOfHeapHeader);
XLogRegisterData((char *) old_key_tuple->t_data
- + offsetof(HeapTupleHeaderData, t_bits),
+ + SizeofHeapTupleHeader,
old_key_tuple->t_len
- - offsetof(HeapTupleHeaderData, t_bits));
+ - SizeofHeapTupleHeader);
}
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
@@ -6732,7 +6732,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
xlhdr.t_infomask = newtup->t_data->t_infomask;
xlhdr.t_hoff = newtup->t_data->t_hoff;
- Assert(offsetof(HeapTupleHeaderData, t_bits) + prefixlen + suffixlen <= newtup->t_len);
+ Assert(SizeofHeapTupleHeader + prefixlen + suffixlen <= newtup->t_len);
/*
* PG73FORMAT: write bitmap [+ padding] [+ oid] + data
@@ -6743,8 +6743,8 @@ log_heap_update(Relation reln, Buffer oldbuf,
if (prefixlen == 0)
{
XLogRegisterBufData(0,
- ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits),
- newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) -suffixlen);
+ ((char *) newtup->t_data) + SizeofHeapTupleHeader,
+ newtup->t_len - SizeofHeapTupleHeader -suffixlen);
}
else
{
@@ -6753,11 +6753,11 @@ log_heap_update(Relation reln, Buffer oldbuf,
* two separate rdata entries.
*/
/* bitmap [+ padding] [+ oid] */
- if (newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits) >0)
+ if (newtup->t_data->t_hoff - SizeofHeapTupleHeader >0)
{
XLogRegisterBufData(0,
- ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits),
- newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits));
+ ((char *) newtup->t_data) + SizeofHeapTupleHeader,
+ newtup->t_data->t_hoff - SizeofHeapTupleHeader);
}
/* data after common prefix */
@@ -6777,8 +6777,8 @@ log_heap_update(Relation reln, Buffer oldbuf,
XLogRegisterData((char *) &xlhdr_idx, SizeOfHeapHeader);
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
- XLogRegisterData((char *) old_key_tuple->t_data + offsetof(HeapTupleHeaderData, t_bits),
- old_key_tuple->t_len - offsetof(HeapTupleHeaderData, t_bits));
+ XLogRegisterData((char *) old_key_tuple->t_data + SizeofHeapTupleHeader,
+ old_key_tuple->t_len - SizeofHeapTupleHeader);
}
recptr = XLogInsert(RM_HEAP_ID, info);
@@ -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,12 +7415,12 @@ heap_xlog_insert(XLogReaderState *record)
data += SizeOfHeapHeader;
htup = &tbuf.hdr;
- MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
+ MemSet((char *) htup, 0, SizeofHeapTupleHeader);
/* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
- memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
+ memcpy((char *) htup + SizeofHeapTupleHeader,
data,
newlen);
- newlen += offsetof(HeapTupleHeaderData, t_bits);
+ newlen += SizeofHeapTupleHeader;
htup->t_infomask2 = xlhdr.t_infomask2;
htup->t_infomask = xlhdr.t_infomask;
htup->t_hoff = xlhdr.t_hoff;
@@ -7469,7 +7469,7 @@ heap_xlog_multi_insert(XLogReaderState *record)
BlockNumber blkno;
Buffer buffer;
Page page;
- struct
+ union
{
HeapTupleHeaderData hdr;
char data[MaxHeapTupleSize];
@@ -7548,14 +7548,14 @@ 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, SizeofHeapTupleHeader);
/* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
- memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
+ memcpy((char *) htup + SizeofHeapTupleHeader,
(char *) tupdata,
newlen);
tupdata += newlen;
- newlen += offsetof(HeapTupleHeaderData, t_bits);
+ newlen += SizeofHeapTupleHeader;
htup->t_infomask2 = xlhdr->t_infomask2;
htup->t_infomask = xlhdr->t_infomask;
htup->t_hoff = xlhdr->t_hoff;
@@ -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,19 +7780,19 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
Assert(tuplen <= MaxHeapTupleSize);
htup = &tbuf.hdr;
- MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
+ MemSet((char *) htup, 0, SizeofHeapTupleHeader);
/*
* Reconstruct the new tuple using the prefix and/or suffix from the
* old tuple, and the data stored in the WAL record.
*/
- newp = (char *) htup + offsetof(HeapTupleHeaderData, t_bits);
+ newp = (char *) htup + SizeofHeapTupleHeader;
if (prefixlen > 0)
{
int len;
/* copy bitmap [+ padding] [+ oid] from WAL record */
- len = xlhdr.t_hoff - offsetof(HeapTupleHeaderData, t_bits);
+ len = xlhdr.t_hoff - SizeofHeapTupleHeader;
memcpy(newp, recdata, len);
recdata += len;
newp += len;
@@ -7802,7 +7802,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
newp += prefixlen;
/* copy new tuple data from WAL record */
- len = tuplen - (xlhdr.t_hoff - offsetof(HeapTupleHeaderData, t_bits));
+ len = tuplen - (xlhdr.t_hoff - SizeofHeapTupleHeader);
memcpy(newp, recdata, len);
recdata += len;
newp += len;
@@ -7823,7 +7823,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
if (suffixlen > 0)
memcpy(newp, (char *) oldtup.t_data + oldtup.t_len - suffixlen, suffixlen);
- newlen = offsetof(HeapTupleHeaderData, t_bits) + tuplen + prefixlen + suffixlen;
+ newlen = SizeofHeapTupleHeader + tuplen + prefixlen + suffixlen;
htup->t_infomask2 = xlhdr.t_infomask2;
htup->t_infomask = xlhdr.t_infomask;
htup->t_hoff = xlhdr.t_hoff;
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index deb3372..8464e87 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -677,7 +677,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
*/
/* compute header overhead --- this should match heap_form_tuple() */
- hoff = offsetof(HeapTupleHeaderData, t_bits);
+ hoff = SizeofHeapTupleHeader;
if (has_nulls)
hoff += BITMAPLEN(numAttrs);
if (newtup->t_data->t_infomask & HEAP_HASOID)
@@ -963,7 +963,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
* different conclusion about the size of the null bitmap, or even
* whether there needs to be one at all.
*/
- new_header_len = offsetof(HeapTupleHeaderData, t_bits);
+ new_header_len = SizeofHeapTupleHeader;
if (has_nulls)
new_header_len += BITMAPLEN(numAttrs);
if (olddata->t_infomask & HEAP_HASOID)
@@ -986,7 +986,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
/*
* Copy the existing tuple header, but adjust natts and t_hoff.
*/
- memcpy(new_data, olddata, offsetof(HeapTupleHeaderData, t_bits));
+ memcpy(new_data, olddata, SizeofHeapTupleHeader);
HeapTupleHeaderSetNatts(new_data, numAttrs);
new_data->t_hoff = new_header_len;
if (olddata->t_infomask & HEAP_HASOID)
@@ -1196,7 +1196,7 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup,
*
* This should match the reconstruction code in toast_insert_or_update.
*/
- new_header_len = offsetof(HeapTupleHeaderData, t_bits);
+ new_header_len = SizeofHeapTupleHeader;
if (has_nulls)
new_header_len += BITMAPLEN(numAttrs);
if (tup->t_infomask & HEAP_HASOID)
@@ -1211,7 +1211,7 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup,
/*
* Copy the existing tuple header, but adjust natts and t_hoff.
*/
- memcpy(new_data, tup, offsetof(HeapTupleHeaderData, t_bits));
+ memcpy(new_data, tup, SizeofHeapTupleHeader);
HeapTupleHeaderSetNatts(new_data, numAttrs);
new_data->t_hoff = new_header_len;
if (tup->t_infomask & HEAP_HASOID)
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index e73252c..a1efddb 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -447,7 +447,7 @@ needs_toast_table(Relation rel)
return false; /* nothing to toast? */
if (maxlength_unknown)
return true; /* any unlimited-length attrs? */
- tuple_length = MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) +
+ tuple_length = MAXALIGN(SizeofHeapTupleHeader +
BITMAPLEN(tupdesc->natts)) +
MAXALIGN(data_length);
return (tuple_length > TOAST_TUPLE_THRESHOLD);
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..d24b4d8 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 SizeofHeapTupleHeader.
*/
if (have_wholerow_var)
{
- int32 wholerow_width = sizeof(HeapTupleHeaderData);
+ int32 wholerow_width = SizeofHeapTupleHeader;
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(SizeofHeapTupleHeader));
}
/*
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..11c4dd9 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 SizeofHeapTupleHeader 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(SizeofHeapTupleHeader));
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..034b8dc 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 += SizeofHeapTupleHeader;
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..31487ea 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);
+ + SizeofHeapTupleHeader;
- memset(&tuple->header, 0, sizeof(HeapTupleHeaderData));
+ memset(&tuple->t_data.header, 0, SizeofHeapTupleHeader);
- memcpy((char *) &tuple->header
- + offsetof(HeapTupleHeaderData, t_bits),
+ memcpy((char *) &tuple->t_data.header
+ + SizeofHeapTupleHeader,
(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;
}
/*
@@ -815,27 +815,27 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
Assert(datalen >= 0);
Assert(datalen <= MaxHeapTupleSize);
- tuple->tuple.t_len = datalen + offsetof(HeapTupleHeaderData, t_bits);
+ tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
/* not a disk based tuple */
ItemPointerSetInvalid(&tuple->tuple.t_self);
/* 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, SizeofHeapTupleHeader);
- memcpy((char *) &tuple->header + offsetof(HeapTupleHeaderData, t_bits),
+ memcpy((char *) &tuple->t_data.header + SizeofHeapTupleHeader,
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/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c
index fb79092..a8a75ef 100644
--- a/src/backend/utils/adt/trigfuncs.c
+++ b/src/backend/utils/adt/trigfuncs.c
@@ -84,9 +84,9 @@ suppress_redundant_updates_trigger(PG_FUNCTION_ARGS)
HeapTupleHeaderGetNatts(oldheader)) &&
((newheader->t_infomask & ~HEAP_XACT_MASK) ==
(oldheader->t_infomask & ~HEAP_XACT_MASK)) &&
- memcmp(((char *) newheader) + offsetof(HeapTupleHeaderData, t_bits),
- ((char *) oldheader) + offsetof(HeapTupleHeaderData, t_bits),
- newtuple->t_len - offsetof(HeapTupleHeaderData, t_bits)) == 0)
+ memcmp(((char *) newheader) + SizeofHeapTupleHeader,
+ ((char *) oldheader) + SizeofHeapTupleHeader,
+ newtuple->t_len - SizeofHeapTupleHeader) == 0)
{
/* ... then suppress the update */
rettuple = NULL;
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index d2ad910..d3c088d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -150,11 +150,13 @@ 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 */
};
+#define SizeofHeapTupleHeader offsetof(HeapTupleHeaderData, t_bits)
+
/* typedef appears in tupbasics.h */
/*
@@ -498,7 +500,7 @@ do { \
* you can, say, fit 2 tuples of size MaxHeapTupleSize/2 on the same page.
*/
#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData)))
-#define MinHeapTupleSize MAXALIGN(offsetof(HeapTupleHeaderData, t_bits))
+#define MinHeapTupleSize MAXALIGN(SizeofHeapTupleHeader)
/*
* MaxHeapTuplesPerPage is an upper bound on the number of tuples that can
@@ -513,7 +515,7 @@ do { \
*/
#define MaxHeapTuplesPerPage \
((int) ((BLCKSZ - SizeOfPageHeaderData) / \
- (MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) + sizeof(ItemIdData))))
+ (MAXALIGN(SizeofHeapTupleHeader) + sizeof(ItemIdData))))
/*
* MaxAttrSize is a somewhat arbitrary upper limit on the declared size of
@@ -579,7 +581,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/access/tuptoaster.h b/src/include/access/tuptoaster.h
index 331dd25..7d18535 100644
--- a/src/include/access/tuptoaster.h
+++ b/src/include/access/tuptoaster.h
@@ -90,7 +90,7 @@
#define TOAST_MAX_CHUNK_SIZE \
(EXTERN_TUPLE_MAX_SIZE - \
- MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) - \
+ MAXALIGN(SizeofHeapTupleHeader) - \
sizeof(Oid) - \
sizeof(int32) - \
VARHDRSZ)
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
Michael Paquier <michael.paquier@gmail.com> writes:
And after all those commits attached is a patch changing
HeapTupleHeaderData, using the following macro to track the size of
the structure:
#define SizeofHeapTupleHeader offsetof(HeapTupleHeaderData, t_bits)
I've pushed this with a few minor fixes (mostly, using MAXALIGN where
appropriate to avoid changing the results of planner calculations).
Andres, would you double-check the changes in reorderbuffer.c?
There were some weird calculations with
offsetof(ReorderBufferTupleBuf, data) - offsetof(HeapTupleHeaderData, t_bits)
which Michael simplified in a way that's not 100% equivalent. I think
it's probably better this way; it looks like the old coding was maybe
wrong, or at least in the habit of misaligning data. But I might be
misunderstanding.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-02-21 15:16:55 -0500, Tom Lane wrote:
Andres, would you double-check the changes in reorderbuffer.c?
There were some weird calculations with
offsetof(ReorderBufferTupleBuf, data) - offsetof(HeapTupleHeaderData, t_bits)
which Michael simplified in a way that's not 100% equivalent. I think
it's probably better this way; it looks like the old coding was maybe
wrong, or at least in the habit of misaligning data. But I might be
misunderstanding.
Hm, yea, that looks/looked slightly wierd. I think it's actually correct
though: HeapTupleData's t_len include's HeapTupleHeaderData itself and
offsetof(ReorderBufferTupleBuf, data) points to *after*
HeapTupleHeaderData. As this is only the length computation, not the
copy, I don't see an active issue. Why I wrote it that way, instead of
using offsetof(ReorderBufferTupleBuf, header) + t_len - which should be
equivalent - I don't know.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
After some more hacking, the only remaining uses of foo[1] in struct
declarations are:
1. A couple of places where the array is actually the only struct member;
for some unexplainable reason gcc won't let you use flexible array syntax
in that case.
2. struct sqlda_struct in ecpg's sqlda-native.h. We have a problem with
using [FLEXIBLE_ARRAY_MEMBER] there because (1) pg_config.h isn't (and I
think shouldn't be) #included by this file, and (2) there is very possibly
application code depending on sizeof() this struct; the risk of breaking
such code seems to outweigh any likely benefit. Also, despite that
I tried changing [1] to [] and fixing the places I could find that
depended on sizeof(struct sqlda_struct), but I apparently can't find them
all because the ecpg regression tests fell over :-(.
Anyway, barring excitement in the buildfarm I think this project is
complete.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Feb 22, 2015 at 6:57 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
After some more hacking, the only remaining uses of foo[1] in struct
declarations are:1. A couple of places where the array is actually the only struct member;
for some unexplainable reason gcc won't let you use flexible array syntax
in that case.
Yes. Thanks for adding notes at those places.
2. struct sqlda_struct in ecpg's sqlda-native.h. We have a problem with
using [FLEXIBLE_ARRAY_MEMBER] there because (1) pg_config.h isn't (and I
think shouldn't be) #included by this file, and (2) there is very possibly
application code depending on sizeof() this struct; the risk of breaking
such code seems to outweigh any likely benefit. Also, despite that
I tried changing [1] to [] and fixing the places I could find that
depended on sizeof(struct sqlda_struct), but I apparently can't find them
all because the ecpg regression tests fell over :-(.
Yeah, I think we can live with that. The rest of the backend code is
clean now, and the allocation calculations are more understandable.
Anyway, barring excitement in the buildfarm I think this project is
complete.
Thanks!
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers