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.
This commit is contained in:
parent
bd9215a346
commit
d3f52d72ce
@ -4669,50 +4669,36 @@ 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);
|
||||
if (list_length(args) == 2 &&
|
||||
IsA(strip_implicit_coercions(linitial(args)),
|
||||
CaseTestExpr))
|
||||
w = (Node *) lsecond(args);
|
||||
}
|
||||
else if (IsA(strip_implicit_coercions(w),
|
||||
CaseTestExpr))
|
||||
appendStringInfo(buf, "TRUE");
|
||||
else if (not_clause(w))
|
||||
{
|
||||
Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
|
||||
CaseTestExpr));
|
||||
appendStringInfo(buf, "FALSE");
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unexpected CASE WHEN clause: %d",
|
||||
(int) nodeTag(w));
|
||||
}
|
||||
else
|
||||
get_rule_expr(w, context, false);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -4728,6 +4714,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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user