diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index d61af92..c73f9bc 100644
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 717,722 ****
--- 717,724 ----
  	alloc_var(&value, len);
  
  	value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
+ 	/* we allow any int16 for weight --- OK? */
+ 
  	value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
  	if (!(value.sign == NUMERIC_POS ||
  		  value.sign == NUMERIC_NEG ||
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 726,731 ****
--- 728,738 ----
  				 errmsg("invalid sign in external \"numeric\" value")));
  
  	value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
+ 	if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ 				 errmsg("invalid scale in external \"numeric\" value")));
+ 
  	for (i = 0; i < len; i++)
  	{
  		NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 737,742 ****
--- 744,757 ----
  		value.digits[i] = d;
  	}
  
+ 	/*
+ 	 * If the given dscale would hide any digits, truncate those digits away.
+ 	 * We could alternatively throw an error, but that would take a bunch of
+ 	 * extra code (about as much as trunc_var involves), and it might cause
+ 	 * client compatibility issues.
+ 	 */
+ 	trunc_var(&value, value.dscale);
+ 
  	apply_typmod(&value, typmod);
  
  	res = make_result(&value);
