8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
* HISTORY
14
14
* AUTHOR DATE MAJOR EVENT
49
49
typedef struct
50
50
{
51
51
List * active_fns ;
52
+ Node * case_val ;
52
53
bool estimate ;
53
54
} eval_const_expressions_context ;
54
55
@@ -1195,6 +1196,7 @@ eval_const_expressions(Node *node)
1195
1196
eval_const_expressions_context context ;
1196
1197
1197
1198
context .active_fns = NIL ; /* nothing being recursively simplified */
1199
+ context .case_val = NULL ; /* no CASE being examined */
1198
1200
context .estimate = false; /* safe transformations only */
1199
1201
return eval_const_expressions_mutator (node , & context );
1200
1202
}
@@ -1219,6 +1221,7 @@ estimate_expression_value(Node *node)
1219
1221
eval_const_expressions_context context ;
1220
1222
1221
1223
context .active_fns = NIL ; /* nothing being recursively simplified */
1224
+ context .case_val = NULL ; /* no CASE being examined */
1222
1225
context .estimate = true; /* unsafe transformations OK */
1223
1226
return eval_const_expressions_mutator (node , & context );
1224
1227
}
@@ -1592,71 +1595,98 @@ eval_const_expressions_mutator(Node *node,
1592
1595
* If there are no non-FALSE alternatives, we simplify the entire
1593
1596
* CASE to the default result (ELSE result).
1594
1597
*
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.
1602
1604
*----------
1603
1605
*/
1604
1606
CaseExpr * caseexpr = (CaseExpr * ) node ;
1605
1607
CaseExpr * newcase ;
1608
+ Node * save_case_val ;
1606
1609
Node * newarg ;
1607
1610
List * newargs ;
1608
- Node * defresult ;
1609
- Const * const_input ;
1611
+ bool const_true_cond ;
1612
+ Node * defresult = NULL ;
1610
1613
ListCell * arg ;
1611
1614
1612
1615
/* Simplify the test expression, if any */
1613
1616
newarg = eval_const_expressions_mutator ((Node * ) caseexpr -> arg ,
1614
1617
context );
1615
1618
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
+
1616
1626
/* Simplify the WHEN clauses */
1617
1627
newargs = NIL ;
1628
+ const_true_cond = false;
1618
1629
foreach (arg , caseexpr -> args )
1619
1630
{
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 );
1637
1641
1638
1642
/*
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 .
1641
1645
*/
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 );
1644
1661
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
+
1645
1673
/*
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.
1647
1676
*/
1648
- newargs = lappend ( newargs , casewhen ) ;
1677
+ defresult = caseresult ;
1649
1678
break ;
1650
1679
}
1651
1680
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 );
1655
1686
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 */
1660
1690
if (newargs == NIL )
1661
1691
return defresult ;
1662
1692
/* Otherwise we need a new CASE node */
@@ -1667,6 +1697,18 @@ eval_const_expressions_mutator(Node *node,
1667
1697
newcase -> defresult = (Expr * ) defresult ;
1668
1698
return (Node * ) newcase ;
1669
1699
}
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
+ }
1670
1712
if (IsA (node , ArrayExpr ))
1671
1713
{
1672
1714
ArrayExpr * arrayexpr = (ArrayExpr * ) node ;
0 commit comments