Skip to content

Commit 0601cb5

Browse files
committed
Limit overall indentation in rule/view dumps.
Continuing to indent no matter how deeply nested we get doesn't really do anything for readability; what's worse, it results in O(N^2) total whitespace, which can become a performance and memory-consumption issue. To address this, once we get past 40 characters of indentation, reduce the indentation step distance 4x, and also limit the maximum indentation by reducing it modulo 40. This latter choice is a bit weird at first glance, but it seems to preserve readability better than a simple cap would do. Back-patch to 9.3, because since commit 62e6664 the performance issue is a hazard for pg_dump. Greg Stark and Tom Lane
1 parent d166eed commit 0601cb5

File tree

2 files changed

+140
-116
lines changed

2 files changed

+140
-116
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
#define PRETTYINDENT_JOIN 4
7272
#define PRETTYINDENT_VAR 4
7373

74+
#define PRETTYINDENT_LIMIT 40 /* wrap limit */
75+
7476
/* Pretty flags */
7577
#define PRETTYFLAG_PAREN 1
7678
#define PRETTYFLAG_INDENT 2
@@ -6391,14 +6393,36 @@ appendContextKeyword(deparse_context *context, const char *str,
63916393

63926394
if (PRETTY_INDENT(context))
63936395
{
6396+
int indentAmount;
6397+
63946398
context->indentLevel += indentBefore;
63956399

63966400
/* remove any trailing spaces currently in the buffer ... */
63976401
removeStringInfoSpaces(buf);
63986402
/* ... then add a newline and some spaces */
63996403
appendStringInfoChar(buf, '\n');
6400-
appendStringInfoSpaces(buf,
6401-
Max(context->indentLevel, 0) + indentPlus);
6404+
6405+
if (context->indentLevel < PRETTYINDENT_LIMIT)
6406+
indentAmount = Max(context->indentLevel, 0) + indentPlus;
6407+
else
6408+
{
6409+
/*
6410+
* If we're indented more than PRETTYINDENT_LIMIT characters, try
6411+
* to conserve horizontal space by reducing the per-level
6412+
* indentation. For best results the scale factor here should
6413+
* divide all the indent amounts that get added to indentLevel
6414+
* (PRETTYINDENT_STD, etc). It's important that the indentation
6415+
* not grow unboundedly, else deeply-nested trees use O(N^2)
6416+
* whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
6417+
*/
6418+
indentAmount = PRETTYINDENT_LIMIT +
6419+
(context->indentLevel - PRETTYINDENT_LIMIT) /
6420+
(PRETTYINDENT_STD / 2);
6421+
indentAmount %= PRETTYINDENT_LIMIT;
6422+
/* scale/wrap logic affects indentLevel, but not indentPlus */
6423+
indentAmount += indentPlus;
6424+
}
6425+
appendStringInfoSpaces(buf, indentAmount);
64026426

64036427
appendStringInfoString(buf, str);
64046428

src/test/regress/expected/rules.out

Lines changed: 114 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,121 +1402,121 @@ pg_rules| SELECT n.nspname AS schemaname,
14021402
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
14031403
WHERE (r.rulename <> '_RETURN'::name);
14041404
pg_seclabels| ( ( ( ( ( ( ( ( ( SELECT l.objoid,
1405-
l.classoid,
1406-
l.objsubid,
1407-
CASE
1408-
WHEN (rel.relkind = 'r'::"char") THEN 'table'::text
1409-
WHEN (rel.relkind = 'v'::"char") THEN 'view'::text
1410-
WHEN (rel.relkind = 'm'::"char") THEN 'materialized view'::text
1411-
WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text
1412-
WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text
1413-
ELSE NULL::text
1414-
END AS objtype,
1415-
rel.relnamespace AS objnamespace,
1416-
CASE
1417-
WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
1418-
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
1419-
END AS objname,
1420-
l.provider,
1421-
l.label
1422-
FROM ((pg_seclabel l
1423-
JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
1424-
JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
1425-
WHERE (l.objsubid = 0)
1426-
UNION ALL
1427-
SELECT l.objoid,
1428-
l.classoid,
1429-
l.objsubid,
1430-
'column'::text AS objtype,
1431-
rel.relnamespace AS objnamespace,
1432-
((
1433-
CASE
1434-
WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
1435-
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
1436-
END || '.'::text) || (att.attname)::text) AS objname,
1437-
l.provider,
1438-
l.label
1439-
FROM (((pg_seclabel l
1440-
JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
1441-
JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum))))
1442-
JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
1443-
WHERE (l.objsubid <> 0))
1444-
UNION ALL
1445-
SELECT l.objoid,
1446-
l.classoid,
1447-
l.objsubid,
1448-
CASE
1449-
WHEN (pro.proisagg = true) THEN 'aggregate'::text
1450-
WHEN (pro.proisagg = false) THEN 'function'::text
1451-
ELSE NULL::text
1452-
END AS objtype,
1453-
pro.pronamespace AS objnamespace,
1454-
(((
1455-
CASE
1456-
WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text)
1457-
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text))
1458-
END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname,
1459-
l.provider,
1460-
l.label
1461-
FROM ((pg_seclabel l
1462-
JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid))))
1463-
JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid)))
1464-
WHERE (l.objsubid = 0))
1465-
UNION ALL
1466-
SELECT l.objoid,
1467-
l.classoid,
1468-
l.objsubid,
1469-
CASE
1470-
WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text
1471-
ELSE 'type'::text
1472-
END AS objtype,
1473-
typ.typnamespace AS objnamespace,
1474-
CASE
1475-
WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text)
1476-
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text))
1477-
END AS objname,
1478-
l.provider,
1479-
l.label
1480-
FROM ((pg_seclabel l
1481-
JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid))))
1482-
JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid)))
1483-
WHERE (l.objsubid = 0))
1484-
UNION ALL
1485-
SELECT l.objoid,
1486-
l.classoid,
1487-
l.objsubid,
1488-
'large object'::text AS objtype,
1489-
NULL::oid AS objnamespace,
1490-
(l.objoid)::text AS objname,
1491-
l.provider,
1492-
l.label
1493-
FROM (pg_seclabel l
1494-
JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid)))
1495-
WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0)))
1496-
UNION ALL
1497-
SELECT l.objoid,
1498-
l.classoid,
1499-
l.objsubid,
1500-
'language'::text AS objtype,
1501-
NULL::oid AS objnamespace,
1502-
quote_ident((lan.lanname)::text) AS objname,
1503-
l.provider,
1504-
l.label
1505-
FROM (pg_seclabel l
1506-
JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid))))
1507-
WHERE (l.objsubid = 0))
1405+
l.classoid,
1406+
l.objsubid,
1407+
CASE
1408+
WHEN (rel.relkind = 'r'::"char") THEN 'table'::text
1409+
WHEN (rel.relkind = 'v'::"char") THEN 'view'::text
1410+
WHEN (rel.relkind = 'm'::"char") THEN 'materialized view'::text
1411+
WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text
1412+
WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text
1413+
ELSE NULL::text
1414+
END AS objtype,
1415+
rel.relnamespace AS objnamespace,
1416+
CASE
1417+
WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
1418+
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
1419+
END AS objname,
1420+
l.provider,
1421+
l.label
1422+
FROM ((pg_seclabel l
1423+
JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
1424+
JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
1425+
WHERE (l.objsubid = 0)
1426+
UNION ALL
1427+
SELECT l.objoid,
1428+
l.classoid,
1429+
l.objsubid,
1430+
'column'::text AS objtype,
1431+
rel.relnamespace AS objnamespace,
1432+
((
1433+
CASE
1434+
WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
1435+
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
1436+
END || '.'::text) || (att.attname)::text) AS objname,
1437+
l.provider,
1438+
l.label
1439+
FROM (((pg_seclabel l
1440+
JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
1441+
JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum))))
1442+
JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
1443+
WHERE (l.objsubid <> 0))
1444+
UNION ALL
1445+
SELECT l.objoid,
1446+
l.classoid,
1447+
l.objsubid,
1448+
CASE
1449+
WHEN (pro.proisagg = true) THEN 'aggregate'::text
1450+
WHEN (pro.proisagg = false) THEN 'function'::text
1451+
ELSE NULL::text
1452+
END AS objtype,
1453+
pro.pronamespace AS objnamespace,
1454+
(((
1455+
CASE
1456+
WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text)
1457+
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text))
1458+
END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname,
1459+
l.provider,
1460+
l.label
1461+
FROM ((pg_seclabel l
1462+
JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid))))
1463+
JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid)))
1464+
WHERE (l.objsubid = 0))
1465+
UNION ALL
1466+
SELECT l.objoid,
1467+
l.classoid,
1468+
l.objsubid,
1469+
CASE
1470+
WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text
1471+
ELSE 'type'::text
1472+
END AS objtype,
1473+
typ.typnamespace AS objnamespace,
1474+
CASE
1475+
WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text)
1476+
ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text))
1477+
END AS objname,
1478+
l.provider,
1479+
l.label
1480+
FROM ((pg_seclabel l
1481+
JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid))))
1482+
JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid)))
1483+
WHERE (l.objsubid = 0))
1484+
UNION ALL
1485+
SELECT l.objoid,
1486+
l.classoid,
1487+
l.objsubid,
1488+
'large object'::text AS objtype,
1489+
NULL::oid AS objnamespace,
1490+
(l.objoid)::text AS objname,
1491+
l.provider,
1492+
l.label
1493+
FROM (pg_seclabel l
1494+
JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid)))
1495+
WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0)))
1496+
UNION ALL
1497+
SELECT l.objoid,
1498+
l.classoid,
1499+
l.objsubid,
1500+
'language'::text AS objtype,
1501+
NULL::oid AS objnamespace,
1502+
quote_ident((lan.lanname)::text) AS objname,
1503+
l.provider,
1504+
l.label
1505+
FROM (pg_seclabel l
1506+
JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid))))
1507+
WHERE (l.objsubid = 0))
15081508
UNION ALL
1509-
SELECT l.objoid,
1510-
l.classoid,
1511-
l.objsubid,
1512-
'schema'::text AS objtype,
1513-
nsp.oid AS objnamespace,
1514-
quote_ident((nsp.nspname)::text) AS objname,
1515-
l.provider,
1516-
l.label
1517-
FROM (pg_seclabel l
1518-
JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid))))
1519-
WHERE (l.objsubid = 0))
1509+
SELECT l.objoid,
1510+
l.classoid,
1511+
l.objsubid,
1512+
'schema'::text AS objtype,
1513+
nsp.oid AS objnamespace,
1514+
quote_ident((nsp.nspname)::text) AS objname,
1515+
l.provider,
1516+
l.label
1517+
FROM (pg_seclabel l
1518+
JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid))))
1519+
WHERE (l.objsubid = 0))
15201520
UNION ALL
15211521
SELECT l.objoid,
15221522
l.classoid,

0 commit comments

Comments
 (0)