Skip to content

Commit 9d7726c

Browse files
committed
Recommend wrappers of PG_DETOAST_DATUM_PACKED().
When commit 3e23b68 introduced single-byte varlena headers, its fmgr.h changes presented PG_GETARG_TEXT_PP() and PG_GETARG_TEXT_P() as equals. Its postgres.h changes presented PG_DETOAST_DATUM_PACKED() and VARDATA_ANY() as the exceptional case. Now, instead, firmly recommend PG_GETARG_TEXT_PP() over PG_GETARG_TEXT_P(); likewise for other ...PP() macros. This shaves cycles and invites consistency of style.
1 parent 944a026 commit 9d7726c

File tree

6 files changed

+76
-59
lines changed

6 files changed

+76
-59
lines changed

doc/src/sgml/xfunc.sgml

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,18 +2388,23 @@ PG_FUNCTION_INFO_V1(copytext);
23882388
Datum
23892389
copytext(PG_FUNCTION_ARGS)
23902390
{
2391-
text *t = PG_GETARG_TEXT_P(0);
2391+
text *t = PG_GETARG_TEXT_PP(0);
2392+
23922393
/*
2393-
* VARSIZE is the total size of the struct in bytes.
2394+
* VARSIZE_ANY_EXHDR is the size of the struct in bytes, minus the
2395+
* VARHDRSZ or VARHDRSZ_SHORT of its header. Construct the copy with a
2396+
* full-length header.
23942397
*/
2395-
text *new_t = (text *) palloc(VARSIZE(t));
2396-
SET_VARSIZE(new_t, VARSIZE(t));
2398+
text *new_t = (text *) palloc(VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
2399+
SET_VARSIZE(new_t, VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
2400+
23972401
/*
2398-
* VARDATA is a pointer to the data region of the struct.
2402+
* VARDATA is a pointer to the data region of the new struct. The source
2403+
* could be a short datum, so retrieve its data through VARDATA_ANY.
23992404
*/
24002405
memcpy((void *) VARDATA(new_t), /* destination */
2401-
(void *) VARDATA(t), /* source */
2402-
VARSIZE(t) - VARHDRSZ); /* how many bytes */
2406+
(void *) VARDATA_ANY(t), /* source */
2407+
VARSIZE_ANY_EXHDR(t)); /* how many bytes */
24032408
PG_RETURN_TEXT_P(new_t);
24042409
}
24052410

@@ -2408,15 +2413,16 @@ PG_FUNCTION_INFO_V1(concat_text);
24082413
Datum
24092414
concat_text(PG_FUNCTION_ARGS)
24102415
{
2411-
text *arg1 = PG_GETARG_TEXT_P(0);
2412-
text *arg2 = PG_GETARG_TEXT_P(1);
2413-
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
2416+
text *arg1 = PG_GETARG_TEXT_PP(0);
2417+
text *arg2 = PG_GETARG_TEXT_PP(1);
2418+
int32 arg1_size = VARSIZE_ANY_EXHDR(arg1);
2419+
int32 arg2_size = VARSIZE_ANY_EXHDR(arg2);
2420+
int32 new_text_size = arg1_size + arg2_size + VARHDRSZ;
24142421
text *new_text = (text *) palloc(new_text_size);
24152422

24162423
SET_VARSIZE(new_text, new_text_size);
2417-
memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
2418-
memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
2419-
VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
2424+
memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size);
2425+
memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
24202426
PG_RETURN_TEXT_P(new_text);
24212427
}
24222428
]]>

src/include/c.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,11 @@ typedef struct
429429
* may be compressed or moved out-of-line. However datatype-specific routines
430430
* are mostly content to deal with de-TOASTed values only, and of course
431431
* client-side routines should never see a TOASTed value. But even in a
432-
* de-TOASTed value, beware of touching vl_len_ directly, as its representation
433-
* is no longer convenient. It's recommended that code always use the VARDATA,
434-
* VARSIZE, and SET_VARSIZE macros instead of relying on direct mentions of
435-
* the struct fields. See postgres.h for details of the TOASTed form.
432+
* de-TOASTed value, beware of touching vl_len_ directly, as its
433+
* representation is no longer convenient. It's recommended that code always
434+
* use macros VARDATA_ANY, VARSIZE_ANY, VARSIZE_ANY_EXHDR, VARDATA, VARSIZE,
435+
* and SET_VARSIZE instead of relying on direct mentions of the struct fields.
436+
* See postgres.h for details of the TOASTed form.
436437
* ----------------
437438
*/
438439
struct varlena

src/include/fmgr.h

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,12 @@ extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
178178
* The resulting datum can be accessed using VARSIZE_ANY() and VARDATA_ANY()
179179
* (beware of multiple evaluations in those macros!)
180180
*
181-
* WARNING: It is only safe to use pg_detoast_datum_packed() and
182-
* VARDATA_ANY() if you really don't care about the alignment. Either because
183-
* you're working with something like text where the alignment doesn't matter
184-
* or because you're not going to access its constituent parts and just use
185-
* things like memcpy on it anyways.
181+
* In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(),
182+
* VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call
183+
* PG_DETOAST_DATUM(), VARDATA() and VARSIZE(). Directly fetching an int16,
184+
* int32 or wider field in the struct representing the datum layout requires
185+
* aligned data. memcpy() is alignment-oblivious, as are most operations on
186+
* datatypes, such as text, whose layout struct contains only char fields.
186187
*
187188
* Note: it'd be nice if these could be macros, but I see no way to do that
188189
* without evaluating the arguments multiple times, which is NOT acceptable.
@@ -243,13 +244,9 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
243244
/* and this if you can handle 1-byte-header datums: */
244245
#define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n))
245246
/* DatumGetFoo macros for varlena types will typically look like this: */
246-
#define DatumGetByteaP(X) ((bytea *) PG_DETOAST_DATUM(X))
247247
#define DatumGetByteaPP(X) ((bytea *) PG_DETOAST_DATUM_PACKED(X))
248-
#define DatumGetTextP(X) ((text *) PG_DETOAST_DATUM(X))
249248
#define DatumGetTextPP(X) ((text *) PG_DETOAST_DATUM_PACKED(X))
250-
#define DatumGetBpCharP(X) ((BpChar *) PG_DETOAST_DATUM(X))
251249
#define DatumGetBpCharPP(X) ((BpChar *) PG_DETOAST_DATUM_PACKED(X))
252-
#define DatumGetVarCharP(X) ((VarChar *) PG_DETOAST_DATUM(X))
253250
#define DatumGetVarCharPP(X) ((VarChar *) PG_DETOAST_DATUM_PACKED(X))
254251
#define DatumGetHeapTupleHeader(X) ((HeapTupleHeader) PG_DETOAST_DATUM(X))
255252
/* And we also offer variants that return an OK-to-write copy */
@@ -264,13 +261,9 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
264261
#define DatumGetBpCharPSlice(X,m,n) ((BpChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
265262
#define DatumGetVarCharPSlice(X,m,n) ((VarChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
266263
/* GETARG macros for varlena types will typically look like this: */
267-
#define PG_GETARG_BYTEA_P(n) DatumGetByteaP(PG_GETARG_DATUM(n))
268264
#define PG_GETARG_BYTEA_PP(n) DatumGetByteaPP(PG_GETARG_DATUM(n))
269-
#define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n))
270265
#define PG_GETARG_TEXT_PP(n) DatumGetTextPP(PG_GETARG_DATUM(n))
271-
#define PG_GETARG_BPCHAR_P(n) DatumGetBpCharP(PG_GETARG_DATUM(n))
272266
#define PG_GETARG_BPCHAR_PP(n) DatumGetBpCharPP(PG_GETARG_DATUM(n))
273-
#define PG_GETARG_VARCHAR_P(n) DatumGetVarCharP(PG_GETARG_DATUM(n))
274267
#define PG_GETARG_VARCHAR_PP(n) DatumGetVarCharPP(PG_GETARG_DATUM(n))
275268
#define PG_GETARG_HEAPTUPLEHEADER(n) DatumGetHeapTupleHeader(PG_GETARG_DATUM(n))
276269
/* And we also offer variants that return an OK-to-write copy */
@@ -284,6 +277,21 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
284277
#define PG_GETARG_TEXT_P_SLICE(n,a,b) DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b)
285278
#define PG_GETARG_BPCHAR_P_SLICE(n,a,b) DatumGetBpCharPSlice(PG_GETARG_DATUM(n),a,b)
286279
#define PG_GETARG_VARCHAR_P_SLICE(n,a,b) DatumGetVarCharPSlice(PG_GETARG_DATUM(n),a,b)
280+
/*
281+
* Obsolescent variants that guarantee INT alignment for the return value.
282+
* Few operations on these particular types need alignment, mainly operations
283+
* that cast the VARDATA pointer to a type like int16[]. Most code should use
284+
* the ...PP(X) counterpart. Nonetheless, these appear frequently in code
285+
* predating the PostgreSQL 8.3 introduction of the ...PP(X) variants.
286+
*/
287+
#define DatumGetByteaP(X) ((bytea *) PG_DETOAST_DATUM(X))
288+
#define DatumGetTextP(X) ((text *) PG_DETOAST_DATUM(X))
289+
#define DatumGetBpCharP(X) ((BpChar *) PG_DETOAST_DATUM(X))
290+
#define DatumGetVarCharP(X) ((VarChar *) PG_DETOAST_DATUM(X))
291+
#define PG_GETARG_BYTEA_P(n) DatumGetByteaP(PG_GETARG_DATUM(n))
292+
#define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n))
293+
#define PG_GETARG_BPCHAR_P(n) DatumGetBpCharP(PG_GETARG_DATUM(n))
294+
#define PG_GETARG_VARCHAR_P(n) DatumGetVarCharP(PG_GETARG_DATUM(n))
287295

288296
/* To return a NULL do this: */
289297
#define PG_RETURN_NULL() \

src/include/postgres.h

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -287,20 +287,18 @@ typedef struct
287287
/* Externally visible macros */
288288

289289
/*
290-
* VARDATA, VARSIZE, and SET_VARSIZE are the recommended API for most code
291-
* for varlena datatypes. Note that they only work on untoasted,
292-
* 4-byte-header Datums!
293-
*
294-
* Code that wants to use 1-byte-header values without detoasting should
295-
* use VARSIZE_ANY/VARSIZE_ANY_EXHDR/VARDATA_ANY. The other macros here
296-
* should usually be used only by tuple assembly/disassembly code and
297-
* code that specifically wants to work with still-toasted Datums.
298-
*
299-
* WARNING: It is only safe to use VARDATA_ANY() -- typically with
300-
* PG_DETOAST_DATUM_PACKED() -- if you really don't care about the alignment.
301-
* Either because you're working with something like text where the alignment
302-
* doesn't matter or because you're not going to access its constituent parts
303-
* and just use things like memcpy on it anyways.
290+
* In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(),
291+
* VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call
292+
* PG_DETOAST_DATUM(), VARDATA() and VARSIZE(). Directly fetching an int16,
293+
* int32 or wider field in the struct representing the datum layout requires
294+
* aligned data. memcpy() is alignment-oblivious, as are most operations on
295+
* datatypes, such as text, whose layout struct contains only char fields.
296+
*
297+
* Code assembling a new datum should call VARDATA() and SET_VARSIZE().
298+
* (Datums begin life untoasted.)
299+
*
300+
* Other macros here should usually be used only by tuple assembly/disassembly
301+
* code and code that specifically wants to work with still-toasted Datums.
304302
*/
305303
#define VARDATA(PTR) VARDATA_4B(PTR)
306304
#define VARSIZE(PTR) VARSIZE_4B(PTR)

src/include/utils/inet.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,13 @@ typedef struct macaddr
104104
/*
105105
* fmgr interface macros
106106
*/
107-
#define DatumGetInetP(X) ((inet *) PG_DETOAST_DATUM(X))
108107
#define DatumGetInetPP(X) ((inet *) PG_DETOAST_DATUM_PACKED(X))
109108
#define InetPGetDatum(X) PointerGetDatum(X)
110-
#define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
111109
#define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
112110
#define PG_RETURN_INET_P(x) return InetPGetDatum(x)
111+
/* obsolescent variants */
112+
#define DatumGetInetP(X) ((inet *) PG_DETOAST_DATUM(X))
113+
#define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
113114
/* macaddr is a fixed-length pass-by-reference datatype */
114115
#define DatumGetMacaddrP(X) ((macaddr *) DatumGetPointer(X))
115116
#define MacaddrPGetDatum(X) PointerGetDatum(X)

src/tutorial/funcs_new.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,24 @@ PG_FUNCTION_INFO_V1(copytext);
6666
Datum
6767
copytext(PG_FUNCTION_ARGS)
6868
{
69-
text *t = PG_GETARG_TEXT_P(0);
69+
text *t = PG_GETARG_TEXT_PP(0);
7070

7171
/*
72-
* VARSIZE is the total size of the struct in bytes.
72+
* VARSIZE_ANY_EXHDR is the size of the struct in bytes, minus the
73+
* VARHDRSZ or VARHDRSZ_SHORT of its header. Construct the copy with a
74+
* full-length header.
7375
*/
74-
text *new_t = (text *) palloc(VARSIZE(t));
76+
text *new_t = (text *) palloc(VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
7577

76-
SET_VARSIZE(new_t, VARSIZE(t));
78+
SET_VARSIZE(new_t, VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
7779

7880
/*
79-
* VARDATA is a pointer to the data region of the struct.
81+
* VARDATA is a pointer to the data region of the new struct. The source
82+
* could be a short datum, so retrieve its data through VARDATA_ANY.
8083
*/
8184
memcpy((void *) VARDATA(new_t), /* destination */
82-
(void *) VARDATA(t), /* source */
83-
VARSIZE(t) - VARHDRSZ); /* how many bytes */
85+
(void *) VARDATA_ANY(t), /* source */
86+
VARSIZE_ANY_EXHDR(t)); /* how many bytes */
8487
PG_RETURN_TEXT_P(new_t);
8588
}
8689

@@ -89,16 +92,16 @@ PG_FUNCTION_INFO_V1(concat_text);
8992
Datum
9093
concat_text(PG_FUNCTION_ARGS)
9194
{
92-
text *arg1 = PG_GETARG_TEXT_P(0);
93-
text *arg2 = PG_GETARG_TEXT_P(1);
94-
int32 arg1_size = VARSIZE(arg1) - VARHDRSZ;
95-
int32 arg2_size = VARSIZE(arg2) - VARHDRSZ;
95+
text *arg1 = PG_GETARG_TEXT_PP(0);
96+
text *arg2 = PG_GETARG_TEXT_PP(1);
97+
int32 arg1_size = VARSIZE_ANY_EXHDR(arg1);
98+
int32 arg2_size = VARSIZE_ANY_EXHDR(arg2);
9699
int32 new_text_size = arg1_size + arg2_size + VARHDRSZ;
97100
text *new_text = (text *) palloc(new_text_size);
98101

99102
SET_VARSIZE(new_text, new_text_size);
100-
memcpy(VARDATA(new_text), VARDATA(arg1), arg1_size);
101-
memcpy(VARDATA(new_text) + arg1_size, VARDATA(arg2), arg2_size);
103+
memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size);
104+
memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
102105
PG_RETURN_TEXT_P(new_text);
103106
}
104107

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy