mirror of
https://github.com/postgres/postgres.git
synced 2025-05-17 06:41:24 +03:00
Foreign data wrappers can use this capability for so-called "join pushdown"; that is, instead of executing two separate foreign scans and then joining the results locally, they can generate a path which performs the join on the remote server and then is scanned locally. This commit does not extend postgres_fdw to take advantage of this capability; it just provides the infrastructure. Custom scan providers can use this in a similar way. Previously, it was only possible for a custom scan provider to scan a single relation. Now, it can scan an entire join tree, provided of course that it knows how to produce the same results that the join would have produced if executed normally. KaiGai Kohei, reviewed by Shigeru Hanada, Ashutosh Bapat, and me.
141 lines
3.7 KiB
C
141 lines
3.7 KiB
C
/* ------------------------------------------------------------------------
|
|
*
|
|
* nodeCustom.c
|
|
* Routines to handle execution of custom scan node
|
|
*
|
|
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
|
|
* 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;
|
|
Index scan_relid = cscan->scan.scanrelid;
|
|
|
|
/* 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);
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
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);
|
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
|
|
|
/* Close the heap relation */
|
|
if (node->ss.ss_currentRelation)
|
|
ExecCloseScanRelation(node->ss.ss_currentRelation);
|
|
}
|
|
|
|
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);
|
|
}
|