diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d6fc0b0a62..b14fde0799 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.149 2000/02/22 00:05:04 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.150 2000/02/24 01:59:17 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -5606,14 +5606,17 @@ Oid param_type(int t)
 }
 
 /*
- *	The optimizer doesn't like '-' 4 for index use.  It only checks for
- *	Var '=' Const.  It wants an integer of -4, so we try to merge the
- *	minus into the constant.
+ * doNegate --- handle negation of a numeric constant.
  *
- *	This code is no longer essential as of 10/1999, since the optimizer
- *	now has a constant-subexpression simplifier.  However, we can save
- *	a few cycles throughout the parse and rewrite stages if we collapse
- *	the minus into the constant sooner rather than later...
+ * Formerly, we did this here because the optimizer couldn't cope with
+ * indexquals that looked like "var = -4" --- it wants "var = const"
+ * and a unary minus operator applied to a constant didn't qualify.
+ * As of Postgres 7.0, that problem doesn't exist anymore because there
+ * is a constant-subexpression simplifier in the optimizer.  However,
+ * there's still a good reason for doing this here, which is that we can
+ * postpone committing to a particular internal representation for simple
+ * negative constants.  It's better to leave "-123.456" in string form
+ * until we know what the desired type is.
  */
 static Node *
 doNegate(Node *n)
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 19d2d11e5c..2d365db91d 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,13 +8,16 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.37 2000/01/26 05:56:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.38 2000/02/24 01:59:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <ctype.h>
+#include <errno.h>
+#include <float.h>
 
 #include "postgres.h"
+
 #include "access/heapam.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
@@ -32,6 +35,8 @@
 #include "utils/syscache.h"
 
 static void disallow_setop(char *op, Type optype, Node *operand);
+static bool fitsInFloat(Value *value);
+
 
 /* make_parsestate()
  * Allocate and initialize a new ParseState.
@@ -393,11 +398,25 @@ transformArraySubscripts(ParseState *pstate,
  * make_const
  *
  *	Convert a Value node (as returned by the grammar) to a Const node
- *	of the "natural" type for the constant.  For strings we produce
- *	a constant of type UNKNOWN ---- representation is the same as text,
- *	but this indicates to later type resolution that we're not sure that
- *	it should be considered text.  Explicit "NULL" constants are also
- *	typed as UNKNOWN.
+ *	of the "natural" type for the constant.  Note that this routine is
+ *	only used when there is no explicit cast for the constant, so we
+ *	have to guess what type is wanted.
+ *
+ *	For string literals we produce a constant of type UNKNOWN ---- whose
+ *	representation is the same as text, but it indicates to later type
+ *	resolution that we're not sure that it should be considered text.
+ *	Explicit "NULL" constants are also typed as UNKNOWN.
+ *
+ *  For integers and floats we produce int4, float8, or numeric depending
+ *	on the value of the number.  XXX In some cases it would be nice to take
+ *	context into account when determining the type to convert to, but in
+ *	other cases we can't delay the type choice.  One possibility is to invent
+ *	a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN;
+ *	that would allow us to do the right thing in examples like a simple
+ *	INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't
+ *	have to resolve the unknown type until we knew the destination column
+ *	type.  On the other hand UNKNOWN has considerable problems of its own.
+ *	We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type.
  */
 Const *
 make_const(Value *value)
@@ -419,18 +438,25 @@ make_const(Value *value)
 			break;
 
 		case T_Float:
+			if (fitsInFloat(value))
 			{
-				float64		dummy;
+				float64		fltval = (float64) palloc(sizeof(float64data));
 
-				dummy = (float64) palloc(sizeof(float64data));
-				*dummy = floatVal(value);
-
-				val = Float64GetDatum(dummy);
+				*fltval = floatVal(value);
+				val = Float64GetDatum(fltval);
 
 				typeid = FLOAT8OID;
 				typelen = sizeof(float64data);
 				typebyval = false;
 			}
+			else
+			{
+				val = PointerGetDatum(numeric_in(strVal(value), 0, -1));
+
+				typeid = NUMERICOID;
+				typelen = -1;	/* variable len */
+				typebyval = false;
+			}
 			break;
 
 		case T_String:
@@ -441,11 +467,11 @@ make_const(Value *value)
 			typebyval = false;
 			break;
 
-		case T_Null:
 		default:
-			if (nodeTag(value) != T_Null)
-				elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
+			elog(NOTICE, "make_const: unknown type %d", nodeTag(value));
+			/* FALLTHROUGH */
 
+		case T_Null:
 			/* return a null const */
 			con = makeConst(UNKNOWNOID,
 							-1,
@@ -467,3 +493,45 @@ make_const(Value *value)
 
 	return con;
 }
+
+/*
+ * Decide whether a T_Float value fits in float8, or must be treated as
+ * type "numeric".  We check the number of digits and check for overflow/
+ * underflow.  (With standard compilation options, Postgres' NUMERIC type
+ * can handle decimal exponents up to 1000, considerably more than most
+ * implementations of float8, so this is a sensible test.)
+ */
+static bool
+fitsInFloat(Value *value)
+{
+	const char	   *ptr;
+	int				ndigits;
+	char		   *endptr;
+
+	/*
+	 * Count digits, ignoring leading zeroes (but not trailing zeroes).
+	 * DBL_DIG is the maximum safe number of digits for "double".
+	 */
+	ptr = strVal(value);
+	while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.')
+		ptr++;
+	ndigits = 0;
+	for (; *ptr; ptr++)
+	{
+		if (isdigit(*ptr))
+			ndigits++;
+		else if (*ptr == 'e' || *ptr == 'E')
+			break;				/* don't count digits in exponent */
+	}
+	if (ndigits > DBL_DIG)
+		return false;
+	/*
+	 * Use strtod() to check for overflow/underflow.
+	 */
+	errno = 0;
+	(void) strtod(strVal(value), &endptr);
+	if (*endptr != '\0' || errno != 0)
+		return false;
+
+	return true;
+}