*** a/src/backend/utils/adt/xid.c
--- b/src/backend/utils/adt/xid.c
***************
*** 32,40 ****
  Datum
  xidin(PG_FUNCTION_ARGS)
  {
! 	char	   *str = PG_GETARG_CSTRING(0);
  
! 	PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
  }
  
  Datum
--- 32,83 ----
  Datum
  xidin(PG_FUNCTION_ARGS)
  {
! 	unsigned long cvt;
! 	char	   *endptr;
! 	char	   *s = PG_GETARG_CSTRING(0);
! 	
! 	if (*s == '\0')
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
! 				 errmsg("invalid input syntax for type xid: \"%s\"",
! 						s)));
  
! 	errno = 0;
! 	cvt = strtoul(s, &endptr, 0);
! 
! 	/*
! 	 * strtoul() normally only sets ERANGE.  On some systems it also may set
! 	 * EINVAL, which simply means it couldn't parse the input string. This is
! 	 * handled by the second "if" consistent across platforms.
! 	 */
! 	if (errno && errno != ERANGE && errno != EINVAL)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
! 				 errmsg("invalid input syntax for type xid: \"%s\"",
! 						s)));
! 
! 	if (endptr == s)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
! 				 errmsg("invalid input syntax for type xid: \"%s\"",
! 						s)));
! 
! 	if (errno == ERANGE)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 				 errmsg("value \"%s\" is out of range for type xid", s)));
! 
! 		/* allow only whitespace after number */
! 	while (*endptr && isspace((unsigned char) *endptr))
! 		endptr++;
! 	if (*endptr)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
! 				 errmsg("invalid input syntax for type xid: \"%s\"",
! 						s)));
! 
! 
! 	PG_RETURN_TRANSACTIONID((TransactionId) cvt);
  }
  
  Datum
