diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 189 |
1 files changed, 12 insertions, 177 deletions
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index db45d8a08b2..8ac2c81b06b 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -239,7 +239,6 @@ DefineQueryRewrite(const char *rulename, Relation event_relation; ListCell *l; Query *query; - bool RelisBecomingView = false; Oid ruleId = InvalidOid; ObjectAddress address; @@ -311,7 +310,18 @@ DefineQueryRewrite(const char *rulename, /* * Rules ON SELECT are restricted to view definitions * - * So there cannot be INSTEAD NOTHING, ... + * So this had better be a view, ... + */ + if (event_relation->rd_rel->relkind != RELKIND_VIEW && + event_relation->rd_rel->relkind != RELKIND_MATVIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" cannot have ON SELECT rules", + RelationGetRelationName(event_relation)), + errdetail_relkind_not_supported(event_relation->rd_rel->relkind))); + + /* + * ... there cannot be INSTEAD NOTHING, ... */ if (action == NIL) ereport(ERROR, @@ -407,93 +417,6 @@ DefineQueryRewrite(const char *rulename, ViewSelectRuleName))); rulename = pstrdup(ViewSelectRuleName); } - - /* - * 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 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) - { - TableScanDesc scanDesc; - Snapshot snapshot; - TupleTableSlot *slot; - - if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - 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), - errmsg("cannot convert partition \"%s\" to a view", - RelationGetRelationName(event_relation)))); - - snapshot = RegisterSnapshot(GetLatestSnapshot()); - scanDesc = table_beginscan(event_relation, snapshot, 0, NULL); - slot = table_slot_create(event_relation, NULL); - if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("could not convert table \"%s\" to a view because it is not empty", - RelationGetRelationName(event_relation)))); - ExecDropSingleTupleTableSlot(slot); - table_endscan(scanDesc); - UnregisterSnapshot(snapshot); - - if (event_relation->rd_rel->relhastriggers) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("could not convert table \"%s\" to a view because it has triggers", - RelationGetRelationName(event_relation)), - errhint("In particular, the table cannot be involved in any foreign key relationships."))); - - if (event_relation->rd_rel->relhasindex) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("could not convert table \"%s\" to a view because it has indexes", - RelationGetRelationName(event_relation)))); - - if (event_relation->rd_rel->relhassubclass) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - 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), - errmsg("could not convert table \"%s\" to a view because it has row security enabled", - RelationGetRelationName(event_relation)))); - - if (relation_has_policies(event_relation)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("could not convert table \"%s\" to a view because it has row security policies", - RelationGetRelationName(event_relation)))); - - RelisBecomingView = true; - } } else { @@ -569,94 +492,6 @@ DefineQueryRewrite(const char *rulename, SetRelationRuleStatus(event_relid, true); } - /* --------------------------------------------------------------------- - * If the relation is becoming a view: - * - delete the associated storage files - * - get rid of any system attributes in pg_attribute; a view shouldn't - * have any of those - * - remove the toast table; there is no need for it anymore, and its - * presence would make vacuum slightly more complicated - * - set relkind to RELKIND_VIEW, and adjust other pg_class fields - * to be appropriate for a view - * - * NB: we had better have AccessExclusiveLock to do this ... - * --------------------------------------------------------------------- - */ - if (RelisBecomingView) - { - Relation relationRelation; - Oid toastrelid; - HeapTuple classTup; - Form_pg_class classForm; - - relationRelation = table_open(RelationRelationId, RowExclusiveLock); - toastrelid = event_relation->rd_rel->reltoastrelid; - - /* drop storage while table still looks like a table */ - RelationDropStorage(event_relation); - DeleteSystemAttributeTuples(event_relid); - - /* - * Drop the toast table if any. (This won't take care of updating the - * toast fields in the relation's own pg_class entry; we handle that - * below.) - */ - if (OidIsValid(toastrelid)) - { - ObjectAddress toastobject; - - /* - * Delete the dependency of the toast relation on the main - * relation so we can drop the former without dropping the latter. - */ - deleteDependencyRecordsFor(RelationRelationId, toastrelid, - false); - - /* Make deletion of dependency record visible */ - CommandCounterIncrement(); - - /* Now drop toast table, including its index */ - toastobject.classId = RelationRelationId; - toastobject.objectId = toastrelid; - toastobject.objectSubId = 0; - performDeletion(&toastobject, DROP_RESTRICT, - PERFORM_DELETION_INTERNAL); - } - - /* - * SetRelationRuleStatus may have updated the pg_class row, so we must - * advance the command counter before trying to update it again. - */ - CommandCounterIncrement(); - - /* - * Fix pg_class entry to look like a normal view's, including setting - * the correct relkind and removal of reltoastrelid of the toast table - * we potentially removed above. - */ - classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid)); - if (!HeapTupleIsValid(classTup)) - elog(ERROR, "cache lookup failed for relation %u", event_relid); - classForm = (Form_pg_class) GETSTRUCT(classTup); - - classForm->relam = InvalidOid; - classForm->reltablespace = InvalidOid; - classForm->relpages = 0; - classForm->reltuples = -1; - classForm->relallvisible = 0; - classForm->reltoastrelid = InvalidOid; - classForm->relhasindex = false; - classForm->relkind = RELKIND_VIEW; - classForm->relfrozenxid = InvalidTransactionId; - classForm->relminmxid = InvalidMultiXactId; - classForm->relreplident = REPLICA_IDENTITY_NOTHING; - - CatalogTupleUpdate(relationRelation, &classTup->t_self, classTup); - - heap_freetuple(classTup); - table_close(relationRelation, RowExclusiveLock); - } - ObjectAddressSet(address, RewriteRelationId, ruleId); /* Close rel, but keep lock till commit... */ |