]> granicus.if.org Git - postgresql/commitdiff
Improve psql's \d command to show whether index columns are key columns.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 19 Jul 2018 18:53:41 +0000 (14:53 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 19 Jul 2018 18:53:48 +0000 (14:53 -0400)
This is essential information when looking at an index that has
"included" columns.  Per discussion, follow the style used in \dC
and some other places: column header is "Key?" and values are "yes"
or "no" (all translatable).

While at it, revise describeOneTableDetails to be a bit more maintainable:
avoid hard-wired column numbers and multiple repetitions of what needs
to be identical test logic.  This also results in the emitted catalog
query corresponding more closely to what we print, which should be a
benefit to users of ECHO_HIDDEN mode, and perhaps a bit faster too
(the old logic sometimes asked for values it would not print, even
ones that are fairly expensive to get).

Discussion: https://postgr.es/m/21724.1531943735@sss.pgh.pa.us

src/bin/psql/describe.c
src/test/regress/expected/alter_table.out
src/test/regress/expected/create_index.out
src/test/regress/expected/index_including.out
src/test/regress/output/tablespace.source

index 6e085158573e38606dfddbf1254a528b3513b4da..c3bdf8555dbcfa9f53c6b3f68d60733bfdde941f 100644 (file)
@@ -1410,6 +1410,7 @@ describeOneTableDetails(const char *schemaname,
                                                const char *oid,
                                                bool verbose)
 {
+       bool            retval = false;
        PQExpBufferData buf;
        PGresult   *res = NULL;
        printTableOpt myopt = pset.popt.topt;
@@ -1421,7 +1422,19 @@ describeOneTableDetails(const char *schemaname,
        PQExpBufferData title;
        PQExpBufferData tmpbuf;
        int                     cols;
-       int                     numrows = 0;
+       int                     attname_col = -1,       /* column indexes in "res" */
+                               atttype_col = -1,
+                               attrdef_col = -1,
+                               attnotnull_col = -1,
+                               attcoll_col = -1,
+                               attidentity_col = -1,
+                               isindexkey_col = -1,
+                               indexdef_col = -1,
+                               fdwopts_col = -1,
+                               attstorage_col = -1,
+                               attstattarget_col = -1,
+                               attdescr_col = -1;
+       int                     numrows;
        struct
        {
                int16           checks;
@@ -1439,9 +1452,6 @@ describeOneTableDetails(const char *schemaname,
                char            relreplident;
        }                       tableinfo;
        bool            show_column_details = false;
-       bool            retval;
-
-       retval = false;
 
        myopt.default_footer = false;
        /* This output looks confusing in expanded mode. */
@@ -1720,42 +1730,88 @@ describeOneTableDetails(const char *schemaname,
                goto error_return;              /* not an error, just return early */
        }
 
+       /* Identify whether we should print collation, nullable, default vals */
+       if (tableinfo.relkind == RELKIND_RELATION ||
+               tableinfo.relkind == RELKIND_VIEW ||
+               tableinfo.relkind == RELKIND_MATVIEW ||
+               tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
+               tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
+               tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+               show_column_details = true;
+
        /*
-        * Get column info
+        * Get per-column info
         *
-        * You need to modify value of "firstvcol" which will be defined below if
-        * you are adding column(s) preceding to verbose-only columns.
+        * Since the set of query columns we need varies depending on relkind and
+        * server version, we compute all the column numbers on-the-fly.  Column
+        * number variables for columns not fetched are left as -1; this avoids
+        * duplicative test logic below.
         */
-       printfPQExpBuffer(&buf, "SELECT a.attname,");
-       appendPQExpBufferStr(&buf, "\n  pg_catalog.format_type(a.atttypid, a.atttypmod),"
-                                                "\n  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
-                                                "\n   FROM pg_catalog.pg_attrdef d"
-                                                "\n   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
-                                                "\n  a.attnotnull, a.attnum,");
-       if (pset.sversion >= 90100)
-               appendPQExpBufferStr(&buf, "\n  (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
-                                                        "   WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
-       else
-               appendPQExpBufferStr(&buf, "\n  NULL AS attcollation");
-       if (pset.sversion >= 100000)
-               appendPQExpBufferStr(&buf, ",\n  a.attidentity");
-       else
-               appendPQExpBufferStr(&buf, ",\n  ''::pg_catalog.char AS attidentity");
+       cols = 0;
+       printfPQExpBuffer(&buf, "SELECT a.attname");
+       attname_col = cols++;
+       appendPQExpBufferStr(&buf, ",\n  pg_catalog.format_type(a.atttypid, a.atttypmod)");
+       atttype_col = cols++;
+
+       if (show_column_details)
+       {
+               appendPQExpBufferStr(&buf,
+                                                        ",\n  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
+                                                        "\n   FROM pg_catalog.pg_attrdef d"
+                                                        "\n   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)"
+                                                        ",\n  a.attnotnull");
+               attrdef_col = cols++;
+               attnotnull_col = cols++;
+               if (pset.sversion >= 90100)
+                       appendPQExpBufferStr(&buf, ",\n  (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
+                                                                "   WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
+               else
+                       appendPQExpBufferStr(&buf, ",\n  NULL AS attcollation");
+               attcoll_col = cols++;
+               if (pset.sversion >= 100000)
+                       appendPQExpBufferStr(&buf, ",\n  a.attidentity");
+               else
+                       appendPQExpBufferStr(&buf, ",\n  ''::pg_catalog.char AS attidentity");
+               attidentity_col = cols++;
+       }
        if (tableinfo.relkind == RELKIND_INDEX ||
                tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
+       {
+               if (pset.sversion >= 110000)
+               {
+                       appendPQExpBuffer(&buf, ",\n  CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
+                                                         oid,
+                                                         gettext_noop("yes"),
+                                                         gettext_noop("no"));
+                       isindexkey_col = cols++;
+               }
                appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
-       else
-               appendPQExpBufferStr(&buf, ",\n  NULL AS indexdef");
+               indexdef_col = cols++;
+       }
+       /* FDW options for foreign table column, only for 9.2 or later */
        if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
+       {
                appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
                                                         "  '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)  FROM "
                                                         "  pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
-       else
-               appendPQExpBufferStr(&buf, ",\n  NULL AS attfdwoptions");
+               fdwopts_col = cols++;
+       }
        if (verbose)
        {
                appendPQExpBufferStr(&buf, ",\n  a.attstorage");
-               appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
+               attstorage_col = cols++;
+
+               /* stats target, if relevant to relkind */
+               if (tableinfo.relkind == RELKIND_RELATION ||
+                       tableinfo.relkind == RELKIND_INDEX ||
+                       tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
+                       tableinfo.relkind == RELKIND_MATVIEW ||
+                       tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
+                       tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+               {
+                       appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
+                       attstattarget_col = cols++;
+               }
 
                /*
                 * In 9.0+, we have column comments for: relations, views, composite
@@ -1767,7 +1823,10 @@ describeOneTableDetails(const char *schemaname,
                        tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
                        tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
                        tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-                       appendPQExpBufferStr(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
+               {
+                       appendPQExpBufferStr(&buf, ",\n  pg_catalog.col_description(a.attrelid, a.attnum)");
+                       attdescr_col = cols++;
+               }
        }
 
        appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
@@ -1843,50 +1902,30 @@ describeOneTableDetails(const char *schemaname,
                        break;
        }
 
-       /* Set the number of columns, and their names */
-       headers[0] = gettext_noop("Column");
-       headers[1] = gettext_noop("Type");
-       cols = 2;
-
-       if (tableinfo.relkind == RELKIND_RELATION ||
-               tableinfo.relkind == RELKIND_VIEW ||
-               tableinfo.relkind == RELKIND_MATVIEW ||
-               tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-               tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-               tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+       /* Fill headers[] with the names of the columns we will output */
+       cols = 0;
+       headers[cols++] = gettext_noop("Column");
+       headers[cols++] = gettext_noop("Type");
+       if (show_column_details)
        {
                headers[cols++] = gettext_noop("Collation");
                headers[cols++] = gettext_noop("Nullable");
                headers[cols++] = gettext_noop("Default");
-               show_column_details = true;
        }
-
-       if (tableinfo.relkind == RELKIND_INDEX ||
-               tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
+       if (isindexkey_col >= 0)
+               headers[cols++] = gettext_noop("Key?");
+       if (indexdef_col >= 0)
                headers[cols++] = gettext_noop("Definition");
-
-       if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
+       if (fdwopts_col >= 0)
                headers[cols++] = gettext_noop("FDW options");
-
-       if (verbose)
-       {
+       if (attstorage_col >= 0)
                headers[cols++] = gettext_noop("Storage");
-               if (tableinfo.relkind == RELKIND_RELATION ||
-                       tableinfo.relkind == RELKIND_INDEX ||
-                       tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-                       tableinfo.relkind == RELKIND_MATVIEW ||
-                       tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-                       tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-                       headers[cols++] = gettext_noop("Stats target");
-               /* Column comments, if the relkind supports this feature. */
-               if (tableinfo.relkind == RELKIND_RELATION ||
-                       tableinfo.relkind == RELKIND_VIEW ||
-                       tableinfo.relkind == RELKIND_MATVIEW ||
-                       tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-                       tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-                       tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-                       headers[cols++] = gettext_noop("Description");
-       }
+       if (attstattarget_col >= 0)
+               headers[cols++] = gettext_noop("Stats target");
+       if (attdescr_col >= 0)
+               headers[cols++] = gettext_noop("Description");
+
+       Assert(cols <= lengthof(headers));
 
        printTableInit(&cont, &myopt, title.data, cols, numrows);
        printTableInitialized = true;
@@ -1894,33 +1933,14 @@ describeOneTableDetails(const char *schemaname,
        for (i = 0; i < cols; i++)
                printTableAddHeader(&cont, headers[i], true, 'l');
 
-       /* Get view_def if table is a view or materialized view */
-       if ((tableinfo.relkind == RELKIND_VIEW ||
-                tableinfo.relkind == RELKIND_MATVIEW) && verbose)
-       {
-               PGresult   *result;
-
-               printfPQExpBuffer(&buf,
-                                                 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
-                                                 oid);
-               result = PSQLexec(buf.data);
-               if (!result)
-                       goto error_return;
-
-               if (PQntuples(result) > 0)
-                       view_def = pg_strdup(PQgetvalue(result, 0, 0));
-
-               PQclear(result);
-       }
-
        /* Generate table cells to be printed */
        for (i = 0; i < numrows; i++)
        {
                /* Column */
-               printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
+               printTableAddCell(&cont, PQgetvalue(res, i, attname_col), false, false);
 
                /* Type */
-               printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
+               printTableAddCell(&cont, PQgetvalue(res, i, atttype_col), false, false);
 
                /* Collation, Nullable, Default */
                if (show_column_details)
@@ -1928,15 +1948,17 @@ describeOneTableDetails(const char *schemaname,
                        char       *identity;
                        char       *default_str = "";
 
-                       printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
+                       printTableAddCell(&cont, PQgetvalue(res, i, attcoll_col), false, false);
 
-                       printTableAddCell(&cont, strcmp(PQgetvalue(res, i, 3), "t") == 0 ? "not null" : "", false, false);
+                       printTableAddCell(&cont,
+                                                         strcmp(PQgetvalue(res, i, attnotnull_col), "t") == 0 ? "not null" : "",
+                                                         false, false);
 
-                       identity = PQgetvalue(res, i, 6);
+                       identity = PQgetvalue(res, i, attidentity_col);
 
                        if (!identity[0])
                                /* (note: above we cut off the 'default' string at 128) */
-                               default_str = PQgetvalue(res, i, 2);
+                               default_str = PQgetvalue(res, i, attrdef_col);
                        else if (identity[0] == ATTRIBUTE_IDENTITY_ALWAYS)
                                default_str = "generated always as identity";
                        else if (identity[0] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
@@ -1945,20 +1967,20 @@ describeOneTableDetails(const char *schemaname,
                        printTableAddCell(&cont, default_str, false, false);
                }
 
-               /* Expression for index column */
-               if (tableinfo.relkind == RELKIND_INDEX ||
-                       tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
-                       printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
+               /* Info for index columns */
+               if (isindexkey_col >= 0)
+                       printTableAddCell(&cont, PQgetvalue(res, i, isindexkey_col), true, false);
+               if (indexdef_col >= 0)
+                       printTableAddCell(&cont, PQgetvalue(res, i, indexdef_col), false, false);
 
-               /* FDW options for foreign table column, only for 9.2 or later */
-               if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
-                       printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
+               /* FDW options for foreign table columns */
+               if (fdwopts_col >= 0)
+                       printTableAddCell(&cont, PQgetvalue(res, i, fdwopts_col), false, false);
 
                /* Storage and Description */
-               if (verbose)
+               if (attstorage_col >= 0)
                {
-                       int                     firstvcol = 9;
-                       char       *storage = PQgetvalue(res, i, firstvcol);
+                       char       *storage = PQgetvalue(res, i, attstorage_col);
 
                        /* these strings are literal in our syntax, so not translated. */
                        printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
@@ -1967,29 +1989,17 @@ describeOneTableDetails(const char *schemaname,
                                                                                (storage[0] == 'e' ? "external" :
                                                                                 "???")))),
                                                          false, false);
+               }
 
-                       /* Statistics target, if the relkind supports this feature */
-                       if (tableinfo.relkind == RELKIND_RELATION ||
-                               tableinfo.relkind == RELKIND_INDEX ||
-                               tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-                               tableinfo.relkind == RELKIND_MATVIEW ||
-                               tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-                               tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-                       {
-                               printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
-                                                                 false, false);
-                       }
+               /* Statistics target, if the relkind supports this feature */
+               if (attstattarget_col >= 0)
+                       printTableAddCell(&cont, PQgetvalue(res, i, attstattarget_col),
+                                                         false, false);
 
-                       /* Column comments, if the relkind supports this feature. */
-                       if (tableinfo.relkind == RELKIND_RELATION ||
-                               tableinfo.relkind == RELKIND_VIEW ||
-                               tableinfo.relkind == RELKIND_MATVIEW ||
-                               tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-                               tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-                               tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-                               printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2),
-                                                                 false, false);
-               }
+               /* Column comments, if the relkind supports this feature */
+               if (attdescr_col >= 0)
+                       printTableAddCell(&cont, PQgetvalue(res, i, attdescr_col),
+                                                         false, false);
        }
 
        /* Make footers */
@@ -2654,6 +2664,25 @@ describeOneTableDetails(const char *schemaname,
                }
        }
 
+       /* Get view_def if table is a view or materialized view */
+       if ((tableinfo.relkind == RELKIND_VIEW ||
+                tableinfo.relkind == RELKIND_MATVIEW) && verbose)
+       {
+               PGresult   *result;
+
+               printfPQExpBuffer(&buf,
+                                                 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
+                                                 oid);
+               result = PSQLexec(buf.data);
+               if (!result)
+                       goto error_return;
+
+               if (PQntuples(result) > 0)
+                       view_def = pg_strdup(PQgetvalue(result, 0, 0));
+
+               PQclear(result);
+       }
+
        if (view_def)
        {
                PGresult   *result = NULL;
index df604a326ca4763a9fe4236cec725c5f4ab8c28d..37440f6aec442895234610482a6fb0eb3f67f087 100644 (file)
@@ -111,12 +111,12 @@ ERROR:  cannot alter statistics on non-expression column "a" of index "attmp_idx
 HINT:  Alter statistics on table column instead.
 ALTER INDEX attmp_idx ALTER COLUMN 2 SET STATISTICS 1000;
 \d+ attmp_idx
-                    Index "public.attmp_idx"
- Column |       Type       | Definition | Storage | Stats target 
---------+------------------+------------+---------+--------------
- a      | integer          | a          | plain   | 
- expr   | double precision | (d + e)    | plain   | 1000
- b      | cstring          | b          | plain   | 
+                        Index "public.attmp_idx"
+ Column |       Type       | Key? | Definition | Storage | Stats target 
+--------+------------------+------+------------+---------+--------------
+ a      | integer          | yes  | a          | plain   | 
+ expr   | double precision | yes  | (d + e)    | plain   | 1000
+ b      | cstring          | yes  | b          | plain   | 
 btree, for table "public.attmp"
 
 ALTER INDEX attmp_idx ALTER COLUMN 3 SET STATISTICS 1000;
index fc81088d4b83e545bf2ec17fe5d96d800a802438..be25101db24cbbc673aec6230e436dcf44eca5d8 100644 (file)
@@ -2362,10 +2362,10 @@ DROP TABLE array_gin_test;
 CREATE INDEX gin_relopts_test ON array_index_op_test USING gin (i)
   WITH (FASTUPDATE=on, GIN_PENDING_LIST_LIMIT=128);
 \d+ gin_relopts_test
-            Index "public.gin_relopts_test"
- Column |  Type   | Definition | Storage | Stats target 
---------+---------+------------+---------+--------------
- i      | integer | i          | plain   | 
+                Index "public.gin_relopts_test"
+ Column |  Type   | Key? | Definition | Storage | Stats target 
+--------+---------+------+------------+---------+--------------
+ i      | integer | yes  | i          | plain   | 
 gin, for table "public.array_index_op_test"
 Options: fastupdate=on, gin_pending_list_limit=128
 
@@ -2582,11 +2582,11 @@ Indexes:
     "cwi_uniq_idx" PRIMARY KEY, btree (a, b)
 
 \d cwi_uniq_idx
-         Index "public.cwi_uniq_idx"
- Column |         Type          | Definition 
---------+-----------------------+------------
- a      | integer               | a
- b      | character varying(10) | b
+            Index "public.cwi_uniq_idx"
+ Column |         Type          | Key? | Definition 
+--------+-----------------------+------+------------
+ a      | integer               | yes  | a
+ b      | character varying(10) | yes  | b
 primary key, btree, for table "public.cwi_test"
 
 CREATE UNIQUE INDEX cwi_uniq2_idx ON cwi_test(b , a);
@@ -2605,11 +2605,11 @@ Indexes:
     "cwi_replaced_pkey" PRIMARY KEY, btree (b, a)
 
 \d cwi_replaced_pkey
-      Index "public.cwi_replaced_pkey"
- Column |         Type          | Definition 
---------+-----------------------+------------
- b      | character varying(10) | b
- a      | integer               | a
+          Index "public.cwi_replaced_pkey"
+ Column |         Type          | Key? | Definition 
+--------+-----------------------+------+------------
+ b      | character varying(10) | yes  | b
+ a      | integer               | yes  | a
 primary key, btree, for table "public.cwi_test"
 
 DROP INDEX cwi_replaced_pkey;  -- Should fail; a constraint depends on it
index e2596391b119f819930ad59fc9250ca1b62b0fd6..45a1c8d0176904e178e63549edbec9a76fa57455 100644 (file)
@@ -20,13 +20,13 @@ WHERE i.indrelid = 'tbl_include_reg'::regclass ORDER BY c.relname;
 (2 rows)
 
 \d tbl_include_reg_idx
-Index "public.tbl_include_reg_idx"
- Column |  Type   | Definition 
---------+---------+------------
- c1     | integer | c1
- c2     | integer | c2
- c3     | integer | c3
- c4     | box     | c4
+  Index "public.tbl_include_reg_idx"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ c1     | integer | yes  | c1
+ c2     | integer | yes  | c2
+ c3     | integer | no   | c3
+ c4     | box     | no   | c4
 btree, for table "public.tbl_include_reg"
 
 -- Unique index and unique constraint
index 24435118bcb2604db186f58e4dd9c14593f05dad..fe3614cd76810cdaec0b93ea2294818eb6c4661b 100644 (file)
@@ -67,17 +67,17 @@ INSERT INTO testschema.test_default_tab VALUES (1);
 CREATE INDEX test_index1 on testschema.test_default_tab (id);
 CREATE INDEX test_index2 on testschema.test_default_tab (id) TABLESPACE regress_tblspace;
 \d testschema.test_index1
-Index "testschema.test_index1"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index1"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 
 \d testschema.test_index2
-Index "testschema.test_index2"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index2"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 Tablespace: "regress_tblspace"
 
@@ -86,17 +86,17 @@ SET default_tablespace TO regress_tblspace;
 -- tablespace should not change if no rewrite
 ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
 \d testschema.test_index1
-Index "testschema.test_index1"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index1"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 
 \d testschema.test_index2
-Index "testschema.test_index2"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index2"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 Tablespace: "regress_tblspace"
 
@@ -109,17 +109,17 @@ SELECT * FROM testschema.test_default_tab;
 -- tablespace should not change even if there is an index rewrite
 ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
 \d testschema.test_index1
-Index "testschema.test_index1"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+    Index "testschema.test_index1"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 btree, for table "testschema.test_default_tab"
 
 \d testschema.test_index2
-Index "testschema.test_index2"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+    Index "testschema.test_index2"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 btree, for table "testschema.test_default_tab"
 Tablespace: "regress_tblspace"
 
@@ -134,34 +134,34 @@ SET default_tablespace TO '';
 -- tablespace should not change if no rewrite
 ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
 \d testschema.test_index1
-Index "testschema.test_index1"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+    Index "testschema.test_index1"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 btree, for table "testschema.test_default_tab"
 
 \d testschema.test_index2
-Index "testschema.test_index2"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+    Index "testschema.test_index2"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 btree, for table "testschema.test_default_tab"
 Tablespace: "regress_tblspace"
 
 -- tablespace should not change even if there is an index rewrite
 ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
 \d testschema.test_index1
-Index "testschema.test_index1"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index1"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 
 \d testschema.test_index2
-Index "testschema.test_index2"
- Column |  Type  | Definition 
---------+--------+------------
- id     | bigint | id
+   Index "testschema.test_index2"
+ Column |  Type  | Key? | Definition 
+--------+--------+------+------------
+ id     | bigint | yes  | id
 btree, for table "testschema.test_default_tab"
 Tablespace: "regress_tblspace"
 
@@ -174,18 +174,18 @@ ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_unique UNIQUE (id);
 SET default_tablespace TO '';
 ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_pkey PRIMARY KEY (id);
 \d testschema.test_tab_unique
-Index "testschema.test_tab_unique"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+  Index "testschema.test_tab_unique"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 unique, btree, for table "testschema.test_tab"
 Tablespace: "regress_tblspace"
 
 \d testschema.test_tab_pkey
-Index "testschema.test_tab_pkey"
- Column |  Type   | Definition 
---------+---------+------------
- id     | integer | id
+   Index "testschema.test_tab_pkey"
+ Column |  Type   | Key? | Definition 
+--------+---------+------+------------
+ id     | integer | yes  | id
 primary key, btree, for table "testschema.test_tab"
 
 SELECT * FROM testschema.test_tab;