1 /*-------------------------------------------------------------------------
2  *
3  * nodeWorktablescan.c
4  *	  routines to handle WorkTableScan nodes.
5  *
6  * Portions Copyright (c) 1996-2019, 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 	 * tuple table initialization
161 	 */
162 	ExecInitResultTypeTL(&scanstate->ss.ps);
163 
164 	/* signal that return type is not yet known */
165 	scanstate->ss.ps.resultopsset = true;
166 	scanstate->ss.ps.resultopsfixed = false;
167 
168 	ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
169 
170 	/*
171 	 * initialize child expressions
172 	 */
173 	scanstate->ss.ps.qual =
174 		ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
175 
176 	/*
177 	 * Do not yet initialize projection info, see ExecWorkTableScan() for
178 	 * details.
179 	 */
180 
181 	return scanstate;
182 }
183 
184 /* ----------------------------------------------------------------
185  *		ExecEndWorkTableScan
186  *
187  *		frees any storage allocated through C routines.
188  * ----------------------------------------------------------------
189  */
190 void
ExecEndWorkTableScan(WorkTableScanState * node)191 ExecEndWorkTableScan(WorkTableScanState *node)
192 {
193 	/*
194 	 * Free exprcontext
195 	 */
196 	ExecFreeExprContext(&node->ss.ps);
197 
198 	/*
199 	 * clean out the tuple table
200 	 */
201 	if (node->ss.ps.ps_ResultTupleSlot)
202 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
203 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
204 }
205 
206 /* ----------------------------------------------------------------
207  *		ExecReScanWorkTableScan
208  *
209  *		Rescans the relation.
210  * ----------------------------------------------------------------
211  */
212 void
ExecReScanWorkTableScan(WorkTableScanState * node)213 ExecReScanWorkTableScan(WorkTableScanState *node)
214 {
215 	if (node->ss.ps.ps_ResultTupleSlot)
216 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
217 
218 	ExecScanReScan(&node->ss);
219 
220 	/* No need (or way) to rescan if ExecWorkTableScan not called yet */
221 	if (node->rustate)
222 		tuplestore_rescan(node->rustate->working_table);
223 }
224