| 1150 | } |
| 1151 | |
| 1152 | void |
| 1153 | standard_ExecutorFinish(QueryDesc *queryDesc) |
| 1154 | { |
| 1155 | EState *estate; |
| 1156 | PlanState *planstate = NULL; |
| 1157 | GpExecIdentity exec_identity; |
| 1158 | MemoryContext oldcontext; |
| 1159 | |
| 1160 | /* sanity checks */ |
| 1161 | Assert(queryDesc != NULL); |
| 1162 | |
| 1163 | estate = queryDesc->estate; |
| 1164 | |
| 1165 | Assert(estate != NULL); |
| 1166 | Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY)); |
| 1167 | |
| 1168 | /* This should be run once and only once per Executor instance */ |
| 1169 | Assert(!estate->es_finished); |
| 1170 | |
| 1171 | /* Switch into per-query memory context */ |
| 1172 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
| 1173 | |
| 1174 | /* Allow instrumentation of Executor overall runtime */ |
| 1175 | if (queryDesc->totaltime) |
| 1176 | InstrStartNode(queryDesc->totaltime); |
| 1177 | |
| 1178 | /* Run ModifyTable nodes to completion */ |
| 1179 | ExecPostprocessPlan(estate); |
| 1180 | |
| 1181 | /* Execute queued AFTER triggers, unless told not to */ |
| 1182 | if (!(estate->es_top_eflags & EXEC_FLAG_SKIP_TRIGGERS)) |
| 1183 | AfterTriggerEndQuery(estate); |
| 1184 | |
| 1185 | if (queryDesc->totaltime) |
| 1186 | InstrStopNode(queryDesc->totaltime, 0); |
| 1187 | |
| 1188 | /* |
| 1189 | * To squelch the whole plan as the query is finished |
| 1190 | * |
| 1191 | * For material node, when 'delayEagerFree' is true, it |
| 1192 | * will not be squelched even if 'ExecSquelchNode' is |
| 1193 | * called on it. But if it is not squechled, it will |
| 1194 | * not send the stop msg to its child motion node, and |
| 1195 | * the sender motion will hang there until the connection |
| 1196 | * is reset or closed. This can lead some issues. |
| 1197 | * For e.g: sometimes we need to collect the querystate |
| 1198 | * from all the backends through |
| 1199 | * 'cdbexplain_recvExecStats'. It will wait until the QE |
| 1200 | * sending the querystate to it. But the QE only sends |
| 1201 | * that in 'standard_ExecutorEnd'. But if it is still |
| 1202 | * blocked at sending out tuples, then the whole query |
| 1203 | * will hang up. |
| 1204 | */ |
| 1205 | exec_identity = getGpExecIdentity(queryDesc, ForwardScanDirection, estate); |
| 1206 | if (exec_identity == GP_NON_ROOT_ON_QE) |
| 1207 | planstate = (PlanState *)getMotionState(queryDesc->planstate, LocallyExecutingSliceIndex(estate)); |
| 1208 | else if (exec_identity == GP_ROOT_SLICE) |
| 1209 | planstate = queryDesc->planstate; |
no test coverage detected