postgresql/src/include/postgres.h
Heikki Linnakangas d65995cbc6 Change PointerGetDatum() back to a macro
The argument was marked as "const void *X", but that might rightly
give the compiler the idea that *X cannot be modified through the
resulting Datum, and make incorrect optimizations based on that. Some
functions use pointer Datums to pass output arguments, like GIN
support functions. Coverity started to complain after commit
6f5ad00ab7 that there's dead code in ginExtractEntries(), because it
didn't see that it passes PointerGetDatum(&nentries) to a function
that sets it.

This issue goes back to commit c8b2ef05f4 (version 16), which
changed PointerGetDatum() from a macro to a static inline function.
This commit changes it back to a macro, but uses a trick with a dummy
conditional expression to still produce a compiler error if you try to
pass a non-pointer as the argument.

Even though this goes back to v16, I'm only committing this to
'master' for now, to verify that this silences the Coverity warning.
If this works, we might want to introduce separate const and non-const
versions of PointerGetDatum() instead of this, but that's a bigger
patch.  It's also not decided yet whether to back-patch this (or some
other fix), given that we haven't yet seen any hard evidence of
compilers actually producing buggy code because of this.

Discussion: https://www.postgresql.org/message-id/342012.1776017102@sss.pgh.pa.us
2026-04-17 22:14:40 +03:00

576 lines
12 KiB
C

/*-------------------------------------------------------------------------
*
* postgres.h
* Primary include file for PostgreSQL server .c files
*
* This should be the first file included by PostgreSQL backend modules.
* Client-side code should include postgres_fe.h instead.
*
*
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
* Portions Copyright (c) 1995, Regents of the University of California
*
* src/include/postgres.h
*
*-------------------------------------------------------------------------
*/
/* IWYU pragma: always_keep */
/*
*----------------------------------------------------------------
* TABLE OF CONTENTS
*
* When adding stuff to this file, please try to put stuff
* into the relevant section, or add new sections as appropriate.
*
* section description
* ------- ------------------------------------------------
* 1) Datum type + support functions
* 2) miscellaneous
*
* NOTES
*
* In general, this file should contain declarations that are widely needed
* in the backend environment, but are of no interest outside the backend.
*
* Simple type definitions live in c.h, where they are shared with
* postgres_fe.h. We do that since those type definitions are needed by
* frontend modules that want to deal with binary data transmission to or
* from the backend. Type definitions in this file should be for
* representations that never escape the backend, such as Datum.
*
*----------------------------------------------------------------
*/
#ifndef POSTGRES_H
#define POSTGRES_H
/* IWYU pragma: begin_exports */
#include "c.h"
#include "utils/elog.h"
#include "utils/palloc.h"
/* IWYU pragma: end_exports */
/* ----------------------------------------------------------------
* Section 1: Datum type + support functions
* ----------------------------------------------------------------
*/
/*
* A Datum contains either a value of a pass-by-value type or a pointer to a
* value of a pass-by-reference type. Therefore, we must have
* sizeof(Datum) >= sizeof(void *). No current or foreseeable Postgres
* platform has pointers wider than 8 bytes, and standardizing on Datum being
* exactly 8 bytes has advantages in reducing cross-platform differences.
*
* The functions below and the analogous functions for other types should be used to
* convert between a Datum and the appropriate C type.
*/
typedef uint64_t Datum;
/*
* This symbol is now vestigial, but we continue to define it so as not to
* unnecessarily break extension code.
*/
#define SIZEOF_DATUM 8
/*
* A NullableDatum is used in places where both a Datum and its nullness needs
* to be stored. This can be more efficient than storing datums and nullness
* in separate arrays, due to better spatial locality, even if more space may
* be wasted due to padding.
*/
typedef struct NullableDatum
{
#define FIELDNO_NULLABLE_DATUM_DATUM 0
Datum value;
#define FIELDNO_NULLABLE_DATUM_ISNULL 1
bool isnull;
/* due to alignment padding this could be used for flags for free */
} NullableDatum;
/*
* DatumGetBool
* Returns boolean value of a datum.
*
* Note: any nonzero value will be considered true.
*/
static inline bool
DatumGetBool(Datum X)
{
return (X != 0);
}
/*
* BoolGetDatum
* Returns datum representation for a boolean.
*
* Note: any nonzero value will be considered true.
*/
static inline Datum
BoolGetDatum(bool X)
{
return (Datum) (X ? 1 : 0);
}
/*
* DatumGetChar
* Returns character value of a datum.
*/
static inline char
DatumGetChar(Datum X)
{
return (char) X;
}
/*
* CharGetDatum
* Returns datum representation for a character.
*/
static inline Datum
CharGetDatum(char X)
{
return (Datum) X;
}
/*
* DatumGetUInt8
* Returns 8-bit unsigned integer value of a datum.
*/
static inline uint8
DatumGetUInt8(Datum X)
{
return (uint8) X;
}
/*
* UInt8GetDatum
* Returns datum representation for an 8-bit unsigned integer.
*/
static inline Datum
UInt8GetDatum(uint8 X)
{
return (Datum) X;
}
/*
* DatumGetInt16
* Returns 16-bit integer value of a datum.
*/
static inline int16
DatumGetInt16(Datum X)
{
return (int16) X;
}
/*
* Int16GetDatum
* Returns datum representation for a 16-bit integer.
*/
static inline Datum
Int16GetDatum(int16 X)
{
return (Datum) X;
}
/*
* DatumGetUInt16
* Returns 16-bit unsigned integer value of a datum.
*/
static inline uint16
DatumGetUInt16(Datum X)
{
return (uint16) X;
}
/*
* UInt16GetDatum
* Returns datum representation for a 16-bit unsigned integer.
*/
static inline Datum
UInt16GetDatum(uint16 X)
{
return (Datum) X;
}
/*
* DatumGetInt32
* Returns 32-bit integer value of a datum.
*/
static inline int32
DatumGetInt32(Datum X)
{
return (int32) X;
}
/*
* Int32GetDatum
* Returns datum representation for a 32-bit integer.
*/
static inline Datum
Int32GetDatum(int32 X)
{
return (Datum) X;
}
/*
* DatumGetUInt32
* Returns 32-bit unsigned integer value of a datum.
*/
static inline uint32
DatumGetUInt32(Datum X)
{
return (uint32) X;
}
/*
* UInt32GetDatum
* Returns datum representation for a 32-bit unsigned integer.
*/
static inline Datum
UInt32GetDatum(uint32 X)
{
return (Datum) X;
}
/*
* DatumGetObjectId
* Returns object identifier value of a datum.
*/
static inline Oid
DatumGetObjectId(Datum X)
{
return (Oid) X;
}
/*
* ObjectIdGetDatum
* Returns datum representation for an object identifier.
*/
static inline Datum
ObjectIdGetDatum(Oid X)
{
return (Datum) X;
}
/*
* DatumGetObjectId8
* Returns 8-byte object identifier value of a datum.
*/
static inline Oid8
DatumGetObjectId8(Datum X)
{
return (Oid8) X;
}
/*
* ObjectId8GetDatum
* Returns datum representation for an 8-byte object identifier
*/
static inline Datum
ObjectId8GetDatum(Oid8 X)
{
return (Datum) X;
}
/*
* DatumGetTransactionId
* Returns transaction identifier value of a datum.
*/
static inline TransactionId
DatumGetTransactionId(Datum X)
{
return (TransactionId) X;
}
/*
* TransactionIdGetDatum
* Returns datum representation for a transaction identifier.
*/
static inline Datum
TransactionIdGetDatum(TransactionId X)
{
return (Datum) X;
}
/*
* MultiXactIdGetDatum
* Returns datum representation for a multixact identifier.
*/
static inline Datum
MultiXactIdGetDatum(MultiXactId X)
{
return (Datum) X;
}
/*
* DatumGetCommandId
* Returns command identifier value of a datum.
*/
static inline CommandId
DatumGetCommandId(Datum X)
{
return (CommandId) X;
}
/*
* CommandIdGetDatum
* Returns datum representation for a command identifier.
*/
static inline Datum
CommandIdGetDatum(CommandId X)
{
return (Datum) X;
}
/*
* DatumGetPointer
* Returns pointer value of a datum.
*/
static inline Pointer
DatumGetPointer(Datum X)
{
return (Pointer) (uintptr_t) X;
}
/*
* PointerGetDatum
* Returns datum representation for a pointer.
*
* This used to be defined as "static inline Datum PointerGetDatum(const void
* *X) ", but it had the problem that the compiler would see the const
* attribute, and could rightly assume that the function won't modify *X.
* While PointerGetDatum() itself doesn't modify *X, the resulting Datum could
* later be passed to a function that converts it back to a non-const pointer
* and modifies it. Most functions don't modify their arguments passed by
* reference - that would be very bogus for any operators or functions exposed
* in SQL - but some functions like GIN support functions do have output
* arguments that are pointer Datums.
*
* The odd-looking "true ? (X) : NULL" conditional expression has the effect
* of producing a compiler error if X is not a pointer.
*/
#define PointerGetDatum(X) \
((Datum) (uintptr_t) (true ? (X) : NULL))
/*
* DatumGetCString
* Returns C string (null-terminated string) value of a datum.
*
* Note: C string is not a full-fledged Postgres type at present,
* but type input functions use this conversion for their inputs.
*/
static inline char *
DatumGetCString(Datum X)
{
return (char *) DatumGetPointer(X);
}
/*
* CStringGetDatum
* Returns datum representation for a C string (null-terminated string).
*
* We assume that the resulting Datum is not used to modify the string, hence
* the argument can be marked as const.
*
* Note: C string is not a full-fledged Postgres type at present,
* but type output functions use this conversion for their outputs.
* Note: CString is pass-by-reference; caller must ensure the pointed-to
* value has adequate lifetime.
*/
static inline Datum
CStringGetDatum(const char *X)
{
return PointerGetDatum(X);
}
/*
* DatumGetName
* Returns name value of a datum.
*/
static inline Name
DatumGetName(Datum X)
{
return (Name) DatumGetPointer(X);
}
/*
* NameGetDatum
* Returns datum representation for a name.
*
* Note: Name is pass-by-reference; caller must ensure the pointed-to
* value has adequate lifetime.
*/
static inline Datum
NameGetDatum(const NameData *X)
{
return CStringGetDatum(NameStr(*X));
}
/*
* DatumGetInt64
* Returns 64-bit integer value of a datum.
*/
static inline int64
DatumGetInt64(Datum X)
{
return (int64) X;
}
/*
* Int64GetDatum
* Returns datum representation for a 64-bit integer.
*/
static inline Datum
Int64GetDatum(int64 X)
{
return (Datum) X;
}
/*
* DatumGetUInt64
* Returns 64-bit unsigned integer value of a datum.
*/
static inline uint64
DatumGetUInt64(Datum X)
{
return (uint64) X;
}
/*
* UInt64GetDatum
* Returns datum representation for a 64-bit unsigned integer.
*/
static inline Datum
UInt64GetDatum(uint64 X)
{
return (Datum) X;
}
/*
* Float <-> Datum conversions
*
* These have to be implemented as inline functions rather than macros, when
* passing by value, because many machines pass int and float function
* parameters/results differently; so we need to play weird games with unions.
*/
/*
* DatumGetFloat4
* Returns 4-byte floating point value of a datum.
*/
static inline float4
DatumGetFloat4(Datum X)
{
union
{
int32 value;
float4 retval;
} myunion;
myunion.value = DatumGetInt32(X);
return myunion.retval;
}
/*
* Float4GetDatum
* Returns datum representation for a 4-byte floating point number.
*/
static inline Datum
Float4GetDatum(float4 X)
{
union
{
float4 value;
int32 retval;
} myunion;
myunion.value = X;
return Int32GetDatum(myunion.retval);
}
/*
* DatumGetFloat8
* Returns 8-byte floating point value of a datum.
*/
static inline float8
DatumGetFloat8(Datum X)
{
union
{
int64 value;
float8 retval;
} myunion;
myunion.value = DatumGetInt64(X);
return myunion.retval;
}
/*
* Float8GetDatum
* Returns datum representation for an 8-byte floating point number.
*/
static inline Datum
Float8GetDatum(float8 X)
{
union
{
float8 value;
int64 retval;
} myunion;
myunion.value = X;
return Int64GetDatum(myunion.retval);
}
/*
* Int64GetDatumFast
* Float8GetDatumFast
*
* These macros were intended to allow writing code that does not depend on
* whether int64 and float8 are pass-by-reference types, while not
* sacrificing performance when they are. They are no longer different
* from the regular functions, though we keep the assertions to protect
* code that might get back-patched into older branches.
*/
#define Int64GetDatumFast(X) \
(StaticAssertVariableIsOfTypeMacro(X, int64), Int64GetDatum(X))
#define Float8GetDatumFast(X) \
(StaticAssertVariableIsOfTypeMacro(X, double), Float8GetDatum(X))
/* ----------------------------------------------------------------
* Section 2: miscellaneous
* ----------------------------------------------------------------
*/
/*
* pg_ternary
* Boolean value with an extra "unset" value
*
* This enum can be used for values that want to distinguish between true,
* false, and unset.
*/
typedef enum pg_ternary
{
PG_TERNARY_FALSE = 0,
PG_TERNARY_TRUE = 1,
PG_TERNARY_UNSET = -1
} pg_ternary;
/*
* NON_EXEC_STATIC: It's sometimes useful to define a variable or function
* that is normally static but extern when using EXEC_BACKEND (see
* pg_config_manual.h). There would then typically be some code in
* postmaster.c that uses those extern symbols to transfer state between
* processes or do whatever other things it needs to do in EXEC_BACKEND mode.
*/
#ifdef EXEC_BACKEND
#define NON_EXEC_STATIC
#else
#define NON_EXEC_STATIC static
#endif
#endif /* POSTGRES_H */