2222#include "access/xact.h"
2323#include "catalog/namespace.h"
2424#include "commands/copy.h"
25+ #include "commands/defrem.h"
2526#include "commands/trigger.h"
2627#include "commands/tablecmds.h"
2728#include "foreign/fdwapi.h"
@@ -64,10 +65,10 @@ static uint64 PathmanCopyFrom(CopyState cstate,
6465 List * range_table ,
6566 bool old_protocol );
6667
67- static void prepare_rri_for_copy (EState * estate ,
68- ResultRelInfoHolder * rri_holder ,
69- const ResultPartsStorage * rps_storage ,
70- void * arg );
68+ static void prepare_rri_for_copy (ResultRelInfoHolder * rri_holder ,
69+ const ResultPartsStorage * rps_storage );
70+ static void finish_rri_copy ( ResultRelInfoHolder * rri_holder ,
71+ const ResultPartsStorage * rps_storage );
7172
7273
7374/*
@@ -110,12 +111,18 @@ is_pathman_related_copy(Node *parsetree)
110111 /* Analyze options list */
111112 foreach (lc , copy_stmt -> options )
112113 {
113- DefElem * defel = (DefElem * ) lfirst (lc );
114-
115- Assert (IsA (defel , DefElem ));
114+ DefElem * defel = lfirst_node (DefElem , lc );
116115
117116 /* We do not support freeze */
118- if (strcmp (defel -> defname , "freeze" ) == 0 )
117+ /*
118+ * It would be great to allow copy.c extract option value and
119+ * check it ready. However, there is no possibility (hooks) to do
120+ * that before messaging 'ok, begin streaming data' to the client,
121+ * which is ugly and confusing: e.g. it would require us to
122+ * actually send something in regression tests before we notice
123+ * the error.
124+ */
125+ if (strcmp (defel -> defname , "freeze" ) == 0 && defGetBoolean (defel ))
119126 elog (ERROR , "freeze is not supported for partitioned tables" );
120127 }
121128
@@ -481,7 +488,6 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
481488
482489 uint64 processed = 0 ;
483490
484-
485491 tupDesc = RelationGetDescr (parent_rel );
486492
487493 parent_result_rel = makeNode (ResultRelInfo );
@@ -499,7 +505,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
499505 /* Initialize ResultPartsStorage */
500506 init_result_parts_storage (& parts_storage , estate , false,
501507 ResultPartsStorageStandard ,
502- prepare_rri_for_copy , NULL );
508+ prepare_rri_for_copy , cstate );
503509 parts_storage .saved_rel_info = parent_result_rel ;
504510
505511 /* Set up a tuple slot too */
@@ -634,13 +640,22 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
634640 /* Check the constraints of the tuple */
635641 if (child_result_rel -> ri_RelationDesc -> rd_att -> constr )
636642 ExecConstraints (child_result_rel , slot , estate );
643+ if (!child_result_rel -> ri_FdwRoutine )
644+ {
645+ /* OK, store the tuple and create index entries for it */
646+ simple_heap_insert (child_result_rel -> ri_RelationDesc , tuple );
637647
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 );
648+ if (child_result_rel -> ri_NumIndices > 0 )
649+ recheckIndexes = ExecInsertIndexTuples (slot , & (tuple -> t_self ),
650+ estate , false, NULL , NIL );
651+ }
652+ #ifdef PG_SHARDMAN
653+ else /* FDW table */
654+ {
655+ child_result_rel -> ri_FdwRoutine -> ForeignNextCopyFrom (
656+ estate , child_result_rel , cstate );
657+ }
658+ #endif
644659
645660 /* AFTER ROW INSERT Triggers (FIXME: NULL transition) */
646661 ExecARInsertTriggersCompat (estate , child_result_rel , tuple ,
@@ -678,7 +693,7 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
678693 ExecResetTupleTable (estate -> es_tupleTable , false);
679694
680695 /* Close partitions and destroy hash table */
681- fini_result_parts_storage (& parts_storage , true);
696+ fini_result_parts_storage (& parts_storage , true, finish_rri_copy );
682697
683698 /* Close parent's indices */
684699 ExecCloseIndices (parent_result_rel );
@@ -689,20 +704,58 @@ PathmanCopyFrom(CopyState cstate, Relation parent_rel,
689704}
690705
691706/*
692- * COPY FROM does not support FDWs, emit ERROR .
707+ * Init COPY FROM, if supported .
693708 */
694709static void
695- prepare_rri_for_copy (EState * estate ,
696- ResultRelInfoHolder * rri_holder ,
697- const ResultPartsStorage * rps_storage ,
698- void * arg )
710+ prepare_rri_for_copy (ResultRelInfoHolder * rri_holder ,
711+ const ResultPartsStorage * rps_storage )
699712{
700- ResultRelInfo * rri = rri_holder -> result_rel_info ;
701- FdwRoutine * fdw_routine = rri -> ri_FdwRoutine ;
713+ ResultRelInfo * rri = rri_holder -> result_rel_info ;
714+ FdwRoutine * fdw_routine = rri -> ri_FdwRoutine ;
702715
703716 if (fdw_routine != NULL )
717+ {
718+ /*
719+ * If this Postgres has no idea about shardman, behave as usual:
720+ * vanilla Postgres doesn't support COPY FROM to foreign partitions.
721+ * However, shardman patches to core extend FDW API to allow it.
722+ */
723+ #ifdef PG_SHARDMAN
724+ /* shardman COPY FROM requested? */
725+ if (* find_rendezvous_variable (
726+ "shardman_pathman_copy_from_rendezvous" ) != NULL &&
727+ FdwCopyFromIsSupported (fdw_routine ))
728+ {
729+ CopyState cstate = (CopyState ) rps_storage -> callback_arg ;
730+ ResultRelInfo * parent_rri = rps_storage -> saved_rel_info ;
731+ EState * estate = rps_storage -> estate ;
732+
733+ fdw_routine -> BeginForeignCopyFrom (estate , rri , cstate , parent_rri );
734+ return ;
735+ }
736+ #endif
737+
704738 elog (ERROR , "cannot copy to foreign partition \"%s\"" ,
705739 get_rel_name (RelationGetRelid (rri -> ri_RelationDesc )));
740+ }
741+ }
742+
743+ /*
744+ * Shut down FDWs.
745+ */
746+ static void
747+ finish_rri_copy (ResultRelInfoHolder * rri_holder ,
748+ const ResultPartsStorage * rps_storage )
749+ {
750+ #ifdef PG_SHARDMAN
751+ ResultRelInfo * resultRelInfo = rri_holder -> result_rel_info ;
752+
753+ if (resultRelInfo -> ri_FdwRoutine )
754+ {
755+ resultRelInfo -> ri_FdwRoutine -> EndForeignCopyFrom (
756+ rps_storage -> estate , resultRelInfo );
757+ }
758+ #endif
706759}
707760
708761/*
0 commit comments