summaryrefslogtreecommitdiffstats
path: root/src/backend/executor/nodeCustom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeCustom.c')
-rw-r--r--src/backend/executor/nodeCustom.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
new file mode 100644
index 0000000..c82060e
--- /dev/null
+++ b/src/backend/executor/nodeCustom.c
@@ -0,0 +1,228 @@
+/* ------------------------------------------------------------------------
+ *
+ * nodeCustom.c
+ * Routines to handle execution of custom scan node
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * ------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/parallel.h"
+#include "executor/executor.h"
+#include "executor/nodeCustom.h"
+#include "miscadmin.h"
+#include "nodes/execnodes.h"
+#include "nodes/extensible.h"
+#include "nodes/plannodes.h"
+#include "parser/parsetree.h"
+#include "utils/hsearch.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+
+static TupleTableSlot *ExecCustomScan(PlanState *pstate);
+
+
+CustomScanState *
+ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
+{
+ CustomScanState *css;
+ Relation scan_rel = NULL;
+ Index scanrelid = cscan->scan.scanrelid;
+ Index tlistvarno;
+
+ /*
+ * Allocate the CustomScanState object. We let the custom scan provider
+ * do the palloc, in case it wants to make a larger object that embeds
+ * CustomScanState as the first field. It must set the node tag and the
+ * methods field correctly at this time. Other standard fields should be
+ * set to zero.
+ */
+ css = castNode(CustomScanState,
+ cscan->methods->CreateCustomScanState(cscan));
+
+ /* ensure flags is filled correctly */
+ css->flags = cscan->flags;
+
+ /* fill up fields of ScanState */
+ css->ss.ps.plan = &cscan->scan.plan;
+ css->ss.ps.state = estate;
+ css->ss.ps.ExecProcNode = ExecCustomScan;
+
+ /* create expression context for node */
+ ExecAssignExprContext(estate, &css->ss.ps);
+
+ /*
+ * open the scan relation, if any
+ */
+ if (scanrelid > 0)
+ {
+ scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags);
+ css->ss.ss_currentRelation = scan_rel;
+ }
+
+ /*
+ * Determine the scan tuple type. If the custom scan provider provided a
+ * targetlist describing the scan tuples, use that; else use base
+ * relation's rowtype.
+ */
+ if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
+ {
+ TupleDesc scan_tupdesc;
+
+ scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist);
+ ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, &TTSOpsVirtual);
+ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
+ tlistvarno = INDEX_VAR;
+ }
+ else
+ {
+ ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel),
+ &TTSOpsVirtual);
+ /* Node's targetlist will contain Vars with varno = scanrelid */
+ tlistvarno = scanrelid;
+ }
+
+ /*
+ * Initialize result slot, type and projection.
+ */
+ ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
+ ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
+
+ /* initialize child expressions */
+ css->ss.ps.qual =
+ ExecInitQual(cscan->scan.plan.qual, (PlanState *) css);
+
+ /*
+ * 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;
+}
+
+static TupleTableSlot *
+ExecCustomScan(PlanState *pstate)
+{
+ CustomScanState *node = castNode(CustomScanState, pstate);
+
+ CHECK_FOR_INTERRUPTS();
+
+ 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);
+}
+
+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);
+}
+
+void
+ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt)
+{
+ const CustomExecMethods *methods = node->methods;
+
+ if (methods->EstimateDSMCustomScan)
+ {
+ node->pscan_len = methods->EstimateDSMCustomScan(node, pcxt);
+ shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
+ shm_toc_estimate_keys(&pcxt->estimator, 1);
+ }
+}
+
+void
+ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
+{
+ const CustomExecMethods *methods = node->methods;
+
+ if (methods->InitializeDSMCustomScan)
+ {
+ int plan_node_id = node->ss.ps.plan->plan_node_id;
+ void *coordinate;
+
+ coordinate = shm_toc_allocate(pcxt->toc, node->pscan_len);
+ methods->InitializeDSMCustomScan(node, pcxt, coordinate);
+ shm_toc_insert(pcxt->toc, plan_node_id, coordinate);
+ }
+}
+
+void
+ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
+{
+ const CustomExecMethods *methods = node->methods;
+
+ if (methods->ReInitializeDSMCustomScan)
+ {
+ int plan_node_id = node->ss.ps.plan->plan_node_id;
+ void *coordinate;
+
+ coordinate = shm_toc_lookup(pcxt->toc, plan_node_id, false);
+ methods->ReInitializeDSMCustomScan(node, pcxt, coordinate);
+ }
+}
+
+void
+ExecCustomScanInitializeWorker(CustomScanState *node,
+ ParallelWorkerContext *pwcxt)
+{
+ const CustomExecMethods *methods = node->methods;
+
+ if (methods->InitializeWorkerCustomScan)
+ {
+ int plan_node_id = node->ss.ps.plan->plan_node_id;
+ void *coordinate;
+
+ coordinate = shm_toc_lookup(pwcxt->toc, plan_node_id, false);
+ methods->InitializeWorkerCustomScan(node, pwcxt->toc, coordinate);
+ }
+}
+
+void
+ExecShutdownCustomScan(CustomScanState *node)
+{
+ const CustomExecMethods *methods = node->methods;
+
+ if (methods->ShutdownCustomScan)
+ methods->ShutdownCustomScan(node);
+}