@@ -499,7 +499,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
499499 /* Initialize ResultPartsStorage */
500500 init_result_parts_storage (& parts_storage , estate , false,
501501 ResultPartsStorageStandard ,
502- prepare_rri_for_copy , NULL );
502+ prepare_rri_for_copy , cstate );
503503 parts_storage .saved_rel_info = parent_result_rel ;
504504
505505 /* Set up a tuple slot too */
@@ -634,13 +634,20 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
634634 /* Check the constraints of the tuple */
635635 if (child_result_rel -> ri_RelationDesc -> rd_att -> constr )
636636 ExecConstraints (child_result_rel , slot , estate );
637+ if (!child_result_rel -> ri_FdwRoutine )
638+ {
639+ /* OK, store the tuple and create index entries for it */
640+ simple_heap_insert (child_result_rel -> ri_RelationDesc , tuple );
637641
638- /* OK, store the tuple and create index entries for it */
639- simple_heap_insert (child_result_rel -> ri_RelationDesc , tuple );
640-
641- if (child_result_rel -> ri_NumIndices > 0 )
642- recheckIndexes = ExecInsertIndexTuples (slot , & (tuple -> t_self ),
643- estate , false, NULL , NIL );
642+ if (child_result_rel -> ri_NumIndices > 0 )
643+ recheckIndexes = ExecInsertIndexTuples (slot , & (tuple -> t_self ),
644+ estate , false, NULL , NIL );
645+ }
646+ else /* FDW table */
647+ {
648+ child_result_rel -> ri_FdwRoutine -> ForeignNextCopyFrom (
649+ estate , child_result_rel , cstate );
650+ }
644651
645652 /* AFTER ROW INSERT Triggers (FIXME: NULL transition) */
646653 ExecARInsertTriggersCompat (estate , child_result_rel , tuple ,
@@ -677,6 +684,24 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
677684
678685 ExecResetTupleTable (estate -> es_tupleTable , false);
679686
687+ {
688+ /* Shut down FDWs. TODO: make hook in fini_result_parts_storage? */
689+ HASH_SEQ_STATUS stat ;
690+ ResultRelInfoHolder * rri_holder ; /* ResultRelInfo holder */
691+
692+ hash_seq_init (& stat , parts_storage .result_rels_table );
693+ while ((rri_holder = (ResultRelInfoHolder * ) hash_seq_search (& stat )) != NULL )
694+ {
695+ ResultRelInfo * resultRelInfo = rri_holder -> result_rel_info ;
696+
697+ if (resultRelInfo -> ri_FdwRoutine )
698+ {
699+ resultRelInfo -> ri_FdwRoutine -> EndForeignCopyFrom (
700+ estate , resultRelInfo );
701+ }
702+ }
703+ }
704+
680705 /* Close partitions and destroy hash table */
681706 fini_result_parts_storage (& parts_storage , true);
682707
@@ -689,7 +714,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
689714}
690715
691716/*
692- * COPY FROM does not support FDWs, emit ERROR .
717+ * Init COPY FROM, if supported .
693718 */
694719static void
695720prepare_rri_for_copy (EState * estate ,
@@ -699,10 +724,17 @@ prepare_rri_for_copy(EState *estate,
699724{
700725 ResultRelInfo * rri = rri_holder -> result_rel_info ;
701726 FdwRoutine * fdw_routine = rri -> ri_FdwRoutine ;
727+ CopyState cstate = (CopyState ) arg ;
702728
703729 if (fdw_routine != NULL )
704- elog (ERROR , "cannot copy to foreign partition \"%s\"" ,
705- get_rel_name (RelationGetRelid (rri -> ri_RelationDesc )));
730+ {
731+ if (!FdwCopyFromIsSupported (fdw_routine ))
732+ ereport (ERROR ,
733+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
734+ errmsg ("FDW adapter for relation \"%s\" doesn't support COPY FROM" ,
735+ RelationGetRelationName (rri -> ri_RelationDesc ))));
736+ rri -> ri_FdwRoutine -> BeginForeignCopyFrom (estate , rri , cstate );
737+ }
706738}
707739
708740/*
0 commit comments