Skip to content

Commit 2ed532e

Browse files
committed
Improve error messages about mismatching relkind
Most error messages about a relkind that was not supported or appropriate for the command was of the pattern "relation \"%s\" is not a table, foreign table, or materialized view" This style can become verbose and tedious to maintain. Moreover, it's not very helpful: If I'm trying to create a comment on a TOAST table, which is not supported, then the information that I could have created a comment on a materialized view is pointless. Instead, write the primary error message shorter and saying more directly that what was attempted is not possible. Then, in the detail message, explain that the operation is not supported for the relkind the object was. To simplify that, add a new function errdetail_relkind_not_supported() that does this. In passing, make use of RELKIND_HAS_STORAGE() where appropriate, instead of listing out the relkinds individually. Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Alvaro Herrera <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
1 parent b9734c1 commit 2ed532e

32 files changed

+512
-378
lines changed

contrib/amcheck/expected/check_heap.out

+10-5
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ CREATE TABLE test_partitioned (a int, b text default repeat('x', 5000))
139139
SELECT * FROM verify_heapam('test_partitioned',
140140
startblock := NULL,
141141
endblock := NULL);
142-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
142+
ERROR: cannot check relation "test_partitioned"
143+
DETAIL: This operation is not supported for partitioned tables.
143144
-- Check that valid options are not rejected nor corruption reported
144145
-- for an empty partition table (the child one)
145146
CREATE TABLE test_partition partition OF test_partitioned FOR VALUES IN (1);
@@ -165,27 +166,31 @@ CREATE INDEX test_index ON test_partition (a);
165166
SELECT * FROM verify_heapam('test_index',
166167
startblock := NULL,
167168
endblock := NULL);
168-
ERROR: "test_index" is not a table, materialized view, or TOAST table
169+
ERROR: cannot check relation "test_index"
170+
DETAIL: This operation is not supported for indexes.
169171
-- Check that views are rejected
170172
CREATE VIEW test_view AS SELECT 1;
171173
SELECT * FROM verify_heapam('test_view',
172174
startblock := NULL,
173175
endblock := NULL);
174-
ERROR: "test_view" is not a table, materialized view, or TOAST table
176+
ERROR: cannot check relation "test_view"
177+
DETAIL: This operation is not supported for views.
175178
-- Check that sequences are rejected
176179
CREATE SEQUENCE test_sequence;
177180
SELECT * FROM verify_heapam('test_sequence',
178181
startblock := NULL,
179182
endblock := NULL);
180-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
183+
ERROR: cannot check relation "test_sequence"
184+
DETAIL: This operation is not supported for sequences.
181185
-- Check that foreign tables are rejected
182186
CREATE FOREIGN DATA WRAPPER dummy;
183187
CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
184188
CREATE FOREIGN TABLE test_foreign_table () SERVER dummy_server;
185189
SELECT * FROM verify_heapam('test_foreign_table',
186190
startblock := NULL,
187191
endblock := NULL);
188-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
192+
ERROR: cannot check relation "test_foreign_table"
193+
DETAIL: This operation is not supported for foreign tables.
189194
-- cleanup
190195
DROP TABLE heaptest;
191196
DROP TABLE test_partition;

contrib/amcheck/verify_heapam.c

+17-21
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ typedef struct HeapCheckContext
147147
} HeapCheckContext;
148148

149149
/* Internal implementation */
150-
static void sanity_check_relation(Relation rel);
151150
static void check_tuple(HeapCheckContext *ctx);
152151
static void check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
153152
ToastedAttribute *ta, int32 *expected_chunk_seq,
@@ -300,7 +299,23 @@ verify_heapam(PG_FUNCTION_ARGS)
300299

301300
/* Open relation, check relkind and access method */
302301
ctx.rel = relation_open(relid, AccessShareLock);
303-
sanity_check_relation(ctx.rel);
302+
303+
/*
304+
* Check that a relation's relkind and access method are both supported.
305+
*/
306+
if (ctx.rel->rd_rel->relkind != RELKIND_RELATION &&
307+
ctx.rel->rd_rel->relkind != RELKIND_MATVIEW &&
308+
ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE)
309+
ereport(ERROR,
310+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
311+
errmsg("cannot check relation \"%s\"",
312+
RelationGetRelationName(ctx.rel)),
313+
errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
314+
315+
if (ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
316+
ereport(ERROR,
317+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
318+
errmsg("only heap AM is supported")));
304319

305320
/* Early exit if the relation is empty */
306321
nblocks = RelationGetNumberOfBlocks(ctx.rel);
@@ -523,25 +538,6 @@ verify_heapam(PG_FUNCTION_ARGS)
523538
PG_RETURN_NULL();
524539
}
525540

526-
/*
527-
* Check that a relation's relkind and access method are both supported.
528-
*/
529-
static void
530-
sanity_check_relation(Relation rel)
531-
{
532-
if (rel->rd_rel->relkind != RELKIND_RELATION &&
533-
rel->rd_rel->relkind != RELKIND_MATVIEW &&
534-
rel->rd_rel->relkind != RELKIND_TOASTVALUE)
535-
ereport(ERROR,
536-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
537-
errmsg("\"%s\" is not a table, materialized view, or TOAST table",
538-
RelationGetRelationName(rel))));
539-
if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
540-
ereport(ERROR,
541-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
542-
errmsg("only heap AM is supported")));
543-
}
544-
545541
/*
546542
* Shared internal implementation for report_corruption and
547543
* report_toast_corruption.

contrib/pageinspect/expected/page.out

+4-2
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ DROP TABLE test1;
180180
create table test_partitioned (a int) partition by range (a);
181181
create index test_partitioned_index on test_partitioned (a);
182182
select get_raw_page('test_partitioned', 0); -- error about partitioned table
183-
ERROR: cannot get raw page from partitioned table "test_partitioned"
183+
ERROR: cannot get raw page from relation "test_partitioned"
184+
DETAIL: This operation is not supported for partitioned tables.
184185
select get_raw_page('test_partitioned_index', 0); -- error about partitioned index
185-
ERROR: cannot get raw page from partitioned index "test_partitioned_index"
186+
ERROR: cannot get raw page from relation "test_partitioned_index"
187+
DETAIL: This operation is not supported for partitioned indexes.
186188
-- a regular table which is a member of a partition set should work though
187189
create table test_part1 partition of test_partitioned for values from ( 1 ) to (100);
188190
select get_raw_page('test_part1', 0); -- get farther and error about empty table

contrib/pageinspect/rawpage.c

+4-24
Original file line numberDiff line numberDiff line change
@@ -155,32 +155,12 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
155155
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
156156
rel = relation_openrv(relrv, AccessShareLock);
157157

158-
/* Check that this relation has storage */
159-
if (rel->rd_rel->relkind == RELKIND_VIEW)
158+
if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
160159
ereport(ERROR,
161160
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
162-
errmsg("cannot get raw page from view \"%s\"",
163-
RelationGetRelationName(rel))));
164-
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
165-
ereport(ERROR,
166-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
167-
errmsg("cannot get raw page from composite type \"%s\"",
168-
RelationGetRelationName(rel))));
169-
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
170-
ereport(ERROR,
171-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
172-
errmsg("cannot get raw page from foreign table \"%s\"",
173-
RelationGetRelationName(rel))));
174-
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
175-
ereport(ERROR,
176-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
177-
errmsg("cannot get raw page from partitioned table \"%s\"",
178-
RelationGetRelationName(rel))));
179-
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
180-
ereport(ERROR,
181-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
182-
errmsg("cannot get raw page from partitioned index \"%s\"",
183-
RelationGetRelationName(rel))));
161+
errmsg("cannot get raw page from relation \"%s\"",
162+
RelationGetRelationName(rel)),
163+
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
184164

185165
/*
186166
* Reject attempts to read non-local temporary relations; we would be

contrib/pg_surgery/expected/heap_surgery.out

+4-2
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,11 @@ rollback;
170170
-- check that it fails on an unsupported relkind
171171
create view vw as select 1;
172172
select heap_force_kill('vw'::regclass, ARRAY['(0, 1)']::tid[]);
173-
ERROR: "vw" is not a table, materialized view, or TOAST table
173+
ERROR: cannot operate on relation "vw"
174+
DETAIL: This operation is not supported for views.
174175
select heap_force_freeze('vw'::regclass, ARRAY['(0, 1)']::tid[]);
175-
ERROR: "vw" is not a table, materialized view, or TOAST table
176+
ERROR: cannot operate on relation "vw"
177+
DETAIL: This operation is not supported for views.
176178
-- cleanup.
177179
drop view vw;
178180
drop extension pg_surgery;

contrib/pg_surgery/heap_surgery.c

+22-32
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ static int32 tidcmp(const void *a, const void *b);
3737
static Datum heap_force_common(FunctionCallInfo fcinfo,
3838
HeapTupleForceOption heap_force_opt);
3939
static void sanity_check_tid_array(ArrayType *ta, int *ntids);
40-
static void sanity_check_relation(Relation rel);
4140
static BlockNumber find_tids_one_page(ItemPointer tids, int ntids,
4241
OffsetNumber *next_start_ptr);
4342

@@ -101,8 +100,28 @@ heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)
101100

102101
rel = relation_open(relid, RowExclusiveLock);
103102

104-
/* Check target relation. */
105-
sanity_check_relation(rel);
103+
/*
104+
* Check target relation.
105+
*/
106+
if (rel->rd_rel->relkind != RELKIND_RELATION &&
107+
rel->rd_rel->relkind != RELKIND_MATVIEW &&
108+
rel->rd_rel->relkind != RELKIND_TOASTVALUE)
109+
ereport(ERROR,
110+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
111+
errmsg("cannot operate on relation \"%s\"",
112+
RelationGetRelationName(rel)),
113+
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
114+
115+
if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
116+
ereport(ERROR,
117+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
118+
errmsg("only heap AM is supported")));
119+
120+
/* Must be owner of the table or superuser. */
121+
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
122+
aclcheck_error(ACLCHECK_NOT_OWNER,
123+
get_relkind_objtype(rel->rd_rel->relkind),
124+
RelationGetRelationName(rel));
106125

107126
tids = ((ItemPointer) ARR_DATA_PTR(ta));
108127

@@ -363,35 +382,6 @@ sanity_check_tid_array(ArrayType *ta, int *ntids)
363382
*ntids = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
364383
}
365384

366-
/*-------------------------------------------------------------------------
367-
* sanity_check_relation()
368-
*
369-
* Perform sanity checks on the given relation.
370-
* ------------------------------------------------------------------------
371-
*/
372-
static void
373-
sanity_check_relation(Relation rel)
374-
{
375-
if (rel->rd_rel->relkind != RELKIND_RELATION &&
376-
rel->rd_rel->relkind != RELKIND_MATVIEW &&
377-
rel->rd_rel->relkind != RELKIND_TOASTVALUE)
378-
ereport(ERROR,
379-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
380-
errmsg("\"%s\" is not a table, materialized view, or TOAST table",
381-
RelationGetRelationName(rel))));
382-
383-
if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
384-
ereport(ERROR,
385-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
386-
errmsg("only heap AM is supported")));
387-
388-
/* Must be owner of the table or superuser. */
389-
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
390-
aclcheck_error(ACLCHECK_NOT_OWNER,
391-
get_relkind_objtype(rel->rd_rel->relkind),
392-
RelationGetRelationName(rel));
393-
}
394-
395385
/*-------------------------------------------------------------------------
396386
* find_tids_one_page()
397387
*

contrib/pg_visibility/expected/pg_visibility.out

+50-25
Original file line numberDiff line numberDiff line change
@@ -41,66 +41,91 @@ ROLLBACK;
4141
create table test_partitioned (a int) partition by list (a);
4242
-- these should all fail
4343
select pg_visibility('test_partitioned', 0);
44-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
44+
ERROR: relation "test_partitioned" is of wrong relation kind
45+
DETAIL: This operation is not supported for partitioned tables.
4546
select pg_visibility_map('test_partitioned');
46-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
47+
ERROR: relation "test_partitioned" is of wrong relation kind
48+
DETAIL: This operation is not supported for partitioned tables.
4749
select pg_visibility_map_summary('test_partitioned');
48-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
50+
ERROR: relation "test_partitioned" is of wrong relation kind
51+
DETAIL: This operation is not supported for partitioned tables.
4952
select pg_check_frozen('test_partitioned');
50-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
53+
ERROR: relation "test_partitioned" is of wrong relation kind
54+
DETAIL: This operation is not supported for partitioned tables.
5155
select pg_truncate_visibility_map('test_partitioned');
52-
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
56+
ERROR: relation "test_partitioned" is of wrong relation kind
57+
DETAIL: This operation is not supported for partitioned tables.
5358
create table test_partition partition of test_partitioned for values in (1);
5459
create index test_index on test_partition (a);
5560
-- indexes do not, so these all fail
5661
select pg_visibility('test_index', 0);
57-
ERROR: "test_index" is not a table, materialized view, or TOAST table
62+
ERROR: relation "test_index" is of wrong relation kind
63+
DETAIL: This operation is not supported for indexes.
5864
select pg_visibility_map('test_index');
59-
ERROR: "test_index" is not a table, materialized view, or TOAST table
65+
ERROR: relation "test_index" is of wrong relation kind
66+
DETAIL: This operation is not supported for indexes.
6067
select pg_visibility_map_summary('test_index');
61-
ERROR: "test_index" is not a table, materialized view, or TOAST table
68+
ERROR: relation "test_index" is of wrong relation kind
69+
DETAIL: This operation is not supported for indexes.
6270
select pg_check_frozen('test_index');
63-
ERROR: "test_index" is not a table, materialized view, or TOAST table
71+
ERROR: relation "test_index" is of wrong relation kind
72+
DETAIL: This operation is not supported for indexes.
6473
select pg_truncate_visibility_map('test_index');
65-
ERROR: "test_index" is not a table, materialized view, or TOAST table
74+
ERROR: relation "test_index" is of wrong relation kind
75+
DETAIL: This operation is not supported for indexes.
6676
create view test_view as select 1;
6777
-- views do not have VMs, so these all fail
6878
select pg_visibility('test_view', 0);
69-
ERROR: "test_view" is not a table, materialized view, or TOAST table
79+
ERROR: relation "test_view" is of wrong relation kind
80+
DETAIL: This operation is not supported for views.
7081
select pg_visibility_map('test_view');
71-
ERROR: "test_view" is not a table, materialized view, or TOAST table
82+
ERROR: relation "test_view" is of wrong relation kind
83+
DETAIL: This operation is not supported for views.
7284
select pg_visibility_map_summary('test_view');
73-
ERROR: "test_view" is not a table, materialized view, or TOAST table
85+
ERROR: relation "test_view" is of wrong relation kind
86+
DETAIL: This operation is not supported for views.
7487
select pg_check_frozen('test_view');
75-
ERROR: "test_view" is not a table, materialized view, or TOAST table
88+
ERROR: relation "test_view" is of wrong relation kind
89+
DETAIL: This operation is not supported for views.
7690
select pg_truncate_visibility_map('test_view');
77-
ERROR: "test_view" is not a table, materialized view, or TOAST table
91+
ERROR: relation "test_view" is of wrong relation kind
92+
DETAIL: This operation is not supported for views.
7893
create sequence test_sequence;
7994
-- sequences do not have VMs, so these all fail
8095
select pg_visibility('test_sequence', 0);
81-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
96+
ERROR: relation "test_sequence" is of wrong relation kind
97+
DETAIL: This operation is not supported for sequences.
8298
select pg_visibility_map('test_sequence');
83-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
99+
ERROR: relation "test_sequence" is of wrong relation kind
100+
DETAIL: This operation is not supported for sequences.
84101
select pg_visibility_map_summary('test_sequence');
85-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
102+
ERROR: relation "test_sequence" is of wrong relation kind
103+
DETAIL: This operation is not supported for sequences.
86104
select pg_check_frozen('test_sequence');
87-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
105+
ERROR: relation "test_sequence" is of wrong relation kind
106+
DETAIL: This operation is not supported for sequences.
88107
select pg_truncate_visibility_map('test_sequence');
89-
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
108+
ERROR: relation "test_sequence" is of wrong relation kind
109+
DETAIL: This operation is not supported for sequences.
90110
create foreign data wrapper dummy;
91111
create server dummy_server foreign data wrapper dummy;
92112
create foreign table test_foreign_table () server dummy_server;
93113
-- foreign tables do not have VMs, so these all fail
94114
select pg_visibility('test_foreign_table', 0);
95-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
115+
ERROR: relation "test_foreign_table" is of wrong relation kind
116+
DETAIL: This operation is not supported for foreign tables.
96117
select pg_visibility_map('test_foreign_table');
97-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
118+
ERROR: relation "test_foreign_table" is of wrong relation kind
119+
DETAIL: This operation is not supported for foreign tables.
98120
select pg_visibility_map_summary('test_foreign_table');
99-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
121+
ERROR: relation "test_foreign_table" is of wrong relation kind
122+
DETAIL: This operation is not supported for foreign tables.
100123
select pg_check_frozen('test_foreign_table');
101-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
124+
ERROR: relation "test_foreign_table" is of wrong relation kind
125+
DETAIL: This operation is not supported for foreign tables.
102126
select pg_truncate_visibility_map('test_foreign_table');
103-
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
127+
ERROR: relation "test_foreign_table" is of wrong relation kind
128+
DETAIL: This operation is not supported for foreign tables.
104129
-- check some of the allowed relkinds
105130
create table regular_table (a int, b text);
106131
alter table regular_table alter column b set storage external;

contrib/pg_visibility/pg_visibility.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ check_relation_relkind(Relation rel)
781781
rel->rd_rel->relkind != RELKIND_TOASTVALUE)
782782
ereport(ERROR,
783783
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
784-
errmsg("\"%s\" is not a table, materialized view, or TOAST table",
785-
RelationGetRelationName(rel))));
784+
errmsg("relation \"%s\" is of wrong relation kind",
785+
RelationGetRelationName(rel)),
786+
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
786787
}

0 commit comments

Comments
 (0)