From 7476e3718b038f563d39ea7f108fbff156275c94 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 20 Jan 2000 02:24:50 +0000
Subject: [PATCH] Assign a typmod of -1 to unadorned CHAR and NUMERIC type
 specs.  This allows casts without specific length requirements to continue to
 work as they did before; that is, x::char will not truncate the value of x,
 whereas x::char(1) will.  Likewise for NUMERIC precision/scale. The column
 length defaults of char(1) and numeric(30,6) are now inserted in analyze.c's
 processing of CREATE TABLE.

---
 src/backend/parser/analyze.c | 39 ++++++++++++++++++++++--
 src/backend/parser/gram.y    | 57 ++++++++++++++++--------------------
 2 files changed, 62 insertions(+), 34 deletions(-)

diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 0dd1e9907a8..a4c2dd7eff9 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: analyze.c,v 1.130 2000/01/16 08:21:59 tgl Exp $
+ *	$Id: analyze.c,v 1.131 2000/01/20 02:24:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,11 @@
 #include "parser/parse_clause.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
+#include "parser/parse_type.h"
 #include "utils/builtins.h"
+#include "utils/numeric.h"
+
+void		CheckSelectForUpdate(Query *qry); /* no points for style... */
 
 static Query *transformStmt(ParseState *pstate, Node *stmt);
 static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
@@ -38,7 +42,7 @@ static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
 
 static void transformForUpdate(Query *qry, List *forUpdate);
 static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
-void		CheckSelectForUpdate(Query *qry);
+static void transformColumnType(ParseState *pstate, ColumnDef *column);
 
 /* kluge to return extra info from transformCreateStmt() */
 static List	   *extras_before;
@@ -601,6 +605,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
 				column = (ColumnDef *) element;
 				columns = lappend(columns, column);
 
+				transformColumnType(pstate, column);
+
 				/* Special case SERIAL type? */
 				if (column->is_sequence)
 				{
@@ -1701,4 +1707,31 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 	heap_close(pkrel, AccessShareLock);
 }
 
-
+/*
+ * Special handling of type definition for a column
+ */
+static void
+transformColumnType(ParseState *pstate, ColumnDef *column)
+{
+	/*
+	 * If the column doesn't have an explicitly specified typmod,
+	 * check to see if we want to insert a default length.
+	 *
+	 * Note that we deliberately do NOT look at array or set information
+	 * here; "numeric[]" needs the same default typmod as "numeric".
+	 */
+	if (column->typename->typmod == -1)
+	{
+		switch (typeTypeId(typenameType(column->typename->name)))
+		{
+			case BPCHAROID:
+				/* "char" -> "char(1)" */
+				column->typename->typmod = VARHDRSZ + 1;
+				break;
+			case NUMERICOID:
+				column->typename->typmod = VARHDRSZ +
+					((NUMERIC_DEFAULT_PRECISION<<16) | NUMERIC_DEFAULT_SCALE);
+				break;
+		}
+	}
+}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d62f3ef61c6..ca22fc095f2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.131 2000/01/18 23:30:20 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.132 2000/01/20 02:24:50 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -1032,6 +1032,7 @@ columnDef:  ColId Typename ColConstraintList
 					n->colname = $1;
 					n->typename = makeNode(TypeName);
 					n->typename->name = xlateSqlType("integer");
+					n->typename->typmod = -1;
 					n->raw_default = NULL;
 					n->cooked_default = NULL;
 					n->is_not_null = TRUE;
@@ -2280,6 +2281,7 @@ func_return:  set_opt TypeId
 					n->name = $2;
 					n->setof = $1;
 					n->arrayBounds = NULL;
+					n->typmod = -1;
 					$$ = (Node *)n;
 				}
 		;
@@ -3643,12 +3645,13 @@ Numeric:  FLOAT opt_float
 		| DOUBLE PRECISION
 				{
 					$$ = makeNode(TypeName);
-					$$->name = xlateSqlType("float");
+					$$->name = xlateSqlType("float8");
+					$$->typmod = -1;
 				}
 		| DECIMAL opt_decimal
 				{
 					$$ = makeNode(TypeName);
-					$$->name = xlateSqlType("numeric");
+					$$->name = xlateSqlType("decimal");
 					$$->typmod = $2;
 				}
 		| NUMERIC opt_numeric
@@ -3664,7 +3667,7 @@ numeric:  FLOAT
 		| DOUBLE PRECISION
 				{	$$ = xlateSqlType("float8"); }
 		| DECIMAL
-				{	$$ = xlateSqlType("numeric"); }
+				{	$$ = xlateSqlType("decimal"); }
 		| NUMERIC
 				{	$$ = xlateSqlType("numeric"); }
 		;
@@ -3707,7 +3710,8 @@ opt_numeric:  '(' Iconst ',' Iconst ')'
 				}
 		| /*EMPTY*/
 				{
-					$$ = ((NUMERIC_DEFAULT_PRECISION << 16) | NUMERIC_DEFAULT_SCALE) + VARHDRSZ;
+					/* Insert "-1" meaning "default"; may be replaced later */
+					$$ = -1;
 				}
 		;
 
@@ -3732,53 +3736,39 @@ opt_decimal:  '(' Iconst ',' Iconst ')'
 				}
 		| /*EMPTY*/
 				{
-					$$ = ((NUMERIC_DEFAULT_PRECISION << 16) | NUMERIC_DEFAULT_SCALE) + VARHDRSZ;
+					/* Insert "-1" meaning "default"; may be replaced later */
+					$$ = -1;
 				}
 		;
 
 
-/* SQL92 character data types
+/*
+ * SQL92 character data types
  * The following implements CHAR() and VARCHAR().
  */
 Character:  character '(' Iconst ')'
 				{
 					$$ = makeNode(TypeName);
-					if (strcasecmp($1, "char") == 0)
-						$$->name = xlateSqlType("bpchar");
-					else if (strcasecmp($1, "varchar") == 0)
-						$$->name = xlateSqlType("varchar");
-					else
-						yyerror("internal parsing error; unrecognized character type");
-
+					$$->name = xlateSqlType($1);
 					if ($3 < 1)
-						elog(ERROR,"length for '%s' type must be at least 1",$1);
+						elog(ERROR,"length for type '%s' must be at least 1",$1);
 					else if ($3 > MaxAttrSize)
 						elog(ERROR,"length for type '%s' cannot exceed %ld",$1,
 							MaxAttrSize);
 
-					/* we actually implement this sort of like a varlen, so
+					/* we actually implement these like a varlen, so
 					 * the first 4 bytes is the length. (the difference
-					 * between this and "text" is that we blank-pad and
-					 * truncate where necessary
+					 * between these and "text" is that we blank-pad and
+					 * truncate where necessary)
 					 */
 					$$->typmod = VARHDRSZ + $3;
 				}
 		| character
 				{
 					$$ = makeNode(TypeName);
-					/* Let's try to make all single-character types into bpchar(1)
-					 * - thomas 1998-05-07
-					 */
-					if (strcasecmp($1, "char") == 0)
-					{
-						$$->name = xlateSqlType("bpchar");
-						$$->typmod = VARHDRSZ + 1;
-					}
-					else
-					{
-						$$->name = xlateSqlType($1);
-						$$->typmod = -1;
-					}
+					$$->name = xlateSqlType($1);
+					/* default length, if needed, will be inserted later */
+					$$->typmod = -1;
 				}
 		;
 
@@ -5131,6 +5121,7 @@ ColLabel:  ColId						{ $$ = $1; }
 		| EXPLAIN						{ $$ = "explain"; }
 		| EXTEND						{ $$ = "extend"; }
 		| FALSE_P						{ $$ = "false"; }
+		| FLOAT							{ $$ = "float"; }
 		| FOREIGN						{ $$ = "foreign"; }
 		| GLOBAL						{ $$ = "global"; }
 		| GROUP							{ $$ = "group"; }
@@ -5314,6 +5305,10 @@ xlateSqlType(char *name)
 	else if (!strcasecmp(name, "real")
 	 || !strcasecmp(name, "float"))
 		return "float8";
+	else if (!strcasecmp(name, "decimal"))
+		return "numeric";
+	else if (!strcasecmp(name, "char"))
+		return "bpchar";
 	else if (!strcasecmp(name, "interval"))
 		return "timespan";
 	else if (!strcasecmp(name, "boolean"))
-- 
GitLab