SELECT * FROM verify_heapam('test_partitioned',
startblock := NULL,
endblock := NULL);
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: cannot check relation "test_partitioned"
+DETAIL: This operation is not supported for partitioned tables.
-- Check that valid options are not rejected nor corruption reported
-- for an empty partition table (the child one)
CREATE TABLE test_partition partition OF test_partitioned FOR VALUES IN (1);
SELECT * FROM verify_heapam('test_index',
startblock := NULL,
endblock := NULL);
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: cannot check relation "test_index"
+DETAIL: This operation is not supported for indexes.
-- Check that views are rejected
CREATE VIEW test_view AS SELECT 1;
SELECT * FROM verify_heapam('test_view',
startblock := NULL,
endblock := NULL);
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: cannot check relation "test_view"
+DETAIL: This operation is not supported for views.
-- Check that sequences are rejected
CREATE SEQUENCE test_sequence;
SELECT * FROM verify_heapam('test_sequence',
startblock := NULL,
endblock := NULL);
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: cannot check relation "test_sequence"
+DETAIL: This operation is not supported for sequences.
-- Check that foreign tables are rejected
CREATE FOREIGN DATA WRAPPER dummy;
CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
SELECT * FROM verify_heapam('test_foreign_table',
startblock := NULL,
endblock := NULL);
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: cannot check relation "test_foreign_table"
+DETAIL: This operation is not supported for foreign tables.
-- cleanup
DROP TABLE heaptest;
DROP TABLE test_partition;
} HeapCheckContext;
/* Internal implementation */
-static void sanity_check_relation(Relation rel);
static void check_tuple(HeapCheckContext *ctx);
static void check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
ToastedAttribute *ta, int32 *expected_chunk_seq,
/* Open relation, check relkind and access method */
ctx.rel = relation_open(relid, AccessShareLock);
- sanity_check_relation(ctx.rel);
+
+ /*
+ * Check that a relation's relkind and access method are both supported.
+ */
+ if (ctx.rel->rd_rel->relkind != RELKIND_RELATION &&
+ ctx.rel->rd_rel->relkind != RELKIND_MATVIEW &&
+ ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot check relation \"%s\"",
+ RelationGetRelationName(ctx.rel)),
+ errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
+
+ if (ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("only heap AM is supported")));
/* Early exit if the relation is empty */
nblocks = RelationGetNumberOfBlocks(ctx.rel);
PG_RETURN_NULL();
}
-/*
- * Check that a relation's relkind and access method are both supported.
- */
-static void
-sanity_check_relation(Relation rel)
-{
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_MATVIEW &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, materialized view, or TOAST table",
- RelationGetRelationName(rel))));
- if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("only heap AM is supported")));
-}
-
/*
* Shared internal implementation for report_corruption and
* report_toast_corruption.
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"
+ERROR: cannot get raw page from relation "test_partitioned"
+DETAIL: This operation is not supported for partitioned tables.
select get_raw_page('test_partitioned_index', 0); -- error about partitioned index
-ERROR: cannot get raw page from partitioned index "test_partitioned_index"
+ERROR: cannot get raw page from relation "test_partitioned_index"
+DETAIL: This operation is not supported for partitioned indexes.
-- 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
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = relation_openrv(relrv, AccessShareLock);
- /* Check that this relation has storage */
- if (rel->rd_rel->relkind == RELKIND_VIEW)
+ if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("cannot get raw page from view \"%s\"",
- RelationGetRelationName(rel))));
- if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("cannot get raw page from composite type \"%s\"",
- RelationGetRelationName(rel))));
- if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("cannot get raw page from foreign table \"%s\"",
- RelationGetRelationName(rel))));
- if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- ereport(ERROR,
- (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))));
+ errmsg("cannot get raw page from relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
/*
* Reject attempts to read non-local temporary relations; we would be
-- check that it fails on an unsupported relkind
create view vw as select 1;
select heap_force_kill('vw'::regclass, ARRAY['(0, 1)']::tid[]);
-ERROR: "vw" is not a table, materialized view, or TOAST table
+ERROR: cannot operate on relation "vw"
+DETAIL: This operation is not supported for views.
select heap_force_freeze('vw'::regclass, ARRAY['(0, 1)']::tid[]);
-ERROR: "vw" is not a table, materialized view, or TOAST table
+ERROR: cannot operate on relation "vw"
+DETAIL: This operation is not supported for views.
-- cleanup.
drop view vw;
drop extension pg_surgery;
static Datum heap_force_common(FunctionCallInfo fcinfo,
HeapTupleForceOption heap_force_opt);
static void sanity_check_tid_array(ArrayType *ta, int *ntids);
-static void sanity_check_relation(Relation rel);
static BlockNumber find_tids_one_page(ItemPointer tids, int ntids,
OffsetNumber *next_start_ptr);
rel = relation_open(relid, RowExclusiveLock);
- /* Check target relation. */
- sanity_check_relation(rel);
+ /*
+ * Check target relation.
+ */
+ if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_MATVIEW &&
+ rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot operate on relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+
+ if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("only heap AM is supported")));
+
+ /* Must be owner of the table or superuser. */
+ if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER,
+ get_relkind_objtype(rel->rd_rel->relkind),
+ RelationGetRelationName(rel));
tids = ((ItemPointer) ARR_DATA_PTR(ta));
*ntids = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
}
-/*-------------------------------------------------------------------------
- * sanity_check_relation()
- *
- * Perform sanity checks on the given relation.
- * ------------------------------------------------------------------------
- */
-static void
-sanity_check_relation(Relation rel)
-{
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_MATVIEW &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, materialized view, or TOAST table",
- RelationGetRelationName(rel))));
-
- if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("only heap AM is supported")));
-
- /* Must be owner of the table or superuser. */
- if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER,
- get_relkind_objtype(rel->rd_rel->relkind),
- RelationGetRelationName(rel));
-}
-
/*-------------------------------------------------------------------------
* find_tids_one_page()
*
create table test_partitioned (a int) partition by list (a);
-- these should all fail
select pg_visibility('test_partitioned', 0);
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
select pg_visibility_map('test_partitioned');
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
select pg_visibility_map_summary('test_partitioned');
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
select pg_check_frozen('test_partitioned');
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
select pg_truncate_visibility_map('test_partitioned');
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
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
select pg_visibility('test_index', 0);
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: relation "test_index" is of wrong relation kind
+DETAIL: This operation is not supported for indexes.
select pg_visibility_map('test_index');
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: relation "test_index" is of wrong relation kind
+DETAIL: This operation is not supported for indexes.
select pg_visibility_map_summary('test_index');
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: relation "test_index" is of wrong relation kind
+DETAIL: This operation is not supported for indexes.
select pg_check_frozen('test_index');
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: relation "test_index" is of wrong relation kind
+DETAIL: This operation is not supported for indexes.
select pg_truncate_visibility_map('test_index');
-ERROR: "test_index" is not a table, materialized view, or TOAST table
+ERROR: relation "test_index" is of wrong relation kind
+DETAIL: This operation is not supported for indexes.
create view test_view as select 1;
-- views do not have VMs, so these all fail
select pg_visibility('test_view', 0);
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
select pg_visibility_map('test_view');
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
select pg_visibility_map_summary('test_view');
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
select pg_check_frozen('test_view');
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
select pg_truncate_visibility_map('test_view');
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
create sequence test_sequence;
-- sequences do not have VMs, so these all fail
select pg_visibility('test_sequence', 0);
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: relation "test_sequence" is of wrong relation kind
+DETAIL: This operation is not supported for sequences.
select pg_visibility_map('test_sequence');
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: relation "test_sequence" is of wrong relation kind
+DETAIL: This operation is not supported for sequences.
select pg_visibility_map_summary('test_sequence');
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: relation "test_sequence" is of wrong relation kind
+DETAIL: This operation is not supported for sequences.
select pg_check_frozen('test_sequence');
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: relation "test_sequence" is of wrong relation kind
+DETAIL: This operation is not supported for sequences.
select pg_truncate_visibility_map('test_sequence');
-ERROR: "test_sequence" is not a table, materialized view, or TOAST table
+ERROR: relation "test_sequence" is of wrong relation kind
+DETAIL: This operation is not supported for sequences.
create foreign data wrapper dummy;
create server dummy_server foreign data wrapper dummy;
create foreign table test_foreign_table () server dummy_server;
-- foreign tables do not have VMs, so these all fail
select pg_visibility('test_foreign_table', 0);
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
select pg_visibility_map('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
select pg_visibility_map_summary('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
select pg_check_frozen('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
select pg_truncate_visibility_map('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
-- check some of the allowed relkinds
create table regular_table (a int, b text);
alter table regular_table alter column b set storage external;
rel->rd_rel->relkind != RELKIND_TOASTVALUE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, materialized view, or TOAST table",
- RelationGetRelationName(rel))));
+ errmsg("relation \"%s\" is of wrong relation kind",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
}
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
+ERROR: cannot get tuple-level statistics for relation "test_partitioned"
+DETAIL: This operation is not supported for partitioned tables.
select pgstattuple('test_partitioned_index');
-ERROR: "test_partitioned_index" (partitioned index) is not supported
+ERROR: cannot get tuple-level statistics for relation "test_partitioned_index"
+DETAIL: This operation is not supported for partitioned indexes.
select pgstattuple_approx('test_partitioned');
-ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
+ERROR: relation "test_partitioned" is of wrong relation kind
+DETAIL: This operation is not supported for partitioned tables.
select pg_relpages('test_partitioned');
-ERROR: "test_partitioned" is not a table, index, materialized view, sequence, or TOAST table
+ERROR: cannot get page count of relation "test_partitioned"
+DETAIL: This operation is not supported for partitioned tables.
select pgstatindex('test_partitioned');
ERROR: relation "test_partitioned" is not a btree index
select pgstatginindex('test_partitioned');
create view test_view as select 1;
-- these should all fail
select pgstattuple('test_view');
-ERROR: "test_view" (view) is not supported
+ERROR: cannot get tuple-level statistics for relation "test_view"
+DETAIL: This operation is not supported for views.
select pgstattuple_approx('test_view');
-ERROR: "test_view" is not a table, materialized view, or TOAST table
+ERROR: relation "test_view" is of wrong relation kind
+DETAIL: This operation is not supported for views.
select pg_relpages('test_view');
-ERROR: "test_view" is not a table, index, materialized view, sequence, or TOAST table
+ERROR: cannot get page count of relation "test_view"
+DETAIL: This operation is not supported for views.
select pgstatindex('test_view');
ERROR: relation "test_view" is not a btree index
select pgstatginindex('test_view');
create foreign table test_foreign_table () server dummy_server;
-- these should all fail
select pgstattuple('test_foreign_table');
-ERROR: "test_foreign_table" (foreign table) is not supported
+ERROR: cannot get tuple-level statistics for relation "test_foreign_table"
+DETAIL: This operation is not supported for foreign tables.
select pgstattuple_approx('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
+ERROR: relation "test_foreign_table" is of wrong relation kind
+DETAIL: This operation is not supported for foreign tables.
select pg_relpages('test_foreign_table');
-ERROR: "test_foreign_table" is not a table, index, materialized view, sequence, or TOAST table
+ERROR: cannot get page count of relation "test_foreign_table"
+DETAIL: This operation is not supported for foreign tables.
select pgstatindex('test_foreign_table');
ERROR: relation "test_foreign_table" is not a btree index
select pgstatginindex('test_foreign_table');
rel->rd_rel->relkind == RELKIND_TOASTVALUE))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("\"%s\" is not a table, materialized view, or TOAST table",
- RelationGetRelationName(rel))));
+ errmsg("relation \"%s\" is of wrong relation kind",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
} HashIndexStat;
static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo);
+static int64 pg_relpages_impl(Relation rel);
static void GetHashPageStats(Page page, HashIndexStat *stats);
-static void check_relation_relkind(Relation rel);
/* ------------------------------------------------------
* pgstatindex()
pg_relpages(PG_FUNCTION_ARGS)
{
text *relname = PG_GETARG_TEXT_PP(0);
- int64 relpages;
Relation rel;
RangeVar *relrv;
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = relation_openrv(relrv, AccessShareLock);
- /* only some relkinds have storage */
- check_relation_relkind(rel);
-
- /* note: this will work OK on non-local temp tables */
-
- relpages = RelationGetNumberOfBlocks(rel);
-
- relation_close(rel, AccessShareLock);
-
- PG_RETURN_INT64(relpages);
+ PG_RETURN_INT64(pg_relpages_impl(rel));
}
/* No need for superuser checks in v1.5, see above */
pg_relpages_v1_5(PG_FUNCTION_ARGS)
{
text *relname = PG_GETARG_TEXT_PP(0);
- int64 relpages;
Relation rel;
RangeVar *relrv;
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = relation_openrv(relrv, AccessShareLock);
- /* only some relkinds have storage */
- check_relation_relkind(rel);
-
- /* note: this will work OK on non-local temp tables */
-
- relpages = RelationGetNumberOfBlocks(rel);
-
- relation_close(rel, AccessShareLock);
-
- PG_RETURN_INT64(relpages);
+ PG_RETURN_INT64(pg_relpages_impl(rel));
}
/* Must keep superuser() check, see above. */
pg_relpagesbyid(PG_FUNCTION_ARGS)
{
Oid relid = PG_GETARG_OID(0);
- int64 relpages;
Relation rel;
if (!superuser())
rel = relation_open(relid, AccessShareLock);
- /* only some relkinds have storage */
- check_relation_relkind(rel);
-
- /* note: this will work OK on non-local temp tables */
-
- relpages = RelationGetNumberOfBlocks(rel);
-
- relation_close(rel, AccessShareLock);
-
- PG_RETURN_INT64(relpages);
+ PG_RETURN_INT64(pg_relpages_impl(rel));
}
/* No need for superuser checks in v1.5, see above */
pg_relpagesbyid_v1_5(PG_FUNCTION_ARGS)
{
Oid relid = PG_GETARG_OID(0);
- int64 relpages;
Relation rel;
rel = relation_open(relid, AccessShareLock);
- /* only some relkinds have storage */
- check_relation_relkind(rel);
+ PG_RETURN_INT64(pg_relpages_impl(rel));
+}
+
+static int64
+pg_relpages_impl(Relation rel)
+{
+ int64 relpages;
+
+ if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot get page count of relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
/* note: this will work OK on non-local temp tables */
relation_close(rel, AccessShareLock);
- PG_RETURN_INT64(relpages);
+ return relpages;
}
/* ------------------------------------------------------
}
stats->free_space += PageGetExactFreeSpace(page);
}
-
-/*
- * check_relation_relkind - convenience routine to check that relation
- * is of the relkind supported by the callers
- */
-static void
-check_relation_relkind(Relation rel)
-{
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_INDEX &&
- rel->rd_rel->relkind != RELKIND_MATVIEW &&
- rel->rd_rel->relkind != RELKIND_SEQUENCE &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table",
- RelationGetRelationName(rel))));
-}
err = "unknown index";
break;
}
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("index \"%s\" (%s) is not supported",
+ RelationGetRelationName(rel), err)));
break;
- case RELKIND_VIEW:
- err = "view";
- break;
- case RELKIND_COMPOSITE_TYPE:
- err = "composite type";
- break;
- case RELKIND_FOREIGN_TABLE:
- err = "foreign table";
- break;
- case RELKIND_PARTITIONED_TABLE:
- err = "partitioned table";
- break;
- case RELKIND_PARTITIONED_INDEX:
- err = "partitioned index";
- break;
+
default:
- err = "unknown";
- break;
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot get tuple-level statistics for relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
}
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("\"%s\" (%s) is not supported",
- RelationGetRelationName(rel), err)));
return 0; /* should not happen */
}
partition.o \
pg_aggregate.o \
pg_cast.o \
+ pg_class.o \
pg_collation.o \
pg_constraint.o \
pg_conversion.o \
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_class.c
+ * routines to support manipulation of the pg_class relation
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/catalog/pg_class.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/pg_class.h"
+
+/*
+ * Issue an errdetail() informing that the relkind is not supported for this
+ * operation.
+ */
+int
+errdetail_relkind_not_supported(char relkind)
+{
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ return errdetail("This operation is not supported for tables.");
+ case RELKIND_INDEX:
+ return errdetail("This operation is not supported for indexes.");
+ case RELKIND_SEQUENCE:
+ return errdetail("This operation is not supported for sequences.");
+ case RELKIND_TOASTVALUE:
+ return errdetail("This operation is not supported for TOAST tables.");
+ case RELKIND_VIEW:
+ return errdetail("This operation is not supported for views.");
+ case RELKIND_MATVIEW:
+ return errdetail("This operation is not supported for materialized views.");
+ case RELKIND_COMPOSITE_TYPE:
+ return errdetail("This operation is not supported for composite types.");
+ case RELKIND_FOREIGN_TABLE:
+ return errdetail("This operation is not supported for foreign tables.");
+ case RELKIND_PARTITIONED_TABLE:
+ return errdetail("This operation is not supported for partitioned tables.");
+ case RELKIND_PARTITIONED_INDEX:
+ return errdetail("This operation is not supported for partitioned indexes.");
+ default:
+ elog(ERROR, "unrecognized relkind: '%c'", relkind);
+ return 0;
+ }
+}
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_MATVIEW)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or materialized view",
- relName)));
+ elog(ERROR, "\"%s\" is not a table or materialized view",
+ relName);
/* create_toast_table does all the work */
if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,
relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
- RelationGetRelationName(relation))));
+ errmsg("cannot set comment on relation \"%s\"",
+ RelationGetRelationName(relation)),
+ errdetail_relkind_not_supported(relation->rd_rel->relkind)));
break;
default:
break;
case RELKIND_PARTITIONED_TABLE:
/* OK */
break;
- case RELKIND_FOREIGN_TABLE:
-
- /*
- * Custom error message for FOREIGN TABLE since the term is close
- * to a regular table and can confuse the user.
- */
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("cannot create index on foreign table \"%s\"",
- RelationGetRelationName(rel))));
- break;
default:
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or materialized view",
- RelationGetRelationName(rel))));
+ errmsg("cannot create index on relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
break;
}
relkind != RELKIND_VIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or view",
- rv->relname)));
+ errmsg("cannot lock relation \"%s\"",
+ rv->relname),
+ errdetail_relkind_not_supported(relkind)));
/*
* Make note if a temporary relation has been accessed in this
relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
- RelationGetRelationName(relation))));
+ errmsg("cannot set security label on relation \"%s\"",
+ RelationGetRelationName(relation)),
+ errdetail_relkind_not_supported(relation->rd_rel->relkind)));
break;
default:
break;
tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("referenced relation \"%s\" is not a table or foreign table",
- RelationGetRelationName(tablerel))));
+ errmsg("sequence cannot be owned by relation \"%s\"",
+ RelationGetRelationName(tablerel)),
+ errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
/* We insist on same owner and schema */
if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
- RelationGetRelationName(rel))));
+ errmsg("cannot define statistics for relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
/* You must own the relation to create stats on it */
if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
AlterTableUtilityContext *context);
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
-static void ATSimplePermissions(Relation rel, int allowed_targets);
-static void ATWrongRelkindError(Relation rel, int allowed_targets);
+static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
static void ATSimpleRecursion(List **wqueue, Relation rel,
AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
AlterTableUtilityContext *context);
relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
- NameStr(classform->relname))));
+ errmsg("cannot rename columns of relation \"%s\"",
+ NameStr(classform->relname)),
+ errdetail_relkind_not_supported(relkind)));
/*
* permissions checking. only the owner of a class can change its schema.
switch (cmd->subtype)
{
case AT_AddColumn: /* ADD COLUMN */
- ATSimplePermissions(rel,
+ ATSimplePermissions(cmd->subtype, rel,
ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
lockmode, context);
pass = AT_PASS_ADD_COL;
break;
case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
- ATSimplePermissions(rel, ATT_VIEW);
+ ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
lockmode, context);
/* Recursion occurs during execution phase */
* substitutes default values into INSERTs before it expands
* rules.
*/
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
/* No command-specific prep needed */
pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
case AT_CookedColumnDefault: /* add a pre-cooked default */
/* This is currently used only in CREATE TABLE */
/* (so the permission check really isn't necessary) */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* This command never recurses */
pass = AT_PASS_ADD_OTHERCONSTR;
break;
case AT_AddIdentity:
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
/* This command never recurses */
pass = AT_PASS_ADD_OTHERCONSTR;
break;
case AT_SetIdentity:
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
/* This command never recurses */
/* This should run after AddIdentity, so do it in MISC pass */
pass = AT_PASS_MISC;
break;
case AT_DropIdentity:
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
/* This command never recurses */
pass = AT_PASS_DROP;
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
ATPrepDropNotNull(rel, recurse, recursing);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
pass = AT_PASS_DROP;
break;
case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* Need command-specific recursion decision */
ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
lockmode, context);
pass = AT_PASS_COL_ATTRS;
break;
case AT_CheckNotNull: /* check column is already marked NOT NULL */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
/* No command-specific prep needed */
pass = AT_PASS_COL_ATTRS;
break;
case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
pass = AT_PASS_DROP;
break;
case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE);
/* This command never recurses */
pass = AT_PASS_MISC;
break;
case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_DropColumn: /* DROP COLUMN */
- ATSimplePermissions(rel,
+ ATSimplePermissions(cmd->subtype, rel,
ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
lockmode, context);
pass = AT_PASS_DROP;
break;
case AT_AddIndex: /* ADD INDEX */
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_ADD_INDEX;
break;
case AT_AddConstraint: /* ADD CONSTRAINT */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
pass = AT_PASS_ADD_CONSTR;
break;
case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_ADD_INDEXCONSTR;
break;
case AT_DropConstraint: /* DROP CONSTRAINT */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
ATCheckPartitionsNotInUse(rel, lockmode);
/* Other recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
pass = AT_PASS_DROP;
break;
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
- ATSimplePermissions(rel,
+ ATSimplePermissions(cmd->subtype, rel,
ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
/* See comments for ATPrepAlterColumnType */
cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
pass = AT_PASS_ALTER_TYPE;
break;
case AT_AlterColumnGenericOptions:
- ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_ClusterOn: /* CLUSTER ON */
case AT_DropCluster: /* SET WITHOUT CLUSTER */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_SetLogged: /* SET LOGGED */
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
if (tab->chgPersistence)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
pass = AT_PASS_MISC;
break;
case AT_SetUnLogged: /* SET UNLOGGED */
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
if (tab->chgPersistence)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
pass = AT_PASS_MISC;
break;
case AT_DropOids: /* SET WITHOUT OIDS */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
pass = AT_PASS_DROP;
break;
case AT_SetTableSpace: /* SET TABLESPACE */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
ATT_PARTITIONED_INDEX);
/* This command never recurses */
ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
case AT_SetRelOptions: /* SET (...) */
case AT_ResetRelOptions: /* RESET (...) */
case AT_ReplaceRelOptions: /* reset them all, then set just these */
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_AddInherit: /* INHERIT */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* This command never recurses */
ATPrepAddInherit(rel);
pass = AT_PASS_MISC;
break;
case AT_DropInherit: /* NO INHERIT */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_AlterConstraint: /* ALTER CONSTRAINT */
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* Recursion occurs during execution phase */
pass = AT_PASS_MISC;
break;
case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
pass = AT_PASS_MISC;
break;
case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
- ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
pass = AT_PASS_MISC;
/* This command never recurses */
/* No command-specific prep needed */
case AT_DisableTrig: /* DISABLE TRIGGER variants */
case AT_DisableTrigAll:
case AT_DisableTrigUser:
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
pass = AT_PASS_MISC;
case AT_DisableRowSecurity:
case AT_ForceRowSecurity:
case AT_NoForceRowSecurity:
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_GenericOptions:
- ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_AttachPartition:
- ATSimplePermissions(rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_DetachPartition:
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_DetachPartitionFinalize:
- ATSimplePermissions(rel, ATT_TABLE);
+ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
return tab;
}
+static const char *
+alter_table_type_to_string(AlterTableType cmdtype)
+{
+ switch (cmdtype)
+ {
+ case AT_AddColumn:
+ case AT_AddColumnRecurse:
+ case AT_AddColumnToView:
+ return "ADD COLUMN";
+ case AT_ColumnDefault:
+ case AT_CookedColumnDefault:
+ return "ALTER COLUMN ... SET DEFAULT";
+ case AT_DropNotNull:
+ return "ALTER COLUMN ... DROP NOT NULL";
+ case AT_SetNotNull:
+ return "ALTER COLUMN ... SET NOT NULL";
+ case AT_DropExpression:
+ return "ALTER COLUMN ... DROP EXPRESSION";
+ case AT_CheckNotNull:
+ return NULL; /* not real grammar */
+ case AT_SetStatistics:
+ return "ALTER COLUMN ... SET STATISTICS";
+ case AT_SetOptions:
+ return "ALTER COLUMN ... SET";
+ case AT_ResetOptions:
+ return "ALTER COLUMN ... RESET";
+ case AT_SetStorage:
+ return "ALTER COLUMN ... SET STORAGE";
+ case AT_SetCompression:
+ return "ALTER COLUMN ... SET COMPRESSION";
+ case AT_DropColumn:
+ case AT_DropColumnRecurse:
+ return "DROP COLUMN";
+ case AT_AddIndex:
+ case AT_ReAddIndex:
+ return NULL; /* not real grammar */
+ case AT_AddConstraint:
+ case AT_AddConstraintRecurse:
+ case AT_ReAddConstraint:
+ case AT_ReAddDomainConstraint:
+ case AT_AddIndexConstraint:
+ return "ADD CONSTRAINT";
+ case AT_AlterConstraint:
+ return "ALTER CONSTRAINT";
+ case AT_ValidateConstraint:
+ case AT_ValidateConstraintRecurse:
+ return "VALIDATE CONSTRAINT";
+ case AT_DropConstraint:
+ case AT_DropConstraintRecurse:
+ return "DROP CONSTRAINT";
+ case AT_ReAddComment:
+ return NULL; /* not real grammar */
+ case AT_AlterColumnType:
+ return "ALTER COLUMN ... SET DATA TYPE";
+ case AT_AlterColumnGenericOptions:
+ return "ALTER COLUMN ... OPTIONS";
+ case AT_ChangeOwner:
+ return "OWNER TO";
+ case AT_ClusterOn:
+ return "CLUSTER ON";
+ case AT_DropCluster:
+ return "SET WITHOUT CLUSTER";
+ case AT_SetLogged:
+ return "SET LOGGED";
+ case AT_SetUnLogged:
+ return "SET UNLOGGED";
+ case AT_DropOids:
+ return "SET WITHOUT OIDS";
+ case AT_SetTableSpace:
+ return "SET TABLESPACE";
+ case AT_SetRelOptions:
+ return "SET";
+ case AT_ResetRelOptions:
+ return "RESET";
+ case AT_ReplaceRelOptions:
+ return NULL; /* not real grammar */
+ case AT_EnableTrig:
+ return "ENABLE TRIGGER";
+ case AT_EnableAlwaysTrig:
+ return "ENABLE ALWAYS TRIGGER";
+ case AT_EnableReplicaTrig:
+ return "ENABLE REPLICA TRIGGER";
+ case AT_DisableTrig:
+ return "DISABLE TRIGGER";
+ case AT_EnableTrigAll:
+ return "ENABLE TRIGGER ALL";
+ case AT_DisableTrigAll:
+ return "DISABLE TRIGGER ALL";
+ case AT_EnableTrigUser:
+ return "ENABLE TRIGGER USER";
+ case AT_DisableTrigUser:
+ return "DISABLE TRIGGER USER";
+ case AT_EnableRule:
+ return "ENABLE RULE";
+ case AT_EnableAlwaysRule:
+ return "ENABLE ALWAYS RULE";
+ case AT_EnableReplicaRule:
+ return "ENABLE REPLICA RULE";
+ case AT_DisableRule:
+ return "DISABLE RULE";
+ case AT_AddInherit:
+ return "INHERIT";
+ case AT_DropInherit:
+ return "NO INHERIT";
+ case AT_AddOf:
+ return "OF";
+ case AT_DropOf:
+ return "NOT OF";
+ case AT_ReplicaIdentity:
+ return "REPLICA IDENTITY";
+ case AT_EnableRowSecurity:
+ return "ENABLE ROW SECURITY";
+ case AT_DisableRowSecurity:
+ return "DISABLE ROW SECURITY";
+ case AT_ForceRowSecurity:
+ return "FORCE ROW SECURITY";
+ case AT_NoForceRowSecurity:
+ return "NO FORCE ROW SECURITY";
+ case AT_GenericOptions:
+ return "OPTIONS";
+ case AT_AttachPartition:
+ return "ATTACH PARTITION";
+ case AT_DetachPartition:
+ return "DETACH PARTITION";
+ case AT_DetachPartitionFinalize:
+ return "DETACH PARTITION ... FINALIZE";
+ case AT_AddIdentity:
+ return "ALTER COLUMN ... ADD IDENTITY";
+ case AT_SetIdentity:
+ return "ALTER COLUMN ... SET";
+ case AT_DropIdentity:
+ return "ALTER COLUMN ... DROP IDENTITY";
+ case AT_ReAddStatistics:
+ return NULL; /* not real grammar */
+ }
+
+ return NULL;
+}
+
/*
* ATSimplePermissions
*
* - Ensure that it is not a system table
*/
static void
-ATSimplePermissions(Relation rel, int allowed_targets)
+ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
{
int actual_target;
/* Wrong target type? */
if ((actual_target & allowed_targets) == 0)
- ATWrongRelkindError(rel, allowed_targets);
+ {
+ const char *action_str = alter_table_type_to_string(cmdtype);
+
+ if (action_str)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ /* translator: %s is a group of some SQL keywords */
+ errmsg("ALTER action %s cannot be performed on relation \"%s\"",
+ action_str, RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+ else
+ /* internal error? */
+ elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
+ RelationGetRelationName(rel));
+ }
/* Permissions checks */
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
RelationGetRelationName(rel))));
}
-/*
- * ATWrongRelkindError
- *
- * Throw an error when a relation has been determined to be of the wrong
- * type.
- */
-static void
-ATWrongRelkindError(Relation rel, int allowed_targets)
-{
- char *msg;
-
- switch (allowed_targets)
- {
- case ATT_TABLE:
- msg = _("\"%s\" is not a table");
- break;
- case ATT_TABLE | ATT_VIEW:
- msg = _("\"%s\" is not a table or view");
- break;
- case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a table, view, or foreign table");
- break;
- case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
- msg = _("\"%s\" is not a table, view, materialized view, or index");
- break;
- case ATT_TABLE | ATT_MATVIEW:
- msg = _("\"%s\" is not a table or materialized view");
- break;
- case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
- msg = _("\"%s\" is not a table, materialized view, or index");
- break;
- case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a table, materialized view, or foreign table");
- break;
- case ATT_TABLE | ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a table or foreign table");
- break;
- case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a table, composite type, or foreign table");
- break;
- case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a table, materialized view, index, or foreign table");
- break;
- case ATT_VIEW:
- msg = _("\"%s\" is not a view");
- break;
- case ATT_FOREIGN_TABLE:
- msg = _("\"%s\" is not a foreign table");
- break;
- default:
- /* shouldn't get here, add all necessary cases above */
- msg = _("\"%s\" is of the wrong type");
- break;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg(msg, RelationGetRelationName(rel))));
-}
-
/*
* ATSimpleRecursion
*
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
if (rel->rd_rel->relispartition && !recursing)
ereport(ERROR,
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(AT_DropColumn, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* Initialize addrs on the first invocation */
Assert(!recursing || addrs != NULL);
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/*
* Call AddRelationNewConstraints to do the work, making sure it works on
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
- ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(AT_DropConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
conrel = table_open(ConstraintRelationId, RowExclusiveLock);
default:
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, sequence, or foreign table",
- NameStr(tuple_class->relname))));
+ errmsg("cannot change owner of relation \"%s\"",
+ NameStr(tuple_class->relname)),
+ errdetail_relkind_not_supported(tuple_class->relkind)));
}
/*
default:
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
- RelationGetRelationName(rel))));
+ errmsg("cannot set options for relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
break;
}
* Must be owner of both parent and child -- child was checked by
* ATSimplePermissions call in ATPrepCmd
*/
- ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(AT_AddInherit, parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* Permanent rels cannot inherit from temporary ones */
if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
* Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
* to a different schema, such as indexes and TOAST tables.
*/
- if (IsA(stmt, AlterObjectSchemaStmt) &&
- relkind != RELKIND_RELATION &&
- relkind != RELKIND_VIEW &&
- relkind != RELKIND_MATVIEW &&
- relkind != RELKIND_SEQUENCE &&
- relkind != RELKIND_FOREIGN_TABLE &&
- relkind != RELKIND_PARTITIONED_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
- rv->relname)));
+ if (IsA(stmt, AlterObjectSchemaStmt))
+ {
+ if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot change schema of index \"%s\"",
+ rv->relname),
+ errhint("Change the schema of the table instead.")));
+ else if (relkind == RELKIND_COMPOSITE_TYPE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot change schema of composite type \"%s\"",
+ rv->relname),
+ errhint("Use ALTER TYPE instead.")));
+ else if (relkind == RELKIND_TOASTVALUE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot change schema of TOAST table \"%s\"",
+ rv->relname),
+ errhint("Change the schema of the table instead.")));
+ }
ReleaseSysCache(tuple);
}
* Must be owner of both parent and source table -- parent was checked by
* ATSimplePermissions call in ATPrepCmd
*/
- ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(AT_AttachPartition, attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* A partition can only have one parent */
if (attachrel->rd_rel->relispartition)
else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or view",
- RelationGetRelationName(rel))));
+ errmsg("relation \"%s\" cannot have triggers",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
if (!allowSystemTableMods && IsSystemRelation(rel))
ereport(ERROR,
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, or foreign table",
- RelationGetRelationName(rel))));
+ errmsg("relation \"%s\" cannot have triggers",
+ RelationGetRelationName(rel)),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
if (!allowSystemTableMods && IsSystemRelation(rel))
ereport(ERROR,
form->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, or foreign table",
- rv->relname)));
+ errmsg("relation \"%s\" cannot have triggers",
+ rv->relname),
+ errdetail_relkind_not_supported(form->relkind)));
/* you must own the table to rename one of its triggers */
if (!pg_class_ownercheck(relid, GetUserId()))
relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
- RelationGetRelationName(relation))));
+ errmsg("relation \"%s\" is invalid in LIKE clause",
+ RelationGetRelationName(relation)),
+ errdetail_relkind_not_supported(relation->rd_rel->relkind)));
cancel_parser_errposition_callback(&pcbstate);
event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or view",
- RelationGetRelationName(event_relation))));
+ errmsg("relation \"%s\" cannot have rules",
+ RelationGetRelationName(event_relation)),
+ errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
if (!allowSystemTableMods && IsSystemRelation(event_relation))
ereport(ERROR,
form->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table or view", rv->relname)));
+ errmsg("relation \"%s\" cannot have rules", rv->relname),
+ errdetail_relkind_not_supported(form->relkind)));
if (!allowSystemTableMods && IsSystemClass(relid, form))
ereport(ERROR,
(relkind) == RELKIND_TOASTVALUE || \
(relkind) == RELKIND_MATVIEW)
+extern int errdetail_relkind_not_supported(char relkind);
#endif /* EXPOSE_TO_CLIENT_CODE */
-- try creating a view and altering that, should fail
create view myview as select * from atacc1;
alter table myview alter column test drop not null;
-ERROR: "myview" is not a table or foreign table
+ERROR: ALTER action ALTER COLUMN ... DROP NOT NULL cannot be performed on relation "myview"
+DETAIL: This operation is not supported for views.
alter table myview alter column test set not null;
-ERROR: "myview" is not a table or foreign table
+ERROR: ALTER action ALTER COLUMN ... SET NOT NULL cannot be performed on relation "myview"
+DETAIL: This operation is not supported for views.
drop view myview;
drop table atacc1;
-- set not null verified by constraints
(0 rows)
alter table myview drop d;
-ERROR: "myview" is not a table, composite type, or foreign table
+ERROR: ALTER action DROP COLUMN cannot be performed on relation "myview"
+DETAIL: This operation is not supported for views.
drop view myview;
-- test some commands to make sure they fail on the dropped column
analyze atacc1(a);
CREATE TABLE ctlt4 (a int, b text);
CREATE SEQUENCE ctlseq1;
CREATE TABLE ctlt10 (LIKE ctlseq1); -- fail
-ERROR: "ctlseq1" is not a table, view, materialized view, composite type, or foreign table
+ERROR: relation "ctlseq1" is invalid in LIKE clause
LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1);
^
+DETAIL: This operation is not supported for sequences.
CREATE VIEW ctlv1 AS SELECT * FROM ctlt4;
CREATE TABLE ctlt11 (LIKE ctlv1);
CREATE TABLE ctlt11a (LIKE ctlv1 INCLUDING ALL);
(1 row)
CREATE INDEX id_ft1_c2 ON ft1 (c2); -- ERROR
-ERROR: cannot create index on foreign table "ft1"
+ERROR: cannot create index on relation "ft1"
+DETAIL: This operation is not supported for foreign tables.
SELECT * FROM ft1; -- ERROR
ERROR: foreign-data wrapper "dummy" has no handler
EXPLAIN SELECT * FROM ft1; -- ERROR
^
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0) NOT VALID;
ALTER FOREIGN TABLE ft1 ALTER CONSTRAINT ft1_c9_check DEFERRABLE; -- ERROR
-ERROR: "ft1" is not a table
+ERROR: ALTER action ALTER CONSTRAINT cannot be performed on relation "ft1"
+DETAIL: This operation is not supported for foreign tables.
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c9_check;
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
ERROR: constraint "no_const" of relation "ft1" does not exist
(2 rows)
alter table idxpart_c detach partition idxpart1_c;
-ERROR: "idxpart_c" is not a table
+ERROR: ALTER action DETACH PARTITION cannot be performed on relation "idxpart_c"
+DETAIL: This operation is not supported for partitioned indexes.
drop table idxpart;
-- If a partition already has an index, don't create a duplicative one
create table idxpart (a int, b int) partition by range (a, b);
ERROR: invalid OWNED BY option
HINT: Specify OWNED BY table.column or OWNED BY NONE.
CREATE SEQUENCE sequence_testx OWNED BY pg_class_oid_index.oid; -- not a table
-ERROR: referenced relation "pg_class_oid_index" is not a table or foreign table
+ERROR: sequence cannot be owned by relation "pg_class_oid_index"
+DETAIL: This operation is not supported for indexes.
CREATE SEQUENCE sequence_testx OWNED BY pg_class.relname; -- not same schema
ERROR: sequence must be in same schema as table it is linked to
CREATE TABLE sequence_test_table (a int);
CREATE TABLE tststats.pt1 PARTITION OF tststats.pt FOR VALUES FROM (-10, -10) TO (10, 10);
CREATE STATISTICS tststats.s1 ON a, b FROM tststats.t;
CREATE STATISTICS tststats.s2 ON a, b FROM tststats.ti;
-ERROR: relation "ti" is not a table, foreign table, or materialized view
+ERROR: cannot define statistics for relation "ti"
+DETAIL: This operation is not supported for indexes.
CREATE STATISTICS tststats.s3 ON a, b FROM tststats.s;
-ERROR: relation "s" is not a table, foreign table, or materialized view
+ERROR: cannot define statistics for relation "s"
+DETAIL: This operation is not supported for sequences.
CREATE STATISTICS tststats.s4 ON a, b FROM tststats.v;
-ERROR: relation "v" is not a table, foreign table, or materialized view
+ERROR: cannot define statistics for relation "v"
+DETAIL: This operation is not supported for views.
CREATE STATISTICS tststats.s5 ON a, b FROM tststats.mv;
CREATE STATISTICS tststats.s6 ON a, b FROM tststats.ty;
-ERROR: relation "ty" is not a table, foreign table, or materialized view
+ERROR: cannot define statistics for relation "ty"
+DETAIL: This operation is not supported for composite types.
CREATE STATISTICS tststats.s7 ON a, b FROM tststats.f;
CREATE STATISTICS tststats.s8 ON a, b FROM tststats.pt;
CREATE STATISTICS tststats.s9 ON a, b FROM tststats.pt1;