aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2017-09-25 11:59:46 -0400
committerPeter Eisentraut <peter_e@gmx.net>2017-09-29 13:34:18 -0400
commit5cc5987cedd8c60c738135abcb25df5247db7d1e (patch)
tree6bea46199475e393e6b06346acf3b0185c989aa7
parent46c35116ae1acc8826705ef2a7b5d9110f9d6e84 (diff)
downloadpostgresql-5cc5987cedd8c60c738135abcb25df5247db7d1e.tar.gz
postgresql-5cc5987cedd8c60c738135abcb25df5247db7d1e.zip
psql: Update \d sequence display
For \d sequencename, the psql code just did SELECT * FROM sequencename to get the information to display, but this does not contain much interesting information anymore in PostgreSQL 10, because the metadata has been moved to a separate system catalog. This patch creates a newly designed sequence display that is not merely an extension of the general relation/table display as it was previously. Example: PostgreSQL 9.6: => \d foobar Sequence "public.foobar" Column | Type | Value ---------------+---------+--------------------- sequence_name | name | foobar last_value | bigint | 1 start_value | bigint | 1 increment_by | bigint | 1 max_value | bigint | 9223372036854775807 min_value | bigint | 1 cache_value | bigint | 1 log_cnt | bigint | 0 is_cycled | boolean | f is_called | boolean | f PostgreSQL 10 before this change: => \d foobar Sequence "public.foobar" Column | Type | Value ------------+---------+------- last_value | bigint | 1 log_cnt | bigint | 0 is_called | boolean | f New: => \d foobar Sequence "public.foobar" Type | Start | Minimum | Maximum | Increment | Cycles? | Cache --------+-------+---------+---------------------+-----------+---------+------- bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1 Reviewed-by: Fabien COELHO <coelho@cri.ensmp.fr>
-rw-r--r--src/bin/psql/describe.c189
-rw-r--r--src/test/regress/expected/identity.out7
-rw-r--r--src/test/regress/expected/sequence.out13
-rw-r--r--src/test/regress/sql/identity.sql2
-rw-r--r--src/test/regress/sql/sequence.sql4
5 files changed, 135 insertions, 80 deletions
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 798e71045fd..019aa844f4d 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1380,8 +1380,6 @@ describeOneTableDetails(const char *schemaname,
int i;
char *view_def = NULL;
char *headers[11];
- char **seq_values = NULL;
- char **ptr;
PQExpBufferData title;
PQExpBufferData tmpbuf;
int cols;
@@ -1563,27 +1561,125 @@ describeOneTableDetails(const char *schemaname,
res = NULL;
/*
- * If it's a sequence, fetch its values and store into an array that will
- * be used later.
+ * If it's a sequence, deal with it here separately.
*/
if (tableinfo.relkind == RELKIND_SEQUENCE)
{
- printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
- /* must be separate because fmtId isn't reentrant */
- appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+ PGresult *result = NULL;
+ printQueryOpt myopt = pset.popt;
+ char *footers[2] = {NULL, NULL};
+
+ if (pset.sversion >= 100000)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
+ " seqstart AS \"%s\",\n"
+ " seqmin AS \"%s\",\n"
+ " seqmax AS \"%s\",\n"
+ " seqincrement AS \"%s\",\n"
+ " CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
+ " seqcache AS \"%s\"\n",
+ gettext_noop("Type"),
+ gettext_noop("Start"),
+ gettext_noop("Minimum"),
+ gettext_noop("Maximum"),
+ gettext_noop("Increment"),
+ gettext_noop("yes"),
+ gettext_noop("no"),
+ gettext_noop("Cycles?"),
+ gettext_noop("Cache"));
+ appendPQExpBuffer(&buf,
+ "FROM pg_catalog.pg_sequence\n"
+ "WHERE seqrelid = '%s';",
+ oid);
+ }
+ else
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT pg_catalog.format_type('bigint'::regtype, NULL) AS \"%s\",\n"
+ " start_value AS \"%s\",\n"
+ " min_value AS \"%s\",\n"
+ " max_value AS \"%s\",\n"
+ " increment_by AS \"%s\",\n"
+ " CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
+ " cache_value AS \"%s\"\n",
+ gettext_noop("Type"),
+ gettext_noop("Start"),
+ gettext_noop("Minimum"),
+ gettext_noop("Maximum"),
+ gettext_noop("Increment"),
+ gettext_noop("yes"),
+ gettext_noop("no"),
+ gettext_noop("Cycles?"),
+ gettext_noop("Cache"));
+ appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
+ /* must be separate because fmtId isn't reentrant */
+ appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+ }
res = PSQLexec(buf.data);
if (!res)
goto error_return;
- seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
+ /* Footer information about a sequence */
+
+ /* Get the column that owns this sequence */
+ printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
+ "\n pg_catalog.quote_ident(relname) || '.' ||"
+ "\n pg_catalog.quote_ident(attname),"
+ "\n d.deptype"
+ "\nFROM pg_catalog.pg_class c"
+ "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
+ "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
+ "\nINNER JOIN pg_catalog.pg_attribute a ON ("
+ "\n a.attrelid=c.oid AND"
+ "\n a.attnum=d.refobjsubid)"
+ "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
+ "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
+ "\n AND d.objid='%s'"
+ "\n AND d.deptype IN ('a', 'i')",
+ oid);
+
+ result = PSQLexec(buf.data);
+
+ /*
+ * If we get no rows back, don't show anything (obviously). We should
+ * never get more than one row back, but if we do, just ignore it and
+ * don't print anything.
+ */
+ if (!result)
+ goto error_return;
+ else if (PQntuples(result) == 1)
+ {
+ switch (PQgetvalue(result, 0, 1)[0])
+ {
+ case 'a':
+ footers[0] = psprintf(_("Owned by: %s"),
+ PQgetvalue(result, 0, 0));
+ break;
+ case 'i':
+ footers[0] = psprintf(_("Sequence for identity column: %s"),
+ PQgetvalue(result, 0, 0));
+ break;
+ }
+ }
+ PQclear(result);
+
+ printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
+ schemaname, relationname);
- for (i = 0; i < PQnfields(res); i++)
- seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
- seq_values[i] = NULL;
+ myopt.footers = footers;
+ myopt.topt.default_footer = false;
+ myopt.title = title.data;
+ myopt.translate_header = true;
- PQclear(res);
- res = NULL;
+ printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+ if (footers[0])
+ free(footers[0]);
+
+ retval = true;
+ goto error_return; /* not an error, just return early */
}
/*
@@ -1667,10 +1763,6 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
schemaname, relationname);
break;
- case RELKIND_SEQUENCE:
- printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
- schemaname, relationname);
- break;
case RELKIND_INDEX:
if (tableinfo.relpersistence == 'u')
printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
@@ -1729,9 +1821,6 @@ describeOneTableDetails(const char *schemaname,
show_column_details = true;
}
- if (tableinfo.relkind == RELKIND_SEQUENCE)
- headers[cols++] = gettext_noop("Value");
-
if (tableinfo.relkind == RELKIND_INDEX)
headers[cols++] = gettext_noop("Definition");
@@ -1813,10 +1902,6 @@ describeOneTableDetails(const char *schemaname,
printTableAddCell(&cont, default_str, false, false);
}
- /* Value: for sequences only */
- if (tableinfo.relkind == RELKIND_SEQUENCE)
- printTableAddCell(&cont, seq_values[i], false, false);
-
/* Expression for index column */
if (tableinfo.relkind == RELKIND_INDEX)
printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
@@ -2027,55 +2112,6 @@ describeOneTableDetails(const char *schemaname,
PQclear(result);
}
- else if (tableinfo.relkind == RELKIND_SEQUENCE)
- {
- /* Footer information about a sequence */
- PGresult *result = NULL;
-
- /* Get the column that owns this sequence */
- printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
- "\n pg_catalog.quote_ident(relname) || '.' ||"
- "\n pg_catalog.quote_ident(attname),"
- "\n d.deptype"
- "\nFROM pg_catalog.pg_class c"
- "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
- "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
- "\nINNER JOIN pg_catalog.pg_attribute a ON ("
- "\n a.attrelid=c.oid AND"
- "\n a.attnum=d.refobjsubid)"
- "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
- "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
- "\n AND d.objid='%s'"
- "\n AND d.deptype IN ('a', 'i')",
- oid);
-
- result = PSQLexec(buf.data);
- if (!result)
- goto error_return;
- else if (PQntuples(result) == 1)
- {
- switch (PQgetvalue(result, 0, 1)[0])
- {
- case 'a':
- printfPQExpBuffer(&buf, _("Owned by: %s"),
- PQgetvalue(result, 0, 0));
- printTableAddFooter(&cont, buf.data);
- break;
- case 'i':
- printfPQExpBuffer(&buf, _("Sequence for identity column: %s"),
- PQgetvalue(result, 0, 0));
- printTableAddFooter(&cont, buf.data);
- break;
- }
- }
-
- /*
- * If we get no rows back, don't show anything (obviously). We should
- * never get more than one row back, but if we do, just ignore it and
- * don't print anything.
- */
- PQclear(result);
- }
else if (tableinfo.relkind == RELKIND_RELATION ||
tableinfo.relkind == RELKIND_MATVIEW ||
tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
@@ -2960,13 +2996,6 @@ error_return:
termPQExpBuffer(&title);
termPQExpBuffer(&tmpbuf);
- if (seq_values)
- {
- for (ptr = seq_values; *ptr; ptr++)
- free(*ptr);
- free(seq_values);
- }
-
if (view_def)
free(view_def);
diff --git a/src/test/regress/expected/identity.out b/src/test/regress/expected/identity.out
index 2800ed7caab..5fa585d6cc5 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -32,6 +32,13 @@ SELECT pg_get_serial_sequence('itest1', 'a');
public.itest1_a_seq
(1 row)
+\d itest1_a_seq
+ Sequence "public.itest1_a_seq"
+ Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
+---------+-------+---------+------------+-----------+---------+-------
+ integer | 1 | 1 | 2147483647 | 1 | no | 1
+Sequence for identity column: public.itest1.a
+
CREATE TABLE itest4 (a int, b text);
ALTER TABLE itest4 ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY; -- error, requires NOT NULL
ERROR: column "a" of relation "itest4" must be declared NOT NULL before identity can be added
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index ea05a3382b8..2384b7dd815 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -535,6 +535,19 @@ SELECT * FROM pg_sequence_parameters('sequence_test4'::regclass);
-1 | -9223372036854775808 | -1 | -1 | f | 1 | 20
(1 row)
+\d sequence_test4
+ Sequence "public.sequence_test4"
+ Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
+--------+-------+----------------------+---------+-----------+---------+-------
+ bigint | -1 | -9223372036854775808 | -1 | -1 | no | 1
+
+\d serialtest2_f2_seq
+ Sequence "public.serialtest2_f2_seq"
+ Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
+---------+-------+---------+------------+-----------+---------+-------
+ integer | 1 | 1 | 2147483647 | 1 | no | 1
+Owned by: public.serialtest2.f2
+
-- Test comments
COMMENT ON SEQUENCE asdf IS 'won''t work';
ERROR: relation "asdf" does not exist
diff --git a/src/test/regress/sql/identity.sql b/src/test/regress/sql/identity.sql
index 7886456a569..e1b5a074c96 100644
--- a/src/test/regress/sql/identity.sql
+++ b/src/test/regress/sql/identity.sql
@@ -14,6 +14,8 @@ SELECT sequence_name FROM information_schema.sequences WHERE sequence_name LIKE
SELECT pg_get_serial_sequence('itest1', 'a');
+\d itest1_a_seq
+
CREATE TABLE itest4 (a int, b text);
ALTER TABLE itest4 ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY; -- error, requires NOT NULL
ALTER TABLE itest4 ALTER COLUMN a SET NOT NULL;
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index c50834a5b97..a7b9e633728 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -246,6 +246,10 @@ WHERE sequencename ~ ANY(ARRAY['sequence_test', 'serialtest'])
SELECT * FROM pg_sequence_parameters('sequence_test4'::regclass);
+\d sequence_test4
+\d serialtest2_f2_seq
+
+
-- Test comments
COMMENT ON SEQUENCE asdf IS 'won''t work';
COMMENT ON SEQUENCE sequence_test2 IS 'will work';