mirror of
https://github.com/postgres/postgres.git
synced 2025-05-09 18:21:05 +03:00
Reduce indentation/parenthesization of set operations in rule/view dumps.
A query such as "SELECT x UNION SELECT y UNION SELECT z UNION ..." produces a left-deep nested parse tree, which we formerly showed in its full nested glory and with all the possible parentheses. This does little for readability, though, and long UNION lists resulting in excessive indentation are common. Instead, let's omit parentheses and indent all the subqueries at the same level in such cases. This patch skips indentation/parenthesization whenever the lefthand input of a SetOperationStmt is another SetOperationStmt of the same kind and ALL/DISTINCT property. We could teach the code the exact syntactic precedence of set operations and thereby avoid parenthesization in some more cases, but it's not clear that that'd be a readability win: it seems better to parenthesize if the set operation changes. (As an example, if there's one UNION in a long list of UNION ALL, it now stands out like a sore thumb, which seems like a good thing.) Back-patch to 9.3. This completes our response to a complaint from Greg Stark that since commit 62e666400d there's a performance problem in pg_dump for views containing long UNION sequences (or other types of deeply nested constructs). The previous commit 0601cb54dac14d979d726ab2ebeda251ae36e857 handles the general problem, but this one makes the specific case of UNION lists look a lot nicer.
This commit is contained in:
parent
de6c439dc8
commit
0652d77fb0
@ -4581,42 +4581,59 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
|
|||||||
else if (IsA(setOp, SetOperationStmt))
|
else if (IsA(setOp, SetOperationStmt))
|
||||||
{
|
{
|
||||||
SetOperationStmt *op = (SetOperationStmt *) setOp;
|
SetOperationStmt *op = (SetOperationStmt *) setOp;
|
||||||
|
int subindent;
|
||||||
if (PRETTY_INDENT(context))
|
|
||||||
{
|
|
||||||
context->indentLevel += PRETTYINDENT_STD;
|
|
||||||
appendStringInfoSpaces(buf, PRETTYINDENT_STD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We force parens whenever nesting two SetOperationStmts. There are
|
* We force parens when nesting two SetOperationStmts, except when the
|
||||||
* some cases in which parens are needed around a leaf query too, but
|
* lefthand input is another setop of the same kind. Syntactically,
|
||||||
* those are more easily handled at the next level down (see code
|
* we could omit parens in rather more cases, but it seems best to use
|
||||||
* above).
|
* 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)
|
if (need_paren)
|
||||||
|
{
|
||||||
appendStringInfoChar(buf, '(');
|
appendStringInfoChar(buf, '(');
|
||||||
get_setop_query(op->larg, query, context, resultDesc);
|
subindent = PRETTYINDENT_STD;
|
||||||
if (need_paren)
|
appendContextKeyword(context, "", subindent, 0, 0);
|
||||||
appendStringInfoChar(buf, ')');
|
}
|
||||||
|
else
|
||||||
|
subindent = 0;
|
||||||
|
|
||||||
if (!PRETTY_INDENT(context))
|
get_setop_query(op->larg, query, context, resultDesc);
|
||||||
|
|
||||||
|
if (need_paren)
|
||||||
|
appendContextKeyword(context, ") ", -subindent, 0, 0);
|
||||||
|
else if (PRETTY_INDENT(context))
|
||||||
|
appendContextKeyword(context, "", -subindent, 0, 0);
|
||||||
|
else
|
||||||
appendStringInfoChar(buf, ' ');
|
appendStringInfoChar(buf, ' ');
|
||||||
|
|
||||||
switch (op->op)
|
switch (op->op)
|
||||||
{
|
{
|
||||||
case SETOP_UNION:
|
case SETOP_UNION:
|
||||||
appendContextKeyword(context, "UNION ",
|
appendStringInfoString(buf, "UNION ");
|
||||||
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
|
||||||
break;
|
break;
|
||||||
case SETOP_INTERSECT:
|
case SETOP_INTERSECT:
|
||||||
appendContextKeyword(context, "INTERSECT ",
|
appendStringInfoString(buf, "INTERSECT ");
|
||||||
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
|
||||||
break;
|
break;
|
||||||
case SETOP_EXCEPT:
|
case SETOP_EXCEPT:
|
||||||
appendContextKeyword(context, "EXCEPT ",
|
appendStringInfoString(buf, "EXCEPT ");
|
||||||
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unrecognized set op: %d",
|
elog(ERROR, "unrecognized set op: %d",
|
||||||
@ -4625,19 +4642,29 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
|
|||||||
if (op->all)
|
if (op->all)
|
||||||
appendStringInfo(buf, "ALL ");
|
appendStringInfo(buf, "ALL ");
|
||||||
|
|
||||||
if (PRETTY_INDENT(context))
|
/* Always parenthesize if RHS is another setop */
|
||||||
appendContextKeyword(context, "", 0, 0, 0);
|
need_paren = IsA(op->rarg, SetOperationStmt);
|
||||||
|
|
||||||
need_paren = !IsA(op->rarg, RangeTblRef);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
if (need_paren)
|
||||||
|
{
|
||||||
appendStringInfoChar(buf, '(');
|
appendStringInfoChar(buf, '(');
|
||||||
|
subindent = PRETTYINDENT_STD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
subindent = 0;
|
||||||
|
appendContextKeyword(context, "", subindent, 0, 0);
|
||||||
|
|
||||||
get_setop_query(op->rarg, query, context, resultDesc);
|
get_setop_query(op->rarg, query, context, resultDesc);
|
||||||
if (need_paren)
|
|
||||||
appendStringInfoChar(buf, ')');
|
|
||||||
|
|
||||||
if (PRETTY_INDENT(context))
|
if (PRETTY_INDENT(context))
|
||||||
context->indentLevel -= PRETTYINDENT_STD;
|
context->indentLevel -= subindent;
|
||||||
|
if (need_paren)
|
||||||
|
appendContextKeyword(context, ")", 0, 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1091,7 +1091,7 @@ union all
|
|||||||
select * from tt7 full join tt8 using (x), tt8 tt8x;
|
select * from tt7 full join tt8 using (x), tt8 tt8x;
|
||||||
select pg_get_viewdef('vv2', true);
|
select pg_get_viewdef('vv2', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
--------------------------------------------------------
|
------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1117,7 +1117,7 @@ select * from
|
|||||||
tt7 tt7x full join tt8 tt8x using (x);
|
tt7 tt7x full join tt8 tt8x using (x);
|
||||||
select pg_get_viewdef('vv3', true);
|
select pg_get_viewdef('vv3', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
-------------------------------------------------------------
|
-----------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1146,7 +1146,7 @@ select * from
|
|||||||
tt7 tt7x full join tt8 tt8x using (x) full join tt8 tt8y using (x);
|
tt7 tt7x full join tt8 tt8x using (x) full join tt8 tt8y using (x);
|
||||||
select pg_get_viewdef('vv4', true);
|
select pg_get_viewdef('vv4', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
------------------------------------------------------------------
|
----------------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1176,7 +1176,7 @@ alter table tt7 drop column zz;
|
|||||||
alter table tt8 add column z2 int;
|
alter table tt8 add column z2 int;
|
||||||
select pg_get_viewdef('vv2', true);
|
select pg_get_viewdef('vv2', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
--------------------------------------------------------
|
------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1196,7 +1196,7 @@ select pg_get_viewdef('vv2', true);
|
|||||||
|
|
||||||
select pg_get_viewdef('vv3', true);
|
select pg_get_viewdef('vv3', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
-------------------------------------------------------------
|
-----------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1219,7 +1219,7 @@ select pg_get_viewdef('vv3', true);
|
|||||||
|
|
||||||
select pg_get_viewdef('vv4', true);
|
select pg_get_viewdef('vv4', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
------------------------------------------------------------------
|
----------------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
@ -1253,7 +1253,7 @@ union all
|
|||||||
select * from tt7a left join tt8a using (x), tt8a tt8ax;
|
select * from tt7a left join tt8a using (x), tt8a tt8ax;
|
||||||
select pg_get_viewdef('vv2a', true);
|
select pg_get_viewdef('vv2a', true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
----------------------------------------------------------------
|
--------------------------------------------------------
|
||||||
SELECT v.a, +
|
SELECT v.a, +
|
||||||
v.b, +
|
v.b, +
|
||||||
v.c, +
|
v.c, +
|
||||||
|
@ -1390,7 +1390,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| JOIN pg_class c ON ((c.oid = r.ev_class))) +
|
| JOIN pg_class c ON ((c.oid = r.ev_class))) +
|
||||||
| LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) +
|
| LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) +
|
||||||
| WHERE (r.rulename <> '_RETURN'::name);
|
| WHERE (r.rulename <> '_RETURN'::name);
|
||||||
pg_seclabels | ( ( ( ( ( ( ( ( ( SELECT l.objoid, +
|
pg_seclabels | SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
| l.objsubid, +
|
| l.objsubid, +
|
||||||
| CASE +
|
| CASE +
|
||||||
@ -1429,7 +1429,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) +
|
| JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) +
|
||||||
| JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) +
|
| JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) +
|
||||||
| JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) +
|
| JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) +
|
||||||
| WHERE (l.objsubid <> 0)) +
|
| WHERE (l.objsubid <> 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1450,7 +1450,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| FROM ((pg_seclabel l +
|
| FROM ((pg_seclabel l +
|
||||||
| JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) +
|
| JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) +
|
||||||
| JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) +
|
| JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) +
|
||||||
| WHERE (l.objsubid = 0)) +
|
| WHERE (l.objsubid = 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1469,7 +1469,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| FROM ((pg_seclabel l +
|
| FROM ((pg_seclabel l +
|
||||||
| JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) +
|
| JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) +
|
||||||
| JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) +
|
| JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) +
|
||||||
| WHERE (l.objsubid = 0)) +
|
| WHERE (l.objsubid = 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1481,7 +1481,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_seclabel l +
|
| FROM (pg_seclabel l +
|
||||||
| JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) +
|
| JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) +
|
||||||
| WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) +
|
| WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0)) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1493,7 +1493,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_seclabel l +
|
| FROM (pg_seclabel l +
|
||||||
| JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) +
|
| JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) +
|
||||||
| WHERE (l.objsubid = 0)) +
|
| WHERE (l.objsubid = 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1505,7 +1505,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_seclabel l +
|
| FROM (pg_seclabel l +
|
||||||
| JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) +
|
| JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) +
|
||||||
| WHERE (l.objsubid = 0)) +
|
| WHERE (l.objsubid = 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1517,7 +1517,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_seclabel l +
|
| FROM (pg_seclabel l +
|
||||||
| JOIN pg_event_trigger evt ON (((l.classoid = evt.tableoid) AND (l.objoid = evt.oid)))) +
|
| JOIN pg_event_trigger evt ON (((l.classoid = evt.tableoid) AND (l.objoid = evt.oid)))) +
|
||||||
| WHERE (l.objsubid = 0)) +
|
| WHERE (l.objsubid = 0) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1528,7 +1528,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.provider, +
|
| l.provider, +
|
||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_shseclabel l +
|
| FROM (pg_shseclabel l +
|
||||||
| JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid))))) +
|
| JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid)))) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
@ -1539,7 +1539,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
| l.provider, +
|
| l.provider, +
|
||||||
| l.label +
|
| l.label +
|
||||||
| FROM (pg_shseclabel l +
|
| FROM (pg_shseclabel l +
|
||||||
| JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid))))) +
|
| JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid)))) +
|
||||||
| UNION ALL +
|
| UNION ALL +
|
||||||
| SELECT l.objoid, +
|
| SELECT l.objoid, +
|
||||||
| l.classoid, +
|
| l.classoid, +
|
||||||
|
@ -301,7 +301,7 @@ SELECT * FROM vsubdepartment ORDER BY name;
|
|||||||
-- Check reverse listing
|
-- Check reverse listing
|
||||||
SELECT pg_get_viewdef('vsubdepartment'::regclass);
|
SELECT pg_get_viewdef('vsubdepartment'::regclass);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
-------------------------------------------------------
|
-----------------------------------------------
|
||||||
WITH RECURSIVE subdepartment AS ( +
|
WITH RECURSIVE subdepartment AS ( +
|
||||||
SELECT department.id, +
|
SELECT department.id, +
|
||||||
department.parent_department, +
|
department.parent_department, +
|
||||||
@ -324,7 +324,7 @@ SELECT pg_get_viewdef('vsubdepartment'::regclass);
|
|||||||
|
|
||||||
SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
|
SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
|
||||||
pg_get_viewdef
|
pg_get_viewdef
|
||||||
-----------------------------------------------------
|
---------------------------------------------
|
||||||
WITH RECURSIVE subdepartment AS ( +
|
WITH RECURSIVE subdepartment AS ( +
|
||||||
SELECT department.id, +
|
SELECT department.id, +
|
||||||
department.parent_department, +
|
department.parent_department, +
|
||||||
|
Loading…
x
Reference in New Issue
Block a user