Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * nodeWorktablescan.c 4 : * routines to handle WorkTableScan nodes. 5 : * 6 : * Portions Copyright (c) 1996-2024, 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/executor.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 * 30 50830 : 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 50830 : tuplestorestate = node->rustate->working_table; 53 : 54 : /* 55 : * Get the next tuple from tuplestore. Return NULL if no more tuples. 56 : */ 57 50830 : slot = node->ss.ss_ScanTupleSlot; 58 50830 : (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot); 59 50830 : return slot; 60 : } 61 : 62 : /* 63 : * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual 64 : */ 65 : static bool 66 0 : WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot) 67 : { 68 : /* nothing to check */ 69 0 : 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 * 81 36748 : ExecWorkTableScan(PlanState *pstate) 82 : { 83 36748 : 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 36748 : if (node->rustate == NULL) 92 : { 93 752 : WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan; 94 752 : EState *estate = node->ss.ps.state; 95 : ParamExecData *param; 96 : 97 752 : param = &(estate->es_param_exec_vals[plan->wtParam]); 98 : Assert(param->execPlan == NULL); 99 : Assert(!param->isnull); 100 752 : 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 752 : ExecAssignScanType(&node->ss, 110 752 : 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 752 : ExecAssignScanProjectionInfo(&node->ss); 117 : } 118 : 119 36748 : return ExecScan(&node->ss, 120 : (ExecScanAccessMtd) WorkTableScanNext, 121 : (ExecScanRecheckMtd) WorkTableScanRecheck); 122 : } 123 : 124 : 125 : /* ---------------------------------------------------------------- 126 : * ExecInitWorkTableScan 127 : * ---------------------------------------------------------------- 128 : */ 129 : WorkTableScanState * 130 806 : 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 806 : scanstate = makeNode(WorkTableScanState); 147 806 : scanstate->ss.ps.plan = (Plan *) node; 148 806 : scanstate->ss.ps.state = estate; 149 806 : scanstate->ss.ps.ExecProcNode = ExecWorkTableScan; 150 806 : scanstate->rustate = NULL; /* we'll set this later */ 151 : 152 : /* 153 : * Miscellaneous initialization 154 : * 155 : * create expression context for node 156 : */ 157 806 : ExecAssignExprContext(estate, &scanstate->ss.ps); 158 : 159 : /* 160 : * tuple table initialization 161 : */ 162 806 : ExecInitResultTypeTL(&scanstate->ss.ps); 163 : 164 : /* signal that return type is not yet known */ 165 806 : scanstate->ss.ps.resultopsset = true; 166 806 : scanstate->ss.ps.resultopsfixed = false; 167 : 168 806 : ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple); 169 : 170 : /* 171 : * initialize child expressions 172 : */ 173 806 : scanstate->ss.ps.qual = 174 806 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); 175 : 176 : /* 177 : * Do not yet initialize projection info, see ExecWorkTableScan() for 178 : * details. 179 : */ 180 : 181 806 : return scanstate; 182 : } 183 : 184 : /* ---------------------------------------------------------------- 185 : * ExecReScanWorkTableScan 186 : * 187 : * Rescans the relation. 188 : * ---------------------------------------------------------------- 189 : */ 190 : void 191 6302 : ExecReScanWorkTableScan(WorkTableScanState *node) 192 : { 193 6302 : if (node->ss.ps.ps_ResultTupleSlot) 194 5876 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); 195 : 196 6302 : ExecScanReScan(&node->ss); 197 : 198 : /* No need (or way) to rescan if ExecWorkTableScan not called yet */ 199 6302 : if (node->rustate) 200 6296 : tuplestore_rescan(node->rustate->working_table); 201 6302 : }