Improve psql's \d command to show whether index columns are key columns.

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
This commit is contained in:
Tom Lane 2018-07-19 14:53:41 -04:00
parent 028e3da294
commit 90371a24a5
5 changed files with 225 additions and 196 deletions

View 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);
}
/* 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);
}
/* 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 (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;

View 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;

View 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

View 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

View 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;