Skip to content

Commit f014211

Browse files
committed
Make decompilation of optimized CASE constructs more robust.
We had some hacks in ruleutils.c to cope with various odd transformations that the optimizer could do on a CASE foo WHEN "CaseTestExpr = RHS" clause. However, the fundamental impossibility of covering all cases was exposed by Heikki, who pointed out that the "=" operator could get replaced by an inlined SQL function, which could contain nearly anything at all. So give up on the hacks and just print the expression as-is if we fail to recognize it as "CaseTestExpr = RHS". (We must cover that case so that decompiled rules print correctly; but we are not under any obligation to make EXPLAIN output be 100% valid SQL in all cases, and already could not do so in some other cases.) This approach requires that we have some printable representation of the CaseTestExpr node type; I used "CASE_TEST_EXPR". Back-patch to all supported branches, since the problem case fails in all.
1 parent 9a57eaf commit f014211

File tree

1 file changed

+33
-34
lines changed

1 file changed

+33
-34
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3721,50 +3721,36 @@ get_rule_expr(Node *node, deparse_context *context,
37213721
CaseWhen *when = (CaseWhen *) lfirst(temp);
37223722
Node *w = (Node *) when->expr;
37233723

3724-
if (!PRETTY_INDENT(context))
3725-
appendStringInfoChar(buf, ' ');
3726-
appendContextKeyword(context, "WHEN ",
3727-
0, 0, 0);
37283724
if (caseexpr->arg)
37293725
{
37303726
/*
3731-
* The parser should have produced WHEN clauses of the
3732-
* form "CaseTestExpr = RHS"; we want to show just the
3733-
* RHS. If the user wrote something silly like "CASE
3734-
* boolexpr WHEN TRUE THEN ...", then the optimizer's
3735-
* simplify_boolean_equality() may have reduced this
3736-
* to just "CaseTestExpr" or "NOT CaseTestExpr", for
3737-
* which we have to show "TRUE" or "FALSE". We have
3738-
* also to consider the possibility that an implicit
3739-
* coercion was inserted between the CaseTestExpr and
3740-
* the operator.
3727+
* The parser should have produced WHEN clauses of
3728+
* the form "CaseTestExpr = RHS", possibly with an
3729+
* implicit coercion inserted above the CaseTestExpr.
3730+
* For accurate decompilation of rules it's essential
3731+
* that we show just the RHS. However in an
3732+
* expression that's been through the optimizer, the
3733+
* WHEN clause could be almost anything (since the
3734+
* equality operator could have been expanded into an
3735+
* inline function). If we don't recognize the form
3736+
* of the WHEN clause, just punt and display it as-is.
37413737
*/
37423738
if (IsA(w, OpExpr))
37433739
{
37443740
List *args = ((OpExpr *) w)->args;
3745-
Node *rhs;
37463741

3747-
Assert(list_length(args) == 2);
3748-
Assert(IsA(strip_implicit_coercions(linitial(args)),
3749-
CaseTestExpr));
3750-
rhs = (Node *) lsecond(args);
3751-
get_rule_expr(rhs, context, false);
3742+
if (list_length(args) == 2 &&
3743+
IsA(strip_implicit_coercions(linitial(args)),
3744+
CaseTestExpr))
3745+
w = (Node *) lsecond(args);
37523746
}
3753-
else if (IsA(strip_implicit_coercions(w),
3754-
CaseTestExpr))
3755-
appendStringInfo(buf, "TRUE");
3756-
else if (not_clause(w))
3757-
{
3758-
Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
3759-
CaseTestExpr));
3760-
appendStringInfo(buf, "FALSE");
3761-
}
3762-
else
3763-
elog(ERROR, "unexpected CASE WHEN clause: %d",
3764-
(int) nodeTag(w));
37653747
}
3766-
else
3767-
get_rule_expr(w, context, false);
3748+
3749+
if (!PRETTY_INDENT(context))
3750+
appendStringInfoChar(buf, ' ');
3751+
appendContextKeyword(context, "WHEN ",
3752+
0, 0, 0);
3753+
get_rule_expr(w, context, false);
37683754
appendStringInfo(buf, " THEN ");
37693755
get_rule_expr((Node *) when->result, context, true);
37703756
}
@@ -3780,6 +3766,19 @@ get_rule_expr(Node *node, deparse_context *context,
37803766
}
37813767
break;
37823768

3769+
case T_CaseTestExpr:
3770+
{
3771+
/*
3772+
* Normally we should never get here, since for expressions
3773+
* that can contain this node type we attempt to avoid
3774+
* recursing to it. But in an optimized expression we might
3775+
* be unable to avoid that (see comments for CaseExpr). If we
3776+
* do see one, print it as CASE_TEST_EXPR.
3777+
*/
3778+
appendStringInfo(buf, "CASE_TEST_EXPR");
3779+
}
3780+
break;
3781+
37833782
case T_ArrayExpr:
37843783
{
37853784
ArrayExpr *arrayexpr = (ArrayExpr *) node;

0 commit comments

Comments
 (0)