summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-05-26 19:25:19 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2011-05-26 19:25:19 -0400
commit3987e9e62046bd800d8d08566ed49fee1ae6cb86 (patch)
tree19734041040d9f718b48d60499b0e5a4b0732aa8
parent44404f394517f89a0bebb1aaace6e64ad79d2817 (diff)
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.
-rw-r--r--src/backend/utils/adt/ruleutils.c67
1 files changed, 33 insertions, 34 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3ab90cb7d88..1595ef032d1 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;