aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/pg_inherits.c12
-rw-r--r--src/backend/rewrite/rewriteDefine.c25
-rw-r--r--src/test/regress/expected/rules.out15
-rw-r--r--src/test/regress/sql/rules.sql16
4 files changed, 52 insertions, 16 deletions
diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index 17f37eb39f3..5145a569a81 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -3,8 +3,8 @@
* pg_inherits.c
* routines to support manipulation of the pg_inherits relation
*
- * Note: currently, this module only contains inquiry functions; the actual
- * creation and deletion of pg_inherits entries is done in tablecmds.c.
+ * Note: currently, this module mostly contains inquiry functions; actual
+ * creation and deletion of pg_inherits entries is mostly done in tablecmds.c.
* Perhaps someday that code should be moved here, but it'd have to be
* disentangled from other stuff such as pg_depend updates.
*
@@ -278,9 +278,11 @@ has_subclass(Oid relationId)
}
/*
- * has_superclass - does this relation inherit from another? The caller
- * should hold a lock on the given relation so that it can't be concurrently
- * added to or removed from an inheritance hierarchy.
+ * has_superclass - does this relation inherit from another?
+ *
+ * Unlike has_subclass, this can be relied on to give an accurate answer.
+ * However, the caller must hold a lock on the given relation so that it
+ * can't be concurrently added to or removed from an inheritance hierarchy.
*/
bool
has_superclass(Oid relationId)
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 9989df11074..d577d8d368f 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -26,6 +26,7 @@
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
+#include "catalog/pg_inherits.h"
#include "catalog/pg_rewrite.h"
#include "catalog/storage.h"
#include "commands/policy.h"
@@ -413,13 +414,14 @@ DefineQueryRewrite(const char *rulename,
* Are we converting a relation to a view?
*
* If so, check that the relation is empty because the storage for the
- * relation is going to be deleted. Also insist that the rel not have
- * any triggers, indexes, child tables, policies, or RLS enabled.
- * (Note: these tests are too strict, because they will reject
- * relations that once had such but don't anymore. But we don't
- * really care, because this whole business of converting relations to
- * views is just a kluge to allow dump/reload of views that
- * participate in circular dependencies.)
+ * relation is going to be deleted. Also insist that the rel not be
+ * involved in partitioning, nor have any triggers, indexes, child or
+ * parent tables, RLS policies, or RLS enabled. (Note: some of these
+ * tests are too strict, because they will reject relations that once
+ * had such but don't anymore. But we don't really care, because this
+ * whole business of converting relations to views is just an obsolete
+ * kluge to allow dump/reload of views that participate in circular
+ * dependencies.)
*/
if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
event_relation->rd_rel->relkind != RELKIND_MATVIEW)
@@ -434,6 +436,9 @@ DefineQueryRewrite(const char *rulename,
errmsg("cannot convert partitioned table \"%s\" to a view",
RelationGetRelationName(event_relation))));
+ /* only case left: */
+ Assert(event_relation->rd_rel->relkind == RELKIND_RELATION);
+
if (event_relation->rd_rel->relispartition)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -471,6 +476,12 @@ DefineQueryRewrite(const char *rulename,
errmsg("could not convert table \"%s\" to a view because it has child tables",
RelationGetRelationName(event_relation))));
+ if (has_superclass(RelationGetRelid(event_relation)))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("could not convert table \"%s\" to a view because it has parent tables",
+ RelationGetRelationName(event_relation))));
+
if (event_relation->rd_rel->relrowsecurity)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index fa436f2caa0..afac6fa2431 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2758,16 +2758,27 @@ select reltoastrelid, relkind, relfrozenxid
(1 row)
drop view rules_fooview;
--- trying to convert a partitioned table to view is not allowed
+-- cannot convert an inheritance parent or child to a view, though
+create table rules_fooview (x int, y text);
+create table rules_fooview_child () inherits (rules_fooview);
+create rule "_RETURN" as on select to rules_fooview do instead
+ select 1 as x, 'aaa'::text as y;
+ERROR: could not convert table "rules_fooview" to a view because it has child tables
+create rule "_RETURN" as on select to rules_fooview_child do instead
+ select 1 as x, 'aaa'::text as y;
+ERROR: could not convert table "rules_fooview_child" to a view because it has parent tables
+drop table rules_fooview cascade;
+NOTICE: drop cascades to table rules_fooview_child
+-- likewise, converting a partitioned table or partition to view is not allowed
create table rules_fooview (x int, y text) partition by list (x);
create rule "_RETURN" as on select to rules_fooview do instead
select 1 as x, 'aaa'::text as y;
ERROR: cannot convert partitioned table "rules_fooview" to a view
--- nor can one convert a partition to view
create table rules_fooview_part partition of rules_fooview for values in (1);
create rule "_RETURN" as on select to rules_fooview_part do instead
select 1 as x, 'aaa'::text as y;
ERROR: cannot convert partition "rules_fooview_part" to a view
+drop table rules_fooview;
--
-- check for planner problems with complex inherited UPDATES
--
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 744cf7ab546..6ec37c43811 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -901,16 +901,28 @@ select reltoastrelid, relkind, relfrozenxid
drop view rules_fooview;
--- trying to convert a partitioned table to view is not allowed
+-- cannot convert an inheritance parent or child to a view, though
+create table rules_fooview (x int, y text);
+create table rules_fooview_child () inherits (rules_fooview);
+
+create rule "_RETURN" as on select to rules_fooview do instead
+ select 1 as x, 'aaa'::text as y;
+create rule "_RETURN" as on select to rules_fooview_child do instead
+ select 1 as x, 'aaa'::text as y;
+
+drop table rules_fooview cascade;
+
+-- likewise, converting a partitioned table or partition to view is not allowed
create table rules_fooview (x int, y text) partition by list (x);
create rule "_RETURN" as on select to rules_fooview do instead
select 1 as x, 'aaa'::text as y;
--- nor can one convert a partition to view
create table rules_fooview_part partition of rules_fooview for values in (1);
create rule "_RETURN" as on select to rules_fooview_part do instead
select 1 as x, 'aaa'::text as y;
+drop table rules_fooview;
+
--
-- check for planner problems with complex inherited UPDATES
--