1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* nodeMaterial.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Routines to handle materialization nodes.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2005-10-15 04:49:52 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.50 2005/10/15 02:49:17 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* INTERFACE ROUTINES
|
2000-06-19 00:44:35 +02:00
|
|
|
* ExecMaterial - materialize the result of a subplan
|
|
|
|
* ExecInitMaterial - initialize node and subnodes
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecEndMaterial - shutdown node and subnodes
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1996-10-31 11:12:26 +01:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2003-03-09 03:19:13 +01:00
|
|
|
#include "access/heapam.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "executor/executor.h"
|
|
|
|
#include "executor/nodeMaterial.h"
|
2000-06-19 00:44:35 +02:00
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "utils/tuplestore.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecMaterial
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2003-03-09 03:19:13 +01:00
|
|
|
* As long as we are at the end of the data collected in the tuplestore,
|
|
|
|
* we collect one new row from the subplan on each call, and stash it
|
|
|
|
* aside in the tuplestore before returning it. The tuplestore is
|
|
|
|
* only read if we are asked to scan backwards, rescan, or mark/restore.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot * /* result tuple from subplan */
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecMaterial(MaterialState *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
EState *estate;
|
|
|
|
ScanDirection dir;
|
2003-03-09 03:19:13 +01:00
|
|
|
bool forward;
|
2000-06-19 00:44:35 +02:00
|
|
|
Tuplestorestate *tuplestorestate;
|
2003-03-09 03:19:13 +01:00
|
|
|
HeapTuple heapTuple = NULL;
|
|
|
|
bool should_free = false;
|
|
|
|
bool eof_tuplestore;
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot *slot;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get state info from node
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
estate = node->ss.ps.state;
|
1997-09-07 07:04:48 +02:00
|
|
|
dir = estate->es_direction;
|
2003-03-09 03:19:13 +01:00
|
|
|
forward = ScanDirectionIsForward(dir);
|
2002-12-05 16:50:39 +01:00
|
|
|
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-03-09 03:19:13 +01:00
|
|
|
* If first time through, initialize the tuplestore.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
if (tuplestorestate == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-02-03 18:34:04 +01:00
|
|
|
tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
|
2000-06-19 00:44:35 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
node->tuplestorestate = (void *) tuplestorestate;
|
2003-03-09 03:19:13 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-03-09 03:19:13 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we are not at the end of the tuplestore, or are going backwards, try
|
|
|
|
* to fetch a tuple from tuplestore.
|
2003-03-09 03:19:13 +01:00
|
|
|
*/
|
|
|
|
eof_tuplestore = tuplestore_ateof(tuplestorestate);
|
2000-06-19 00:44:35 +02:00
|
|
|
|
2003-03-09 03:19:13 +01:00
|
|
|
if (!forward && eof_tuplestore)
|
|
|
|
{
|
|
|
|
if (!node->eof_underlying)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2003-03-09 03:19:13 +01:00
|
|
|
/*
|
|
|
|
* When reversing direction at tuplestore EOF, the first
|
2005-10-15 04:49:52 +02:00
|
|
|
* getheaptuple call will fetch the last-added tuple; but we want
|
|
|
|
* to return the one before that, if possible. So do an extra
|
|
|
|
* fetch.
|
2003-03-09 03:19:13 +01:00
|
|
|
*/
|
|
|
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
|
|
|
forward,
|
|
|
|
&should_free);
|
|
|
|
if (heapTuple == NULL)
|
2003-08-04 02:43:34 +02:00
|
|
|
return NULL; /* the tuplestore must be empty */
|
2003-03-09 03:19:13 +01:00
|
|
|
if (should_free)
|
|
|
|
heap_freetuple(heapTuple);
|
|
|
|
}
|
|
|
|
eof_tuplestore = false;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-03-09 03:19:13 +01:00
|
|
|
if (!eof_tuplestore)
|
|
|
|
{
|
|
|
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
|
|
|
forward,
|
|
|
|
&should_free);
|
|
|
|
if (heapTuple == NULL && forward)
|
|
|
|
eof_tuplestore = true;
|
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2003-03-09 03:19:13 +01:00
|
|
|
/*
|
|
|
|
* If necessary, try to fetch another row from the subplan.
|
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Note: the eof_underlying state variable exists to short-circuit further
|
|
|
|
* subplan calls. It's not optional, unfortunately, because some plan
|
|
|
|
* node types are not robust about being called again when they've already
|
|
|
|
* returned NULL.
|
2003-03-09 03:19:13 +01:00
|
|
|
*/
|
|
|
|
if (eof_tuplestore && !node->eof_underlying)
|
|
|
|
{
|
|
|
|
PlanState *outerNode;
|
|
|
|
TupleTableSlot *outerslot;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We can only get here with forward==true, so no need to worry about
|
|
|
|
* which direction the subplan will go.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2003-03-09 03:19:13 +01:00
|
|
|
outerNode = outerPlanState(node);
|
|
|
|
outerslot = ExecProcNode(outerNode);
|
|
|
|
if (TupIsNull(outerslot))
|
|
|
|
{
|
|
|
|
node->eof_underlying = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-03-16 22:38:10 +01:00
|
|
|
heapTuple = ExecFetchSlotTuple(outerslot);
|
2003-03-09 03:19:13 +01:00
|
|
|
should_free = false;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-03-09 03:19:13 +01:00
|
|
|
* Append returned tuple to tuplestore, too. NOTE: because the
|
2005-10-15 04:49:52 +02:00
|
|
|
* tuplestore is certainly in EOF state, its read position will move
|
|
|
|
* forward over the added tuple. This is what we want.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2003-03-09 03:19:13 +01:00
|
|
|
tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-03-16 22:38:10 +01:00
|
|
|
* Return the obtained tuple, if any.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
|
2005-03-16 22:38:10 +01:00
|
|
|
if (heapTuple)
|
|
|
|
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
|
|
|
else
|
|
|
|
return ExecClearTuple(slot);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecInitMaterial
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
MaterialState *
|
|
|
|
ExecInitMaterial(Material *node, EState *estate)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
MaterialState *matstate;
|
|
|
|
Plan *outerPlan;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* create state structure
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
matstate = makeNode(MaterialState);
|
2002-12-05 16:50:39 +01:00
|
|
|
matstate->ss.ps.plan = (Plan *) node;
|
|
|
|
matstate->ss.ps.state = estate;
|
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
matstate->tuplestorestate = NULL;
|
2003-03-09 03:19:13 +01:00
|
|
|
matstate->eof_underlying = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Miscellaneous initialization
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* Materialization nodes don't need ExprContexts because they never call
|
|
|
|
* ExecQual or ExecProject.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-05-27 22:42:20 +02:00
|
|
|
#define MATERIAL_NSLOTS 2
|
2001-03-22 07:16:21 +01:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* tuple table initialization
|
2000-06-19 00:44:35 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* material nodes only return tuples from their materialized relation.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecInitResultTupleSlot(estate, &matstate->ss.ps);
|
|
|
|
ExecInitScanTupleSlot(estate, &matstate->ss);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* initializes child nodes
|
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
outerPlan = outerPlan(node);
|
|
|
|
outerPlanState(matstate) = ExecInitNode(outerPlan, estate);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* initialize tuple type. no need to initialize projection info because
|
|
|
|
* this node doesn't do projections.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecAssignResultTypeFromOuterPlan(&matstate->ss.ps);
|
|
|
|
ExecAssignScanTypeFromOuterPlan(&matstate->ss);
|
|
|
|
matstate->ss.ps.ps_ProjInfo = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
return matstate;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1997-09-08 23:56:23 +02:00
|
|
|
ExecCountSlotsMaterial(Material *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
2001-10-25 07:50:21 +02:00
|
|
|
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
|
|
|
MATERIAL_NSLOTS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecEndMaterial
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecEndMaterial(MaterialState *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-12-05 16:50:39 +01:00
|
|
|
* clean out the tuple table
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Release tuplestore resources
|
2000-03-02 05:06:39 +01:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
if (node->tuplestorestate != NULL)
|
|
|
|
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
|
|
|
node->tuplestorestate = NULL;
|
2002-12-15 17:17:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* shut down the subplan
|
|
|
|
*/
|
|
|
|
ExecEndNode(outerPlanState(node));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-02-13 04:26:53 +01:00
|
|
|
/* ----------------------------------------------------------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* ExecMaterialMarkPos
|
1998-02-13 04:26:53 +01:00
|
|
|
*
|
2000-06-19 00:44:35 +02:00
|
|
|
* Calls tuplestore to save the current position in the stored file.
|
1998-02-13 04:26:53 +01:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecMaterialMarkPos(MaterialState *node)
|
1998-02-13 04:26:53 +01:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* if we haven't materialized yet, just return.
|
2000-06-19 00:44:35 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
if (!node->tuplestorestate)
|
1998-02-13 04:26:53 +01:00
|
|
|
return;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
|
1998-02-13 04:26:53 +01:00
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* ExecMaterialRestrPos
|
|
|
|
*
|
|
|
|
* Calls tuplestore to restore the last saved file position.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
void
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecMaterialRestrPos(MaterialState *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* if we haven't materialized yet, just return.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
if (!node->tuplestorestate)
|
2000-06-19 00:44:35 +02:00
|
|
|
return;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* restore the scan to the previously marked position
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* ExecMaterialReScan
|
|
|
|
*
|
|
|
|
* Rescans the materialized relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-19 00:44:35 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we haven't materialized yet, just return. If outerplan' chgParam is
|
|
|
|
* not NULL then it will be re-scanned by ExecProcNode, else - no reason
|
|
|
|
* to re-scan it at all.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
if (!node->tuplestorestate)
|
1997-09-07 07:04:48 +02:00
|
|
|
return;
|
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
2000-06-19 00:44:35 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If subnode is to be rescanned then we forget previous stored results;
|
|
|
|
* we have to re-read the subplan and re-store.
|
2000-06-19 00:44:35 +02:00
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Otherwise we can just rewind and rescan the stored output. The state of
|
|
|
|
* the subnode does not change.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
if (((PlanState *) node)->lefttree->chgParam != NULL)
|
2000-06-19 00:44:35 +02:00
|
|
|
{
|
2002-12-05 16:50:39 +01:00
|
|
|
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
|
|
|
node->tuplestorestate = NULL;
|
2003-03-09 03:19:13 +01:00
|
|
|
node->eof_underlying = false;
|
2000-06-19 00:44:35 +02:00
|
|
|
}
|
|
|
|
else
|
2002-12-05 16:50:39 +01:00
|
|
|
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|