From a060d5ffdcae76f8cabe0c4dbcbc3b88ad1515e7 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 20 Jun 2007 18:15:49 +0000
Subject: [PATCH] CREATE DOMAIN ... DEFAULT NULL failed because gram.y
 special-cases DEFAULT NULL and DefineDomain didn't.  Bug goes all the way
 back to original coding of domains.  Per bug #3396 from Sergey Burladyan.

---
 src/backend/commands/typecmds.c | 67 ++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 27 deletions(-)

diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d9748cf0ea8..86790308201 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.105 2007/06/15 20:56:49 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.106 2007/06/20 18:15:49 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -605,9 +605,9 @@ DefineDomain(CreateDomainStmt *stmt)
 	char		typtype;
 	Datum		datum;
 	bool		isnull;
-	Node	   *defaultExpr = NULL;
 	char	   *defaultValue = NULL;
 	char	   *defaultValueBin = NULL;
+	bool		saw_default = false;
 	bool		typNotNull = false;
 	bool		nullDefined = false;
 	int32		typNDims = list_length(stmt->typename->arrayBounds);
@@ -719,7 +719,6 @@ DefineDomain(CreateDomainStmt *stmt)
 	{
 		Node	   *newConstraint = lfirst(listptr);
 		Constraint *constr;
-		ParseState *pstate;
 
 		/* Check for unsupported constraint types */
 		if (IsA(newConstraint, FkConstraint))
@@ -740,35 +739,49 @@ DefineDomain(CreateDomainStmt *stmt)
 
 				/*
 				 * The inherited default value may be overridden by the user
-				 * with the DEFAULT <expr> statement.
+				 * with the DEFAULT <expr> clause ... but only once.
 				 */
-				if (defaultExpr)
+				if (saw_default)
 					ereport(ERROR,
 							(errcode(ERRCODE_SYNTAX_ERROR),
 							 errmsg("multiple default expressions")));
+				saw_default = true;
 
-				/* Create a dummy ParseState for transformExpr */
-				pstate = make_parsestate(NULL);
-
-				/*
-				 * Cook the constr->raw_expr into an expression. Note: Name is
-				 * strictly for error message
-				 */
-				defaultExpr = cookDefault(pstate, constr->raw_expr,
-										  basetypeoid,
-										  basetypeMod,
-										  domainName);
-
-				/*
-				 * Expression must be stored as a nodeToString result, but we
-				 * also require a valid textual representation (mainly to make
-				 * life easier for pg_dump).
-				 */
-				defaultValue = deparse_expression(defaultExpr,
-											  deparse_context_for(domainName,
-																  InvalidOid),
-												  false, false);
-				defaultValueBin = nodeToString(defaultExpr);
+				if (constr->raw_expr)
+				{
+					ParseState *pstate;
+					Node	   *defaultExpr;
+
+					/* Create a dummy ParseState for transformExpr */
+					pstate = make_parsestate(NULL);
+
+					/*
+					 * Cook the constr->raw_expr into an expression.
+					 * Note: name is strictly for error message
+					 */
+					defaultExpr = cookDefault(pstate, constr->raw_expr,
+											  basetypeoid,
+											  basetypeMod,
+											  domainName);
+
+					/*
+					 * Expression must be stored as a nodeToString result, but
+					 * we also require a valid textual representation (mainly
+					 * to make life easier for pg_dump).
+					 */
+					defaultValue =
+						deparse_expression(defaultExpr,
+										   deparse_context_for(domainName,
+															   InvalidOid),
+										   false, false);
+					defaultValueBin = nodeToString(defaultExpr);
+				}
+				else
+				{
+					/* DEFAULT NULL is same as not having a default */
+					defaultValue = NULL;
+					defaultValueBin = NULL;
+				}
 				break;
 
 			case CONSTR_NOTNULL:
-- 
GitLab