Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0b03e59

Browse files
committed
Introduce custom path and scan providers.
This allows extension modules to define their own methods for scanning a relation, and get the core code to use them. It's unclear as yet how much use this capability will find, but we won't find out if we never commit it. KaiGai Kohei, reviewed at various times and in various levels of detail by Shigeru Hanada, Tom Lane, Andres Freund, Álvaro Herrera, and myself.
1 parent 7250d85 commit 0b03e59

22 files changed

+638
-10
lines changed

src/backend/commands/explain.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
724724
case T_CteScan:
725725
case T_WorkTableScan:
726726
case T_ForeignScan:
727+
case T_CustomScan:
727728
*rels_used = bms_add_member(*rels_used,
728729
((Scan *) plan)->scanrelid);
729730
break;
@@ -853,6 +854,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
853854
const char *sname; /* node type name for non-text output */
854855
const char *strategy = NULL;
855856
const char *operation = NULL;
857+
const char *custom_name = NULL;
856858
int save_indent = es->indent;
857859
bool haschildren;
858860

@@ -941,6 +943,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
941943
case T_ForeignScan:
942944
pname = sname = "Foreign Scan";
943945
break;
946+
case T_CustomScan:
947+
sname = "Custom Scan";
948+
custom_name = ((CustomScan *) plan)->methods->CustomName;
949+
if (custom_name)
950+
pname = psprintf("Custom Scan (%s)", custom_name);
951+
else
952+
pname = sname;
953+
break;
944954
case T_Material:
945955
pname = sname = "Materialize";
946956
break;
@@ -1042,6 +1052,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
10421052
ExplainPropertyText("Parent Relationship", relationship, es);
10431053
if (plan_name)
10441054
ExplainPropertyText("Subplan Name", plan_name, es);
1055+
if (custom_name)
1056+
ExplainPropertyText("Custom Plan Provider", custom_name, es);
10451057
}
10461058

10471059
switch (nodeTag(plan))
@@ -1055,6 +1067,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
10551067
case T_CteScan:
10561068
case T_WorkTableScan:
10571069
case T_ForeignScan:
1070+
case T_CustomScan:
10581071
ExplainScanTarget((Scan *) plan, es);
10591072
break;
10601073
case T_IndexScan:
@@ -1358,6 +1371,18 @@ ExplainNode(PlanState *planstate, List *ancestors,
13581371
planstate, es);
13591372
show_foreignscan_info((ForeignScanState *) planstate, es);
13601373
break;
1374+
case T_CustomScan:
1375+
{
1376+
CustomScanState *css = (CustomScanState *) planstate;
1377+
1378+
show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1379+
if (plan->qual)
1380+
show_instrumentation_count("Rows Removed by Filter", 1,
1381+
planstate, es);
1382+
if (css->methods->ExplainCustomScan)
1383+
css->methods->ExplainCustomScan(css, ancestors, es);
1384+
}
1385+
break;
13611386
case T_NestLoop:
13621387
show_upper_qual(((NestLoop *) plan)->join.joinqual,
13631388
"Join Filter", planstate, ancestors, es);

src/backend/executor/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ OBJS = execAmi.o execCurrent.o execGrouping.o execJunk.o execMain.o \
1616
execProcnode.o execQual.o execScan.o execTuples.o \
1717
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
1818
nodeBitmapAnd.o nodeBitmapOr.o \
19-
nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeHash.o \
19+
nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeCustom.o nodeHash.o \
2020
nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \
2121
nodeLimit.o nodeLockRows.o \
2222
nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeModifyTable.o \

src/backend/executor/execAmi.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "executor/nodeBitmapIndexscan.h"
2222
#include "executor/nodeBitmapOr.h"
2323
#include "executor/nodeCtescan.h"
24+
#include "executor/nodeCustom.h"
2425
#include "executor/nodeForeignscan.h"
2526
#include "executor/nodeFunctionscan.h"
2627
#include "executor/nodeGroup.h"
@@ -49,6 +50,7 @@
4950
#include "executor/nodeWindowAgg.h"
5051
#include "executor/nodeWorktablescan.h"
5152
#include "nodes/nodeFuncs.h"
53+
#include "nodes/relation.h"
5254
#include "utils/rel.h"
5355
#include "utils/syscache.h"
5456

@@ -197,6 +199,10 @@ ExecReScan(PlanState *node)
197199
ExecReScanForeignScan((ForeignScanState *) node);
198200
break;
199201

202+
case T_CustomScanState:
203+
ExecReScanCustomScan((CustomScanState *) node);
204+
break;
205+
200206
case T_NestLoopState:
201207
ExecReScanNestLoop((NestLoopState *) node);
202208
break;
@@ -291,6 +297,10 @@ ExecMarkPos(PlanState *node)
291297
ExecValuesMarkPos((ValuesScanState *) node);
292298
break;
293299

300+
case T_CustomScanState:
301+
ExecCustomMarkPos((CustomScanState *) node);
302+
break;
303+
294304
case T_MaterialState:
295305
ExecMaterialMarkPos((MaterialState *) node);
296306
break;
@@ -348,6 +358,10 @@ ExecRestrPos(PlanState *node)
348358
ExecValuesRestrPos((ValuesScanState *) node);
349359
break;
350360

361+
case T_CustomScanState:
362+
ExecCustomRestrPos((CustomScanState *) node);
363+
break;
364+
351365
case T_MaterialState:
352366
ExecMaterialRestrPos((MaterialState *) node);
353367
break;
@@ -379,9 +393,9 @@ ExecRestrPos(PlanState *node)
379393
* and valuesscan support is actually useless code at present.)
380394
*/
381395
bool
382-
ExecSupportsMarkRestore(NodeTag plantype)
396+
ExecSupportsMarkRestore(Path *pathnode)
383397
{
384-
switch (plantype)
398+
switch (pathnode->pathtype)
385399
{
386400
case T_SeqScan:
387401
case T_IndexScan:
@@ -403,6 +417,16 @@ ExecSupportsMarkRestore(NodeTag plantype)
403417
*/
404418
return false;
405419

420+
case T_CustomScan:
421+
{
422+
CustomPath *cpath = (CustomPath *) pathnode;
423+
424+
Assert(IsA(cpath, CustomPath));
425+
if (cpath->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
426+
return true;
427+
}
428+
break;
429+
406430
default:
407431
break;
408432
}
@@ -465,6 +489,16 @@ ExecSupportsBackwardScan(Plan *node)
465489
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
466490
TargetListSupportsBackwardScan(node->targetlist);
467491

492+
case T_CustomScan:
493+
{
494+
uint32 flags = ((CustomScan *) node)->flags;
495+
496+
if (TargetListSupportsBackwardScan(node->targetlist) &&
497+
(flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) != 0)
498+
return true;
499+
}
500+
return false;
501+
468502
case T_Material:
469503
case T_Sort:
470504
/* these don't evaluate tlist */

src/backend/executor/execProcnode.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#include "executor/nodeBitmapIndexscan.h"
8686
#include "executor/nodeBitmapOr.h"
8787
#include "executor/nodeCtescan.h"
88+
#include "executor/nodeCustom.h"
8889
#include "executor/nodeForeignscan.h"
8990
#include "executor/nodeFunctionscan.h"
9091
#include "executor/nodeGroup.h"
@@ -244,6 +245,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
244245
estate, eflags);
245246
break;
246247

248+
case T_CustomScan:
249+
result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
250+
estate, eflags);
251+
break;
252+
247253
/*
248254
* join nodes
249255
*/
@@ -442,6 +448,10 @@ ExecProcNode(PlanState *node)
442448
result = ExecForeignScan((ForeignScanState *) node);
443449
break;
444450

451+
case T_CustomScanState:
452+
result = ExecCustomScan((CustomScanState *) node);
453+
break;
454+
445455
/*
446456
* join nodes
447457
*/
@@ -678,6 +688,10 @@ ExecEndNode(PlanState *node)
678688
ExecEndForeignScan((ForeignScanState *) node);
679689
break;
680690

691+
case T_CustomScanState:
692+
ExecEndCustomScan((CustomScanState *) node);
693+
break;
694+
681695
/*
682696
* join nodes
683697
*/

src/backend/executor/nodeCustom.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* ------------------------------------------------------------------------
2+
*
3+
* nodeCustom.c
4+
* Routines to handle execution of custom scan node
5+
*
6+
* Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* ------------------------------------------------------------------------
10+
*/
11+
#include "postgres.h"
12+
13+
#include "executor/executor.h"
14+
#include "executor/nodeCustom.h"
15+
#include "nodes/execnodes.h"
16+
#include "nodes/plannodes.h"
17+
#include "parser/parsetree.h"
18+
#include "utils/hsearch.h"
19+
#include "utils/memutils.h"
20+
#include "utils/rel.h"
21+
22+
CustomScanState *
23+
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
24+
{
25+
CustomScanState *css;
26+
Relation scan_rel;
27+
28+
/* populate a CustomScanState according to the CustomScan */
29+
css = (CustomScanState *) cscan->methods->CreateCustomScanState(cscan);
30+
Assert(IsA(css, CustomScanState));
31+
32+
/* fill up fields of ScanState */
33+
css->ss.ps.plan = &cscan->scan.plan;
34+
css->ss.ps.state = estate;
35+
36+
/* create expression context for node */
37+
ExecAssignExprContext(estate, &css->ss.ps);
38+
39+
/* initialize child expressions */
40+
css->ss.ps.targetlist = (List *)
41+
ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
42+
(PlanState *) css);
43+
css->ss.ps.qual = (List *)
44+
ExecInitExpr((Expr *) cscan->scan.plan.qual,
45+
(PlanState *) css);
46+
47+
/* tuple table initialization */
48+
ExecInitScanTupleSlot(estate, &css->ss);
49+
ExecInitResultTupleSlot(estate, &css->ss.ps);
50+
51+
/* initialize scan relation */
52+
scan_rel = ExecOpenScanRelation(estate, cscan->scan.scanrelid, eflags);
53+
css->ss.ss_currentRelation = scan_rel;
54+
css->ss.ss_currentScanDesc = NULL; /* set by provider */
55+
ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
56+
57+
css->ss.ps.ps_TupFromTlist = false;
58+
59+
/*
60+
* Initialize result tuple type and projection info.
61+
*/
62+
ExecAssignResultTypeFromTL(&css->ss.ps);
63+
ExecAssignScanProjectionInfo(&css->ss);
64+
65+
/*
66+
* The callback of custom-scan provider applies the final initialization
67+
* of the custom-scan-state node according to its logic.
68+
*/
69+
css->methods->BeginCustomScan(css, estate, eflags);
70+
71+
return css;
72+
}
73+
74+
TupleTableSlot *
75+
ExecCustomScan(CustomScanState *node)
76+
{
77+
Assert(node->methods->ExecCustomScan != NULL);
78+
return node->methods->ExecCustomScan(node);
79+
}
80+
81+
void
82+
ExecEndCustomScan(CustomScanState *node)
83+
{
84+
Assert(node->methods->EndCustomScan != NULL);
85+
node->methods->EndCustomScan(node);
86+
87+
/* Free the exprcontext */
88+
ExecFreeExprContext(&node->ss.ps);
89+
90+
/* Clean out the tuple table */
91+
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
92+
if (node->ss.ss_ScanTupleSlot)
93+
ExecClearTuple(node->ss.ss_ScanTupleSlot);
94+
95+
/* Close the heap relation */
96+
ExecCloseScanRelation(node->ss.ss_currentRelation);
97+
}
98+
99+
void
100+
ExecReScanCustomScan(CustomScanState *node)
101+
{
102+
Assert(node->methods->ReScanCustomScan != NULL);
103+
node->methods->ReScanCustomScan(node);
104+
}
105+
106+
void
107+
ExecCustomMarkPos(CustomScanState *node)
108+
{
109+
if (!node->methods->MarkPosCustomScan)
110+
ereport(ERROR,
111+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
112+
errmsg("custom-scan \"%s\" does not support MarkPos",
113+
node->methods->CustomName)));
114+
node->methods->MarkPosCustomScan(node);
115+
}
116+
117+
void
118+
ExecCustomRestrPos(CustomScanState *node)
119+
{
120+
if (!node->methods->RestrPosCustomScan)
121+
ereport(ERROR,
122+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
123+
errmsg("custom-scan \"%s\" does not support MarkPos",
124+
node->methods->CustomName)));
125+
node->methods->RestrPosCustomScan(node);
126+
}

src/backend/nodes/copyfuncs.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,29 @@ _copyForeignScan(const ForeignScan *from)
597597
return newnode;
598598
}
599599

600+
/*
601+
* _copyCustomScan
602+
*/
603+
static CustomScan *
604+
_copyCustomScan(const CustomScan *from)
605+
{
606+
CustomScan *newnode;
607+
608+
newnode = from->methods->CopyCustomScan(from);
609+
Assert(nodeTag(newnode) == nodeTag(from));
610+
611+
CopyScanFields((const Scan *) from, (Scan *) newnode);
612+
COPY_SCALAR_FIELD(flags);
613+
/*
614+
* NOTE: The method field of CustomScan is required to be a pointer
615+
* to a static table of callback functions. So, we don't copy the
616+
* table itself, just reference the original one.
617+
*/
618+
COPY_SCALAR_FIELD(methods);
619+
620+
return newnode;
621+
}
622+
600623
/*
601624
* CopyJoinFields
602625
*
@@ -4043,6 +4066,9 @@ copyObject(const void *from)
40434066
case T_ForeignScan:
40444067
retval = _copyForeignScan(from);
40454068
break;
4069+
case T_CustomScan:
4070+
retval = _copyCustomScan(from);
4071+
break;
40464072
case T_Join:
40474073
retval = _copyJoin(from);
40484074
break;

0 commit comments

Comments
 (0)