aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/explain.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-08-15 21:39:50 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-08-15 21:39:50 +0000
commit817946bb04e1dcac02d85572103f1e1381102a0a (patch)
tree221b38d8cae6163c5d4f9e9248e1555f9042e685 /src/backend/commands/explain.c
parent9cb84097623e5efe32b7289ca3c403f70ee152d8 (diff)
downloadpostgresql-817946bb04e1dcac02d85572103f1e1381102a0a.tar.gz
postgresql-817946bb04e1dcac02d85572103f1e1381102a0a.zip
Arrange to cache a ResultRelInfo in the executor's EState for relations that
are not one of the query's defined result relations, but nonetheless have triggers fired against them while the query is active. This was formerly impossible but can now occur because of my recent patch to fix the firing order for RI triggers. Caching a ResultRelInfo avoids duplicating work by repeatedly opening and closing the same relation, and also allows EXPLAIN ANALYZE to "see" and report on these extra triggers. Use the same mechanism to cache open relations when firing deferred triggers at transaction shutdown; this replaces the former one-element-cache strategy used in that case, and should improve performance a bit when there are deferred triggers on a number of relations.
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r--src/backend/commands/explain.c96
1 files changed, 57 insertions, 39 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 39e8073f55b..c9d454bc497 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.164 2007/05/25 17:54:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.165 2007/08/15 21:39:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -52,6 +52,8 @@ typedef struct ExplainState
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
const char *queryString,
ParamListInfo params, TupOutputState *tstate);
+static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
+ StringInfo buf);
static double elapsed_time(instr_time *starttime);
static void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
@@ -310,50 +312,21 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
if (es->printAnalyze)
{
ResultRelInfo *rInfo;
+ bool show_relname;
int numrels = queryDesc->estate->es_num_result_relations;
+ List *targrels = queryDesc->estate->es_trig_target_relations;
int nr;
+ ListCell *l;
+ show_relname = (numrels > 1 || targrels != NIL);
rInfo = queryDesc->estate->es_result_relations;
for (nr = 0; nr < numrels; rInfo++, nr++)
- {
- int nt;
-
- if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
- continue;
- for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
- {
- Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
- Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
- char *conname;
+ report_triggers(rInfo, show_relname, &buf);
- /* Must clean up instrumentation state */
- InstrEndLoop(instr);
-
- /*
- * We ignore triggers that were never invoked; they likely
- * aren't relevant to the current query type.
- */
- if (instr->ntuples == 0)
- continue;
-
- if (OidIsValid(trig->tgconstraint) &&
- (conname = get_constraint_name(trig->tgconstraint)) != NULL)
- {
- appendStringInfo(&buf, "Trigger for constraint %s",
- conname);
- pfree(conname);
- }
- else
- appendStringInfo(&buf, "Trigger %s", trig->tgname);
-
- if (numrels > 1)
- appendStringInfo(&buf, " on %s",
- RelationGetRelationName(rInfo->ri_RelationDesc));
-
- appendStringInfo(&buf, ": time=%.3f calls=%.0f\n",
- 1000.0 * instr->total,
- instr->ntuples);
- }
+ foreach(l, targrels)
+ {
+ rInfo = (ResultRelInfo *) lfirst(l);
+ report_triggers(rInfo, show_relname, &buf);
}
}
@@ -382,6 +355,51 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
pfree(es);
}
+/*
+ * report_triggers -
+ * report execution stats for a single relation's triggers
+ */
+static void
+report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo buf)
+{
+ int nt;
+
+ if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
+ return;
+ for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
+ {
+ Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
+ Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
+ char *conname;
+
+ /* Must clean up instrumentation state */
+ InstrEndLoop(instr);
+
+ /*
+ * We ignore triggers that were never invoked; they likely
+ * aren't relevant to the current query type.
+ */
+ if (instr->ntuples == 0)
+ continue;
+
+ if (OidIsValid(trig->tgconstraint) &&
+ (conname = get_constraint_name(trig->tgconstraint)) != NULL)
+ {
+ appendStringInfo(buf, "Trigger for constraint %s", conname);
+ pfree(conname);
+ }
+ else
+ appendStringInfo(buf, "Trigger %s", trig->tgname);
+
+ if (show_relname)
+ appendStringInfo(buf, " on %s",
+ RelationGetRelationName(rInfo->ri_RelationDesc));
+
+ appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
+ 1000.0 * instr->total, instr->ntuples);
+ }
+}
+
/* Compute elapsed time in seconds since given timestamp */
static double
elapsed_time(instr_time *starttime)