mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
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
44404f3945
commit
3987e9e620
@ -5187,50 +5187,36 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
CaseWhen *when = (CaseWhen *) lfirst(temp);
|
CaseWhen *when = (CaseWhen *) lfirst(temp);
|
||||||
Node *w = (Node *) when->expr;
|
Node *w = (Node *) when->expr;
|
||||||
|
|
||||||
if (!PRETTY_INDENT(context))
|
|
||||||
appendStringInfoChar(buf, ' ');
|
|
||||||
appendContextKeyword(context, "WHEN ",
|
|
||||||
0, 0, 0);
|
|
||||||
if (caseexpr->arg)
|
if (caseexpr->arg)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The parser should have produced WHEN clauses of the
|
* The parser should have produced WHEN clauses of
|
||||||
* form "CaseTestExpr = RHS"; we want to show just the
|
* the form "CaseTestExpr = RHS", possibly with an
|
||||||
* RHS. If the user wrote something silly like "CASE
|
* implicit coercion inserted above the CaseTestExpr.
|
||||||
* boolexpr WHEN TRUE THEN ...", then the optimizer's
|
* For accurate decompilation of rules it's essential
|
||||||
* simplify_boolean_equality() may have reduced this
|
* that we show just the RHS. However in an
|
||||||
* to just "CaseTestExpr" or "NOT CaseTestExpr", for
|
* expression that's been through the optimizer, the
|
||||||
* which we have to show "TRUE" or "FALSE". We have
|
* WHEN clause could be almost anything (since the
|
||||||
* also to consider the possibility that an implicit
|
* equality operator could have been expanded into an
|
||||||
* coercion was inserted between the CaseTestExpr and
|
* inline function). If we don't recognize the form
|
||||||
* the operator.
|
* of the WHEN clause, just punt and display it as-is.
|
||||||
*/
|
*/
|
||||||
if (IsA(w, OpExpr))
|
if (IsA(w, OpExpr))
|
||||||
{
|
{
|
||||||
List *args = ((OpExpr *) w)->args;
|
List *args = ((OpExpr *) w)->args;
|
||||||
Node *rhs;
|
|
||||||
|
|
||||||
Assert(list_length(args) == 2);
|
if (list_length(args) == 2 &&
|
||||||
Assert(IsA(strip_implicit_coercions(linitial(args)),
|
IsA(strip_implicit_coercions(linitial(args)),
|
||||||
CaseTestExpr));
|
CaseTestExpr))
|
||||||
rhs = (Node *) lsecond(args);
|
w = (Node *) lsecond(args);
|
||||||
get_rule_expr(rhs, context, false);
|
|
||||||
}
|
}
|
||||||
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 ");
|
appendStringInfo(buf, " THEN ");
|
||||||
get_rule_expr((Node *) when->result, context, true);
|
get_rule_expr((Node *) when->result, context, true);
|
||||||
}
|
}
|
||||||
@ -5246,6 +5232,19 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case T_ArrayExpr:
|
||||||
{
|
{
|
||||||
ArrayExpr *arrayexpr = (ArrayExpr *) node;
|
ArrayExpr *arrayexpr = (ArrayExpr *) node;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user