| 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 | * |
| 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 | |
| 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); |
| 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 | /* |
| 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 | /* ---------------------------------------------------------------- |
| 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 | * |
| 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 | |