#ifndef HTUP_DETAILS_H
#define HTUP_DETAILS_H
#include "access/htup.h"
#include "access/transam.h"
#include "access/tupdesc.h"
#include "access/tupmacs.h"
#include "storage/bufpage.h"
#include "varatt.h"
#define MaxTupleAttributeNumber 1664
#define MaxHeapAttributeNumber 1600
typedef struct HeapTupleFields
{
TransactionId t_xmin;
TransactionId t_xmax;
union
{
CommandId t_cid;
TransactionId t_xvac;
} t_field3;
} HeapTupleFields;
typedef struct DatumTupleFields
{
int32 datum_len_;
int32 datum_typmod;
Oid datum_typeid;
} DatumTupleFields;
struct HeapTupleHeaderData
{
union
{
HeapTupleFields t_heap;
DatumTupleFields t_datum;
} t_choice;
ItemPointerData t_ctid;
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2 2
uint16 t_infomask2;
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK 3
uint16 t_infomask;
#define FIELDNO_HEAPTUPLEHEADERDATA_HOFF 4
uint8 t_hoff;
#define FIELDNO_HEAPTUPLEHEADERDATA_BITS 5
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER];
};
#define SizeofHeapTupleHeader offsetof(HeapTupleHeaderData, t_bits)
#define HEAP_HASNULL 0x0001
#define HEAP_HASVARWIDTH 0x0002
#define HEAP_HASEXTERNAL 0x0004
#define HEAP_HASOID_OLD 0x0008
#define HEAP_XMAX_KEYSHR_LOCK 0x0010
#define HEAP_COMBOCID 0x0020
#define HEAP_XMAX_EXCL_LOCK 0x0040
#define HEAP_XMAX_LOCK_ONLY 0x0080
#define HEAP_XMAX_SHR_LOCK (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
#define HEAP_LOCK_MASK (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \
HEAP_XMAX_KEYSHR_LOCK)
#define HEAP_XMIN_COMMITTED 0x0100
#define HEAP_XMIN_INVALID 0x0200
#define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)
#define HEAP_XMAX_COMMITTED 0x0400
#define HEAP_XMAX_INVALID 0x0800
#define HEAP_XMAX_IS_MULTI 0x1000
#define HEAP_UPDATED 0x2000
#define HEAP_MOVED_OFF 0x4000
#define HEAP_MOVED_IN 0x8000
#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
#define HEAP_XACT_MASK 0xFFF0
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;
}
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;
}
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;
}
#define HEAP_XMAX_BITS (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID | \
HEAP_XMAX_IS_MULTI | HEAP_LOCK_MASK | HEAP_XMAX_LOCK_ONLY)
#define HEAP_NATTS_MASK 0x07FF
#define HEAP_KEYS_UPDATED 0x2000
#define HEAP_HOT_UPDATED 0x4000
#define HEAP_ONLY_TUPLE 0x8000
#define HEAP2_XACT_MASK 0xE000
#define HEAP_TUPLE_HAS_MATCH HEAP_ONLY_TUPLE
static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup);
static inline TransactionId
HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_heap.t_xmin;
}
static inline TransactionId
HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
{
return HeapTupleHeaderXminFrozen(tup) ?
FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup);
}
static inline void
HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
{
tup->t_choice.t_heap.t_xmin = xid;
}
static inline bool
HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
{
return (tup->t_infomask & HEAP_XMIN_COMMITTED) != 0;
}
static inline bool
HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup) \
{
return (tup->t_infomask & (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)) ==
HEAP_XMIN_INVALID;
}
static inline bool
HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
{
return (tup->t_infomask & HEAP_XMIN_FROZEN) == HEAP_XMIN_FROZEN;
}
static inline void
HeapTupleHeaderSetXminCommitted(HeapTupleHeaderData *tup)
{
Assert(!HeapTupleHeaderXminInvalid(tup));
tup->t_infomask |= HEAP_XMIN_COMMITTED;
}
static inline void
HeapTupleHeaderSetXminInvalid(HeapTupleHeaderData *tup)
{
Assert(!HeapTupleHeaderXminCommitted(tup));
tup->t_infomask |= HEAP_XMIN_INVALID;
}
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
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
static inline CommandId
HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_heap.t_field3.t_cid;
}
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;
}
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;
}
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");
static inline bool
HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
{
return ItemPointerGetOffsetNumberNoCheck(&tup->t_ctid) == SpecTokenOffsetNumber;
}
static inline BlockNumber
HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
{
Assert(HeapTupleHeaderIsSpeculative(tup));
return ItemPointerGetBlockNumber(&tup->t_ctid);
}
static inline void
HeapTupleHeaderSetSpeculativeToken(HeapTupleHeaderData *tup, BlockNumber token)
{
ItemPointerSet(&tup->t_ctid, token, SpecTokenOffsetNumber);
}
static inline bool
HeapTupleHeaderIndicatesMovedPartitions(const HeapTupleHeaderData *tup)
{
return ItemPointerIndicatesMovedPartitions(&tup->t_ctid);
}
static inline void
HeapTupleHeaderSetMovedPartitions(HeapTupleHeaderData *tup)
{
ItemPointerSetMovedPartitions(&tup->t_ctid);
}
static inline uint32
HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
{
return VARSIZE(tup);
}
static inline void
HeapTupleHeaderSetDatumLength(HeapTupleHeaderData *tup, uint32 len)
{
SET_VARSIZE(tup, len);
}
static inline Oid
HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_datum.datum_typeid;
}
static inline void
HeapTupleHeaderSetTypeId(HeapTupleHeaderData *tup, Oid datum_typeid)
{
tup->t_choice.t_datum.datum_typeid = datum_typeid;
}
static inline int32
HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
{
return tup->t_choice.t_datum.datum_typmod;
}
static inline void
HeapTupleHeaderSetTypMod(HeapTupleHeaderData *tup, int32 typmod)
{
tup->t_choice.t_datum.datum_typmod = typmod;
}
static inline bool
HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
{
return
(tup->t_infomask2 & HEAP_HOT_UPDATED) != 0 &&
(tup->t_infomask & HEAP_XMAX_INVALID) == 0 &&
!HeapTupleHeaderXminInvalid(tup);
}
static inline void
HeapTupleHeaderSetHotUpdated(HeapTupleHeaderData *tup)
{
tup->t_infomask2 |= HEAP_HOT_UPDATED;
}
static inline void
HeapTupleHeaderClearHotUpdated(HeapTupleHeaderData *tup)
{
tup->t_infomask2 &= ~HEAP_HOT_UPDATED;
}
static inline bool
HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup) \
{
return (tup->t_infomask2 & HEAP_ONLY_TUPLE) != 0;
}
static inline void
HeapTupleHeaderSetHeapOnly(HeapTupleHeaderData *tup)
{
tup->t_infomask2 |= HEAP_ONLY_TUPLE;
}
static inline void
HeapTupleHeaderClearHeapOnly(HeapTupleHeaderData *tup)
{
tup->t_infomask2 &= ~HEAP_ONLY_TUPLE;
}
#define HeapTupleHeaderGetNatts(tup) \
((tup)->t_infomask2 & HEAP_NATTS_MASK)
#define HeapTupleHeaderSetNatts(tup, natts) \
( \
(tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
)
#define HeapTupleHeaderHasExternal(tup) \
(((tup)->t_infomask & HEAP_HASEXTERNAL) != 0)
static inline int
BITMAPLEN(int NATTS)
{
return (NATTS + 7) / 8;
}
#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData)))
#define MinHeapTupleSize MAXALIGN(SizeofHeapTupleHeader)
#define MaxHeapTuplesPerPage \
((int) ((BLCKSZ - SizeOfPageHeaderData) / \
(MAXALIGN(SizeofHeapTupleHeader) + sizeof(ItemIdData))))
#define MaxAttrSize (10 * 1024 * 1024)
#define MINIMAL_TUPLE_OFFSET \
((offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) / MAXIMUM_ALIGNOF * MAXIMUM_ALIGNOF)
#define MINIMAL_TUPLE_PADDING \
((offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) % MAXIMUM_ALIGNOF)
#define MINIMAL_TUPLE_DATA_OFFSET \
offsetof(MinimalTupleData, t_infomask2)
struct MinimalTupleData
{
uint32 t_len;
char mt_padding[MINIMAL_TUPLE_PADDING];
uint16 t_infomask2;
uint16 t_infomask;
uint8 t_hoff;
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER];
};
#define SizeofMinimalTupleHeader offsetof(MinimalTupleData, t_bits)
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;
}
static inline void *
GETSTRUCT(const HeapTupleData *tuple)
{
return ((char *) (tuple->t_data) + tuple->t_data->t_hoff);
}
static inline bool
HeapTupleHasNulls(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASNULL) != 0;
}
static inline bool
HeapTupleNoNulls(const HeapTupleData *tuple)
{
return !HeapTupleHasNulls(tuple);
}
static inline bool
HeapTupleHasVarWidth(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASVARWIDTH) != 0;
}
static inline bool
HeapTupleAllFixed(const HeapTupleData *tuple)
{
return !HeapTupleHasVarWidth(tuple);
}
static inline bool
HeapTupleHasExternal(const HeapTupleData *tuple)
{
return (tuple->t_data->t_infomask & HEAP_HASEXTERNAL) != 0;
}
static inline bool
HeapTupleIsHotUpdated(const HeapTupleData *tuple)
{
return HeapTupleHeaderIsHotUpdated(tuple->t_data);
}
static inline void
HeapTupleSetHotUpdated(const HeapTupleData *tuple)
{
HeapTupleHeaderSetHotUpdated(tuple->t_data);
}
static inline void
HeapTupleClearHotUpdated(const HeapTupleData *tuple)
{
HeapTupleHeaderClearHotUpdated(tuple->t_data);
}
static inline bool
HeapTupleIsHeapOnly(const HeapTupleData *tuple)
{
return HeapTupleHeaderIsHeapOnly(tuple->t_data);
}
static inline void
HeapTupleSetHeapOnly(const HeapTupleData *tuple)
{
HeapTupleHeaderSetHeapOnly(tuple->t_data);
}
static inline void
HeapTupleClearHeapOnly(const HeapTupleData *tuple)
{
HeapTupleHeaderClearHeapOnly(tuple->t_data);
}
extern Size heap_compute_data_size(TupleDesc tupleDesc,
const Datum *values, const bool *isnull);
extern void heap_fill_tuple(TupleDesc tupleDesc,
const Datum *values, const bool *isnull,
char *data, Size data_size,
uint16 *infomask, bits8 *bit);
extern bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc);
extern Datum nocachegetattr(HeapTuple tup, int attnum,
TupleDesc tupleDesc);
extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
bool *isnull);
extern Datum getmissingattr(TupleDesc tupleDesc,
int attnum, bool *isnull);
extern HeapTuple heap_copytuple(HeapTuple tuple);
extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
const Datum *values, const bool *isnull);
extern HeapTuple heap_modify_tuple(HeapTuple tuple,
TupleDesc tupleDesc,
const Datum *replValues,
const bool *replIsnull,
const bool *doReplace);
extern HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple,
TupleDesc tupleDesc,
int nCols,
const int *replCols,
const Datum *replValues,
const bool *replIsnull);
extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
Datum *values, bool *isnull);
extern void heap_freetuple(HeapTuple htup);
extern MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor,
const Datum *values, const bool *isnull,
Size extra);
extern void heap_free_minimal_tuple(MinimalTuple mtup);
extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup, Size extra);
extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup);
extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra);
extern size_t varsize_any(void *p);
extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
#ifndef FRONTEND
static inline Datum
fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
{
Assert(attnum > 0);
*isnull = false;
if (HeapTupleNoNulls(tup))
{
CompactAttribute *att;
att = TupleDescCompactAttr(tupleDesc, attnum - 1);
if (att->attcacheoff >= 0)
return fetchatt(att, (char *) tup->t_data + tup->t_data->t_hoff +
att->attcacheoff);
else
return nocachegetattr(tup, attnum, tupleDesc);
}
else
{
if (att_isnull(attnum - 1, tup->t_data->t_bits))
{
*isnull = true;
return (Datum) NULL;
}
else
return nocachegetattr(tup, attnum, tupleDesc);
}
}
static inline Datum
heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
{
if (attnum > 0)
{
if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
return getmissingattr(tupleDesc, attnum, isnull);
else
return fastgetattr(tup, attnum, tupleDesc, isnull);
}
else
return heap_getsysattr(tup, attnum, tupleDesc, isnull);
}
#endif
#endif