1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Create a new 'MultiExecProcNode' call API for plan nodes that don't

return just a single tuple at a time.  Currently the only such node
type is Hash, but I expect we will soon have indexscans that can return
tuple bitmaps.  A side benefit is that EXPLAIN ANALYZE now shows the
correct tuple count for a Hash node.
This commit is contained in:
Tom Lane
2005-04-16 20:07:35 +00:00
parent 85eee28cec
commit d8b1bf4791
9 changed files with 121 additions and 39 deletions

View File

@ -12,7 +12,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -375,6 +375,50 @@ ExecProcNode(PlanState *node)
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
*

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -33,13 +33,10 @@ InstrAlloc(int n)
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 */
@ -48,12 +45,13 @@ InstrStopNode(Instrumentation *instr, bool returnedTuple)
{
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;
}
@ -86,9 +84,17 @@ InstrStopNode(Instrumentation *instr, bool returnedTuple)
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 */
@ -97,14 +103,14 @@ InstrEndLoop(Instrumentation *instr)
{
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;

View File

@ -8,13 +8,13 @@
*
*
* 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
*/
@ -22,6 +22,7 @@
#include "executor/execdebug.h"
#include "executor/hashjoin.h"
#include "executor/instrument.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
@ -36,12 +37,25 @@ static void ExecHashIncreaseNumBatches(HashJoinTable hashtable);
/* ----------------------------------------------------------------
* 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;
@ -50,6 +64,10 @@ ExecHash(HashState *node)
ExprContext *econtext;
uint32 hashvalue;
/* must provide our own instrumentation support */
if (node->ps.instrument)
InstrStartNode(node->ps.instrument);
/*
* get state info from node
*/
@ -70,14 +88,24 @@ ExecHash(HashState *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;
}
@ -220,7 +248,7 @@ ExecHashTableCreate(Hash *node, List *hashOperators)
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;

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -123,13 +123,13 @@ ExecHashJoin(HashJoinState *node)
* 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;