aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c81
1 files changed, 54 insertions, 27 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5ed762cddb6..957f0fc7d9f 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -4714,42 +4714,59 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
else if (IsA(setOp, SetOperationStmt))
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
-
- if (PRETTY_INDENT(context))
- {
- context->indentLevel += PRETTYINDENT_STD;
- appendStringInfoSpaces(buf, PRETTYINDENT_STD);
- }
+ int subindent;
/*
- * We force parens whenever nesting two SetOperationStmts. There are
- * some cases in which parens are needed around a leaf query too, but
- * those are more easily handled at the next level down (see code
- * above).
+ * We force parens when nesting two SetOperationStmts, except when the
+ * lefthand input is another setop of the same kind. Syntactically,
+ * we could omit parens in rather more cases, but it seems best to use
+ * parens to flag cases where the setop operator changes. If we use
+ * parens, we also increase the indentation level for the child query.
+ *
+ * There are some cases in which parens are needed around a leaf query
+ * too, but those are more easily handled at the next level down (see
+ * code above).
*/
- need_paren = !IsA(op->larg, RangeTblRef);
+ if (IsA(op->larg, SetOperationStmt))
+ {
+ SetOperationStmt *lop = (SetOperationStmt *) op->larg;
+
+ if (op->op == lop->op && op->all == lop->all)
+ need_paren = false;
+ else
+ need_paren = true;
+ }
+ else
+ need_paren = false;
if (need_paren)
+ {
appendStringInfoChar(buf, '(');
+ subindent = PRETTYINDENT_STD;
+ appendContextKeyword(context, "", subindent, 0, 0);
+ }
+ else
+ subindent = 0;
+
get_setop_query(op->larg, query, context, resultDesc);
- if (need_paren)
- appendStringInfoChar(buf, ')');
- if (!PRETTY_INDENT(context))
+ if (need_paren)
+ appendContextKeyword(context, ") ", -subindent, 0, 0);
+ else if (PRETTY_INDENT(context))
+ appendContextKeyword(context, "", -subindent, 0, 0);
+ else
appendStringInfoChar(buf, ' ');
+
switch (op->op)
{
case SETOP_UNION:
- appendContextKeyword(context, "UNION ",
- -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
+ appendStringInfoString(buf, "UNION ");
break;
case SETOP_INTERSECT:
- appendContextKeyword(context, "INTERSECT ",
- -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
+ appendStringInfoString(buf, "INTERSECT ");
break;
case SETOP_EXCEPT:
- appendContextKeyword(context, "EXCEPT ",
- -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
+ appendStringInfoString(buf, "EXCEPT ");
break;
default:
elog(ERROR, "unrecognized set op: %d",
@@ -4758,19 +4775,29 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
if (op->all)
appendStringInfoString(buf, "ALL ");
- if (PRETTY_INDENT(context))
- appendContextKeyword(context, "", 0, 0, 0);
-
- need_paren = !IsA(op->rarg, RangeTblRef);
+ /* Always parenthesize if RHS is another setop */
+ need_paren = IsA(op->rarg, SetOperationStmt);
+ /*
+ * The indentation code here is deliberately a bit different from that
+ * for the lefthand input, because we want the line breaks in
+ * different places.
+ */
if (need_paren)
+ {
appendStringInfoChar(buf, '(');
+ subindent = PRETTYINDENT_STD;
+ }
+ else
+ subindent = 0;
+ appendContextKeyword(context, "", subindent, 0, 0);
+
get_setop_query(op->rarg, query, context, resultDesc);
- if (need_paren)
- appendStringInfoChar(buf, ')');
if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_STD;
+ context->indentLevel -= subindent;
+ if (need_paren)
+ appendContextKeyword(context, ")", 0, 0, 0);
}
else
{