1 /*-------------------------------------------------------------------------
2  *
3  * nodeWorktablescan.c
4  *	  routines to handle WorkTableScan nodes.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/executor/nodeWorktablescan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "executor/execdebug.h"
19 #include "executor/nodeWorktablescan.h"
20 
21 static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
22 
23 /* ----------------------------------------------------------------
24  *		WorkTableScanNext
25  *
26  *		This is a workhorse for ExecWorkTableScan
27  * ----------------------------------------------------------------
28  */
29 static TupleTableSlot *
WorkTableScanNext(WorkTableScanState * node)30 WorkTableScanNext(WorkTableScanState *node)
31 {
32 	TupleTableSlot *slot;
33 	Tuplestorestate *tuplestorestate;
34 
35 	/*
36 	 * get information from the estate and scan state
37 	 *
38 	 * Note: we intentionally do not support backward scan.  Although it would
39 	 * take only a couple more lines here, it would force nodeRecursiveunion.c
40 	 * to create the tuplestore with backward scan enabled, which has a
41 	 * performance cost.  In practice backward scan is never useful for a
42 	 * worktable plan node, since it cannot appear high enough in the plan
43 	 * tree of a scrollable cursor to be exposed to a backward-scan
44 	 * requirement.  So it's not worth expending effort to support it.
45 	 *
46 	 * Note: we are also assuming that this node is the only reader of the
47 	 * worktable.  Therefore, we don't need a private read pointer for the
48 	 * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
49 	 */
50 	Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51 
52 	tuplestorestate = node->rustate->working_table;
53 
54 	/*
55 	 * Get the next tuple from tuplestore. Return NULL if no more tuples.
56 	 */
57 	slot = node->ss.ss_ScanTupleSlot;
58 	(void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
59 	return slot;
60 }
61 
62 /*
63  * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64  */
65 static bool
WorkTableScanRecheck(WorkTableScanState * node,TupleTableSlot * slot)66 WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
67 {
68 	/* nothing to check */
69 	return true;
70 }
71 
72 /* ----------------------------------------------------------------
73  *		ExecWorkTableScan(node)
74  *
75  *		Scans the worktable sequentially and returns the next qualifying tuple.
76  *		We call the ExecScan() routine and pass it the appropriate
77  *		access method functions.
78  * ----------------------------------------------------------------
79  */
80 static TupleTableSlot *
ExecWorkTableScan(PlanState * pstate)81 ExecWorkTableScan(PlanState *pstate)
82 {
83 	WorkTableScanState *node = castNode(WorkTableScanState, pstate);
84 
85 	/*
86 	 * On the first call, find the ancestor RecursiveUnion's state via the
87 	 * Param slot reserved for it.  (We can't do this during node init because
88 	 * there are corner cases where we'll get the init call before the
89 	 * RecursiveUnion does.)
90 	 */
91 	if (node->rustate == NULL)
92 	{
93 		WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
94 		EState	   *estate = node->ss.ps.state;
95 		ParamExecData *param;
96 
97 		param = &(estate->es_param_exec_vals[plan->wtParam]);
98 		Assert(param->execPlan == NULL);
99 		Assert(!param->isnull);
100 		node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
101 		Assert(node->rustate);
102 
103 		/*
104 		 * The scan tuple type (ie, the rowtype we expect to find in the work
105 		 * table) is the same as the result rowtype of the ancestor
106 		 * RecursiveUnion node.  Note this depends on the assumption that
107 		 * RecursiveUnion doesn't allow projection.
108 		 */
109 		ExecAssignScanType(&node->ss,
110 						   ExecGetResultType(&node->rustate->ps));
111 
112 		/*
113 		 * Now we can initialize the projection info.  This must be completed
114 		 * before we can call ExecScan().
115 		 */
116 		ExecAssignScanProjectionInfo(&node->ss);
117 	}
118 
119 	return ExecScan(&node->ss,
120 					(ExecScanAccessMtd) WorkTableScanNext,
121 					(ExecScanRecheckMtd) WorkTableScanRecheck);
122 }
123 
124 
125 /* ----------------------------------------------------------------
126  *		ExecInitWorkTableScan
127  * ----------------------------------------------------------------
128  */
129 WorkTableScanState *
ExecInitWorkTableScan(WorkTableScan * node,EState * estate,int eflags)130 ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
131 {
132 	WorkTableScanState *scanstate;
133 
134 	/* check for unsupported flags */
135 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136 
137 	/*
138 	 * WorkTableScan should not have any children.
139 	 */
140 	Assert(outerPlan(node) == NULL);
141 	Assert(innerPlan(node) == NULL);
142 
143 	/*
144 	 * create new WorkTableScanState for node
145 	 */
146 	scanstate = makeNode(WorkTableScanState);
147 	scanstate->ss.ps.plan = (Plan *) node;
148 	scanstate->ss.ps.state = estate;
149 	scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
150 	scanstate->rustate = NULL;	/* we'll set this later */
151 
152 	/*
153 	 * Miscellaneous initialization
154 	 *
155 	 * create expression context for node
156 	 */
157 	ExecAssignExprContext(estate, &scanstate->ss.ps);
158 
159 	/*
160 	 * initialize child expressions
161 	 */
162 	scanstate->ss.ps.qual =
163 		ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
164 
165 	/*
166 	 * tuple table initialization
167 	 */
168 	ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
169 	ExecInitScanTupleSlot(estate, &scanstate->ss);
170 
171 	/*
172 	 * Initialize result tuple type, but not yet projection info.
173 	 */
174 	ExecAssignResultTypeFromTL(&scanstate->ss.ps);
175 
176 	return scanstate;
177 }
178 
179 /* ----------------------------------------------------------------
180  *		ExecEndWorkTableScan
181  *
182  *		frees any storage allocated through C routines.
183  * ----------------------------------------------------------------
184  */
185 void
ExecEndWorkTableScan(WorkTableScanState * node)186 ExecEndWorkTableScan(WorkTableScanState *node)
187 {
188 	/*
189 	 * Free exprcontext
190 	 */
191 	ExecFreeExprContext(&node->ss.ps);
192 
193 	/*
194 	 * clean out the tuple table
195 	 */
196 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
197 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
198 }
199 
200 /* ----------------------------------------------------------------
201  *		ExecReScanWorkTableScan
202  *
203  *		Rescans the relation.
204  * ----------------------------------------------------------------
205  */
206 void
ExecReScanWorkTableScan(WorkTableScanState * node)207 ExecReScanWorkTableScan(WorkTableScanState *node)
208 {
209 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
210 
211 	ExecScanReScan(&node->ss);
212 
213 	/* No need (or way) to rescan if ExecWorkTableScan not called yet */
214 	if (node->rustate)
215 		tuplestore_rescan(node->rustate->working_table);
216 }
217