1 /*-------------------------------------------------------------------------
3 * pgsp_explain.c: extracted code from explain.c for explain of triggers.
5 * Copyright (c) 2008-2013, PostgreSQL Global Development Group
6 * Copyright (c) 2012-2015, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
9 * pg_store_plan/pgsp_explain.c
11 *-------------------------------------------------------------------------
15 #include "commands/explain.h"
16 #include "utils/rel.h"
17 #include "utils/lsyscache.h"
18 #include "utils/json.h"
19 #include "pgsp_explain.h"
21 static void pgspExplainOpenGroup(const char *objtype, const char *labelname,
22 bool labeled, ExplainState *es);
23 static void pgspExplainCloseGroup(const char *objtype, const char *labelname,
24 bool labeled, ExplainState *es);
25 static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
27 static void pgspExplainPropertyText(const char *qlabel, const char *value, ExplainState *es);
28 static void pgspExplainPropertyFloat(const char *qlabel, double value, int ndigits,
30 static void pgspExplainProperty(const char *qlabel, const char *value, bool numeric,
32 static void pgspExplainJSONLineEnding(ExplainState *es);
35 * ExplainState is modified at 9.4.1 and 9.3.6. But the change is for
36 * internal use and to avoid binary-incompatibility not changing the
37 * size of ExplainState. So we can use ExplainState->extra as if it
38 * were grouping_stack safely and should do so. Using ->extra as List*
39 * discards the memory for ExplainStateExtra but it is not a problem
40 * since it is allocated by palloc.
42 #if (PG_VERSION_NUM >= 90401 && PG_VERSION_NUM < 90500) || \
43 (PG_VERSION_NUM >= 90306 && PG_VERSION_NUM < 90400)
44 #define GROUPING_STACK(es) (*((List **)(&(es)->extra)))
46 #define GROUPING_STACK(es) ((es)->grouping_stack)
49 /* ExplainInitState() is replaced with NewExlainState() in 9.5 */
50 #if PG_VERSION_NUM < 90500
54 ExplainState *es = (ExplainState *)palloc0(sizeof(ExplainState));
63 pgspExplainTriggers(ExplainState *es, QueryDesc *queryDesc)
69 int numrels = queryDesc->estate->es_num_result_relations;
70 List *targrels = queryDesc->estate->es_trig_target_relations;
74 pgspExplainOpenGroup("Triggers", "Triggers", false, es);
76 show_relname = (numrels > 1 || targrels != NIL);
77 rInfo = queryDesc->estate->es_result_relations;
78 for (nr = 0; nr < numrels; rInfo++, nr++)
79 report_triggers(rInfo, show_relname, es);
83 rInfo = (ResultRelInfo *) lfirst(l);
84 report_triggers(rInfo, show_relname, es);
87 pgspExplainCloseGroup("Triggers", "Triggers", false, es);
92 pgspExplainOpenGroup(const char *objtype, const char *labelname,
93 bool labeled, ExplainState *es)
95 pgspExplainJSONLineEnding(es);
96 appendStringInfoSpaces(es->str, 2 * es->indent);
99 escape_json(es->str, labelname);
100 appendStringInfoString(es->str, ": ");
102 appendStringInfoChar(es->str, labeled ? '{' : '[');
104 GROUPING_STACK(es) = lcons_int(0, GROUPING_STACK(es));
109 pgspExplainCloseGroup(const char *objtype, const char *labelname,
110 bool labeled, ExplainState *es)
113 appendStringInfoChar(es->str, '\n');
114 appendStringInfoSpaces(es->str, 2 * es->indent);
115 appendStringInfoChar(es->str, labeled ? '}' : ']');
116 GROUPING_STACK(es) = list_delete_first(GROUPING_STACK(es));
120 report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
124 if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
126 for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
128 Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
129 Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
131 char *conname = NULL;
133 /* Must clean up instrumentation state */
137 * We ignore triggers that were never invoked; they likely aren't
138 * relevant to the current query type.
140 if (instr->ntuples == 0)
143 pgspExplainOpenGroup("Trigger", NULL, true, es);
145 relname = RelationGetRelationName(rInfo->ri_RelationDesc);
146 if (OidIsValid(trig->tgconstraint))
147 conname = get_constraint_name(trig->tgconstraint);
149 pgspExplainPropertyText("Trigger Name", trig->tgname, es);
151 pgspExplainPropertyText("Constraint Name", conname, es);
152 pgspExplainPropertyText("Relation", relname, es);
153 pgspExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
154 pgspExplainPropertyFloat("Calls", instr->ntuples, 0, es);
159 pgspExplainCloseGroup("Trigger", NULL, true, es);
164 pgspExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
166 pgspExplainProperty(qlabel, value, false, es);
170 pgspExplainPropertyFloat(const char *qlabel, double value, int ndigits,
175 snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
176 pgspExplainProperty(qlabel, buf, true, es);
181 pgspExplainProperty(const char *qlabel, const char *value, bool numeric,
184 pgspExplainJSONLineEnding(es);
185 appendStringInfoSpaces(es->str, es->indent * 2);
186 escape_json(es->str, qlabel);
187 appendStringInfoString(es->str, ": ");
189 appendStringInfoString(es->str, value);
191 escape_json(es->str, value);
195 pgspExplainJSONLineEnding(ExplainState *es)
197 Assert(es->format == EXPLAIN_FORMAT_JSON);
198 if (linitial_int(GROUPING_STACK(es)) != 0)
199 appendStringInfoChar(es->str, ',');
201 linitial_int(GROUPING_STACK(es)) = 1;
202 appendStringInfoChar(es->str, '\n');