Limit overall indentation in rule/view dumps.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Apr 2014 16:48:12 +0000 (12:48 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Apr 2014 16:48:12 +0000 (12:48 -0400)
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 62e666400d the performance issue
is a hazard for pg_dump.

Greg Stark and Tom Lane

src/backend/utils/adt/ruleutils.c
src/test/regress/expected/rules.out

index 88345312336829dfc7a89a4c2f99f9619a11354e..5ed762cddb65936c69c8ea89de14764a64016caa 100644 (file)
@@ -71,6 +71,8 @@
 #define PRETTYINDENT_JOIN      4
 #define PRETTYINDENT_VAR       4
 
+#define PRETTYINDENT_LIMIT     40      /* wrap limit */
+
 /* Pretty flags */
 #define PRETTYFLAG_PAREN       1
 #define PRETTYFLAG_INDENT      2
@@ -6391,14 +6393,36 @@ appendContextKeyword(deparse_context *context, const char *str,
 
    if (PRETTY_INDENT(context))
    {
+       int         indentAmount;
+
        context->indentLevel += indentBefore;
 
        /* remove any trailing spaces currently in the buffer ... */
        removeStringInfoSpaces(buf);
        /* ... then add a newline and some spaces */
        appendStringInfoChar(buf, '\n');
-       appendStringInfoSpaces(buf,
-                              Max(context->indentLevel, 0) + indentPlus);
+
+       if (context->indentLevel < PRETTYINDENT_LIMIT)
+           indentAmount = Max(context->indentLevel, 0) + indentPlus;
+       else
+       {
+           /*
+            * If we're indented more than PRETTYINDENT_LIMIT characters, try
+            * to conserve horizontal space by reducing the per-level
+            * indentation.  For best results the scale factor here should
+            * divide all the indent amounts that get added to indentLevel
+            * (PRETTYINDENT_STD, etc).  It's important that the indentation
+            * not grow unboundedly, else deeply-nested trees use O(N^2)
+            * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
+            */
+           indentAmount = PRETTYINDENT_LIMIT +
+               (context->indentLevel - PRETTYINDENT_LIMIT) /
+               (PRETTYINDENT_STD / 2);
+           indentAmount %= PRETTYINDENT_LIMIT;
+           /* scale/wrap logic affects indentLevel, but not indentPlus */
+           indentAmount += indentPlus;
+       }
+       appendStringInfoSpaces(buf, indentAmount);
 
        appendStringInfoString(buf, str);
 
index 68cabf8b24302a74b098984c397914bbe04e3683..b0750f97352153bc998a80b4af2648b8d43172f1 100644 (file)
@@ -1402,121 +1402,121 @@ pg_rules| SELECT n.nspname AS schemaname,
      LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
   WHERE (r.rulename <> '_RETURN'::name);
 pg_seclabels|        (        (        (        (        (        (        (        (        (         SELECT l.objoid,
-                                                                                    l.classoid,
-                                                                                    l.objsubid,
-                                                                                        CASE
-                                                                                            WHEN (rel.relkind = 'r'::"char") THEN 'table'::text
-                                                                                            WHEN (rel.relkind = 'v'::"char") THEN 'view'::text
-                                                                                            WHEN (rel.relkind = 'm'::"char") THEN 'materialized view'::text
-                                                                                            WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text
-                                                                                            WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text
-                                                                                            ELSE NULL::text
-                                                                                        END AS objtype,
-                                                                                    rel.relnamespace AS objnamespace,
-                                                                                        CASE
-                                                                                            WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
-                                                                                            ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
-                                                                                        END AS objname,
-                                                                                    l.provider,
-                                                                                    l.label
-                                                                                   FROM ((pg_seclabel l
-                                                                                     JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
-                                                                                     JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
-                                                                                  WHERE (l.objsubid = 0)
-                                                                        UNION ALL
-                                                                                 SELECT l.objoid,
-                                                                                    l.classoid,
-                                                                                    l.objsubid,
-                                                                                    'column'::text AS objtype,
-                                                                                    rel.relnamespace AS objnamespace,
-                                                                                    ((
-                                                                                        CASE
-                                                                                            WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
-                                                                                            ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
-                                                                                        END || '.'::text) || (att.attname)::text) AS objname,
-                                                                                    l.provider,
-                                                                                    l.label
-                                                                                   FROM (((pg_seclabel l
-                                                                                     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_namespace nsp ON ((rel.relnamespace = nsp.oid)))
-                                                                                  WHERE (l.objsubid <> 0))
-                                                                UNION ALL
-                                                                         SELECT l.objoid,
-                                                                            l.classoid,
-                                                                            l.objsubid,
-                                                                                CASE
-                                                                                    WHEN (pro.proisagg = true) THEN 'aggregate'::text
-                                                                                    WHEN (pro.proisagg = false) THEN 'function'::text
-                                                                                    ELSE NULL::text
-                                                                                END AS objtype,
-                                                                            pro.pronamespace AS objnamespace,
-                                                                            (((
-                                                                                CASE
-                                                                                    WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text)
-                                                                                    ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text))
-                                                                                END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname,
-                                                                            l.provider,
-                                                                            l.label
-                                                                           FROM ((pg_seclabel l
-                                                                             JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid))))
-                                                                             JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid)))
-                                                                          WHERE (l.objsubid = 0))
-                                                        UNION ALL
-                                                                 SELECT l.objoid,
-                                                                    l.classoid,
-                                                                    l.objsubid,
-                                                                        CASE
-                                                                            WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text
-                                                                            ELSE 'type'::text
-                                                                        END AS objtype,
-                                                                    typ.typnamespace AS objnamespace,
-                                                                        CASE
-                                                                            WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text)
-                                                                            ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text))
-                                                                        END AS objname,
-                                                                    l.provider,
-                                                                    l.label
-                                                                   FROM ((pg_seclabel l
-                                                                     JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid))))
-                                                                     JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid)))
-                                                                  WHERE (l.objsubid = 0))
-                                                UNION ALL
-                                                         SELECT l.objoid,
-                                                            l.classoid,
-                                                            l.objsubid,
-                                                            'large object'::text AS objtype,
-                                                            NULL::oid AS objnamespace,
-                                                            (l.objoid)::text AS objname,
-                                                            l.provider,
-                                                            l.label
-                                                           FROM (pg_seclabel l
-                                                             JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid)))
-                                                          WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0)))
-                                        UNION ALL
-                                                 SELECT l.objoid,
-                                                    l.classoid,
-                                                    l.objsubid,
-                                                    'language'::text AS objtype,
-                                                    NULL::oid AS objnamespace,
-                                                    quote_ident((lan.lanname)::text) AS objname,
-                                                    l.provider,
-                                                    l.label
-                                                   FROM (pg_seclabel l
-                                                     JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid))))
-                                                  WHERE (l.objsubid = 0))
+              l.classoid,
+              l.objsubid,
+            CASE
+             WHEN (rel.relkind = 'r'::"char") THEN 'table'::text
+             WHEN (rel.relkind = 'v'::"char") THEN 'view'::text
+             WHEN (rel.relkind = 'm'::"char") THEN 'materialized view'::text
+             WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text
+             WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text
+             ELSE NULL::text
+            END AS objtype,
+              rel.relnamespace AS objnamespace,
+            CASE
+             WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
+             ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
+            END AS objname,
+              l.provider,
+              l.label
+             FROM ((pg_seclabel l
+               JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid))))
+               JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid)))
+            WHERE (l.objsubid = 0)
+        UNION ALL
+           SELECT l.objoid,
+              l.classoid,
+              l.objsubid,
+              'column'::text AS objtype,
+              rel.relnamespace AS objnamespace,
+              ((
+            CASE
+             WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text)
+             ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text))
+            END || '.'::text) || (att.attname)::text) AS objname,
+              l.provider,
+              l.label
+             FROM (((pg_seclabel l
+               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_namespace nsp ON ((rel.relnamespace = nsp.oid)))
+            WHERE (l.objsubid <> 0))
+      UNION ALL
+         SELECT l.objoid,
+            l.classoid,
+            l.objsubid,
+          CASE
+           WHEN (pro.proisagg = true) THEN 'aggregate'::text
+           WHEN (pro.proisagg = false) THEN 'function'::text
+           ELSE NULL::text
+          END AS objtype,
+            pro.pronamespace AS objnamespace,
+            (((
+          CASE
+           WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text)
+           ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text))
+          END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname,
+            l.provider,
+            l.label
+           FROM ((pg_seclabel l
+             JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid))))
+             JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid)))
+          WHERE (l.objsubid = 0))
+    UNION ALL
+       SELECT l.objoid,
+          l.classoid,
+          l.objsubid,
+        CASE
+         WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text
+         ELSE 'type'::text
+        END AS objtype,
+          typ.typnamespace AS objnamespace,
+        CASE
+         WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text)
+         ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text))
+        END AS objname,
+          l.provider,
+          l.label
+         FROM ((pg_seclabel l
+           JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid))))
+           JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid)))
+        WHERE (l.objsubid = 0))
+  UNION ALL
+     SELECT l.objoid,
+        l.classoid,
+        l.objsubid,
+        'large object'::text AS objtype,
+        NULL::oid AS objnamespace,
+        (l.objoid)::text AS objname,
+        l.provider,
+        l.label
+       FROM (pg_seclabel l
+         JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid)))
+      WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0)))
+UNION ALL
+   SELECT l.objoid,
+      l.classoid,
+      l.objsubid,
+      'language'::text AS objtype,
+      NULL::oid AS objnamespace,
+      quote_ident((lan.lanname)::text) AS objname,
+      l.provider,
+      l.label
+     FROM (pg_seclabel l
+       JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid))))
+    WHERE (l.objsubid = 0))
                                 UNION ALL
                                        SELECT l.objoid,
-                                            l.classoid,
-                                            l.objsubid,
-                                            'schema'::text AS objtype,
-                                            nsp.oid AS objnamespace,
-                                            quote_ident((nsp.nspname)::text) AS objname,
-                                            l.provider,
-                                            l.label
-                                           FROM (pg_seclabel l
-                                             JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid))))
-                                          WHERE (l.objsubid = 0))
+ SELECT l.objoid,
+    l.classoid,
+    l.objsubid,
+    'schema'::text AS objtype,
+    nsp.oid AS objnamespace,
+    quote_ident((nsp.nspname)::text) AS objname,
+    l.provider,
+    l.label
+   FROM (pg_seclabel l
+     JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid))))
+  WHERE (l.objsubid = 0))
                         UNION ALL
                                  SELECT l.objoid,
                                     l.classoid,