2014-11-07 23:26:02 +01:00
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* nodeCustom.c
|
|
|
|
* Routines to handle execution of custom scan node
|
|
|
|
*
|
2015-01-06 17:43:47 +01:00
|
|
|
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
|
2014-11-07 23:26:02 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* ------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "executor/executor.h"
|
|
|
|
#include "executor/nodeCustom.h"
|
|
|
|
#include "nodes/execnodes.h"
|
|
|
|
#include "nodes/plannodes.h"
|
|
|
|
#include "parser/parsetree.h"
|
|
|
|
#include "utils/hsearch.h"
|
|
|
|
#include "utils/memutils.h"
|
|
|
|
#include "utils/rel.h"
|
|
|
|
|
|
|
|
CustomScanState *
|
|
|
|
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
|
|
|
|
{
|
|
|
|
CustomScanState *css;
|
2015-05-01 14:50:35 +02:00
|
|
|
Index scan_relid = cscan->scan.scanrelid;
|
2014-11-07 23:26:02 +01:00
|
|
|
|
|
|
|
/* populate a CustomScanState according to the CustomScan */
|
|
|
|
css = (CustomScanState *) cscan->methods->CreateCustomScanState(cscan);
|
|
|
|
Assert(IsA(css, CustomScanState));
|
|
|
|
|
|
|
|
/* fill up fields of ScanState */
|
|
|
|
css->ss.ps.plan = &cscan->scan.plan;
|
|
|
|
css->ss.ps.state = estate;
|
|
|
|
|
|
|
|
/* create expression context for node */
|
|
|
|
ExecAssignExprContext(estate, &css->ss.ps);
|
|
|
|
|
|
|
|
/* initialize child expressions */
|
|
|
|
css->ss.ps.targetlist = (List *)
|
|
|
|
ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
|
|
|
|
(PlanState *) css);
|
|
|
|
css->ss.ps.qual = (List *)
|
|
|
|
ExecInitExpr((Expr *) cscan->scan.plan.qual,
|
|
|
|
(PlanState *) css);
|
|
|
|
|
|
|
|
/* tuple table initialization */
|
|
|
|
ExecInitScanTupleSlot(estate, &css->ss);
|
|
|
|
ExecInitResultTupleSlot(estate, &css->ss.ps);
|
|
|
|
|
2015-05-01 14:50:35 +02:00
|
|
|
/*
|
|
|
|
* open the base relation and acquire an appropriate lock on it;
|
|
|
|
* also, get and assign the scan type
|
|
|
|
*/
|
|
|
|
if (scan_relid > 0)
|
|
|
|
{
|
|
|
|
Relation scan_rel;
|
|
|
|
|
|
|
|
scan_rel = ExecOpenScanRelation(estate, scan_relid, eflags);
|
|
|
|
css->ss.ss_currentRelation = scan_rel;
|
|
|
|
css->ss.ss_currentScanDesc = NULL; /* set by provider */
|
|
|
|
ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TupleDesc ps_tupdesc;
|
|
|
|
|
|
|
|
ps_tupdesc = ExecCleanTypeFromTL(cscan->custom_ps_tlist, false);
|
|
|
|
ExecAssignScanType(&css->ss, ps_tupdesc);
|
|
|
|
}
|
2014-11-07 23:26:02 +01:00
|
|
|
css->ss.ps.ps_TupFromTlist = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize result tuple type and projection info.
|
|
|
|
*/
|
|
|
|
ExecAssignResultTypeFromTL(&css->ss.ps);
|
|
|
|
ExecAssignScanProjectionInfo(&css->ss);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The callback of custom-scan provider applies the final initialization
|
|
|
|
* of the custom-scan-state node according to its logic.
|
|
|
|
*/
|
|
|
|
css->methods->BeginCustomScan(css, estate, eflags);
|
|
|
|
|
|
|
|
return css;
|
|
|
|
}
|
|
|
|
|
|
|
|
TupleTableSlot *
|
|
|
|
ExecCustomScan(CustomScanState *node)
|
|
|
|
{
|
|
|
|
Assert(node->methods->ExecCustomScan != NULL);
|
|
|
|
return node->methods->ExecCustomScan(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExecEndCustomScan(CustomScanState *node)
|
|
|
|
{
|
|
|
|
Assert(node->methods->EndCustomScan != NULL);
|
|
|
|
node->methods->EndCustomScan(node);
|
|
|
|
|
|
|
|
/* Free the exprcontext */
|
|
|
|
ExecFreeExprContext(&node->ss.ps);
|
|
|
|
|
|
|
|
/* Clean out the tuple table */
|
|
|
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
2015-05-01 14:50:35 +02:00
|
|
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
2014-11-07 23:26:02 +01:00
|
|
|
|
|
|
|
/* Close the heap relation */
|
2015-05-01 14:50:35 +02:00
|
|
|
if (node->ss.ss_currentRelation)
|
|
|
|
ExecCloseScanRelation(node->ss.ss_currentRelation);
|
2014-11-07 23:26:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExecReScanCustomScan(CustomScanState *node)
|
|
|
|
{
|
|
|
|
Assert(node->methods->ReScanCustomScan != NULL);
|
|
|
|
node->methods->ReScanCustomScan(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExecCustomMarkPos(CustomScanState *node)
|
|
|
|
{
|
|
|
|
if (!node->methods->MarkPosCustomScan)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("custom-scan \"%s\" does not support MarkPos",
|
|
|
|
node->methods->CustomName)));
|
|
|
|
node->methods->MarkPosCustomScan(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExecCustomRestrPos(CustomScanState *node)
|
|
|
|
{
|
|
|
|
if (!node->methods->RestrPosCustomScan)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("custom-scan \"%s\" does not support MarkPos",
|
|
|
|
node->methods->CustomName)));
|
|
|
|
node->methods->RestrPosCustomScan(node);
|
|
|
|
}
|