diff options
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r-- | contrib/postgres_fdw/postgres_fdw.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index fea288e8ebb..bfa9a1823b6 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -183,6 +183,10 @@ typedef struct PgFdwModifyState /* working memory context */ MemoryContext temp_cxt; /* context for per-tuple temporary data */ + + /* for update row movement if subplan result rel */ + struct PgFdwModifyState *aux_fmstate; /* foreign-insert state, if + * created */ } PgFdwModifyState; /* @@ -1773,6 +1777,13 @@ postgresExecForeignInsert(EState *estate, PGresult *res; int n_rows; + /* + * If the fmstate has aux_fmstate set, use the aux_fmstate (see + * postgresBeginForeignInsert()) + */ + if (fmstate->aux_fmstate) + fmstate = fmstate->aux_fmstate; + /* Set up the prepared statement on the remote server, if we didn't yet */ if (!fmstate->p_name) prepare_foreign_modify(fmstate); @@ -2013,6 +2024,22 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, List *retrieved_attrs = NIL; bool doNothing = false; + /* + * If the foreign table we are about to insert routed rows into is also + * an UPDATE subplan result rel that will be updated later, proceeding + * with the INSERT will result in the later UPDATE incorrectly modifying + * those routed rows, so prevent the INSERT --- it would be nice if we + * could handle this case; but for now, throw an error for safety. + */ + if (plan && plan->operation == CMD_UPDATE && + (resultRelInfo->ri_usesFdwDirectModify || + resultRelInfo->ri_FdwState) && + resultRelInfo > mtstate->resultRelInfo + mtstate->mt_whichplan) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot route tuples into foreign table to be updated \"%s\"", + RelationGetRelationName(rel)))); + initStringInfo(&sql); /* We transmit all columns that are defined in the foreign table. */ @@ -2079,7 +2106,19 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, retrieved_attrs != NIL, retrieved_attrs); - resultRelInfo->ri_FdwState = fmstate; + /* + * If the given resultRelInfo already has PgFdwModifyState set, it means + * the foreign table is an UPDATE subplan result rel; in which case, store + * the resulting state into the aux_fmstate of the PgFdwModifyState. + */ + if (resultRelInfo->ri_FdwState) + { + Assert(plan && plan->operation == CMD_UPDATE); + Assert(resultRelInfo->ri_usesFdwDirectModify == false); + ((PgFdwModifyState *) resultRelInfo->ri_FdwState)->aux_fmstate = fmstate; + } + else + resultRelInfo->ri_FdwState = fmstate; } /* @@ -2094,6 +2133,13 @@ postgresEndForeignInsert(EState *estate, Assert(fmstate != NULL); + /* + * If the fmstate has aux_fmstate set, get the aux_fmstate (see + * postgresBeginForeignInsert()) + */ + if (fmstate->aux_fmstate) + fmstate = fmstate->aux_fmstate; + /* Destroy the execution state */ finish_foreign_modify(fmstate); } @@ -3390,6 +3436,9 @@ create_foreign_modify(EState *estate, Assert(fmstate->p_nums <= n_params); + /* Initialize auxiliary state */ + fmstate->aux_fmstate = NULL; + return fmstate; } |