1 /*-------------------------------------------------------------------------
4 * routines to handle WorkTableScan nodes.
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
18 #include "executor/execdebug.h"
19 #include "executor/nodeWorktablescan.h"
21 static TupleTableSlot
*WorkTableScanNext(WorkTableScanState
*node
);
23 /* ----------------------------------------------------------------
26 * This is a workhorse for ExecWorkTableScan
27 * ----------------------------------------------------------------
29 static TupleTableSlot
*
30 WorkTableScanNext(WorkTableScanState
*node
)
34 Tuplestorestate
*tuplestorestate
;
37 * get information from the estate and scan state
39 * Note: we intentionally do not support backward scan. Although it would
40 * take only a couple more lines here, it would force nodeRecursiveunion.c
41 * to create the tuplestore with backward scan enabled, which has a
42 * performance cost. In practice backward scan is never useful for a
43 * worktable plan node, since it cannot appear high enough in the plan
44 * tree of a scrollable cursor to be exposed to a backward-scan
45 * requirement. So it's not worth expending effort to support it.
47 * Note: we are also assuming that this node is the only reader of the
48 * worktable. Therefore, we don't need a private read pointer for the
49 * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
51 estate
= node
->ss
.ps
.state
;
52 Assert(ScanDirectionIsForward(estate
->es_direction
));
54 tuplestorestate
= node
->rustate
->working_table
;
57 * Get the next tuple from tuplestore. Return NULL if no more tuples.
59 slot
= node
->ss
.ss_ScanTupleSlot
;
60 (void) tuplestore_gettupleslot(tuplestorestate
, true, false, slot
);
64 /* ----------------------------------------------------------------
65 * ExecWorkTableScan(node)
67 * Scans the worktable sequentially and returns the next qualifying tuple.
68 * It calls the ExecScan() routine and passes it the access method
69 * which retrieves tuples sequentially.
70 * ----------------------------------------------------------------
73 ExecWorkTableScan(WorkTableScanState
*node
)
76 * On the first call, find the ancestor RecursiveUnion's state via the
77 * Param slot reserved for it. (We can't do this during node init because
78 * there are corner cases where we'll get the init call before the
79 * RecursiveUnion does.)
81 if (node
->rustate
== NULL
)
83 WorkTableScan
*plan
= (WorkTableScan
*) node
->ss
.ps
.plan
;
84 EState
*estate
= node
->ss
.ps
.state
;
87 param
= &(estate
->es_param_exec_vals
[plan
->wtParam
]);
88 Assert(param
->execPlan
== NULL
);
89 Assert(!param
->isnull
);
90 node
->rustate
= (RecursiveUnionState
*) DatumGetPointer(param
->value
);
91 Assert(node
->rustate
&& IsA(node
->rustate
, RecursiveUnionState
));
94 * The scan tuple type (ie, the rowtype we expect to find in the work
95 * table) is the same as the result rowtype of the ancestor
96 * RecursiveUnion node. Note this depends on the assumption that
97 * RecursiveUnion doesn't allow projection.
99 ExecAssignScanType(&node
->ss
,
100 ExecGetResultType(&node
->rustate
->ps
));
103 * Now we can initialize the projection info. This must be completed
104 * before we can call ExecScan().
106 ExecAssignScanProjectionInfo(&node
->ss
);
110 * use WorkTableScanNext as access method
112 return ExecScan(&node
->ss
, (ExecScanAccessMtd
) WorkTableScanNext
);
116 /* ----------------------------------------------------------------
117 * ExecInitWorkTableScan
118 * ----------------------------------------------------------------
121 ExecInitWorkTableScan(WorkTableScan
*node
, EState
*estate
, int eflags
)
123 WorkTableScanState
*scanstate
;
125 /* check for unsupported flags */
126 Assert(!(eflags
& (EXEC_FLAG_BACKWARD
| EXEC_FLAG_MARK
)));
129 * WorkTableScan should not have any children.
131 Assert(outerPlan(node
) == NULL
);
132 Assert(innerPlan(node
) == NULL
);
135 * create new WorkTableScanState for node
137 scanstate
= makeNode(WorkTableScanState
);
138 scanstate
->ss
.ps
.plan
= (Plan
*) node
;
139 scanstate
->ss
.ps
.state
= estate
;
140 scanstate
->rustate
= NULL
; /* we'll set this later */
143 * Miscellaneous initialization
145 * create expression context for node
147 ExecAssignExprContext(estate
, &scanstate
->ss
.ps
);
150 * initialize child expressions
152 scanstate
->ss
.ps
.targetlist
= (List
*)
153 ExecInitExpr((Expr
*) node
->scan
.plan
.targetlist
,
154 (PlanState
*) scanstate
);
155 scanstate
->ss
.ps
.qual
= (List
*)
156 ExecInitExpr((Expr
*) node
->scan
.plan
.qual
,
157 (PlanState
*) scanstate
);
159 #define WORKTABLESCAN_NSLOTS 2
162 * tuple table initialization
164 ExecInitResultTupleSlot(estate
, &scanstate
->ss
.ps
);
165 ExecInitScanTupleSlot(estate
, &scanstate
->ss
);
168 * Initialize result tuple type, but not yet projection info.
170 ExecAssignResultTypeFromTL(&scanstate
->ss
.ps
);
172 scanstate
->ss
.ps
.ps_TupFromTlist
= false;
178 ExecCountSlotsWorkTableScan(WorkTableScan
*node
)
180 return ExecCountSlotsNode(outerPlan(node
)) +
181 ExecCountSlotsNode(innerPlan(node
)) +
182 WORKTABLESCAN_NSLOTS
;
185 /* ----------------------------------------------------------------
186 * ExecEndWorkTableScan
188 * frees any storage allocated through C routines.
189 * ----------------------------------------------------------------
192 ExecEndWorkTableScan(WorkTableScanState
*node
)
197 ExecFreeExprContext(&node
->ss
.ps
);
200 * clean out the tuple table
202 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
203 ExecClearTuple(node
->ss
.ss_ScanTupleSlot
);
206 /* ----------------------------------------------------------------
207 * ExecWorkTableScanReScan
209 * Rescans the relation.
210 * ----------------------------------------------------------------
213 ExecWorkTableScanReScan(WorkTableScanState
*node
, ExprContext
*exprCtxt
)
215 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
216 node
->ss
.ps
.ps_TupFromTlist
= false;
218 /* No need (or way) to rescan if ExecWorkTableScan not called yet */
220 tuplestore_rescan(node
->rustate
->working_table
);