diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a7ea96ec72d252dc73c897d5a7c6d0603dc8c22b..acf948816d071c28bc502734d24fb9b33bb4c705 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.187 2005/01/28 19:34:07 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.188 2005/02/02 21:49:07 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -49,6 +49,7 @@
 typedef struct
 {
 	List	   *active_fns;
+	Node	   *case_val;
 	bool		estimate;
 } eval_const_expressions_context;
 
@@ -1195,6 +1196,7 @@ eval_const_expressions(Node *node)
 	eval_const_expressions_context context;
 
 	context.active_fns = NIL;	/* nothing being recursively simplified */
+	context.case_val = NULL;	/* no CASE being examined */
 	context.estimate = false;	/* safe transformations only */
 	return eval_const_expressions_mutator(node, &context);
 }
@@ -1219,6 +1221,7 @@ estimate_expression_value(Node *node)
 	eval_const_expressions_context context;
 
 	context.active_fns = NIL;	/* nothing being recursively simplified */
+	context.case_val = NULL;	/* no CASE being examined */
 	context.estimate = true;	/* unsafe transformations OK */
 	return eval_const_expressions_mutator(node, &context);
 }
@@ -1592,71 +1595,98 @@ eval_const_expressions_mutator(Node *node,
 		 * If there are no non-FALSE alternatives, we simplify the entire
 		 * CASE to the default result (ELSE result).
 		 *
-		 * If we have a simple-form CASE with constant test expression and
-		 * one or more constant comparison expressions, we could run the
-		 * implied comparisons and potentially reduce those arms to constants.
-		 * This is not yet implemented, however.  At present, the
-		 * CaseTestExpr placeholder will always act as a non-constant node
-		 * and prevent the comparison boolean expressions from being reduced
-		 * to Const nodes.
+		 * If we have a simple-form CASE with constant test expression,
+		 * we substitute the constant value for contained CaseTestExpr
+		 * placeholder nodes, so that we have the opportunity to reduce
+		 * constant test conditions.  For example this allows
+		 *		CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
+		 * to reduce to 1 rather than drawing a divide-by-0 error.
 		 *----------
 		 */
 		CaseExpr   *caseexpr = (CaseExpr *) node;
 		CaseExpr   *newcase;
+		Node	   *save_case_val;
 		Node	   *newarg;
 		List	   *newargs;
-		Node	   *defresult;
-		Const	   *const_input;
+		bool		const_true_cond;
+		Node	   *defresult = NULL;
 		ListCell   *arg;
 
 		/* Simplify the test expression, if any */
 		newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
 												context);
 
+		/* Set up for contained CaseTestExpr nodes */
+		save_case_val = context->case_val;
+		if (newarg && IsA(newarg, Const))
+			context->case_val = newarg;
+		else
+			context->case_val = NULL;
+
 		/* Simplify the WHEN clauses */
 		newargs = NIL;
+		const_true_cond = false;
 		foreach(arg, caseexpr->args)
 		{
-			/* Simplify this alternative's condition and result */
-			CaseWhen   *casewhen = (CaseWhen *)
-			expression_tree_mutator((Node *) lfirst(arg),
-									eval_const_expressions_mutator,
-									(void *) context);
-
-			Assert(IsA(casewhen, CaseWhen));
-			if (casewhen->expr == NULL ||
-				!IsA(casewhen->expr, Const))
-			{
-				newargs = lappend(newargs, casewhen);
-				continue;
-			}
-			const_input = (Const *) casewhen->expr;
-			if (const_input->constisnull ||
-				!DatumGetBool(const_input->constvalue))
-				continue;		/* drop alternative with FALSE condition */
+			CaseWhen   *oldcasewhen = (CaseWhen *) lfirst(arg);
+			Node	   *casecond;
+			Node	   *caseresult;
+
+			Assert(IsA(oldcasewhen, CaseWhen));
+
+			/* Simplify this alternative's test condition */
+			casecond =
+				eval_const_expressions_mutator((Node *) oldcasewhen->expr,
+											   context);
 
 			/*
-			 * Found a TRUE condition.	If it's the first (un-dropped)
-			 * alternative, the CASE reduces to just this alternative.
+			 * If the test condition is constant FALSE (or NULL), then drop
+			 * this WHEN clause completely, without processing the result.
 			 */
-			if (newargs == NIL)
-				return (Node *) casewhen->result;
+			if (casecond && IsA(casecond, Const))
+			{
+				Const	   *const_input = (Const *) casecond;
+
+				if (const_input->constisnull ||
+					!DatumGetBool(const_input->constvalue))
+					continue;	/* drop alternative with FALSE condition */
+				/* Else it's constant TRUE */
+				const_true_cond = true;
+			}
+
+			/* Simplify this alternative's result value */
+			caseresult =
+				eval_const_expressions_mutator((Node *) oldcasewhen->result,
+											   context);
 
+			/* If non-constant test condition, emit a new WHEN node */
+			if (!const_true_cond)
+			{
+				CaseWhen   *newcasewhen = makeNode(CaseWhen);
+
+				newcasewhen->expr = (Expr *) casecond;
+				newcasewhen->result = (Expr *) caseresult;
+				newargs = lappend(newargs, newcasewhen);
+				continue;
+			}
+  
 			/*
-			 * Otherwise, add it to the list, and drop all the rest.
+			 * Found a TRUE condition, so none of the remaining alternatives
+			 * can be reached.  We treat the result as the default result.
 			 */
-			newargs = lappend(newargs, casewhen);
+			defresult = caseresult;
 			break;
 		}
 
-		/* Simplify the default result */
-		defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
-												   context);
+		/* Simplify the default result, unless we replaced it above */
+		if (!const_true_cond)
+			defresult =
+				eval_const_expressions_mutator((Node *) caseexpr->defresult,
+											   context);
 
-		/*
-		 * If no non-FALSE alternatives, CASE reduces to the default
-		 * result
-		 */
+		context->case_val = save_case_val;
+
+		/* If no non-FALSE alternatives, CASE reduces to the default result */
 		if (newargs == NIL)
 			return defresult;
 		/* Otherwise we need a new CASE node */
@@ -1667,6 +1697,18 @@ eval_const_expressions_mutator(Node *node,
 		newcase->defresult = (Expr *) defresult;
 		return (Node *) newcase;
 	}
+	if (IsA(node, CaseTestExpr))
+	{
+		/*
+		 * If we know a constant test value for the current CASE
+		 * construct, substitute it for the placeholder.  Else just
+		 * return the placeholder as-is.
+		 */
+		if (context->case_val)
+			return copyObject(context->case_val);
+		else
+			return copyObject(node);
+	}
 	if (IsA(node, ArrayExpr))
 	{
 		ArrayExpr  *arrayexpr = (ArrayExpr *) node;
diff --git a/src/test/regress/expected/case.out b/src/test/regress/expected/case.out
index df3fb094b3ec470186a642d6ca0f1452282051eb..9ec32b8bd26a2f9749756c4b5d56851a36790072 100644
--- a/src/test/regress/expected/case.out
+++ b/src/test/regress/expected/case.out
@@ -72,6 +72,23 @@ SELECT '6' AS "One",
  6   |                     6
 (1 row)
 
+-- Constant-expression folding shouldn't evaluate unreachable subexpressions
+SELECT CASE WHEN 1=0 THEN 1/0 WHEN 1=1 THEN 1 ELSE 2/0 END;
+ case 
+------
+    1
+(1 row)
+
+SELECT CASE 1 WHEN 0 THEN 1/0 WHEN 1 THEN 1 ELSE 2/0 END;
+ case 
+------
+    1
+(1 row)
+
+-- However we do not currently suppress folding of potentially
+-- reachable subexpressions
+SELECT CASE WHEN i > 100 THEN 1/0 ELSE 0 END FROM case_tbl;
+ERROR:  division by zero
 -- Test for cases involving untyped literals in test expression
 SELECT CASE 'a' WHEN 'a' THEN 1 ELSE 2 END;
  case 
diff --git a/src/test/regress/sql/case.sql b/src/test/regress/sql/case.sql
index 85e17e0807f496d5da079409ccc3dda9155fef5e..2ab22fb1c6d812fb544241169a0bf73966cb3a1c 100644
--- a/src/test/regress/sql/case.sql
+++ b/src/test/regress/sql/case.sql
@@ -58,6 +58,14 @@ SELECT '6' AS "One",
     ELSE 7
   END AS "Two WHEN with default";
 
+-- Constant-expression folding shouldn't evaluate unreachable subexpressions
+SELECT CASE WHEN 1=0 THEN 1/0 WHEN 1=1 THEN 1 ELSE 2/0 END;
+SELECT CASE 1 WHEN 0 THEN 1/0 WHEN 1 THEN 1 ELSE 2/0 END;
+
+-- However we do not currently suppress folding of potentially
+-- reachable subexpressions
+SELECT CASE WHEN i > 100 THEN 1/0 ELSE 0 END FROM case_tbl;
+
 -- Test for cases involving untyped literals in test expression
 SELECT CASE 'a' WHEN 'a' THEN 1 ELSE 2 END;