]> granicus.if.org Git - postgresql/commitdiff
Make decompilation of optimized CASE constructs more robust.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 26 May 2011 23:25:19 +0000 (19:25 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 26 May 2011 23:26:04 +0000 (19:26 -0400)
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

index d540026ff8b211247a291efaeb4036b1fda2e39e..5569e338bbcccce6a2d8565ef898be6bee8306e8 100644 (file)
@@ -3721,50 +3721,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);
                                }
@@ -3780,6 +3766,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;