Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfffb581

Browse files
committed
Adjust constant-folding of CASE expressions so that the simple comparison
form of CASE (eg, CASE 0 WHEN 1 THEN ...) can be constant-folded as itwas in 7.4. Also, avoid constant-folding result expressions that arecertainly unreachable --- the former coding was a bit cavalier about thisand could generate unexpected results for all-constant CASE expressions.Add regression test cases. Per report from Vlad Marchenko.
1 parentb3a7e98 commitfffb581

File tree

3 files changed

+107
-40
lines changed

3 files changed

+107
-40
lines changed

‎src/backend/optimizer/util/clauses.c

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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
@@ -49,6 +49,7 @@
4949
typedefstruct
5050
{
5151
List*active_fns;
52+
Node*case_val;
5253
boolestimate;
5354
}eval_const_expressions_context;
5455

@@ -1195,6 +1196,7 @@ eval_const_expressions(Node *node)
11951196
eval_const_expressions_contextcontext;
11961197

11971198
context.active_fns=NIL;/* nothing being recursively simplified */
1199+
context.case_val=NULL;/* no CASE being examined */
11981200
context.estimate= false;/* safe transformations only */
11991201
returneval_const_expressions_mutator(node,&context);
12001202
}
@@ -1219,6 +1221,7 @@ estimate_expression_value(Node *node)
12191221
eval_const_expressions_contextcontext;
12201222

12211223
context.active_fns=NIL;/* nothing being recursively simplified */
1224+
context.case_val=NULL;/* no CASE being examined */
12221225
context.estimate= true;/* unsafe transformations OK */
12231226
returneval_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
*/
16041606
CaseExpr*caseexpr= (CaseExpr*)node;
16051607
CaseExpr*newcase;
1608+
Node*save_case_val;
16061609
Node*newarg;
16071610
List*newargs;
1608-
Node*defresult;
1609-
Const*const_input;
1611+
boolconst_true_cond;
1612+
Node*defresult=NULL;
16101613
ListCell*arg;
16111614

16121615
/* Simplify the test expression, if any */
16131616
newarg=eval_const_expressions_mutator((Node*)caseexpr->arg,
16141617
context);
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 */
16171627
newargs=NIL;
1628+
const_true_cond= false;
16181629
foreach(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;
16491678
break;
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 */
16601690
if (newargs==NIL)
16611691
returndefresult;
16621692
/* Otherwise we need a new CASE node */
@@ -1667,6 +1697,18 @@ eval_const_expressions_mutator(Node *node,
16671697
newcase->defresult= (Expr*)defresult;
16681698
return (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+
returncopyObject(context->case_val);
1709+
else
1710+
returncopyObject(node);
1711+
}
16701712
if (IsA(node,ArrayExpr))
16711713
{
16721714
ArrayExpr*arrayexpr= (ArrayExpr*)node;

‎src/test/regress/expected/case.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ SELECT '6' AS "One",
7272
6 | 6
7373
(1 row)
7474

75+
-- Constant-expression folding shouldn't evaluate unreachable subexpressions
76+
SELECT CASE WHEN 1=0 THEN 1/0 WHEN 1=1 THEN 1 ELSE 2/0 END;
77+
case
78+
------
79+
1
80+
(1 row)
81+
82+
SELECT CASE 1 WHEN 0 THEN 1/0 WHEN 1 THEN 1 ELSE 2/0 END;
83+
case
84+
------
85+
1
86+
(1 row)
87+
88+
-- However we do not currently suppress folding of potentially
89+
-- reachable subexpressions
90+
SELECT CASE WHEN i > 100 THEN 1/0 ELSE 0 END FROM case_tbl;
91+
ERROR: division by zero
7592
-- Test for cases involving untyped literals in test expression
7693
SELECT CASE 'a' WHEN 'a' THEN 1 ELSE 2 END;
7794
case

‎src/test/regress/sql/case.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ SELECT '6' AS "One",
5858
ELSE7
5959
ENDAS"Two WHEN with default";
6060

61+
-- Constant-expression folding shouldn't evaluate unreachable subexpressions
62+
SELECT CASE WHEN1=0 THEN1/0 WHEN1=1 THEN1 ELSE2/0 END;
63+
SELECT CASE1 WHEN0 THEN1/0 WHEN1 THEN1 ELSE2/0 END;
64+
65+
-- However we do not currently suppress folding of potentially
66+
-- reachable subexpressions
67+
SELECT CASE WHEN i>100 THEN1/0 ELSE0 ENDFROM case_tbl;
68+
6169
-- Test for cases involving untyped literals in test expression
6270
SELECT CASE'a' WHEN'a' THEN1 ELSE2 END;
6371

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp