| Line | Hits | Source | Commit |
|---|---|---|---|
| 316 | - | gettext_noop("Use DROP PROPERTY GRAPH to remove a property graph.")}, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 317 | - | {'\0', 0, NULL, NULL, NULL, NULL} | - |
| 318 | - | }; | - |
| 319 | - | - | |
| 320 | - | /* communication between RemoveRelations and RangeVarCallbackForDropRelation */ | - |
| 321 | - | struct DropRelationCallbackState | - |
| 322 | - | { | - |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1539 | - | RemoveRelations(DropStmt *drop) | - |
| 1540 | - | { | - |
| 1541 | - | ObjectAddresses *objects; | - |
| 1542 | - | char relkind; | - |
| 1543 | - | ListCell *cell; | - |
| 1544 | - | int flags = 0; | - |
| 1545 | - | LOCKMODE lockmode = AccessExclusiveLock; | - |
| 1546 | - | - | |
| 1547 | - | /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */ | - |
| 1548 | - | if (drop->concurrent) | - |
| 1549 | - | { | - |
| 1550 | - | /* | - |
| 1551 | - | * Note that for temporary relations this lock may get upgraded later | - |
| 1552 | - | * on, but as no other session can access a temporary relation, this | - |
| 1553 | - | * is actually fine. | - |
| 1554 | - | */ | - |
| 1555 | - | lockmode = ShareUpdateExclusiveLock; | - |
| 1556 | - | Assert(drop->removeType == OBJECT_INDEX); | - |
| 1557 | - | if (list_length(drop->objects) != 1) | - |
| 1558 | - | ereport(ERROR, | - |
| 1559 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | - |
| 1560 | - | errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects"))); | - |
| 1561 | - | if (drop->behavior == DROP_CASCADE) | - |
| 1562 | - | ereport(ERROR, | - |
| 1563 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | - |
| 1564 | - | errmsg("DROP INDEX CONCURRENTLY does not support CASCADE"))); | - |
| 1565 | - | } | - |
| 1566 | - | - | |
| 1567 | - | /* | - |
| 1568 | - | * First we identify all the relations, then we delete them in a single | - |
| 1569 | - | * performMultipleDeletions() call. This is to avoid unwanted DROP | - |
| 1570 | - | * RESTRICT errors if one of the relations depends on another. | - |
| 1571 | - | */ | - |
| 1572 | - | - | |
| 1573 | - | /* Determine required relkind */ | - |
| 1574 | - | switch (drop->removeType) | - |
| 1575 | - | { | - |
| 1576 | - | case OBJECT_TABLE: | - |
| 1577 | - | relkind = RELKIND_RELATION; | - |
| 1578 | - | break; | - |
| 1579 | - | - | |
| 1580 | - | case OBJECT_INDEX: | - |
| 1581 | - | relkind = RELKIND_INDEX; | - |
| 1582 | - | break; | - |
| 1583 | - | - | |
| 1584 | - | case OBJECT_SEQUENCE: | - |
| 1585 | - | relkind = RELKIND_SEQUENCE; | - |
| 1586 | - | break; | - |
| 1587 | - | - | |
| 1588 | - | case OBJECT_VIEW: | - |
| 1589 | - | relkind = RELKIND_VIEW; | - |
| 1590 | - | break; | - |
| 1591 | - | - | |
| 1592 | - | case OBJECT_MATVIEW: | - |
| 1593 | - | relkind = RELKIND_MATVIEW; | - |
| 1594 | - | break; | - |
| 1595 | - | - | |
| 1596 | - | case OBJECT_FOREIGN_TABLE: | - |
| 1597 | - | relkind = RELKIND_FOREIGN_TABLE; | - |
| 1598 | - | break; | - |
| 1599 | - | - | |
| 1600 | 24 | case OBJECT_PROPGRAPH: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1601 | 24 | relkind = RELKIND_PROPGRAPH; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1602 | 24 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1603 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1604 | - | default: | - |
| 1605 | - | elog(ERROR, "unrecognized drop object type: %d", | - |
| 1606 | - | (int) drop->removeType); | - |
| 1607 | - | relkind = 0; /* keep compiler quiet */ | - |
| 1608 | - | break; | - |
| 1609 | - | } | - |
| 1610 | - | - | |
| 1611 | - | /* Lock and validate each relation; build a list of object addresses */ | - |
| 1612 | - | objects = new_object_addresses(); | - |
| 1613 | - | - | |
| 1614 | - | foreach(cell, drop->objects) | - |
| 1615 | - | { | - |
| 1616 | - | RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell)); | - |
| 1617 | - | Oid relOid; | - |
| 1618 | - | ObjectAddress obj; | - |
| 1619 | - | struct DropRelationCallbackState state; | - |
| 1620 | - | - | |
| 1621 | - | /* | - |
| 1622 | - | * These next few steps are a great deal like relation_openrv, but we | - |
| 1623 | - | * don't bother building a relcache entry since we don't need it. | - |
| 1624 | - | * | - |
| 1625 | - | * Check for shared-cache-inval messages before trying to access the | - |
| 1626 | - | * relation. This is needed to cover the case where the name | - |
| 1627 | - | * identifies a rel that has been dropped and recreated since the | - |
| 1628 | - | * start of our transaction: if we don't flush the old syscache entry, | - |
| 1629 | - | * then we'll latch onto that entry and suffer an error later. | - |
| 1630 | - | */ | - |
| 1631 | - | AcceptInvalidationMessages(); | - |
| 1632 | - | - | |
| 1633 | - | /* Look up the appropriate relation using namespace search. */ | - |
| 1634 | - | state.expected_relkind = relkind; | - |
| 1635 | - | state.heap_lockmode = drop->concurrent ? | - |
| 1636 | - | ShareUpdateExclusiveLock : AccessExclusiveLock; | - |
| 1637 | - | /* We must initialize these fields to show that no locks are held: */ | - |
| 1638 | - | state.heapOid = InvalidOid; | - |
| 1639 | - | state.partParentOid = InvalidOid; | - |
| 1640 | - | - | |
| 1641 | - | relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK, | - |
| 1642 | - | RangeVarCallbackForDropRelation, | - |
| 1643 | - | &state); | - |
| 1644 | - | - | |
| 1645 | - | /* Not there? */ | - |
| 1646 | - | if (!OidIsValid(relOid)) | - |
| 1647 | - | { | - |
| 1648 | - | DropErrorMsgNonExistent(rel, relkind, drop->missing_ok); | - |
| 1649 | - | continue; | - |
| 1650 | - | } | - |
| 1651 | - | - | |
| 1652 | - | /* | - |
| 1653 | - | * Decide if concurrent mode needs to be used here or not. The | - |
| 1654 | - | * callback retrieved the rel's persistence for us. | - |
| 1655 | - | */ | - |
| 1656 | - | if (drop->concurrent && | - |
| 1657 | - | state.actual_relpersistence != RELPERSISTENCE_TEMP) | - |
| 1658 | - | { | - |
| 1659 | - | Assert(list_length(drop->objects) == 1 && | - |
| 1660 | - | drop->removeType == OBJECT_INDEX); | - |
| 1661 | - | flags |= PERFORM_DELETION_CONCURRENTLY; | - |
| 1662 | - | } | - |
| 1663 | - | - | |
| 1664 | - | /* | - |
| 1665 | - | * Concurrent index drop cannot be used with partitioned indexes, | - |
| 1666 | - | * either. | - |
| 1667 | - | */ | - |
| 1668 | - | if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 && | - |
| 1669 | - | state.actual_relkind == RELKIND_PARTITIONED_INDEX) | - |
| 1670 | - | ereport(ERROR, | - |
| 1671 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | - |
| 1672 | - | errmsg("cannot drop partitioned index \"%s\" concurrently", | - |
| 1673 | - | rel->relname))); | - |
| 1674 | - | - | |
| 1675 | - | /* | - |
| 1676 | - | * If we're told to drop a partitioned index, we must acquire lock on | - |
| 1677 | - | * all the children of its parent partitioned table before proceeding. | - |
| 1678 | - | * Otherwise we'd try to lock the child index partitions before their | - |
| 1679 | - | * tables, leading to potential deadlock against other sessions that | - |
| 1680 | - | * will lock those objects in the other order. | - |
| 1681 | - | */ | - |
| 1682 | - | if (state.actual_relkind == RELKIND_PARTITIONED_INDEX) | - |
| 1683 | - | (void) find_all_inheritors(state.heapOid, | - |
| 1684 | - | state.heap_lockmode, | - |
| 1685 | - | NULL); | - |
| 1686 | - | - | |
| 1687 | - | /* OK, we're ready to delete this one */ | - |
| 1688 | - | obj.classId = RelationRelationId; | - |
| 1689 | - | obj.objectId = relOid; | - |
| 1690 | - | obj.objectSubId = 0; | - |
| 1691 | - | - | |
| 1692 | - | add_exact_object_address(&obj, objects); | - |
| 1693 | - | } | - |
| 1694 | - | - | |
| 1695 | - | performMultipleDeletions(objects, drop->behavior, flags); | - |
| 1696 | - | - | |
| 1697 | - | free_object_addresses(objects); | - |
| 1698 | - | } | - |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 16110 | - | ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode) | - |
| 16111 | - | { | - |
| 16112 | - | Relation target_rel; | - |
| 16113 | - | Relation class_rel; | - |
| 16114 | - | HeapTuple tuple; | - |
| 16115 | - | Form_pg_class tuple_class; | - |
| 16116 | - | - | |
| 16117 | - | /* | - |
| 16118 | - | * Get exclusive lock till end of transaction on the target table. Use | - |
| 16119 | - | * relation_open so that we can work on indexes and sequences. | - |
| 16120 | - | */ | - |
| 16121 | - | target_rel = relation_open(relationOid, lockmode); | - |
| 16122 | - | - | |
| 16123 | - | /* Get its pg_class tuple, too */ | - |
| 16124 | - | class_rel = table_open(RelationRelationId, RowExclusiveLock); | - |
| 16125 | - | - | |
| 16126 | - | tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid)); | - |
| 16127 | - | if (!HeapTupleIsValid(tuple)) | - |
| 16128 | - | elog(ERROR, "cache lookup failed for relation %u", relationOid); | - |
| 16129 | - | tuple_class = (Form_pg_class) GETSTRUCT(tuple); | - |
| 16130 | - | - | |
| 16131 | - | /* Can we change the ownership of this tuple? */ | - |
| 16132 | - | switch (tuple_class->relkind) | - |
| 16133 | - | { | - |
| 16134 | - | case RELKIND_RELATION: | - |
| 16135 | - | case RELKIND_VIEW: | - |
| 16136 | - | case RELKIND_MATVIEW: | - |
| 16137 | - | case RELKIND_FOREIGN_TABLE: | - |
| 16138 | - | case RELKIND_PARTITIONED_TABLE: | - |
| 16139 | - | case RELKIND_PROPGRAPH: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 16140 | - | /* ok to change owner */ | - |
| 16141 | - | break; | - |
| 16142 | - | case RELKIND_INDEX: | - |
| 16143 | - | if (!recursing) | - |
| 16144 | - | { | - |
| 16145 | - | /* | - |
| 16146 | - | * Because ALTER INDEX OWNER used to be allowed, and in fact | - |
| 16147 | - | * is generated by old versions of pg_dump, we give a warning | - |
| 16148 | - | * and do nothing rather than erroring out. Also, to avoid | - |
| 16149 | - | * unnecessary chatter while restoring those old dumps, say | - |
| 16150 | - | * nothing at all if the command would be a no-op anyway. | - |
| 16151 | - | */ | - |
| 16152 | - | if (tuple_class->relowner != newOwnerId) | - |
| 16153 | - | ereport(WARNING, | - |
| 16154 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 16155 | - | errmsg("cannot change owner of index \"%s\"", | - |
| 16156 | - | NameStr(tuple_class->relname)), | - |
| 16157 | - | errhint("Change the ownership of the index's table instead."))); | - |
| 16158 | - | /* quick hack to exit via the no-op path */ | - |
| 16159 | - | newOwnerId = tuple_class->relowner; | - |
| 16160 | - | } | - |
| 16161 | - | break; | - |
| 16162 | - | case RELKIND_PARTITIONED_INDEX: | - |
| 16163 | - | if (recursing) | - |
| 16164 | - | break; | - |
| 16165 | - | ereport(ERROR, | - |
| 16166 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 16167 | - | errmsg("cannot change owner of index \"%s\"", | - |
| 16168 | - | NameStr(tuple_class->relname)), | - |
| 16169 | - | errhint("Change the ownership of the index's table instead."))); | - |
| 16170 | - | break; | - |
| 16171 | - | case RELKIND_SEQUENCE: | - |
| 16172 | - | if (!recursing && | - |
| 16173 | - | tuple_class->relowner != newOwnerId) | - |
| 16174 | - | { | - |
| 16175 | - | /* if it's an owned sequence, disallow changing it by itself */ | - |
| 16176 | - | Oid tableId; | - |
| 16177 | - | int32 colId; | - |
| 16178 | - | - | |
| 16179 | - | if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) || | - |
| 16180 | - | sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId)) | - |
| 16181 | - | ereport(ERROR, | - |
| 16182 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | - |
| 16183 | - | errmsg("cannot change owner of sequence \"%s\"", | - |
| 16184 | - | NameStr(tuple_class->relname)), | - |
| 16185 | - | errdetail("Sequence \"%s\" is linked to table \"%s\".", | - |
| 16186 | - | NameStr(tuple_class->relname), | - |
| 16187 | - | get_rel_name(tableId)))); | - |
| 16188 | - | } | - |
| 16189 | - | break; | - |
| 16190 | - | case RELKIND_COMPOSITE_TYPE: | - |
| 16191 | - | if (recursing) | - |
| 16192 | - | break; | - |
| 16193 | - | ereport(ERROR, | - |
| 16194 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 16195 | - | errmsg("\"%s\" is a composite type", | - |
| 16196 | - | NameStr(tuple_class->relname)), | - |
| 16197 | - | /* translator: %s is an SQL ALTER command */ | - |
| 16198 | - | errhint("Use %s instead.", | - |
| 16199 | - | "ALTER TYPE"))); | - |
| 16200 | - | break; | - |
| 16201 | - | case RELKIND_TOASTVALUE: | - |
| 16202 | - | if (recursing) | - |
| 16203 | - | break; | - |
| 16204 | - | /* FALL THRU */ | - |
| 16205 | - | default: | - |
| 16206 | - | ereport(ERROR, | - |
| 16207 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 16208 | - | errmsg("cannot change owner of relation \"%s\"", | - |
| 16209 | - | NameStr(tuple_class->relname)), | - |
| 16210 | - | errdetail_relkind_not_supported(tuple_class->relkind))); | - |
| 16211 | - | } | - |
| 16212 | - | - | |
| 16213 | - | /* | - |
| 16214 | - | * If the new owner is the same as the existing owner, consider the | - |
| 16215 | - | * command to have succeeded. This is for dump restoration purposes. | - |
| 16216 | - | */ | - |
| 16217 | - | if (tuple_class->relowner != newOwnerId) | - |
| 16218 | - | { | - |
| 16219 | - | Datum repl_val[Natts_pg_class]; | - |
| 16220 | - | bool repl_null[Natts_pg_class]; | - |
| 16221 | - | bool repl_repl[Natts_pg_class]; | - |
| 16222 | - | Acl *newAcl; | - |
| 16223 | - | Datum aclDatum; | - |
| 16224 | - | bool isNull; | - |
| 16225 | - | HeapTuple newtuple; | - |
| 16226 | - | - | |
| 16227 | - | /* skip permission checks when recursing to index or toast table */ | - |
| 16228 | - | if (!recursing) | - |
| 16229 | - | { | - |
| 16230 | - | /* Superusers can always do it */ | - |
| 16231 | - | if (!superuser()) | - |
| 16232 | - | { | - |
| 16233 | - | Oid namespaceOid = tuple_class->relnamespace; | - |
| 16234 | - | AclResult aclresult; | - |
| 16235 | - | - | |
| 16236 | - | /* Otherwise, must be owner of the existing object */ | - |
| 16237 | - | if (!object_ownercheck(RelationRelationId, relationOid, GetUserId())) | - |
| 16238 | - | aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)), | - |
| 16239 | - | RelationGetRelationName(target_rel)); | - |
| 16240 | - | - | |
| 16241 | - | /* Must be able to become new owner */ | - |
| 16242 | - | check_can_set_role(GetUserId(), newOwnerId); | - |
| 16243 | - | - | |
| 16244 | - | /* New owner must have CREATE privilege on namespace */ | - |
| 16245 | - | aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId, | - |
| 16246 | - | ACL_CREATE); | - |
| 16247 | - | if (aclresult != ACLCHECK_OK) | - |
| 16248 | - | aclcheck_error(aclresult, OBJECT_SCHEMA, | - |
| 16249 | - | get_namespace_name(namespaceOid)); | - |
| 16250 | - | } | - |
| 16251 | - | } | - |
| 16252 | - | - | |
| 16253 | - | memset(repl_null, false, sizeof(repl_null)); | - |
| 16254 | - | memset(repl_repl, false, sizeof(repl_repl)); | - |
| 16255 | - | - | |
| 16256 | - | repl_repl[Anum_pg_class_relowner - 1] = true; | - |
| 16257 | - | repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId); | - |
| 16258 | - | - | |
| 16259 | - | /* | - |
| 16260 | - | * Determine the modified ACL for the new owner. This is only | - |
| 16261 | - | * necessary when the ACL is non-null. | - |
| 16262 | - | */ | - |
| 16263 | - | aclDatum = SysCacheGetAttr(RELOID, tuple, | - |
| 16264 | - | Anum_pg_class_relacl, | - |
| 16265 | - | &isNull); | - |
| 16266 | - | if (!isNull) | - |
| 16267 | - | { | - |
| 16268 | - | newAcl = aclnewowner(DatumGetAclP(aclDatum), | - |
| 16269 | - | tuple_class->relowner, newOwnerId); | - |
| 16270 | - | repl_repl[Anum_pg_class_relacl - 1] = true; | - |
| 16271 | - | repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl); | - |
| 16272 | - | } | - |
| 16273 | - | - | |
| 16274 | - | newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl); | - |
| 16275 | - | - | |
| 16276 | - | CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple); | - |
| 16277 | - | - | |
| 16278 | - | heap_freetuple(newtuple); | - |
| 16279 | - | - | |
| 16280 | - | /* | - |
| 16281 | - | * We must similarly update any per-column ACLs to reflect the new | - |
| 16282 | - | * owner; for neatness reasons that's split out as a subroutine. | - |
| 16283 | - | */ | - |
| 16284 | - | change_owner_fix_column_acls(relationOid, | - |
| 16285 | - | tuple_class->relowner, | - |
| 16286 | - | newOwnerId); | - |
| 16287 | - | - | |
| 16288 | - | /* | - |
| 16289 | - | * Update owner dependency reference, if any. A composite type has | - |
| 16290 | - | * none, because it's tracked for the pg_type entry instead of here; | - |
| 16291 | - | * indexes and TOAST tables don't have their own entries either. | - |
| 16292 | - | */ | - |
| 16293 | - | if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE && | - |
| 16294 | - | tuple_class->relkind != RELKIND_INDEX && | - |
| 16295 | - | tuple_class->relkind != RELKIND_PARTITIONED_INDEX && | - |
| 16296 | - | tuple_class->relkind != RELKIND_TOASTVALUE) | - |
| 16297 | - | changeDependencyOnOwner(RelationRelationId, relationOid, | - |
| 16298 | - | newOwnerId); | - |
| 16299 | - | - | |
| 16300 | - | /* | - |
| 16301 | - | * Also change the ownership of the table's row type, if it has one | - |
| 16302 | - | */ | - |
| 16303 | - | if (OidIsValid(tuple_class->reltype)) | - |
| 16304 | - | AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId); | - |
| 16305 | - | - | |
| 16306 | - | /* | - |
| 16307 | - | * If we are operating on a table or materialized view, also change | - |
| 16308 | - | * the ownership of any indexes and sequences that belong to the | - |
| 16309 | - | * relation, as well as its toast table (if it has one). | - |
| 16310 | - | */ | - |
| 16311 | - | if (tuple_class->relkind == RELKIND_RELATION || | - |
| 16312 | - | tuple_class->relkind == RELKIND_PARTITIONED_TABLE || | - |
| 16313 | - | tuple_class->relkind == RELKIND_MATVIEW || | - |
| 16314 | - | tuple_class->relkind == RELKIND_TOASTVALUE) | - |
| 16315 | - | { | - |
| 16316 | - | List *index_oid_list; | - |
| 16317 | - | ListCell *i; | - |
| 16318 | - | - | |
| 16319 | - | /* Find all the indexes belonging to this relation */ | - |
| 16320 | - | index_oid_list = RelationGetIndexList(target_rel); | - |
| 16321 | - | - | |
| 16322 | - | /* For each index, recursively change its ownership */ | - |
| 16323 | - | foreach(i, index_oid_list) | - |
| 16324 | - | ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode); | - |
| 16325 | - | - | |
| 16326 | - | list_free(index_oid_list); | - |
| 16327 | - | } | - |
| 16328 | - | - | |
| 16329 | - | /* If it has a toast table, recurse to change its ownership */ | - |
| 16330 | - | if (tuple_class->reltoastrelid != InvalidOid) | - |
| 16331 | - | ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId, | - |
| 16332 | - | true, lockmode); | - |
| 16333 | - | - | |
| 16334 | - | /* If it has dependent sequences, recurse to change them too */ | - |
| 16335 | - | change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode); | - |
| 16336 | - | } | - |
| 16337 | - | - | |
| 16338 | - | InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0); | - |
| 16339 | - | - | |
| 16340 | - | ReleaseSysCache(tuple); | - |
| 16341 | - | table_close(class_rel, RowExclusiveLock); | - |
| 16342 | - | relation_close(target_rel, NoLock); | - |
| 16343 | - | } | - |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 19623 | - | RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, | - |
| 19624 | - | void *arg) | - |
| 19625 | - | { | - |
| 19626 | - | Node *stmt = (Node *) arg; | - |
| 19627 | - | ObjectType reltype; | - |
| 19628 | - | HeapTuple tuple; | - |
| 19629 | - | Form_pg_class classform; | - |
| 19630 | - | AclResult aclresult; | - |
| 19631 | - | char relkind; | - |
| 19632 | - | - | |
| 19633 | - | tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); | - |
| 19634 | - | if (!HeapTupleIsValid(tuple)) | - |
| 19635 | - | return; /* concurrently dropped */ | - |
| 19636 | - | classform = (Form_pg_class) GETSTRUCT(tuple); | - |
| 19637 | - | relkind = classform->relkind; | - |
| 19638 | - | - | |
| 19639 | - | /* Must own relation. */ | - |
| 19640 | - | if (!object_ownercheck(RelationRelationId, relid, GetUserId())) | - |
| 19641 | - | aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname); | - |
| 19642 | - | - | |
| 19643 | - | /* No system table modifications unless explicitly allowed. */ | - |
| 19644 | - | if (!allowSystemTableMods && IsSystemClass(relid, classform)) | - |
| 19645 | - | ereport(ERROR, | - |
| 19646 | - | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), | - |
| 19647 | - | errmsg("permission denied: \"%s\" is a system catalog", | - |
| 19648 | - | rv->relname))); | - |
| 19649 | - | - | |
| 19650 | - | /* | - |
| 19651 | - | * Extract the specified relation type from the statement parse tree. | - |
| 19652 | - | * | - |
| 19653 | - | * Also, for ALTER .. RENAME, check permissions: the user must (still) | - |
| 19654 | - | * have CREATE rights on the containing namespace. | - |
| 19655 | - | */ | - |
| 19656 | - | if (IsA(stmt, RenameStmt)) | - |
| 19657 | - | { | - |
| 19658 | - | aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace, | - |
| 19659 | - | GetUserId(), ACL_CREATE); | - |
| 19660 | - | if (aclresult != ACLCHECK_OK) | - |
| 19661 | - | aclcheck_error(aclresult, OBJECT_SCHEMA, | - |
| 19662 | - | get_namespace_name(classform->relnamespace)); | - |
| 19663 | - | reltype = ((RenameStmt *) stmt)->renameType; | - |
| 19664 | - | } | - |
| 19665 | - | else if (IsA(stmt, AlterObjectSchemaStmt)) | - |
| 19666 | - | reltype = ((AlterObjectSchemaStmt *) stmt)->objectType; | - |
| 19667 | - | - | |
| 19668 | - | else if (IsA(stmt, AlterTableStmt)) | - |
| 19669 | - | reltype = ((AlterTableStmt *) stmt)->objtype; | - |
| 19670 | - | else | - |
| 19671 | - | { | - |
| 19672 | - | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt)); | - |
| 19673 | - | reltype = OBJECT_TABLE; /* placate compiler */ | - |
| 19674 | - | } | - |
| 19675 | - | - | |
| 19676 | - | /* | - |
| 19677 | - | * For compatibility with prior releases, we allow ALTER TABLE to be used | - |
| 19678 | - | * with most other types of relations (but not composite types). We allow | - |
| 19679 | - | * similar flexibility for ALTER INDEX in the case of RENAME, but not | - |
| 19680 | - | * otherwise. Otherwise, the user must select the correct form of the | - |
| 19681 | - | * command for the relation at issue. | - |
| 19682 | - | */ | - |
| 19683 | - | if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE) | - |
| 19684 | - | ereport(ERROR, | - |
| 19685 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19686 | - | errmsg("\"%s\" is not a sequence", rv->relname))); | - |
| 19687 | - | - | |
| 19688 | - | if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW) | - |
| 19689 | - | ereport(ERROR, | - |
| 19690 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19691 | - | errmsg("\"%s\" is not a view", rv->relname))); | - |
| 19692 | - | - | |
| 19693 | - | if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW) | - |
| 19694 | - | ereport(ERROR, | - |
| 19695 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19696 | - | errmsg("\"%s\" is not a materialized view", rv->relname))); | - |
| 19697 | - | - | |
| 19698 | - | if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE) | - |
| 19699 | - | ereport(ERROR, | - |
| 19700 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19701 | - | errmsg("\"%s\" is not a foreign table", rv->relname))); | - |
| 19702 | - | - | |
| 19703 | - | if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE) | - |
| 19704 | - | ereport(ERROR, | - |
| 19705 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19706 | - | errmsg("\"%s\" is not a composite type", rv->relname))); | - |
| 19707 | - | - | |
| 19708 | 18081 | if (reltype == OBJECT_PROPGRAPH && relkind != RELKIND_PROPGRAPH) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 19709 | 0 | ereport(ERROR, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 19710 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 19711 | - | errmsg("\"%s\" is not a property graph", rv->relname))); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 19712 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 19713 | - | if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX && | - |
| 19714 | - | relkind != RELKIND_PARTITIONED_INDEX | - |
| 19715 | - | && !IsA(stmt, RenameStmt)) | - |
| 19716 | - | ereport(ERROR, | - |
| 19717 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19718 | - | errmsg("\"%s\" is not an index", rv->relname))); | - |
| 19719 | - | - | |
| 19720 | - | /* | - |
| 19721 | - | * Don't allow ALTER TABLE on composite types. We want people to use ALTER | - |
| 19722 | - | * TYPE for that. | - |
| 19723 | - | */ | - |
| 19724 | - | if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE) | - |
| 19725 | - | ereport(ERROR, | - |
| 19726 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19727 | - | errmsg("\"%s\" is a composite type", rv->relname), | - |
| 19728 | - | /* translator: %s is an SQL ALTER command */ | - |
| 19729 | - | errhint("Use %s instead.", | - |
| 19730 | - | "ALTER TYPE"))); | - |
| 19731 | - | - | |
| 19732 | - | /* | - |
| 19733 | - | * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved | - |
| 19734 | - | * to a different schema, such as indexes and TOAST tables. | - |
| 19735 | - | */ | - |
| 19736 | - | if (IsA(stmt, AlterObjectSchemaStmt)) | - |
| 19737 | - | { | - |
| 19738 | - | if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) | - |
| 19739 | - | ereport(ERROR, | - |
| 19740 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19741 | - | errmsg("cannot change schema of index \"%s\"", | - |
| 19742 | - | rv->relname), | - |
| 19743 | - | errhint("Change the schema of the table instead."))); | - |
| 19744 | - | else if (relkind == RELKIND_COMPOSITE_TYPE) | - |
| 19745 | - | ereport(ERROR, | - |
| 19746 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19747 | - | errmsg("cannot change schema of composite type \"%s\"", | - |
| 19748 | - | rv->relname), | - |
| 19749 | - | /* translator: %s is an SQL ALTER command */ | - |
| 19750 | - | errhint("Use %s instead.", | - |
| 19751 | - | "ALTER TYPE"))); | - |
| 19752 | - | else if (relkind == RELKIND_TOASTVALUE) | - |
| 19753 | - | ereport(ERROR, | - |
| 19754 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | - |
| 19755 | - | errmsg("cannot change schema of TOAST table \"%s\"", | - |
| 19756 | - | rv->relname), | - |
| 19757 | - | errhint("Change the schema of the table instead."))); | - |
| 19758 | - | } | - |
| 19759 | - | - | |
| 19760 | - | ReleaseSysCache(tuple); | - |
| 19761 | - | } | - |