Convert macros to static inline functions
Inspired by [0]/messages/by-id/202203241021.uts52sczx3al@alvherre.pgsql, I looked to convert more macros to inline functions.
The attached patches are organized "bottom up" in terms of their API
layering; some of the later ones depend on some of the earlier ones.
Note 1: Some macros that do by-value assignments like
#define PageXLogRecPtrSet(ptr, lsn) \
((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn))
can't be converted to functions without changing the API, so I left
those alone for now.
Note 2: Many macros in htup_details.h operate both on HeapTupleHeader
and on MinimalTuple, so converting them to a function doesn't work in a
straightforward way. I have some in-progress work in that area, but I
have not included any of that here.
[0]: /messages/by-id/202203241021.uts52sczx3al@alvherre.pgsql
/messages/by-id/202203241021.uts52sczx3al@alvherre.pgsql
Attachments:
0001-Convert-macros-to-static-inline-functions-block.h.patchtext/plain; charset=UTF-8; name=0001-Convert-macros-to-static-inline-functions-block.h.patchDownload
From 3c1abb1cb26bd58b09a5416ae7df192a9c247653 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (block.h)
Remove BlockIdIsValid(), which wasn't used and is unnecessary.
Remove BlockIdCopy(), which wasn't used and can be done by struct
assignment.
(BlockIdEquals() also isn't used, but seems reasonable to keep
around.)
---
src/include/storage/block.h | 53 ++++++++++++++++---------------------
1 file changed, 23 insertions(+), 30 deletions(-)
diff --git a/src/include/storage/block.h b/src/include/storage/block.h
index d756e3fda5..c726142f96 100644
--- a/src/include/storage/block.h
+++ b/src/include/storage/block.h
@@ -59,7 +59,7 @@ typedef struct BlockIdData
typedef BlockIdData *BlockId; /* block identifier */
/* ----------------
- * support macros
+ * support functions
* ----------------
*/
@@ -67,49 +67,42 @@ typedef BlockIdData *BlockId; /* block identifier */
* BlockNumberIsValid
* True iff blockNumber is valid.
*/
-#define BlockNumberIsValid(blockNumber) \
- ((BlockNumber) (blockNumber) != InvalidBlockNumber)
-
-/*
- * BlockIdIsValid
- * True iff the block identifier is valid.
- */
-#define BlockIdIsValid(blockId) \
- PointerIsValid(blockId)
+static inline bool
+BlockNumberIsValid(BlockNumber blockNumber)
+{
+ return blockNumber != InvalidBlockNumber;
+}
/*
* BlockIdSet
* Sets a block identifier to the specified value.
*/
-#define BlockIdSet(blockId, blockNumber) \
-( \
- (blockId)->bi_hi = (blockNumber) >> 16, \
- (blockId)->bi_lo = (blockNumber) & 0xffff \
-)
-
-/*
- * BlockIdCopy
- * Copy a block identifier.
- */
-#define BlockIdCopy(toBlockId, fromBlockId) \
-( \
- (toBlockId)->bi_hi = (fromBlockId)->bi_hi, \
- (toBlockId)->bi_lo = (fromBlockId)->bi_lo \
-)
+static inline void
+BlockIdSet(BlockIdData *blockId, BlockNumber blockNumber)
+{
+ blockId->bi_hi = blockNumber >> 16;
+ blockId->bi_lo = blockNumber & 0xffff;
+}
/*
* BlockIdEquals
* Check for block number equality.
*/
-#define BlockIdEquals(blockId1, blockId2) \
- ((blockId1)->bi_hi == (blockId2)->bi_hi && \
- (blockId1)->bi_lo == (blockId2)->bi_lo)
+static inline bool
+BlockIdEquals(const BlockIdData *blockId1, const BlockIdData *blockId2)
+{
+ return (blockId1->bi_hi == blockId2->bi_hi &&
+ blockId1->bi_lo == blockId2->bi_lo);
+}
/*
* BlockIdGetBlockNumber
* Retrieve the block number from a block identifier.
*/
-#define BlockIdGetBlockNumber(blockId) \
- ((((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo))
+static inline BlockNumber
+BlockIdGetBlockNumber(const BlockIdData *blockId)
+{
+ return (((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo);
+}
#endif /* BLOCK_H */
--
2.35.1
0002-Convert-macros-to-static-inline-functions-bufpage.h.patchtext/plain; charset=UTF-8; name=0002-Convert-macros-to-static-inline-functions-bufpage.h.patchDownload
From e4ff58468a812bbeba377b957956ea18a9e100d4 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (bufpage.h)
rawpage.c needs some adjustments because it was previously playing
loose with the Page vs. PageHeader types, which is no longer possible
with the functions instead of macros.
---
contrib/pageinspect/rawpage.c | 24 ++++---
src/include/storage/bufpage.h | 125 ++++++++++++++++++++--------------
2 files changed, 86 insertions(+), 63 deletions(-)
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 730a46b1d8..90942be71e 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -254,7 +254,8 @@ page_header(PG_FUNCTION_ARGS)
Datum values[9];
bool nulls[9];
- PageHeader page;
+ Page page;
+ PageHeader pageheader;
XLogRecPtr lsn;
if (!superuser())
@@ -262,7 +263,8 @@ page_header(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to use raw page functions")));
- page = (PageHeader) get_page_from_raw(raw_page);
+ page = get_page_from_raw(raw_page);
+ pageheader = (PageHeader) page;
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
@@ -282,8 +284,8 @@ page_header(PG_FUNCTION_ARGS)
}
else
values[0] = LSNGetDatum(lsn);
- values[1] = UInt16GetDatum(page->pd_checksum);
- values[2] = UInt16GetDatum(page->pd_flags);
+ values[1] = UInt16GetDatum(pageheader->pd_checksum);
+ values[2] = UInt16GetDatum(pageheader->pd_flags);
/* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
switch (TupleDescAttr(tupdesc, 3)->atttypid)
@@ -292,18 +294,18 @@ page_header(PG_FUNCTION_ARGS)
Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
- values[3] = UInt16GetDatum(page->pd_lower);
- values[4] = UInt16GetDatum(page->pd_upper);
- values[5] = UInt16GetDatum(page->pd_special);
+ values[3] = UInt16GetDatum(pageheader->pd_lower);
+ values[4] = UInt16GetDatum(pageheader->pd_upper);
+ values[5] = UInt16GetDatum(pageheader->pd_special);
values[6] = UInt16GetDatum(PageGetPageSize(page));
break;
case INT4OID:
Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
- values[3] = Int32GetDatum(page->pd_lower);
- values[4] = Int32GetDatum(page->pd_upper);
- values[5] = Int32GetDatum(page->pd_special);
+ values[3] = Int32GetDatum(pageheader->pd_lower);
+ values[4] = Int32GetDatum(pageheader->pd_upper);
+ values[5] = Int32GetDatum(pageheader->pd_special);
values[6] = Int32GetDatum(PageGetPageSize(page));
break;
default:
@@ -312,7 +314,7 @@ page_header(PG_FUNCTION_ARGS)
}
values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
- values[8] = TransactionIdGetDatum(page->pd_prune_xid);
+ values[8] = TransactionIdGetDatum(pageheader->pd_prune_xid);
/* Build and return the tuple. */
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index e9f253f2c8..6d5d6b2b0d 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -14,6 +14,7 @@
#ifndef BUFPAGE_H
#define BUFPAGE_H
+#include "access/transam.h"
#include "access/xlogdefs.h"
#include "storage/block.h"
#include "storage/item.h"
@@ -97,8 +98,12 @@ typedef struct
uint32 xrecoff; /* low bits */
} PageXLogRecPtr;
-#define PageXLogRecPtrGet(val) \
- ((uint64) (val).xlogid << 32 | (val).xrecoff)
+
+static inline XLogRecPtr
+PageXLogRecPtrGet(PageXLogRecPtr val)
+{
+ return (uint64) val.xlogid << 32 | val.xrecoff;
+}
#define PageXLogRecPtrSet(ptr, lsn) \
((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn))
@@ -200,7 +205,7 @@ typedef PageHeaderData *PageHeader;
#define PG_DATA_CHECKSUM_VERSION 1
/* ----------------------------------------------------------------
- * page support macros
+ * page support macros and functions
* ----------------------------------------------------------------
*/
@@ -247,7 +252,7 @@ typedef PageHeaderData *PageHeader;
((char *) (page) + MAXALIGN(SizeOfPageHeaderData))
/* ----------------
- * macros to access page size info
+ * macros and functions to access page size info
* ----------------
*/
@@ -265,15 +270,21 @@ typedef PageHeaderData *PageHeader;
* BufferGetPageSize, which can be called on an unformatted page).
* however, it can be called on a page that is not stored in a buffer.
*/
-#define PageGetPageSize(page) \
- ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00))
+static inline Size
+PageGetPageSize(Page page)
+{
+ return (Size) (((PageHeader) page)->pd_pagesize_version & (uint16) 0xFF00);
+}
/*
* PageGetPageLayoutVersion
* Returns the page layout version of a page.
*/
-#define PageGetPageLayoutVersion(page) \
- (((PageHeader) (page))->pd_pagesize_version & 0x00FF)
+static inline uint8
+PageGetPageLayoutVersion(Page page)
+{
+ return (((PageHeader) page)->pd_pagesize_version & 0x00FF);
+}
/*
* PageSetPageSizeAndVersion
@@ -282,52 +293,52 @@ typedef PageHeaderData *PageHeader;
* We could support setting these two values separately, but there's
* no real need for it at the moment.
*/
-#define PageSetPageSizeAndVersion(page, size, version) \
-( \
- AssertMacro(((size) & 0xFF00) == (size)), \
- AssertMacro(((version) & 0x00FF) == (version)), \
- ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \
-)
+static inline void
+PageSetPageSizeAndVersion(Page page, Size size, uint8 version)
+{
+ Assert((size & 0xFF00) == size);
+ Assert((version & 0x00FF) == version);
+
+ ((PageHeader) page)->pd_pagesize_version = size | version;
+}
/* ----------------
- * page special data macros
+ * page special data macros and functions
* ----------------
*/
/*
* PageGetSpecialSize
* Returns size of special space on a page.
*/
-#define PageGetSpecialSize(page) \
- ((uint16) (PageGetPageSize(page) - ((PageHeader)(page))->pd_special))
+static inline uint16
+PageGetSpecialSize(Page page)
+{
+ return ((uint16) (PageGetPageSize(page) - ((PageHeader) page)->pd_special));
+}
/*
* Using assertions, validate that the page special pointer is OK.
*
* This is intended to catch use of the pointer before page initialization.
- * It is implemented as a function due to the limitations of the MSVC
- * compiler, which choked on doing all these tests within another macro. We
- * return true so that AssertMacro() can be used while still getting the
- * specifics from the macro failure within this function.
*/
-static inline bool
+static inline void
PageValidateSpecialPointer(Page page)
{
Assert(PageIsValid(page));
Assert(((PageHeader) (page))->pd_special <= BLCKSZ);
Assert(((PageHeader) (page))->pd_special >= SizeOfPageHeaderData);
-
- return true;
}
/*
* PageGetSpecialPointer
* Returns pointer to special space on a page.
*/
-#define PageGetSpecialPointer(page) \
-( \
- AssertMacro(PageValidateSpecialPointer(page)), \
- (char *) ((char *) (page) + ((PageHeader) (page))->pd_special) \
-)
+static inline char *
+PageGetSpecialPointer(Page page)
+{
+ PageValidateSpecialPointer(page);
+ return (char *) page + ((PageHeader) page)->pd_special;
+}
/*
* PageGetItem
@@ -337,12 +348,14 @@ PageValidateSpecialPointer(Page page)
* This does not change the status of any of the resources passed.
* The semantics may change in the future.
*/
-#define PageGetItem(page, itemId) \
-( \
- AssertMacro(PageIsValid(page)), \
- AssertMacro(ItemIdHasStorage(itemId)), \
- (Item)(((char *)(page)) + ItemIdGetOffset(itemId)) \
-)
+static inline Item
+PageGetItem(Page page, ItemId itemId)
+{
+ Assert(PageIsValid(page));
+ Assert(ItemIdHasStorage(itemId));
+
+ return (Item) (((char *) page) + ItemIdGetOffset(itemId));
+}
/*
* PageGetMaxOffsetNumber
@@ -351,17 +364,19 @@ PageValidateSpecialPointer(Page page)
* of items on the page.
*
* NOTE: if the page is not initialized (pd_lower == 0), we must
- * return zero to ensure sane behavior. Accept double evaluation
- * of the argument so that we can ensure this.
+ * return zero to ensure sane behavior.
*/
-#define PageGetMaxOffsetNumber(page) \
- (((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData ? 0 : \
- ((((PageHeader) (page))->pd_lower - SizeOfPageHeaderData) \
- / sizeof(ItemIdData)))
+static inline OffsetNumber
+PageGetMaxOffsetNumber(Page page)
+{
+ if (((PageHeader) page)->pd_lower <= SizeOfPageHeaderData)
+ return 0;
+ else
+ return ((((PageHeader) page)->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData));
+}
/*
- * Additional macros for access to page headers. (Beware multiple evaluation
- * of the arguments!)
+ * Additional macros and functions for access to page headers.
*/
#define PageGetLSN(page) \
PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
@@ -389,15 +404,21 @@ PageValidateSpecialPointer(Page page)
#define PageClearAllVisible(page) \
(((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE)
-#define PageSetPrunable(page, xid) \
-do { \
- Assert(TransactionIdIsNormal(xid)); \
- if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
- TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
- ((PageHeader) (page))->pd_prune_xid = (xid); \
-} while (0)
-#define PageClearPrunable(page) \
- (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
+static inline void
+PageSetPrunable(Page page, TransactionId xid)
+{
+ Assert(TransactionIdIsNormal(xid));
+
+ if (!TransactionIdIsValid(((PageHeader) page)->pd_prune_xid) ||
+ TransactionIdPrecedes(xid, ((PageHeader) page)->pd_prune_xid))
+ ((PageHeader) page)->pd_prune_xid = xid;
+}
+
+static inline void
+PageClearPrunable(Page page)
+{
+ ((PageHeader) page)->pd_prune_xid = InvalidTransactionId;
+}
/* ----------------------------------------------------------------
--
2.35.1
0003-Convert-macros-to-static-inline-functions-itemptr.h.patchtext/plain; charset=UTF-8; name=0003-Convert-macros-to-static-inline-functions-itemptr.h.patchDownload
From 3cb3bb9a8425910194834fec7e1316af96514e82 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (itemptr.h)
---
src/include/storage/itemptr.h | 129 +++++++++++++++++++---------------
1 file changed, 73 insertions(+), 56 deletions(-)
diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h
index 81947bc657..3ec88a68df 100644
--- a/src/include/storage/itemptr.h
+++ b/src/include/storage/itemptr.h
@@ -71,7 +71,7 @@ typedef ItemPointerData *ItemPointer;
/* ----------------
- * support macros
+ * support functions
* ----------------
*/
@@ -79,77 +79,87 @@ typedef ItemPointerData *ItemPointer;
* ItemPointerIsValid
* True iff the disk item pointer is not NULL.
*/
-#define ItemPointerIsValid(pointer) \
- ((bool) (PointerIsValid(pointer) && ((pointer)->ip_posid != 0)))
+static inline bool
+ItemPointerIsValid(const ItemPointerData *pointer)
+{
+ return PointerIsValid(pointer) && pointer->ip_posid != 0;
+}
/*
* ItemPointerGetBlockNumberNoCheck
* Returns the block number of a disk item pointer.
*/
-#define ItemPointerGetBlockNumberNoCheck(pointer) \
-( \
- BlockIdGetBlockNumber(&(pointer)->ip_blkid) \
-)
+static inline BlockNumber
+ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
+{
+ return BlockIdGetBlockNumber(&pointer->ip_blkid);
+}
/*
* ItemPointerGetBlockNumber
* As above, but verifies that the item pointer looks valid.
*/
-#define ItemPointerGetBlockNumber(pointer) \
-( \
- AssertMacro(ItemPointerIsValid(pointer)), \
- ItemPointerGetBlockNumberNoCheck(pointer) \
-)
+static inline BlockNumber
+ItemPointerGetBlockNumber(const ItemPointerData *pointer)
+{
+ Assert(ItemPointerIsValid(pointer));
+ return ItemPointerGetBlockNumberNoCheck(pointer);
+}
/*
* ItemPointerGetOffsetNumberNoCheck
* Returns the offset number of a disk item pointer.
*/
-#define ItemPointerGetOffsetNumberNoCheck(pointer) \
-( \
- (pointer)->ip_posid \
-)
+static inline OffsetNumber
+ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
+{
+ return pointer->ip_posid;
+}
/*
* ItemPointerGetOffsetNumber
* As above, but verifies that the item pointer looks valid.
*/
-#define ItemPointerGetOffsetNumber(pointer) \
-( \
- AssertMacro(ItemPointerIsValid(pointer)), \
- ItemPointerGetOffsetNumberNoCheck(pointer) \
-)
+static inline OffsetNumber
+ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
+{
+ Assert(ItemPointerIsValid(pointer));
+ return ItemPointerGetOffsetNumberNoCheck(pointer);
+}
/*
* ItemPointerSet
* Sets a disk item pointer to the specified block and offset.
*/
-#define ItemPointerSet(pointer, blockNumber, offNum) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), blockNumber), \
- (pointer)->ip_posid = offNum \
-)
+static inline void
+ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, blockNumber);
+ pointer->ip_posid = offNum;
+}
/*
* ItemPointerSetBlockNumber
* Sets a disk item pointer to the specified block.
*/
-#define ItemPointerSetBlockNumber(pointer, blockNumber) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), blockNumber) \
-)
+static inline void
+ItemPointerSetBlockNumber(ItemPointerData *pointer, BlockNumber blockNumber)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, blockNumber);
+}
/*
* ItemPointerSetOffsetNumber
* Sets a disk item pointer to the specified offset.
*/
-#define ItemPointerSetOffsetNumber(pointer, offsetNumber) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- (pointer)->ip_posid = (offsetNumber) \
-)
+static inline void
+ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
+{
+ Assert(PointerIsValid(pointer));
+ pointer->ip_posid = offsetNumber;
+}
/*
* ItemPointerCopy
@@ -158,42 +168,49 @@ typedef ItemPointerData *ItemPointer;
* Should there ever be padding in an ItemPointer this would need to be handled
* differently as it's used as hash key.
*/
-#define ItemPointerCopy(fromPointer, toPointer) \
-( \
- AssertMacro(PointerIsValid(toPointer)), \
- AssertMacro(PointerIsValid(fromPointer)), \
- *(toPointer) = *(fromPointer) \
-)
+static inline void
+ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
+{
+ Assert(PointerIsValid(toPointer));
+ Assert(PointerIsValid(fromPointer));
+ *toPointer = *fromPointer;
+}
/*
* ItemPointerSetInvalid
* Sets a disk item pointer to be invalid.
*/
-#define ItemPointerSetInvalid(pointer) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), InvalidBlockNumber), \
- (pointer)->ip_posid = InvalidOffsetNumber \
-)
+static inline void
+ItemPointerSetInvalid(ItemPointerData *pointer)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, InvalidBlockNumber);
+ pointer->ip_posid = InvalidOffsetNumber;
+}
/*
* ItemPointerIndicatesMovedPartitions
* True iff the block number indicates the tuple has moved to another
* partition.
*/
-#define ItemPointerIndicatesMovedPartitions(pointer) \
-( \
- ItemPointerGetOffsetNumber(pointer) == MovedPartitionsOffsetNumber && \
- ItemPointerGetBlockNumberNoCheck(pointer) == MovedPartitionsBlockNumber \
-)
+static inline bool
+ItemPointerIndicatesMovedPartitions(const ItemPointerData *pointer)
+{
+ return
+ ItemPointerGetOffsetNumber(pointer) == MovedPartitionsOffsetNumber &&
+ ItemPointerGetBlockNumberNoCheck(pointer) == MovedPartitionsBlockNumber;
+}
/*
* ItemPointerSetMovedPartitions
* Indicate that the item referenced by the itempointer has moved into a
* different partition.
*/
-#define ItemPointerSetMovedPartitions(pointer) \
- ItemPointerSet((pointer), MovedPartitionsBlockNumber, MovedPartitionsOffsetNumber)
+static inline void
+ItemPointerSetMovedPartitions(ItemPointerData *pointer)
+{
+ ItemPointerSet(pointer, MovedPartitionsBlockNumber, MovedPartitionsOffsetNumber);
+}
/* ----------------
* externs
--
2.35.1
0004-Convert-macros-to-static-inline-functions-bufmgr.h.patchtext/plain; charset=UTF-8; name=0004-Convert-macros-to-static-inline-functions-bufmgr.h.patchDownload
From 86ce1edc994669bd3c86965e1c264951a231c6ca Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (bufmgr.h)
---
src/include/storage/bufmgr.h | 50 +++++++++++++++++++++---------------
1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 58391406f6..ce725afa5e 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -98,7 +98,7 @@ extern PGDLLIMPORT int32 *LocalRefCount;
#define BUFFER_LOCK_EXCLUSIVE 2
/*
- * These routines are beaten on quite heavily, hence the macroization.
+ * These routines are beaten on quite heavily, hence inline.
*/
/*
@@ -120,11 +120,14 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* even in non-assert-enabled builds can be significant. Thus, we've
* now demoted the range checks to assertions within the macro itself.
*/
-#define BufferIsValid(bufnum) \
-( \
- AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \
- (bufnum) != InvalidBuffer \
-)
+static inline bool
+BufferIsValid(Buffer bufnum)
+{
+ Assert(bufnum <= NBuffers);
+ Assert(bufnum >= -NLocBuffer);
+
+ return bufnum != InvalidBuffer;
+}
/*
* BufferGetBlock
@@ -133,14 +136,16 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* Note:
* Assumes buffer is valid.
*/
-#define BufferGetBlock(buffer) \
-( \
- AssertMacro(BufferIsValid(buffer)), \
- BufferIsLocal(buffer) ? \
- LocalBufferBlockPointers[-(buffer) - 1] \
- : \
- (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \
-)
+static inline Block
+BufferGetBlock(Buffer buffer)
+{
+ Assert(BufferIsValid(buffer));
+
+ if (BufferIsLocal(buffer))
+ return LocalBufferBlockPointers[-buffer - 1];
+ else
+ return (Block) (BufferBlocks + ((Size) (buffer - 1)) * BLCKSZ);
+}
/*
* BufferGetPageSize
@@ -153,11 +158,12 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* (formatted) disk page.
*/
/* XXX should dig out of buffer descriptor */
-#define BufferGetPageSize(buffer) \
-( \
- AssertMacro(BufferIsValid(buffer)), \
- (Size)BLCKSZ \
-)
+static inline Size
+BufferGetPageSize(Buffer buffer)
+{
+ AssertMacro(BufferIsValid(buffer));
+ return (Size) BLCKSZ;
+}
/*
* BufferGetPage
@@ -166,7 +172,11 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* When this is called as part of a scan, there may be a need for a nearby
* call to TestForOldSnapshot(). See the definition of that for details.
*/
-#define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer))
+static inline Page
+BufferGetPage(Buffer buffer)
+{
+ return (Page) BufferGetBlock(buffer);
+}
/*
* prototypes for functions in bufmgr.c
--
2.35.1
0005-Convert-macros-to-static-inline-functions-xlog_inter.patchtext/plain; charset=UTF-8; name=0005-Convert-macros-to-static-inline-functions-xlog_inter.patchDownload
From fc3b47997af392d0c33ed2f0df52d281c873e406 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (xlog_internal.h)
---
src/include/access/xlog_internal.h | 154 ++++++++++++++++++-----------
1 file changed, 96 insertions(+), 58 deletions(-)
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index fae0bef8f5..aea24f737c 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -159,74 +159,112 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define XLOG_FNAME_LEN 24
/*
- * Generate a WAL segment file name. Do not use this macro in a helper
+ * Generate a WAL segment file name. Do not use this function in a helper
* function allocating the result generated.
*/
-#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
+static inline void
+XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
+}
-#define XLogFileNameById(fname, tli, log, seg) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg)
+// FIXME: This is only used by pg_archivecleanup and could be gotten rid of.
+static inline void
+XLogFileNameById(char *fname, TimeLineID tli, uint32 log, uint32 seg)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg);
+}
-#define IsXLogFileName(fname) \
- (strlen(fname) == XLOG_FNAME_LEN && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN)
+static inline bool
+IsXLogFileName(const char *fname)
+{
+ return (strlen(fname) == XLOG_FNAME_LEN && \
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN);
+}
/*
* XLOG segment with .partial suffix. Used by pg_receivewal and at end of
* archive recovery, when we want to archive a WAL segment but it might not
* be complete yet.
*/
-#define IsPartialXLogFileName(fname) \
- (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
- strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0)
-
-#define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes) \
- do { \
- uint32 log; \
- uint32 seg; \
- sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \
- *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; \
- } while (0)
-
-#define XLogFilePath(path, tli, logSegNo, wal_segsz_bytes) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
-
-#define TLHistoryFileName(fname, tli) \
- snprintf(fname, MAXFNAMELEN, "%08X.history", tli)
-
-#define IsTLHistoryFileName(fname) \
- (strlen(fname) == 8 + strlen(".history") && \
- strspn(fname, "0123456789ABCDEF") == 8 && \
- strcmp((fname) + 8, ".history") == 0)
-
-#define TLHistoryFilePath(path, tli) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli)
-
-#define StatusFilePath(path, xlog, suffix) \
- snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix)
-
-#define BackupHistoryFileName(fname, tli, logSegNo, startpoint, wal_segsz_bytes) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)))
-
-#define IsBackupHistoryFileName(fname) \
- (strlen(fname) > XLOG_FNAME_LEN && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
- strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0)
-
-#define BackupHistoryFilePath(path, tli, logSegNo, startpoint, wal_segsz_bytes) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)))
+static inline bool
+IsPartialXLogFileName(const char *fname)
+{
+ return (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") &&
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
+ strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0);
+}
+
+static inline void
+XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
+{
+ uint32 log;
+ uint32 seg;
+ sscanf(fname, "%08X%08X%08X", tli, &log, &seg);
+ *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg;
+}
+
+static inline void
+XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
+}
+
+static inline void
+TLHistoryFileName(char *fname, TimeLineID tli)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X.history", tli);
+}
+
+static inline bool
+IsTLHistoryFileName(const char *fname)
+{
+ return (strlen(fname) == 8 + strlen(".history") &&
+ strspn(fname, "0123456789ABCDEF") == 8 &&
+ strcmp((fname) + 8, ".history") == 0);
+}
+
+static inline void
+TLHistoryFilePath(char *path, TimeLineID tli)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli);
+}
+
+static inline void
+StatusFilePath(char *path, const char *xlog, const char *suffix)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix);
+}
+
+static inline void
+BackupHistoryFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)));
+}
+
+static inline bool
+IsBackupHistoryFileName(const char *fname)
+{
+ return (strlen(fname) > XLOG_FNAME_LEN &&
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
+ strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0);
+}
+
+static inline void
+BackupHistoryFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)));
+}
/*
* Information logged when we detect a change in one of the parameters
--
2.35.1
0006-Convert-macros-to-static-inline-functions-tupmacs.h.patchtext/plain; charset=UTF-8; name=0006-Convert-macros-to-static-inline-functions-tupmacs.h.patchDownload
From eeac95fe1d510d2071d460124c2c3b60b8dcd88d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (tupmacs.h)
XXX The renaming in gistutil.c is unnecessary if the subsequent itup.h
patch is also included.
---
src/backend/access/gist/gistutil.c | 16 +--
src/include/access/itup.h | 2 +-
src/include/access/tupmacs.h | 159 +++++++++++------------------
3 files changed, 68 insertions(+), 109 deletions(-)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index d4bf0c7563..24b2c493e7 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -667,7 +667,7 @@ HeapTuple
gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
{
MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
- Datum fetchatt[INDEX_MAX_KEYS];
+ Datum att[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
int i;
@@ -680,9 +680,9 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
if (giststate->fetchFn[i].fn_oid != InvalidOid)
{
if (!isnull[i])
- fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
+ att[i] = gistFetchAtt(giststate, i, datum, r);
else
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
else if (giststate->compressFn[i].fn_oid == InvalidOid)
{
@@ -691,9 +691,9 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
* original value, att is necessarily stored in original form.
*/
if (!isnull[i])
- fetchatt[i] = datum;
+ att[i] = datum;
else
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
else
{
@@ -703,7 +703,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
* in this column, and we can replace it with a NULL.
*/
isnull[i] = true;
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
}
@@ -712,12 +712,12 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
*/
for (; i < r->rd_att->natts; i++)
{
- fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
+ att[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
&isnull[i]);
}
MemoryContextSwitchTo(oldcxt);
- return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
+ return heap_form_tuple(giststate->fetchTupdesc, att, isnull);
}
float
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 2c8877e991..6e6aec1043 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -114,7 +114,7 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
) \
: \
( \
- (att_isnull((attnum)-1, (char *)(tup) + sizeof(IndexTupleData))) ? \
+ (att_isnull((attnum)-1, (bits8 *)(tup) + sizeof(IndexTupleData))) ? \
( \
*(isnull) = true, \
(Datum)NULL \
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 16c74a581e..4876dabc3d 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -14,6 +14,7 @@
#ifndef TUPMACS_H
#define TUPMACS_H
+#include "catalog/pg_attribute.h"
#include "catalog/pg_type_d.h" /* for TYPALIGN macros */
@@ -22,10 +23,14 @@
* Note that a 0 in the null bitmap indicates a null, while 1 indicates
* non-null.
*/
-#define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07))))
+static inline bool
+att_isnull(int ATT, const bits8 *BITS)
+{
+ return !(BITS[ATT >> 3] & (1 << (ATT & 0x07)));
+}
/*
- * Given a Form_pg_attribute and a pointer into a tuple's data area,
+ * Given byval/len parameters and a pointer into a tuple's data area,
* return the correct value or pointer.
*
* We return a Datum value in all cases. If the attribute has "byval" false,
@@ -38,61 +43,38 @@
*
* Note that T must already be properly aligned for this to work correctly.
*/
-#define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen)
+static inline Datum
+fetch_att(const void *T, bool attbyval, int attlen)
+{
+ if (attbyval)
+ {
+#if SIZEOF_DATUM == 8
+ if (attlen == sizeof(Datum))
+ return *((const Datum *) T);
+ else
+#endif
+ if (attlen == sizeof(int32))
+ return Int32GetDatum(*((const int32 *) T));
+ else if (attlen == sizeof(int16))
+ return Int16GetDatum(*((const int16 *) T));
+ else
+ {
+ Assert(attlen == 1);
+ return CharGetDatum(*((const char *) T));
+ }
+ }
+ else
+ return PointerGetDatum(T);
+}
/*
- * Same, but work from byval/len parameters rather than Form_pg_attribute.
+ * Same, but work from a Form_pg_attribute rather than byval/len parameters.
*/
-#if SIZEOF_DATUM == 8
-
-#define fetch_att(T,attbyval,attlen) \
-( \
- (attbyval) ? \
- ( \
- (attlen) == (int) sizeof(Datum) ? \
- *((Datum *)(T)) \
- : \
- ( \
- (attlen) == (int) sizeof(int32) ? \
- Int32GetDatum(*((int32 *)(T))) \
- : \
- ( \
- (attlen) == (int) sizeof(int16) ? \
- Int16GetDatum(*((int16 *)(T))) \
- : \
- ( \
- AssertMacro((attlen) == 1), \
- CharGetDatum(*((char *)(T))) \
- ) \
- ) \
- ) \
- ) \
- : \
- PointerGetDatum((char *) (T)) \
-)
-#else /* SIZEOF_DATUM != 8 */
-
-#define fetch_att(T,attbyval,attlen) \
-( \
- (attbyval) ? \
- ( \
- (attlen) == (int) sizeof(int32) ? \
- Int32GetDatum(*((int32 *)(T))) \
- : \
- ( \
- (attlen) == (int) sizeof(int16) ? \
- Int16GetDatum(*((int16 *)(T))) \
- : \
- ( \
- AssertMacro((attlen) == 1), \
- CharGetDatum(*((char *)(T))) \
- ) \
- ) \
- ) \
- : \
- PointerGetDatum((char *) (T)) \
-)
-#endif /* SIZEOF_DATUM == 8 */
+static inline Datum
+fetchatt(const FormData_pg_attribute *A, const void *T)
+{
+ return fetch_att(T, A->attbyval, A->attlen);
+}
/*
* att_align_datum aligns the given offset as needed for a datum of alignment
@@ -194,54 +176,31 @@
* store_att_byval is a partial inverse of fetch_att: store a given Datum
* value into a tuple data area at the specified address. However, it only
* handles the byval case, because in typical usage the caller needs to
- * distinguish by-val and by-ref cases anyway, and so a do-it-all macro
+ * distinguish by-val and by-ref cases anyway, and so a do-it-all function
* wouldn't be convenient.
*/
+static inline void
+store_att_byval(void *T, Datum newdatum, int attlen)
+{
+ switch (attlen)
+ {
+ case sizeof(char):
+ *(char *) T = DatumGetChar(newdatum);
+ break;
+ case sizeof(int16):
+ *(int16 *) T = DatumGetInt16(newdatum);
+ break;
+ case sizeof(int32):
+ *(int32 *) T = DatumGetInt32(newdatum);
+ break;
#if SIZEOF_DATUM == 8
-
-#define store_att_byval(T,newdatum,attlen) \
- do { \
- switch (attlen) \
- { \
- case sizeof(char): \
- *(char *) (T) = DatumGetChar(newdatum); \
- break; \
- case sizeof(int16): \
- *(int16 *) (T) = DatumGetInt16(newdatum); \
- break; \
- case sizeof(int32): \
- *(int32 *) (T) = DatumGetInt32(newdatum); \
- break; \
- case sizeof(Datum): \
- *(Datum *) (T) = (newdatum); \
- break; \
- default: \
- elog(ERROR, "unsupported byval length: %d", \
- (int) (attlen)); \
- break; \
- } \
- } while (0)
-#else /* SIZEOF_DATUM != 8 */
-
-#define store_att_byval(T,newdatum,attlen) \
- do { \
- switch (attlen) \
- { \
- case sizeof(char): \
- *(char *) (T) = DatumGetChar(newdatum); \
- break; \
- case sizeof(int16): \
- *(int16 *) (T) = DatumGetInt16(newdatum); \
- break; \
- case sizeof(int32): \
- *(int32 *) (T) = DatumGetInt32(newdatum); \
- break; \
- default: \
- elog(ERROR, "unsupported byval length: %d", \
- (int) (attlen)); \
- break; \
- } \
- } while (0)
-#endif /* SIZEOF_DATUM == 8 */
+ case sizeof(Datum):
+ *(Datum *) T = newdatum;
+ break;
+#endif
+ default:
+ elog(ERROR, "unsupported byval length: %d", attlen);
+ }
+}
#endif
--
2.35.1
0007-Convert-macros-to-static-inline-functions-itup.h.patchtext/plain; charset=UTF-8; name=0007-Convert-macros-to-static-inline-functions-itup.h.patchDownload
From ebb518f6f3faff60430c1784ed3bbf44cea311f0 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (itup.h)
---
src/include/access/itup.h | 107 +++++++++++++++++++-------------------
1 file changed, 53 insertions(+), 54 deletions(-)
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 6e6aec1043..36e5e87b9c 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -73,21 +73,33 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
#define IndexTupleHasVarwidths(itup) ((((IndexTuple) (itup))->t_info & INDEX_VAR_MASK))
+/* routines in indextuple.c */
+extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull);
+extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
+ TupleDesc tupleDesc);
+extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull);
+extern void index_deform_tuple_internal(TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull,
+ char *tp, bits8 *bp, int hasnulls);
+extern IndexTuple CopyIndexTuple(IndexTuple source);
+extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor,
+ IndexTuple source, int leavenatts);
+
+
/*
* Takes an infomask as argument (primarily because this needs to be usable
* at index_form_tuple time so enough space is allocated).
*/
-#define IndexInfoFindDataOffset(t_info) \
-( \
- (!((t_info) & INDEX_NULL_MASK)) ? \
- ( \
- (Size)MAXALIGN(sizeof(IndexTupleData)) \
- ) \
- : \
- ( \
- (Size)MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData)) \
- ) \
-)
+static inline Size
+IndexInfoFindDataOffset(unsigned short t_info)
+{
+ if (!(t_info & INDEX_NULL_MASK))
+ return MAXALIGN(sizeof(IndexTupleData));
+ else
+ return MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData));
+}
/* ----------------
* index_getattr
@@ -97,34 +109,36 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
*
* ----------------
*/
-#define index_getattr(tup, attnum, tupleDesc, isnull) \
-( \
- AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \
- *(isnull) = false, \
- !IndexTupleHasNulls(tup) ? \
- ( \
- TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff >= 0 ? \
- ( \
- fetchatt(TupleDescAttr((tupleDesc), (attnum)-1), \
- (char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \
- + TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff) \
- ) \
- : \
- nocache_index_getattr((tup), (attnum), (tupleDesc)) \
- ) \
- : \
- ( \
- (att_isnull((attnum)-1, (bits8 *)(tup) + sizeof(IndexTupleData))) ? \
- ( \
- *(isnull) = true, \
- (Datum)NULL \
- ) \
- : \
- ( \
- nocache_index_getattr((tup), (attnum), (tupleDesc)) \
- ) \
- ) \
-)
+static inline Datum
+index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
+{
+ Assert(PointerIsValid(isnull));
+ Assert(attnum > 0);
+
+ *isnull = false;
+
+ if (!IndexTupleHasNulls(tup))
+ {
+ if (TupleDescAttr(tupleDesc, attnum - 1)->attcacheoff >= 0)
+ {
+ return fetchatt(TupleDescAttr(tupleDesc, attnum - 1),
+ (char *) tup + IndexInfoFindDataOffset(tup->t_info)
+ + TupleDescAttr(tupleDesc, attnum-1)->attcacheoff);
+ }
+ else
+ return nocache_index_getattr(tup, attnum, tupleDesc);
+ }
+ else
+ {
+ if (att_isnull(attnum - 1, (bits8 *) tup + sizeof(IndexTupleData)))
+ {
+ *isnull = true;
+ return (Datum) NULL;
+ }
+ else
+ return nocache_index_getattr(tup, attnum, tupleDesc);
+ }
+}
/*
* MaxIndexTuplesPerPage is an upper bound on the number of tuples that can
@@ -146,19 +160,4 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
((int) ((BLCKSZ - SizeOfPageHeaderData) / \
(MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData))))
-
-/* routines in indextuple.c */
-extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
- Datum *values, bool *isnull);
-extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
- TupleDesc tupleDesc);
-extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
- Datum *values, bool *isnull);
-extern void index_deform_tuple_internal(TupleDesc tupleDescriptor,
- Datum *values, bool *isnull,
- char *tp, bits8 *bp, int hasnulls);
-extern IndexTuple CopyIndexTuple(IndexTuple source);
-extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor,
- IndexTuple source, int leavenatts);
-
#endif /* ITUP_H */
--
2.35.1
0008-Convert-macros-to-static-inline-functions-pgstat.h.patchtext/plain; charset=UTF-8; name=0008-Convert-macros-to-static-inline-functions-pgstat.h.patchDownload
From b1aacce2517f2fe65143aa108da06e2b0dd5cbe3 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 16 May 2022 09:58:13 +0200
Subject: [PATCH] Convert macros to static inline functions (pgstat.h)
---
src/include/pgstat.h | 227 ++++++++++++++++++++++++-------------------
1 file changed, 125 insertions(+), 102 deletions(-)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index ac28f813b4..e7a122dcdb 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -16,6 +16,7 @@
#include "postmaster/pgarch.h" /* for MAX_XFN_CHARS */
#include "utils/backend_progress.h" /* for backward compatibility */
#include "utils/backend_status.h" /* for backward compatibility */
+#include "utils/rel.h"
#include "utils/relcache.h"
#include "utils/wait_event.h" /* for backward compatibility */
@@ -396,6 +397,62 @@ typedef struct PgStat_WalStats
} PgStat_WalStats;
+/*
+ * Variables in pgstat.c
+ */
+
+/* GUC parameters */
+extern PGDLLIMPORT bool pgstat_track_counts;
+extern PGDLLIMPORT int pgstat_track_functions;
+extern PGDLLIMPORT int pgstat_fetch_consistency;
+
+
+/*
+ * Variables in pgstat_bgwriter.c
+ */
+
+/* updated directly by bgwriter and bufmgr */
+extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats;
+
+
+/*
+ * Variables in pgstat_checkpointer.c
+ */
+
+/*
+ * Checkpointer statistics counters are updated directly by checkpointer and
+ * bufmgr.
+ */
+extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats;
+
+
+/*
+ * Variables in pgstat_database.c
+ */
+
+/* Updated by pgstat_count_buffer_*_time macros */
+extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime;
+extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime;
+
+/*
+ * Updated by pgstat_count_conn_*_time macros, called by
+ * pgstat_report_activity().
+ */
+extern PGDLLIMPORT PgStat_Counter pgStatActiveTime;
+extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime;
+
+/* updated by the traffic cop and in errfinish() */
+extern PGDLLIMPORT SessionEndType pgStatSessionEndCause;
+
+
+/*
+ * Variables in pgstat_wal.c
+ */
+
+/* updated directly by backends and background processes */
+extern PGDLLIMPORT PgStat_WalStats PendingWalStats;
+
+
/*
* Functions in pgstat.c
*/
@@ -465,14 +522,26 @@ extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount);
extern void pgstat_report_checksum_failure(void);
extern void pgstat_report_connect(Oid dboid);
-#define pgstat_count_buffer_read_time(n) \
- (pgStatBlockReadTime += (n))
-#define pgstat_count_buffer_write_time(n) \
- (pgStatBlockWriteTime += (n))
-#define pgstat_count_conn_active_time(n) \
- (pgStatActiveTime += (n))
-#define pgstat_count_conn_txn_idle_time(n) \
- (pgStatTransactionIdleTime += (n))
+static inline void
+pgstat_count_buffer_read_time(PgStat_Counter n)
+{
+ pgStatBlockReadTime += n;
+}
+static inline void
+pgstat_count_buffer_write_time(PgStat_Counter n)
+{
+ pgStatBlockWriteTime += n;
+}
+static inline void
+pgstat_count_conn_active_time(PgStat_Counter n)
+{
+ pgStatActiveTime += n;
+}
+static inline void
+pgstat_count_conn_txn_idle_time(PgStat_Counter n)
+{
+ pgStatTransactionIdleTime += n;
+}
extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
@@ -516,47 +585,57 @@ extern void pgstat_report_analyze(Relation rel,
* pgstat_assoc_relation() to do so. See its comment for why this is done
* separately from pgstat_init_relation().
*/
-#define pgstat_should_count_relation(rel) \
- (likely((rel)->pgstat_info != NULL) ? true : \
- ((rel)->pgstat_enabled ? pgstat_assoc_relation(rel), true : false))
+static inline bool
+pgstat_should_count_relation(Relation rel)
+{
+ return (likely(rel->pgstat_info != NULL) ? true :
+ (rel->pgstat_enabled ? pgstat_assoc_relation(rel), true : false));
+}
/* nontransactional event counts are simple enough to inline */
-#define pgstat_count_heap_scan(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_numscans++; \
- } while (0)
-#define pgstat_count_heap_getnext(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_returned++; \
- } while (0)
-#define pgstat_count_heap_fetch(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_fetched++; \
- } while (0)
-#define pgstat_count_index_scan(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_numscans++; \
- } while (0)
-#define pgstat_count_index_tuples(rel, n) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_returned += (n); \
- } while (0)
-#define pgstat_count_buffer_read(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_blocks_fetched++; \
- } while (0)
-#define pgstat_count_buffer_hit(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_blocks_hit++; \
- } while (0)
+static inline void
+pgstat_count_heap_scan(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_numscans++;
+}
+static inline void
+pgstat_count_heap_getnext(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_returned++;
+}
+static inline void
+pgstat_count_heap_fetch(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_fetched++;
+}
+static inline void
+pgstat_count_index_scan(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_numscans++;
+}
+static inline void
+pgstat_count_index_tuples(Relation rel, PgStat_Counter n)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_returned += n;
+}
+static inline void
+pgstat_count_buffer_read(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_blocks_fetched++;
+}
+static inline void
+pgstat_count_buffer_hit(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_blocks_hit++;
+}
extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
extern void pgstat_count_heap_update(Relation rel, bool hot);
@@ -636,60 +715,4 @@ extern void pgstat_report_wal(bool force);
extern PgStat_WalStats *pgstat_fetch_stat_wal(void);
-/*
- * Variables in pgstat.c
- */
-
-/* GUC parameters */
-extern PGDLLIMPORT bool pgstat_track_counts;
-extern PGDLLIMPORT int pgstat_track_functions;
-extern PGDLLIMPORT int pgstat_fetch_consistency;
-
-
-/*
- * Variables in pgstat_bgwriter.c
- */
-
-/* updated directly by bgwriter and bufmgr */
-extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats;
-
-
-/*
- * Variables in pgstat_checkpointer.c
- */
-
-/*
- * Checkpointer statistics counters are updated directly by checkpointer and
- * bufmgr.
- */
-extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats;
-
-
-/*
- * Variables in pgstat_database.c
- */
-
-/* Updated by pgstat_count_buffer_*_time macros */
-extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime;
-extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime;
-
-/*
- * Updated by pgstat_count_conn_*_time macros, called by
- * pgstat_report_activity().
- */
-extern PGDLLIMPORT PgStat_Counter pgStatActiveTime;
-extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime;
-
-/* updated by the traffic cop and in errfinish() */
-extern PGDLLIMPORT SessionEndType pgStatSessionEndCause;
-
-
-/*
- * Variables in pgstat_wal.c
- */
-
-/* updated directly by backends and background processes */
-extern PGDLLIMPORT PgStat_WalStats PendingWalStats;
-
-
#endif /* PGSTAT_H */
--
2.35.1
On Mon, May 16, 2022 at 1:58 PM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:
Inspired by [0], I looked to convert more macros to inline functions.
The attached patches are organized "bottom up" in terms of their API
layering; some of the later ones depend on some of the earlier ones.
All the patches look good to me, except the following that are minor
things that can be ignored if you want.
0002 patch:
+static inline OffsetNumber
+PageGetMaxOffsetNumber(Page page)
+{
+ if (((PageHeader) page)->pd_lower <= SizeOfPageHeaderData)
+ return 0;
+ else
+ return ((((PageHeader) page)->pd_lower - SizeOfPageHeaderData)
/ sizeof(ItemIdData));
+}
The "else" is not necessary, we can have the return statement directly
which would save some indentation as well. The Similar pattern can be
considered for 0004 and 0007 patches as well.
--
0004 patch:
+static inline void
+XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo
*logSegNo, int wal_segsz_bytes)
+{
+ uint32 log;
+ uint32 seg;
+ sscanf(fname, "%08X%08X%08X", tli, &log, &seg);
+ *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg;
+}
Can we have a blank line after variable declarations that we usually have?
--
0006 patch:
+static inline Datum
+fetch_att(const void *T, bool attbyval, int attlen)
+{
+ if (attbyval)
+ {
+#if SIZEOF_DATUM == 8
+ if (attlen == sizeof(Datum))
+ return *((const Datum *) T);
+ else
+#endif
Can we have a switch case like store_att_byval() instead of if-else,
code would look more symmetric, IMO.
Regards,
Amul
On 2022-May-16, Amul Sul wrote:
+static inline OffsetNumber +PageGetMaxOffsetNumber(Page page) +{ + if (((PageHeader) page)->pd_lower <= SizeOfPageHeaderData) + return 0; + else + return ((((PageHeader) page)->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData)); +}The "else" is not necessary, we can have the return statement directly
which would save some indentation as well. The Similar pattern can be
considered for 0004 and 0007 patches as well.
Yeah. In these cases I propose to also have a local variable so that
the cast to PageHeader appears only once.
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
On 16.05.22 15:23, Amul Sul wrote:
+static inline OffsetNumber +PageGetMaxOffsetNumber(Page page) +{ + if (((PageHeader) page)->pd_lower <= SizeOfPageHeaderData) + return 0; + else + return ((((PageHeader) page)->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData)); +}The "else" is not necessary, we can have the return statement directly
which would save some indentation as well. The Similar pattern can be
considered for 0004 and 0007 patches as well.
I kind of like it better this way. It preserves the functional style of
the original macro.
+static inline void +XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes) +{ + uint32 log; + uint32 seg; + sscanf(fname, "%08X%08X%08X", tli, &log, &seg); + *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; +}Can we have a blank line after variable declarations that we usually have?
done
0006 patch: +static inline Datum +fetch_att(const void *T, bool attbyval, int attlen) +{ + if (attbyval) + { +#if SIZEOF_DATUM == 8 + if (attlen == sizeof(Datum)) + return *((const Datum *) T); + else +#endifCan we have a switch case like store_att_byval() instead of if-else,
code would look more symmetric, IMO.
done
Attachments:
v2-0001-Convert-macros-to-static-inline-functions-block.h.patchtext/plain; charset=UTF-8; name=v2-0001-Convert-macros-to-static-inline-functions-block.h.patchDownload
From 75cc12a425a58340799376bc1e2dfdebfcb7ea0a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (block.h)
Remove BlockIdIsValid(), which wasn't used and is unnecessary.
Remove BlockIdCopy(), which wasn't used and can be done by struct
assignment.
(BlockIdEquals() also isn't used, but seems reasonable to keep
around.)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/storage/block.h | 53 ++++++++++++++++---------------------
1 file changed, 23 insertions(+), 30 deletions(-)
diff --git a/src/include/storage/block.h b/src/include/storage/block.h
index d756e3fda5..c726142f96 100644
--- a/src/include/storage/block.h
+++ b/src/include/storage/block.h
@@ -59,7 +59,7 @@ typedef struct BlockIdData
typedef BlockIdData *BlockId; /* block identifier */
/* ----------------
- * support macros
+ * support functions
* ----------------
*/
@@ -67,49 +67,42 @@ typedef BlockIdData *BlockId; /* block identifier */
* BlockNumberIsValid
* True iff blockNumber is valid.
*/
-#define BlockNumberIsValid(blockNumber) \
- ((BlockNumber) (blockNumber) != InvalidBlockNumber)
-
-/*
- * BlockIdIsValid
- * True iff the block identifier is valid.
- */
-#define BlockIdIsValid(blockId) \
- PointerIsValid(blockId)
+static inline bool
+BlockNumberIsValid(BlockNumber blockNumber)
+{
+ return blockNumber != InvalidBlockNumber;
+}
/*
* BlockIdSet
* Sets a block identifier to the specified value.
*/
-#define BlockIdSet(blockId, blockNumber) \
-( \
- (blockId)->bi_hi = (blockNumber) >> 16, \
- (blockId)->bi_lo = (blockNumber) & 0xffff \
-)
-
-/*
- * BlockIdCopy
- * Copy a block identifier.
- */
-#define BlockIdCopy(toBlockId, fromBlockId) \
-( \
- (toBlockId)->bi_hi = (fromBlockId)->bi_hi, \
- (toBlockId)->bi_lo = (fromBlockId)->bi_lo \
-)
+static inline void
+BlockIdSet(BlockIdData *blockId, BlockNumber blockNumber)
+{
+ blockId->bi_hi = blockNumber >> 16;
+ blockId->bi_lo = blockNumber & 0xffff;
+}
/*
* BlockIdEquals
* Check for block number equality.
*/
-#define BlockIdEquals(blockId1, blockId2) \
- ((blockId1)->bi_hi == (blockId2)->bi_hi && \
- (blockId1)->bi_lo == (blockId2)->bi_lo)
+static inline bool
+BlockIdEquals(const BlockIdData *blockId1, const BlockIdData *blockId2)
+{
+ return (blockId1->bi_hi == blockId2->bi_hi &&
+ blockId1->bi_lo == blockId2->bi_lo);
+}
/*
* BlockIdGetBlockNumber
* Retrieve the block number from a block identifier.
*/
-#define BlockIdGetBlockNumber(blockId) \
- ((((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo))
+static inline BlockNumber
+BlockIdGetBlockNumber(const BlockIdData *blockId)
+{
+ return (((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo);
+}
#endif /* BLOCK_H */
--
2.36.1
v2-0002-Convert-macros-to-static-inline-functions-bufpage.patchtext/plain; charset=UTF-8; name=v2-0002-Convert-macros-to-static-inline-functions-bufpage.patchDownload
From 103f6b446cc2efa0b6a21bf181171cbad176d968 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (bufpage.h)
rawpage.c needs some adjustments because it was previously playing
loose with the Page vs. PageHeader types, which is no longer possible
with the functions instead of macros.
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
contrib/pageinspect/rawpage.c | 24 ++++---
src/include/storage/bufpage.h | 131 ++++++++++++++++++++--------------
2 files changed, 92 insertions(+), 63 deletions(-)
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 730a46b1d8..90942be71e 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -254,7 +254,8 @@ page_header(PG_FUNCTION_ARGS)
Datum values[9];
bool nulls[9];
- PageHeader page;
+ Page page;
+ PageHeader pageheader;
XLogRecPtr lsn;
if (!superuser())
@@ -262,7 +263,8 @@ page_header(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to use raw page functions")));
- page = (PageHeader) get_page_from_raw(raw_page);
+ page = get_page_from_raw(raw_page);
+ pageheader = (PageHeader) page;
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
@@ -282,8 +284,8 @@ page_header(PG_FUNCTION_ARGS)
}
else
values[0] = LSNGetDatum(lsn);
- values[1] = UInt16GetDatum(page->pd_checksum);
- values[2] = UInt16GetDatum(page->pd_flags);
+ values[1] = UInt16GetDatum(pageheader->pd_checksum);
+ values[2] = UInt16GetDatum(pageheader->pd_flags);
/* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
switch (TupleDescAttr(tupdesc, 3)->atttypid)
@@ -292,18 +294,18 @@ page_header(PG_FUNCTION_ARGS)
Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
- values[3] = UInt16GetDatum(page->pd_lower);
- values[4] = UInt16GetDatum(page->pd_upper);
- values[5] = UInt16GetDatum(page->pd_special);
+ values[3] = UInt16GetDatum(pageheader->pd_lower);
+ values[4] = UInt16GetDatum(pageheader->pd_upper);
+ values[5] = UInt16GetDatum(pageheader->pd_special);
values[6] = UInt16GetDatum(PageGetPageSize(page));
break;
case INT4OID:
Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
- values[3] = Int32GetDatum(page->pd_lower);
- values[4] = Int32GetDatum(page->pd_upper);
- values[5] = Int32GetDatum(page->pd_special);
+ values[3] = Int32GetDatum(pageheader->pd_lower);
+ values[4] = Int32GetDatum(pageheader->pd_upper);
+ values[5] = Int32GetDatum(pageheader->pd_special);
values[6] = Int32GetDatum(PageGetPageSize(page));
break;
default:
@@ -312,7 +314,7 @@ page_header(PG_FUNCTION_ARGS)
}
values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
- values[8] = TransactionIdGetDatum(page->pd_prune_xid);
+ values[8] = TransactionIdGetDatum(pageheader->pd_prune_xid);
/* Build and return the tuple. */
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index e9f253f2c8..23a93ebda0 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -14,6 +14,7 @@
#ifndef BUFPAGE_H
#define BUFPAGE_H
+#include "access/transam.h"
#include "access/xlogdefs.h"
#include "storage/block.h"
#include "storage/item.h"
@@ -97,8 +98,12 @@ typedef struct
uint32 xrecoff; /* low bits */
} PageXLogRecPtr;
-#define PageXLogRecPtrGet(val) \
- ((uint64) (val).xlogid << 32 | (val).xrecoff)
+
+static inline XLogRecPtr
+PageXLogRecPtrGet(PageXLogRecPtr val)
+{
+ return (uint64) val.xlogid << 32 | val.xrecoff;
+}
#define PageXLogRecPtrSet(ptr, lsn) \
((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn))
@@ -200,7 +205,7 @@ typedef PageHeaderData *PageHeader;
#define PG_DATA_CHECKSUM_VERSION 1
/* ----------------------------------------------------------------
- * page support macros
+ * page support macros and functions
* ----------------------------------------------------------------
*/
@@ -247,7 +252,7 @@ typedef PageHeaderData *PageHeader;
((char *) (page) + MAXALIGN(SizeOfPageHeaderData))
/* ----------------
- * macros to access page size info
+ * macros and functions to access page size info
* ----------------
*/
@@ -265,15 +270,21 @@ typedef PageHeaderData *PageHeader;
* BufferGetPageSize, which can be called on an unformatted page).
* however, it can be called on a page that is not stored in a buffer.
*/
-#define PageGetPageSize(page) \
- ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00))
+static inline Size
+PageGetPageSize(Page page)
+{
+ return (Size) (((PageHeader) page)->pd_pagesize_version & (uint16) 0xFF00);
+}
/*
* PageGetPageLayoutVersion
* Returns the page layout version of a page.
*/
-#define PageGetPageLayoutVersion(page) \
- (((PageHeader) (page))->pd_pagesize_version & 0x00FF)
+static inline uint8
+PageGetPageLayoutVersion(Page page)
+{
+ return (((PageHeader) page)->pd_pagesize_version & 0x00FF);
+}
/*
* PageSetPageSizeAndVersion
@@ -282,52 +293,52 @@ typedef PageHeaderData *PageHeader;
* We could support setting these two values separately, but there's
* no real need for it at the moment.
*/
-#define PageSetPageSizeAndVersion(page, size, version) \
-( \
- AssertMacro(((size) & 0xFF00) == (size)), \
- AssertMacro(((version) & 0x00FF) == (version)), \
- ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \
-)
+static inline void
+PageSetPageSizeAndVersion(Page page, Size size, uint8 version)
+{
+ Assert((size & 0xFF00) == size);
+ Assert((version & 0x00FF) == version);
+
+ ((PageHeader) page)->pd_pagesize_version = size | version;
+}
/* ----------------
- * page special data macros
+ * page special data macros and functions
* ----------------
*/
/*
* PageGetSpecialSize
* Returns size of special space on a page.
*/
-#define PageGetSpecialSize(page) \
- ((uint16) (PageGetPageSize(page) - ((PageHeader)(page))->pd_special))
+static inline uint16
+PageGetSpecialSize(Page page)
+{
+ return ((uint16) (PageGetPageSize(page) - ((PageHeader) page)->pd_special));
+}
/*
* Using assertions, validate that the page special pointer is OK.
*
* This is intended to catch use of the pointer before page initialization.
- * It is implemented as a function due to the limitations of the MSVC
- * compiler, which choked on doing all these tests within another macro. We
- * return true so that AssertMacro() can be used while still getting the
- * specifics from the macro failure within this function.
*/
-static inline bool
+static inline void
PageValidateSpecialPointer(Page page)
{
Assert(PageIsValid(page));
Assert(((PageHeader) (page))->pd_special <= BLCKSZ);
Assert(((PageHeader) (page))->pd_special >= SizeOfPageHeaderData);
-
- return true;
}
/*
* PageGetSpecialPointer
* Returns pointer to special space on a page.
*/
-#define PageGetSpecialPointer(page) \
-( \
- AssertMacro(PageValidateSpecialPointer(page)), \
- (char *) ((char *) (page) + ((PageHeader) (page))->pd_special) \
-)
+static inline char *
+PageGetSpecialPointer(Page page)
+{
+ PageValidateSpecialPointer(page);
+ return (char *) page + ((PageHeader) page)->pd_special;
+}
/*
* PageGetItem
@@ -337,12 +348,14 @@ PageValidateSpecialPointer(Page page)
* This does not change the status of any of the resources passed.
* The semantics may change in the future.
*/
-#define PageGetItem(page, itemId) \
-( \
- AssertMacro(PageIsValid(page)), \
- AssertMacro(ItemIdHasStorage(itemId)), \
- (Item)(((char *)(page)) + ItemIdGetOffset(itemId)) \
-)
+static inline Item
+PageGetItem(Page page, ItemId itemId)
+{
+ Assert(PageIsValid(page));
+ Assert(ItemIdHasStorage(itemId));
+
+ return (Item) (((char *) page) + ItemIdGetOffset(itemId));
+}
/*
* PageGetMaxOffsetNumber
@@ -351,17 +364,21 @@ PageValidateSpecialPointer(Page page)
* of items on the page.
*
* NOTE: if the page is not initialized (pd_lower == 0), we must
- * return zero to ensure sane behavior. Accept double evaluation
- * of the argument so that we can ensure this.
+ * return zero to ensure sane behavior.
*/
-#define PageGetMaxOffsetNumber(page) \
- (((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData ? 0 : \
- ((((PageHeader) (page))->pd_lower - SizeOfPageHeaderData) \
- / sizeof(ItemIdData)))
+static inline OffsetNumber
+PageGetMaxOffsetNumber(Page page)
+{
+ PageHeader pageheader = (PageHeader) page;
+
+ if (pageheader->pd_lower <= SizeOfPageHeaderData)
+ return 0;
+ else
+ return (pageheader->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData);
+}
/*
- * Additional macros for access to page headers. (Beware multiple evaluation
- * of the arguments!)
+ * Additional macros and functions for access to page headers.
*/
#define PageGetLSN(page) \
PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
@@ -389,15 +406,25 @@ PageValidateSpecialPointer(Page page)
#define PageClearAllVisible(page) \
(((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE)
-#define PageSetPrunable(page, xid) \
-do { \
- Assert(TransactionIdIsNormal(xid)); \
- if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
- TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
- ((PageHeader) (page))->pd_prune_xid = (xid); \
-} while (0)
-#define PageClearPrunable(page) \
- (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
+static inline void
+PageSetPrunable(Page page, TransactionId xid)
+{
+ PageHeader pageheader = (PageHeader) page;
+
+ Assert(TransactionIdIsNormal(xid));
+
+ if (!TransactionIdIsValid(pageheader->pd_prune_xid) ||
+ TransactionIdPrecedes(xid, pageheader->pd_prune_xid))
+ pageheader->pd_prune_xid = xid;
+}
+
+static inline void
+PageClearPrunable(Page page)
+{
+ PageHeader pageheader = (PageHeader) page;
+
+ pageheader->pd_prune_xid = InvalidTransactionId;
+}
/* ----------------------------------------------------------------
--
2.36.1
v2-0003-Convert-macros-to-static-inline-functions-itemptr.patchtext/plain; charset=UTF-8; name=v2-0003-Convert-macros-to-static-inline-functions-itemptr.patchDownload
From 667f5e233c5a563f62bfd5b6a94871599ab7a8c3 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (itemptr.h)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/storage/itemptr.h | 129 +++++++++++++++++++---------------
1 file changed, 73 insertions(+), 56 deletions(-)
diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h
index 81947bc657..3ec88a68df 100644
--- a/src/include/storage/itemptr.h
+++ b/src/include/storage/itemptr.h
@@ -71,7 +71,7 @@ typedef ItemPointerData *ItemPointer;
/* ----------------
- * support macros
+ * support functions
* ----------------
*/
@@ -79,77 +79,87 @@ typedef ItemPointerData *ItemPointer;
* ItemPointerIsValid
* True iff the disk item pointer is not NULL.
*/
-#define ItemPointerIsValid(pointer) \
- ((bool) (PointerIsValid(pointer) && ((pointer)->ip_posid != 0)))
+static inline bool
+ItemPointerIsValid(const ItemPointerData *pointer)
+{
+ return PointerIsValid(pointer) && pointer->ip_posid != 0;
+}
/*
* ItemPointerGetBlockNumberNoCheck
* Returns the block number of a disk item pointer.
*/
-#define ItemPointerGetBlockNumberNoCheck(pointer) \
-( \
- BlockIdGetBlockNumber(&(pointer)->ip_blkid) \
-)
+static inline BlockNumber
+ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
+{
+ return BlockIdGetBlockNumber(&pointer->ip_blkid);
+}
/*
* ItemPointerGetBlockNumber
* As above, but verifies that the item pointer looks valid.
*/
-#define ItemPointerGetBlockNumber(pointer) \
-( \
- AssertMacro(ItemPointerIsValid(pointer)), \
- ItemPointerGetBlockNumberNoCheck(pointer) \
-)
+static inline BlockNumber
+ItemPointerGetBlockNumber(const ItemPointerData *pointer)
+{
+ Assert(ItemPointerIsValid(pointer));
+ return ItemPointerGetBlockNumberNoCheck(pointer);
+}
/*
* ItemPointerGetOffsetNumberNoCheck
* Returns the offset number of a disk item pointer.
*/
-#define ItemPointerGetOffsetNumberNoCheck(pointer) \
-( \
- (pointer)->ip_posid \
-)
+static inline OffsetNumber
+ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
+{
+ return pointer->ip_posid;
+}
/*
* ItemPointerGetOffsetNumber
* As above, but verifies that the item pointer looks valid.
*/
-#define ItemPointerGetOffsetNumber(pointer) \
-( \
- AssertMacro(ItemPointerIsValid(pointer)), \
- ItemPointerGetOffsetNumberNoCheck(pointer) \
-)
+static inline OffsetNumber
+ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
+{
+ Assert(ItemPointerIsValid(pointer));
+ return ItemPointerGetOffsetNumberNoCheck(pointer);
+}
/*
* ItemPointerSet
* Sets a disk item pointer to the specified block and offset.
*/
-#define ItemPointerSet(pointer, blockNumber, offNum) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), blockNumber), \
- (pointer)->ip_posid = offNum \
-)
+static inline void
+ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, blockNumber);
+ pointer->ip_posid = offNum;
+}
/*
* ItemPointerSetBlockNumber
* Sets a disk item pointer to the specified block.
*/
-#define ItemPointerSetBlockNumber(pointer, blockNumber) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), blockNumber) \
-)
+static inline void
+ItemPointerSetBlockNumber(ItemPointerData *pointer, BlockNumber blockNumber)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, blockNumber);
+}
/*
* ItemPointerSetOffsetNumber
* Sets a disk item pointer to the specified offset.
*/
-#define ItemPointerSetOffsetNumber(pointer, offsetNumber) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- (pointer)->ip_posid = (offsetNumber) \
-)
+static inline void
+ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
+{
+ Assert(PointerIsValid(pointer));
+ pointer->ip_posid = offsetNumber;
+}
/*
* ItemPointerCopy
@@ -158,42 +168,49 @@ typedef ItemPointerData *ItemPointer;
* Should there ever be padding in an ItemPointer this would need to be handled
* differently as it's used as hash key.
*/
-#define ItemPointerCopy(fromPointer, toPointer) \
-( \
- AssertMacro(PointerIsValid(toPointer)), \
- AssertMacro(PointerIsValid(fromPointer)), \
- *(toPointer) = *(fromPointer) \
-)
+static inline void
+ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
+{
+ Assert(PointerIsValid(toPointer));
+ Assert(PointerIsValid(fromPointer));
+ *toPointer = *fromPointer;
+}
/*
* ItemPointerSetInvalid
* Sets a disk item pointer to be invalid.
*/
-#define ItemPointerSetInvalid(pointer) \
-( \
- AssertMacro(PointerIsValid(pointer)), \
- BlockIdSet(&((pointer)->ip_blkid), InvalidBlockNumber), \
- (pointer)->ip_posid = InvalidOffsetNumber \
-)
+static inline void
+ItemPointerSetInvalid(ItemPointerData *pointer)
+{
+ Assert(PointerIsValid(pointer));
+ BlockIdSet(&pointer->ip_blkid, InvalidBlockNumber);
+ pointer->ip_posid = InvalidOffsetNumber;
+}
/*
* ItemPointerIndicatesMovedPartitions
* True iff the block number indicates the tuple has moved to another
* partition.
*/
-#define ItemPointerIndicatesMovedPartitions(pointer) \
-( \
- ItemPointerGetOffsetNumber(pointer) == MovedPartitionsOffsetNumber && \
- ItemPointerGetBlockNumberNoCheck(pointer) == MovedPartitionsBlockNumber \
-)
+static inline bool
+ItemPointerIndicatesMovedPartitions(const ItemPointerData *pointer)
+{
+ return
+ ItemPointerGetOffsetNumber(pointer) == MovedPartitionsOffsetNumber &&
+ ItemPointerGetBlockNumberNoCheck(pointer) == MovedPartitionsBlockNumber;
+}
/*
* ItemPointerSetMovedPartitions
* Indicate that the item referenced by the itempointer has moved into a
* different partition.
*/
-#define ItemPointerSetMovedPartitions(pointer) \
- ItemPointerSet((pointer), MovedPartitionsBlockNumber, MovedPartitionsOffsetNumber)
+static inline void
+ItemPointerSetMovedPartitions(ItemPointerData *pointer)
+{
+ ItemPointerSet(pointer, MovedPartitionsBlockNumber, MovedPartitionsOffsetNumber);
+}
/* ----------------
* externs
--
2.36.1
v2-0004-Convert-macros-to-static-inline-functions-bufmgr..patchtext/plain; charset=UTF-8; name=v2-0004-Convert-macros-to-static-inline-functions-bufmgr..patchDownload
From 9dd948206d3f8bd3c1b19c00af7e73c8070dae52 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (bufmgr.h)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/storage/bufmgr.h | 50 +++++++++++++++++++++---------------
1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 58391406f6..ce725afa5e 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -98,7 +98,7 @@ extern PGDLLIMPORT int32 *LocalRefCount;
#define BUFFER_LOCK_EXCLUSIVE 2
/*
- * These routines are beaten on quite heavily, hence the macroization.
+ * These routines are beaten on quite heavily, hence inline.
*/
/*
@@ -120,11 +120,14 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* even in non-assert-enabled builds can be significant. Thus, we've
* now demoted the range checks to assertions within the macro itself.
*/
-#define BufferIsValid(bufnum) \
-( \
- AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \
- (bufnum) != InvalidBuffer \
-)
+static inline bool
+BufferIsValid(Buffer bufnum)
+{
+ Assert(bufnum <= NBuffers);
+ Assert(bufnum >= -NLocBuffer);
+
+ return bufnum != InvalidBuffer;
+}
/*
* BufferGetBlock
@@ -133,14 +136,16 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* Note:
* Assumes buffer is valid.
*/
-#define BufferGetBlock(buffer) \
-( \
- AssertMacro(BufferIsValid(buffer)), \
- BufferIsLocal(buffer) ? \
- LocalBufferBlockPointers[-(buffer) - 1] \
- : \
- (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \
-)
+static inline Block
+BufferGetBlock(Buffer buffer)
+{
+ Assert(BufferIsValid(buffer));
+
+ if (BufferIsLocal(buffer))
+ return LocalBufferBlockPointers[-buffer - 1];
+ else
+ return (Block) (BufferBlocks + ((Size) (buffer - 1)) * BLCKSZ);
+}
/*
* BufferGetPageSize
@@ -153,11 +158,12 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* (formatted) disk page.
*/
/* XXX should dig out of buffer descriptor */
-#define BufferGetPageSize(buffer) \
-( \
- AssertMacro(BufferIsValid(buffer)), \
- (Size)BLCKSZ \
-)
+static inline Size
+BufferGetPageSize(Buffer buffer)
+{
+ AssertMacro(BufferIsValid(buffer));
+ return (Size) BLCKSZ;
+}
/*
* BufferGetPage
@@ -166,7 +172,11 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* When this is called as part of a scan, there may be a need for a nearby
* call to TestForOldSnapshot(). See the definition of that for details.
*/
-#define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer))
+static inline Page
+BufferGetPage(Buffer buffer)
+{
+ return (Page) BufferGetBlock(buffer);
+}
/*
* prototypes for functions in bufmgr.c
--
2.36.1
v2-0005-Convert-macros-to-static-inline-functions-xlog_in.patchtext/plain; charset=UTF-8; name=v2-0005-Convert-macros-to-static-inline-functions-xlog_in.patchDownload
From 02caccee2c51237157bb0ced29e714eb422fb489 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions
(xlog_internal.h)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/access/xlog_internal.h | 155 ++++++++++++++++++-----------
1 file changed, 97 insertions(+), 58 deletions(-)
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index fae0bef8f5..51c91cb279 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -159,74 +159,113 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define XLOG_FNAME_LEN 24
/*
- * Generate a WAL segment file name. Do not use this macro in a helper
+ * Generate a WAL segment file name. Do not use this function in a helper
* function allocating the result generated.
*/
-#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
+static inline void
+XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
+}
-#define XLogFileNameById(fname, tli, log, seg) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg)
+// FIXME: This is only used by pg_archivecleanup and could be gotten rid of.
+static inline void
+XLogFileNameById(char *fname, TimeLineID tli, uint32 log, uint32 seg)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg);
+}
-#define IsXLogFileName(fname) \
- (strlen(fname) == XLOG_FNAME_LEN && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN)
+static inline bool
+IsXLogFileName(const char *fname)
+{
+ return (strlen(fname) == XLOG_FNAME_LEN && \
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN);
+}
/*
* XLOG segment with .partial suffix. Used by pg_receivewal and at end of
* archive recovery, when we want to archive a WAL segment but it might not
* be complete yet.
*/
-#define IsPartialXLogFileName(fname) \
- (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
- strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0)
-
-#define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes) \
- do { \
- uint32 log; \
- uint32 seg; \
- sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \
- *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; \
- } while (0)
-
-#define XLogFilePath(path, tli, logSegNo, wal_segsz_bytes) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
-
-#define TLHistoryFileName(fname, tli) \
- snprintf(fname, MAXFNAMELEN, "%08X.history", tli)
-
-#define IsTLHistoryFileName(fname) \
- (strlen(fname) == 8 + strlen(".history") && \
- strspn(fname, "0123456789ABCDEF") == 8 && \
- strcmp((fname) + 8, ".history") == 0)
-
-#define TLHistoryFilePath(path, tli) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli)
-
-#define StatusFilePath(path, xlog, suffix) \
- snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix)
-
-#define BackupHistoryFileName(fname, tli, logSegNo, startpoint, wal_segsz_bytes) \
- snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)))
-
-#define IsBackupHistoryFileName(fname) \
- (strlen(fname) > XLOG_FNAME_LEN && \
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
- strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0)
-
-#define BackupHistoryFilePath(path, tli, logSegNo, startpoint, wal_segsz_bytes) \
- snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \
- (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
- (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)))
+static inline bool
+IsPartialXLogFileName(const char *fname)
+{
+ return (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") &&
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
+ strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0);
+}
+
+static inline void
+XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
+{
+ uint32 log;
+ uint32 seg;
+
+ sscanf(fname, "%08X%08X%08X", tli, &log, &seg);
+ *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg;
+}
+
+static inline void
+XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
+}
+
+static inline void
+TLHistoryFileName(char *fname, TimeLineID tli)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X.history", tli);
+}
+
+static inline bool
+IsTLHistoryFileName(const char *fname)
+{
+ return (strlen(fname) == 8 + strlen(".history") &&
+ strspn(fname, "0123456789ABCDEF") == 8 &&
+ strcmp((fname) + 8, ".history") == 0);
+}
+
+static inline void
+TLHistoryFilePath(char *path, TimeLineID tli)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli);
+}
+
+static inline void
+StatusFilePath(char *path, const char *xlog, const char *suffix)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix);
+}
+
+static inline void
+BackupHistoryFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
+{
+ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)));
+}
+
+static inline bool
+IsBackupHistoryFileName(const char *fname)
+{
+ return (strlen(fname) > XLOG_FNAME_LEN &&
+ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
+ strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0);
+}
+
+static inline void
+BackupHistoryFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
+{
+ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli,
+ (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
+ (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)));
+}
/*
* Information logged when we detect a change in one of the parameters
--
2.36.1
v2-0006-Convert-macros-to-static-inline-functions-tupmacs.patchtext/plain; charset=UTF-8; name=v2-0006-Convert-macros-to-static-inline-functions-tupmacs.patchDownload
From 41cfab80cb71453ee48bebe914ce3814d8696ec1 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (tupmacs.h)
XXX The renaming in gistutil.c is unnecessary if the subsequent itup.h
patch is also included.
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/backend/access/gist/gistutil.c | 16 +--
src/include/access/itup.h | 2 +-
src/include/access/tupmacs.h | 161 +++++++++++------------------
3 files changed, 70 insertions(+), 109 deletions(-)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index d4bf0c7563..24b2c493e7 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -667,7 +667,7 @@ HeapTuple
gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
{
MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
- Datum fetchatt[INDEX_MAX_KEYS];
+ Datum att[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
int i;
@@ -680,9 +680,9 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
if (giststate->fetchFn[i].fn_oid != InvalidOid)
{
if (!isnull[i])
- fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
+ att[i] = gistFetchAtt(giststate, i, datum, r);
else
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
else if (giststate->compressFn[i].fn_oid == InvalidOid)
{
@@ -691,9 +691,9 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
* original value, att is necessarily stored in original form.
*/
if (!isnull[i])
- fetchatt[i] = datum;
+ att[i] = datum;
else
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
else
{
@@ -703,7 +703,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
* in this column, and we can replace it with a NULL.
*/
isnull[i] = true;
- fetchatt[i] = (Datum) 0;
+ att[i] = (Datum) 0;
}
}
@@ -712,12 +712,12 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
*/
for (; i < r->rd_att->natts; i++)
{
- fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
+ att[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
&isnull[i]);
}
MemoryContextSwitchTo(oldcxt);
- return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
+ return heap_form_tuple(giststate->fetchTupdesc, att, isnull);
}
float
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 2c8877e991..6e6aec1043 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -114,7 +114,7 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
) \
: \
( \
- (att_isnull((attnum)-1, (char *)(tup) + sizeof(IndexTupleData))) ? \
+ (att_isnull((attnum)-1, (bits8 *)(tup) + sizeof(IndexTupleData))) ? \
( \
*(isnull) = true, \
(Datum)NULL \
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 16c74a581e..3f6e9d146f 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -14,6 +14,7 @@
#ifndef TUPMACS_H
#define TUPMACS_H
+#include "catalog/pg_attribute.h"
#include "catalog/pg_type_d.h" /* for TYPALIGN macros */
@@ -22,10 +23,14 @@
* Note that a 0 in the null bitmap indicates a null, while 1 indicates
* non-null.
*/
-#define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07))))
+static inline bool
+att_isnull(int ATT, const bits8 *BITS)
+{
+ return !(BITS[ATT >> 3] & (1 << (ATT & 0x07)));
+}
/*
- * Given a Form_pg_attribute and a pointer into a tuple's data area,
+ * Given byval/len parameters and a pointer into a tuple's data area,
* return the correct value or pointer.
*
* We return a Datum value in all cases. If the attribute has "byval" false,
@@ -38,61 +43,40 @@
*
* Note that T must already be properly aligned for this to work correctly.
*/
-#define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen)
+static inline Datum
+fetch_att(const void *T, bool attbyval, int attlen)
+{
+ if (attbyval)
+ {
+ switch (attlen)
+ {
+ case sizeof(char):
+ return CharGetDatum(*((const char *) T));
+ case sizeof(int16):
+ return Int16GetDatum(*((const int16 *) T));
+ case sizeof(int32):
+ return Int32GetDatum(*((const int32 *) T));
+#if SIZEOF_DATUM == 8
+ case sizeof(Datum):
+ return *((const Datum *) T);
+#endif
+ default:
+ elog(ERROR, "unsupported byval length: %d", attlen);
+ return 0;
+ }
+ }
+ else
+ return PointerGetDatum(T);
+}
/*
- * Same, but work from byval/len parameters rather than Form_pg_attribute.
+ * Same, but work from a Form_pg_attribute rather than byval/len parameters.
*/
-#if SIZEOF_DATUM == 8
-
-#define fetch_att(T,attbyval,attlen) \
-( \
- (attbyval) ? \
- ( \
- (attlen) == (int) sizeof(Datum) ? \
- *((Datum *)(T)) \
- : \
- ( \
- (attlen) == (int) sizeof(int32) ? \
- Int32GetDatum(*((int32 *)(T))) \
- : \
- ( \
- (attlen) == (int) sizeof(int16) ? \
- Int16GetDatum(*((int16 *)(T))) \
- : \
- ( \
- AssertMacro((attlen) == 1), \
- CharGetDatum(*((char *)(T))) \
- ) \
- ) \
- ) \
- ) \
- : \
- PointerGetDatum((char *) (T)) \
-)
-#else /* SIZEOF_DATUM != 8 */
-
-#define fetch_att(T,attbyval,attlen) \
-( \
- (attbyval) ? \
- ( \
- (attlen) == (int) sizeof(int32) ? \
- Int32GetDatum(*((int32 *)(T))) \
- : \
- ( \
- (attlen) == (int) sizeof(int16) ? \
- Int16GetDatum(*((int16 *)(T))) \
- : \
- ( \
- AssertMacro((attlen) == 1), \
- CharGetDatum(*((char *)(T))) \
- ) \
- ) \
- ) \
- : \
- PointerGetDatum((char *) (T)) \
-)
-#endif /* SIZEOF_DATUM == 8 */
+static inline Datum
+fetchatt(const FormData_pg_attribute *A, const void *T)
+{
+ return fetch_att(T, A->attbyval, A->attlen);
+}
/*
* att_align_datum aligns the given offset as needed for a datum of alignment
@@ -194,54 +178,31 @@
* store_att_byval is a partial inverse of fetch_att: store a given Datum
* value into a tuple data area at the specified address. However, it only
* handles the byval case, because in typical usage the caller needs to
- * distinguish by-val and by-ref cases anyway, and so a do-it-all macro
+ * distinguish by-val and by-ref cases anyway, and so a do-it-all function
* wouldn't be convenient.
*/
+static inline void
+store_att_byval(void *T, Datum newdatum, int attlen)
+{
+ switch (attlen)
+ {
+ case sizeof(char):
+ *(char *) T = DatumGetChar(newdatum);
+ break;
+ case sizeof(int16):
+ *(int16 *) T = DatumGetInt16(newdatum);
+ break;
+ case sizeof(int32):
+ *(int32 *) T = DatumGetInt32(newdatum);
+ break;
#if SIZEOF_DATUM == 8
-
-#define store_att_byval(T,newdatum,attlen) \
- do { \
- switch (attlen) \
- { \
- case sizeof(char): \
- *(char *) (T) = DatumGetChar(newdatum); \
- break; \
- case sizeof(int16): \
- *(int16 *) (T) = DatumGetInt16(newdatum); \
- break; \
- case sizeof(int32): \
- *(int32 *) (T) = DatumGetInt32(newdatum); \
- break; \
- case sizeof(Datum): \
- *(Datum *) (T) = (newdatum); \
- break; \
- default: \
- elog(ERROR, "unsupported byval length: %d", \
- (int) (attlen)); \
- break; \
- } \
- } while (0)
-#else /* SIZEOF_DATUM != 8 */
-
-#define store_att_byval(T,newdatum,attlen) \
- do { \
- switch (attlen) \
- { \
- case sizeof(char): \
- *(char *) (T) = DatumGetChar(newdatum); \
- break; \
- case sizeof(int16): \
- *(int16 *) (T) = DatumGetInt16(newdatum); \
- break; \
- case sizeof(int32): \
- *(int32 *) (T) = DatumGetInt32(newdatum); \
- break; \
- default: \
- elog(ERROR, "unsupported byval length: %d", \
- (int) (attlen)); \
- break; \
- } \
- } while (0)
-#endif /* SIZEOF_DATUM == 8 */
+ case sizeof(Datum):
+ *(Datum *) T = newdatum;
+ break;
+#endif
+ default:
+ elog(ERROR, "unsupported byval length: %d", attlen);
+ }
+}
#endif
--
2.36.1
v2-0007-Convert-macros-to-static-inline-functions-itup.h.patchtext/plain; charset=UTF-8; name=v2-0007-Convert-macros-to-static-inline-functions-itup.h.patchDownload
From 4e065f7a2097534801f299649fc69993e1b81a6d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (itup.h)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/access/itup.h | 107 +++++++++++++++++++-------------------
1 file changed, 53 insertions(+), 54 deletions(-)
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 6e6aec1043..36e5e87b9c 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -73,21 +73,33 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
#define IndexTupleHasVarwidths(itup) ((((IndexTuple) (itup))->t_info & INDEX_VAR_MASK))
+/* routines in indextuple.c */
+extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull);
+extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
+ TupleDesc tupleDesc);
+extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull);
+extern void index_deform_tuple_internal(TupleDesc tupleDescriptor,
+ Datum *values, bool *isnull,
+ char *tp, bits8 *bp, int hasnulls);
+extern IndexTuple CopyIndexTuple(IndexTuple source);
+extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor,
+ IndexTuple source, int leavenatts);
+
+
/*
* Takes an infomask as argument (primarily because this needs to be usable
* at index_form_tuple time so enough space is allocated).
*/
-#define IndexInfoFindDataOffset(t_info) \
-( \
- (!((t_info) & INDEX_NULL_MASK)) ? \
- ( \
- (Size)MAXALIGN(sizeof(IndexTupleData)) \
- ) \
- : \
- ( \
- (Size)MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData)) \
- ) \
-)
+static inline Size
+IndexInfoFindDataOffset(unsigned short t_info)
+{
+ if (!(t_info & INDEX_NULL_MASK))
+ return MAXALIGN(sizeof(IndexTupleData));
+ else
+ return MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData));
+}
/* ----------------
* index_getattr
@@ -97,34 +109,36 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
*
* ----------------
*/
-#define index_getattr(tup, attnum, tupleDesc, isnull) \
-( \
- AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \
- *(isnull) = false, \
- !IndexTupleHasNulls(tup) ? \
- ( \
- TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff >= 0 ? \
- ( \
- fetchatt(TupleDescAttr((tupleDesc), (attnum)-1), \
- (char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \
- + TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff) \
- ) \
- : \
- nocache_index_getattr((tup), (attnum), (tupleDesc)) \
- ) \
- : \
- ( \
- (att_isnull((attnum)-1, (bits8 *)(tup) + sizeof(IndexTupleData))) ? \
- ( \
- *(isnull) = true, \
- (Datum)NULL \
- ) \
- : \
- ( \
- nocache_index_getattr((tup), (attnum), (tupleDesc)) \
- ) \
- ) \
-)
+static inline Datum
+index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
+{
+ Assert(PointerIsValid(isnull));
+ Assert(attnum > 0);
+
+ *isnull = false;
+
+ if (!IndexTupleHasNulls(tup))
+ {
+ if (TupleDescAttr(tupleDesc, attnum - 1)->attcacheoff >= 0)
+ {
+ return fetchatt(TupleDescAttr(tupleDesc, attnum - 1),
+ (char *) tup + IndexInfoFindDataOffset(tup->t_info)
+ + TupleDescAttr(tupleDesc, attnum-1)->attcacheoff);
+ }
+ else
+ return nocache_index_getattr(tup, attnum, tupleDesc);
+ }
+ else
+ {
+ if (att_isnull(attnum - 1, (bits8 *) tup + sizeof(IndexTupleData)))
+ {
+ *isnull = true;
+ return (Datum) NULL;
+ }
+ else
+ return nocache_index_getattr(tup, attnum, tupleDesc);
+ }
+}
/*
* MaxIndexTuplesPerPage is an upper bound on the number of tuples that can
@@ -146,19 +160,4 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
((int) ((BLCKSZ - SizeOfPageHeaderData) / \
(MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData))))
-
-/* routines in indextuple.c */
-extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
- Datum *values, bool *isnull);
-extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
- TupleDesc tupleDesc);
-extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
- Datum *values, bool *isnull);
-extern void index_deform_tuple_internal(TupleDesc tupleDescriptor,
- Datum *values, bool *isnull,
- char *tp, bits8 *bp, int hasnulls);
-extern IndexTuple CopyIndexTuple(IndexTuple source);
-extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor,
- IndexTuple source, int leavenatts);
-
#endif /* ITUP_H */
--
2.36.1
v2-0008-Convert-macros-to-static-inline-functions-pgstat..patchtext/plain; charset=UTF-8; name=v2-0008-Convert-macros-to-static-inline-functions-pgstat..patchDownload
From c8a2beac1c278cfc0daafffc7f678697970ecd18 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 23 May 2022 07:28:13 +0200
Subject: [PATCH v2] Convert macros to static inline functions (pgstat.h)
Discussion: https://www.postgresql.org/message-id/flat/5b558da8-99fb-0a99-83dd-f72f05388517%40enterprisedb.com
---
src/include/pgstat.h | 227 ++++++++++++++++++++++++-------------------
1 file changed, 125 insertions(+), 102 deletions(-)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index ac28f813b4..e7a122dcdb 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -16,6 +16,7 @@
#include "postmaster/pgarch.h" /* for MAX_XFN_CHARS */
#include "utils/backend_progress.h" /* for backward compatibility */
#include "utils/backend_status.h" /* for backward compatibility */
+#include "utils/rel.h"
#include "utils/relcache.h"
#include "utils/wait_event.h" /* for backward compatibility */
@@ -396,6 +397,62 @@ typedef struct PgStat_WalStats
} PgStat_WalStats;
+/*
+ * Variables in pgstat.c
+ */
+
+/* GUC parameters */
+extern PGDLLIMPORT bool pgstat_track_counts;
+extern PGDLLIMPORT int pgstat_track_functions;
+extern PGDLLIMPORT int pgstat_fetch_consistency;
+
+
+/*
+ * Variables in pgstat_bgwriter.c
+ */
+
+/* updated directly by bgwriter and bufmgr */
+extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats;
+
+
+/*
+ * Variables in pgstat_checkpointer.c
+ */
+
+/*
+ * Checkpointer statistics counters are updated directly by checkpointer and
+ * bufmgr.
+ */
+extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats;
+
+
+/*
+ * Variables in pgstat_database.c
+ */
+
+/* Updated by pgstat_count_buffer_*_time macros */
+extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime;
+extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime;
+
+/*
+ * Updated by pgstat_count_conn_*_time macros, called by
+ * pgstat_report_activity().
+ */
+extern PGDLLIMPORT PgStat_Counter pgStatActiveTime;
+extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime;
+
+/* updated by the traffic cop and in errfinish() */
+extern PGDLLIMPORT SessionEndType pgStatSessionEndCause;
+
+
+/*
+ * Variables in pgstat_wal.c
+ */
+
+/* updated directly by backends and background processes */
+extern PGDLLIMPORT PgStat_WalStats PendingWalStats;
+
+
/*
* Functions in pgstat.c
*/
@@ -465,14 +522,26 @@ extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount);
extern void pgstat_report_checksum_failure(void);
extern void pgstat_report_connect(Oid dboid);
-#define pgstat_count_buffer_read_time(n) \
- (pgStatBlockReadTime += (n))
-#define pgstat_count_buffer_write_time(n) \
- (pgStatBlockWriteTime += (n))
-#define pgstat_count_conn_active_time(n) \
- (pgStatActiveTime += (n))
-#define pgstat_count_conn_txn_idle_time(n) \
- (pgStatTransactionIdleTime += (n))
+static inline void
+pgstat_count_buffer_read_time(PgStat_Counter n)
+{
+ pgStatBlockReadTime += n;
+}
+static inline void
+pgstat_count_buffer_write_time(PgStat_Counter n)
+{
+ pgStatBlockWriteTime += n;
+}
+static inline void
+pgstat_count_conn_active_time(PgStat_Counter n)
+{
+ pgStatActiveTime += n;
+}
+static inline void
+pgstat_count_conn_txn_idle_time(PgStat_Counter n)
+{
+ pgStatTransactionIdleTime += n;
+}
extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
@@ -516,47 +585,57 @@ extern void pgstat_report_analyze(Relation rel,
* pgstat_assoc_relation() to do so. See its comment for why this is done
* separately from pgstat_init_relation().
*/
-#define pgstat_should_count_relation(rel) \
- (likely((rel)->pgstat_info != NULL) ? true : \
- ((rel)->pgstat_enabled ? pgstat_assoc_relation(rel), true : false))
+static inline bool
+pgstat_should_count_relation(Relation rel)
+{
+ return (likely(rel->pgstat_info != NULL) ? true :
+ (rel->pgstat_enabled ? pgstat_assoc_relation(rel), true : false));
+}
/* nontransactional event counts are simple enough to inline */
-#define pgstat_count_heap_scan(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_numscans++; \
- } while (0)
-#define pgstat_count_heap_getnext(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_returned++; \
- } while (0)
-#define pgstat_count_heap_fetch(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_fetched++; \
- } while (0)
-#define pgstat_count_index_scan(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_numscans++; \
- } while (0)
-#define pgstat_count_index_tuples(rel, n) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_tuples_returned += (n); \
- } while (0)
-#define pgstat_count_buffer_read(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_blocks_fetched++; \
- } while (0)
-#define pgstat_count_buffer_hit(rel) \
- do { \
- if (pgstat_should_count_relation(rel)) \
- (rel)->pgstat_info->t_counts.t_blocks_hit++; \
- } while (0)
+static inline void
+pgstat_count_heap_scan(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_numscans++;
+}
+static inline void
+pgstat_count_heap_getnext(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_returned++;
+}
+static inline void
+pgstat_count_heap_fetch(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_fetched++;
+}
+static inline void
+pgstat_count_index_scan(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_numscans++;
+}
+static inline void
+pgstat_count_index_tuples(Relation rel, PgStat_Counter n)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_tuples_returned += n;
+}
+static inline void
+pgstat_count_buffer_read(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_blocks_fetched++;
+}
+static inline void
+pgstat_count_buffer_hit(Relation rel)
+{
+ if (pgstat_should_count_relation(rel))
+ rel->pgstat_info->t_counts.t_blocks_hit++;
+}
extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
extern void pgstat_count_heap_update(Relation rel, bool hot);
@@ -636,60 +715,4 @@ extern void pgstat_report_wal(bool force);
extern PgStat_WalStats *pgstat_fetch_stat_wal(void);
-/*
- * Variables in pgstat.c
- */
-
-/* GUC parameters */
-extern PGDLLIMPORT bool pgstat_track_counts;
-extern PGDLLIMPORT int pgstat_track_functions;
-extern PGDLLIMPORT int pgstat_fetch_consistency;
-
-
-/*
- * Variables in pgstat_bgwriter.c
- */
-
-/* updated directly by bgwriter and bufmgr */
-extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats;
-
-
-/*
- * Variables in pgstat_checkpointer.c
- */
-
-/*
- * Checkpointer statistics counters are updated directly by checkpointer and
- * bufmgr.
- */
-extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats;
-
-
-/*
- * Variables in pgstat_database.c
- */
-
-/* Updated by pgstat_count_buffer_*_time macros */
-extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime;
-extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime;
-
-/*
- * Updated by pgstat_count_conn_*_time macros, called by
- * pgstat_report_activity().
- */
-extern PGDLLIMPORT PgStat_Counter pgStatActiveTime;
-extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime;
-
-/* updated by the traffic cop and in errfinish() */
-extern PGDLLIMPORT SessionEndType pgStatSessionEndCause;
-
-
-/*
- * Variables in pgstat_wal.c
- */
-
-/* updated directly by backends and background processes */
-extern PGDLLIMPORT PgStat_WalStats PendingWalStats;
-
-
#endif /* PGSTAT_H */
--
2.36.1
On Mon, May 16, 2022 at 1:28 AM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:
Inspired by [0], I looked to convert more macros to inline functions.
The attached patches are organized "bottom up" in terms of their API
layering; some of the later ones depend on some of the earlier ones.
Big +1 from me.
I converted over most of the nbtree.h function style macros in
Postgres 13, having put it off in Postgres 12 (there is one remaining
function macro due to an issue with #include dependencies). This
vastly improved the maintainability of the code, and I wish I'd done
it sooner.
Inline functions made it a lot easier to pepper various B-Tree code
utility functions with defensive assertions concerning preconditions
and postconditions. That's something that I am particular about. In
theory you can just use AssertMacro() in a function style macro. In
practice that approach is ugly, and necessitates thinking about
multiple evaluation hazards, which is enough to discourage good
defensive coding practices.
--
Peter Geoghegan
On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
Here is another one from the same batch of work that I somehow didn't
send in last time.
(IMO it's questionable whether this one should be an inline function or
macro at all, rather than a normal external function.)
Attachments:
0001-Convert-macros-to-static-inline-functions-rel.h.patchtext/plain; charset=UTF-8; name=0001-Convert-macros-to-static-inline-functions-rel.h.patchDownload
From 6d1e97d8d03e2a01842dacd3528bf2dbf40377cf Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Tue, 19 Jul 2022 06:58:12 +0200
Subject: [PATCH] Convert macros to static inline functions (rel.h)
---
src/include/utils/rel.h | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 7dc401cf0df9..aee07a6979b1 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -572,22 +572,23 @@ RelationGetSmgr(Relation rel)
smgrsetowner(&(rel->rd_smgr), smgropen(rel->rd_locator, rel->rd_backend));
return rel->rd_smgr;
}
-#endif
/*
* RelationCloseSmgr
* Close the relation at the smgr level, if not already done.
- *
- * Note: smgrclose should unhook from owner pointer, hence the Assert.
*/
-#define RelationCloseSmgr(relation) \
- do { \
- if ((relation)->rd_smgr != NULL) \
- { \
- smgrclose((relation)->rd_smgr); \
- Assert((relation)->rd_smgr == NULL); \
- } \
- } while (0)
+static inline void
+RelationCloseSmgr(Relation relation)
+{
+ if (relation->rd_smgr != NULL)
+ {
+ smgrclose(relation->rd_smgr);
+
+ /* smgrclose should unhook from owner pointer */
+ Assert(relation->rd_smgr == NULL);
+ }
+}
+#endif
/*
* RelationGetTargetBlock
--
2.37.3
On Tue, Oct 4, 2022 at 12:00 PM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:
On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
Here is another one from the same batch of work that I somehow didn't
send in last time.
I think assertion can be placed outside of the IF-block and braces can
be removed.
(IMO it's questionable whether this one should be an inline function or
macro at all, rather than a normal external function.)
IMO, it should be inlined with RelationGetSmgr().
Regards,
Amul
On 04.10.22 08:57, Amul Sul wrote:
On Tue, Oct 4, 2022 at 12:00 PM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
Here is another one from the same batch of work that I somehow didn't
send in last time.I think assertion can be placed outside of the IF-block and braces can
be removed.
Committed that way, thanks.
On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
This is an older thread where I left something unfinished:
Note 2: Many macros in htup_details.h operate both on HeapTupleHeader
and on MinimalTuple, so converting them to a function doesn't work in a
straightforward way. I have some in-progress work in that area, but I
have not included any of that here.
Here is the patch set for this.
There are actually only two macros that operate on both HeapTupleHeader
and MinimalTuple, so it wasn't as much as I had written above. I just
left those as macros. I converted the rest to inline functions in a
straightforward way as before. A small amount of reordering was necessary.
But just for language-nerd fun, I'm including here an additional patch
showing how the remaining ones could be done with C11 generic selection.
I'm not planning to commit that one at this time.
Attachments:
0001-Add-some-const-decorations-htup.h.patchtext/plain; charset=UTF-8; name=0001-Add-some-const-decorations-htup.h.patchDownload
From 422181163bfe1a292ee51941a007d54bc127ccec Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 27 Dec 2024 11:07:35 +0100
Subject: [PATCH 1/3] Add some const decorations (htup.h)
---
src/backend/access/heap/heapam.c | 6 +++---
src/backend/utils/time/combocid.c | 6 +++---
src/include/access/htup.h | 8 ++++----
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 329e727f80d..75171e8f2c0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7419,10 +7419,10 @@ MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
* checking the hint bits.
*/
TransactionId
-HeapTupleGetUpdateXid(HeapTupleHeader tuple)
+HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
{
- return MultiXactIdGetUpdateXid(HeapTupleHeaderGetRawXmax(tuple),
- tuple->t_infomask);
+ return MultiXactIdGetUpdateXid(HeapTupleHeaderGetRawXmax(tup),
+ tup->t_infomask);
}
/*
diff --git a/src/backend/utils/time/combocid.c b/src/backend/utils/time/combocid.c
index f85510b74ff..1ecdc93b7e2 100644
--- a/src/backend/utils/time/combocid.c
+++ b/src/backend/utils/time/combocid.c
@@ -101,7 +101,7 @@ static CommandId GetRealCmax(CommandId combocid);
*/
CommandId
-HeapTupleHeaderGetCmin(HeapTupleHeader tup)
+HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup)
{
CommandId cid = HeapTupleHeaderGetRawCommandId(tup);
@@ -115,7 +115,7 @@ HeapTupleHeaderGetCmin(HeapTupleHeader tup)
}
CommandId
-HeapTupleHeaderGetCmax(HeapTupleHeader tup)
+HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup)
{
CommandId cid = HeapTupleHeaderGetRawCommandId(tup);
@@ -150,7 +150,7 @@ HeapTupleHeaderGetCmax(HeapTupleHeader tup)
* changes the tuple in shared buffers.
*/
void
-HeapTupleHeaderAdjustCmax(HeapTupleHeader tup,
+HeapTupleHeaderAdjustCmax(const HeapTupleHeaderData *tup,
CommandId *cmax,
bool *iscombo)
{
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index 116cb1bb273..a5f1ef2441d 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -78,12 +78,12 @@ typedef HeapTupleData *HeapTuple;
#define HeapTupleIsValid(tuple) PointerIsValid(tuple)
/* HeapTupleHeader functions implemented in utils/time/combocid.c */
-extern CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup);
-extern CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup);
-extern void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup,
+extern CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup);
+extern CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup);
+extern void HeapTupleHeaderAdjustCmax(const HeapTupleHeaderData *tup,
CommandId *cmax, bool *iscombo);
/* Prototype for HeapTupleHeader accessors in heapam.c */
-extern TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple);
+extern TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup);
#endif /* HTUP_H */
base-commit: d85ce012f99f63249bb45a78fcecb7a2383920b1
--
2.47.1
0002-Convert-macros-to-static-inline-functions-htup_detai.patchtext/plain; charset=UTF-8; name=0002-Convert-macros-to-static-inline-functions-htup_detai.patchDownload
From 89308e0446259a1ae619e39603324d2c2b8ed66c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 27 Dec 2024 11:07:35 +0100
Subject: [PATCH 2/3] Convert macros to static inline functions
(htup_details.h, itup.h)
---
contrib/pageinspect/heapfuncs.c | 15 +-
src/include/access/htup_details.h | 543 ++++++++++++++++++------------
src/include/access/itup.h | 20 +-
3 files changed, 352 insertions(+), 226 deletions(-)
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index 41ff597199c..4961a3c866c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -42,13 +42,14 @@
* was used to upgrade from an older version, tuples might still have an
* oid. Seems worthwhile to display that.
*/
-#define HeapTupleHeaderGetOidOld(tup) \
-( \
- ((tup)->t_infomask & HEAP_HASOID_OLD) ? \
- *((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) \
- : \
- InvalidOid \
-)
+static inline Oid
+HeapTupleHeaderGetOidOld(const HeapTupleHeaderData *tup)
+{
+ if (tup->t_infomask & HEAP_HASOID_OLD)
+ return *((Oid *) ((char *) (tup) + (tup)->t_hoff - sizeof(Oid)));
+ else
+ return InvalidOid;
+}
/*
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 0d1adff540f..bab480fe2f0 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -225,12 +225,13 @@ struct HeapTupleHeaderData
*
* See also HeapTupleHeaderIsOnlyLocked, which also checks for a possible
* aborted updater transaction.
- *
- * Beware of multiple evaluations of the argument.
*/
-#define HEAP_XMAX_IS_LOCKED_ONLY(infomask) \
- (((infomask) & HEAP_XMAX_LOCK_ONLY) || \
- (((infomask) & (HEAP_XMAX_IS_MULTI | HEAP_LOCK_MASK)) == HEAP_XMAX_EXCL_LOCK))
+static inline bool
+HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
+{
+ return (infomask & HEAP_XMAX_LOCK_ONLY) ||
+ (infomask & (HEAP_XMAX_IS_MULTI | HEAP_LOCK_MASK)) == HEAP_XMAX_EXCL_LOCK;
+}
/*
* A tuple that has HEAP_XMAX_IS_MULTI and HEAP_XMAX_LOCK_ONLY but neither of
@@ -250,22 +251,35 @@ struct HeapTupleHeaderData
* bogus, regardless of where they stand with respect to the current valid
* multixact range.
*/
-#define HEAP_LOCKED_UPGRADED(infomask) \
-( \
- ((infomask) & HEAP_XMAX_IS_MULTI) != 0 && \
- ((infomask) & HEAP_XMAX_LOCK_ONLY) != 0 && \
- (((infomask) & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) == 0) \
-)
+static inline bool
+HEAP_LOCKED_UPGRADED(uint16 infomask)
+{
+ return
+ (infomask & HEAP_XMAX_IS_MULTI) != 0 &&
+ (infomask & HEAP_XMAX_LOCK_ONLY) != 0 &&
+ (infomask & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) == 0;
+}
/*
* Use these to test whether a particular lock is applied to a tuple
*/
-#define HEAP_XMAX_IS_SHR_LOCKED(infomask) \
- (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_SHR_LOCK)
-#define HEAP_XMAX_IS_EXCL_LOCKED(infomask) \
- (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_EXCL_LOCK)
-#define HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) \
- (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_KEYSHR_LOCK)
+static inline bool
+HEAP_XMAX_IS_SHR_LOCKED(int16 infomask)
+{
+ return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_SHR_LOCK;
+}
+
+static inline bool
+HEAP_XMAX_IS_EXCL_LOCKED(int16 infomask)
+{
+ return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_EXCL_LOCK;
+}
+
+static inline bool
+HEAP_XMAX_IS_KEYSHR_LOCKED(int16 infomask)
+{
+ return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_KEYSHR_LOCK;
+}
/* turn these all off when Xmax is to change */
#define HEAP_XMAX_BITS (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID | \
@@ -292,12 +306,11 @@ struct HeapTupleHeaderData
#define HEAP_TUPLE_HAS_MATCH HEAP_ONLY_TUPLE /* tuple has a join match */
/*
- * HeapTupleHeader accessor macros
- *
- * Note: beware of multiple evaluations of "tup" argument. But the Set
- * macros evaluate their other argument only once.
+ * HeapTupleHeader accessor functions
*/
+static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup);
+
/*
* HeapTupleHeaderGetRawXmin returns the "raw" xmin field, which is the xid
* originally used to insert the tuple. However, the tuple might actually
@@ -306,56 +319,78 @@ struct HeapTupleHeaderData
* the xmin to FrozenTransactionId, and that value may still be encountered
* on disk.
*/
-#define HeapTupleHeaderGetRawXmin(tup) \
-( \
- (tup)->t_choice.t_heap.t_xmin \
-)
+static inline TransactionId
+HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
+{
+ return tup->t_choice.t_heap.t_xmin;
+}
-#define HeapTupleHeaderGetXmin(tup) \
-( \
- HeapTupleHeaderXminFrozen(tup) ? \
- FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup) \
-)
+static inline TransactionId
+HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
+{
+ return HeapTupleHeaderXminFrozen(tup) ?
+ FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup);
+}
-#define HeapTupleHeaderSetXmin(tup, xid) \
-( \
- (tup)->t_choice.t_heap.t_xmin = (xid) \
-)
+static inline void
+HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
+{
+ tup->t_choice.t_heap.t_xmin = xid;
+}
-#define HeapTupleHeaderXminCommitted(tup) \
-( \
- ((tup)->t_infomask & HEAP_XMIN_COMMITTED) != 0 \
-)
+static inline bool
+HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
+{
+ return (tup->t_infomask & HEAP_XMIN_COMMITTED) != 0;
+}
-#define HeapTupleHeaderXminInvalid(tup) \
-( \
- ((tup)->t_infomask & (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)) == \
- HEAP_XMIN_INVALID \
-)
+static inline bool
+HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup) \
+{
+ return (tup->t_infomask & (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)) ==
+ HEAP_XMIN_INVALID;
+}
-#define HeapTupleHeaderXminFrozen(tup) \
-( \
- ((tup)->t_infomask & (HEAP_XMIN_FROZEN)) == HEAP_XMIN_FROZEN \
-)
+static inline bool
+HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
+{
+ return (tup->t_infomask & HEAP_XMIN_FROZEN) == HEAP_XMIN_FROZEN;
+}
-#define HeapTupleHeaderSetXminCommitted(tup) \
-( \
- AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \
- ((tup)->t_infomask |= HEAP_XMIN_COMMITTED) \
-)
+static inline void
+HeapTupleHeaderSetXminCommitted(HeapTupleHeaderData *tup)
+{
+ Assert(!HeapTupleHeaderXminInvalid(tup));
+ tup->t_infomask |= HEAP_XMIN_COMMITTED;
+}
-#define HeapTupleHeaderSetXminInvalid(tup) \
-( \
- AssertMacro(!HeapTupleHeaderXminCommitted(tup)), \
- ((tup)->t_infomask |= HEAP_XMIN_INVALID) \
-)
+static inline void
+HeapTupleHeaderSetXminInvalid(HeapTupleHeaderData *tup)
+{
+ Assert(!HeapTupleHeaderXminCommitted(tup));
+ tup->t_infomask |= HEAP_XMIN_INVALID;
+}
-#define HeapTupleHeaderSetXminFrozen(tup) \
-( \
- AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \
- ((tup)->t_infomask |= HEAP_XMIN_FROZEN) \
-)
+static inline void
+HeapTupleHeaderSetXminFrozen(HeapTupleHeaderData *tup)
+{
+ Assert(!HeapTupleHeaderXminInvalid(tup));
+ tup->t_infomask |= HEAP_XMIN_FROZEN;
+}
+static inline TransactionId
+HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
+{
+ return tup->t_choice.t_heap.t_xmax;
+}
+
+static inline void
+HeapTupleHeaderSetXmax(HeapTupleHeaderData *tup, TransactionId xid)
+{
+ tup->t_choice.t_heap.t_xmax = xid;
+}
+
+#ifndef FRONTEND
/*
* HeapTupleHeaderGetRawXmax gets you the raw Xmax field. To find out the Xid
* that updated a tuple, you might need to resolve the MultiXactId if certain
@@ -363,25 +398,17 @@ struct HeapTupleHeaderData
* to resolve the MultiXactId if necessary. This might involve multixact I/O,
* so it should only be used if absolutely necessary.
*/
-#define HeapTupleHeaderGetUpdateXid(tup) \
-( \
- (!((tup)->t_infomask & HEAP_XMAX_INVALID) && \
- ((tup)->t_infomask & HEAP_XMAX_IS_MULTI) && \
- !((tup)->t_infomask & HEAP_XMAX_LOCK_ONLY)) ? \
- HeapTupleGetUpdateXid(tup) \
- : \
- HeapTupleHeaderGetRawXmax(tup) \
-)
-
-#define HeapTupleHeaderGetRawXmax(tup) \
-( \
- (tup)->t_choice.t_heap.t_xmax \
-)
-
-#define HeapTupleHeaderSetXmax(tup, xid) \
-( \
- (tup)->t_choice.t_heap.t_xmax = (xid) \
-)
+static inline TransactionId
+HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
+{
+ if (!((tup)->t_infomask & HEAP_XMAX_INVALID) &&
+ ((tup)->t_infomask & HEAP_XMAX_IS_MULTI) &&
+ !((tup)->t_infomask & HEAP_XMAX_LOCK_ONLY))
+ return HeapTupleGetUpdateXid(tup);
+ else
+ return HeapTupleHeaderGetRawXmax(tup);
+}
+#endif /* FRONTEND */
/*
* HeapTupleHeaderGetRawCommandId will give you what's in the header whether
@@ -389,147 +416,168 @@ struct HeapTupleHeaderData
* HeapTupleHeaderGetCmax instead, but note that those Assert that you can
* get a legitimate result, ie you are in the originating transaction!
*/
-#define HeapTupleHeaderGetRawCommandId(tup) \
-( \
- (tup)->t_choice.t_heap.t_field3.t_cid \
-)
+static inline CommandId
+HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
+{
+ return tup->t_choice.t_heap.t_field3.t_cid;
+}
/* SetCmin is reasonably simple since we never need a combo CID */
-#define HeapTupleHeaderSetCmin(tup, cid) \
-do { \
- Assert(!((tup)->t_infomask & HEAP_MOVED)); \
- (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \
- (tup)->t_infomask &= ~HEAP_COMBOCID; \
-} while (0)
+static inline void
+HeapTupleHeaderSetCmin(HeapTupleHeaderData *tup, CommandId cid)
+{
+ Assert(!(tup->t_infomask & HEAP_MOVED));
+ tup->t_choice.t_heap.t_field3.t_cid = cid;
+ tup->t_infomask &= ~HEAP_COMBOCID;
+}
/* SetCmax must be used after HeapTupleHeaderAdjustCmax; see combocid.c */
-#define HeapTupleHeaderSetCmax(tup, cid, iscombo) \
-do { \
- Assert(!((tup)->t_infomask & HEAP_MOVED)); \
- (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \
- if (iscombo) \
- (tup)->t_infomask |= HEAP_COMBOCID; \
- else \
- (tup)->t_infomask &= ~HEAP_COMBOCID; \
-} while (0)
-
-#define HeapTupleHeaderGetXvac(tup) \
-( \
- ((tup)->t_infomask & HEAP_MOVED) ? \
- (tup)->t_choice.t_heap.t_field3.t_xvac \
- : \
- InvalidTransactionId \
-)
+static inline void
+HeapTupleHeaderSetCmax(HeapTupleHeaderData *tup, CommandId cid, bool iscombo)
+{
+ Assert(!((tup)->t_infomask & HEAP_MOVED));
+ tup->t_choice.t_heap.t_field3.t_cid = cid;
+ if (iscombo)
+ tup->t_infomask |= HEAP_COMBOCID;
+ else
+ tup->t_infomask &= ~HEAP_COMBOCID;
+}
+
+static inline TransactionId
+HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
+{
+ if (tup->t_infomask & HEAP_MOVED)
+ return tup->t_choice.t_heap.t_field3.t_xvac;
+ else
+ return InvalidTransactionId;
+}
-#define HeapTupleHeaderSetXvac(tup, xid) \
-do { \
- Assert((tup)->t_infomask & HEAP_MOVED); \
- (tup)->t_choice.t_heap.t_field3.t_xvac = (xid); \
-} while (0)
+static inline void
+HeapTupleHeaderSetXvac(HeapTupleHeaderData *tup, TransactionId xid)
+{
+ Assert(tup->t_infomask & HEAP_MOVED);
+ tup->t_choice.t_heap.t_field3.t_xvac = xid;
+}
StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
"invalid speculative token constant");
-#define HeapTupleHeaderIsSpeculative(tup) \
-( \
- (ItemPointerGetOffsetNumberNoCheck(&(tup)->t_ctid) == SpecTokenOffsetNumber) \
-)
+static inline bool
+HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
+{
+ return ItemPointerGetOffsetNumberNoCheck(&tup->t_ctid) == SpecTokenOffsetNumber;
+}
-#define HeapTupleHeaderGetSpeculativeToken(tup) \
-( \
- AssertMacro(HeapTupleHeaderIsSpeculative(tup)), \
- ItemPointerGetBlockNumber(&(tup)->t_ctid) \
-)
+static inline BlockNumber
+HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
+{
+ Assert(HeapTupleHeaderIsSpeculative(tup));
+ return ItemPointerGetBlockNumber(&tup->t_ctid);
+}
-#define HeapTupleHeaderSetSpeculativeToken(tup, token) \
-( \
- ItemPointerSet(&(tup)->t_ctid, token, SpecTokenOffsetNumber) \
-)
+static inline void
+HeapTupleHeaderSetSpeculativeToken(HeapTupleHeaderData *tup, BlockNumber token)
+{
+ ItemPointerSet(&tup->t_ctid, token, SpecTokenOffsetNumber);
+}
-#define HeapTupleHeaderIndicatesMovedPartitions(tup) \
- ItemPointerIndicatesMovedPartitions(&(tup)->t_ctid)
+static inline bool
+HeapTupleHeaderIndicatesMovedPartitions(const HeapTupleHeaderData *tup)
+{
+ return ItemPointerIndicatesMovedPartitions(&tup->t_ctid);
+}
-#define HeapTupleHeaderSetMovedPartitions(tup) \
- ItemPointerSetMovedPartitions(&(tup)->t_ctid)
+static inline void
+HeapTupleHeaderSetMovedPartitions(HeapTupleHeaderData *tup)
+{
+ ItemPointerSetMovedPartitions(&tup->t_ctid);
+}
-#define HeapTupleHeaderGetDatumLength(tup) \
- VARSIZE(tup)
+static inline uint32
+HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
+{
+ return VARSIZE(tup);
+}
-#define HeapTupleHeaderSetDatumLength(tup, len) \
- SET_VARSIZE(tup, len)
+static inline void
+HeapTupleHeaderSetDatumLength(HeapTupleHeaderData *tup, uint32 len)
+{
+ SET_VARSIZE(tup, len);
+}
-#define HeapTupleHeaderGetTypeId(tup) \
-( \
- (tup)->t_choice.t_datum.datum_typeid \
-)
+static inline Oid
+HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
+{
+ return tup->t_choice.t_datum.datum_typeid;
+}
-#define HeapTupleHeaderSetTypeId(tup, typeid) \
-( \
- (tup)->t_choice.t_datum.datum_typeid = (typeid) \
-)
+static inline void
+HeapTupleHeaderSetTypeId(HeapTupleHeaderData *tup, Oid typeid)
+{
+ tup->t_choice.t_datum.datum_typeid = typeid;
+}
-#define HeapTupleHeaderGetTypMod(tup) \
-( \
- (tup)->t_choice.t_datum.datum_typmod \
-)
+static inline int32
+HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
+{
+ return tup->t_choice.t_datum.datum_typmod;
+}
-#define HeapTupleHeaderSetTypMod(tup, typmod) \
-( \
- (tup)->t_choice.t_datum.datum_typmod = (typmod) \
-)
+static inline void
+HeapTupleHeaderSetTypMod(HeapTupleHeaderData *tup, int32 typmod)
+{
+ tup->t_choice.t_datum.datum_typmod = typmod;
+}
/*
* Note that we stop considering a tuple HOT-updated as soon as it is known
* aborted or the would-be updating transaction is known aborted. For best
- * efficiency, check tuple visibility before using this macro, so that the
+ * efficiency, check tuple visibility before using this function, so that the
* INVALID bits will be as up to date as possible.
*/
-#define HeapTupleHeaderIsHotUpdated(tup) \
-( \
- ((tup)->t_infomask2 & HEAP_HOT_UPDATED) != 0 && \
- ((tup)->t_infomask & HEAP_XMAX_INVALID) == 0 && \
- !HeapTupleHeaderXminInvalid(tup) \
-)
-
-#define HeapTupleHeaderSetHotUpdated(tup) \
-( \
- (tup)->t_infomask2 |= HEAP_HOT_UPDATED \
-)
-
-#define HeapTupleHeaderClearHotUpdated(tup) \
-( \
- (tup)->t_infomask2 &= ~HEAP_HOT_UPDATED \
-)
+static inline bool
+HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
+{
+ return
+ (tup->t_infomask2 & HEAP_HOT_UPDATED) != 0 &&
+ (tup->t_infomask & HEAP_XMAX_INVALID) == 0 &&
+ !HeapTupleHeaderXminInvalid(tup);
+}
-#define HeapTupleHeaderIsHeapOnly(tup) \
-( \
- ((tup)->t_infomask2 & HEAP_ONLY_TUPLE) != 0 \
-)
+static inline void
+HeapTupleHeaderSetHotUpdated(HeapTupleHeaderData *tup)
+{
+ tup->t_infomask2 |= HEAP_HOT_UPDATED;
+}
-#define HeapTupleHeaderSetHeapOnly(tup) \
-( \
- (tup)->t_infomask2 |= HEAP_ONLY_TUPLE \
-)
+static inline void
+HeapTupleHeaderClearHotUpdated(HeapTupleHeaderData *tup)
+{
+ tup->t_infomask2 &= ~HEAP_HOT_UPDATED;
+}
-#define HeapTupleHeaderClearHeapOnly(tup) \
-( \
- (tup)->t_infomask2 &= ~HEAP_ONLY_TUPLE \
-)
+static inline bool
+HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup) \
+{
+ return (tup->t_infomask2 & HEAP_ONLY_TUPLE) != 0;
+}
-#define HeapTupleHeaderHasMatch(tup) \
-( \
- ((tup)->t_infomask2 & HEAP_TUPLE_HAS_MATCH) != 0 \
-)
+static inline void
+HeapTupleHeaderSetHeapOnly(HeapTupleHeaderData *tup)
+{
+ tup->t_infomask2 |= HEAP_ONLY_TUPLE;
+}
-#define HeapTupleHeaderSetMatch(tup) \
-( \
- (tup)->t_infomask2 |= HEAP_TUPLE_HAS_MATCH \
-)
+static inline void
+HeapTupleHeaderClearHeapOnly(HeapTupleHeaderData *tup)
+{
+ tup->t_infomask2 &= ~HEAP_ONLY_TUPLE;
+}
-#define HeapTupleHeaderClearMatch(tup) \
-( \
- (tup)->t_infomask2 &= ~HEAP_TUPLE_HAS_MATCH \
-)
+/*
+ * These are used with both HeapTuple and MinimalTuple, so they must be
+ * macros.
+ */
#define HeapTupleHeaderGetNatts(tup) \
((tup)->t_infomask2 & HEAP_NATTS_MASK)
@@ -547,7 +595,11 @@ StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
* BITMAPLEN(NATTS) -
* Computes size of null bitmap given number of data columns.
*/
-#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
+static inline int
+BITMAPLEN(int NATTS)
+{
+ return (NATTS + 7) / 8;
+}
/*
* MaxHeapTupleSize is the maximum allowed size of a heap tuple, including
@@ -651,48 +703,107 @@ struct MinimalTupleData
#define SizeofMinimalTupleHeader offsetof(MinimalTupleData, t_bits)
+/*
+ * MinimalTuple accessor functions
+ */
+
+static inline bool
+HeapTupleHeaderHasMatch(const MinimalTupleData *tup)
+{
+ return (tup->t_infomask2 & HEAP_TUPLE_HAS_MATCH) != 0;
+}
+
+static inline void
+HeapTupleHeaderSetMatch(MinimalTupleData *tup)
+{
+ tup->t_infomask2 |= HEAP_TUPLE_HAS_MATCH;
+}
+
+static inline void
+HeapTupleHeaderClearMatch(MinimalTupleData *tup)
+{
+ tup->t_infomask2 &= ~HEAP_TUPLE_HAS_MATCH;
+}
+
/*
* GETSTRUCT - given a HeapTuple pointer, return address of the user data
*/
-#define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff)
+static inline void *
+GETSTRUCT(const HeapTupleData *tuple)
+{
+ return ((char *) (tuple->t_data) + tuple->t_data->t_hoff);
+}
/*
- * Accessor macros to be used with HeapTuple pointers.
+ * Accessor functions to be used with HeapTuple pointers.
*/
-#define HeapTupleHasNulls(tuple) \
- (((tuple)->t_data->t_infomask & HEAP_HASNULL) != 0)
+static inline bool
+HeapTupleHasNulls(const HeapTupleData *tuple)
+{
+ return (tuple->t_data->t_infomask & HEAP_HASNULL) != 0;
+}
-#define HeapTupleNoNulls(tuple) \
- (!((tuple)->t_data->t_infomask & HEAP_HASNULL))
+static inline bool
+HeapTupleNoNulls(const HeapTupleData *tuple)
+{
+ return !HeapTupleHasNulls(tuple);
+}
-#define HeapTupleHasVarWidth(tuple) \
- (((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH) != 0)
+static inline bool
+HeapTupleHasVarWidth(const HeapTupleData *tuple)
+{
+ return (tuple->t_data->t_infomask & HEAP_HASVARWIDTH) != 0;
+}
-#define HeapTupleAllFixed(tuple) \
- (!((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH))
+static inline bool
+HeapTupleAllFixed(const HeapTupleData *tuple)
+{
+ return !HeapTupleHasVarWidth(tuple);
+}
-#define HeapTupleHasExternal(tuple) \
- (((tuple)->t_data->t_infomask & HEAP_HASEXTERNAL) != 0)
+static inline bool
+HeapTupleHasExternal(const HeapTupleData *tuple)
+{
+ return (tuple->t_data->t_infomask & HEAP_HASEXTERNAL) != 0;
+}
-#define HeapTupleIsHotUpdated(tuple) \
- HeapTupleHeaderIsHotUpdated((tuple)->t_data)
+static inline bool
+HeapTupleIsHotUpdated(const HeapTupleData *tuple)
+{
+ return HeapTupleHeaderIsHotUpdated(tuple->t_data);
+}
-#define HeapTupleSetHotUpdated(tuple) \
- HeapTupleHeaderSetHotUpdated((tuple)->t_data)
+static inline void
+HeapTupleSetHotUpdated(const HeapTupleData *tuple)
+{
+ HeapTupleHeaderSetHotUpdated(tuple->t_data);
+}
-#define HeapTupleClearHotUpdated(tuple) \
- HeapTupleHeaderClearHotUpdated((tuple)->t_data)
+static inline void
+HeapTupleClearHotUpdated(const HeapTupleData *tuple)
+{
+ HeapTupleHeaderClearHotUpdated(tuple->t_data);
+}
-#define HeapTupleIsHeapOnly(tuple) \
- HeapTupleHeaderIsHeapOnly((tuple)->t_data)
+static inline bool
+HeapTupleIsHeapOnly(const HeapTupleData *tuple)
+{
+ return HeapTupleHeaderIsHeapOnly(tuple->t_data);
+}
-#define HeapTupleSetHeapOnly(tuple) \
- HeapTupleHeaderSetHeapOnly((tuple)->t_data)
+static inline void
+HeapTupleSetHeapOnly(const HeapTupleData *tuple)
+{
+ HeapTupleHeaderSetHeapOnly(tuple->t_data);
+}
-#define HeapTupleClearHeapOnly(tuple) \
- HeapTupleHeaderClearHeapOnly((tuple)->t_data)
+static inline void
+HeapTupleClearHeapOnly(const HeapTupleData *tuple)
+{
+ HeapTupleHeaderClearHeapOnly(tuple->t_data);
+}
/* prototypes for functions in common/heaptuple.c */
extern Size heap_compute_data_size(TupleDesc tupleDesc,
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 4393b19a7fd..bce0e8aa8be 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -68,9 +68,23 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
#define INDEX_VAR_MASK 0x4000
#define INDEX_NULL_MASK 0x8000
-#define IndexTupleSize(itup) ((Size) ((itup)->t_info & INDEX_SIZE_MASK))
-#define IndexTupleHasNulls(itup) ((((IndexTuple) (itup))->t_info & INDEX_NULL_MASK))
-#define IndexTupleHasVarwidths(itup) ((((IndexTuple) (itup))->t_info & INDEX_VAR_MASK))
+static inline Size
+IndexTupleSize(const IndexTupleData *itup)
+{
+ return (itup->t_info & INDEX_SIZE_MASK);
+}
+
+static inline bool
+IndexTupleHasNulls(const IndexTupleData *itup)
+{
+ return itup->t_info & INDEX_NULL_MASK;
+}
+
+static inline bool
+IndexTupleHasVarwidths(const IndexTupleData *itup)
+{
+ return itup->t_info & INDEX_VAR_MASK;
+}
/* routines in indextuple.c */
--
2.47.1
0003-WIP-Use-some-generic-selection.patchtext/plain; charset=UTF-8; name=0003-WIP-Use-some-generic-selection.patchDownload
From b8f2c2f144c1763029ba8b84093a1885f57627a1 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 27 Dec 2024 11:07:35 +0100
Subject: [PATCH 3/3] WIP: Use some generic selection
Use generic selection (C11 _Generic) to allow a few functions in
htup_details.h to work with both HeapTuple and MinimalTuple.
---
src/include/access/htup_details.h | 50 +++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index bab480fe2f0..cb862ff089d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -574,21 +574,23 @@ HeapTupleHeaderClearHeapOnly(HeapTupleHeaderData *tup)
tup->t_infomask2 &= ~HEAP_ONLY_TUPLE;
}
-/*
- * These are used with both HeapTuple and MinimalTuple, so they must be
- * macros.
- */
-
-#define HeapTupleHeaderGetNatts(tup) \
- ((tup)->t_infomask2 & HEAP_NATTS_MASK)
+static inline int
+HeapTupleHeaderGetNatts(const HeapTupleHeaderData *tup)
+{
+ return tup->t_infomask2 & HEAP_NATTS_MASK;
+}
-#define HeapTupleHeaderSetNatts(tup, natts) \
-( \
- (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
-)
+static inline void
+HeapTupleHeaderSetNatts(HeapTupleHeaderData *tup, int natts)
+{
+ tup->t_infomask2 = (tup->t_infomask2 & ~HEAP_NATTS_MASK) | natts;
+}
-#define HeapTupleHeaderHasExternal(tup) \
- (((tup)->t_infomask & HEAP_HASEXTERNAL) != 0)
+static inline bool
+HeapTupleHeaderHasExternal(HeapTupleHeaderData *tup)
+{
+ return (tup->t_infomask & HEAP_HASEXTERNAL) != 0;
+}
/*
@@ -725,6 +727,28 @@ HeapTupleHeaderClearMatch(MinimalTupleData *tup)
tup->t_infomask2 &= ~HEAP_TUPLE_HAS_MATCH;
}
+/*
+ * Accessor functions for both HeapTupleHeader and MinimalTuple
+ */
+
+static inline bool
+MinimalTupleHasExternal(MinimalTupleData *tup)
+{
+ return (tup->t_infomask & HEAP_HASEXTERNAL) != 0;
+}
+
+#define HeapTupleHeaderHasExternal(tup) \
+ _Generic((tup), HeapTupleHeaderData*: HeapTupleHeaderHasExternal, MinimalTupleData*: MinimalTupleHasExternal)(tup)
+
+static inline void
+MinimalTupleSetNatts(MinimalTupleData *tup, int natts)
+{
+ tup->t_infomask2 = (tup->t_infomask2 & ~HEAP_NATTS_MASK) | natts;
+}
+
+#define HeapTupleHeaderSetNatts(tup, natts) \
+ _Generic((tup), HeapTupleHeaderData*: HeapTupleHeaderSetNatts, MinimalTupleData*: MinimalTupleSetNatts)(tup, natts)
+
/*
* GETSTRUCT - given a HeapTuple pointer, return address of the user data
--
2.47.1
On 27.12.24 11:16, Peter Eisentraut wrote:
On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
This is an older thread where I left something unfinished:
Note 2: Many macros in htup_details.h operate both on HeapTupleHeader
and on MinimalTuple, so converting them to a function doesn't work in
a straightforward way. I have some in-progress work in that area, but
I have not included any of that here.Here is the patch set for this.
I have committed this.
There are actually only two macros that operate on both HeapTupleHeader
and MinimalTuple, so it wasn't as much as I had written above. I just
left those as macros. I converted the rest to inline functions in a
straightforward way as before. A small amount of reordering was necessary.But just for language-nerd fun, I'm including here an additional patch
showing how the remaining ones could be done with C11 generic selection.
I'm not planning to commit that one at this time.
... except this.
On Thu, 23 Jan 2025 at 14:39, Peter Eisentraut <
peter.eisentraut@enterprisedb.com> wrote:
On 27.12.24 11:16, Peter Eisentraut wrote:
On 16.05.22 10:27, Peter Eisentraut wrote:
Inspired by [0], I looked to convert more macros to inline functions.
This is an older thread where I left something unfinished:
Note 2: Many macros in htup_details.h operate both on HeapTupleHeader
and on MinimalTuple, so converting them to a function doesn't work in
a straightforward way. I have some in-progress work in that area, but
I have not included any of that here.Here is the patch set for this.
I have committed this.
Great job! I've been working on the 64 XIDs patch for years, and I've never
liked this place. On the other hand,
as we know, inlining does not always work since it only suggests to the
compiler to do it. After all, many of
these calls are used in pretty "hot" places and every instruction is
important, in my opinion. Wouldn't it be
better to use pg_attribute_always_inline in this particular module?
PFA patch. I don't use pg_attribute_always_inline for fastgetattr and
heap_getattr because they are relatively
large. I think it's worth leaving the possibility for debugging here.
--
Best regards,
Maxim Orlov.
Attachments:
v2-0001-Use-pg_attribute_always_inline-for-static-inline-.patchapplication/octet-stream; name=v2-0001-Use-pg_attribute_always_inline-for-static-inline-.patchDownload
From 1ab2df5f4fb800a1a58d2f049d4903bf2b4921b2 Mon Sep 17 00:00:00 2001
From: Maxim Orlov <orlovmg@gmail.com>
Date: Fri, 31 Jan 2025 16:16:10 +0300
Subject: [PATCH v2] Use pg_attribute_always_inline for static inline functions
(htup_details.h, itup.h)
---
src/include/access/htup_details.h | 110 +++++++++++++++---------------
1 file changed, 55 insertions(+), 55 deletions(-)
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 6cd4b95bfd..cce0df4c82 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -226,7 +226,7 @@ struct HeapTupleHeaderData
* See also HeapTupleHeaderIsOnlyLocked, which also checks for a possible
* aborted updater transaction.
*/
-static inline bool
+static pg_attribute_always_inline bool
HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
{
return (infomask & HEAP_XMAX_LOCK_ONLY) ||
@@ -251,7 +251,7 @@ HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
* bogus, regardless of where they stand with respect to the current valid
* multixact range.
*/
-static inline bool
+static pg_attribute_always_inline bool
HEAP_LOCKED_UPGRADED(uint16 infomask)
{
return
@@ -263,19 +263,19 @@ HEAP_LOCKED_UPGRADED(uint16 infomask)
/*
* Use these to test whether a particular lock is applied to a tuple
*/
-static inline bool
+static pg_attribute_always_inline bool
HEAP_XMAX_IS_SHR_LOCKED(int16 infomask)
{
return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_SHR_LOCK;
}
-static inline bool
+static pg_attribute_always_inline bool
HEAP_XMAX_IS_EXCL_LOCKED(int16 infomask)
{
return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_EXCL_LOCK;
}
-static inline bool
+static pg_attribute_always_inline bool
HEAP_XMAX_IS_KEYSHR_LOCKED(int16 infomask)
{
return (infomask & HEAP_LOCK_MASK) == HEAP_XMAX_KEYSHR_LOCK;
@@ -319,72 +319,72 @@ static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup);
* the xmin to FrozenTransactionId, and that value may still be encountered
* on disk.
*/
-static inline TransactionId
+static pg_attribute_always_inline TransactionId
HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_heap.t_xmin;
}
-static inline TransactionId
+static pg_attribute_always_inline TransactionId
HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
{
return HeapTupleHeaderXminFrozen(tup) ?
FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
{
tup->t_choice.t_heap.t_xmin = xid;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
{
return (tup->t_infomask & HEAP_XMIN_COMMITTED) != 0;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup) \
{
return (tup->t_infomask & (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)) ==
HEAP_XMIN_INVALID;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
{
return (tup->t_infomask & HEAP_XMIN_FROZEN) == HEAP_XMIN_FROZEN;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXminCommitted(HeapTupleHeaderData *tup)
{
Assert(!HeapTupleHeaderXminInvalid(tup));
tup->t_infomask |= HEAP_XMIN_COMMITTED;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXminInvalid(HeapTupleHeaderData *tup)
{
Assert(!HeapTupleHeaderXminCommitted(tup));
tup->t_infomask |= HEAP_XMIN_INVALID;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXminFrozen(HeapTupleHeaderData *tup)
{
Assert(!HeapTupleHeaderXminInvalid(tup));
tup->t_infomask |= HEAP_XMIN_FROZEN;
}
-static inline TransactionId
+static pg_attribute_always_inline TransactionId
HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_heap.t_xmax;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXmax(HeapTupleHeaderData *tup, TransactionId xid)
{
tup->t_choice.t_heap.t_xmax = xid;
@@ -398,7 +398,7 @@ HeapTupleHeaderSetXmax(HeapTupleHeaderData *tup, TransactionId xid)
* to resolve the MultiXactId if necessary. This might involve multixact I/O,
* so it should only be used if absolutely necessary.
*/
-static inline TransactionId
+static pg_attribute_always_inline TransactionId
HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
{
if (!((tup)->t_infomask & HEAP_XMAX_INVALID) &&
@@ -416,14 +416,14 @@ HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
* HeapTupleHeaderGetCmax instead, but note that those Assert that you can
* get a legitimate result, ie you are in the originating transaction!
*/
-static inline CommandId
+static pg_attribute_always_inline CommandId
HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_heap.t_field3.t_cid;
}
/* SetCmin is reasonably simple since we never need a combo CID */
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetCmin(HeapTupleHeaderData *tup, CommandId cid)
{
Assert(!(tup->t_infomask & HEAP_MOVED));
@@ -432,7 +432,7 @@ HeapTupleHeaderSetCmin(HeapTupleHeaderData *tup, CommandId cid)
}
/* SetCmax must be used after HeapTupleHeaderAdjustCmax; see combocid.c */
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetCmax(HeapTupleHeaderData *tup, CommandId cid, bool iscombo)
{
Assert(!((tup)->t_infomask & HEAP_MOVED));
@@ -443,7 +443,7 @@ HeapTupleHeaderSetCmax(HeapTupleHeaderData *tup, CommandId cid, bool iscombo)
tup->t_infomask &= ~HEAP_COMBOCID;
}
-static inline TransactionId
+static pg_attribute_always_inline TransactionId
HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
{
if (tup->t_infomask & HEAP_MOVED)
@@ -452,7 +452,7 @@ HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
return InvalidTransactionId;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetXvac(HeapTupleHeaderData *tup, TransactionId xid)
{
Assert(tup->t_infomask & HEAP_MOVED);
@@ -462,68 +462,68 @@ HeapTupleHeaderSetXvac(HeapTupleHeaderData *tup, TransactionId xid)
StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
"invalid speculative token constant");
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
{
return ItemPointerGetOffsetNumberNoCheck(&tup->t_ctid) == SpecTokenOffsetNumber;
}
-static inline BlockNumber
+static pg_attribute_always_inline BlockNumber
HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
{
Assert(HeapTupleHeaderIsSpeculative(tup));
return ItemPointerGetBlockNumber(&tup->t_ctid);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetSpeculativeToken(HeapTupleHeaderData *tup, BlockNumber token)
{
ItemPointerSet(&tup->t_ctid, token, SpecTokenOffsetNumber);
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderIndicatesMovedPartitions(const HeapTupleHeaderData *tup)
{
return ItemPointerIndicatesMovedPartitions(&tup->t_ctid);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetMovedPartitions(HeapTupleHeaderData *tup)
{
ItemPointerSetMovedPartitions(&tup->t_ctid);
}
-static inline uint32
+static pg_attribute_always_inline uint32
HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
{
return VARSIZE(tup);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetDatumLength(HeapTupleHeaderData *tup, uint32 len)
{
SET_VARSIZE(tup, len);
}
-static inline Oid
+static pg_attribute_always_inline Oid
HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_datum.datum_typeid;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetTypeId(HeapTupleHeaderData *tup, Oid datum_typeid)
{
tup->t_choice.t_datum.datum_typeid = datum_typeid;
}
-static inline int32
+static pg_attribute_always_inline int32
HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_datum.datum_typmod;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetTypMod(HeapTupleHeaderData *tup, int32 typmod)
{
tup->t_choice.t_datum.datum_typmod = typmod;
@@ -535,7 +535,7 @@ HeapTupleHeaderSetTypMod(HeapTupleHeaderData *tup, int32 typmod)
* efficiency, check tuple visibility before using this function, so that the
* INVALID bits will be as up to date as possible.
*/
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
{
return
@@ -544,31 +544,31 @@ HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
!HeapTupleHeaderXminInvalid(tup);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetHotUpdated(HeapTupleHeaderData *tup)
{
tup->t_infomask2 |= HEAP_HOT_UPDATED;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderClearHotUpdated(HeapTupleHeaderData *tup)
{
tup->t_infomask2 &= ~HEAP_HOT_UPDATED;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup) \
{
return (tup->t_infomask2 & HEAP_ONLY_TUPLE) != 0;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetHeapOnly(HeapTupleHeaderData *tup)
{
tup->t_infomask2 |= HEAP_ONLY_TUPLE;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderClearHeapOnly(HeapTupleHeaderData *tup)
{
tup->t_infomask2 &= ~HEAP_ONLY_TUPLE;
@@ -595,7 +595,7 @@ HeapTupleHeaderClearHeapOnly(HeapTupleHeaderData *tup)
* BITMAPLEN(NATTS) -
* Computes size of null bitmap given number of data columns.
*/
-static inline int
+static pg_attribute_always_inline int
BITMAPLEN(int NATTS)
{
return (NATTS + 7) / 8;
@@ -707,19 +707,19 @@ struct MinimalTupleData
* MinimalTuple accessor functions
*/
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHeaderHasMatch(const MinimalTupleData *tup)
{
return (tup->t_infomask2 & HEAP_TUPLE_HAS_MATCH) != 0;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderSetMatch(MinimalTupleData *tup)
{
tup->t_infomask2 |= HEAP_TUPLE_HAS_MATCH;
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleHeaderClearMatch(MinimalTupleData *tup)
{
tup->t_infomask2 &= ~HEAP_TUPLE_HAS_MATCH;
@@ -729,7 +729,7 @@ HeapTupleHeaderClearMatch(MinimalTupleData *tup)
/*
* GETSTRUCT - given a HeapTuple pointer, return address of the user data
*/
-static inline void *
+static pg_attribute_always_inline void *
GETSTRUCT(const HeapTupleData *tuple)
{
return ((char *) (tuple->t_data) + tuple->t_data->t_hoff);
@@ -739,67 +739,67 @@ GETSTRUCT(const HeapTupleData *tuple)
* Accessor functions to be used with HeapTuple pointers.
*/
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHasNulls(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASNULL) != 0;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleNoNulls(const HeapTupleData *tuple)
{
return !HeapTupleHasNulls(tuple);
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHasVarWidth(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASVARWIDTH) != 0;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleAllFixed(const HeapTupleData *tuple)
{
return !HeapTupleHasVarWidth(tuple);
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleHasExternal(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASEXTERNAL) != 0;
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleIsHotUpdated(const HeapTupleData *tuple)
{
return HeapTupleHeaderIsHotUpdated(tuple->t_data);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleSetHotUpdated(const HeapTupleData *tuple)
{
HeapTupleHeaderSetHotUpdated(tuple->t_data);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleClearHotUpdated(const HeapTupleData *tuple)
{
HeapTupleHeaderClearHotUpdated(tuple->t_data);
}
-static inline bool
+static pg_attribute_always_inline bool
HeapTupleIsHeapOnly(const HeapTupleData *tuple)
{
return HeapTupleHeaderIsHeapOnly(tuple->t_data);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleSetHeapOnly(const HeapTupleData *tuple)
{
HeapTupleHeaderSetHeapOnly(tuple->t_data);
}
-static inline void
+static pg_attribute_always_inline void
HeapTupleClearHeapOnly(const HeapTupleData *tuple)
{
HeapTupleHeaderClearHeapOnly(tuple->t_data);
--
2.43.0
On 31.01.25 14:29, Maxim Orlov wrote:
Great job! I've been working on the 64 XIDs patch for years, and I've
never liked this place. On the other hand,
as we know, inlining does not always work since it only suggests to the
compiler to do it. After all, many of
these calls are used in pretty "hot" places and every instruction is
important, in my opinion. Wouldn't it be
better to use pg_attribute_always_inline in this particular module?PFA patch. I don't use pg_attribute_always_inline for fastgetattr and
heap_getattr because they are relatively
large. I think it's worth leaving the possibility for debugging here.
I've done some analysis with -Winline. The reasons for inlining to fail
are:
1) The function is too large.
2) The function call is unlikely. (Usually when used in elog() arguments.)
3) The function can never be inlined because it uses setjmp(). (This is
kind of a bug on our end, I think.)
The existing uses of pg_attribute_always_inline all appear to address
reason 1.
I think my/your patch does not touch any functions near the limit size,
so it does not seem necessary.
I think if we use pg_attribute_always_inline without any evidence, then
"inline" by itself might become meaningless.