PostgreSQL Source Code: src/backend/commands/explain_dr.c Source File

PostgreSQL Source Code git master
explain_dr.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * explain_dr.c
4 * Explain DestReceiver to measure serialization overhead
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/commands/explain_dr.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "commands/explain.h"
17#include "commands/explain_dr.h"
18#include "commands/explain_state.h"
19#include "libpq/pqformat.h"
20#include "libpq/protocol.h"
21#include "utils/lsyscache.h"
22#include "varatt.h"
23
24/*
25 * DestReceiver functions for SERIALIZE option
26 *
27 * A DestReceiver for query tuples, that serializes passed rows into RowData
28 * messages while measuring the resources expended and total serialized size,
29 * while never sending the data to the client. This allows measuring the
30 * overhead of deTOASTing and datatype out/sendfuncs, which are not otherwise
31 * exercisable without actually hitting the network.
32 */
33 typedef struct SerializeDestReceiver
34{
35 DestReceiver pub;
36 ExplainState *es; /* this EXPLAIN statement's ExplainState */
37 int8 format; /* text or binary, like pq wire protocol */
38 TupleDesc attrinfo; /* the output tuple desc */
39 int nattrs; /* current number of columns */
40 FmgrInfo *finfos; /* precomputed call info for output fns */
41 MemoryContext tmpcontext; /* per-row temporary memory context */
42 StringInfoData buf; /* buffer to hold the constructed message */
43 SerializeMetrics metrics; /* collected metrics */
44 } SerializeDestReceiver;
45
46/*
47 * Get the function lookup info that we'll need for output.
48 *
49 * This is a subset of what printtup_prepare_info() does. We don't need to
50 * cope with format choices varying across columns, so it's slightly simpler.
51 */
52static void
53 serialize_prepare_info(SerializeDestReceiver *receiver,
54 TupleDesc typeinfo, int nattrs)
55{
56 /* get rid of any old data */
57 if (receiver->finfos)
58 pfree(receiver->finfos);
59 receiver->finfos = NULL;
60
61 receiver->attrinfo = typeinfo;
62 receiver->nattrs = nattrs;
63 if (nattrs <= 0)
64 return;
65
66 receiver->finfos = (FmgrInfo *) palloc0(nattrs * sizeof(FmgrInfo));
67
68 for (int i = 0; i < nattrs; i++)
69 {
70 FmgrInfo *finfo = receiver->finfos + i;
71 Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
72 Oid typoutput;
73 Oid typsend;
74 bool typisvarlena;
75
76 if (receiver->format == 0)
77 {
78 /* wire protocol format text */
79 getTypeOutputInfo(attr->atttypid,
80 &typoutput,
81 &typisvarlena);
82 fmgr_info(typoutput, finfo);
83 }
84 else if (receiver->format == 1)
85 {
86 /* wire protocol format binary */
87 getTypeBinaryOutputInfo(attr->atttypid,
88 &typsend,
89 &typisvarlena);
90 fmgr_info(typsend, finfo);
91 }
92 else
93 ereport(ERROR,
94 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
95 errmsg("unsupported format code: %d", receiver->format)));
96 }
97}
98
99/*
100 * serializeAnalyzeReceive - collect tuples for EXPLAIN (SERIALIZE)
101 *
102 * This should match printtup() in printtup.c as closely as possible,
103 * except for the addition of measurement code.
104 */
105static bool
106 serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self)
107{
108 TupleDesc typeinfo = slot->tts_tupleDescriptor;
109 SerializeDestReceiver *myState = (SerializeDestReceiver *) self;
110 MemoryContext oldcontext;
111 StringInfo buf = &myState->buf;
112 int natts = typeinfo->natts;
113 instr_time start,
114 end;
115 BufferUsage instr_start;
116
117 /* only measure time, buffers if requested */
118 if (myState->es->timing)
119 INSTR_TIME_SET_CURRENT(start);
120 if (myState->es->buffers)
121 instr_start = pgBufferUsage;
122
123 /* Set or update my derived attribute info, if needed */
124 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
125 serialize_prepare_info(myState, typeinfo, natts);
126
127 /* Make sure the tuple is fully deconstructed */
128 slot_getallattrs(slot);
129
130 /* Switch into per-row context so we can recover memory below */
131 oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
132
133 /*
134 * Prepare a DataRow message (note buffer is in per-query context)
135 *
136 * Note that we fill a StringInfo buffer the same as printtup() does, so
137 * as to capture the costs of manipulating the strings accurately.
138 */
139 pq_beginmessage_reuse(buf, PqMsg_DataRow);
140
141 pq_sendint16(buf, natts);
142
143 /*
144 * send the attributes of this tuple
145 */
146 for (int i = 0; i < natts; i++)
147 {
148 FmgrInfo *finfo = myState->finfos + i;
149 Datum attr = slot->tts_values[i];
150
151 if (slot->tts_isnull[i])
152 {
153 pq_sendint32(buf, -1);
154 continue;
155 }
156
157 if (myState->format == 0)
158 {
159 /* Text output */
160 char *outputstr;
161
162 outputstr = OutputFunctionCall(finfo, attr);
163 pq_sendcountedtext(buf, outputstr, strlen(outputstr));
164 }
165 else
166 {
167 /* Binary output */
168 bytea *outputbytes;
169
170 outputbytes = SendFunctionCall(finfo, attr);
171 pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
172 pq_sendbytes(buf, VARDATA(outputbytes),
173 VARSIZE(outputbytes) - VARHDRSZ);
174 }
175 }
176
177 /*
178 * We mustn't call pq_endmessage_reuse(), since that would actually send
179 * the data to the client. Just count the data, instead. We can leave
180 * the buffer alone; it'll be reset on the next iteration (as would also
181 * happen in printtup()).
182 */
183 myState->metrics.bytesSent += buf->len;
184
185 /* Return to caller's context, and flush row's temporary memory */
186 MemoryContextSwitchTo(oldcontext);
187 MemoryContextReset(myState->tmpcontext);
188
189 /* Update timing data */
190 if (myState->es->timing)
191 {
192 INSTR_TIME_SET_CURRENT(end);
193 INSTR_TIME_ACCUM_DIFF(myState->metrics.timeSpent, end, start);
194 }
195
196 /* Update buffer metrics */
197 if (myState->es->buffers)
198 BufferUsageAccumDiff(&myState->metrics.bufferUsage,
199 &pgBufferUsage,
200 &instr_start);
201
202 return true;
203}
204
205/*
206 * serializeAnalyzeStartup - start up the serializeAnalyze receiver
207 */
208static void
209 serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
210{
211 SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
212
213 Assert(receiver->es != NULL);
214
215 switch (receiver->es->serialize)
216 {
217 case EXPLAIN_SERIALIZE_NONE:
218 Assert(false);
219 break;
220 case EXPLAIN_SERIALIZE_TEXT:
221 receiver->format = 0; /* wire protocol format text */
222 break;
223 case EXPLAIN_SERIALIZE_BINARY:
224 receiver->format = 1; /* wire protocol format binary */
225 break;
226 }
227
228 /* Create per-row temporary memory context */
229 receiver->tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
230 "SerializeTupleReceive",
231 ALLOCSET_DEFAULT_SIZES);
232
233 /* The output buffer is re-used across rows, as in printtup.c */
234 initStringInfo(&receiver->buf);
235
236 /* Initialize results counters */
237 memset(&receiver->metrics, 0, sizeof(SerializeMetrics));
238 INSTR_TIME_SET_ZERO(receiver->metrics.timeSpent);
239}
240
241/*
242 * serializeAnalyzeShutdown - shut down the serializeAnalyze receiver
243 */
244static void
245 serializeAnalyzeShutdown(DestReceiver *self)
246{
247 SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
248
249 if (receiver->finfos)
250 pfree(receiver->finfos);
251 receiver->finfos = NULL;
252
253 if (receiver->buf.data)
254 pfree(receiver->buf.data);
255 receiver->buf.data = NULL;
256
257 if (receiver->tmpcontext)
258 MemoryContextDelete(receiver->tmpcontext);
259 receiver->tmpcontext = NULL;
260}
261
262/*
263 * serializeAnalyzeDestroy - destroy the serializeAnalyze receiver
264 */
265static void
266 serializeAnalyzeDestroy(DestReceiver *self)
267{
268 pfree(self);
269}
270
271/*
272 * Build a DestReceiver for EXPLAIN (SERIALIZE) instrumentation.
273 */
274DestReceiver *
275 CreateExplainSerializeDestReceiver(ExplainState *es)
276{
277 SerializeDestReceiver *self;
278
279 self = (SerializeDestReceiver *) palloc0(sizeof(SerializeDestReceiver));
280
281 self->pub.receiveSlot = serializeAnalyzeReceive;
282 self->pub.rStartup = serializeAnalyzeStartup;
283 self->pub.rShutdown = serializeAnalyzeShutdown;
284 self->pub.rDestroy = serializeAnalyzeDestroy;
285 self->pub.mydest = DestExplainSerialize;
286
287 self->es = es;
288
289 return (DestReceiver *) self;
290}
291
292/*
293 * GetSerializationMetrics - collect metrics
294 *
295 * We have to be careful here since the receiver could be an IntoRel
296 * receiver if the subject statement is CREATE TABLE AS. In that
297 * case, return all-zeroes stats.
298 */
299SerializeMetrics
300 GetSerializationMetrics(DestReceiver *dest)
301{
302 SerializeMetrics empty;
303
304 if (dest->mydest == DestExplainSerialize)
305 return ((SerializeDestReceiver *) dest)->metrics;
306
307 memset(&empty, 0, sizeof(SerializeMetrics));
308 INSTR_TIME_SET_ZERO(empty.timeSpent);
309
310 return empty;
311}
#define VARHDRSZ
Definition: c.h:697
int8_t int8
Definition: c.h:532
@ DestExplainSerialize
Definition: dest.h:99
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
static void serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: explain_dr.c:209
SerializeMetrics GetSerializationMetrics(DestReceiver *dest)
Definition: explain_dr.c:300
static void serialize_prepare_info(SerializeDestReceiver *receiver, TupleDesc typeinfo, int nattrs)
Definition: explain_dr.c:53
static void serializeAnalyzeDestroy(DestReceiver *self)
Definition: explain_dr.c:266
static bool serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self)
Definition: explain_dr.c:106
struct SerializeDestReceiver SerializeDestReceiver
DestReceiver * CreateExplainSerializeDestReceiver(ExplainState *es)
Definition: explain_dr.c:275
static void serializeAnalyzeShutdown(DestReceiver *self)
Definition: explain_dr.c:245
@ EXPLAIN_SERIALIZE_TEXT
Definition: explain_state.h:23
@ EXPLAIN_SERIALIZE_NONE
Definition: explain_state.h:22
@ EXPLAIN_SERIALIZE_BINARY
Definition: explain_state.h:24
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:128
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1744
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
Assert(PointerIsAligned(start, uint64))
return str start
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:172
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:184
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:248
i
int i
Definition: isn.c:77
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition: lsyscache.c:3140
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3074
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
static char * buf
Definition: pg_test_fsync.c:72
uint64_t Datum
Definition: postgres.h:70
unsigned int Oid
Definition: postgres_ext.h:32
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_beginmessage_reuse(StringInfo buf, char msgtype)
Definition: pqformat.c:109
void pq_sendcountedtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:142
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:136
#define PqMsg_DataRow
Definition: protocol.h:43
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
ExplainSerializeOption serialize
Definition: explain_state.h:58
bool buffers
Definition: explain_state.h:51
Definition: fmgr.h:57
ExplainState * es
Definition: explain_dr.c:36
TupleDesc attrinfo
Definition: explain_dr.c:38
SerializeMetrics metrics
Definition: explain_dr.c:43
FmgrInfo * finfos
Definition: explain_dr.c:40
StringInfoData buf
Definition: explain_dr.c:42
MemoryContext tmpcontext
Definition: explain_dr.c:41
DestReceiver pub
Definition: explain_dr.c:35
uint64 bytesSent
Definition: explain_dr.h:25
instr_time timeSpent
Definition: explain_dr.h:26
BufferUsage bufferUsage
Definition: explain_dr.h:27
char * data
Definition: stringinfo.h:48
int natts
Definition: tupdesc.h:137
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:122
bool * tts_isnull
Definition: tuptable.h:126
Datum * tts_values
Definition: tuptable.h:124
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: dest.h:121
void(* rShutdown)(DestReceiver *self)
Definition: dest.h:124
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
CommandDest mydest
Definition: dest.h:128
Definition: c.h:692
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:371
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static char * VARDATA(const void *PTR)
Definition: varatt.h:305

AltStyle によって変換されたページ (->オリジナル) /