On Tue, May 01, 2018 at 12:30:44PM -0400, Robert Haas wrote:
> That's probably going to cause some translation problems.  The form of
> "a" that you need will vary: "a" vs. "an" in English, "un" vs. "una"
> in Spanish, etc.  And it wouldn't be surprising if there are problems
> in some languages even if you make it "This relation is %s".  There's
> a reason why the documentation advises against building up
> translatable strings from constituent parts.  If we go this route,
> it's probably best to separately translate "This relation is a
> table.", "This relation is an index.", etc.

Yeah, I get the feeling that this is not going to be much
consistent-proof either, so while I have not been able to come up with a
better idea, let's not go through this route.

> However, backing up a minute, I don't think "relation \"%s\" is not a
> btree index" is such a terrible message.  These modules are intended
> to be intended by people who Know What They Are Doing.  If we do want
> to change the message, I submit that the only thing that makes it a
> little unclear is that a user might fail to realize that a partitioned
> index is not an index.  But that could be fixed just by adding a
> separate message for that one case (index \"%s\" is partitioned) and
> sticking with the existing message for other cases.

I have been chewing on that, and I come to agree that there is perhaps
little point to complicate the code as long as a failure is properly
reported to the user.  I propose hence the attached, which adds test
cases in the contrib module set for partitioned indexes (amcheck also
lacked tests for partition tables and indexes), and fixes a set of code
paths to be consistent with the presence of this new relkind.

Visibly I have found a bug in git, format-patch reports the following
line in the stats:
 .../pg_visibility/expected/pg_visibility.out    | 13 ++++++++++++-
But the patch contents are actually correct...
--
Michael
From f71b4d1932fd6da3a679f9d755f387f5986c71e8 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Wed, 2 May 2018 10:56:29 +0900
Subject: [PATCH] Fix gaps in modules with handling of partitioned indexes

The following modules lacked handling and/or coverage for partitioned
indexes:
- pgstattuple
- pg_visibility
- pageinspect
- amcheck
For some index-related functions, a partitioned index can be defined of
the same object type as what the function works on but still get a
failure, still the error messages are kept the same to keep the code
simple.

Test cases are added to cover all those additions.
---
 contrib/amcheck/expected/check_btree.out        | 17 ++++++++++++++++-
 contrib/amcheck/sql/check_btree.sql             | 13 ++++++++++++-
 contrib/pageinspect/expected/btree.out          | 12 ++++++++++++
 contrib/pageinspect/expected/page.out           |  6 +++++-
 contrib/pageinspect/rawpage.c                   |  5 +++++
 contrib/pageinspect/sql/btree.sql               | 10 ++++++++++
 contrib/pageinspect/sql/page.sql                |  5 ++++-
 .../pg_visibility/expected/pg_visibility.out    | 13 ++++++++++++-
 contrib/pg_visibility/sql/pg_visibility.sql     |  8 +++++++-
 contrib/pgstattuple/expected/pgstattuple.out    | 13 +++++++++++++
 contrib/pgstattuple/pgstatindex.c               |  1 -
 contrib/pgstattuple/pgstattuple.c               |  3 +++
 contrib/pgstattuple/sql/pgstattuple.sql         |  7 +++++++
 doc/src/sgml/catalogs.sgml                      |  3 ++-
 14 files changed, 108 insertions(+), 8 deletions(-)

diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out
index e864579774..b288565be9 100644
--- a/contrib/amcheck/expected/check_btree.out
+++ b/contrib/amcheck/expected/check_btree.out
@@ -2,7 +2,9 @@ CREATE TABLE bttest_a(id int8);
 CREATE TABLE bttest_b(id int8);
 CREATE TABLE bttest_multi(id int8, data int8);
 CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
--- Stabalize tests
+CREATE TABLE bttest_partitioned (a int) PARTITION BY RANGE (a);
+CREATE INDEX bttest_partitioned_index ON bttest_partitioned (a);
+-- Stabilize tests
 ALTER TABLE bttest_a SET (autovacuum_enabled = false);
 ALTER TABLE bttest_b SET (autovacuum_enabled = false);
 ALTER TABLE bttest_multi SET (autovacuum_enabled = false);
@@ -48,6 +50,18 @@ SELECT bt_index_check('bttest_a');
 ERROR:  "bttest_a" is not an index
 SELECT bt_index_parent_check('bttest_a');
 ERROR:  "bttest_a" is not an index
+-- verify partitioned tables are rejected (error)
+SELECT bt_index_check('bttest_partitioned');
+ERROR:  "bttest_partitioned" is not an index
+SELECT bt_index_parent_check('bttest_partitioned');
+ERROR:  "bttest_partitioned" is not an index
+-- verify partitioned indexes are rejected (error)
+SELECT bt_index_check('bttest_partitioned_index');
+ERROR:  only B-Tree indexes are supported as targets for verification
+DETAIL:  Relation "bttest_partitioned_index" is not a B-Tree index.
+SELECT bt_index_parent_check('bttest_partitioned_index');
+ERROR:  only B-Tree indexes are supported as targets for verification
+DETAIL:  Relation "bttest_partitioned_index" is not a B-Tree index.
 -- verify non-existing indexes are rejected (error)
 SELECT bt_index_check(17);
 ERROR:  could not open relation with OID 17
@@ -145,5 +159,6 @@ DROP TABLE bttest_a;
 DROP TABLE bttest_b;
 DROP TABLE bttest_multi;
 DROP TABLE delete_test_table;
+DROP TABLE bttest_partitioned;
 DROP OWNED BY bttest_role; -- permissions
 DROP ROLE bttest_role;
diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql
index 7b1ab4f148..cad496eda8 100644
--- a/contrib/amcheck/sql/check_btree.sql
+++ b/contrib/amcheck/sql/check_btree.sql
@@ -2,8 +2,10 @@ CREATE TABLE bttest_a(id int8);
 CREATE TABLE bttest_b(id int8);
 CREATE TABLE bttest_multi(id int8, data int8);
 CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
+CREATE TABLE bttest_partitioned (a int) PARTITION BY RANGE (a);
+CREATE INDEX bttest_partitioned_index ON bttest_partitioned (a);
 
--- Stabalize tests
+-- Stabilize tests
 ALTER TABLE bttest_a SET (autovacuum_enabled = false);
 ALTER TABLE bttest_b SET (autovacuum_enabled = false);
 ALTER TABLE bttest_multi SET (autovacuum_enabled = false);
@@ -42,6 +44,14 @@ RESET ROLE;
 SELECT bt_index_check('bttest_a');
 SELECT bt_index_parent_check('bttest_a');
 
+-- verify partitioned tables are rejected (error)
+SELECT bt_index_check('bttest_partitioned');
+SELECT bt_index_parent_check('bttest_partitioned');
+
+-- verify partitioned indexes are rejected (error)
+SELECT bt_index_check('bttest_partitioned_index');
+SELECT bt_index_parent_check('bttest_partitioned_index');
+
 -- verify non-existing indexes are rejected (error)
 SELECT bt_index_check(17);
 SELECT bt_index_parent_check(17);
@@ -93,5 +103,6 @@ DROP TABLE bttest_a;
 DROP TABLE bttest_b;
 DROP TABLE bttest_multi;
 DROP TABLE delete_test_table;
+DROP TABLE bttest_partitioned;
 DROP OWNED BY bttest_role; -- permissions
 DROP ROLE bttest_role;
diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out
index 2aaa4df53b..cb2f04874b 100644
--- a/contrib/pageinspect/expected/btree.out
+++ b/contrib/pageinspect/expected/btree.out
@@ -58,3 +58,15 @@ data       | 01 00 00 00 00 00 00 01
 SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 2));
 ERROR:  block number 2 is out of range for relation "test1_a_idx"
 DROP TABLE test1;
+-- Partitioned indexes, all should fail
+CREATE TABLE test_partitioned (a int) PARTITION BY RANGE (a);
+CREATE INDEX test_partitioned_index ON test_partitioned (a);
+SELECT bt_metap('test_partitioned_index');
+ERROR:  relation "test_partitioned_index" is not a btree index
+SELECT bt_page_stats('test_partitioned_index', 0);
+ERROR:  relation "test_partitioned_index" is not a btree index
+SELECT bt_page_items('test_partitioned_index', 0);
+ERROR:  relation "test_partitioned_index" is not a btree index
+SELECT * FROM bt_page_items(get_raw_page('test_partitioned_index', 0));
+ERROR:  cannot get raw page from partitioned index "test_partitioned_index"
+DROP TABLE test_partitioned;
diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out
index 5edb650085..3fcd9fbe6d 100644
--- a/contrib/pageinspect/expected/page.out
+++ b/contrib/pageinspect/expected/page.out
@@ -83,10 +83,14 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
 (1 row)
 
 DROP TABLE test1;
--- check that using any of these functions with a partitioned table would fail
+-- check that using any of these functions with a partitioned table or index
+-- would fail
 create table test_partitioned (a int) partition by range (a);
+create index test_partitioned_index on test_partitioned (a);
 select get_raw_page('test_partitioned', 0); -- error about partitioned table
 ERROR:  cannot get raw page from partitioned table "test_partitioned"
+select get_raw_page('test_partitioned_index', 0); -- error about partitioned index
+ERROR:  cannot get raw page from partitioned index "test_partitioned_index"
 -- a regular table which is a member of a partition set should work though
 create table test_part1 partition of test_partitioned for values from ( 1 ) to (100);
 select get_raw_page('test_part1', 0); -- get farther and error about empty table
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 72f1d21e1b..d7bf782ccd 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -128,6 +128,11 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get raw page from partitioned table \"%s\"",
 						RelationGetRelationName(rel))));
+	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("cannot get raw page from partitioned index \"%s\"",
+						RelationGetRelationName(rel))));
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql
index 8eac64c7b3..42e90d897d 100644
--- a/contrib/pageinspect/sql/btree.sql
+++ b/contrib/pageinspect/sql/btree.sql
@@ -19,3 +19,13 @@ SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1));
 SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 2));
 
 DROP TABLE test1;
+
+-- Partitioned indexes, all should fail
+CREATE TABLE test_partitioned (a int) PARTITION BY RANGE (a);
+CREATE INDEX test_partitioned_index ON test_partitioned (a);
+SELECT bt_metap('test_partitioned_index');
+SELECT bt_page_stats('test_partitioned_index', 0);
+SELECT bt_page_items('test_partitioned_index', 0);
+SELECT * FROM bt_page_items(get_raw_page('test_partitioned_index', 0));
+
+DROP TABLE test_partitioned;
diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql
index 8f35830e06..8ac9991837 100644
--- a/contrib/pageinspect/sql/page.sql
+++ b/contrib/pageinspect/sql/page.sql
@@ -33,9 +33,12 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
 
 DROP TABLE test1;
 
--- check that using any of these functions with a partitioned table would fail
+-- check that using any of these functions with a partitioned table or index
+-- would fail
 create table test_partitioned (a int) partition by range (a);
+create index test_partitioned_index on test_partitioned (a);
 select get_raw_page('test_partitioned', 0); -- error about partitioned table
+select get_raw_page('test_partitioned_index', 0); -- error about partitioned index
 
 -- a regular table which is a member of a partition set should work though
 create table test_part1 partition of test_partitioned for values from ( 1 ) to (100);
diff --git a/contrib/pg_visibility/expected/pg_visibility.out b/contrib/pg_visibility/expected/pg_visibility.out
index f0dcb897c4..3500e83ebc 100644
--- a/contrib/pg_visibility/expected/pg_visibility.out
+++ b/contrib/pg_visibility/expected/pg_visibility.out
@@ -2,19 +2,30 @@ CREATE EXTENSION pg_visibility;
 --
 -- check that using the module's functions with unsupported relations will fail
 --
--- partitioned tables (the parent ones) don't have visibility maps
+-- partitioned tables and indexes (the parent ones) don't have visibility maps
 create table test_partitioned (a int) partition by list (a);
+create index test_partitioned_index on test_partitioned (a);
 -- these should all fail
 select pg_visibility('test_partitioned', 0);
 ERROR:  "test_partitioned" is not a table, materialized view, or TOAST table
+select pg_visibility('test_partitioned_index', 0);
+ERROR:  "test_partitioned_index" is not a table, materialized view, or TOAST table
 select pg_visibility_map('test_partitioned');
 ERROR:  "test_partitioned" is not a table, materialized view, or TOAST table
+select pg_visibility_map('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table, materialized view, or TOAST table
 select pg_visibility_map_summary('test_partitioned');
 ERROR:  "test_partitioned" is not a table, materialized view, or TOAST table
+select pg_visibility_map_summary('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table, materialized view, or TOAST table
 select pg_check_frozen('test_partitioned');
 ERROR:  "test_partitioned" is not a table, materialized view, or TOAST table
+select pg_check_frozen('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table, materialized view, or TOAST table
 select pg_truncate_visibility_map('test_partitioned');
 ERROR:  "test_partitioned" is not a table, materialized view, or TOAST table
+select pg_truncate_visibility_map('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table, materialized view, or TOAST table
 create table test_partition partition of test_partitioned for values in (1);
 create index test_index on test_partition (a);
 -- indexes do not, so these all fail
diff --git a/contrib/pg_visibility/sql/pg_visibility.sql b/contrib/pg_visibility/sql/pg_visibility.sql
index c2a7f1d9e4..648ee86d05 100644
--- a/contrib/pg_visibility/sql/pg_visibility.sql
+++ b/contrib/pg_visibility/sql/pg_visibility.sql
@@ -4,14 +4,20 @@ CREATE EXTENSION pg_visibility;
 -- check that using the module's functions with unsupported relations will fail
 --
 
--- partitioned tables (the parent ones) don't have visibility maps
+-- partitioned tables and indexes (the parent ones) don't have visibility maps
 create table test_partitioned (a int) partition by list (a);
+create index test_partitioned_index on test_partitioned (a);
 -- these should all fail
 select pg_visibility('test_partitioned', 0);
+select pg_visibility('test_partitioned_index', 0);
 select pg_visibility_map('test_partitioned');
+select pg_visibility_map('test_partitioned_index');
 select pg_visibility_map_summary('test_partitioned');
+select pg_visibility_map_summary('test_partitioned_index');
 select pg_check_frozen('test_partitioned');
+select pg_check_frozen('test_partitioned_index');
 select pg_truncate_visibility_map('test_partitioned');
+select pg_truncate_visibility_map('test_partitioned_index');
 
 create table test_partition partition of test_partitioned for values in (1);
 create index test_index on test_partition (a);
diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out
index a7087f6d45..4b126d3be8 100644
--- a/contrib/pgstattuple/expected/pgstattuple.out
+++ b/contrib/pgstattuple/expected/pgstattuple.out
@@ -152,19 +152,32 @@ select pgstatginindex('test_hashidx');
 ERROR:  relation "test_hashidx" is not a GIN index
 -- check that using any of these functions with unsupported relations will fail
 create table test_partitioned (a int) partition by range (a);
+create index test_partitioned_index on test_partitioned(a);
 -- these should all fail
 select pgstattuple('test_partitioned');
 ERROR:  "test_partitioned" (partitioned table) is not supported
+select pgstattuple('test_partitioned_index');
+ERROR:  "test_partitioned_index" (partitioned index) is not supported
 select pgstattuple_approx('test_partitioned');
 ERROR:  "test_partitioned" is not a table or materialized view
+select pgstattuple_approx('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table or materialized view
 select pg_relpages('test_partitioned');
 ERROR:  "test_partitioned" is not a table, index, materialized view, sequence, or TOAST table
+select pg_relpages('test_partitioned_index');
+ERROR:  "test_partitioned_index" is not a table, index, materialized view, sequence, or TOAST table
 select pgstatindex('test_partitioned');
 ERROR:  relation "test_partitioned" is not a btree index
+select pgstatindex('test_partitioned_index');
+ERROR:  relation "test_partitioned_index" is not a btree index
 select pgstatginindex('test_partitioned');
 ERROR:  relation "test_partitioned" is not a GIN index
+select pgstatginindex('test_partitioned_index');
+ERROR:  relation "test_partitioned_index" is not a GIN index
 select pgstathashindex('test_partitioned');
 ERROR:  "test_partitioned" is not an index
+select pgstathashindex('test_partitioned_index');
+ERROR:  relation "test_partitioned_index" is not a HASH index
 create view test_view as select 1;
 -- these should all fail
 select pgstattuple('test_view');
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 75317b96a2..3d50262f83 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -604,7 +604,6 @@ pgstathashindex(PG_FUNCTION_ARGS)
 				 errmsg("relation \"%s\" is not a HASH index",
 						RelationGetRelationName(rel))));
 
-
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
 	 * likely to get wrong data since we have no visibility into the owning
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index b599b6ca21..6d67bd8271 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -296,6 +296,9 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 		case RELKIND_PARTITIONED_TABLE:
 			err = "partitioned table";
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+			err = "partitioned index";
+			break;
 		default:
 			err = "unknown";
 			break;
diff --git a/contrib/pgstattuple/sql/pgstattuple.sql b/contrib/pgstattuple/sql/pgstattuple.sql
index a8e341e351..1459672cab 100644
--- a/contrib/pgstattuple/sql/pgstattuple.sql
+++ b/contrib/pgstattuple/sql/pgstattuple.sql
@@ -64,13 +64,20 @@ select pgstatginindex('test_hashidx');
 
 -- check that using any of these functions with unsupported relations will fail
 create table test_partitioned (a int) partition by range (a);
+create index test_partitioned_index on test_partitioned(a);
 -- these should all fail
 select pgstattuple('test_partitioned');
+select pgstattuple('test_partitioned_index');
 select pgstattuple_approx('test_partitioned');
+select pgstattuple_approx('test_partitioned_index');
 select pg_relpages('test_partitioned');
+select pg_relpages('test_partitioned_index');
 select pgstatindex('test_partitioned');
+select pgstatindex('test_partitioned_index');
 select pgstatginindex('test_partitioned');
+select pgstatginindex('test_partitioned_index');
 select pgstathashindex('test_partitioned');
+select pgstathashindex('test_partitioned_index');
 
 create view test_view as select 1;
 -- these should all fail
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 26984b6cba..16181db926 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1840,7 +1840,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        <literal>m</literal> = materialized view,
        <literal>c</literal> = composite type,
        <literal>f</literal> = foreign table,
-       <literal>p</literal> = partitioned table
+       <literal>p</literal> = partitioned table,
+       <literal>I</literal> = partitioned index
       </entry>
      </row>
 
-- 
2.17.0

Attachment: signature.asc
Description: PGP signature

Reply via email to