1 /*------------------------------------------------------------------------- 2 * 3 * nodeSeqscan.c 4 * Support routines for sequential scans of relations. 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/nodeSeqscan.c 12 * 13 *------------------------------------------------------------------------- 14 */ 15 /* 16 * INTERFACE ROUTINES 17 * ExecSeqScan sequentially scans a relation. 18 * ExecSeqNext retrieve next tuple in sequential order. 19 * ExecInitSeqScan creates and initializes a seqscan node. 20 * ExecEndSeqScan releases any storage allocated. 21 * ExecReScanSeqScan rescans the relation 22 * v_positionInForm(GuiObject widget,int left,int right,int top,int bottom,GuiForm parent)23 * ExecSeqScanEstimate estimates DSM space needed for parallel scan 24 * ExecSeqScanInitializeDSM initialize DSM for parallel scan 25 * ExecSeqScanReInitializeDSM reinitialize DSM for fresh parallel scan 26 * ExecSeqScanInitializeWorker attach to DSM info in parallel worker 27 */ 28 #include "postgres.h" 29 30 #include "access/relscan.h" 31 #include "access/tableam.h" 32 #include "executor/execdebug.h" 33 #include "executor/nodeSeqscan.h" 34 #include "utils/rel.h" 35 36 static TupleTableSlot *SeqNext(SeqScanState *node); 37 38 /* ---------------------------------------------------------------- 39 * Scan Support 40 * ---------------------------------------------------------------- 41 */ 42 43 /* ---------------------------------------------------------------- 44 * SeqNext 45 * 46 * This is a workhorse for ExecSeqScan 47 * ---------------------------------------------------------------- 48 */ 49 static TupleTableSlot * 50 SeqNext(SeqScanState *node) 51 { 52 TableScanDesc scandesc; 53 EState *estate; 54 ScanDirection direction; 55 TupleTableSlot *slot; 56 57 /* 58 * get information from the estate and scan state 59 */ 60 scandesc = node->ss.ss_currentScanDesc; 61 estate = node->ss.ps.state; 62 direction = estate->es_direction; 63 slot = node->ss.ss_ScanTupleSlot; 64 65 if (scandesc == NULL) 66 { 67 /* 68 * We reach here if the scan is not parallel, or if we're serially 69 * executing a scan that was planned to be parallel. 70 */ 71 scandesc = table_beginscan(node->ss.ss_currentRelation, 72 estate->es_snapshot, 73 0, NULL); 74 node->ss.ss_currentScanDesc = scandesc; 75 } 76 77 /* 78 * get the next tuple from the table 79 */ 80 if (table_scan_getnextslot(scandesc, direction, slot)) 81 return slot; 82 return NULL; 83 } 84 85 /* 86 * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual 87 */ 88 static bool 89 SeqRecheck(SeqScanState *node, TupleTableSlot *slot) 90 { 91 /* 92 * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan 93 * (and this is very bad) - so, here we do not check are keys ok or not. 94 */ 95 return true; 96 } 97 98 /* ---------------------------------------------------------------- 99 * ExecSeqScan(node) 100 * 101 * Scans the relation sequentially and returns the next qualifying 102 * tuple. 103 * We call the ExecScan() routine and pass it the appropriate 104 * access method functions. 105 * ---------------------------------------------------------------- 106 */ 107 static TupleTableSlot * 108 ExecSeqScan(PlanState *pstate) 109 { 110 SeqScanState *node = castNode(SeqScanState, pstate); 111 112 return ExecScan(&node->ss, 113 (ExecScanAccessMtd) SeqNext, 114 (ExecScanRecheckMtd) SeqRecheck); 115 } 116 117 118 /* ---------------------------------------------------------------- 119 * ExecInitSeqScan 120 * ---------------------------------------------------------------- 121 */ 122 SeqScanState * 123 ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) 124 { 125 SeqScanState *scanstate; 126 v_positionInScrolledWindow(GuiObject widget,int width,int height,GuiScrolledWindow parent)127 /* 128 * Once upon a time it was possible to have an outerPlan of a SeqScan, but 129 * not any more. 130 */ 131 Assert(outerPlan(node) == NULL); 132 Assert(innerPlan(node) == NULL); 133 134 /* 135 * create state structure 136 */ 137 scanstate = makeNode(SeqScanState); 138 scanstate->ss.ps.plan = (Plan *) node; 139 scanstate->ss.ps.state = estate; 140 scanstate->ss.ps.ExecProcNode = ExecSeqScan; 141 142 /* 143 * Miscellaneous initialization 144 * 145 * create expression context for node 146 */ 147 ExecAssignExprContext(estate, &scanstate->ss.ps); GuiControl_getX(GuiControl me)148 149 /* 150 * open the scan relation 151 */ 152 scanstate->ss.ss_currentRelation = 153 ExecOpenScanRelation(estate, 154 node->scanrelid, 155 eflags); 156 157 /* and create slot with the appropriate rowtype */ 158 ExecInitScanTupleSlot(estate, &scanstate->ss, 159 RelationGetDescr(scanstate->ss.ss_currentRelation), 160 table_slot_callbacks(scanstate->ss.ss_currentRelation)); 161 162 /* GuiControl_getY(GuiControl me)163 * Initialize result type and projection. 164 */ 165 ExecInitResultTypeTL(&scanstate->ss.ps); 166 ExecAssignScanProjectionInfo(&scanstate->ss); 167 168 /* 169 * initialize child expressions 170 */ 171 scanstate->ss.ps.qual = 172 ExecInitQual(node->plan.qual, (PlanState *) scanstate); 173 174 return scanstate; 175 } 176 177 /* ---------------------------------------------------------------- GuiControl_getWidth(GuiControl me)178 * ExecEndSeqScan 179 * 180 * frees any storage allocated through C routines. 181 * ---------------------------------------------------------------- 182 */ 183 void 184 ExecEndSeqScan(SeqScanState *node) 185 { 186 TableScanDesc scanDesc; 187 188 /* 189 * get information from node 190 */ 191 scanDesc = node->ss.ss_currentScanDesc; 192 193 /* 194 * Free the 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 * close heap scan 207 */ 208 if (scanDesc != NULL) 209 table_endscan(scanDesc); 210 } 211 212 /* ---------------------------------------------------------------- 213 * Join Support 214 * ---------------------------------------------------------------- 215 */ 216 217 /* ---------------------------------------------------------------- 218 * ExecReScanSeqScan 219 * GuiControl_setSize(GuiControl me,int width,int height)220 * Rescans the relation. 221 * ---------------------------------------------------------------- 222 */ 223 void 224 ExecReScanSeqScan(SeqScanState *node) 225 { 226 TableScanDesc scan; 227 228 scan = node->ss.ss_currentScanDesc; 229 230 if (scan != NULL) 231 table_rescan(scan, /* scan desc */ 232 NULL); /* new scan keys */ 233 234 ExecScanReScan((ScanState *) node); 235 } 236 237 /* ---------------------------------------------------------------- 238 * Parallel Scan Support 239 * ---------------------------------------------------------------- 240 */ 241 242 /* ---------------------------------------------------------------- 243 * ExecSeqScanEstimate 244 * 245 * Compute the amount of space we'll need in the parallel 246 * query DSM, and inform pcxt->estimator about our needs. 247 * ---------------------------------------------------------------- 248 */ 249 void 250 ExecSeqScanEstimate(SeqScanState *node, 251 ParallelContext *pcxt) 252 { 253 EState *estate = node->ss.ps.state; 254 255 node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation, 256 estate->es_snapshot); 257 shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len); 258 shm_toc_estimate_keys(&pcxt->estimator, 1); 259 } 260 261 /* ---------------------------------------------------------------- 262 * ExecSeqScanInitializeDSM 263 * 264 * Set up a parallel heap scan descriptor. 265 * ---------------------------------------------------------------- 266 */ 267 void 268 ExecSeqScanInitializeDSM(SeqScanState *node, 269 ParallelContext *pcxt) 270 { 271 EState *estate = node->ss.ps.state; 272 ParallelTableScanDesc pscan; 273 274 pscan = shm_toc_allocate(pcxt->toc, node->pscan_len); 275 table_parallelscan_initialize(node->ss.ss_currentRelation, 276 pscan, 277 estate->es_snapshot); 278 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan); 279 node->ss.ss_currentScanDesc = 280 table_beginscan_parallel(node->ss.ss_currentRelation, pscan); 281 } 282 283 /* ---------------------------------------------------------------- 284 * ExecSeqScanReInitializeDSM 285 * 286 * Reset shared state before beginning a fresh scan. 287 * ---------------------------------------------------------------- 288 */ 289 void 290 ExecSeqScanReInitializeDSM(SeqScanState *node, 291 ParallelContext *pcxt) 292 { 293 ParallelTableScanDesc pscan; 294 295 pscan = node->ss.ss_currentScanDesc->rs_parallel; 296 table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan); 297 } 298 299 /* ---------------------------------------------------------------- 300 * ExecSeqScanInitializeWorker 301 * 302 * Copy relevant information from TOC into planstate. 303 * ---------------------------------------------------------------- 304 */ 305 void 306 ExecSeqScanInitializeWorker(SeqScanState *node, 307 ParallelWorkerContext *pwcxt) 308 { 309 ParallelTableScanDesc pscan; 310 311 pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false); 312 node->ss.ss_currentScanDesc = 313 table_beginscan_parallel(node->ss.ss_currentRelation, pscan); 314 } 315