Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c3928b4

Browse files
committed
Fix segfault during EvalPlanQual with mix of local and foreign partitions.
It's not sensible to re-evaluate a direct-modify Foreign Update or Delete during EvalPlanQual. However, ExecInitForeignScan() can still get called if a table mixes local and foreign partitions. EvalPlanQualStart() left the es_result_relations array uninitialized in the child EPQ EState, but ExecInitForeignScan() still expected to find it. That caused a segfault. Fix by skipping the es_result_relations lookup during EvalPlanQual processing. To make things a bit more robust, also skip the BeginDirectModify calls, and add a runtime check that ExecForeignScan() is not called on direct-modify foreign scans during EvalPlanQual processing. This is new in v14, commit 1375422. Before that, EvalPlanQualStart() copied the whole ResultRelInfo array to the EPQ EState. Backpatch to v14. Report and diagnosis by Andrey Lepikhov. Discussion: https://www.postgresql.org/message-id/cb2b808d-cbaa-4772-76ee-c8809bafcf3d%40postgrespro.ru
1 parent a6bd28b commit c3928b4

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

src/backend/executor/nodeForeignscan.c

+41-5
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,22 @@ ForeignNext(ForeignScanState *node)
4444
TupleTableSlot *slot;
4545
ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
4646
ExprContext *econtext = node->ss.ps.ps_ExprContext;
47+
EState *estate = node->ss.ps.state;
4748
MemoryContext oldcontext;
4849

4950
/* Call the Iterate function in short-lived context */
5051
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
5152
if (plan->operation != CMD_SELECT)
53+
{
54+
/*
55+
* direct modifications cannot be re-evaluated, so shouldn't get here
56+
* during EvalPlanQual processing
57+
*/
58+
if (estate->es_epq_active != NULL)
59+
elog(ERROR, "cannot re-evaluate a Foreign Update or Delete during EvalPlanQual");
60+
5261
slot = node->fdwroutine->IterateDirectModify(node);
62+
}
5363
else
5464
slot = node->fdwroutine->IterateForeignScan(node);
5565
MemoryContextSwitchTo(oldcontext);
@@ -223,11 +233,25 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
223233
scanstate->fdw_state = NULL;
224234

225235
/*
226-
* For the FDW's convenience, look up the modification target relation's.
227-
* ResultRelInfo.
236+
* For the FDW's convenience, look up the modification target relation's
237+
* ResultRelInfo. The ModifyTable node should have initialized it for us,
238+
* see ExecInitModifyTable.
239+
*
240+
* Don't try to look up the ResultRelInfo when EvalPlanQual is active,
241+
* though. Direct modififications cannot be re-evaluated as part of
242+
* EvalPlanQual. The lookup wouldn't work anyway because during
243+
* EvalPlanQual processing, EvalPlanQual only initializes the subtree
244+
* under the ModifyTable, and doesn't run ExecInitModifyTable.
228245
*/
229-
if (node->resultRelation > 0)
246+
if (node->resultRelation > 0 && estate->es_epq_active == NULL)
247+
{
248+
if (estate->es_result_relations == NULL ||
249+
estate->es_result_relations[node->resultRelation - 1] == NULL)
250+
{
251+
elog(ERROR, "result relation not initialized");
252+
}
230253
scanstate->resultRelInfo = estate->es_result_relations[node->resultRelation - 1];
254+
}
231255

232256
/* Initialize any outer plan. */
233257
if (outerPlan(node))
@@ -238,7 +262,15 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
238262
* Tell the FDW to initialize the scan.
239263
*/
240264
if (node->operation != CMD_SELECT)
241-
fdwroutine->BeginDirectModify(scanstate, eflags);
265+
{
266+
/*
267+
* Direct modifications cannot be re-evaluated by EvalPlanQual, so
268+
* don't bother preparing the FDW. There can ForeignScan nodes in the
269+
* EvalPlanQual subtree, but ExecForeignScan should never be called.
270+
*/
271+
if (estate->es_epq_active == NULL)
272+
fdwroutine->BeginDirectModify(scanstate, eflags);
273+
}
242274
else
243275
fdwroutine->BeginForeignScan(scanstate, eflags);
244276

@@ -255,10 +287,14 @@ void
255287
ExecEndForeignScan(ForeignScanState *node)
256288
{
257289
ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
290+
EState *estate = node->ss.ps.state;
258291

259292
/* Let the FDW shut down */
260293
if (plan->operation != CMD_SELECT)
261-
node->fdwroutine->EndDirectModify(node);
294+
{
295+
if (estate->es_epq_active == NULL)
296+
node->fdwroutine->EndDirectModify(node);
297+
}
262298
else
263299
node->fdwroutine->EndForeignScan(node);
264300

0 commit comments

Comments
 (0)