@@ -659,9 +659,24 @@ CTranslatorDXLToPlStmt::TranslateDXLTblScan(
659659
660660 // The postgres_fdw wrapper does not support row level security. So
661661 // passing only the query_quals while creating the foreign scan node.
662+ //
663+ // BuildForeignScan internally calls build_simple_rel which looks up
664+ // RTEPermissionInfo via root->parse->rteperminfos. The RTE here was
665+ // newly created by ORCA with its own perminfoindex numbering, which
666+ // may not match m_orig_query->rteperminfos (e.g. after the rewriter
667+ // expands external-table ON SELECT rules into subqueries the outer
668+ // query's rteperminfos shrinks). Temporarily swap in ORCA's own
669+ // perminfos list so the indices are consistent.
670+ Query *orig_query = m_dxl_to_plstmt_context->m_orig_query ;
671+ List *saved_perminfos = orig_query->rteperminfos ;
672+ orig_query->rteperminfos =
673+ m_dxl_to_plstmt_context->GetPermInfosList ();
674+
662675 ForeignScan *foreign_scan =
663676 gpdb::CreateForeignScan (oidRel, index, query_quals, targetlist,
664- m_dxl_to_plstmt_context->m_orig_query , rte);
677+ orig_query, rte);
678+
679+ orig_query->rteperminfos = saved_perminfos;
665680 foreign_scan->scan .scanrelid = index;
666681 plan = &(foreign_scan->scan .plan );
667682 plan_return = (Plan *) foreign_scan;
@@ -4611,9 +4626,15 @@ CTranslatorDXLToPlStmt::TranslateDXLDynForeignScan(
46114626 RelationGetDescr (childRel),
46124627 index, qual, targetlist);
46134628
4629+ // Same perminfos swap as in the non-dynamic foreign scan path above.
4630+ Query *orig_query = m_dxl_to_plstmt_context->m_orig_query ;
4631+ List *saved_perminfos = orig_query->rteperminfos ;
4632+ orig_query->rteperminfos =
4633+ m_dxl_to_plstmt_context->GetPermInfosList ();
4634+
46144635 ForeignScan *foreign_scan_first_part =
46154636 gpdb::CreateForeignScan (oid_first_child, index, qual, targetlist,
4616- m_dxl_to_plstmt_context-> m_orig_query , rte);
4637+ orig_query , rte);
46174638
46184639 // Set the plan fields to the first partition. We still want the plan type to be
46194640 // a dynamic foreign scan
@@ -4645,11 +4666,14 @@ CTranslatorDXLToPlStmt::TranslateDXLDynForeignScan(
46454666
46464667 ForeignScan *foreign_scan =
46474668 gpdb::CreateForeignScan (rte->relid , index, qual, targetlist,
4648- m_dxl_to_plstmt_context-> m_orig_query , rte);
4669+ orig_query , rte);
46494670
46504671 dyn_foreign_scan->fdw_private_list = gpdb::LAppend (
46514672 dyn_foreign_scan->fdw_private_list , foreign_scan->fdw_private );
46524673 }
4674+
4675+ orig_query->rteperminfos = saved_perminfos;
4676+
46534677 // convert qual and targetlist back to root relation. This is used by the
46544678 // executor node to remap to the children
46554679 gpdb::RelationWrapper prevRel = gpdb::GetRelation (rte->relid );
@@ -5336,7 +5360,7 @@ CTranslatorDXLToPlStmt::ProcessDXLTblDescr(
53365360 rte->eref = alias;
53375361 rte->alias = alias;
53385362
5339- m_dxl_to_plstmt_context->AddPerfmInfo (pi);
5363+ m_dxl_to_plstmt_context->AddPermInfo (pi);
53405364
53415365 // set up rte <> perm info link.
53425366 rte->perminfoindex = gpdb::ListLength (
0 commit comments