1 /*-------------------------------------------------------------------------
2  *
3  * nodeNamedtuplestorescan.c
4  *	  routines to handle NamedTuplestoreScan 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/nodeNamedtuplestorescan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "executor/execdebug.h"
19 #include "executor/nodeNamedtuplestorescan.h"
20 #include "miscadmin.h"
21 #include "utils/queryenvironment.h"
22 
23 static TupleTableSlot *NamedTuplestoreScanNext(NamedTuplestoreScanState *node);
24 
25 /* ----------------------------------------------------------------
26  *		NamedTuplestoreScanNext
27  *
28  *		This is a workhorse for ExecNamedTuplestoreScan
29  * ----------------------------------------------------------------
30  */
31 static TupleTableSlot *
32 NamedTuplestoreScanNext(NamedTuplestoreScanState *node)
33 {
34 	TupleTableSlot *slot;
35 
36 	/* We intentionally do not support backward scan. */
37 	Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
38 
39 	/*
40 	 * Get the next tuple from tuplestore. Return NULL if no more tuples.
41 	 */
42 	slot = node->ss.ss_ScanTupleSlot;
43 	tuplestore_select_read_pointer(node->relation, node->readptr);
44 	(void) tuplestore_gettupleslot(node->relation, true, false, slot);
45 	return slot;
46 }
47 
48 /*
49  * NamedTuplestoreScanRecheck -- access method routine to recheck a tuple in
50  * EvalPlanQual
51  */
52 static bool
53 NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
54 {
55 	/* nothing to check */
56 	return true;
57 }
58 
59 /* ----------------------------------------------------------------
60  *		ExecNamedTuplestoreScan(node)
61  *
62  *		Scans the CTE sequentially and returns the next qualifying tuple.
63  *		We call the ExecScan() routine and pass it the appropriate
64  *		access method functions.
65  * ----------------------------------------------------------------
66  */
67 static TupleTableSlot *
68 ExecNamedTuplestoreScan(PlanState *pstate)
69 {
70 	NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
71 
72 	return ExecScan(&node->ss,
73 					(ExecScanAccessMtd) NamedTuplestoreScanNext,
74 					(ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
75 }
76 
77 
78 /* ----------------------------------------------------------------
79  *		ExecInitNamedTuplestoreScan
80  * ----------------------------------------------------------------
81  */
82 NamedTuplestoreScanState *
83 ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags)
84 {
85 	NamedTuplestoreScanState *scanstate;
86 	EphemeralNamedRelation enr;
87 
88 	/* check for unsupported flags */
89 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
90 
91 	/*
92 	 * NamedTuplestoreScan should not have any children.
93 	 */
94 	Assert(outerPlan(node) == NULL);
95 	Assert(innerPlan(node) == NULL);
96 
97 	/*
98 	 * create new NamedTuplestoreScanState for node
99 	 */
100 	scanstate = makeNode(NamedTuplestoreScanState);
101 	scanstate->ss.ps.plan = (Plan *) node;
102 	scanstate->ss.ps.state = estate;
103 	scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
104 
105 	enr = get_ENR(estate->es_queryEnv, node->enrname);
106 	if (!enr)
107 		elog(ERROR, "executor could not find named tuplestore \"%s\"",
108 			 node->enrname);
109 
110 	Assert(enr->reldata);
111 	scanstate->relation = (Tuplestorestate *) enr->reldata;
112 	scanstate->tupdesc = ENRMetadataGetTupDesc(&(enr->md));
113 	scanstate->readptr =
114 		tuplestore_alloc_read_pointer(scanstate->relation, EXEC_FLAG_REWIND);
115 
116 	/*
117 	 * The new read pointer copies its position from read pointer 0, which
118 	 * could be anywhere, so explicitly rewind it.
119 	 */
120 	tuplestore_select_read_pointer(scanstate->relation, scanstate->readptr);
121 	tuplestore_rescan(scanstate->relation);
122 
123 	/*
124 	 * XXX: Should we add a function to free that read pointer when done?
125 	 *
126 	 * This was attempted, but it did not improve performance or memory usage
127 	 * in any tested cases.
128 	 */
129 
130 	/*
131 	 * Miscellaneous initialization
132 	 *
133 	 * create expression context for node
134 	 */
135 	ExecAssignExprContext(estate, &scanstate->ss.ps);
136 
137 	/*
138 	 * The scan tuple type is specified for the tuplestore.
139 	 */
140 	ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc,
141 						  &TTSOpsMinimalTuple);
142 
143 	/*
144 	 * Initialize result type and projection.
145 	 */
146 	ExecInitResultTypeTL(&scanstate->ss.ps);
147 	ExecAssignScanProjectionInfo(&scanstate->ss);
148 
149 	/*
150 	 * initialize child expressions
151 	 */
152 	scanstate->ss.ps.qual =
153 		ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
154 
155 	return scanstate;
156 }
157 
158 /* ----------------------------------------------------------------
159  *		ExecEndNamedTuplestoreScan
160  *
161  *		frees any storage allocated through C routines.
162  * ----------------------------------------------------------------
163  */
164 void
165 ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node)
166 {
167 	/*
168 	 * Free exprcontext
169 	 */
170 	ExecFreeExprContext(&node->ss.ps);
171 
172 	/*
173 	 * clean out the tuple table
174 	 */
175 	if (node->ss.ps.ps_ResultTupleSlot)
176 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
177 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
178 }
179 
180 /* ----------------------------------------------------------------
181  *		ExecReScanNamedTuplestoreScan
182  *
183  *		Rescans the relation.
184  * ----------------------------------------------------------------
185  */
186 void
187 ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node)
188 {
189 	Tuplestorestate *tuplestorestate = node->relation;
190 
191 	if (node->ss.ps.ps_ResultTupleSlot)
192 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
193 
194 	ExecScanReScan(&node->ss);
195 
196 	/*
197 	 * Rewind my own pointer.
198 	 */
199 	tuplestore_select_read_pointer(tuplestorestate, node->readptr);
200 	tuplestore_rescan(tuplestorestate);
201 }
202