*** a/contrib/file_fdw/file_fdw.c --- b/contrib/file_fdw/file_fdw.c *************** *** 502,507 **** fileIterateForeignScan(ForeignScanState *node) --- 502,510 ---- { FileFdwExecutionState *festate = (FileFdwExecutionState *) node->fdw_state; TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; + Relation rel = node->ss.ss_currentRelation; + TupleConstr *constr = rel->rd_att->constr; + bool has_not_null = (constr != NULL) ? constr->has_not_null : false; bool found; ErrorContextCallback errcontext; *************** *** 528,534 **** fileIterateForeignScan(ForeignScanState *node) --- 531,556 ---- slot->tts_values, slot->tts_isnull, NULL); if (found) + { ExecStoreVirtualTuple(slot); + if (has_not_null) + { + int natts = rel->rd_att->natts; + int attrChk; + + for (attrChk = 1; attrChk <= natts; attrChk++) + { + if (rel->rd_att->attrs[attrChk - 1]->attnotnull && + slot_attisnull(slot, attrChk)) + ereport(ERROR, + (errcode(ERRCODE_NOT_NULL_VIOLATION), + errmsg("null value in column \"%s\" violates not-null constraint", + NameStr(rel->rd_att->attrs[attrChk - 1]->attname)), + errdetail("Failing row contains %s.", + ExecBuildSlotValueDescription(slot, 64)))); + } + } + } /* Remove error callback. */ error_context_stack = errcontext.previous; *** a/src/backend/executor/execMain.c --- b/src/backend/executor/execMain.c *************** *** 86,93 **** static void ExecutePlan(EState *estate, PlanState *planstate, DestReceiver *dest); static bool ExecCheckRTEPerms(RangeTblEntry *rte); static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt); - static char *ExecBuildSlotValueDescription(TupleTableSlot *slot, - int maxfieldlen); static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree); static void OpenIntoRel(QueryDesc *queryDesc); --- 86,91 ---- *************** *** 1604,1610 **** ExecConstraints(ResultRelInfo *resultRelInfo, * here since heap field values could be very long, whereas index entries * typically aren't so wide. */ ! static char * ExecBuildSlotValueDescription(TupleTableSlot *slot, int maxfieldlen) { StringInfoData buf; --- 1602,1608 ---- * here since heap field values could be very long, whereas index entries * typically aren't so wide. */ ! char * ExecBuildSlotValueDescription(TupleTableSlot *slot, int maxfieldlen) { StringInfoData buf; *** a/src/include/executor/executor.h --- b/src/include/executor/executor.h *************** *** 184,189 **** extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); --- 184,191 ---- extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); extern void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate); + extern char *ExecBuildSlotValueDescription(TupleTableSlot *slot, + int maxfieldlen); extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti); extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist); extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,