@@ -499,7 +499,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
499
499
/* Initialize ResultPartsStorage */
500
500
init_result_parts_storage (& parts_storage , estate , false,
501
501
ResultPartsStorageStandard ,
502
- prepare_rri_for_copy , NULL );
502
+ prepare_rri_for_copy , cstate );
503
503
parts_storage .saved_rel_info = parent_result_rel ;
504
504
505
505
/* Set up a tuple slot too */
@@ -634,13 +634,20 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
634
634
/* Check the constraints of the tuple */
635
635
if (child_result_rel -> ri_RelationDesc -> rd_att -> constr )
636
636
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 );
637
641
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
+ }
644
651
645
652
/* AFTER ROW INSERT Triggers (FIXME: NULL transition) */
646
653
ExecARInsertTriggersCompat (estate , child_result_rel , tuple ,
@@ -677,6 +684,24 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
677
684
678
685
ExecResetTupleTable (estate -> es_tupleTable , false);
679
686
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
+
680
705
/* Close partitions and destroy hash table */
681
706
fini_result_parts_storage (& parts_storage , true);
682
707
@@ -689,7 +714,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
689
714
}
690
715
691
716
/*
692
- * COPY FROM does not support FDWs, emit ERROR .
717
+ * Init COPY FROM, if supported .
693
718
*/
694
719
static void
695
720
prepare_rri_for_copy (EState * estate ,
@@ -699,10 +724,17 @@ prepare_rri_for_copy(EState *estate,
699
724
{
700
725
ResultRelInfo * rri = rri_holder -> result_rel_info ;
701
726
FdwRoutine * fdw_routine = rri -> ri_FdwRoutine ;
727
+ CopyState cstate = (CopyState ) arg ;
702
728
703
729
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
+ }
706
738
}
707
739
708
740
/*
0 commit comments