From 3987e9e62046bd800d8d08566ed49fee1ae6cb86 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 26 May 2011 19:25:19 -0400 Subject: [PATCH] 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. --- src/backend/utils/adt/ruleutils.c | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 3ab90cb7d8..1595ef032d 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5187,50 +5187,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); } @@ -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; -- 2.40.0