diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 7e96a8e1ddb..7ca6226973f 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1645,6 +1645,7 @@ SELECT $1 \parse stmt1 \dE[Sx+] [ pattern ] \di[Sx+] [ pattern ] \dm[Sx+] [ pattern ] + \dN[Sx+] [ pattern ] \ds[Sx+] [ pattern ] \dt[Sx+] [ pattern ] \dv[Sx+] [ pattern ] @@ -1652,15 +1653,16 @@ SELECT $1 \parse stmt1 In this group of commands, the letters E, - i, m, s, - t, and v - stand for foreign table, index, materialized view, + i, m, N, + s, t, and v + stand for foreign table, index, materialized view, no partitions, sequence, table, and view, respectively. You can specify any or all of these letters, in any order, to obtain a listing of objects of these types. For example, \dti lists - tables and indexes. + tables and indexes, and \dNt lists + tables that are not partitions of any other relation. If x is appended to the command name, the results are displayed in expanded mode. If + is diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 4a2976dddf0..bf5f61e5d3e 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1190,6 +1190,7 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) case 'i': case 's': case 'E': + case 'N': success = listTables(&cmd[1], pattern, show_verbose, show_system); break; case 'r': diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 36f24502842..5e31ceba437 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4031,6 +4031,7 @@ describeRoleGrants(const char *pattern, bool showSystem) * tabtypes is an array of characters, specifying what info is desired: * t - tables * i - indexes + * N - no partitions (only applies to tables and indexes) * v - views * m - materialized views * s - sequences @@ -4046,6 +4047,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys bool showMatViews = strchr(tabtypes, 'm') != NULL; bool showSeq = strchr(tabtypes, 's') != NULL; bool showForeign = strchr(tabtypes, 'E') != NULL; + bool showNoPartitions = strchr(tabtypes, 'N') != NULL; int ntypes; PQExpBufferData buf; @@ -4054,12 +4056,26 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys int cols_so_far; bool translate_columns[] = {false, false, true, false, false, false, false, false, false}; + /* + * Note: Declarative table partitioning is only supported as of Pg 10.0. + */ + if (showNoPartitions && pset.sversion < 100000) + { + showNoPartitions = false; + } + /* Count the number of explicitly-requested relation types */ ntypes = showTables + showIndexes + showViews + showMatViews + showSeq + showForeign; - /* If none, we default to \dtvmsE (but see also command.c) */ + if (ntypes == 0) - showTables = showViews = showMatViews = showSeq = showForeign = true; + { + if (showNoPartitions) + showTables = showIndexes = true; + else + /* If none, we default to \dtvmsE (but see also command.c) */ + showTables = showViews = showMatViews = showSeq = showForeign = true; + } initPQExpBuffer(&buf); @@ -4185,6 +4201,9 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys " AND n.nspname !~ '^pg_toast'\n" " AND n.nspname <> 'information_schema'\n"); + if (showNoPartitions) + appendPQExpBufferStr(&buf, " AND NOT c.relispartition\n"); + if (!validateSQLNamePattern(&buf, pattern, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)", @@ -4258,8 +4277,11 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys else { myopt.title = + (ntypes != 1 && showNoPartitions) ? _("List of relations (no partitions)") : (ntypes != 1) ? _("List of relations") : + (showTables && showNoPartitions) ? _("List of tables (no partitions)") : (showTables) ? _("List of tables") : + (showIndexes && showNoPartitions) ? _("List of indexes (no partitions)") : (showIndexes) ? _("List of indexes") : (showViews) ? _("List of views") : (showMatViews) ? _("List of materialized views") : diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 6ae1a9940de..24774d949ec 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -251,6 +251,7 @@ slashUsage(unsigned short int pager) HELP0(" \\dL[Sx+] [PATTERN] list procedural languages\n"); HELP0(" \\dm[Sx+] [PATTERN] list materialized views\n"); HELP0(" \\dn[Sx+] [PATTERN] list schemas\n"); + HELP0(" \\dN[Sx+] [PATTERN] list tables and indexes (no partitions)\n"); HELP0(" \\do[Sx+] [OPPTRN [TYPEPTRN [TYPEPTRN]]]\n" " list operators\n"); HELP0(" \\dO[Sx+] [PATTERN] list collations\n"); diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 0b7b3aead7c..f2018762d52 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -693,6 +693,17 @@ static const SchemaQuery Query_for_list_of_tables = { .result = "c.relname", }; +/* All tables EXCEPT those marked as relispartition = true */ +static const SchemaQuery Query_for_list_of_not_relispartition_tables = { + .catname = "pg_catalog.pg_class c", + .selcondition = "c.relispartition = false AND " + "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_PARTITIONED_TABLE) ")", + .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", + .namespace = "c.relnamespace", + .result = "c.relname", +}; + static const SchemaQuery Query_for_list_of_partitioned_tables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")", @@ -797,6 +808,17 @@ static const SchemaQuery Query_for_list_of_indexes = { .result = "c.relname", }; +/* All indexes EXCEPT those marked as relispartition = true */ +static const SchemaQuery Query_for_list_of_not_relispartition_indexes = { + .catname = "pg_catalog.pg_class c", + .selcondition = "c.relispartition = false AND " + "c.relkind IN (" CppAsString2(RELKIND_INDEX) ", " + CppAsString2(RELKIND_PARTITIONED_INDEX) ")", + .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", + .namespace = "c.relnamespace", + .result = "c.relname", +}; + static const SchemaQuery Query_for_list_of_partitioned_indexes = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind = " CppAsString2(RELKIND_PARTITIONED_INDEX), @@ -814,6 +836,19 @@ static const SchemaQuery Query_for_list_of_relations = { .result = "c.relname", }; +/* All relations EXCEPT those marked as relispartition = true */ +static const SchemaQuery Query_for_list_of_not_relispartition_relations = { + .catname = "pg_catalog.pg_class c", + .selcondition = "c.relispartition = false AND " + "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_PARTITIONED_TABLE) ", " + CppAsString2(RELKIND_INDEX) ", " + CppAsString2(RELKIND_PARTITIONED_INDEX) ")", + .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", + .namespace = "c.relnamespace", + .result = "c.relname", +}; + /* partitioned relations */ static const SchemaQuery Query_for_list_of_partitioned_relations = { .catname = "pg_catalog.pg_class c", @@ -1916,7 +1951,7 @@ psql_completion(const char *text, int start, int end) "\\db", "\\dc", "\\dconfig", "\\dC", "\\dd", "\\ddp", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df", "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", - "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", + "\\dm", "\\dn", "\\dN", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", "\\drds", "\\drg", "\\dRs", "\\dRp", "\\ds", "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", "\\echo", "\\edit", "\\ef", "\\elif", "\\else", "\\encoding", @@ -5376,6 +5411,8 @@ match_previous_words(int pattern_id, else if (TailMatchesCS("\\dF*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_ts_configurations); + else if (TailMatchesCS("\\diN*") || TailMatchesCS("\\dNi*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_not_relispartition_indexes); else if (TailMatchesCS("\\di*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes); else if (TailMatchesCS("\\dL*")) @@ -5399,6 +5436,8 @@ match_previous_words(int pattern_id, COMPLETE_WITH_VERSIONED_QUERY(Query_for_list_of_subscriptions); else if (TailMatchesCS("\\ds*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences); + else if (TailMatchesCS("\\dtN*") || TailMatchesCS("\\dNt*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_not_relispartition_tables); else if (TailMatchesCS("\\dt*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables); else if (TailMatchesCS("\\dT*")) @@ -5421,6 +5460,8 @@ match_previous_words(int pattern_id, COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers); /* must be at end of \d alternatives: */ + else if (TailMatchesCS("\\dN*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_not_relispartition_relations); else if (TailMatchesCS("\\d*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations); diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index c8f3932edf0..ce4dbb0bec8 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -5052,6 +5052,47 @@ create index testpart_orange_index on testpart_orange(logdate); testpart | testpart_apple_index | regress_partitioning_role | | testpart_apple (1 row) +-- only non-partition relations should be displayed +\dN + List of relations (no partitions) + Schema | Name | Type | Owner | Table +----------+------------------------+-------------------+---------------------------+------------------ + testpart | testpart_apple | partitioned table | regress_partitioning_role | + testpart | testpart_apple_index | partitioned index | regress_partitioning_role | testpart_apple + testpart | testpart_orange | partitioned table | regress_partitioning_role | + testpart | testpart_orange_index | partitioned index | regress_partitioning_role | testpart_orange + testpart | testtable_apple | table | regress_partitioning_role | + testpart | testtable_apple_index | index | regress_partitioning_role | testtable_apple + testpart | testtable_orange | table | regress_partitioning_role | + testpart | testtable_orange_index | index | regress_partitioning_role | testtable_orange +(8 rows) + +\dN test*apple* + List of relations (no partitions) + Schema | Name | Type | Owner | Table +----------+-----------------------+-------------------+---------------------------+----------------- + testpart | testpart_apple | partitioned table | regress_partitioning_role | + testpart | testpart_apple_index | partitioned index | regress_partitioning_role | testpart_apple + testpart | testtable_apple | table | regress_partitioning_role | + testpart | testtable_apple_index | index | regress_partitioning_role | testtable_apple +(4 rows) + +\dNt test*apple* + List of tables (no partitions) + Schema | Name | Type | Owner +----------+-----------------+-------------------+--------------------------- + testpart | testpart_apple | partitioned table | regress_partitioning_role + testpart | testtable_apple | table | regress_partitioning_role +(2 rows) + +\dNi test*apple* + List of indexes (no partitions) + Schema | Name | Type | Owner | Table +----------+-----------------------+-------------------+---------------------------+----------------- + testpart | testpart_apple_index | partitioned index | regress_partitioning_role | testpart_apple + testpart | testtable_apple_index | index | regress_partitioning_role | testtable_apple +(2 rows) + drop table testtable_apple; drop table testtable_orange; drop table testpart_apple; @@ -5073,6 +5114,7 @@ create table child_30_35 partition of child_30_40 create table child_35_40 partition of child_30_40 for values from (35) to (40); insert into parent_tab values (generate_series(30,39)); +-- only partition related object should be displayed \dPt List of partitioned tables Schema | Name | Owner @@ -5141,6 +5183,45 @@ insert into parent_tab values (generate_series(30,39)); testpart | child_30_40_id_idx | regress_partitioning_role | partitioned index | parent_index | child_30_40 (4 rows) +-- only non-partition relations should be displayed +\dNt + List of tables (no partitions) + Schema | Name | Type | Owner +----------+------------+-------------------+--------------------------- + testpart | parent_tab | partitioned table | regress_partitioning_role +(1 row) + +\dNi + List of indexes (no partitions) + Schema | Name | Type | Owner | Table +----------+--------------+-------------------+---------------------------+------------ + testpart | parent_index | partitioned index | regress_partitioning_role | parent_tab +(1 row) + +\dNit + List of relations (no partitions) + Schema | Name | Type | Owner | Table +----------+--------------+-------------------+---------------------------+------------ + testpart | parent_index | partitioned index | regress_partitioning_role | parent_tab + testpart | parent_tab | partitioned table | regress_partitioning_role | +(2 rows) + +\dN + List of relations (no partitions) + Schema | Name | Type | Owner | Table +----------+--------------+-------------------+---------------------------+------------ + testpart | parent_index | partitioned index | regress_partitioning_role | parent_tab + testpart | parent_tab | partitioned table | regress_partitioning_role | +(2 rows) + +\dN testpart.* + List of relations (no partitions) + Schema | Name | Type | Owner | Table +----------+--------------+-------------------+---------------------------+------------ + testpart | parent_index | partitioned index | regress_partitioning_role | parent_tab + testpart | parent_tab | partitioned table | regress_partitioning_role | +(2 rows) + drop table parent_tab cascade; drop schema testpart; set search_path to default; diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index dcdbd4fc020..7ec82d67602 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1276,6 +1276,12 @@ create index testpart_orange_index on testpart_orange(logdate); \dPt test*apple* \dPi test*apple* +-- only non-partition relations should be displayed +\dN +\dN test*apple* +\dNt test*apple* +\dNi test*apple* + drop table testtable_apple; drop table testtable_orange; drop table testpart_apple; @@ -1299,6 +1305,7 @@ create table child_35_40 partition of child_30_40 for values from (35) to (40); insert into parent_tab values (generate_series(30,39)); +-- only partition related object should be displayed \dPt \dPi @@ -1310,6 +1317,14 @@ insert into parent_tab values (generate_series(30,39)); \dPn \dPn testpart.* +-- only non-partition relations should be displayed +\dNt +\dNi +\dNit +\dN + +\dN testpart.* + drop table parent_tab cascade; drop schema testpart;