Commit 3987e9e6 authored by Tom Lane's avatar Tom Lane

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.
parent 44404f39
......@@ -5187,49 +5187,35 @@ get_rule_expr(Node *node, deparse_context *context,
CaseWhen *when = (CaseWhen *) lfirst(temp);
Node *w = (Node *) when->expr;
if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "WHEN ",
0, 0, 0);
if (caseexpr->arg)
{
/*
* The parser should have produced WHEN clauses of the
* form "CaseTestExpr = RHS"; we want to show just the
* RHS. If the user wrote something silly like "CASE
* boolexpr WHEN TRUE THEN ...", then the optimizer's
* simplify_boolean_equality() may have reduced this
* to just "CaseTestExpr" or "NOT CaseTestExpr", for
* which we have to show "TRUE" or "FALSE". We have
* also to consider the possibility that an implicit
* coercion was inserted between the CaseTestExpr and
* the operator.
* The parser should have produced WHEN clauses of
* the form "CaseTestExpr = RHS", possibly with an
* implicit coercion inserted above the CaseTestExpr.
* For accurate decompilation of rules it's essential
* that we show just the RHS. However in an
* expression that's been through the optimizer, the
* WHEN clause could be almost anything (since the
* equality operator could have been expanded into an
* inline function). If we don't recognize the form
* of the WHEN clause, just punt and display it as-is.
*/
if (IsA(w, OpExpr))
{
List *args = ((OpExpr *) w)->args;
Node *rhs;
Assert(list_length(args) == 2);
Assert(IsA(strip_implicit_coercions(linitial(args)),
CaseTestExpr));
rhs = (Node *) lsecond(args);
get_rule_expr(rhs, context, false);
}
else if (IsA(strip_implicit_coercions(w),
if (list_length(args) == 2 &&
IsA(strip_implicit_coercions(linitial(args)),
CaseTestExpr))
appendStringInfo(buf, "TRUE");
else if (not_clause(w))
{
Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
CaseTestExpr));
appendStringInfo(buf, "FALSE");
w = (Node *) lsecond(args);
}
else
elog(ERROR, "unexpected CASE WHEN clause: %d",
(int) nodeTag(w));
}
else
if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "WHEN ",
0, 0, 0);
get_rule_expr(w, context, false);
appendStringInfo(buf, " THEN ");
get_rule_expr((Node *) when->result, context, true);
......@@ -5246,6 +5232,19 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
case T_CaseTestExpr:
{
/*
* Normally we should never get here, since for expressions
* that can contain this node type we attempt to avoid
* recursing to it. But in an optimized expression we might
* be unable to avoid that (see comments for CaseExpr). If we
* do see one, print it as CASE_TEST_EXPR.
*/
appendStringInfo(buf, "CASE_TEST_EXPR");
}
break;
case T_ArrayExpr:
{
ArrayExpr *arrayexpr = (ArrayExpr *) node;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment