file_fdw_notnull_v1.patch

text/plain

Filename: file_fdw_notnull_v1.patch
Type: text/plain
Part: 0
Message: NOT NULL violation error handling in file_fdw

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
Series: patch v1
File+
contrib/file_fdw/file_fdw.c 22 0
src/backend/executor/execMain.c 1 0
src/include/executor/executor.h 2 0
*** 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,