| 1 | /* ------------------------------------------------------------------------ |
| 2 | * |
| 3 | * nodeCustom.c |
| 4 | * Routines to handle execution of custom scan node |
| 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 | */ |
| 11 | #include "postgres.h" |
| 12 | |
| 13 | #include "access/parallel.h" |
| 14 | #include "executor/executor.h" |
| 15 | #include "executor/nodeCustom.h" |
| 16 | #include "nodes/execnodes.h" |
| 17 | #include "nodes/extensible.h" |
| 18 | #include "nodes/plannodes.h" |
| 19 | #include "miscadmin.h" |
| 20 | #include "parser/parsetree.h" |
| 21 | #include "utils/hsearch.h" |
| 22 | #include "utils/memutils.h" |
| 23 | #include "utils/rel.h" |
| 24 | |
| 25 | |
| 26 | static TupleTableSlot *ExecCustomScan(PlanState *pstate); |
| 27 | |
| 28 | |
| 29 | CustomScanState * |
| 30 | ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) |
| 31 | { |
| 32 | CustomScanState *css; |
| 33 | Relation scan_rel = NULL; |
| 34 | Index scanrelid = cscan->scan.scanrelid; |
| 35 | Index tlistvarno; |
| 36 | |
| 37 | /* |
| 38 | * Allocate the CustomScanState object. We let the custom scan provider |
| 39 | * do the palloc, in case it wants to make a larger object that embeds |
| 40 | * CustomScanState as the first field. It must set the node tag and the |
| 41 | * methods field correctly at this time. Other standard fields should be |
| 42 | * set to zero. |
| 43 | */ |
| 44 | css = castNode(CustomScanState, |
| 45 | cscan->methods->CreateCustomScanState(cscan)); |
| 46 | |
| 47 | /* ensure flags is filled correctly */ |
| 48 | css->flags = cscan->flags; |
| 49 | |
| 50 | /* fill up fields of ScanState */ |
| 51 | css->ss.ps.plan = &cscan->scan.plan; |
| 52 | css->ss.ps.state = estate; |
| 53 | css->ss.ps.ExecProcNode = ExecCustomScan; |
| 54 | |
| 55 | /* create expression context for node */ |
| 56 | ExecAssignExprContext(estate, &css->ss.ps); |
| 57 | |
| 58 | /* |
| 59 | * open the scan relation, if any |
| 60 | */ |
| 61 | if (scanrelid > 0) |
| 62 | { |
| 63 | scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags); |
| 64 | css->ss.ss_currentRelation = scan_rel; |
| 65 | } |
| 66 | |
| 67 | /* |
| 68 | * Determine the scan tuple type. If the custom scan provider provided a |
| 69 | * targetlist describing the scan tuples, use that; else use base |
| 70 | * relation's rowtype. |
| 71 | */ |
| 72 | if (cscan->custom_scan_tlist != NIL || scan_rel == NULL) |
| 73 | { |
| 74 | TupleDesc scan_tupdesc; |
| 75 | |
| 76 | scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist); |
| 77 | ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, &TTSOpsVirtual); |
| 78 | /* Node's targetlist will contain Vars with varno = INDEX_VAR */ |
| 79 | tlistvarno = INDEX_VAR; |
| 80 | } |
| 81 | else |
| 82 | { |
| 83 | ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel), |
| 84 | &TTSOpsVirtual); |
| 85 | /* Node's targetlist will contain Vars with varno = scanrelid */ |
| 86 | tlistvarno = scanrelid; |
| 87 | } |
| 88 | |
| 89 | /* |
| 90 | * Initialize result slot, type and projection. |
| 91 | */ |
| 92 | ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual); |
| 93 | ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno); |
| 94 | |
| 95 | /* initialize child expressions */ |
| 96 | css->ss.ps.qual = |
| 97 | ExecInitQual(cscan->scan.plan.qual, (PlanState *) css); |
| 98 | |
| 99 | /* |
| 100 | * The callback of custom-scan provider applies the final initialization |
| 101 | * of the custom-scan-state node according to its logic. |
| 102 | */ |
| 103 | css->methods->BeginCustomScan(css, estate, eflags); |
| 104 | |
| 105 | return css; |
| 106 | } |
| 107 | |
| 108 | static TupleTableSlot * |
| 109 | ExecCustomScan(PlanState *pstate) |
| 110 | { |
| 111 | CustomScanState *node = castNode(CustomScanState, pstate); |
| 112 | |
| 113 | CHECK_FOR_INTERRUPTS(); |
| 114 | |
| 115 | Assert(node->methods->ExecCustomScan != NULL); |
| 116 | return node->methods->ExecCustomScan(node); |
| 117 | } |
| 118 | |
| 119 | void |
| 120 | ExecEndCustomScan(CustomScanState *node) |
| 121 | { |
| 122 | Assert(node->methods->EndCustomScan != NULL); |
| 123 | node->methods->EndCustomScan(node); |
| 124 | |
| 125 | /* Free the exprcontext */ |
| 126 | ExecFreeExprContext(&node->ss.ps); |
| 127 | |
| 128 | /* Clean out the tuple table */ |
| 129 | ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); |
| 130 | ExecClearTuple(node->ss.ss_ScanTupleSlot); |
| 131 | } |
| 132 | |
| 133 | void |
| 134 | ExecReScanCustomScan(CustomScanState *node) |
| 135 | { |
| 136 | Assert(node->methods->ReScanCustomScan != NULL); |
| 137 | node->methods->ReScanCustomScan(node); |
| 138 | } |
| 139 | |
| 140 | void |
| 141 | ExecCustomMarkPos(CustomScanState *node) |
| 142 | { |
| 143 | if (!node->methods->MarkPosCustomScan) |
| 144 | ereport(ERROR, |
| 145 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 146 | errmsg("custom scan \"%s\" does not support MarkPos" , |
| 147 | node->methods->CustomName))); |
| 148 | node->methods->MarkPosCustomScan(node); |
| 149 | } |
| 150 | |
| 151 | void |
| 152 | ExecCustomRestrPos(CustomScanState *node) |
| 153 | { |
| 154 | if (!node->methods->RestrPosCustomScan) |
| 155 | ereport(ERROR, |
| 156 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 157 | errmsg("custom scan \"%s\" does not support MarkPos" , |
| 158 | node->methods->CustomName))); |
| 159 | node->methods->RestrPosCustomScan(node); |
| 160 | } |
| 161 | |
| 162 | void |
| 163 | ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt) |
| 164 | { |
| 165 | const CustomExecMethods *methods = node->methods; |
| 166 | |
| 167 | if (methods->EstimateDSMCustomScan) |
| 168 | { |
| 169 | node->pscan_len = methods->EstimateDSMCustomScan(node, pcxt); |
| 170 | shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len); |
| 171 | shm_toc_estimate_keys(&pcxt->estimator, 1); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | void |
| 176 | ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt) |
| 177 | { |
| 178 | const CustomExecMethods *methods = node->methods; |
| 179 | |
| 180 | if (methods->InitializeDSMCustomScan) |
| 181 | { |
| 182 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
| 183 | void *coordinate; |
| 184 | |
| 185 | coordinate = shm_toc_allocate(pcxt->toc, node->pscan_len); |
| 186 | methods->InitializeDSMCustomScan(node, pcxt, coordinate); |
| 187 | shm_toc_insert(pcxt->toc, plan_node_id, coordinate); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | void |
| 192 | ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt) |
| 193 | { |
| 194 | const CustomExecMethods *methods = node->methods; |
| 195 | |
| 196 | if (methods->ReInitializeDSMCustomScan) |
| 197 | { |
| 198 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
| 199 | void *coordinate; |
| 200 | |
| 201 | coordinate = shm_toc_lookup(pcxt->toc, plan_node_id, false); |
| 202 | methods->ReInitializeDSMCustomScan(node, pcxt, coordinate); |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | void |
| 207 | ExecCustomScanInitializeWorker(CustomScanState *node, |
| 208 | ParallelWorkerContext *pwcxt) |
| 209 | { |
| 210 | const CustomExecMethods *methods = node->methods; |
| 211 | |
| 212 | if (methods->InitializeWorkerCustomScan) |
| 213 | { |
| 214 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
| 215 | void *coordinate; |
| 216 | |
| 217 | coordinate = shm_toc_lookup(pwcxt->toc, plan_node_id, false); |
| 218 | methods->InitializeWorkerCustomScan(node, pwcxt->toc, coordinate); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | void |
| 223 | ExecShutdownCustomScan(CustomScanState *node) |
| 224 | { |
| 225 | const CustomExecMethods *methods = node->methods; |
| 226 | |
| 227 | if (methods->ShutdownCustomScan) |
| 228 | methods->ShutdownCustomScan(node); |
| 229 | } |
| 230 | |