| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * execScan.c |
| 4 | * This code provides support for generalized relation scans. ExecScan |
| 5 | * is passed a node and a pointer to a function to "do the right thing" |
| 6 | * and return a tuple from the relation. ExecScan then does the tedious |
| 7 | * stuff - checking the qualification and projecting the tuple |
| 8 | * appropriately. |
| 9 | * |
| 10 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 11 | * Portions Copyright (c) 1994, Regents of the University of California |
| 12 | * |
| 13 | * |
| 14 | * IDENTIFICATION |
| 15 | * src/backend/executor/execScan.c |
| 16 | * |
| 17 | *------------------------------------------------------------------------- |
| 18 | */ |
| 19 | #include "postgres.h" |
| 20 | |
| 21 | #include "executor/executor.h" |
| 22 | #include "miscadmin.h" |
| 23 | #include "utils/memutils.h" |
| 24 | |
| 25 | |
| 26 | |
| 27 | /* |
| 28 | * ExecScanFetch -- check interrupts & fetch next potential tuple |
| 29 | * |
| 30 | * This routine is concerned with substituting a test tuple if we are |
| 31 | * inside an EvalPlanQual recheck. If we aren't, just execute |
| 32 | * the access method's next-tuple routine. |
| 33 | */ |
| 34 | static inline TupleTableSlot * |
| 35 | ExecScanFetch(ScanState *node, |
| 36 | ExecScanAccessMtd accessMtd, |
| 37 | ExecScanRecheckMtd recheckMtd) |
| 38 | { |
| 39 | EState *estate = node->ps.state; |
| 40 | |
| 41 | CHECK_FOR_INTERRUPTS(); |
| 42 | |
| 43 | if (estate->es_epq_active != NULL) |
| 44 | { |
| 45 | EPQState *epqstate = estate->es_epq_active; |
| 46 | |
| 47 | /* |
| 48 | * We are inside an EvalPlanQual recheck. Return the test tuple if |
| 49 | * one is available, after rechecking any access-method-specific |
| 50 | * conditions. |
| 51 | */ |
| 52 | Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; |
| 53 | |
| 54 | if (scanrelid == 0) |
| 55 | { |
| 56 | /* |
| 57 | * This is a ForeignScan or CustomScan which has pushed down a |
| 58 | * join to the remote side. The recheck method is responsible not |
| 59 | * only for rechecking the scan/join quals but also for storing |
| 60 | * the correct tuple in the slot. |
| 61 | */ |
| 62 | |
| 63 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
| 64 | |
| 65 | if (!(*recheckMtd) (node, slot)) |
| 66 | ExecClearTuple(slot); /* would not be returned by scan */ |
| 67 | return slot; |
| 68 | } |
| 69 | else if (epqstate->relsubs_done[scanrelid - 1]) |
| 70 | { |
| 71 | /* |
| 72 | * Return empty slot, as we already performed an EPQ substitution |
| 73 | * for this relation. |
| 74 | */ |
| 75 | |
| 76 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
| 77 | |
| 78 | /* Return empty slot, as we already returned a tuple */ |
| 79 | return ExecClearTuple(slot); |
| 80 | } |
| 81 | else if (epqstate->relsubs_slot[scanrelid - 1] != NULL) |
| 82 | { |
| 83 | /* |
| 84 | * Return replacement tuple provided by the EPQ caller. |
| 85 | */ |
| 86 | |
| 87 | TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1]; |
| 88 | |
| 89 | Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL); |
| 90 | |
| 91 | /* Mark to remember that we shouldn't return more */ |
| 92 | epqstate->relsubs_done[scanrelid - 1] = true; |
| 93 | |
| 94 | /* Return empty slot if we haven't got a test tuple */ |
| 95 | if (TupIsNull(slot)) |
| 96 | return NULL; |
| 97 | |
| 98 | /* Check if it meets the access-method conditions */ |
| 99 | if (!(*recheckMtd) (node, slot)) |
| 100 | return ExecClearTuple(slot); /* would not be returned by |
| 101 | * scan */ |
| 102 | return slot; |
| 103 | } |
| 104 | else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL) |
| 105 | { |
| 106 | /* |
| 107 | * Fetch and return replacement tuple using a non-locking rowmark. |
| 108 | */ |
| 109 | |
| 110 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
| 111 | |
| 112 | /* Mark to remember that we shouldn't return more */ |
| 113 | epqstate->relsubs_done[scanrelid - 1] = true; |
| 114 | |
| 115 | if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot)) |
| 116 | return NULL; |
| 117 | |
| 118 | /* Return empty slot if we haven't got a test tuple */ |
| 119 | if (TupIsNull(slot)) |
| 120 | return NULL; |
| 121 | |
| 122 | /* Check if it meets the access-method conditions */ |
| 123 | if (!(*recheckMtd) (node, slot)) |
| 124 | return ExecClearTuple(slot); /* would not be returned by |
| 125 | * scan */ |
| 126 | return slot; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | * Run the node-type-specific access method function to get the next tuple |
| 132 | */ |
| 133 | return (*accessMtd) (node); |
| 134 | } |
| 135 | |
| 136 | /* ---------------------------------------------------------------- |
| 137 | * ExecScan |
| 138 | * |
| 139 | * Scans the relation using the 'access method' indicated and |
| 140 | * returns the next qualifying tuple in the direction specified |
| 141 | * in the global variable ExecDirection. |
| 142 | * The access method returns the next tuple and ExecScan() is |
| 143 | * responsible for checking the tuple returned against the qual-clause. |
| 144 | * |
| 145 | * A 'recheck method' must also be provided that can check an |
| 146 | * arbitrary tuple of the relation against any qual conditions |
| 147 | * that are implemented internal to the access method. |
| 148 | * |
| 149 | * Conditions: |
| 150 | * -- the "cursor" maintained by the AMI is positioned at the tuple |
| 151 | * returned previously. |
| 152 | * |
| 153 | * Initial States: |
| 154 | * -- the relation indicated is opened for scanning so that the |
| 155 | * "cursor" is positioned before the first qualifying tuple. |
| 156 | * ---------------------------------------------------------------- |
| 157 | */ |
| 158 | TupleTableSlot * |
| 159 | ExecScan(ScanState *node, |
| 160 | ExecScanAccessMtd accessMtd, /* function returning a tuple */ |
| 161 | ExecScanRecheckMtd recheckMtd) |
| 162 | { |
| 163 | ExprContext *econtext; |
| 164 | ExprState *qual; |
| 165 | ProjectionInfo *projInfo; |
| 166 | |
| 167 | /* |
| 168 | * Fetch data from node |
| 169 | */ |
| 170 | qual = node->ps.qual; |
| 171 | projInfo = node->ps.ps_ProjInfo; |
| 172 | econtext = node->ps.ps_ExprContext; |
| 173 | |
| 174 | /* interrupt checks are in ExecScanFetch */ |
| 175 | |
| 176 | /* |
| 177 | * If we have neither a qual to check nor a projection to do, just skip |
| 178 | * all the overhead and return the raw scan tuple. |
| 179 | */ |
| 180 | if (!qual && !projInfo) |
| 181 | { |
| 182 | ResetExprContext(econtext); |
| 183 | return ExecScanFetch(node, accessMtd, recheckMtd); |
| 184 | } |
| 185 | |
| 186 | /* |
| 187 | * Reset per-tuple memory context to free any expression evaluation |
| 188 | * storage allocated in the previous tuple cycle. |
| 189 | */ |
| 190 | ResetExprContext(econtext); |
| 191 | |
| 192 | /* |
| 193 | * get a tuple from the access method. Loop until we obtain a tuple that |
| 194 | * passes the qualification. |
| 195 | */ |
| 196 | for (;;) |
| 197 | { |
| 198 | TupleTableSlot *slot; |
| 199 | |
| 200 | slot = ExecScanFetch(node, accessMtd, recheckMtd); |
| 201 | |
| 202 | /* |
| 203 | * if the slot returned by the accessMtd contains NULL, then it means |
| 204 | * there is nothing more to scan so we just return an empty slot, |
| 205 | * being careful to use the projection result slot so it has correct |
| 206 | * tupleDesc. |
| 207 | */ |
| 208 | if (TupIsNull(slot)) |
| 209 | { |
| 210 | if (projInfo) |
| 211 | return ExecClearTuple(projInfo->pi_state.resultslot); |
| 212 | else |
| 213 | return slot; |
| 214 | } |
| 215 | |
| 216 | /* |
| 217 | * place the current tuple into the expr context |
| 218 | */ |
| 219 | econtext->ecxt_scantuple = slot; |
| 220 | |
| 221 | /* |
| 222 | * check that the current tuple satisfies the qual-clause |
| 223 | * |
| 224 | * check for non-null qual here to avoid a function call to ExecQual() |
| 225 | * when the qual is null ... saves only a few cycles, but they add up |
| 226 | * ... |
| 227 | */ |
| 228 | if (qual == NULL || ExecQual(qual, econtext)) |
| 229 | { |
| 230 | /* |
| 231 | * Found a satisfactory scan tuple. |
| 232 | */ |
| 233 | if (projInfo) |
| 234 | { |
| 235 | /* |
| 236 | * Form a projection tuple, store it in the result tuple slot |
| 237 | * and return it. |
| 238 | */ |
| 239 | return ExecProject(projInfo); |
| 240 | } |
| 241 | else |
| 242 | { |
| 243 | /* |
| 244 | * Here, we aren't projecting, so just return scan tuple. |
| 245 | */ |
| 246 | return slot; |
| 247 | } |
| 248 | } |
| 249 | else |
| 250 | InstrCountFiltered1(node, 1); |
| 251 | |
| 252 | /* |
| 253 | * Tuple fails qual, so free per-tuple memory and try again. |
| 254 | */ |
| 255 | ResetExprContext(econtext); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | /* |
| 260 | * ExecAssignScanProjectionInfo |
| 261 | * Set up projection info for a scan node, if necessary. |
| 262 | * |
| 263 | * We can avoid a projection step if the requested tlist exactly matches |
| 264 | * the underlying tuple type. If so, we just set ps_ProjInfo to NULL. |
| 265 | * Note that this case occurs not only for simple "SELECT * FROM ...", but |
| 266 | * also in most cases where there are joins or other processing nodes above |
| 267 | * the scan node, because the planner will preferentially generate a matching |
| 268 | * tlist. |
| 269 | * |
| 270 | * The scan slot's descriptor must have been set already. |
| 271 | */ |
| 272 | void |
| 273 | ExecAssignScanProjectionInfo(ScanState *node) |
| 274 | { |
| 275 | Scan *scan = (Scan *) node->ps.plan; |
| 276 | TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; |
| 277 | |
| 278 | ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid); |
| 279 | } |
| 280 | |
| 281 | /* |
| 282 | * ExecAssignScanProjectionInfoWithVarno |
| 283 | * As above, but caller can specify varno expected in Vars in the tlist. |
| 284 | */ |
| 285 | void |
| 286 | ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno) |
| 287 | { |
| 288 | TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; |
| 289 | |
| 290 | ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno); |
| 291 | } |
| 292 | |
| 293 | /* |
| 294 | * ExecScanReScan |
| 295 | * |
| 296 | * This must be called within the ReScan function of any plan node type |
| 297 | * that uses ExecScan(). |
| 298 | */ |
| 299 | void |
| 300 | ExecScanReScan(ScanState *node) |
| 301 | { |
| 302 | EState *estate = node->ps.state; |
| 303 | |
| 304 | /* |
| 305 | * We must clear the scan tuple so that observers (e.g., execCurrent.c) |
| 306 | * can tell that this plan node is not positioned on a tuple. |
| 307 | */ |
| 308 | ExecClearTuple(node->ss_ScanTupleSlot); |
| 309 | |
| 310 | /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ |
| 311 | if (estate->es_epq_active != NULL) |
| 312 | { |
| 313 | EPQState *epqstate = estate->es_epq_active; |
| 314 | Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; |
| 315 | |
| 316 | if (scanrelid > 0) |
| 317 | epqstate->relsubs_done[scanrelid - 1] = false; |
| 318 | else |
| 319 | { |
| 320 | Bitmapset *relids; |
| 321 | int rtindex = -1; |
| 322 | |
| 323 | /* |
| 324 | * If an FDW or custom scan provider has replaced the join with a |
| 325 | * scan, there are multiple RTIs; reset the epqScanDone flag for |
| 326 | * all of them. |
| 327 | */ |
| 328 | if (IsA(node->ps.plan, ForeignScan)) |
| 329 | relids = ((ForeignScan *) node->ps.plan)->fs_relids; |
| 330 | else if (IsA(node->ps.plan, CustomScan)) |
| 331 | relids = ((CustomScan *) node->ps.plan)->custom_relids; |
| 332 | else |
| 333 | elog(ERROR, "unexpected scan node: %d" , |
| 334 | (int) nodeTag(node->ps.plan)); |
| 335 | |
| 336 | while ((rtindex = bms_next_member(relids, rtindex)) >= 0) |
| 337 | { |
| 338 | Assert(rtindex > 0); |
| 339 | epqstate->relsubs_done[rtindex - 1] = false; |
| 340 | } |
| 341 | } |
| 342 | } |
| 343 | } |
| 344 | |