10000 Fix up handling of simple-form CASE with constant test expression. · machack666/postgres@6dca260 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6dca260

Browse files
committed
Fix up handling of simple-form CASE with constant test expression.
eval_const_expressions() can replace CaseTestExprs with constants when the surrounding CASE's test expression is a constant. This confuses ruleutils.c's heuristic for deparsing simple-form CASEs, leading to Assert failures or "unexpected CASE WHEN clause" errors. I had put in a hack solution for that years ago (see commit 514ce7a of 2006-10-01), but bug #5794 from Peter Speck shows that that solution failed to cover all cases. Fortunately, there's a much better way, which came to me upon reflecting that Peter's "CASE TRUE WHEN" seemed pretty redundant: we can "simplify" the simple-form CASE to the general form of CASE, by simply omitting the constant test expression from the rebuilt CASE construct. This is intuitively valid because there is no need for the executor to evaluate the test expression at runtime; it will never be referenced, because any CaseTestExprs that would have referenced it are now replaced by constants. This won't save a whole lot of cycles, since evaluating a Const is pretty cheap, but a cycle saved is a cycle earned. In any case it beats kluging ruleutils.c still further. So this patch improves const-simplification and reverts the previous change in ruleutils.c. Back-patch to all supported branches. The bug exists in 8.1 too, but it's out of warranty.
1 parent b053c53 commit 6dca260

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,18 @@ eval_const_expressions_mutator(Node *node,
18631863
* placeholder nodes, so that we have the opportunity to reduce
18641864
* constant test conditions. For example this allows
18651865
* CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
1866-
* to reduce to 1 rather than drawing a divide-by-0 error.
1866+
* to reduce to 1 rather than drawing a divide-by-0 error. Note
1867+
* that when the test expression is constant, we don't have to
1868+
* include it in the resulting CASE; for example
1869+
* CASE 0 WHEN x THEN y ELSE z END
1870+
* is transformed by the parser to
1871+
* CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
1872+
* which we can simplify to
1873+
* CASE WHEN 0 = x THEN y ELSE z END
1874+
* It is not necessary for the executor to evaluate the "arg"
1875+
* expression when executing the CASE, since any contained
1876+
* CaseTestExprs that might have referred to it will have been
1877+
* replaced by the constant.
18671878
*----------
18681879
*/
18691880
CaseExpr *caseexpr = (CaseExpr *) node;
@@ -1882,7 +1893,10 @@ eval_const_expressions_mutator(Node *node,
18821893
/* Set up for contained CaseTestExpr nodes */
18831894
save_case_val = context->case_val;
18841895
if (newarg && IsA(newarg, Const))
1896+
{
18851897
context->case_val = newarg;
1898+
newarg = NULL; /* not needed anymore, see comment above */
1899+
}
18861900
else
18871901
context->case_val = NULL;
18881902

src/backend/utils/adt/ruleutils.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3691,23 +3691,19 @@ get_rule_expr(Node *node, deparse_context *context,
36913691
* boolexpr WHEN TRUE THEN ...", then the optimizer's
36923692
* simplify_boolean_equality() may have reduced this
36933693
* to just "CaseTestExpr" or "NOT CaseTestExpr", for
3694-
* which we have to show "TRUE" or "FALSE". Also,
3695-
* depending on context the original CaseTestExpr
3696-
* might have been reduced to a Const (but we won't
3697-
* see "WHEN Const"). We have also to consider the
3698-
* possibility that an implicit coercion was inserted
3699-
* between the CaseTestExpr and the operator.
3694+
* which we have to show "TRUE" or "FALSE". We have
3695+
* also to consider the possibility that an implicit
3696+
* coercion was inserted between the CaseTestExpr and
3697+
* the operator.
37003698
*/
37013699
if (IsA(w, OpExpr))
37023700
{
37033701
List *args = ((OpExpr *) w)->args;
3704-
Node *lhs;
37053702
Node *rhs;
37063703

37073704
Assert(list_length(args) == 2);
3708-
lhs = strip_implicit_coercions(linitial(args));
3709-
Assert(IsA(lhs, CaseTestExpr) ||
3710-
IsA(lhs, Const));
3705+
Assert(IsA(strip_implicit_coercions(linitial(args)),
3706+
CaseTestExpr));
37113707
rhs = (Node *) lsecond(args);
37123708
get_rule_expr(rhs, context, false);
37133709
}

0 commit comments

Comments
 (0)
0