I had this lying around as a draft patch, as part of my ongoing campaign
to convert many complicated macros to static inline functions. Since
the topic was mentioned in another thread [0], I cleaned up the patch so
that we can all look at it.
The titular change is to convert the macros in varatt.h to inline
functions, so they are easier to read and use. I only touched the ones
for external use, not the internal ones, mainly because I don't have a
way to test a big-endian build.
Part of the change is also figuring out exactly what the argument and
return types should be. In many cases, there were some inconsistencies,
because the macros would just cast anything you give them into the shape
they want, no matter whether it makes sense. In particular, the callers
were inconsistent about whether macros like VARDATA() and VARSIZE()
should take struct varlena or Datum, or I guess both. I cleaned this up
by adding the required DatumGetPointer() calls in the first patch. The
thread [0] is now discussing some other ideas, but this is what I had,
and this way it's at least consistent with other existing code.
[0]:
https://www.postgresql.org/message-id/flat/1749799.1752797397%40sss.pgh.pa.usFrom fb4036e3ea593fe3d6f0791793cc9e282226783d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 31 Jul 2025 14:54:16 +0200
Subject: [PATCH v1 1/2] Fix varatt versus Datum type confusions
Macros like VARDATA() and VARSIZE() should be thought of as taking
values of type pointer to struct varlena or some other related struct.
The way they are implemented, you can pass anything to it and it will
cast it right. But this is in principle incorrect. To fix, add the
required DatumGetPointer() calls. Or in a couple of cases, remove
superfluous PointerGetDatum() calls.
---
contrib/hstore/hstore_gin.c | 2 +-
contrib/hstore/hstore_gist.c | 4 ++--
contrib/hstore/hstore_io.c | 24 ++++++++++-----------
contrib/hstore/hstore_op.c | 4 ++--
contrib/test_decoding/test_decoding.c | 2 +-
src/backend/access/brin/brin_minmax_multi.c | 2 +-
src/backend/access/common/heaptuple.c | 8 +++----
src/backend/access/common/reloptions.c | 8 +++----
src/backend/access/common/toast_internals.c | 2 +-
src/backend/access/gin/gininsert.c | 2 +-
src/backend/access/spgist/spgutils.c | 4 ++--
src/backend/access/table/toast_helper.c | 2 +-
src/backend/replication/logical/proto.c | 2 +-
src/backend/replication/pgoutput/pgoutput.c | 4 ++--
src/backend/statistics/mcv.c | 2 +-
src/backend/tsearch/ts_selfuncs.c | 2 +-
src/backend/utils/adt/jsonb_gin.c | 4 ++--
src/backend/utils/adt/jsonb_op.c | 8 +++----
src/backend/utils/adt/jsonfuncs.c | 4 ++--
src/backend/utils/adt/jsonpath_exec.c | 4 ++--
src/backend/utils/adt/multirangetypes.c | 7 +++---
src/backend/utils/adt/rangetypes.c | 6 ++----
src/backend/utils/adt/tsvector_op.c | 24 ++++++++++-----------
23 files changed, 65 insertions(+), 66 deletions(-)
diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c
index 766c00bb6a7..2e5fa115924 100644
--- a/contrib/hstore/hstore_gin.c
+++ b/contrib/hstore/hstore_gin.c
@@ -127,7 +127,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS)
/* Nulls in the array are ignored, cf
hstoreArrayToPairs */
if (key_nulls[i])
continue;
- item = makeitem(VARDATA(key_datums[i]),
VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
+ item =
makeitem(VARDATA(DatumGetPointer(key_datums[i])),
VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ, KEYFLAG);
entries[j++] = PointerGetDatum(item);
}
diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c
index a3b08af3850..69515dc3d3f 100644
--- a/contrib/hstore/hstore_gist.c
+++ b/contrib/hstore/hstore_gist.c
@@ -576,7 +576,7 @@ ghstore_consistent(PG_FUNCTION_ARGS)
if (key_nulls[i])
continue;
- crc = crc32_sz(VARDATA(key_datums[i]),
VARSIZE(key_datums[i]) - VARHDRSZ);
+ crc = crc32_sz(VARDATA(DatumGetPointer(key_datums[i])),
VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
if (!(GETBIT(sign, HASHVAL(crc, siglen))))
res = false;
}
@@ -599,7 +599,7 @@ ghstore_consistent(PG_FUNCTION_ARGS)
if (key_nulls[i])
continue;
- crc = crc32_sz(VARDATA(key_datums[i]),
VARSIZE(key_datums[i]) - VARHDRSZ);
+ crc = crc32_sz(VARDATA(DatumGetPointer(key_datums[i])),
VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
if (GETBIT(sign, HASHVAL(crc, siglen)))
res = true;
}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 4f867e4bd1f..9c53877c4a5 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -684,22 +684,22 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
if (!value_nulls || value_nulls[i])
{
- pairs[i].key = VARDATA(key_datums[i]);
+ pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
pairs[i].val = NULL;
pairs[i].keylen =
- hstoreCheckKeyLen(VARSIZE(key_datums[i]) -
VARHDRSZ);
+
hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
pairs[i].vallen = 4;
pairs[i].isnull = true;
pairs[i].needfree = false;
}
else
{
- pairs[i].key = VARDATA(key_datums[i]);
- pairs[i].val = VARDATA(value_datums[i]);
+ pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
+ pairs[i].val =
VARDATA(DatumGetPointer(value_datums[i]));
pairs[i].keylen =
- hstoreCheckKeyLen(VARSIZE(key_datums[i]) -
VARHDRSZ);
+
hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
pairs[i].vallen =
- hstoreCheckValLen(VARSIZE(value_datums[i]) -
VARHDRSZ);
+
hstoreCheckValLen(VARSIZE(DatumGetPointer(value_datums[i])) - VARHDRSZ);
pairs[i].isnull = false;
pairs[i].needfree = false;
}
@@ -778,22 +778,22 @@ hstore_from_array(PG_FUNCTION_ARGS)
if (in_nulls[i * 2 + 1])
{
- pairs[i].key = VARDATA(in_datums[i * 2]);
+ pairs[i].key = VARDATA(DatumGetPointer(in_datums[i *
2]));
pairs[i].val = NULL;
pairs[i].keylen =
- hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) -
VARHDRSZ);
+
hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
pairs[i].vallen = 4;
pairs[i].isnull = true;
pairs[i].needfree = false;
}
else
{
- pairs[i].key = VARDATA(in_datums[i * 2]);
- pairs[i].val = VARDATA(in_datums[i * 2 + 1]);
+ pairs[i].key = VARDATA(DatumGetPointer(in_datums[i *
2]));
+ pairs[i].val = VARDATA(DatumGetPointer(in_datums[i * 2
+ 1]));
pairs[i].keylen =
- hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) -
VARHDRSZ);
+
hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
pairs[i].vallen =
- hstoreCheckValLen(VARSIZE(in_datums[i * 2 + 1])
- VARHDRSZ);
+
hstoreCheckValLen(VARSIZE(DatumGetPointer(in_datums[i * 2 + 1])) - VARHDRSZ);
pairs[i].isnull = false;
pairs[i].needfree = false;
}
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index 5e57eceffc8..bcba75f9258 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -107,8 +107,8 @@ hstoreArrayToPairs(ArrayType *a, int *npairs)
{
if (!key_nulls[i])
{
- key_pairs[j].key = VARDATA(key_datums[i]);
- key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
+ key_pairs[j].key =
VARDATA(DatumGetPointer(key_datums[i]));
+ key_pairs[j].keylen =
VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ;
key_pairs[j].val = NULL;
key_pairs[j].vallen = 0;
key_pairs[j].needfree = 0;
diff --git a/contrib/test_decoding/test_decoding.c
b/contrib/test_decoding/test_decoding.c
index bb495563200..f671a7d4b31 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -581,7 +581,7 @@ tuple_to_stringinfo(StringInfo s, TupleDesc tupdesc,
HeapTuple tuple, bool skip_
/* print data */
if (isnull)
appendStringInfoString(s, "null");
- else if (typisvarlena && VARATT_IS_EXTERNAL_ONDISK(origval))
+ else if (typisvarlena &&
VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(origval)))
appendStringInfoString(s, "unchanged-toast-datum");
else if (!typisvarlena)
print_literal(s, typid,
diff --git a/src/backend/access/brin/brin_minmax_multi.c
b/src/backend/access/brin/brin_minmax_multi.c
index 0d1507a2a36..b85a70a0db2 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -624,7 +624,7 @@ brin_range_serialize(Ranges *range)
for (i = 0; i < nvalues; i++)
{
- len += VARSIZE_ANY(range->values[i]);
+ len += VARSIZE_ANY(DatumGetPointer(range->values[i]));
}
}
else if (typlen == -2) /* cstring */
diff --git a/src/backend/access/common/heaptuple.c
b/src/backend/access/common/heaptuple.c
index 969d1028cae..a410b5eb99b 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -189,7 +189,7 @@ getmissingattr(TupleDesc tupleDesc,
if (att->attlen > 0)
key.len = att->attlen;
else
- key.len = VARSIZE_ANY(attrmiss->am_value);
+ key.len =
VARSIZE_ANY(DatumGetPointer(attrmiss->am_value));
key.value = attrmiss->am_value;
entry = hash_search(missing_cache, &key, HASH_ENTER,
&found);
@@ -901,9 +901,9 @@ expand_tuple(HeapTuple *targetHeapTuple,
att->attlen,
attrmiss[attnum].am_value);
- targetDataLen =
att_addlength_pointer(targetDataLen,
-
att->attlen,
-
attrmiss[attnum].am_value);
+ targetDataLen =
att_addlength_datum(targetDataLen,
+
att->attlen,
+
attrmiss[attnum].am_value);
}
else
{
diff --git a/src/backend/access/common/reloptions.c
b/src/backend/access/common/reloptions.c
index 50747c16396..594a657ea1a 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1190,8 +1190,8 @@ transformRelOptions(Datum oldOptions, List *defList,
const char *namspace,
for (i = 0; i < noldoptions; i++)
{
- char *text_str = VARDATA(oldoptions[i]);
- int text_len =
VARSIZE(oldoptions[i]) - VARHDRSZ;
+ char *text_str =
VARDATA(DatumGetPointer(oldoptions[i]));
+ int text_len =
VARSIZE(DatumGetPointer(oldoptions[i])) - VARHDRSZ;
/* Search for a match in defList */
foreach(cell, defList)
@@ -1456,8 +1456,8 @@ parseRelOptionsInternal(Datum options, bool validate,
for (i = 0; i < noptions; i++)
{
- char *text_str = VARDATA(optiondatums[i]);
- int text_len = VARSIZE(optiondatums[i]) -
VARHDRSZ;
+ char *text_str =
VARDATA(DatumGetPointer(optiondatums[i]));
+ int text_len =
VARSIZE(DatumGetPointer(optiondatums[i])) - VARHDRSZ;
int j;
/* Search for a match in reloptions */
diff --git a/src/backend/access/common/toast_internals.c
b/src/backend/access/common/toast_internals.c
index 7d8be8346ce..196e06115e9 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -144,7 +144,7 @@ toast_save_datum(Relation rel, Datum value,
int num_indexes;
int validIndex;
- Assert(!VARATT_IS_EXTERNAL(value));
+ Assert(!VARATT_IS_EXTERNAL(dval));
/*
* Open the toast relation and its indexes. We can use the index to
check
diff --git a/src/backend/access/gin/gininsert.c
b/src/backend/access/gin/gininsert.c
index a65acd89104..47b1898a064 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -2233,7 +2233,7 @@ _gin_build_tuple(OffsetNumber attrnum, unsigned char
category,
else if (typlen > 0)
keylen = typlen;
else if (typlen == -1)
- keylen = VARSIZE_ANY(key);
+ keylen = VARSIZE_ANY(DatumGetPointer(key));
else if (typlen == -2)
keylen = strlen(DatumGetPointer(key)) + 1;
else
diff --git a/src/backend/access/spgist/spgutils.c
b/src/backend/access/spgist/spgutils.c
index 95fea74e296..9b86c016acb 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -785,7 +785,7 @@ SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
else if (att->attlen > 0)
size = att->attlen;
else
- size = VARSIZE_ANY(datum);
+ size = VARSIZE_ANY(DatumGetPointer(datum));
return MAXALIGN(size);
}
@@ -804,7 +804,7 @@ memcpyInnerDatum(void *target, SpGistTypeDesc *att, Datum
datum)
}
else
{
- size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
+ size = (att->attlen > 0) ? att->attlen :
VARSIZE_ANY(DatumGetPointer(datum));
memcpy(target, DatumGetPointer(datum), size);
}
}
diff --git a/src/backend/access/table/toast_helper.c
b/src/backend/access/table/toast_helper.c
index b60fab0a4d2..11f97d65367 100644
--- a/src/backend/access/table/toast_helper.c
+++ b/src/backend/access/table/toast_helper.c
@@ -330,7 +330,7 @@ toast_delete_external(Relation rel, const Datum *values,
const bool *isnull,
if (isnull[i])
continue;
- else if (VARATT_IS_EXTERNAL_ONDISK(value))
+ else if
(VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(value)))
toast_delete_datum(rel, value, is_speculative);
}
}
diff --git a/src/backend/replication/logical/proto.c
b/src/backend/replication/logical/proto.c
index 1a352b542dc..1b3d9eb49dd 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -809,7 +809,7 @@ logicalrep_write_tuple(StringInfo out, Relation rel,
TupleTableSlot *slot,
continue;
}
- if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(values[i]))
+ if (att->attlen == -1 &&
VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(values[i])))
{
/*
* Unchanged toasted datum. (Note that we don't
promise to detect
diff --git a/src/backend/replication/pgoutput/pgoutput.c
b/src/backend/replication/pgoutput/pgoutput.c
index f4c977262c5..80540c017bd 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1374,8 +1374,8 @@ pgoutput_row_filter(Relation relation, TupleTableSlot
*old_slot,
* VARTAG_INDIRECT. See ReorderBufferToastReplace.
*/
if (att->attlen == -1 &&
- VARATT_IS_EXTERNAL_ONDISK(new_slot->tts_values[i]) &&
- !VARATT_IS_EXTERNAL_ONDISK(old_slot->tts_values[i]))
+
VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(new_slot->tts_values[i])) &&
+
!VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(old_slot->tts_values[i])))
{
if (!tmp_new_slot)
{
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index d98cda698d9..f59fb821543 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -767,7 +767,7 @@ statext_mcv_serialize(MCVList *mcvlist, VacAttrStats
**stats)
values[dim][i] =
PointerGetDatum(PG_DETOAST_DATUM(values[dim][i]));
/* serialized length (uint32 length + data) */
- len = VARSIZE_ANY_EXHDR(values[dim][i]);
+ len =
VARSIZE_ANY_EXHDR(DatumGetPointer(values[dim][i]));
info[dim].nbytes += sizeof(uint32); /* length */
info[dim].nbytes += len; /* value (no
header) */
diff --git a/src/backend/tsearch/ts_selfuncs.c
b/src/backend/tsearch/ts_selfuncs.c
index 0c1d2bc1109..453a5e5c2ea 100644
--- a/src/backend/tsearch/ts_selfuncs.c
+++ b/src/backend/tsearch/ts_selfuncs.c
@@ -233,7 +233,7 @@ mcelem_tsquery_selec(TSQuery query, Datum *mcelem, int
nmcelem,
* The text Datums came from an array, so it cannot be
compressed or
* stored out-of-line -- it's safe to use VARSIZE_ANY*.
*/
- Assert(!VARATT_IS_COMPRESSED(mcelem[i]) &&
!VARATT_IS_EXTERNAL(mcelem[i]));
+ Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(mcelem[i])) &&
!VARATT_IS_EXTERNAL(DatumGetPointer(mcelem[i])));
lookup[i].element = (text *) DatumGetPointer(mcelem[i]);
lookup[i].frequency = numbers[i];
}
diff --git a/src/backend/utils/adt/jsonb_gin.c
b/src/backend/utils/adt/jsonb_gin.c
index c1950792b5a..9b56248cf0b 100644
--- a/src/backend/utils/adt/jsonb_gin.c
+++ b/src/backend/utils/adt/jsonb_gin.c
@@ -896,8 +896,8 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
continue;
/* We rely on the array elements not being toasted */
entries[j++] = make_text_key(JGINFLAG_KEY,
-
VARDATA_ANY(key_datums[i]),
-
VARSIZE_ANY_EXHDR(key_datums[i]));
+
VARDATA_ANY(DatumGetPointer(key_datums[i])),
+
VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i])));
}
*nentries = j;
diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c
index fa5603f26e1..51d38e321fb 100644
--- a/src/backend/utils/adt/jsonb_op.c
+++ b/src/backend/utils/adt/jsonb_op.c
@@ -63,8 +63,8 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
strVal.type = jbvString;
/* We rely on the array elements not being toasted */
- strVal.val.string.val = VARDATA_ANY(key_datums[i]);
- strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
+ strVal.val.string.val =
VARDATA_ANY(DatumGetPointer(key_datums[i]));
+ strVal.val.string.len =
VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
if (findJsonbValueFromContainer(&jb->root,
JB_FOBJECT | JB_FARRAY,
@@ -96,8 +96,8 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
strVal.type = jbvString;
/* We rely on the array elements not being toasted */
- strVal.val.string.val = VARDATA_ANY(key_datums[i]);
- strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
+ strVal.val.string.val =
VARDATA_ANY(DatumGetPointer(key_datums[i]));
+ strVal.val.string.len =
VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
if (findJsonbValueFromContainer(&jb->root,
JB_FOBJECT | JB_FARRAY,
diff --git a/src/backend/utils/adt/jsonfuncs.c
b/src/backend/utils/adt/jsonfuncs.c
index bcb1720b6cd..370456408bf 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -4766,8 +4766,8 @@ jsonb_delete_array(PG_FUNCTION_ARGS)
continue;
/* We rely on the array elements not being
toasted */
- keyptr = VARDATA_ANY(keys_elems[i]);
- keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
+ keyptr =
VARDATA_ANY(DatumGetPointer(keys_elems[i]));
+ keylen =
VARSIZE_ANY_EXHDR(DatumGetPointer(keys_elems[i]));
if (keylen == v.val.string.len &&
memcmp(keyptr, v.val.string.val,
keylen) == 0)
{
diff --git a/src/backend/utils/adt/jsonpath_exec.c
b/src/backend/utils/adt/jsonpath_exec.c
index dbab24737ef..407041b14a1 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -3074,8 +3074,8 @@ JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
JsonbValue *res)
case TEXTOID:
case VARCHAROID:
res->type = jbvString;
- res->val.string.val = VARDATA_ANY(val);
- res->val.string.len = VARSIZE_ANY_EXHDR(val);
+ res->val.string.val = VARDATA_ANY(DatumGetPointer(val));
+ res->val.string.len =
VARSIZE_ANY_EXHDR(DatumGetPointer(val));
break;
case DATEOID:
case TIMEOID:
diff --git a/src/backend/utils/adt/multirangetypes.c
b/src/backend/utils/adt/multirangetypes.c
index cd84ced5b48..bb1c7011e38 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -394,12 +394,13 @@ multirange_send(PG_FUNCTION_ARGS)
for (int i = 0; i < range_count; i++)
{
Datum range;
+ bytea *outputbytes;
range = RangeTypePGetDatum(ranges[i]);
- range = PointerGetDatum(SendFunctionCall(&cache->typioproc,
range));
+ outputbytes = SendFunctionCall(&cache->typioproc, range);
- pq_sendint32(buf, VARSIZE(range) - VARHDRSZ);
- pq_sendbytes(buf, VARDATA(range), VARSIZE(range) - VARHDRSZ);
+ pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
+ pq_sendbytes(buf, VARDATA(outputbytes), VARSIZE(outputbytes) -
VARHDRSZ);
}
PG_RETURN_BYTEA_P(pq_endtypsend(buf));
diff --git a/src/backend/utils/adt/rangetypes.c
b/src/backend/utils/adt/rangetypes.c
index 66cc0acf4a7..802646df1bb 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -285,8 +285,7 @@ range_send(PG_FUNCTION_ARGS)
if (RANGE_HAS_LBOUND(flags))
{
- Datum bound =
PointerGetDatum(SendFunctionCall(&cache->typioproc,
-
lower.val));
+ bytea *bound = SendFunctionCall(&cache->typioproc,
lower.val);
uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
char *bound_data = VARDATA(bound);
@@ -296,8 +295,7 @@ range_send(PG_FUNCTION_ARGS)
if (RANGE_HAS_UBOUND(flags))
{
- Datum bound =
PointerGetDatum(SendFunctionCall(&cache->typioproc,
-
upper.val));
+ bytea *bound = SendFunctionCall(&cache->typioproc,
upper.val);
uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
char *bound_data = VARDATA(bound);
diff --git a/src/backend/utils/adt/tsvector_op.c
b/src/backend/utils/adt/tsvector_op.c
index 1fa1275ca63..0625da9532f 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -329,8 +329,8 @@ tsvector_setweight_by_filter(PG_FUNCTION_ARGS)
if (nulls[i])
continue;
- lex = VARDATA(dlexemes[i]);
- lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
+ lex = VARDATA(DatumGetPointer(dlexemes[i]));
+ lex_len = VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
lex_pos = tsvector_bsearch(tsout, lex, lex_len);
if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) !=
0)
@@ -443,10 +443,10 @@ compare_text_lexemes(const void *va, const void *vb)
{
Datum a = *((const Datum *) va);
Datum b = *((const Datum *) vb);
- char *alex = VARDATA_ANY(a);
- int alex_len = VARSIZE_ANY_EXHDR(a);
- char *blex = VARDATA_ANY(b);
- int blex_len = VARSIZE_ANY_EXHDR(b);
+ char *alex = VARDATA_ANY(DatumGetPointer(a));
+ int alex_len =
VARSIZE_ANY_EXHDR(DatumGetPointer(a));
+ char *blex = VARDATA_ANY(DatumGetPointer(b));
+ int blex_len =
VARSIZE_ANY_EXHDR(DatumGetPointer(b));
return tsCompareString(alex, alex_len, blex, blex_len, false);
}
@@ -605,8 +605,8 @@ tsvector_delete_arr(PG_FUNCTION_ARGS)
if (nulls[i])
continue;
- lex = VARDATA(dlexemes[i]);
- lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
+ lex = VARDATA(DatumGetPointer(dlexemes[i]));
+ lex_len = VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
lex_pos = tsvector_bsearch(tsin, lex, lex_len);
if (lex_pos >= 0)
@@ -770,7 +770,7 @@ array_to_tsvector(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("lexeme array may not contain
nulls")));
- if (VARSIZE(dlexemes[i]) - VARHDRSZ == 0)
+ if (VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ == 0)
ereport(ERROR,
(errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
errmsg("lexeme array may not contain
empty strings")));
@@ -786,7 +786,7 @@ array_to_tsvector(PG_FUNCTION_ARGS)
/* Calculate space needed for surviving lexemes. */
for (i = 0; i < nitems; i++)
- datalen += VARSIZE(dlexemes[i]) - VARHDRSZ;
+ datalen += VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
tslen = CALCDATASIZE(nitems, datalen);
/* Allocate and fill tsvector. */
@@ -798,8 +798,8 @@ array_to_tsvector(PG_FUNCTION_ARGS)
cur = STRPTR(tsout);
for (i = 0; i < nitems; i++)
{
- char *lex = VARDATA(dlexemes[i]);
- int lex_len = VARSIZE(dlexemes[i]) -
VARHDRSZ;
+ char *lex = VARDATA(DatumGetPointer(dlexemes[i]));
+ int lex_len =
VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
memcpy(cur, lex, lex_len);
arrout[i].haspos = 0;
base-commit: 3357471cf9f5e470dfed0c7919bcf31c7efaf2b9
--
2.50.1
From e1ef8d2e1233e6cfb9dfdd1514fc9a311b9bee2c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 31 Jul 2025 14:54:16 +0200
Subject: [PATCH v1 2/2] Convert varatt.h macros to static inline functions
Only the external interfaces, not the endian-dependent internal
macros (mostly because I don't have access to test big-endian
architectures). (The VARTAG_1B_E() changes are required for C++
compatibility.)
---
doc/src/sgml/xfunc.sgml | 2 +-
src/include/varatt.h | 270 ++++++++++++++++++++++++++++++----------
2 files changed, 205 insertions(+), 67 deletions(-)
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 2d81afce8cb..30219f432d9 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -2165,7 +2165,7 @@ <title>Base Types in C-Language Functions</title>
it's considered good style to use the macro <literal>VARHDRSZ</literal>
to refer to the size of the overhead for a variable-length type.
Also, the length field <emphasis>must</emphasis> be set using the
- <literal>SET_VARSIZE</literal> macro, not by simple assignment.
+ <literal>SET_VARSIZE</literal> function, not by simple assignment.
</para>
<para>
diff --git a/src/include/varatt.h b/src/include/varatt.h
index 2e8564d4998..4061ec1a82a 100644
--- a/src/include/varatt.h
+++ b/src/include/varatt.h
@@ -90,14 +90,27 @@ typedef enum vartag_external
} vartag_external;
/* this test relies on the specific tag values above */
-#define VARTAG_IS_EXPANDED(tag) \
- (((tag) & ~1) == VARTAG_EXPANDED_RO)
+static inline bool
+VARTAG_IS_EXPANDED(vartag_external tag)
+{
+ return ((tag & ~1) == VARTAG_EXPANDED_RO);
+}
-#define VARTAG_SIZE(tag) \
- ((tag) == VARTAG_INDIRECT ? sizeof(varatt_indirect) : \
- VARTAG_IS_EXPANDED(tag) ? sizeof(varatt_expanded) : \
- (tag) == VARTAG_ONDISK ? sizeof(varatt_external) : \
- (AssertMacro(false), 0))
+static inline size_t
+VARTAG_SIZE(vartag_external tag)
+{
+ if (tag == VARTAG_INDIRECT)
+ return sizeof(varatt_indirect);
+ else if (VARTAG_IS_EXPANDED(tag))
+ return sizeof(varatt_expanded);
+ else if (tag == VARTAG_ONDISK)
+ return sizeof(varatt_external);
+ else
+ {
+ Assert(false);
+ return 0;
+ }
+}
/*
* These structs describe the header of a varlena object that may have been
@@ -194,7 +207,7 @@ typedef struct
#define VARSIZE_1B(PTR) \
(((varattrib_1b *) (PTR))->va_header & 0x7F)
#define VARTAG_1B_E(PTR) \
- (((varattrib_1b_e *) (PTR))->va_tag)
+ ((vartag_external) ((varattrib_1b_e *) (PTR))->va_tag)
#define SET_VARSIZE_4B(PTR,len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = (len) & 0x3FFFFFFF)
@@ -227,7 +240,7 @@ typedef struct
#define VARSIZE_1B(PTR) \
((((varattrib_1b *) (PTR))->va_header >> 1) & 0x7F)
#define VARTAG_1B_E(PTR) \
- (((varattrib_1b_e *) (PTR))->va_tag)
+ ((vartag_external) ((varattrib_1b_e *) (PTR))->va_tag)
#define SET_VARSIZE_4B(PTR,len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2))
@@ -254,13 +267,6 @@ typedef struct
#define VARHDRSZ_COMPRESSED offsetof(varattrib_4b,
va_compressed.va_data)
#define VARHDRSZ_SHORT offsetof(varattrib_1b, va_data)
-#define VARATT_SHORT_MAX 0x7F
-#define VARATT_CAN_MAKE_SHORT(PTR) \
- (VARATT_IS_4B_U(PTR) && \
- (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) <= VARATT_SHORT_MAX)
-#define VARATT_CONVERTED_SHORT_SIZE(PTR) \
- (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT)
-
/*
* In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(),
* VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call
@@ -272,63 +278,195 @@ typedef struct
* Code assembling a new datum should call VARDATA() and SET_VARSIZE().
* (Datums begin life untoasted.)
*
- * Other macros here should usually be used only by tuple assembly/disassembly
+ * Other functions here should usually be used only by tuple
assembly/disassembly
* code and code that specifically wants to work with still-toasted Datums.
*/
-#define VARDATA(PTR) VARDATA_4B(PTR)
-#define VARSIZE(PTR) VARSIZE_4B(PTR)
-
-#define VARSIZE_SHORT(PTR) VARSIZE_1B(PTR)
-#define VARDATA_SHORT(PTR) VARDATA_1B(PTR)
-
-#define VARTAG_EXTERNAL(PTR) VARTAG_1B_E(PTR)
-#define VARSIZE_EXTERNAL(PTR) (VARHDRSZ_EXTERNAL +
VARTAG_SIZE(VARTAG_EXTERNAL(PTR)))
-#define VARDATA_EXTERNAL(PTR) VARDATA_1B_E(PTR)
-
-#define VARATT_IS_COMPRESSED(PTR) VARATT_IS_4B_C(PTR)
-#define VARATT_IS_EXTERNAL(PTR)
VARATT_IS_1B_E(PTR)
-#define VARATT_IS_EXTERNAL_ONDISK(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_ONDISK)
-#define VARATT_IS_EXTERNAL_INDIRECT(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_INDIRECT)
-#define VARATT_IS_EXTERNAL_EXPANDED_RO(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RO)
-#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RW)
-#define VARATT_IS_EXTERNAL_EXPANDED(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR)))
-#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR) \
- (VARATT_IS_EXTERNAL(PTR) && !VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR)))
-#define VARATT_IS_SHORT(PTR) VARATT_IS_1B(PTR)
-#define VARATT_IS_EXTENDED(PTR)
(!VARATT_IS_4B_U(PTR))
-
-#define SET_VARSIZE(PTR, len) SET_VARSIZE_4B(PTR, len)
-#define SET_VARSIZE_SHORT(PTR, len) SET_VARSIZE_1B(PTR, len)
-#define SET_VARSIZE_COMPRESSED(PTR, len) SET_VARSIZE_4B_C(PTR, len)
-
-#define SET_VARTAG_EXTERNAL(PTR, tag) SET_VARTAG_1B_E(PTR, tag)
-
-#define VARSIZE_ANY(PTR) \
- (VARATT_IS_1B_E(PTR) ? VARSIZE_EXTERNAL(PTR) : \
- (VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR) : \
- VARSIZE_4B(PTR)))
+
+static inline char *
+VARDATA(const void *PTR)
+{
+ return VARDATA_4B(PTR);
+}
+
+static inline size_t
+VARSIZE(const void *PTR)
+{
+ return VARSIZE_4B(PTR);
+}
+
+static inline size_t
+VARSIZE_SHORT(const void *PTR)
+{
+ return VARSIZE_1B(PTR);
+}
+
+static inline char *
+VARDATA_SHORT(const void *PTR)
+{
+ return VARDATA_1B(PTR);
+}
+
+static inline vartag_external
+VARTAG_EXTERNAL(const void *PTR)
+{
+ return VARTAG_1B_E(PTR);
+}
+
+static inline size_t
+VARSIZE_EXTERNAL(const void *PTR)
+{
+ return VARHDRSZ_EXTERNAL + VARTAG_SIZE(VARTAG_EXTERNAL(PTR));
+}
+
+static inline char *
+VARDATA_EXTERNAL(const void *PTR)
+{
+ return VARDATA_1B_E(PTR);
+}
+
+static inline bool
+VARATT_IS_COMPRESSED(const void *PTR)
+{
+ return VARATT_IS_4B_C(PTR);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL(const void *PTR)
+{
+ return VARATT_IS_1B_E(PTR);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_ONDISK(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) ==
VARTAG_ONDISK);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_INDIRECT(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) ==
VARTAG_INDIRECT);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_EXPANDED_RO(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) ==
VARTAG_EXPANDED_RO);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_EXPANDED_RW(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) ==
VARTAG_EXPANDED_RW);
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_EXPANDED(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) &&
VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR)));
+}
+
+static inline bool
+VARATT_IS_EXTERNAL_NON_EXPANDED(const void *PTR)
+{
+ return (VARATT_IS_EXTERNAL(PTR) &&
!VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR)));
+}
+
+static inline bool
+VARATT_IS_SHORT(const void *PTR)
+{
+ return VARATT_IS_1B(PTR);
+}
+
+static inline bool
+VARATT_IS_EXTENDED(const void *PTR)
+{
+ return !VARATT_IS_4B_U(PTR);
+}
+
+#define VARATT_SHORT_MAX 0x7F
+
+static inline bool
+VARATT_CAN_MAKE_SHORT(const void *PTR)
+{
+ return (VARATT_IS_4B_U(PTR) &&
+ (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) <=
VARATT_SHORT_MAX);
+}
+
+static inline size_t
+VARATT_CONVERTED_SHORT_SIZE(const void *PTR)
+{
+ return VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT;
+}
+
+static inline void
+SET_VARSIZE(void *PTR, size_t len)
+{
+ SET_VARSIZE_4B(PTR, len);
+}
+
+static inline void
+SET_VARSIZE_SHORT(void *PTR, size_t len)
+{
+ SET_VARSIZE_1B(PTR, len);
+}
+
+static inline void
+SET_VARSIZE_COMPRESSED(void *PTR, size_t len)
+{
+ SET_VARSIZE_4B_C(PTR, len);
+}
+
+static inline void
+SET_VARTAG_EXTERNAL(void *PTR, vartag_external tag)
+{
+ SET_VARTAG_1B_E(PTR, tag);
+}
+
+static inline size_t
+VARSIZE_ANY(const void *PTR)
+{
+ if (VARATT_IS_1B_E(PTR))
+ return VARSIZE_EXTERNAL(PTR);
+ else if (VARATT_IS_1B(PTR))
+ return VARSIZE_1B(PTR);
+ else
+ return VARSIZE_4B(PTR);
+}
/* Size of a varlena data, excluding header */
-#define VARSIZE_ANY_EXHDR(PTR) \
- (VARATT_IS_1B_E(PTR) ? VARSIZE_EXTERNAL(PTR)-VARHDRSZ_EXTERNAL : \
- (VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR)-VARHDRSZ_SHORT : \
- VARSIZE_4B(PTR)-VARHDRSZ))
+static inline size_t
+VARSIZE_ANY_EXHDR(const void *PTR)
+{
+ if (VARATT_IS_1B_E(PTR))
+ return VARSIZE_EXTERNAL(PTR) - VARHDRSZ_EXTERNAL;
+ else if (VARATT_IS_1B(PTR))
+ return VARSIZE_1B(PTR) - VARHDRSZ_SHORT;
+ else
+ return VARSIZE_4B(PTR) - VARHDRSZ;
+}
/* caution: this will not work on an external or compressed-in-line Datum */
/* caution: this will return a possibly unaligned pointer */
-#define VARDATA_ANY(PTR) \
- (VARATT_IS_1B(PTR) ? VARDATA_1B(PTR) : VARDATA_4B(PTR))
-
-/* Decompressed size and compression method of a compressed-in-line Datum */
-#define VARDATA_COMPRESSED_GET_EXTSIZE(PTR) \
- (((varattrib_4b *) (PTR))->va_compressed.va_tcinfo &
VARLENA_EXTSIZE_MASK)
-#define VARDATA_COMPRESSED_GET_COMPRESS_METHOD(PTR) \
- (((varattrib_4b *) (PTR))->va_compressed.va_tcinfo >>
VARLENA_EXTSIZE_BITS)
+static inline char *
+VARDATA_ANY(const void *PTR)
+{
+ return (VARATT_IS_1B(PTR) ? VARDATA_1B(PTR) : VARDATA_4B(PTR));
+}
+
+/* Decompressed size of a compressed-in-line Datum */
+static inline size_t
+VARDATA_COMPRESSED_GET_EXTSIZE(const void *PTR)
+{
+ return (((const varattrib_4b *) PTR)->va_compressed.va_tcinfo &
VARLENA_EXTSIZE_MASK);
+}
+
+/* Compression method of a compressed-in-line Datum */
+static inline unsigned int
+VARDATA_COMPRESSED_GET_COMPRESS_METHOD(const void *PTR)
+{
+ return (((const varattrib_4b *) PTR)->va_compressed.va_tcinfo >>
VARLENA_EXTSIZE_BITS);
+}
/* Same for external Datums; but note argument is a struct varatt_external */
#define VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer) \
--
2.50.1