diff --git a/src/backend/executor/.execMain.c.swp b/src/backend/executor/.execMain.c.swp index 6f54fd9..8a29cc6 100644 Binary files a/src/backend/executor/.execMain.c.swp and b/src/backend/executor/.execMain.c.swp differ diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index eb24051..04d90ea 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1082,86 +1082,88 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) RelationGetRelationName(resultRel)))); break; case RELKIND_FOREIGN_TABLE: - /* Okay only if the FDW supports it */ - fdwroutine = GetFdwRoutineForRelation(resultRel, false); - switch (operation) - { - case CMD_INSERT: - if (fdwroutine->ExecForeignInsert == NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot insert into foreign table \"%s\"", - RelationGetRelationName(resultRel)))); - if (fdwroutine->IsForeignRelUpdatable != NULL && - (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_INSERT)) == 0) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("foreign table \"%s\" does not allow inserts", - RelationGetRelationName(resultRel)))); - break; - case CMD_UPDATE: - if (fdwroutine->ExecForeignUpdate == NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot update foreign table \"%s\"", - RelationGetRelationName(resultRel)))); - if (fdwroutine->IsForeignRelUpdatable != NULL && - (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_UPDATE)) == 0) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("foreign table \"%s\" does not allow updates", - RelationGetRelationName(resultRel)))); - break; - case CMD_DELETE: - if (fdwroutine->ExecForeignDelete == NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot delete from foreign table \"%s\"", - RelationGetRelationName(resultRel)))); - if (fdwroutine->IsForeignRelUpdatable != NULL && - (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_DELETE)) == 0) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("foreign table \"%s\" does not allow deletes", - RelationGetRelationName(resultRel)))); - break; - default: - elog(ERROR, "unrecognized CmdType: %d", (int) operation); - break; - } - if (resultRelInfo->ri_FdwPushdown) { - if (fdwroutine->BeginDMLPushdown == NULL || - fdwroutine->IterateDMLPushdown == NULL || - fdwroutine->EndDMLPushdown == NULL) + /* + * Mark DMLPushdownOk if DML is pushed down safe and FDW provides + * the DMLPushdown APIs. Later if ExecForeignInsert or + * ExecForeignUpdate or ExecForeignDelete is missing and + * DMLPushdownOk is false, then only throw an error. + */ + bool DMLPushdownOk = false; + /* Okay only if the FDW supports it */ + fdwroutine = GetFdwRoutineForRelation(resultRel, false); + if (resultRelInfo->ri_FdwPushdown) { - switch (operation) + if (fdwroutine->BeginDMLPushdown == NULL || + fdwroutine->IterateDMLPushdown == NULL || + fdwroutine->EndDMLPushdown == NULL) { - case CMD_INSERT: + switch (operation) + { + case CMD_INSERT: + case CMD_UPDATE: + case CMD_DELETE: + DMLPushdownOk = false; + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) operation); + break; + } + } + else + DMLPushdownOk = true; + } + + switch (operation) + { + case CMD_INSERT: + if (fdwroutine->ExecForeignInsert == NULL && + !DMLPushdownOk) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot push down insert on foreign table \"%s\"", + errmsg("cannot insert into foreign table \"%s\"", RelationGetRelationName(resultRel)))); - break; - case CMD_UPDATE: + if (fdwroutine->IsForeignRelUpdatable != NULL && + (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_INSERT)) == 0) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("foreign table \"%s\" does not allow inserts", + RelationGetRelationName(resultRel)))); + break; + case CMD_UPDATE: + if (fdwroutine->ExecForeignUpdate == NULL && + !DMLPushdownOk) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot push down update on foreign table \"%s\"", + errmsg("cannot update foreign table \"%s\"", RelationGetRelationName(resultRel)))); - break; - case CMD_DELETE: + if (fdwroutine->IsForeignRelUpdatable != NULL && + (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_UPDATE)) == 0) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("foreign table \"%s\" does not allow updates", + RelationGetRelationName(resultRel)))); + break; + case CMD_DELETE: + if (fdwroutine->ExecForeignDelete == NULL && + !DMLPushdownOk) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot push down delete on foreign table \"%s\"", + errmsg("cannot delete from foreign table \"%s\"", RelationGetRelationName(resultRel)))); - break; - default: - elog(ERROR, "unrecognized CmdType: %d", (int) operation); - break; - } + if (fdwroutine->IsForeignRelUpdatable != NULL && + (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_DELETE)) == 0) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("foreign table \"%s\" does not allow deletes", + RelationGetRelationName(resultRel)))); + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) operation); + break; } + break; } - break; default: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE),