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