From fd19a350ea0a69f26ac2f8cdc28fdd4ff9264adb Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 5 Aug 1999 02:33:54 +0000
Subject: [PATCH] Revise parse_coerce() to handle coercion of int and float
 constants, not only string constants, at parse time.  Get rid of
 parser_typecast2(), which is bogus and redundant...

---
 src/backend/parser/parse_coerce.c | 139 ++++++++++++++----------
 src/backend/parser/parse_expr.c   | 170 ++----------------------------
 src/backend/parser/parse_func.c   |  17 +--
 src/backend/parser/parse_type.c   |  19 +++-
 src/include/parser/parse_expr.h   |   3 +-
 src/include/parser/parse_type.h   |   5 +-
 6 files changed, 114 insertions(+), 239 deletions(-)

diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index df1bb3f2c21..026c66168ba 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.21 1999/07/17 20:17:23 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.22 1999/08/05 02:33:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,74 +35,101 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
 			int32 atttypmod)
 {
 	Node	   *result = NULL;
-	Type		targetType;
-	Oid			infunc;
-	Datum		val;
 
-	if (targetTypeId == InvalidOid)
+	if (targetTypeId == InvalidOid ||
+		targetTypeId == inputTypeId)
+	{
+		/* no conversion needed */
 		result = node;
-	else if (inputTypeId != targetTypeId)
+	}
+	else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
 	{
-
-		/*
-		 * one of the known-good transparent conversions? then drop
-		 * through...
+		/* no work if one of the known-good transparent conversions */
+		result = node;
+	}
+	else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
+	{
+		/* Input is a string constant with previously undetermined type.
+		 * Apply the target type's typinput function to it to produce
+		 * a constant of the target type.
+		 *
+		 * NOTE: this case cannot be folded together with the other
+		 * constant-input case, since the typinput function does not
+		 * necessarily behave the same as a type conversion function.
+		 * For example, int4's typinput function will reject "1.2",
+		 * whereas float-to-int type conversion will round to integer.
 		 */
-		if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
-			result = node;
+		Const	   *con = (Const *) node;
+		Type		targetType = typeidType(targetTypeId);
+		char	   *val;
 
+		/* We know the source constant is really of type 'text' */
+		val = textout((text *) con->constvalue);
+
+		/* now make a new const node */
+		con = makeNode(Const);
+		con->consttype = targetTypeId;
+		con->constlen = typeLen(targetType);
+		con->constvalue = stringTypeDatum(targetType, val, atttypmod);
+		con->constisnull = false;
+		con->constbyval = typeByVal(targetType);
+		con->constisset = false;
+
+		pfree(val);
+
+		result = (Node *) con;
+	}
+	else
+	{
 		/*
-		 * if not unknown input type, try for explicit conversion using
-		 * functions...
+		 * Otherwise, find the appropriate type conversion function
+		 * (caller should have determined that there is one), and
+		 * generate an expression tree representing run-time
+		 * application of the conversion function.
 		 */
-		else if (inputTypeId != UNKNOWNOID)
-		{
+		FuncCall   *n = makeNode(FuncCall);
+		Type		targetType = typeidType(targetTypeId);
 
-			/*
-			 * We already know there is a function which will do this, so
-			 * let's use it
-			 */
-			FuncCall   *n = makeNode(FuncCall);
+		n->funcname = typeTypeName(targetType);
+		n->args = lcons(node, NIL);
 
-			n->funcname = typeidTypeName(targetTypeId);
-			n->args = lcons(node, NIL);
+		result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
 
-			result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
-		}
-		else
+		/*
+		 * If the input is a constant, apply the type conversion function
+		 * now instead of delaying to runtime.  (This could someday be
+		 * done in a downstream constant-expression-simplifier, but we
+		 * can save cycles in the rewriter if we do it here.)
+		 *
+		 * XXX there are cases where we probably shouldn't do this,
+		 * such as coercing text 'now' to datetime?  Need a way to
+		 * know whether type conversion function is cacheable...
+		 */
+		if (IsA(node, Const))
 		{
-			if (nodeTag(node) == T_Const)
-			{
-				Const	   *con = (Const *) node;
-
-				val = (Datum) textout((struct varlena *) con->constvalue);
-				targetType = typeidType(targetTypeId);
-				infunc = typeInfunc(targetType);
-				con = makeNode(Const);
-				con->consttype = targetTypeId;
-				con->constlen = typeLen(targetType);
-
-				/*
-				 * Use "-1" for varchar() type. For char(), we need to pad
-				 * out the type with the proper number of spaces.  This
-				 * was a major problem for DEFAULT string constants to
-				 * char() types.
-				 */
-				con->constvalue = (Datum) fmgr(infunc,
-											   val,
-											   typeTypElem(targetType),
-						   (targetTypeId != BPCHAROID) ? -1 : atttypmod);
-				con->constisnull = false;
-				con->constbyval = typeByVal(targetType);
-				con->constisset = false;
-				result = (Node *) con;
-			}
-			else
-				result = node;
+			Const	   *con = (Const *) node;
+			Oid			convertFuncid;
+			Datum		val;
+
+			Assert(IsA(result, Expr) &&
+				   ((Expr *) result)->opType == FUNC_EXPR);
+
+			/* Convert the given constant */
+			convertFuncid = ((Func *) (((Expr *) result)->oper))->funcid;
+			val = (Datum) fmgr(convertFuncid, con->constvalue);
+
+			/* now make a new const node */
+			con = makeNode(Const);
+			con->consttype = targetTypeId;
+			con->constlen = typeLen(targetType);
+			con->constvalue = val;
+			con->constisnull = false;
+			con->constbyval = typeByVal(targetType);
+			con->constisset = false;
+
+			result = (Node *) con;
 		}
 	}
-	else
-		result = node;
 
 	return result;
 }
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index e9a67453342..0ecee29f52d 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.55 1999/07/19 00:26:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.56 1999/08/05 02:33:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -631,16 +631,16 @@ exprTypmod(Node *expr)
 	return -1;
 }
 
+/*
+ * Produce an appropriate Const node from a constant value produced
+ * by the parser and an explicit type name to cast to.
+ */
 static Node *
 parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
 {
-	/* check for passing non-ints */
 	Const	   *adt;
 	Datum		lcp;
 	Type		tp;
-	char		type_string[NAMEDATALEN];
-	int32		len;
-	char	   *cp = NULL;
 	char	   *const_string = NULL;
 	bool		string_palloced = false;
 
@@ -659,180 +659,30 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
 			break;
 		default:
 			elog(ERROR,
-			 "parser_typecast: cannot cast this expression to type '%s'",
+				 "parser_typecast: cannot cast this expression to type '%s'",
 				 typename->name);
 	}
 
 	if (typename->arrayBounds != NIL)
 	{
+		char		type_string[NAMEDATALEN+2];
+
 		sprintf(type_string, "_%s", typename->name);
 		tp = (Type) typenameType(type_string);
 	}
 	else
 		tp = (Type) typenameType(typename->name);
 
-	len = typeLen(tp);
-
-	cp = stringTypeString(tp, const_string, atttypmod);
-
-	if (!typeByVal(tp))
-		lcp = PointerGetDatum(cp);
-	else
-	{
-		switch (len)
-		{
-			case 1:
-				lcp = Int8GetDatum(cp);
-				break;
-			case 2:
-				lcp = Int16GetDatum(cp);
-				break;
-			case 4:
-				lcp = Int32GetDatum(cp);
-				break;
-			default:
-				lcp = PointerGetDatum(cp);
-				break;
-		}
-	}
-
-	adt = makeConst(typeTypeId(tp),
-					len,
-					(Datum) lcp,
-					false,
-					typeByVal(tp),
-					false,		/* not a set */
-					true /* is cast */ );
-
-	if (string_palloced)
-		pfree(const_string);
-
-	return (Node *) adt;
-}
-
-
-/* parser_typecast2()
- * Convert (only) constants to specified type.
- */
-Node *
-parser_typecast2(Node *expr, Oid exprType, Type tp, int32 atttypmod)
-{
-	/* check for passing non-ints */
-	Const	   *adt;
-	Datum		lcp;
-	int32		len = typeLen(tp);
-	char	   *cp = NULL;
-
-	char	   *const_string = NULL;
-	bool		string_palloced = false;
-
-	Assert(IsA(expr, Const));
-
-	switch (exprType)
-	{
-		case 0:			/* NULL */
-			break;
-		case INT4OID:			/* int4 */
-			const_string = (char *) palloc(256);
-			string_palloced = true;
-			sprintf(const_string, "%d",
-					(int) ((Const *) expr)->constvalue);
-			break;
-		case NAMEOID:			/* name */
-			const_string = (char *) palloc(256);
-			string_palloced = true;
-			sprintf(const_string, "%s",
-					(char *) ((Const *) expr)->constvalue);
-			break;
-		case CHAROID:			/* char */
-			const_string = (char *) palloc(256);
-			string_palloced = true;
-			sprintf(const_string, "%c",
-					(char) ((Const *) expr)->constvalue);
-			break;
-		case FLOAT4OID: /* float4 */
-			{
-				float32		floatVal = DatumGetFloat32(((Const *) expr)->constvalue);
-
-				const_string = (char *) palloc(256);
-				string_palloced = true;
-				sprintf(const_string, "%f", *floatVal);
-				break;
-			}
-		case FLOAT8OID: /* float8 */
-			{
-				float64		floatVal = DatumGetFloat64(((Const *) expr)->constvalue);
-
-				const_string = (char *) palloc(256);
-				string_palloced = true;
-				sprintf(const_string, "%f", *floatVal);
-				break;
-			}
-		case CASHOID:			/* money */
-			const_string = (char *) palloc(256);
-			string_palloced = true;
-			sprintf(const_string, "%ld",
-					(long) ((Const *) expr)->constvalue);
-			break;
-		case TEXTOID:			/* text */
-			const_string = DatumGetPointer(((Const *) expr)->constvalue);
-			const_string = (char *) textout((struct varlena *) const_string);
-			break;
-		case UNKNOWNOID:		/* unknown */
-			const_string = DatumGetPointer(((Const *) expr)->constvalue);
-			const_string = (char *) textout((struct varlena *) const_string);
-			break;
-		default:
-			elog(ERROR, "unknown type %u", exprType);
-	}
-
-	if (!exprType)
-	{
-		adt = makeConst(typeTypeId(tp),
-						(Size) 0,
-						(Datum) NULL,
-						true,	/* isnull */
-						false,	/* was omitted */
-						false,	/* not a set */
-						true /* is cast */ );
-		return (Node *) adt;
-	}
-
-	cp = stringTypeString(tp, const_string, atttypmod);
-
-	if (!typeByVal(tp))
-		lcp = PointerGetDatum(cp);
-	else
-	{
-		switch (len)
-		{
-			case 1:
-				lcp = Int8GetDatum(cp);
-				break;
-			case 2:
-				lcp = Int16GetDatum(cp);
-				break;
-			case 4:
-				lcp = Int32GetDatum(cp);
-				break;
-			default:
-				lcp = PointerGetDatum(cp);
-				break;
-		}
-	}
+	lcp = stringTypeDatum(tp, const_string, atttypmod);
 
 	adt = makeConst(typeTypeId(tp),
-					(Size) len,
+					typeLen(tp),
 					(Datum) lcp,
 					false,
 					typeByVal(tp),
 					false,		/* not a set */
 					true /* is cast */ );
 
-	/*
-	 * printf("adt %s : %u %d %d\n",CString(expr),typeTypeId(tp) ,
-	 * len,cp);
-	 */
 	if (string_palloced)
 		pfree(const_string);
 
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 33d93fc9eb8..65f177885d4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.50 1999/07/17 20:17:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.51 1999/08/05 02:33:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1278,21 +1278,8 @@ make_arguments(ParseState *pstate,
 		 i < nargs;
 		 i++, current_fargs = lnext(current_fargs))
 	{
-
-		/*
-		 * unspecified type for string constant? then use heuristics for
-		 * conversion...
-		 */
-		if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
-		{
-			lfirst(current_fargs) = parser_typecast2(lfirst(current_fargs),
-													 input_typeids[i],
-										 typeidType(function_typeids[i]),
-													 -1);
-		}
-
 		/* types don't match? then force coersion using a function call... */
-		else if (input_typeids[i] != function_typeids[i])
+		if (input_typeids[i] != function_typeids[i])
 		{
 			lfirst(current_fargs) = coerce_type(pstate,
 												lfirst(current_fargs),
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ae826adcd90..38cf29d636c 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.24 1999/07/17 20:17:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.25 1999/08/05 02:33:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -133,8 +133,8 @@ typeTypeFlag(Type t)
 
 /* Given a type structure and a string, returns the internal form of
    that string */
-char *
-stringTypeString(Type tp, char *string, int32 atttypmod)
+Datum
+stringTypeDatum(Type tp, char *string, int32 atttypmod)
 {
 	Oid			op;
 	Oid			typelem;
@@ -142,7 +142,7 @@ stringTypeString(Type tp, char *string, int32 atttypmod)
 	op = ((Form_pg_type) GETSTRUCT(tp))->typinput;
 	typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem;	/* XXX - used for
 														 * array_in */
-	return (char *) fmgr(op, string, typelem, atttypmod);
+	return (Datum) fmgr(op, string, typelem, atttypmod);
 }
 
 /* Given a type id, returns the out-conversion function of the type */
@@ -242,3 +242,14 @@ typeInfunc(Type typ)
 
 	return typtup->typinput;
 }
+
+/* Given a type structure, return the out-conversion function of the type */
+Oid
+typeOutfunc(Type typ)
+{
+	Form_pg_type typtup;
+
+	typtup = (Form_pg_type) GETSTRUCT(typ);
+
+	return typtup->typoutput;
+}
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index 3bd4d3fb47c..52d723db1cf 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_expr.h,v 1.14 1999/07/19 00:26:16 tgl Exp $
+ * $Id: parse_expr.h,v 1.15 1999/08/05 02:33:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,5 @@
 extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
 extern Oid	exprType(Node *expr);
 extern int32 exprTypmod(Node *expr);
-extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod);
 
 #endif	 /* PARSE_EXPR_H */
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 5ca8f9b34c5..3b722af6f13 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_type.h,v 1.10 1999/05/29 03:17:19 tgl Exp $
+ * $Id: parse_type.h,v 1.11 1999/08/05 02:33:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,11 +26,12 @@ extern int16 typeLen(Type t);
 extern bool typeByVal(Type t);
 extern char *typeTypeName(Type t);
 extern char typeTypeFlag(Type t);
-extern char *stringTypeString(Type tp, char *string, int32 atttypmod);
+extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
 extern Oid	typeidTypeRelid(Oid type_id);
 extern Oid	typeTypeRelid(Type typ);
 extern Oid	typeTypElem(Type typ);
 extern Oid	GetArrayElementType(Oid typearray);
 extern Oid	typeInfunc(Type typ);
+extern Oid	typeOutfunc(Type typ);
 
 #endif	 /* PARSE_TYPE_H */
-- 
GitLab