* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.131 2005/03/25 21:57:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.132 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
TupOutputState *tstate);
-static double elapsed_time(instr_time * starttime);
+static double elapsed_time(instr_time *starttime);
static void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
{
int nt;
- if (!rInfo->ri_TrigDesc)
+ if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
continue;
for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
{
/* Compute elapsed time in seconds since given timestamp */
static double
-elapsed_time(instr_time * starttime)
+elapsed_time(instr_time *starttime)
{
instr_time endtime;
* We have to forcibly clean up the instrumentation state because
* we haven't done ExecutorEnd yet. This is pretty grotty ...
*/
- InstrEndLoop(planstate->instrument);
+ if (planstate->instrument)
+ InstrEndLoop(planstate->instrument);
if (planstate->instrument && planstate->instrument->nloops > 0)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.48 2005/04/06 20:13:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.49 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return result;
}
+
+/* ----------------------------------------------------------------
+ * MultiExecProcNode
+ *
+ * Execute a node that doesn't return individual tuples
+ * (it might return a hashtable, bitmap, etc). Caller should
+ * check it got back the expected kind of Node.
+ *
+ * This has essentially the same responsibilities as ExecProcNode,
+ * but it does not do InstrStartNode/InstrStopNode (mainly because
+ * it can't tell how many returned tuples to count). Each per-node
+ * function must provide its own instrumentation support.
+ * ----------------------------------------------------------------
+ */
+Node *
+MultiExecProcNode(PlanState *node)
+{
+ Node *result;
+
+ CHECK_FOR_INTERRUPTS();
+
+ if (node->chgParam != NULL) /* something changed */
+ ExecReScan(node, NULL); /* let ReScan handle this */
+
+ switch (nodeTag(node))
+ {
+ /*
+ * Only node types that actually support multiexec will be listed
+ */
+
+ case T_HashState:
+ result = MultiExecHash((HashState *) node);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
+ result = NULL;
+ break;
+ }
+
+ return result;
+}
+
+
/*
* ExecCountSlotsNode - count up the number of tuple table slots needed
*
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/instrument.c,v 1.11 2005/03/25 21:57:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/instrument.c,v 1.12 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
void
InstrStartNode(Instrumentation *instr)
{
- if (!instr)
- return;
-
- if (!INSTR_TIME_IS_ZERO(instr->starttime))
- elog(DEBUG2, "InstrStartNode called twice in a row");
- else
+ if (INSTR_TIME_IS_ZERO(instr->starttime))
INSTR_TIME_SET_CURRENT(instr->starttime);
+ else
+ elog(DEBUG2, "InstrStartNode called twice in a row");
}
/* Exit from a plan node */
{
instr_time endtime;
- if (!instr)
- return;
+ /* count the returned tuples */
+ if (returnedTuple)
+ instr->tuplecount += 1;
if (INSTR_TIME_IS_ZERO(instr->starttime))
{
- elog(DEBUG2, "InstrStopNode without start");
+ elog(DEBUG2, "InstrStopNode called without start");
return;
}
instr->running = true;
instr->firsttuple = INSTR_TIME_GET_DOUBLE(instr->counter);
}
+}
- if (returnedTuple)
- instr->tuplecount += 1;
+/* As above, but count multiple tuples returned at once */
+void
+InstrStopNodeMulti(Instrumentation *instr, double nTuples)
+{
+ /* count the returned tuples */
+ instr->tuplecount += nTuples;
+
+ /* delegate the rest */
+ InstrStopNode(instr, false);
}
/* Finish a run cycle for a plan node */
{
double totaltime;
- if (!instr)
- return;
-
/* Skip if nothing has happened, or already shut down */
if (!instr->running)
return;
- /* Accumulate statistics */
+ if (!INSTR_TIME_IS_ZERO(instr->starttime))
+ elog(DEBUG2, "InstrEndLoop called on running node");
+
+ /* Accumulate per-cycle statistics into totals */
totaltime = INSTR_TIME_GET_DOUBLE(instr->counter);
instr->startup += instr->firsttuple;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.92 2005/03/31 02:02:52 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.93 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecHash - generate an in-memory hash table of the relation
+ * MultiExecHash - generate an in-memory hash table of the relation
* ExecInitHash - initialize node and subnodes
* ExecEndHash - shutdown node and subnodes
*/
#include "executor/execdebug.h"
#include "executor/hashjoin.h"
+#include "executor/instrument.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
/* ----------------------------------------------------------------
* ExecHash
*
- * build hash table for hashjoin, doing partitioning if more
- * than one batch is required.
+ * stub for pro forma compliance
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecHash(HashState *node)
+{
+ elog(ERROR, "Hash node does not support ExecProcNode call convention");
+ return NULL;
+}
+
+/* ----------------------------------------------------------------
+ * MultiExecHash
+ *
+ * build hash table for hashjoin, doing partitioning if more
+ * than one batch is required.
+ * ----------------------------------------------------------------
+ */
+Node *
+MultiExecHash(HashState *node)
{
PlanState *outerNode;
List *hashkeys;
ExprContext *econtext;
uint32 hashvalue;
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStartNode(node->ps.instrument);
+
/*
* get state info from node
*/
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
- hashtable->hashNonEmpty = true;
+ hashtable->totalTuples += 1;
/* We have to compute the hash value */
econtext->ecxt_innertuple = slot;
hashvalue = ExecHashGetHashValue(hashtable, econtext, hashkeys);
ExecHashTableInsert(hashtable, ExecFetchSlotTuple(slot), hashvalue);
}
- /* We needn't return a tuple slot or anything else */
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStopNodeMulti(node->ps.instrument, hashtable->totalTuples);
+
+ /*
+ * We do not return the hash table directly because it's not a subtype
+ * of Node, and so would violate the MultiExecProcNode API. Instead,
+ * our parent Hashjoin node is expected to know how to fish it out
+ * of our node state. Ugly but not really worth cleaning up, since
+ * Hashjoin knows quite a bit more about Hash besides that.
+ */
return NULL;
}
hashtable->nbatch_original = nbatch;
hashtable->nbatch_outstart = nbatch;
hashtable->growEnabled = true;
- hashtable->hashNonEmpty = false;
+ hashtable->totalTuples = 0;
hashtable->innerBatchFile = NULL;
hashtable->outerBatchFile = NULL;
hashtable->spaceUsed = 0;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.70 2005/03/31 02:02:52 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.71 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* execute the Hash node, to build the hash table
*/
hashNode->hashtable = hashtable;
- (void) ExecProcNode((PlanState *) hashNode);
+ (void) MultiExecProcNode((PlanState *) hashNode);
/*
* If the inner relation is completely empty, and we're not doing
* an outer join, we can quit without scanning the outer relation.
*/
- if (!hashtable->hashNonEmpty && node->js.jointype != JOIN_LEFT)
+ if (hashtable->totalTuples == 0 && node->js.jointype != JOIN_LEFT)
{
ExecHashTableDestroy(hashtable);
node->hj_HashTable = NULL;
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.117 2005/03/16 21:38:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.118 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate);
extern TupleTableSlot *ExecProcNode(PlanState *node);
+extern Node *MultiExecProcNode(PlanState *node);
extern int ExecCountSlotsNode(Plan *node);
extern void ExecEndNode(PlanState *node);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/hashjoin.h,v 1.35 2005/03/06 22:15:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/hashjoin.h,v 1.36 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool growEnabled; /* flag to shut off nbatch increases */
- bool hashNonEmpty; /* did inner plan produce any rows? */
+ double totalTuples; /* # tuples obtained from inner plan */
/*
* These arrays are allocated for the life of the hash join, but
*
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/executor/instrument.h,v 1.10 2005/03/25 21:57:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/instrument.h,v 1.11 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Info about current plan cycle: */
bool running; /* TRUE if we've completed first tuple */
instr_time starttime; /* Start time of current iteration of node */
- instr_time counter; /* Accumulates runtime for this node */
+ instr_time counter; /* Accumulated runtime for this node */
double firsttuple; /* Time for first tuple of this cycle */
- double tuplecount; /* Tuples so far this cycle */
+ double tuplecount; /* Tuples emitted so far this cycle */
/* Accumulated statistics across all completed cycles: */
double startup; /* Total startup time (in seconds) */
double total; /* Total total time (in seconds) */
extern Instrumentation *InstrAlloc(int n);
extern void InstrStartNode(Instrumentation *instr);
extern void InstrStopNode(Instrumentation *instr, bool returnedTuple);
+extern void InstrStopNodeMulti(Instrumentation *instr, double nTuples);
extern void InstrEndLoop(Instrumentation *instr);
#endif /* INSTRUMENT_H */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.36 2005/03/06 22:15:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.37 2005/04/16 20:07:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern int ExecCountSlotsHash(Hash *node);
extern HashState *ExecInitHash(Hash *node, EState *estate);
extern TupleTableSlot *ExecHash(HashState *node);
+extern Node *MultiExecHash(HashState *node);
extern void ExecEndHash(HashState *node);
extern void ExecReScanHash(HashState *node, ExprContext *exprCtxt);