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
|
|
|
*
|
2001-01-24 20:43:33 +01:00
|
|
|
* Portions Copyright (c) 1996-2001, 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
|
2001-03-22 05:01:46 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.34 2001/03/22 03:59:28 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"
|
|
|
|
|
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
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* The first time this is called, ExecMaterial retrieves tuples
|
2000-06-19 00:44:35 +02:00
|
|
|
* from this node's outer subplan and inserts them into a tuplestore
|
2001-03-22 05:01:46 +01:00
|
|
|
* (a temporary tuple storage structure). The first tuple is then
|
2000-06-19 00:44:35 +02:00
|
|
|
* returned. Successive calls to ExecMaterial return successive
|
|
|
|
* tuples from the tuplestore.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Initial State:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-06-19 00:44:35 +02:00
|
|
|
* matstate->tuplestorestate is initially NULL, indicating we
|
|
|
|
* haven't yet collected the results of the subplan.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot * /* result tuple from subplan */
|
1997-09-08 23:56:23 +02:00
|
|
|
ExecMaterial(Material *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
EState *estate;
|
|
|
|
MaterialState *matstate;
|
|
|
|
ScanDirection dir;
|
2000-06-19 00:44:35 +02:00
|
|
|
Tuplestorestate *tuplestorestate;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple heapTuple;
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot *slot;
|
2000-06-19 00:44:35 +02:00
|
|
|
bool should_free;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* get state info from node
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
matstate = node->matstate;
|
|
|
|
estate = node->plan.state;
|
|
|
|
dir = estate->es_direction;
|
2000-06-19 00:44:35 +02:00
|
|
|
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* If first time through, read all tuples from outer plan and
|
|
|
|
* pass them to tuplestore.c.
|
|
|
|
* Subsequent calls just fetch tuples from tuplestore.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
if (tuplestorestate == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-06-19 00:44:35 +02:00
|
|
|
Plan *outerNode;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Want to scan subplan in the forward direction while creating
|
|
|
|
* the stored data. (Does setting my direction actually affect
|
|
|
|
* the subplan? I bet this is useless code...)
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
estate->es_direction = ForwardScanDirection;
|
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Initialize tuplestore module.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2001-03-22 05:01:46 +01:00
|
|
|
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
2000-06-19 00:44:35 +02:00
|
|
|
SortMem);
|
|
|
|
|
|
|
|
matstate->tuplestorestate = (void *) tuplestorestate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Scan the subplan and feed all the tuples to tuplestore.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
outerNode = outerPlan((Plan *) node);
|
2000-06-19 00:44:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
slot = ExecProcNode(outerNode, (Plan *) node);
|
|
|
|
|
1998-11-27 20:52:36 +01:00
|
|
|
if (TupIsNull(slot))
|
1997-09-07 07:04:48 +02:00
|
|
|
break;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
tuplestore_puttuple(tuplestorestate, (void *) slot->val);
|
1997-09-07 07:04:48 +02:00
|
|
|
ExecClearTuple(slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Complete the store.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
tuplestore_donestoring(tuplestorestate);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* restore to user specified direction
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
estate->es_direction = dir;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Get the first or next tuple from tuplestore.
|
|
|
|
* Returns NULL if no more tuples.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
|
|
|
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
|
|
|
ScanDirectionIsForward(dir),
|
|
|
|
&should_free);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecInitMaterial
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
bool /* initialization status */
|
1997-09-08 23:56:23 +02:00
|
|
|
ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
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
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* assign the node's execution state
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
node->plan.state = estate;
|
|
|
|
|
1996-07-09 08:22:35 +02: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);
|
2000-06-19 00:44:35 +02:00
|
|
|
matstate->tuplestorestate = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
node->matstate = matstate;
|
|
|
|
|
|
|
|
/* ----------------
|
2000-07-12 04:37:39 +02:00
|
|
|
* Miscellaneous initialization
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
|
|
|
* Materialization nodes don't need ExprContexts because
|
2000-07-12 04:37:39 +02:00
|
|
|
* they never call ExecQual or ExecProject.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
#define MATERIAL_NSLOTS 1
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* tuple table initialization
|
2000-06-19 00:44:35 +02:00
|
|
|
*
|
|
|
|
* material nodes only return tuples from their materialized
|
|
|
|
* relation.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
|
1997-09-07 07:04:48 +02:00
|
|
|
ExecInitScanTupleSlot(estate, &matstate->csstate);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* initializes child nodes
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
outerPlan = outerPlan((Plan *) node);
|
|
|
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* initialize tuple type. no need to initialize projection
|
|
|
|
* info because this node doesn't do projections.
|
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
|
1997-09-07 07:04:48 +02:00
|
|
|
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
|
|
|
|
matstate->csstate.cstate.cs_ProjInfo = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
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)) +
|
|
|
|
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
|
1997-09-08 23:56:23 +02:00
|
|
|
ExecEndMaterial(Material *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
MaterialState *matstate;
|
|
|
|
Plan *outerPlan;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get info from the material state
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
matstate = node->matstate;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* shut down the subplan
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
outerPlan = outerPlan((Plan *) node);
|
|
|
|
ExecEndNode(outerPlan, (Plan *) node);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* clean out the tuple table
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
|
2000-03-02 05:06:39 +01:00
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* Release tuplestore resources
|
2000-03-02 05:06:39 +01:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
if (matstate->tuplestorestate != NULL)
|
|
|
|
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
|
|
|
matstate->tuplestorestate = NULL;
|
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
|
2000-06-19 00:44:35 +02:00
|
|
|
ExecMaterialMarkPos(Material *node)
|
1998-02-13 04:26:53 +01:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
MaterialState *matstate = node->matstate;
|
1998-02-13 04:26:53 +01:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
/* ----------------
|
|
|
|
* if we haven't materialized yet, just return.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (!matstate->tuplestorestate)
|
1998-02-13 04:26:53 +01:00
|
|
|
return;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
tuplestore_markpos((Tuplestorestate *) matstate->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
|
|
|
|
ExecMaterialRestrPos(Material *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
MaterialState *matstate = node->matstate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* if we haven't materialized yet, just return.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
if (!matstate->tuplestorestate)
|
|
|
|
return;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
2000-06-19 00:44:35 +02:00
|
|
|
* restore the scan to the previously marked position
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
tuplestore_restorepos((Tuplestorestate *) matstate->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
|
2000-06-19 00:44:35 +02:00
|
|
|
ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-19 00:44:35 +02:00
|
|
|
MaterialState *matstate = node->matstate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
/*
|
2001-03-22 05:01:46 +01: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
|
2000-06-19 00:44:35 +02:00
|
|
|
* reason to re-scan it at all.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
if (!matstate->tuplestorestate)
|
1997-09-07 07:04:48 +02:00
|
|
|
return;
|
|
|
|
|
2000-06-19 00:44:35 +02:00
|
|
|
ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
|
|
|
|
|
|
|
|
/*
|
2001-03-22 05:01:46 +01: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
|
|
|
*
|
|
|
|
* Otherwise we can just rewind and rescan the stored output.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
if (((Plan *) node)->lefttree->chgParam != NULL)
|
|
|
|
{
|
|
|
|
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
|
|
|
matstate->tuplestorestate = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|