88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.187 2005/01/28 19:34 :07 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.188 2005/02/02 21:49 :07 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
4949typedef struct
5050{
5151List * active_fns ;
52+ Node * case_val ;
5253bool estimate ;
5354}eval_const_expressions_context ;
5455
@@ -1195,6 +1196,7 @@ eval_const_expressions(Node *node)
11951196eval_const_expressions_context context ;
11961197
11971198context .active_fns = NIL ;/* nothing being recursively simplified */
1199+ context .case_val = NULL ;/* no CASE being examined */
11981200context .estimate = false;/* safe transformations only */
11991201return eval_const_expressions_mutator (node ,& context );
12001202}
@@ -1219,6 +1221,7 @@ estimate_expression_value(Node *node)
12191221eval_const_expressions_context context ;
12201222
12211223context .active_fns = NIL ;/* nothing being recursively simplified */
1224+ context .case_val = NULL ;/* no CASE being examined */
12221225context .estimate = true;/* unsafe transformations OK */
12231226return eval_const_expressions_mutator (node ,& context );
12241227}
@@ -1592,71 +1595,98 @@ eval_const_expressions_mutator(Node *node,
15921595 * If there are no non-FALSE alternatives, we simplify the entire
15931596 * CASE to the default result (ELSE result).
15941597 *
1595- * If we have a simple-form CASE with constant test expression and
1596- * one or more constant comparison expressions, we could run the
1597- * implied comparisons and potentially reduce those arms to constants.
1598- * This is not yet implemented, however. At present, the
1599- * CaseTestExpr placeholder will always act as a non-constant node
1600- * and prevent the comparison boolean expressions from being reduced
1601- * to Const nodes.
1598+ * If we have a simple-form CASE with constant test expression,
1599+ * we substitute the constant value for contained CaseTestExpr
1600+ * placeholder nodes, so that we have the opportunity to reduce
1601+ * constant test conditions. For example this allows
1602+ *CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
1603+ * to reduce to 1 rather than drawing a divide-by-0 error.
16021604 *----------
16031605 */
16041606CaseExpr * caseexpr = (CaseExpr * )node ;
16051607CaseExpr * newcase ;
1608+ Node * save_case_val ;
16061609Node * newarg ;
16071610List * newargs ;
1608- Node * defresult ;
1609- Const * const_input ;
1611+ bool const_true_cond ;
1612+ Node * defresult = NULL ;
16101613ListCell * arg ;
16111614
16121615/* Simplify the test expression, if any */
16131616newarg = eval_const_expressions_mutator ((Node * )caseexpr -> arg ,
16141617context );
16151618
1619+ /* Set up for contained CaseTestExpr nodes */
1620+ save_case_val = context -> case_val ;
1621+ if (newarg && IsA (newarg ,Const ))
1622+ context -> case_val = newarg ;
1623+ else
1624+ context -> case_val = NULL ;
1625+
16161626/* Simplify the WHEN clauses */
16171627newargs = NIL ;
1628+ const_true_cond = false;
16181629foreach (arg ,caseexpr -> args )
16191630{
1620- /* Simplify this alternative's condition and result */
1621- CaseWhen * casewhen = (CaseWhen * )
1622- expression_tree_mutator ((Node * )lfirst (arg ),
1623- eval_const_expressions_mutator ,
1624- (void * )context );
1625-
1626- Assert (IsA (casewhen ,CaseWhen ));
1627- if (casewhen -> expr == NULL ||
1628- !IsA (casewhen -> expr ,Const ))
1629- {
1630- newargs = lappend (newargs ,casewhen );
1631- continue ;
1632- }
1633- const_input = (Const * )casewhen -> expr ;
1634- if (const_input -> constisnull ||
1635- !DatumGetBool (const_input -> constvalue ))
1636- continue ;/* drop alternative with FALSE condition */
1631+ CaseWhen * oldcasewhen = (CaseWhen * )lfirst (arg );
1632+ Node * casecond ;
1633+ Node * caseresult ;
1634+
1635+ Assert (IsA (oldcasewhen ,CaseWhen ));
1636+
1637+ /* Simplify this alternative's test condition */
1638+ casecond =
1639+ eval_const_expressions_mutator ((Node * )oldcasewhen -> expr ,
1640+ context );
16371641
16381642/*
1639- *Found a TRUE condition.If it's the first (un-dropped)
1640- *alternative, the CASE reduces to just this alternative .
1643+ *If the test condition is constant FALSE (or NULL), then drop
1644+ *this WHEN clause completely, without processing the result .
16411645 */
1642- if (newargs == NIL )
1643- return (Node * )casewhen -> result ;
1646+ if (casecond && IsA (casecond ,Const ))
1647+ {
1648+ Const * const_input = (Const * )casecond ;
1649+
1650+ if (const_input -> constisnull ||
1651+ !DatumGetBool (const_input -> constvalue ))
1652+ continue ;/* drop alternative with FALSE condition */
1653+ /* Else it's constant TRUE */
1654+ const_true_cond = true;
1655+ }
1656+
1657+ /* Simplify this alternative's result value */
1658+ caseresult =
1659+ eval_const_expressions_mutator ((Node * )oldcasewhen -> result ,
1660+ context );
16441661
1662+ /* If non-constant test condition, emit a new WHEN node */
1663+ if (!const_true_cond )
1664+ {
1665+ CaseWhen * newcasewhen = makeNode (CaseWhen );
1666+
1667+ newcasewhen -> expr = (Expr * )casecond ;
1668+ newcasewhen -> result = (Expr * )caseresult ;
1669+ newargs = lappend (newargs ,newcasewhen );
1670+ continue ;
1671+ }
1672+
16451673/*
1646- * Otherwise, add it to the list, and drop all the rest.
1674+ * Found a TRUE condition, so none of the remaining alternatives
1675+ * can be reached. We treat the result as the default result.
16471676 */
1648- newargs = lappend ( newargs , casewhen ) ;
1677+ defresult = caseresult ;
16491678break ;
16501679}
16511680
1652- /* Simplify the default result */
1653- defresult = eval_const_expressions_mutator ((Node * )caseexpr -> defresult ,
1654- context );
1681+ /* Simplify the default result, unless we replaced it above */
1682+ if (!const_true_cond )
1683+ defresult =
1684+ eval_const_expressions_mutator ((Node * )caseexpr -> defresult ,
1685+ context );
16551686
1656- /*
1657- * If no non-FALSE alternatives, CASE reduces to the default
1658- * result
1659- */
1687+ context -> case_val = save_case_val ;
1688+
1689+ /* If no non-FALSE alternatives, CASE reduces to the default result */
16601690if (newargs == NIL )
16611691return defresult ;
16621692/* Otherwise we need a new CASE node */
@@ -1667,6 +1697,18 @@ eval_const_expressions_mutator(Node *node,
16671697newcase -> defresult = (Expr * )defresult ;
16681698return (Node * )newcase ;
16691699}
1700+ if (IsA (node ,CaseTestExpr ))
1701+ {
1702+ /*
1703+ * If we know a constant test value for the current CASE
1704+ * construct, substitute it for the placeholder. Else just
1705+ * return the placeholder as-is.
1706+ */
1707+ if (context -> case_val )
1708+ return copyObject (context -> case_val );
1709+ else
1710+ return copyObject (node );
1711+ }
16701712if (IsA (node ,ArrayExpr ))
16711713{
16721714ArrayExpr * arrayexpr = (ArrayExpr * )node ;