From e114e3a2708cab8efd64281d09cecbd6303aa329 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 11 Nov 2011 23:32:02 +0100
Subject: [PATCH] Replace a long chain of if's in
 eval_const_expressions_mutator by a switch()

For unknown reasons the function used non chained ifs for every handled
nodeType.

Replacing the if chain with if; else if; ... resulted in a small
speedup. Replacing it with a switch() in a bigger one.

When testing with a statement containing a longer VALUES statement:
pgbench -M prepared -f stmt -T 10:
orig: 10015.287829
if: 10075.482117
switch: 10246.527402
---
 src/backend/optimizer/util/clauses.c | 1733 +++++++++++++++++-----------------
 1 files changed, 869 insertions(+), 864 deletions(-)

diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 197d9c2..f6f0b11 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2106,233 +2106,137 @@ eval_const_expressions_mutator(Node *node,
 {
 	if (node == NULL)
 		return NULL;
-	if (IsA(node, Param))
+	switch(nodeTag(node))
 	{
-		Param	   *param = (Param *) node;
-
-		/* Look to see if we've been given a value for this Param */
-		if (param->paramkind == PARAM_EXTERN &&
-			context->boundParams != NULL &&
-			param->paramid > 0 &&
-			param->paramid <= context->boundParams->numParams)
+		case T_Param:
 		{
-			ParamExternData *prm = &context->boundParams->params[param->paramid - 1];
+			Param	   *param = (Param *) node;
 
-			if (OidIsValid(prm->ptype))
+			/* Look to see if we've been given a value for this Param */
+			if (param->paramkind == PARAM_EXTERN &&
+				context->boundParams != NULL &&
+				param->paramid > 0 &&
+				param->paramid <= context->boundParams->numParams)
 			{
-				/* OK to substitute parameter value? */
-				if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
+				ParamExternData *prm = &context->boundParams->params[param->paramid - 1];
+
+				if (OidIsValid(prm->ptype))
 				{
-					/*
-					 * Return a Const representing the param value.  Must copy
-					 * pass-by-ref datatypes, since the Param might be in a
-					 * memory context shorter-lived than our output plan
-					 * should be.
-					 */
-					int16		typLen;
-					bool		typByVal;
-					Datum		pval;
-
-					Assert(prm->ptype == param->paramtype);
-					get_typlenbyval(param->paramtype, &typLen, &typByVal);
-					if (prm->isnull || typByVal)
-						pval = prm->value;
-					else
-						pval = datumCopy(prm->value, typByVal, typLen);
-					return (Node *) makeConst(param->paramtype,
-											  param->paramtypmod,
-											  param->paramcollid,
-											  (int) typLen,
-											  pval,
-											  prm->isnull,
-											  typByVal);
+					/* OK to substitute parameter value? */
+					if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
+					{
+						/*
+						 * Return a Const representing the param value.  Must copy
+						 * pass-by-ref datatypes, since the Param might be in a
+						 * memory context shorter-lived than our output plan
+						 * should be.
+						 */
+						int16		typLen;
+						bool		typByVal;
+						Datum		pval;
+
+						Assert(prm->ptype == param->paramtype);
+						get_typlenbyval(param->paramtype, &typLen, &typByVal);
+						if (prm->isnull || typByVal)
+							pval = prm->value;
+						else
+							pval = datumCopy(prm->value, typByVal, typLen);
+						return (Node *) makeConst(param->paramtype,
+												  param->paramtypmod,
+												  param->paramcollid,
+												  (int) typLen,
+												  pval,
+												  prm->isnull,
+												  typByVal);
+					}
 				}
 			}
+			/* Not replaceable, so just copy the Param (no need to recurse) */
+			return (Node *) copyObject(param);
 		}
-		/* Not replaceable, so just copy the Param (no need to recurse) */
-		return (Node *) copyObject(param);
-	}
-	if (IsA(node, FuncExpr))
-	{
-		FuncExpr   *expr = (FuncExpr *) node;
-		List	   *args;
-		bool		has_named_args;
-		Expr	   *simple;
-		FuncExpr   *newexpr;
-		ListCell   *lc;
-
-		/*
-		 * Reduce constants in the FuncExpr's arguments, and check to see if
-		 * there are any named args.
-		 */
-		args = NIL;
-		has_named_args = false;
-		foreach(lc, expr->args)
+		case T_FuncExpr:
 		{
-			Node	   *arg = (Node *) lfirst(lc);
-
-			arg = eval_const_expressions_mutator(arg, context);
-			if (IsA(arg, NamedArgExpr))
-				has_named_args = true;
-			args = lappend(args, arg);
-		}
+			FuncExpr   *expr = (FuncExpr *) node;
+			List	   *args;
+			bool		has_named_args;
+			Expr	   *simple;
+			FuncExpr   *newexpr;
+			ListCell   *lc;
 
-		/*
-		 * Code for op/func reduction is pretty bulky, so split it out as a
-		 * separate function.  Note: exprTypmod normally returns -1 for a
-		 * FuncExpr, but not when the node is recognizably a length coercion;
-		 * we want to preserve the typmod in the eventual Const if so.
-		 */
-		simple = simplify_function((Expr *) expr,
-								   expr->funcid,
-								   expr->funcresulttype, exprTypmod(node),
-								   expr->funccollid,
-								   expr->inputcollid,
-								   &args,
-								   has_named_args, true, context);
-		if (simple)				/* successfully simplified it */
-			return (Node *) simple;
-
-		/*
-		 * The expression cannot be simplified any further, so build and
-		 * return a replacement FuncExpr node using the possibly-simplified
-		 * arguments.  Note that we have also converted the argument list to
-		 * positional notation.
-		 */
-		newexpr = makeNode(FuncExpr);
-		newexpr->funcid = expr->funcid;
-		newexpr->funcresulttype = expr->funcresulttype;
-		newexpr->funcretset = expr->funcretset;
-		newexpr->funcformat = expr->funcformat;
-		newexpr->funccollid = expr->funccollid;
-		newexpr->inputcollid = expr->inputcollid;
-		newexpr->args = args;
-		newexpr->location = expr->location;
-		return (Node *) newexpr;
-	}
-	if (IsA(node, OpExpr))
-	{
-		OpExpr	   *expr = (OpExpr *) node;
-		List	   *args;
-		Expr	   *simple;
-		OpExpr	   *newexpr;
-
-		/*
-		 * Reduce constants in the OpExpr's arguments.  We know args is either
-		 * NIL or a List node, so we can call expression_tree_mutator directly
-		 * rather than recursing to self.
-		 */
-		args = (List *) expression_tree_mutator((Node *) expr->args,
-											  eval_const_expressions_mutator,
-												(void *) context);
-
-		/*
-		 * Need to get OID of underlying function.	Okay to scribble on input
-		 * to this extent.
-		 */
-		set_opfuncid(expr);
+			/*
+			 * Reduce constants in the FuncExpr's arguments, and check to see if
+			 * there are any named args.
+			 */
+			args = NIL;
+			has_named_args = false;
+			foreach(lc, expr->args)
+			{
+				Node	   *arg = (Node *) lfirst(lc);
 
-		/*
-		 * Code for op/func reduction is pretty bulky, so split it out as a
-		 * separate function.
-		 */
-		simple = simplify_function((Expr *) expr,
-								   expr->opfuncid,
-								   expr->opresulttype, -1,
-								   expr->opcollid,
-								   expr->inputcollid,
-								   &args,
-								   false, true, context);
-		if (simple)				/* successfully simplified it */
-			return (Node *) simple;
+				arg = eval_const_expressions_mutator(arg, context);
+				if (IsA(arg, NamedArgExpr))
+					has_named_args = true;
+				args = lappend(args, arg);
+			}
 
-		/*
-		 * If the operator is boolean equality or inequality, we know how to
-		 * simplify cases involving one constant and one non-constant
-		 * argument.
-		 */
-		if (expr->opno == BooleanEqualOperator ||
-			expr->opno == BooleanNotEqualOperator)
-		{
-			simple = (Expr *) simplify_boolean_equality(expr->opno, args);
-			if (simple)			/* successfully simplified it */
+			/*
+			 * Code for op/func reduction is pretty bulky, so split it out as a
+			 * separate function.  Note: exprTypmod normally returns -1 for a
+			 * FuncExpr, but not when the node is recognizably a length coercion;
+			 * we want to preserve the typmod in the eventual Const if so.
+			 */
+			simple = simplify_function((Expr *) expr,
+									   expr->funcid,
+									   expr->funcresulttype, exprTypmod(node),
+									   expr->funccollid,
+									   expr->inputcollid,
+									   &args,
+									   has_named_args, true, context);
+			if (simple)				/* successfully simplified it */
 				return (Node *) simple;
-		}
-
-		/*
-		 * The expression cannot be simplified any further, so build and
-		 * return a replacement OpExpr node using the possibly-simplified
-		 * arguments.
-		 */
-		newexpr = makeNode(OpExpr);
-		newexpr->opno = expr->opno;
-		newexpr->opfuncid = expr->opfuncid;
-		newexpr->opresulttype = expr->opresulttype;
-		newexpr->opretset = expr->opretset;
-		newexpr->opcollid = expr->opcollid;
-		newexpr->inputcollid = expr->inputcollid;
-		newexpr->args = args;
-		newexpr->location = expr->location;
-		return (Node *) newexpr;
-	}
-	if (IsA(node, DistinctExpr))
-	{
-		DistinctExpr *expr = (DistinctExpr *) node;
-		List	   *args;
-		ListCell   *arg;
-		bool		has_null_input = false;
-		bool		all_null_input = true;
-		bool		has_nonconst_input = false;
-		Expr	   *simple;
-		DistinctExpr *newexpr;
-
-		/*
-		 * Reduce constants in the DistinctExpr's arguments.  We know args is
-		 * either NIL or a List node, so we can call expression_tree_mutator
-		 * directly rather than recursing to self.
-		 */
-		args = (List *) expression_tree_mutator((Node *) expr->args,
-											  eval_const_expressions_mutator,
-												(void *) context);
 
-		/*
-		 * We must do our own check for NULLs because DistinctExpr has
-		 * different results for NULL input than the underlying operator does.
-		 */
-		foreach(arg, args)
-		{
-			if (IsA(lfirst(arg), Const))
-			{
-				has_null_input |= ((Const *) lfirst(arg))->constisnull;
-				all_null_input &= ((Const *) lfirst(arg))->constisnull;
-			}
-			else
-				has_nonconst_input = true;
+			/*
+			 * The expression cannot be simplified any further, so build and
+			 * return a replacement FuncExpr node using the possibly-simplified
+			 * arguments.  Note that we have also converted the argument list to
+			 * positional notation.
+			 */
+			newexpr = makeNode(FuncExpr);
+			newexpr->funcid = expr->funcid;
+			newexpr->funcresulttype = expr->funcresulttype;
+			newexpr->funcretset = expr->funcretset;
+			newexpr->funcformat = expr->funcformat;
+			newexpr->funccollid = expr->funccollid;
+			newexpr->inputcollid = expr->inputcollid;
+			newexpr->args = args;
+			newexpr->location = expr->location;
+			return (Node *) newexpr;
 		}
-
-		/* all constants? then can optimize this out */
-		if (!has_nonconst_input)
+		case T_OpExpr:
 		{
-			/* all nulls? then not distinct */
-			if (all_null_input)
-				return makeBoolConst(false, false);
+			OpExpr	   *expr = (OpExpr *) node;
+			List	   *args;
+			Expr	   *simple;
+			OpExpr	   *newexpr;
 
-			/* one null? then distinct */
-			if (has_null_input)
-				return makeBoolConst(true, false);
-
-			/* otherwise try to evaluate the '=' operator */
-			/* (NOT okay to try to inline it, though!) */
+			/*
+			 * Reduce constants in the OpExpr's arguments.  We know args is either
+			 * NIL or a List node, so we can call expression_tree_mutator directly
+			 * rather than recursing to self.
+			 */
+			args = (List *) expression_tree_mutator((Node *) expr->args,
+												  eval_const_expressions_mutator,
+													(void *) context);
 
 			/*
-			 * Need to get OID of underlying function.	Okay to scribble on
-			 * input to this extent.
+			 * Need to get OID of underlying function.	Okay to scribble on input
+			 * to this extent.
 			 */
-			set_opfuncid((OpExpr *) expr);		/* rely on struct equivalence */
+			set_opfuncid(expr);
 
 			/*
-			 * Code for op/func reduction is pretty bulky, so split it out as
-			 * a separate function.
+			 * Code for op/func reduction is pretty bulky, so split it out as a
+			 * separate function.
 			 */
 			simple = simplify_function((Expr *) expr,
 									   expr->opfuncid,
@@ -2340,755 +2244,856 @@ eval_const_expressions_mutator(Node *node,
 									   expr->opcollid,
 									   expr->inputcollid,
 									   &args,
-									   false, false, context);
-			if (simple)			/* successfully simplified it */
-			{
-				/*
-				 * Since the underlying operator is "=", must negate its
-				 * result
-				 */
-				Const	   *csimple = (Const *) simple;
+									   false, true, context);
+			if (simple)				/* successfully simplified it */
+				return (Node *) simple;
 
-				Assert(IsA(csimple, Const));
-				csimple->constvalue =
-					BoolGetDatum(!DatumGetBool(csimple->constvalue));
-				return (Node *) csimple;
+			/*
+			 * If the operator is boolean equality or inequality, we know how to
+			 * simplify cases involving one constant and one non-constant
+			 * argument.
+			 */
+			if (expr->opno == BooleanEqualOperator ||
+				expr->opno == BooleanNotEqualOperator)
+			{
+				simple = (Expr *) simplify_boolean_equality(expr->opno, args);
+				if (simple)			/* successfully simplified it */
+					return (Node *) simple;
 			}
+
+			/*
+			 * The expression cannot be simplified any further, so build and
+			 * return a replacement OpExpr node using the possibly-simplified
+			 * arguments.
+			 */
+			newexpr = makeNode(OpExpr);
+			newexpr->opno = expr->opno;
+			newexpr->opfuncid = expr->opfuncid;
+			newexpr->opresulttype = expr->opresulttype;
+			newexpr->opretset = expr->opretset;
+			newexpr->opcollid = expr->opcollid;
+			newexpr->inputcollid = expr->inputcollid;
+			newexpr->args = args;
+			newexpr->location = expr->location;
+			return (Node *) newexpr;
 		}
+		case T_DistinctExpr:
+		{
+			DistinctExpr *expr = (DistinctExpr *) node;
+			List	   *args;
+			ListCell   *arg;
+			bool		has_null_input = false;
+			bool		all_null_input = true;
+			bool		has_nonconst_input = false;
+			Expr	   *simple;
+			DistinctExpr *newexpr;
 
-		/*
-		 * The expression cannot be simplified any further, so build and
-		 * return a replacement DistinctExpr node using the
-		 * possibly-simplified arguments.
-		 */
-		newexpr = makeNode(DistinctExpr);
-		newexpr->opno = expr->opno;
-		newexpr->opfuncid = expr->opfuncid;
-		newexpr->opresulttype = expr->opresulttype;
-		newexpr->opretset = expr->opretset;
-		newexpr->opcollid = expr->opcollid;
-		newexpr->inputcollid = expr->inputcollid;
-		newexpr->args = args;
-		newexpr->location = expr->location;
-		return (Node *) newexpr;
-	}
-	if (IsA(node, BoolExpr))
-	{
-		BoolExpr   *expr = (BoolExpr *) node;
+			/*
+			 * Reduce constants in the DistinctExpr's arguments.  We know args is
+			 * either NIL or a List node, so we can call expression_tree_mutator
+			 * directly rather than recursing to self.
+			 */
+			args = (List *) expression_tree_mutator((Node *) expr->args,
+												  eval_const_expressions_mutator,
+													(void *) context);
 
-		switch (expr->boolop)
-		{
-			case OR_EXPR:
-				{
-					List	   *newargs;
-					bool		haveNull = false;
-					bool		forceTrue = false;
-
-					newargs = simplify_or_arguments(expr->args, context,
-													&haveNull, &forceTrue);
-					if (forceTrue)
-						return makeBoolConst(true, false);
-					if (haveNull)
-						newargs = lappend(newargs, makeBoolConst(false, true));
-					/* If all the inputs are FALSE, result is FALSE */
-					if (newargs == NIL)
-						return makeBoolConst(false, false);
-					/* If only one nonconst-or-NULL input, it's the result */
-					if (list_length(newargs) == 1)
-						return (Node *) linitial(newargs);
-					/* Else we still need an OR node */
-					return (Node *) make_orclause(newargs);
-				}
-			case AND_EXPR:
+			/*
+			 * We must do our own check for NULLs because DistinctExpr has
+			 * different results for NULL input than the underlying operator does.
+			 */
+			foreach(arg, args)
+			{
+				if (IsA(lfirst(arg), Const))
 				{
-					List	   *newargs;
-					bool		haveNull = false;
-					bool		forceFalse = false;
-
-					newargs = simplify_and_arguments(expr->args, context,
-													 &haveNull, &forceFalse);
-					if (forceFalse)
-						return makeBoolConst(false, false);
-					if (haveNull)
-						newargs = lappend(newargs, makeBoolConst(false, true));
-					/* If all the inputs are TRUE, result is TRUE */
-					if (newargs == NIL)
-						return makeBoolConst(true, false);
-					/* If only one nonconst-or-NULL input, it's the result */
-					if (list_length(newargs) == 1)
-						return (Node *) linitial(newargs);
-					/* Else we still need an AND node */
-					return (Node *) make_andclause(newargs);
+					has_null_input |= ((Const *) lfirst(arg))->constisnull;
+					all_null_input &= ((Const *) lfirst(arg))->constisnull;
 				}
-			case NOT_EXPR:
-				{
-					Node	   *arg;
+				else
+					has_nonconst_input = true;
+			}
+
+			/* all constants? then can optimize this out */
+			if (!has_nonconst_input)
+			{
+				/* all nulls? then not distinct */
+				if (all_null_input)
+					return makeBoolConst(false, false);
+
+				/* one null? then distinct */
+				if (has_null_input)
+					return makeBoolConst(true, false);
 
-					Assert(list_length(expr->args) == 1);
-					arg = eval_const_expressions_mutator(linitial(expr->args),
-														 context);
+				/* otherwise try to evaluate the '=' operator */
+				/* (NOT okay to try to inline it, though!) */
 
+				/*
+				 * Need to get OID of underlying function.	Okay to scribble on
+				 * input to this extent.
+				 */
+				set_opfuncid((OpExpr *) expr);		/* rely on struct equivalence */
+
+				/*
+				 * Code for op/func reduction is pretty bulky, so split it out as
+				 * a separate function.
+				 */
+				simple = simplify_function((Expr *) expr,
+										   expr->opfuncid,
+										   expr->opresulttype, -1,
+										   expr->opcollid,
+										   expr->inputcollid,
+										   &args,
+										   false, false, context);
+				if (simple)			/* successfully simplified it */
+				{
 					/*
-					 * Use negate_clause() to see if we can simplify away the
-					 * NOT.
+					 * Since the underlying operator is "=", must negate its
+					 * result
 					 */
-					return negate_clause(arg);
+					Const	   *csimple = (Const *) simple;
+
+					Assert(IsA(csimple, Const));
+					csimple->constvalue =
+						BoolGetDatum(!DatumGetBool(csimple->constvalue));
+					return (Node *) csimple;
 				}
-			default:
-				elog(ERROR, "unrecognized boolop: %d",
-					 (int) expr->boolop);
-				break;
+			}
+
+			/*
+			 * The expression cannot be simplified any further, so build and
+			 * return a replacement DistinctExpr node using the
+			 * possibly-simplified arguments.
+			 */
+			newexpr = makeNode(DistinctExpr);
+			newexpr->opno = expr->opno;
+			newexpr->opfuncid = expr->opfuncid;
+			newexpr->opresulttype = expr->opresulttype;
+			newexpr->opretset = expr->opretset;
+			newexpr->opcollid = expr->opcollid;
+			newexpr->inputcollid = expr->inputcollid;
+			newexpr->args = args;
+			newexpr->location = expr->location;
+			return (Node *) newexpr;
 		}
-	}
-	if (IsA(node, SubPlan) ||
-		IsA(node, AlternativeSubPlan))
-	{
-		/*
-		 * Return a SubPlan unchanged --- too late to do anything with it.
-		 *
-		 * XXX should we ereport() here instead?  Probably this routine should
-		 * never be invoked after SubPlan creation.
-		 */
-		return node;
-	}
-	if (IsA(node, RelabelType))
-	{
-		/*
-		 * If we can simplify the input to a constant, then we don't need the
-		 * RelabelType node anymore: just change the type field of the Const
-		 * node.  Otherwise, must copy the RelabelType node.
-		 */
-		RelabelType *relabel = (RelabelType *) node;
-		Node	   *arg;
+		case T_BoolExpr:
+		{
+			BoolExpr   *expr = (BoolExpr *) node;
+
+			switch (expr->boolop)
+			{
+				case OR_EXPR:
+					{
+						List	   *newargs;
+						bool		haveNull = false;
+						bool		forceTrue = false;
+
+						newargs = simplify_or_arguments(expr->args, context,
+														&haveNull, &forceTrue);
+						if (forceTrue)
+							return makeBoolConst(true, false);
+						if (haveNull)
+							newargs = lappend(newargs, makeBoolConst(false, true));
+						/* If all the inputs are FALSE, result is FALSE */
+						if (newargs == NIL)
+							return makeBoolConst(false, false);
+						/* If only one nonconst-or-NULL input, it's the result */
+						if (list_length(newargs) == 1)
+							return (Node *) linitial(newargs);
+						/* Else we still need an OR node */
+						return (Node *) make_orclause(newargs);
+					}
+				case AND_EXPR:
+					{
+						List	   *newargs;
+						bool		haveNull = false;
+						bool		forceFalse = false;
+
+						newargs = simplify_and_arguments(expr->args, context,
+														 &haveNull, &forceFalse);
+						if (forceFalse)
+							return makeBoolConst(false, false);
+						if (haveNull)
+							newargs = lappend(newargs, makeBoolConst(false, true));
+						/* If all the inputs are TRUE, result is TRUE */
+						if (newargs == NIL)
+							return makeBoolConst(true, false);
+						/* If only one nonconst-or-NULL input, it's the result */
+						if (list_length(newargs) == 1)
+							return (Node *) linitial(newargs);
+						/* Else we still need an AND node */
+						return (Node *) make_andclause(newargs);
+					}
+				case NOT_EXPR:
+					{
+						Node	   *arg;
+
+						Assert(list_length(expr->args) == 1);
+						arg = eval_const_expressions_mutator(linitial(expr->args),
+															 context);
+
+						/*
+						 * Use negate_clause() to see if we can simplify away the
+						 * NOT.
+						 */
+						return negate_clause(arg);
+					}
+				default:
+					elog(ERROR, "unrecognized boolop: %d",
+						 (int) expr->boolop);
+					break;
+			}
+		}
+		case T_SubPlan:
+		case T_AlternativeSubPlan:
+			/*
+			 * Return a SubPlan unchanged --- too late to do anything with it.
+			 *
+			 * XXX should we ereport() here instead?  Probably this routine should
+			 * never be invoked after SubPlan creation.
+			 */
+			return node;
+		case T_RelabelType:
+		{
+			/*
+			 * If we can simplify the input to a constant, then we don't need the
+			 * RelabelType node anymore: just change the type field of the Const
+			 * node.  Otherwise, must copy the RelabelType node.
+			 */
+			RelabelType *relabel = (RelabelType *) node;
+			Node	   *arg;
 
-		arg = eval_const_expressions_mutator((Node *) relabel->arg,
-											 context);
+			arg = eval_const_expressions_mutator((Node *) relabel->arg,
+												 context);
 
-		/*
-		 * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can
-		 * discard all but the top one.
-		 */
-		while (arg && IsA(arg, RelabelType))
-			arg = (Node *) ((RelabelType *) arg)->arg;
+			/*
+			 * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can
+			 * discard all but the top one.
+			 */
+			while (arg && IsA(arg, RelabelType))
+				arg = (Node *) ((RelabelType *) arg)->arg;
 
-		if (arg && IsA(arg, Const))
-		{
-			Const	   *con = (Const *) arg;
+			if (arg && IsA(arg, Const))
+			{
+				Const	   *con = (Const *) arg;
 
-			con->consttype = relabel->resulttype;
-			con->consttypmod = relabel->resulttypmod;
-			con->constcollid = relabel->resultcollid;
-			return (Node *) con;
+				con->consttype = relabel->resulttype;
+				con->consttypmod = relabel->resulttypmod;
+				con->constcollid = relabel->resultcollid;
+				return (Node *) con;
+			}
+			else
+			{
+				RelabelType *newrelabel = makeNode(RelabelType);
+
+				newrelabel->arg = (Expr *) arg;
+				newrelabel->resulttype = relabel->resulttype;
+				newrelabel->resulttypmod = relabel->resulttypmod;
+				newrelabel->resultcollid = relabel->resultcollid;
+				newrelabel->relabelformat = relabel->relabelformat;
+				newrelabel->location = relabel->location;
+				return (Node *) newrelabel;
+			}
 		}
-		else
+		case T_CoerceViaIO:
 		{
-			RelabelType *newrelabel = makeNode(RelabelType);
-
-			newrelabel->arg = (Expr *) arg;
-			newrelabel->resulttype = relabel->resulttype;
-			newrelabel->resulttypmod = relabel->resulttypmod;
-			newrelabel->resultcollid = relabel->resultcollid;
-			newrelabel->relabelformat = relabel->relabelformat;
-			newrelabel->location = relabel->location;
-			return (Node *) newrelabel;
-		}
-	}
-	if (IsA(node, CoerceViaIO))
-	{
-		CoerceViaIO *expr = (CoerceViaIO *) node;
-		Expr	   *arg;
-		List	   *args;
-		Oid			outfunc;
-		bool		outtypisvarlena;
-		Oid			infunc;
-		Oid			intypioparam;
-		Expr	   *simple;
-		CoerceViaIO *newexpr;
+			CoerceViaIO *expr = (CoerceViaIO *) node;
+			Expr	   *arg;
+			List	   *args;
+			Oid			outfunc;
+			bool		outtypisvarlena;
+			Oid			infunc;
+			Oid			intypioparam;
+			Expr	   *simple;
+			CoerceViaIO *newexpr;
 
-		/*
-		 * Reduce constants in the CoerceViaIO's argument.
-		 */
-		arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
-													  context);
-		args = list_make1(arg);
+			/*
+			 * Reduce constants in the CoerceViaIO's argument.
+			 */
+			arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
+														  context);
+			args = list_make1(arg);
 
-		/*
-		 * CoerceViaIO represents calling the source type's output function
-		 * then the result type's input function.  So, try to simplify it as
-		 * though it were a stack of two such function calls.  First we need
-		 * to know what the functions are.
-		 *
-		 * Note that the coercion functions are assumed not to care about
-		 * input collation, so we just pass InvalidOid for that.
-		 */
-		getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);
-		getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
-
-		simple = simplify_function(NULL,
-								   outfunc,
-								   CSTRINGOID, -1,
-								   InvalidOid,
-								   InvalidOid,
-								   &args,
-								   false, true, context);
-		if (simple)				/* successfully simplified output fn */
-		{
 			/*
-			 * Input functions may want 1 to 3 arguments.  We always supply
-			 * all three, trusting that nothing downstream will complain.
+			 * CoerceViaIO represents calling the source type's output function
+			 * then the result type's input function.  So, try to simplify it as
+			 * though it were a stack of two such function calls.  First we need
+			 * to know what the functions are.
+			 *
+			 * Note that the coercion functions are assumed not to care about
+			 * input collation, so we just pass InvalidOid for that.
 			 */
-			args = list_make3(simple,
-							  makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
-										ObjectIdGetDatum(intypioparam),
-										false, true),
-							makeConst(INT4OID, -1, InvalidOid, sizeof(int32),
-									  Int32GetDatum(-1),
-									  false, true));
+			getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);
+			getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
 
 			simple = simplify_function(NULL,
-									   infunc,
-									   expr->resulttype, -1,
-									   expr->resultcollid,
+									   outfunc,
+									   CSTRINGOID, -1,
+									   InvalidOid,
 									   InvalidOid,
 									   &args,
 									   false, true, context);
-			if (simple)			/* successfully simplified input fn */
-				return (Node *) simple;
+			if (simple)				/* successfully simplified output fn */
+			{
+				/*
+				 * Input functions may want 1 to 3 arguments.  We always supply
+				 * all three, trusting that nothing downstream will complain.
+				 */
+				args = list_make3(simple,
+								  makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
+											ObjectIdGetDatum(intypioparam),
+											false, true),
+								makeConst(INT4OID, -1, InvalidOid, sizeof(int32),
+										  Int32GetDatum(-1),
+										  false, true));
+
+				simple = simplify_function(NULL,
+										   infunc,
+										   expr->resulttype, -1,
+										   expr->resultcollid,
+										   InvalidOid,
+										   &args,
+										   false, true, context);
+				if (simple)			/* successfully simplified input fn */
+					return (Node *) simple;
+			}
+
+			/*
+			 * The expression cannot be simplified any further, so build and
+			 * return a replacement CoerceViaIO node using the possibly-simplified
+			 * argument.
+			 */
+			newexpr = makeNode(CoerceViaIO);
+			newexpr->arg = arg;
+			newexpr->resulttype = expr->resulttype;
+			newexpr->resultcollid = expr->resultcollid;
+			newexpr->coerceformat = expr->coerceformat;
+			newexpr->location = expr->location;
+			return (Node *) newexpr;
 		}
+		case T_ArrayCoerceExpr:
+		{
+			ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
+			Expr	   *arg;
+			ArrayCoerceExpr *newexpr;
 
-		/*
-		 * The expression cannot be simplified any further, so build and
-		 * return a replacement CoerceViaIO node using the possibly-simplified
-		 * argument.
-		 */
-		newexpr = makeNode(CoerceViaIO);
-		newexpr->arg = arg;
-		newexpr->resulttype = expr->resulttype;
-		newexpr->resultcollid = expr->resultcollid;
-		newexpr->coerceformat = expr->coerceformat;
-		newexpr->location = expr->location;
-		return (Node *) newexpr;
-	}
-	if (IsA(node, ArrayCoerceExpr))
-	{
-		ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
-		Expr	   *arg;
-		ArrayCoerceExpr *newexpr;
+			/*
+			 * Reduce constants in the ArrayCoerceExpr's argument, then build a
+			 * new ArrayCoerceExpr.
+			 */
+			arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
+														  context);
+
+			newexpr = makeNode(ArrayCoerceExpr);
+			newexpr->arg = arg;
+			newexpr->elemfuncid = expr->elemfuncid;
+			newexpr->resulttype = expr->resulttype;
+			newexpr->resulttypmod = expr->resulttypmod;
+			newexpr->resultcollid = expr->resultcollid;
+			newexpr->isExplicit = expr->isExplicit;
+			newexpr->coerceformat = expr->coerceformat;
+			newexpr->location = expr->location;
 
-		/*
-		 * Reduce constants in the ArrayCoerceExpr's argument, then build a
-		 * new ArrayCoerceExpr.
-		 */
-		arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
-													  context);
-
-		newexpr = makeNode(ArrayCoerceExpr);
-		newexpr->arg = arg;
-		newexpr->elemfuncid = expr->elemfuncid;
-		newexpr->resulttype = expr->resulttype;
-		newexpr->resulttypmod = expr->resulttypmod;
-		newexpr->resultcollid = expr->resultcollid;
-		newexpr->isExplicit = expr->isExplicit;
-		newexpr->coerceformat = expr->coerceformat;
-		newexpr->location = expr->location;
+			/*
+			 * If constant argument and it's a binary-coercible or immutable
+			 * conversion, we can simplify it to a constant.
+			 */
+			if (arg && IsA(arg, Const) &&
+				(!OidIsValid(newexpr->elemfuncid) ||
+				 func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE))
+				return (Node *) evaluate_expr((Expr *) newexpr,
+											  newexpr->resulttype,
+											  newexpr->resulttypmod,
+											  newexpr->resultcollid);
+
+			/* Else we must return the partially-simplified node */
+			return (Node *) newexpr;
+		}
+	case T_CollateExpr:
+		{
+			/*
+			 * If we can simplify the input to a constant, then we don't need the
+			 * CollateExpr node at all: just change the constcollid field of the
+			 * Const node.	Otherwise, replace the CollateExpr with a RelabelType.
+			 * (We do that so as to improve uniformity of expression
+			 * representation and thus simplify comparison of expressions.)
+			 */
+			CollateExpr *collate = (CollateExpr *) node;
+			Node	   *arg;
 
-		/*
-		 * If constant argument and it's a binary-coercible or immutable
-		 * conversion, we can simplify it to a constant.
-		 */
-		if (arg && IsA(arg, Const) &&
-			(!OidIsValid(newexpr->elemfuncid) ||
-			 func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE))
-			return (Node *) evaluate_expr((Expr *) newexpr,
-										  newexpr->resulttype,
-										  newexpr->resulttypmod,
-										  newexpr->resultcollid);
-
-		/* Else we must return the partially-simplified node */
-		return (Node *) newexpr;
-	}
-	if (IsA(node, CollateExpr))
-	{
-		/*
-		 * If we can simplify the input to a constant, then we don't need the
-		 * CollateExpr node at all: just change the constcollid field of the
-		 * Const node.	Otherwise, replace the CollateExpr with a RelabelType.
-		 * (We do that so as to improve uniformity of expression
-		 * representation and thus simplify comparison of expressions.)
-		 */
-		CollateExpr *collate = (CollateExpr *) node;
-		Node	   *arg;
+			arg = eval_const_expressions_mutator((Node *) collate->arg,
+												 context);
 
-		arg = eval_const_expressions_mutator((Node *) collate->arg,
-											 context);
+			if (arg && IsA(arg, Const))
+			{
+				Const	   *con = (Const *) arg;
 
-		if (arg && IsA(arg, Const))
-		{
-			Const	   *con = (Const *) arg;
+				con->constcollid = collate->collOid;
+				return (Node *) con;
+			}
+			else if (collate->collOid == exprCollation(arg))
+			{
+				/* Don't need a RelabelType either... */
+				return arg;
+			}
+			else
+			{
+				RelabelType *relabel = makeNode(RelabelType);
 
-			con->constcollid = collate->collOid;
-			return (Node *) con;
-		}
-		else if (collate->collOid == exprCollation(arg))
-		{
-			/* Don't need a RelabelType either... */
-			return arg;
+				relabel->resulttype = exprType(arg);
+				relabel->resulttypmod = exprTypmod(arg);
+				relabel->resultcollid = collate->collOid;
+				relabel->relabelformat = COERCE_DONTCARE;
+				relabel->location = collate->location;
+
+				/* Don't create stacked RelabelTypes */
+				while (arg && IsA(arg, RelabelType))
+					arg = (Node *) ((RelabelType *) arg)->arg;
+				relabel->arg = (Expr *) arg;
+
+				return (Node *) relabel;
+			}
 		}
-		else
+	case T_CaseExpr:
 		{
-			RelabelType *relabel = makeNode(RelabelType);
+			/*----------
+			 * CASE expressions can be simplified if there are constant
+			 * condition clauses:
+			 *		FALSE (or NULL): drop the alternative
+			 *		TRUE: drop all remaining alternatives
+			 * If the first non-FALSE alternative is a constant TRUE, we can
+			 * simplify the entire CASE to that alternative's expression.
+			 * 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,
+			 * 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.	Note
+			 * that when the test expression is constant, we don't have to
+			 * include it in the resulting CASE; for example
+			 *		CASE 0 WHEN x THEN y ELSE z END
+			 * is transformed by the parser to
+			 *		CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
+			 * which we can simplify to
+			 *		CASE WHEN 0 = x THEN y ELSE z END
+			 * It is not necessary for the executor to evaluate the "arg"
+			 * expression when executing the CASE, since any contained
+			 * CaseTestExprs that might have referred to it will have been
+			 * replaced by the constant.
+			 *----------
+			 */
+			CaseExpr   *caseexpr = (CaseExpr *) node;
+			CaseExpr   *newcase;
+			Node	   *save_case_val;
+			Node	   *newarg;
+			List	   *newargs;
+			bool		const_true_cond;
+			Node	   *defresult = NULL;
+			ListCell   *arg;
+
+			/* Simplify the test expression, if any */
+			newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
+													context);
 
-			relabel->resulttype = exprType(arg);
-			relabel->resulttypmod = exprTypmod(arg);
-			relabel->resultcollid = collate->collOid;
-			relabel->relabelformat = COERCE_DONTCARE;
-			relabel->location = collate->location;
+			/* Set up for contained CaseTestExpr nodes */
+			save_case_val = context->case_val;
+			if (newarg && IsA(newarg, Const))
+			{
+				context->case_val = newarg;
+				newarg = NULL;		/* not needed anymore, see comment above */
+			}
+			else
+				context->case_val = NULL;
 
-			/* Don't create stacked RelabelTypes */
-			while (arg && IsA(arg, RelabelType))
-				arg = (Node *) ((RelabelType *) arg)->arg;
-			relabel->arg = (Expr *) arg;
+			/* Simplify the WHEN clauses */
+			newargs = NIL;
+			const_true_cond = false;
+			foreach(arg, caseexpr->args)
+			{
+				CaseWhen   *oldcasewhen = (CaseWhen *) lfirst(arg);
+				Node	   *casecond;
+				Node	   *caseresult;
 
-			return (Node *) relabel;
-		}
-	}
-	if (IsA(node, CaseExpr))
-	{
-		/*----------
-		 * CASE expressions can be simplified if there are constant
-		 * condition clauses:
-		 *		FALSE (or NULL): drop the alternative
-		 *		TRUE: drop all remaining alternatives
-		 * If the first non-FALSE alternative is a constant TRUE, we can
-		 * simplify the entire CASE to that alternative's expression.
-		 * 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,
-		 * 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.	Note
-		 * that when the test expression is constant, we don't have to
-		 * include it in the resulting CASE; for example
-		 *		CASE 0 WHEN x THEN y ELSE z END
-		 * is transformed by the parser to
-		 *		CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
-		 * which we can simplify to
-		 *		CASE WHEN 0 = x THEN y ELSE z END
-		 * It is not necessary for the executor to evaluate the "arg"
-		 * expression when executing the CASE, since any contained
-		 * CaseTestExprs that might have referred to it will have been
-		 * replaced by the constant.
-		 *----------
-		 */
-		CaseExpr   *caseexpr = (CaseExpr *) node;
-		CaseExpr   *newcase;
-		Node	   *save_case_val;
-		Node	   *newarg;
-		List	   *newargs;
-		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;
-			newarg = NULL;		/* not needed anymore, see comment above */
-		}
-		else
-			context->case_val = NULL;
+				Assert(IsA(oldcasewhen, CaseWhen));
 
-		/* Simplify the WHEN clauses */
-		newargs = NIL;
-		const_true_cond = false;
-		foreach(arg, caseexpr->args)
-		{
-			CaseWhen   *oldcasewhen = (CaseWhen *) lfirst(arg);
-			Node	   *casecond;
-			Node	   *caseresult;
+				/* Simplify this alternative's test condition */
+				casecond =
+					eval_const_expressions_mutator((Node *) oldcasewhen->expr,
+												   context);
 
-			Assert(IsA(oldcasewhen, CaseWhen));
+				/*
+				 * If the test condition is constant FALSE (or NULL), then drop
+				 * this WHEN clause completely, without processing the result.
+				 */
+				if (casecond && IsA(casecond, Const))
+				{
+					Const	   *const_input = (Const *) casecond;
 
-			/* Simplify this alternative's test condition */
-			casecond =
-				eval_const_expressions_mutator((Node *) oldcasewhen->expr,
-											   context);
+					if (const_input->constisnull ||
+						!DatumGetBool(const_input->constvalue))
+						continue;	/* drop alternative with FALSE condition */
+					/* Else it's constant TRUE */
+					const_true_cond = true;
+				}
 
-			/*
-			 * If the test condition is constant FALSE (or NULL), then drop
-			 * this WHEN clause completely, without processing the result.
-			 */
-			if (casecond && IsA(casecond, Const))
-			{
-				Const	   *const_input = (Const *) casecond;
+				/* Simplify this alternative's result value */
+				caseresult =
+					eval_const_expressions_mutator((Node *) oldcasewhen->result,
+												   context);
 
-				if (const_input->constisnull ||
-					!DatumGetBool(const_input->constvalue))
-					continue;	/* drop alternative with FALSE condition */
-				/* Else it's constant TRUE */
-				const_true_cond = true;
-			}
+				/* If non-constant test condition, emit a new WHEN node */
+				if (!const_true_cond)
+				{
+					CaseWhen   *newcasewhen = makeNode(CaseWhen);
 
-			/* Simplify this alternative's result value */
-			caseresult =
-				eval_const_expressions_mutator((Node *) oldcasewhen->result,
-											   context);
+					newcasewhen->expr = (Expr *) casecond;
+					newcasewhen->result = (Expr *) caseresult;
+					newcasewhen->location = oldcasewhen->location;
+					newargs = lappend(newargs, newcasewhen);
+					continue;
+				}
 
-			/* If non-constant test condition, emit a new WHEN node */
+				/*
+				 * Found a TRUE condition, so none of the remaining alternatives
+				 * can be reached.	We treat the result as the default result.
+				 */
+				defresult = caseresult;
+				break;
+			}
+
+			/* Simplify the default result, unless we replaced it above */
 			if (!const_true_cond)
-			{
-				CaseWhen   *newcasewhen = makeNode(CaseWhen);
+				defresult =
+					eval_const_expressions_mutator((Node *) caseexpr->defresult,
+												   context);
 
-				newcasewhen->expr = (Expr *) casecond;
-				newcasewhen->result = (Expr *) caseresult;
-				newcasewhen->location = oldcasewhen->location;
-				newargs = lappend(newargs, newcasewhen);
-				continue;
-			}
+			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 */
+			newcase = makeNode(CaseExpr);
+			newcase->casetype = caseexpr->casetype;
+			newcase->casecollid = caseexpr->casecollid;
+			newcase->arg = (Expr *) newarg;
+			newcase->args = newargs;
+			newcase->defresult = (Expr *) defresult;
+			newcase->location = caseexpr->location;
+			return (Node *) newcase;
+		}
+		case T_CaseTestExpr:
+		{
 			/*
-			 * Found a TRUE condition, so none of the remaining alternatives
-			 * can be reached.	We treat the result as the default result.
+			 * If we know a constant test value for the current CASE construct,
+			 * substitute it for the placeholder.  Else just return the
+			 * placeholder as-is.
 			 */
-			defresult = caseresult;
-			break;
+			if (context->case_val)
+				return copyObject(context->case_val);
+			else
+				return copyObject(node);
 		}
-
-		/* Simplify the default result, unless we replaced it above */
-		if (!const_true_cond)
-			defresult =
-				eval_const_expressions_mutator((Node *) caseexpr->defresult,
-											   context);
-
-		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 */
-		newcase = makeNode(CaseExpr);
-		newcase->casetype = caseexpr->casetype;
-		newcase->casecollid = caseexpr->casecollid;
-		newcase->arg = (Expr *) newarg;
-		newcase->args = newargs;
-		newcase->defresult = (Expr *) defresult;
-		newcase->location = caseexpr->location;
-		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;
-		ArrayExpr  *newarray;
-		bool		all_const = true;
-		List	   *newelems;
-		ListCell   *element;
-
-		newelems = NIL;
-		foreach(element, arrayexpr->elements)
+		case T_ArrayExpr:
 		{
-			Node	   *e;
-
-			e = eval_const_expressions_mutator((Node *) lfirst(element),
-											   context);
-			if (!IsA(e, Const))
-				all_const = false;
-			newelems = lappend(newelems, e);
-		}
+			ArrayExpr  *arrayexpr = (ArrayExpr *) node;
+			ArrayExpr  *newarray;
+			bool		all_const = true;
+			List	   *newelems;
+			ListCell   *element;
+
+			newelems = NIL;
+			foreach(element, arrayexpr->elements)
+			{
+				Node	   *e;
 
-		newarray = makeNode(ArrayExpr);
-		newarray->array_typeid = arrayexpr->array_typeid;
-		newarray->array_collid = arrayexpr->array_collid;
-		newarray->element_typeid = arrayexpr->element_typeid;
-		newarray->elements = newelems;
-		newarray->multidims = arrayexpr->multidims;
-		newarray->location = arrayexpr->location;
-
-		if (all_const)
-			return (Node *) evaluate_expr((Expr *) newarray,
-										  newarray->array_typeid,
-										  exprTypmod(node),
-										  newarray->array_collid);
-
-		return (Node *) newarray;
-	}
-	if (IsA(node, CoalesceExpr))
-	{
-		CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
-		CoalesceExpr *newcoalesce;
-		List	   *newargs;
-		ListCell   *arg;
+				e = eval_const_expressions_mutator((Node *) lfirst(element),
+												   context);
+				if (!IsA(e, Const))
+					all_const = false;
+				newelems = lappend(newelems, e);
+			}
 
-		newargs = NIL;
-		foreach(arg, coalesceexpr->args)
+			newarray = makeNode(ArrayExpr);
+			newarray->array_typeid = arrayexpr->array_typeid;
+			newarray->array_collid = arrayexpr->array_collid;
+			newarray->element_typeid = arrayexpr->element_typeid;
+			newarray->elements = newelems;
+			newarray->multidims = arrayexpr->multidims;
+			newarray->location = arrayexpr->location;
+
+			if (all_const)
+				return (Node *) evaluate_expr((Expr *) newarray,
+											  newarray->array_typeid,
+											  exprTypmod(node),
+											  newarray->array_collid);
+
+			return (Node *) newarray;
+		}
+		case T_CoalesceExpr:
 		{
-			Node	   *e;
-
-			e = eval_const_expressions_mutator((Node *) lfirst(arg),
-											   context);
+			CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
+			CoalesceExpr *newcoalesce;
+			List	   *newargs;
+			ListCell   *arg;
 
-			/*
-			 * We can remove null constants from the list. For a non-null
-			 * constant, if it has not been preceded by any other
-			 * non-null-constant expressions then it is the result. Otherwise,
-			 * it's the next argument, but we can drop following arguments
-			 * since they will never be reached.
-			 */
-			if (IsA(e, Const))
+			newargs = NIL;
+			foreach(arg, coalesceexpr->args)
 			{
-				if (((Const *) e)->constisnull)
-					continue;	/* drop null constant */
-				if (newargs == NIL)
-					return e;	/* first expr */
+				Node	   *e;
+
+				e = eval_const_expressions_mutator((Node *) lfirst(arg),
+												   context);
+
+				/*
+				 * We can remove null constants from the list. For a non-null
+				 * constant, if it has not been preceded by any other
+				 * non-null-constant expressions then it is the result. Otherwise,
+				 * it's the next argument, but we can drop following arguments
+				 * since they will never be reached.
+				 */
+				if (IsA(e, Const))
+				{
+					if (((Const *) e)->constisnull)
+						continue;	/* drop null constant */
+					if (newargs == NIL)
+						return e;	/* first expr */
+					newargs = lappend(newargs, e);
+					break;
+				}
 				newargs = lappend(newargs, e);
-				break;
 			}
-			newargs = lappend(newargs, e);
-		}
 
-		/* If all the arguments were constant null, the result is just null */
-		if (newargs == NIL)
-			return (Node *) makeNullConst(coalesceexpr->coalescetype,
-										  -1,
-										  coalesceexpr->coalescecollid);
-
-		newcoalesce = makeNode(CoalesceExpr);
-		newcoalesce->coalescetype = coalesceexpr->coalescetype;
-		newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
-		newcoalesce->args = newargs;
-		newcoalesce->location = coalesceexpr->location;
-		return (Node *) newcoalesce;
-	}
-	if (IsA(node, FieldSelect))
-	{
-		/*
-		 * We can optimize field selection from a whole-row Var into a simple
-		 * Var.  (This case won't be generated directly by the parser, because
-		 * ParseComplexProjection short-circuits it. But it can arise while
-		 * simplifying functions.)	Also, we can optimize field selection from
-		 * a RowExpr construct.
-		 *
-		 * We must however check that the declared type of the field is still
-		 * the same as when the FieldSelect was created --- this can change if
-		 * someone did ALTER COLUMN TYPE on the rowtype.
-		 */
-		FieldSelect *fselect = (FieldSelect *) node;
-		FieldSelect *newfselect;
-		Node	   *arg;
-
-		arg = eval_const_expressions_mutator((Node *) fselect->arg,
-											 context);
-		if (arg && IsA(arg, Var) &&
-			((Var *) arg)->varattno == InvalidAttrNumber)
-		{
-			if (rowtype_field_matches(((Var *) arg)->vartype,
-									  fselect->fieldnum,
-									  fselect->resulttype,
-									  fselect->resulttypmod,
-									  fselect->resultcollid))
-				return (Node *) makeVar(((Var *) arg)->varno,
-										fselect->fieldnum,
-										fselect->resulttype,
-										fselect->resulttypmod,
-										fselect->resultcollid,
-										((Var *) arg)->varlevelsup);
+			/* If all the arguments were constant null, the result is just null */
+			if (newargs == NIL)
+				return (Node *) makeNullConst(coalesceexpr->coalescetype,
+											  -1,
+											  coalesceexpr->coalescecollid);
+
+			newcoalesce = makeNode(CoalesceExpr);
+			newcoalesce->coalescetype = coalesceexpr->coalescetype;
+			newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
+			newcoalesce->args = newargs;
+			newcoalesce->location = coalesceexpr->location;
+			return (Node *) newcoalesce;
 		}
-		if (arg && IsA(arg, RowExpr))
+		case T_FieldSelect:
 		{
-			RowExpr    *rowexpr = (RowExpr *) arg;
-
-			if (fselect->fieldnum > 0 &&
-				fselect->fieldnum <= list_length(rowexpr->args))
+			/*
+			 * We can optimize field selection from a whole-row Var into a simple
+			 * Var.  (This case won't be generated directly by the parser, because
+			 * ParseComplexProjection short-circuits it. But it can arise while
+			 * simplifying functions.)	Also, we can optimize field selection from
+			 * a RowExpr construct.
+			 *
+			 * We must however check that the declared type of the field is still
+			 * the same as when the FieldSelect was created --- this can change if
+			 * someone did ALTER COLUMN TYPE on the rowtype.
+			 */
+			FieldSelect *fselect = (FieldSelect *) node;
+			FieldSelect *newfselect;
+			Node	   *arg;
+
+			arg = eval_const_expressions_mutator((Node *) fselect->arg,
+												 context);
+			if (arg && IsA(arg, Var) &&
+				((Var *) arg)->varattno == InvalidAttrNumber)
 			{
-				Node	   *fld = (Node *) list_nth(rowexpr->args,
-													fselect->fieldnum - 1);
-
-				if (rowtype_field_matches(rowexpr->row_typeid,
+				if (rowtype_field_matches(((Var *) arg)->vartype,
 										  fselect->fieldnum,
 										  fselect->resulttype,
 										  fselect->resulttypmod,
-										  fselect->resultcollid) &&
-					fselect->resulttype == exprType(fld) &&
-					fselect->resulttypmod == exprTypmod(fld) &&
-					fselect->resultcollid == exprCollation(fld))
-					return fld;
+										  fselect->resultcollid))
+					return (Node *) makeVar(((Var *) arg)->varno,
+											fselect->fieldnum,
+											fselect->resulttype,
+											fselect->resulttypmod,
+											fselect->resultcollid,
+											((Var *) arg)->varlevelsup);
 			}
-		}
-		newfselect = makeNode(FieldSelect);
-		newfselect->arg = (Expr *) arg;
-		newfselect->fieldnum = fselect->fieldnum;
-		newfselect->resulttype = fselect->resulttype;
-		newfselect->resulttypmod = fselect->resulttypmod;
-		newfselect->resultcollid = fselect->resultcollid;
-		return (Node *) newfselect;
-	}
-	if (IsA(node, NullTest))
-	{
-		NullTest   *ntest = (NullTest *) node;
-		NullTest   *newntest;
-		Node	   *arg;
+			if (arg && IsA(arg, RowExpr))
+			{
+				RowExpr    *rowexpr = (RowExpr *) arg;
 
-		arg = eval_const_expressions_mutator((Node *) ntest->arg,
-											 context);
-		if (arg && IsA(arg, RowExpr))
+				if (fselect->fieldnum > 0 &&
+					fselect->fieldnum <= list_length(rowexpr->args))
+				{
+					Node	   *fld = (Node *) list_nth(rowexpr->args,
+														fselect->fieldnum - 1);
+
+					if (rowtype_field_matches(rowexpr->row_typeid,
+											  fselect->fieldnum,
+											  fselect->resulttype,
+											  fselect->resulttypmod,
+											  fselect->resultcollid) &&
+						fselect->resulttype == exprType(fld) &&
+						fselect->resulttypmod == exprTypmod(fld) &&
+						fselect->resultcollid == exprCollation(fld))
+						return fld;
+				}
+			}
+			newfselect = makeNode(FieldSelect);
+			newfselect->arg = (Expr *) arg;
+			newfselect->fieldnum = fselect->fieldnum;
+			newfselect->resulttype = fselect->resulttype;
+			newfselect->resulttypmod = fselect->resulttypmod;
+			newfselect->resultcollid = fselect->resultcollid;
+			return (Node *) newfselect;
+		}
+		case T_NullTest:
 		{
-			/*
-			 * We break ROW(...) IS [NOT] NULL into separate tests on its
-			 * component fields.  This form is usually more efficient to
-			 * evaluate, as well as being more amenable to optimization.
-			 */
-			RowExpr    *rarg = (RowExpr *) arg;
-			List	   *newargs = NIL;
-			ListCell   *l;
-
-			Assert(ntest->argisrow);
+			NullTest   *ntest = (NullTest *) node;
+			NullTest   *newntest;
+			Node	   *arg;
 
-			foreach(l, rarg->args)
+			arg = eval_const_expressions_mutator((Node *) ntest->arg,
+												 context);
+			if (arg && IsA(arg, RowExpr))
 			{
-				Node	   *relem = (Node *) lfirst(l);
-
 				/*
-				 * A constant field refutes the whole NullTest if it's of the
-				 * wrong nullness; else we can discard it.
+				 * We break ROW(...) IS [NOT] NULL into separate tests on its
+				 * component fields.  This form is usually more efficient to
+				 * evaluate, as well as being more amenable to optimization.
 				 */
-				if (relem && IsA(relem, Const))
+				RowExpr    *rarg = (RowExpr *) arg;
+				List	   *newargs = NIL;
+				ListCell   *l;
+
+				Assert(ntest->argisrow);
+
+				foreach(l, rarg->args)
 				{
-					Const	   *carg = (Const *) relem;
+					Node	   *relem = (Node *) lfirst(l);
 
-					if (carg->constisnull ?
-						(ntest->nulltesttype == IS_NOT_NULL) :
-						(ntest->nulltesttype == IS_NULL))
-						return makeBoolConst(false, false);
-					continue;
+					/*
+					 * A constant field refutes the whole NullTest if it's of the
+					 * wrong nullness; else we can discard it.
+					 */
+					if (relem && IsA(relem, Const))
+					{
+						Const	   *carg = (Const *) relem;
+
+						if (carg->constisnull ?
+							(ntest->nulltesttype == IS_NOT_NULL) :
+							(ntest->nulltesttype == IS_NULL))
+							return makeBoolConst(false, false);
+						continue;
+					}
+					newntest = makeNode(NullTest);
+					newntest->arg = (Expr *) relem;
+					newntest->nulltesttype = ntest->nulltesttype;
+					newntest->argisrow = type_is_rowtype(exprType(relem));
+					newargs = lappend(newargs, newntest);
 				}
-				newntest = makeNode(NullTest);
-				newntest->arg = (Expr *) relem;
-				newntest->nulltesttype = ntest->nulltesttype;
-				newntest->argisrow = type_is_rowtype(exprType(relem));
-				newargs = lappend(newargs, newntest);
+				/* If all the inputs were constants, result is TRUE */
+				if (newargs == NIL)
+					return makeBoolConst(true, false);
+				/* If only one nonconst input, it's the result */
+				if (list_length(newargs) == 1)
+					return (Node *) linitial(newargs);
+				/* Else we need an AND node */
+				return (Node *) make_andclause(newargs);
 			}
-			/* If all the inputs were constants, result is TRUE */
-			if (newargs == NIL)
-				return makeBoolConst(true, false);
-			/* If only one nonconst input, it's the result */
-			if (list_length(newargs) == 1)
-				return (Node *) linitial(newargs);
-			/* Else we need an AND node */
-			return (Node *) make_andclause(newargs);
-		}
-		if (!ntest->argisrow && arg && IsA(arg, Const))
-		{
-			Const	   *carg = (Const *) arg;
-			bool		result;
-
-			switch (ntest->nulltesttype)
+			if (!ntest->argisrow && arg && IsA(arg, Const))
 			{
-				case IS_NULL:
-					result = carg->constisnull;
-					break;
-				case IS_NOT_NULL:
-					result = !carg->constisnull;
-					break;
-				default:
-					elog(ERROR, "unrecognized nulltesttype: %d",
-						 (int) ntest->nulltesttype);
-					result = false;		/* keep compiler quiet */
-					break;
-			}
+				Const	   *carg = (Const *) arg;
+				bool		result;
 
-			return makeBoolConst(result, false);
-		}
+				switch (ntest->nulltesttype)
+				{
+					case IS_NULL:
+						result = carg->constisnull;
+						break;
+					case IS_NOT_NULL:
+						result = !carg->constisnull;
+						break;
+					default:
+						elog(ERROR, "unrecognized nulltesttype: %d",
+							 (int) ntest->nulltesttype);
+						result = false;		/* keep compiler quiet */
+						break;
+				}
 
-		newntest = makeNode(NullTest);
-		newntest->arg = (Expr *) arg;
-		newntest->nulltesttype = ntest->nulltesttype;
-		newntest->argisrow = ntest->argisrow;
-		return (Node *) newntest;
-	}
-	if (IsA(node, BooleanTest))
-	{
-		BooleanTest *btest = (BooleanTest *) node;
-		BooleanTest *newbtest;
-		Node	   *arg;
+				return makeBoolConst(result, false);
+			}
 
-		arg = eval_const_expressions_mutator((Node *) btest->arg,
-											 context);
-		if (arg && IsA(arg, Const))
+			newntest = makeNode(NullTest);
+			newntest->arg = (Expr *) arg;
+			newntest->nulltesttype = ntest->nulltesttype;
+			newntest->argisrow = ntest->argisrow;
+			return (Node *) newntest;
+		}
+		case T_BooleanTest:
 		{
-			Const	   *carg = (Const *) arg;
-			bool		result;
+			BooleanTest *btest = (BooleanTest *) node;
+			BooleanTest *newbtest;
+			Node	   *arg;
 
-			switch (btest->booltesttype)
+			arg = eval_const_expressions_mutator((Node *) btest->arg,
+												 context);
+			if (arg && IsA(arg, Const))
 			{
-				case IS_TRUE:
-					result = (!carg->constisnull &&
-							  DatumGetBool(carg->constvalue));
-					break;
-				case IS_NOT_TRUE:
-					result = (carg->constisnull ||
-							  !DatumGetBool(carg->constvalue));
-					break;
-				case IS_FALSE:
-					result = (!carg->constisnull &&
-							  !DatumGetBool(carg->constvalue));
-					break;
-				case IS_NOT_FALSE:
-					result = (carg->constisnull ||
-							  DatumGetBool(carg->constvalue));
-					break;
-				case IS_UNKNOWN:
-					result = carg->constisnull;
-					break;
-				case IS_NOT_UNKNOWN:
-					result = !carg->constisnull;
-					break;
-				default:
-					elog(ERROR, "unrecognized booltesttype: %d",
-						 (int) btest->booltesttype);
-					result = false;		/* keep compiler quiet */
-					break;
+				Const	   *carg = (Const *) arg;
+				bool		result;
+
+				switch (btest->booltesttype)
+				{
+					case IS_TRUE:
+						result = (!carg->constisnull &&
+								  DatumGetBool(carg->constvalue));
+						break;
+					case IS_NOT_TRUE:
+						result = (carg->constisnull ||
+								  !DatumGetBool(carg->constvalue));
+						break;
+					case IS_FALSE:
+						result = (!carg->constisnull &&
+								  !DatumGetBool(carg->constvalue));
+						break;
+					case IS_NOT_FALSE:
+						result = (carg->constisnull ||
+								  DatumGetBool(carg->constvalue));
+						break;
+					case IS_UNKNOWN:
+						result = carg->constisnull;
+						break;
+					case IS_NOT_UNKNOWN:
+						result = !carg->constisnull;
+						break;
+					default:
+						elog(ERROR, "unrecognized booltesttype: %d",
+							 (int) btest->booltesttype);
+						result = false;		/* keep compiler quiet */
+						break;
+				}
+
+				return makeBoolConst(result, false);
 			}
 
-			return makeBoolConst(result, false);
+			newbtest = makeNode(BooleanTest);
+			newbtest->arg = (Expr *) arg;
+			newbtest->booltesttype = btest->booltesttype;
+			return (Node *) newbtest;
 		}
+		case T_PlaceHolderVar:
+			if(context->estimate)
+			{
+				/*
+				 * In estimation mode, just strip the PlaceHolderVar node altogether;
+				 * this amounts to estimating that the contained value won't be forced
+				 * to null by an outer join.  In regular mode we just use the default
+				 * behavior (ie, simplify the expression but leave the PlaceHolderVar
+				 * node intact).
+				 */
+				PlaceHolderVar *phv = (PlaceHolderVar *) node;
 
-		newbtest = makeNode(BooleanTest);
-		newbtest->arg = (Expr *) arg;
-		newbtest->booltesttype = btest->booltesttype;
-		return (Node *) newbtest;
-	}
-	if (IsA(node, PlaceHolderVar) &&context->estimate)
-	{
-		/*
-		 * In estimation mode, just strip the PlaceHolderVar node altogether;
-		 * this amounts to estimating that the contained value won't be forced
-		 * to null by an outer join.  In regular mode we just use the default
-		 * behavior (ie, simplify the expression but leave the PlaceHolderVar
-		 * node intact).
-		 */
-		PlaceHolderVar *phv = (PlaceHolderVar *) node;
-
-		return eval_const_expressions_mutator((Node *) phv->phexpr,
-											  context);
+				return eval_const_expressions_mutator((Node *) phv->phexpr,
+				                                      context);
+			}
+			//fall through
+		default:
+			;
 	}
 
 	/*
-- 
1.7.7.3

