Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8e166e1

Browse files
committed
Rearrange explain.c's API so callers need not embed sizeof(ExplainState).
The folly of the previous arrangement was just demonstrated: there's no convenient way to add fields to ExplainState without breaking ABI, even if callers have no need to touch those fields. Since we might well need to do that again someday in back branches, let's change things so that only explain.c has to have sizeof(ExplainState) compiled into it. This costs one extra palloc() per EXPLAIN operation, which is surely pretty negligible.
1 parent a5cd70d commit 8e166e1

File tree

3 files changed

+55
-56
lines changed

3 files changed

+55
-56
lines changed

contrib/auto_explain/auto_explain.c

+21-22
Original file line numberDiff line numberDiff line change
@@ -294,32 +294,31 @@ explain_ExecutorEnd(QueryDesc *queryDesc)
294294
msec = queryDesc->totaltime->total * 1000.0;
295295
if (msec >= auto_explain_log_min_duration)
296296
{
297-
ExplainState es;
298-
299-
ExplainInitState(&es);
300-
es.analyze = (queryDesc->instrument_options && auto_explain_log_analyze);
301-
es.verbose = auto_explain_log_verbose;
302-
es.buffers = (es.analyze && auto_explain_log_buffers);
303-
es.timing = (es.analyze && auto_explain_log_timing);
304-
es.summary = es.analyze;
305-
es.format = auto_explain_log_format;
306-
307-
ExplainBeginOutput(&es);
308-
ExplainQueryText(&es, queryDesc);
309-
ExplainPrintPlan(&es, queryDesc);
310-
if (es.analyze && auto_explain_log_triggers)
311-
ExplainPrintTriggers(&es, queryDesc);
312-
ExplainEndOutput(&es);
297+
ExplainState *es = NewExplainState();
298+
299+
es->analyze = (queryDesc->instrument_options && auto_explain_log_analyze);
300+
es->verbose = auto_explain_log_verbose;
301+
es->buffers = (es->analyze && auto_explain_log_buffers);
302+
es->timing = (es->analyze && auto_explain_log_timing);
303+
es->summary = es->analyze;
304+
es->format = auto_explain_log_format;
305+
306+
ExplainBeginOutput(es);
307+
ExplainQueryText(es, queryDesc);
308+
ExplainPrintPlan(es, queryDesc);
309+
if (es->analyze && auto_explain_log_triggers)
310+
ExplainPrintTriggers(es, queryDesc);
311+
ExplainEndOutput(es);
313312

314313
/* Remove last line break */
315-
if (es.str->len > 0 && es.str->data[es.str->len - 1] == '\n')
316-
es.str->data[--es.str->len] = '\0';
314+
if (es->str->len > 0 && es->str->data[es->str->len - 1] == '\n')
315+
es->str->data[--es->str->len] = '\0';
317316

318317
/* Fix JSON to output an object */
319318
if (auto_explain_log_format == EXPLAIN_FORMAT_JSON)
320319
{
321-
es.str->data[0] = '{';
322-
es.str->data[es.str->len - 1] = '}';
320+
es->str->data[0] = '{';
321+
es->str->data[es->str->len - 1] = '}';
323322
}
324323

325324
/*
@@ -330,10 +329,10 @@ explain_ExecutorEnd(QueryDesc *queryDesc)
330329
*/
331330
ereport(LOG,
332331
(errmsg("duration: %.3f ms plan:\n%s",
333-
msec, es.str->data),
332+
msec, es->str->data),
334333
errhidestmt(true)));
335334

336-
pfree(es.str->data);
335+
pfree(es->str->data);
337336
}
338337
}
339338

src/backend/commands/explain.c

+33-33
Original file line numberDiff line numberDiff line change
@@ -125,45 +125,42 @@ void
125125
ExplainQuery(ExplainStmt *stmt, const char *queryString,
126126
ParamListInfo params, DestReceiver *dest)
127127
{
128-
ExplainState es;
128+
ExplainState *es = NewExplainState();
129129
TupOutputState *tstate;
130130
List *rewritten;
131131
ListCell *lc;
132132
bool timing_set = false;
133133

134-
/* Initialize ExplainState. */
135-
ExplainInitState(&es);
136-
137134
/* Parse options list. */
138135
foreach(lc, stmt->options)
139136
{
140137
DefElem *opt = (DefElem *) lfirst(lc);
141138

142139
if (strcmp(opt->defname, "analyze") == 0)
143-
es.analyze = defGetBoolean(opt);
140+
es->analyze = defGetBoolean(opt);
144141
else if (strcmp(opt->defname, "verbose") == 0)
145-
es.verbose = defGetBoolean(opt);
142+
es->verbose = defGetBoolean(opt);
146143
else if (strcmp(opt->defname, "costs") == 0)
147-
es.costs = defGetBoolean(opt);
144+
es->costs = defGetBoolean(opt);
148145
else if (strcmp(opt->defname, "buffers") == 0)
149-
es.buffers = defGetBoolean(opt);
146+
es->buffers = defGetBoolean(opt);
150147
else if (strcmp(opt->defname, "timing") == 0)
151148
{
152149
timing_set = true;
153-
es.timing = defGetBoolean(opt);
150+
es->timing = defGetBoolean(opt);
154151
}
155152
else if (strcmp(opt->defname, "format") == 0)
156153
{
157154
char *p = defGetString(opt);
158155

159156
if (strcmp(p, "text") == 0)
160-
es.format = EXPLAIN_FORMAT_TEXT;
157+
es->format = EXPLAIN_FORMAT_TEXT;
161158
else if (strcmp(p, "xml") == 0)
162-
es.format = EXPLAIN_FORMAT_XML;
159+
es->format = EXPLAIN_FORMAT_XML;
163160
else if (strcmp(p, "json") == 0)
164-
es.format = EXPLAIN_FORMAT_JSON;
161+
es->format = EXPLAIN_FORMAT_JSON;
165162
else if (strcmp(p, "yaml") == 0)
166-
es.format = EXPLAIN_FORMAT_YAML;
163+
es->format = EXPLAIN_FORMAT_YAML;
167164
else
168165
ereport(ERROR,
169166
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -177,22 +174,22 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
177174
opt->defname)));
178175
}
179176

180-
if (es.buffers && !es.analyze)
177+
if (es->buffers && !es->analyze)
181178
ereport(ERROR,
182179
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
183180
errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
184181

185182
/* if the timing was not set explicitly, set default value */
186-
es.timing = (timing_set) ? es.timing : es.analyze;
183+
es->timing = (timing_set) ? es->timing : es->analyze;
187184

188185
/* check that timing is used with EXPLAIN ANALYZE */
189-
if (es.timing && !es.analyze)
186+
if (es->timing && !es->analyze)
190187
ereport(ERROR,
191188
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
192189
errmsg("EXPLAIN option TIMING requires ANALYZE")));
193190

194191
/* currently, summary option is not exposed to users; just set it */
195-
es.summary = es.analyze;
192+
es->summary = es->analyze;
196193

197194
/*
198195
* Parse analysis was done already, but we still have to run the rule
@@ -210,16 +207,16 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
210207
rewritten = QueryRewrite((Query *) copyObject(stmt->query));
211208

212209
/* emit opening boilerplate */
213-
ExplainBeginOutput(&es);
210+
ExplainBeginOutput(es);
214211

215212
if (rewritten == NIL)
216213
{
217214
/*
218215
* In the case of an INSTEAD NOTHING, tell at least that. But in
219216
* non-text format, the output is delimited, so this isn't necessary.
220217
*/
221-
if (es.format == EXPLAIN_FORMAT_TEXT)
222-
appendStringInfoString(es.str, "Query rewrites to nothing\n");
218+
if (es->format == EXPLAIN_FORMAT_TEXT)
219+
appendStringInfoString(es->str, "Query rewrites to nothing\n");
223220
}
224221
else
225222
{
@@ -228,41 +225,44 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
228225
/* Explain every plan */
229226
foreach(l, rewritten)
230227
{
231-
ExplainOneQuery((Query *) lfirst(l), NULL, &es,
228+
ExplainOneQuery((Query *) lfirst(l), NULL, es,
232229
queryString, params);
233230

234231
/* Separate plans with an appropriate separator */
235232
if (lnext(l) != NULL)
236-
ExplainSeparatePlans(&es);
233+
ExplainSeparatePlans(es);
237234
}
238235
}
239236

240237
/* emit closing boilerplate */
241-
ExplainEndOutput(&es);
242-
Assert(es.indent == 0);
238+
ExplainEndOutput(es);
239+
Assert(es->indent == 0);
243240

244241
/* output tuples */
245242
tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
246-
if (es.format == EXPLAIN_FORMAT_TEXT)
247-
do_text_output_multiline(tstate, es.str->data);
243+
if (es->format == EXPLAIN_FORMAT_TEXT)
244+
do_text_output_multiline(tstate, es->str->data);
248245
else
249-
do_text_output_oneline(tstate, es.str->data);
246+
do_text_output_oneline(tstate, es->str->data);
250247
end_tup_output(tstate);
251248

252-
pfree(es.str->data);
249+
pfree(es->str->data);
253250
}
254251

255252
/*
256-
* Initialize ExplainState.
253+
* Create a new ExplainState struct initialized with default options.
257254
*/
258-
void
259-
ExplainInitState(ExplainState *es)
255+
ExplainState *
256+
NewExplainState(void)
260257
{
261-
/* Set default options. */
262-
memset(es, 0, sizeof(ExplainState));
258+
ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
259+
260+
/* Set default options (most fields can be left as zeroes). */
263261
es->costs = true;
264262
/* Prepare output buffer. */
265263
es->str = makeStringInfo();
264+
265+
return es;
266266
}
267267

268268
/*

src/include/commands/explain.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook;
6060
extern void ExplainQuery(ExplainStmt *stmt, const char *queryString,
6161
ParamListInfo params, DestReceiver *dest);
6262

63-
extern void ExplainInitState(ExplainState *es);
63+
extern ExplainState *NewExplainState(void);
6464

6565
extern TupleDesc ExplainResultDesc(ExplainStmt *stmt);
6666

0 commit comments

Comments
 (0)