LCOV - code coverage report
Current view: top level - src/backend/commands - alter.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 282 347 81.3 %
Date: 2020-06-01 09:07:10 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * alter.c
       4             :  *    Drivers for generic alter commands
       5             :  *
       6             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/commands/alter.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/htup_details.h"
      18             : #include "access/relation.h"
      19             : #include "access/sysattr.h"
      20             : #include "access/table.h"
      21             : #include "catalog/dependency.h"
      22             : #include "catalog/indexing.h"
      23             : #include "catalog/namespace.h"
      24             : #include "catalog/objectaccess.h"
      25             : #include "catalog/pg_collation.h"
      26             : #include "catalog/pg_conversion.h"
      27             : #include "catalog/pg_event_trigger.h"
      28             : #include "catalog/pg_foreign_data_wrapper.h"
      29             : #include "catalog/pg_foreign_server.h"
      30             : #include "catalog/pg_language.h"
      31             : #include "catalog/pg_largeobject.h"
      32             : #include "catalog/pg_largeobject_metadata.h"
      33             : #include "catalog/pg_namespace.h"
      34             : #include "catalog/pg_opclass.h"
      35             : #include "catalog/pg_opfamily.h"
      36             : #include "catalog/pg_proc.h"
      37             : #include "catalog/pg_statistic_ext.h"
      38             : #include "catalog/pg_subscription.h"
      39             : #include "catalog/pg_ts_config.h"
      40             : #include "catalog/pg_ts_dict.h"
      41             : #include "catalog/pg_ts_parser.h"
      42             : #include "catalog/pg_ts_template.h"
      43             : #include "commands/alter.h"
      44             : #include "commands/collationcmds.h"
      45             : #include "commands/conversioncmds.h"
      46             : #include "commands/dbcommands.h"
      47             : #include "commands/defrem.h"
      48             : #include "commands/event_trigger.h"
      49             : #include "commands/extension.h"
      50             : #include "commands/policy.h"
      51             : #include "commands/proclang.h"
      52             : #include "commands/publicationcmds.h"
      53             : #include "commands/schemacmds.h"
      54             : #include "commands/subscriptioncmds.h"
      55             : #include "commands/tablecmds.h"
      56             : #include "commands/tablespace.h"
      57             : #include "commands/trigger.h"
      58             : #include "commands/typecmds.h"
      59             : #include "commands/user.h"
      60             : #include "miscadmin.h"
      61             : #include "parser/parse_func.h"
      62             : #include "rewrite/rewriteDefine.h"
      63             : #include "tcop/utility.h"
      64             : #include "utils/builtins.h"
      65             : #include "utils/fmgroids.h"
      66             : #include "utils/lsyscache.h"
      67             : #include "utils/rel.h"
      68             : #include "utils/syscache.h"
      69             : 
      70             : static Oid  AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
      71             : 
      72             : /*
      73             :  * Raise an error to the effect that an object of the given name is already
      74             :  * present in the given namespace.
      75             :  */
      76             : static void
      77          16 : report_name_conflict(Oid classId, const char *name)
      78             : {
      79             :     char       *msgfmt;
      80             : 
      81          16 :     switch (classId)
      82             :     {
      83           4 :         case EventTriggerRelationId:
      84           4 :             msgfmt = gettext_noop("event trigger \"%s\" already exists");
      85           4 :             break;
      86           4 :         case ForeignDataWrapperRelationId:
      87           4 :             msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
      88           4 :             break;
      89           4 :         case ForeignServerRelationId:
      90           4 :             msgfmt = gettext_noop("server \"%s\" already exists");
      91           4 :             break;
      92           4 :         case LanguageRelationId:
      93           4 :             msgfmt = gettext_noop("language \"%s\" already exists");
      94           4 :             break;
      95           0 :         case PublicationRelationId:
      96           0 :             msgfmt = gettext_noop("publication \"%s\" already exists");
      97           0 :             break;
      98           0 :         case SubscriptionRelationId:
      99           0 :             msgfmt = gettext_noop("subscription \"%s\" already exists");
     100           0 :             break;
     101           0 :         default:
     102           0 :             elog(ERROR, "unsupported object class %u", classId);
     103             :             break;
     104             :     }
     105             : 
     106          16 :     ereport(ERROR,
     107             :             (errcode(ERRCODE_DUPLICATE_OBJECT),
     108             :              errmsg(msgfmt, name)));
     109             : }
     110             : 
     111             : static void
     112          48 : report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
     113             : {
     114             :     char       *msgfmt;
     115             : 
     116             :     Assert(OidIsValid(nspOid));
     117             : 
     118          48 :     switch (classId)
     119             :     {
     120           8 :         case ConversionRelationId:
     121             :             Assert(OidIsValid(nspOid));
     122           8 :             msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
     123           8 :             break;
     124           8 :         case StatisticExtRelationId:
     125             :             Assert(OidIsValid(nspOid));
     126           8 :             msgfmt = gettext_noop("statistics object \"%s\" already exists in schema \"%s\"");
     127           8 :             break;
     128           8 :         case TSParserRelationId:
     129             :             Assert(OidIsValid(nspOid));
     130           8 :             msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
     131           8 :             break;
     132           8 :         case TSDictionaryRelationId:
     133             :             Assert(OidIsValid(nspOid));
     134           8 :             msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
     135           8 :             break;
     136           8 :         case TSTemplateRelationId:
     137             :             Assert(OidIsValid(nspOid));
     138           8 :             msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
     139           8 :             break;
     140           8 :         case TSConfigRelationId:
     141             :             Assert(OidIsValid(nspOid));
     142           8 :             msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
     143           8 :             break;
     144           0 :         default:
     145           0 :             elog(ERROR, "unsupported object class %u", classId);
     146             :             break;
     147             :     }
     148             : 
     149          48 :     ereport(ERROR,
     150             :             (errcode(ERRCODE_DUPLICATE_OBJECT),
     151             :              errmsg(msgfmt, name, get_namespace_name(nspOid))));
     152             : }
     153             : 
     154             : /*
     155             :  * AlterObjectRename_internal
     156             :  *
     157             :  * Generic function to rename the given object, for simple cases (won't
     158             :  * work for tables, nor other cases where we need to do more than change
     159             :  * the name column of a single catalog entry).
     160             :  *
     161             :  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
     162             :  * objectId: OID of object to be renamed
     163             :  * new_name: CString representation of new name
     164             :  */
     165             : static void
     166         246 : AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
     167             : {
     168         246 :     Oid         classId = RelationGetRelid(rel);
     169         246 :     int         oidCacheId = get_object_catcache_oid(classId);
     170         246 :     int         nameCacheId = get_object_catcache_name(classId);
     171         246 :     AttrNumber  Anum_name = get_object_attnum_name(classId);
     172         246 :     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
     173         246 :     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
     174             :     HeapTuple   oldtup;
     175             :     HeapTuple   newtup;
     176             :     Datum       datum;
     177             :     bool        isnull;
     178             :     Oid         namespaceId;
     179             :     Oid         ownerId;
     180             :     char       *old_name;
     181             :     AclResult   aclresult;
     182             :     Datum      *values;
     183             :     bool       *nulls;
     184             :     bool       *replaces;
     185             :     NameData    nameattrdata;
     186             : 
     187         246 :     oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
     188         246 :     if (!HeapTupleIsValid(oldtup))
     189           0 :         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
     190             :              objectId, RelationGetRelationName(rel));
     191             : 
     192         246 :     datum = heap_getattr(oldtup, Anum_name,
     193             :                          RelationGetDescr(rel), &isnull);
     194             :     Assert(!isnull);
     195         246 :     old_name = NameStr(*(DatumGetName(datum)));
     196             : 
     197             :     /* Get OID of namespace */
     198         246 :     if (Anum_namespace > 0)
     199             :     {
     200         168 :         datum = heap_getattr(oldtup, Anum_namespace,
     201             :                              RelationGetDescr(rel), &isnull);
     202             :         Assert(!isnull);
     203         168 :         namespaceId = DatumGetObjectId(datum);
     204             :     }
     205             :     else
     206          78 :         namespaceId = InvalidOid;
     207             : 
     208             :     /* Permission checks ... superusers can always do it */
     209         246 :     if (!superuser())
     210             :     {
     211             :         /* Fail if object does not have an explicit owner */
     212         148 :         if (Anum_owner <= 0)
     213           0 :             ereport(ERROR,
     214             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     215             :                      errmsg("must be superuser to rename %s",
     216             :                             getObjectDescriptionOids(classId, objectId))));
     217             : 
     218             :         /* Otherwise, must be owner of the existing object */
     219         148 :         datum = heap_getattr(oldtup, Anum_owner,
     220             :                              RelationGetDescr(rel), &isnull);
     221             :         Assert(!isnull);
     222         148 :         ownerId = DatumGetObjectId(datum);
     223             : 
     224         148 :         if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
     225          44 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
     226             :                            old_name);
     227             : 
     228             :         /* User must have CREATE privilege on the namespace */
     229         104 :         if (OidIsValid(namespaceId))
     230             :         {
     231          96 :             aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
     232             :                                               ACL_CREATE);
     233          96 :             if (aclresult != ACLCHECK_OK)
     234           0 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
     235           0 :                                get_namespace_name(namespaceId));
     236             :         }
     237             :     }
     238             : 
     239             :     /*
     240             :      * Check for duplicate name (more friendly than unique-index failure).
     241             :      * Since this is just a friendliness check, we can just skip it in cases
     242             :      * where there isn't suitable support.
     243             :      */
     244         202 :     if (classId == ProcedureRelationId)
     245             :     {
     246          48 :         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
     247             : 
     248          48 :         IsThereFunctionInNamespace(new_name, proc->pronargs,
     249             :                                    &proc->proargtypes, proc->pronamespace);
     250             :     }
     251         154 :     else if (classId == CollationRelationId)
     252             :     {
     253           0 :         Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(oldtup);
     254             : 
     255           0 :         IsThereCollationInNamespace(new_name, coll->collnamespace);
     256             :     }
     257         154 :     else if (classId == OperatorClassRelationId)
     258             :     {
     259          12 :         Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
     260             : 
     261          12 :         IsThereOpClassInNamespace(new_name, opc->opcmethod,
     262             :                                   opc->opcnamespace);
     263             :     }
     264         142 :     else if (classId == OperatorFamilyRelationId)
     265             :     {
     266          12 :         Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(oldtup);
     267             : 
     268          12 :         IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
     269             :                                    opf->opfnamespace);
     270             :     }
     271         130 :     else if (classId == SubscriptionRelationId)
     272             :     {
     273          10 :         if (SearchSysCacheExists2(SUBSCRIPTIONNAME, MyDatabaseId,
     274             :                                   CStringGetDatum(new_name)))
     275           0 :             report_name_conflict(classId, new_name);
     276             : 
     277             :         /* Also enforce regression testing naming rules, if enabled */
     278             : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
     279             :         if (strncmp(new_name, "regress_", 8) != 0)
     280             :             elog(WARNING, "subscriptions created by regression test cases should have names starting with \"regress_\"");
     281             : #endif
     282             :     }
     283         120 :     else if (nameCacheId >= 0)
     284             :     {
     285         120 :         if (OidIsValid(namespaceId))
     286             :         {
     287          64 :             if (SearchSysCacheExists2(nameCacheId,
     288             :                                       CStringGetDatum(new_name),
     289             :                                       ObjectIdGetDatum(namespaceId)))
     290          24 :                 report_namespace_conflict(classId, new_name, namespaceId);
     291             :         }
     292             :         else
     293             :         {
     294          56 :             if (SearchSysCacheExists1(nameCacheId,
     295             :                                       CStringGetDatum(new_name)))
     296          16 :                 report_name_conflict(classId, new_name);
     297             :         }
     298             :     }
     299             : 
     300             :     /* Build modified tuple */
     301         146 :     values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
     302         146 :     nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
     303         146 :     replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
     304         146 :     namestrcpy(&nameattrdata, new_name);
     305         146 :     values[Anum_name - 1] = NameGetDatum(&nameattrdata);
     306         146 :     replaces[Anum_name - 1] = true;
     307         146 :     newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
     308             :                                values, nulls, replaces);
     309             : 
     310             :     /* Perform actual update */
     311         146 :     CatalogTupleUpdate(rel, &oldtup->t_self, newtup);
     312             : 
     313         146 :     InvokeObjectPostAlterHook(classId, objectId, 0);
     314             : 
     315             :     /* Release memory */
     316         146 :     pfree(values);
     317         146 :     pfree(nulls);
     318         146 :     pfree(replaces);
     319         146 :     heap_freetuple(newtup);
     320             : 
     321         146 :     ReleaseSysCache(oldtup);
     322         146 : }
     323             : 
     324             : /*
     325             :  * Executes an ALTER OBJECT / RENAME TO statement.  Based on the object
     326             :  * type, the function appropriate to that type is executed.
     327             :  *
     328             :  * Return value is the address of the renamed object.
     329             :  */
     330             : ObjectAddress
     331         742 : ExecRenameStmt(RenameStmt *stmt)
     332             : {
     333         742 :     switch (stmt->renameType)
     334             :     {
     335          52 :         case OBJECT_TABCONSTRAINT:
     336             :         case OBJECT_DOMCONSTRAINT:
     337          52 :             return RenameConstraint(stmt);
     338             : 
     339           0 :         case OBJECT_DATABASE:
     340           0 :             return RenameDatabase(stmt->subname, stmt->newname);
     341             : 
     342          12 :         case OBJECT_ROLE:
     343          12 :             return RenameRole(stmt->subname, stmt->newname);
     344             : 
     345           4 :         case OBJECT_SCHEMA:
     346           4 :             return RenameSchema(stmt->subname, stmt->newname);
     347             : 
     348           4 :         case OBJECT_TABLESPACE:
     349           4 :             return RenameTableSpace(stmt->subname, stmt->newname);
     350             : 
     351         160 :         case OBJECT_TABLE:
     352             :         case OBJECT_SEQUENCE:
     353             :         case OBJECT_VIEW:
     354             :         case OBJECT_MATVIEW:
     355             :         case OBJECT_INDEX:
     356             :         case OBJECT_FOREIGN_TABLE:
     357         160 :             return RenameRelation(stmt);
     358             : 
     359         194 :         case OBJECT_COLUMN:
     360             :         case OBJECT_ATTRIBUTE:
     361         194 :             return renameatt(stmt);
     362             : 
     363          24 :         case OBJECT_RULE:
     364          24 :             return RenameRewriteRule(stmt->relation, stmt->subname,
     365          24 :                                      stmt->newname);
     366             : 
     367           8 :         case OBJECT_TRIGGER:
     368           8 :             return renametrig(stmt);
     369             : 
     370          12 :         case OBJECT_POLICY:
     371          12 :             return rename_policy(stmt);
     372             : 
     373          22 :         case OBJECT_DOMAIN:
     374             :         case OBJECT_TYPE:
     375          22 :             return RenameType(stmt);
     376             : 
     377         250 :         case OBJECT_AGGREGATE:
     378             :         case OBJECT_COLLATION:
     379             :         case OBJECT_CONVERSION:
     380             :         case OBJECT_EVENT_TRIGGER:
     381             :         case OBJECT_FDW:
     382             :         case OBJECT_FOREIGN_SERVER:
     383             :         case OBJECT_FUNCTION:
     384             :         case OBJECT_OPCLASS:
     385             :         case OBJECT_OPFAMILY:
     386             :         case OBJECT_LANGUAGE:
     387             :         case OBJECT_PROCEDURE:
     388             :         case OBJECT_ROUTINE:
     389             :         case OBJECT_STATISTIC_EXT:
     390             :         case OBJECT_TSCONFIGURATION:
     391             :         case OBJECT_TSDICTIONARY:
     392             :         case OBJECT_TSPARSER:
     393             :         case OBJECT_TSTEMPLATE:
     394             :         case OBJECT_PUBLICATION:
     395             :         case OBJECT_SUBSCRIPTION:
     396             :             {
     397             :                 ObjectAddress address;
     398             :                 Relation    catalog;
     399             :                 Relation    relation;
     400             : 
     401         250 :                 address = get_object_address(stmt->renameType,
     402             :                                              stmt->object,
     403             :                                              &relation,
     404             :                                              AccessExclusiveLock, false);
     405             :                 Assert(relation == NULL);
     406             : 
     407         246 :                 catalog = table_open(address.classId, RowExclusiveLock);
     408         246 :                 AlterObjectRename_internal(catalog,
     409             :                                            address.objectId,
     410         246 :                                            stmt->newname);
     411         146 :                 table_close(catalog, RowExclusiveLock);
     412             : 
     413         146 :                 return address;
     414             :             }
     415             : 
     416           0 :         default:
     417           0 :             elog(ERROR, "unrecognized rename stmt type: %d",
     418             :                  (int) stmt->renameType);
     419             :             return InvalidObjectAddress;    /* keep compiler happy */
     420             :     }
     421             : }
     422             : 
     423             : /*
     424             :  * Executes an ALTER OBJECT / [NO] DEPENDS ON EXTENSION statement.
     425             :  *
     426             :  * Return value is the address of the altered object.  refAddress is an output
     427             :  * argument which, if not null, receives the address of the object that the
     428             :  * altered object now depends on.
     429             :  */
     430             : ObjectAddress
     431          46 : ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress)
     432             : {
     433             :     ObjectAddress address;
     434             :     ObjectAddress refAddr;
     435             :     Relation    rel;
     436             : 
     437             :     address =
     438          46 :         get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
     439             :                               &rel, AccessExclusiveLock, false);
     440             : 
     441             :     /*
     442             :      * Verify that the user is entitled to run the command.
     443             :      *
     444             :      * We don't check any privileges on the extension, because that's not
     445             :      * needed.  The object owner is stipulating, by running this command, that
     446             :      * the extension owner can drop the object whenever they feel like it,
     447             :      * which is not considered a problem.
     448             :      */
     449          46 :     check_object_ownership(GetUserId(),
     450             :                            stmt->objectType, address, stmt->object, rel);
     451             : 
     452             :     /*
     453             :      * If a relation was involved, it would have been opened and locked. We
     454             :      * don't need the relation here, but we'll retain the lock until commit.
     455             :      */
     456          46 :     if (rel)
     457          34 :         table_close(rel, NoLock);
     458             : 
     459          46 :     refAddr = get_object_address(OBJECT_EXTENSION, (Node *) stmt->extname,
     460             :                                  &rel, AccessExclusiveLock, false);
     461             :     Assert(rel == NULL);
     462          46 :     if (refAddress)
     463          46 :         *refAddress = refAddr;
     464             : 
     465          46 :     if (stmt->remove)
     466             :     {
     467           8 :         deleteDependencyRecordsForSpecific(address.classId, address.objectId,
     468             :                                            DEPENDENCY_AUTO_EXTENSION,
     469             :                                            refAddr.classId, refAddr.objectId);
     470             :     }
     471             :     else
     472             :     {
     473             :         List       *currexts;
     474             : 
     475             :         /* Avoid duplicates */
     476          38 :         currexts = getAutoExtensionsOfObject(address.classId,
     477             :                                              address.objectId);
     478          38 :         if (!list_member_oid(currexts, refAddr.objectId))
     479          36 :             recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
     480             :     }
     481             : 
     482          46 :     return address;
     483             : }
     484             : 
     485             : /*
     486             :  * Executes an ALTER OBJECT / SET SCHEMA statement.  Based on the object
     487             :  * type, the function appropriate to that type is executed.
     488             :  *
     489             :  * Return value is that of the altered object.
     490             :  *
     491             :  * oldSchemaAddr is an output argument which, if not NULL, is set to the object
     492             :  * address of the original schema.
     493             :  */
     494             : ObjectAddress
     495         244 : ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
     496             :                           ObjectAddress *oldSchemaAddr)
     497             : {
     498             :     ObjectAddress address;
     499             :     Oid         oldNspOid;
     500             : 
     501         244 :     switch (stmt->objectType)
     502             :     {
     503           0 :         case OBJECT_EXTENSION:
     504           0 :             address = AlterExtensionNamespace(strVal((Value *) stmt->object), stmt->newschema,
     505             :                                               oldSchemaAddr ? &oldNspOid : NULL);
     506           0 :             break;
     507             : 
     508          62 :         case OBJECT_FOREIGN_TABLE:
     509             :         case OBJECT_SEQUENCE:
     510             :         case OBJECT_TABLE:
     511             :         case OBJECT_VIEW:
     512             :         case OBJECT_MATVIEW:
     513          62 :             address = AlterTableNamespace(stmt,
     514             :                                           oldSchemaAddr ? &oldNspOid : NULL);
     515          60 :             break;
     516             : 
     517          12 :         case OBJECT_DOMAIN:
     518             :         case OBJECT_TYPE:
     519          12 :             address = AlterTypeNamespace(castNode(List, stmt->object), stmt->newschema,
     520             :                                          stmt->objectType,
     521             :                                          oldSchemaAddr ? &oldNspOid : NULL);
     522          12 :             break;
     523             : 
     524             :             /* generic code path */
     525         170 :         case OBJECT_AGGREGATE:
     526             :         case OBJECT_COLLATION:
     527             :         case OBJECT_CONVERSION:
     528             :         case OBJECT_FUNCTION:
     529             :         case OBJECT_OPERATOR:
     530             :         case OBJECT_OPCLASS:
     531             :         case OBJECT_OPFAMILY:
     532             :         case OBJECT_PROCEDURE:
     533             :         case OBJECT_ROUTINE:
     534             :         case OBJECT_STATISTIC_EXT:
     535             :         case OBJECT_TSCONFIGURATION:
     536             :         case OBJECT_TSDICTIONARY:
     537             :         case OBJECT_TSPARSER:
     538             :         case OBJECT_TSTEMPLATE:
     539          90 :             {
     540             :                 Relation    catalog;
     541             :                 Relation    relation;
     542             :                 Oid         classId;
     543             :                 Oid         nspOid;
     544             : 
     545         170 :                 address = get_object_address(stmt->objectType,
     546             :                                              stmt->object,
     547             :                                              &relation,
     548             :                                              AccessExclusiveLock,
     549             :                                              false);
     550             :                 Assert(relation == NULL);
     551         166 :                 classId = address.classId;
     552         166 :                 catalog = table_open(classId, RowExclusiveLock);
     553         166 :                 nspOid = LookupCreationNamespace(stmt->newschema);
     554             : 
     555         166 :                 oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
     556             :                                                           nspOid);
     557          90 :                 table_close(catalog, RowExclusiveLock);
     558             :             }
     559          90 :             break;
     560             : 
     561           0 :         default:
     562           0 :             elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
     563             :                  (int) stmt->objectType);
     564             :             return InvalidObjectAddress;    /* keep compiler happy */
     565             :     }
     566             : 
     567         162 :     if (oldSchemaAddr)
     568         162 :         ObjectAddressSet(*oldSchemaAddr, NamespaceRelationId, oldNspOid);
     569             : 
     570         162 :     return address;
     571             : }
     572             : 
     573             : /*
     574             :  * Change an object's namespace given its classOid and object Oid.
     575             :  *
     576             :  * Objects that don't have a namespace should be ignored.
     577             :  *
     578             :  * This function is currently used only by ALTER EXTENSION SET SCHEMA,
     579             :  * so it only needs to cover object types that can be members of an
     580             :  * extension, and it doesn't have to deal with certain special cases
     581             :  * such as not wanting to process array types --- those should never
     582             :  * be direct members of an extension anyway.  Nonetheless, we insist
     583             :  * on listing all OCLASS types in the switch.
     584             :  *
     585             :  * Returns the OID of the object's previous namespace, or InvalidOid if
     586             :  * object doesn't have a schema.
     587             :  */
     588             : Oid
     589           0 : AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
     590             :                          ObjectAddresses *objsMoved)
     591             : {
     592           0 :     Oid         oldNspOid = InvalidOid;
     593             :     ObjectAddress dep;
     594             : 
     595           0 :     dep.classId = classId;
     596           0 :     dep.objectId = objid;
     597           0 :     dep.objectSubId = 0;
     598             : 
     599           0 :     switch (getObjectClass(&dep))
     600             :     {
     601           0 :         case OCLASS_CLASS:
     602             :             {
     603             :                 Relation    rel;
     604             : 
     605           0 :                 rel = relation_open(objid, AccessExclusiveLock);
     606           0 :                 oldNspOid = RelationGetNamespace(rel);
     607             : 
     608           0 :                 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
     609             : 
     610           0 :                 relation_close(rel, NoLock);
     611           0 :                 break;
     612             :             }
     613             : 
     614           0 :         case OCLASS_TYPE:
     615           0 :             oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
     616           0 :             break;
     617             : 
     618           0 :         case OCLASS_PROC:
     619             :         case OCLASS_COLLATION:
     620             :         case OCLASS_CONVERSION:
     621             :         case OCLASS_OPERATOR:
     622             :         case OCLASS_OPCLASS:
     623             :         case OCLASS_OPFAMILY:
     624             :         case OCLASS_STATISTIC_EXT:
     625             :         case OCLASS_TSPARSER:
     626             :         case OCLASS_TSDICT:
     627             :         case OCLASS_TSTEMPLATE:
     628             :         case OCLASS_TSCONFIG:
     629             :             {
     630             :                 Relation    catalog;
     631             : 
     632           0 :                 catalog = table_open(classId, RowExclusiveLock);
     633             : 
     634           0 :                 oldNspOid = AlterObjectNamespace_internal(catalog, objid,
     635             :                                                           nspOid);
     636             : 
     637           0 :                 table_close(catalog, RowExclusiveLock);
     638             :             }
     639           0 :             break;
     640             : 
     641           0 :         case OCLASS_CAST:
     642             :         case OCLASS_CONSTRAINT:
     643             :         case OCLASS_DEFAULT:
     644             :         case OCLASS_LANGUAGE:
     645             :         case OCLASS_LARGEOBJECT:
     646             :         case OCLASS_AM:
     647             :         case OCLASS_AMOP:
     648             :         case OCLASS_AMPROC:
     649             :         case OCLASS_REWRITE:
     650             :         case OCLASS_TRIGGER:
     651             :         case OCLASS_SCHEMA:
     652             :         case OCLASS_ROLE:
     653             :         case OCLASS_DATABASE:
     654             :         case OCLASS_TBLSPACE:
     655             :         case OCLASS_FDW:
     656             :         case OCLASS_FOREIGN_SERVER:
     657             :         case OCLASS_USER_MAPPING:
     658             :         case OCLASS_DEFACL:
     659             :         case OCLASS_EXTENSION:
     660             :         case OCLASS_EVENT_TRIGGER:
     661             :         case OCLASS_POLICY:
     662             :         case OCLASS_PUBLICATION:
     663             :         case OCLASS_PUBLICATION_REL:
     664             :         case OCLASS_SUBSCRIPTION:
     665             :         case OCLASS_TRANSFORM:
     666             :             /* ignore object types that don't have schema-qualified names */
     667           0 :             break;
     668             : 
     669             :             /*
     670             :              * There's intentionally no default: case here; we want the
     671             :              * compiler to warn if a new OCLASS hasn't been handled above.
     672             :              */
     673             :     }
     674             : 
     675           0 :     return oldNspOid;
     676             : }
     677             : 
     678             : /*
     679             :  * Generic function to change the namespace of a given object, for simple
     680             :  * cases (won't work for tables, nor other cases where we need to do more
     681             :  * than change the namespace column of a single catalog entry).
     682             :  *
     683             :  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
     684             :  * objid: OID of object to change the namespace of
     685             :  * nspOid: OID of new namespace
     686             :  *
     687             :  * Returns the OID of the object's previous namespace.
     688             :  */
     689             : static Oid
     690         166 : AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
     691             : {
     692         166 :     Oid         classId = RelationGetRelid(rel);
     693         166 :     int         oidCacheId = get_object_catcache_oid(classId);
     694         166 :     int         nameCacheId = get_object_catcache_name(classId);
     695         166 :     AttrNumber  Anum_name = get_object_attnum_name(classId);
     696         166 :     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
     697         166 :     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
     698             :     Oid         oldNspOid;
     699             :     Datum       name,
     700             :                 namespace;
     701             :     bool        isnull;
     702             :     HeapTuple   tup,
     703             :                 newtup;
     704             :     Datum      *values;
     705             :     bool       *nulls;
     706             :     bool       *replaces;
     707             : 
     708         166 :     tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
     709         166 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     710           0 :         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
     711             :              objid, RelationGetRelationName(rel));
     712             : 
     713         166 :     name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
     714             :     Assert(!isnull);
     715         166 :     namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
     716             :                              &isnull);
     717             :     Assert(!isnull);
     718         166 :     oldNspOid = DatumGetObjectId(namespace);
     719             : 
     720             :     /*
     721             :      * If the object is already in the correct namespace, we don't need to do
     722             :      * anything except fire the object access hook.
     723             :      */
     724         166 :     if (oldNspOid == nspOid)
     725             :     {
     726           4 :         InvokeObjectPostAlterHook(classId, objid, 0);
     727           4 :         return oldNspOid;
     728             :     }
     729             : 
     730             :     /* Check basic namespace related issues */
     731         162 :     CheckSetNamespace(oldNspOid, nspOid);
     732             : 
     733             :     /* Permission checks ... superusers can always do it */
     734         162 :     if (!superuser())
     735             :     {
     736             :         Datum       owner;
     737             :         Oid         ownerId;
     738             :         AclResult   aclresult;
     739             : 
     740             :         /* Fail if object does not have an explicit owner */
     741         104 :         if (Anum_owner <= 0)
     742           0 :             ereport(ERROR,
     743             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     744             :                      errmsg("must be superuser to set schema of %s",
     745             :                             getObjectDescriptionOids(classId, objid))));
     746             : 
     747             :         /* Otherwise, must be owner of the existing object */
     748         104 :         owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
     749             :         Assert(!isnull);
     750         104 :         ownerId = DatumGetObjectId(owner);
     751             : 
     752         104 :         if (!has_privs_of_role(GetUserId(), ownerId))
     753          36 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objid),
     754          36 :                            NameStr(*(DatumGetName(name))));
     755             : 
     756             :         /* User must have CREATE privilege on new namespace */
     757          68 :         aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
     758          68 :         if (aclresult != ACLCHECK_OK)
     759           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
     760           0 :                            get_namespace_name(nspOid));
     761             :     }
     762             : 
     763             :     /*
     764             :      * Check for duplicate name (more friendly than unique-index failure).
     765             :      * Since this is just a friendliness check, we can just skip it in cases
     766             :      * where there isn't suitable support.
     767             :      */
     768         126 :     if (classId == ProcedureRelationId)
     769             :     {
     770          26 :         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
     771             : 
     772          26 :         IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
     773             :                                    &proc->proargtypes, nspOid);
     774             :     }
     775         100 :     else if (classId == CollationRelationId)
     776             :     {
     777           0 :         Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
     778             : 
     779           0 :         IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
     780             :     }
     781         100 :     else if (classId == OperatorClassRelationId)
     782             :     {
     783          12 :         Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
     784             : 
     785          12 :         IsThereOpClassInNamespace(NameStr(opc->opcname),
     786             :                                   opc->opcmethod, nspOid);
     787             :     }
     788          88 :     else if (classId == OperatorFamilyRelationId)
     789             :     {
     790          12 :         Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
     791             : 
     792          12 :         IsThereOpFamilyInNamespace(NameStr(opf->opfname),
     793             :                                    opf->opfmethod, nspOid);
     794             :     }
     795         144 :     else if (nameCacheId >= 0 &&
     796          68 :              SearchSysCacheExists2(nameCacheId, name,
     797             :                                    ObjectIdGetDatum(nspOid)))
     798          24 :         report_namespace_conflict(classId,
     799          24 :                                   NameStr(*(DatumGetName(name))),
     800             :                                   nspOid);
     801             : 
     802             :     /* Build modified tuple */
     803          86 :     values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
     804          86 :     nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
     805          86 :     replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
     806          86 :     values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
     807          86 :     replaces[Anum_namespace - 1] = true;
     808          86 :     newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
     809             :                                values, nulls, replaces);
     810             : 
     811             :     /* Perform actual update */
     812          86 :     CatalogTupleUpdate(rel, &tup->t_self, newtup);
     813             : 
     814             :     /* Release memory */
     815          86 :     pfree(values);
     816          86 :     pfree(nulls);
     817          86 :     pfree(replaces);
     818             : 
     819             :     /* update dependencies to point to the new schema */
     820          86 :     changeDependencyFor(classId, objid,
     821             :                         NamespaceRelationId, oldNspOid, nspOid);
     822             : 
     823          86 :     InvokeObjectPostAlterHook(classId, objid, 0);
     824             : 
     825          86 :     return oldNspOid;
     826             : }
     827             : 
     828             : /*
     829             :  * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
     830             :  * type, the function appropriate to that type is executed.
     831             :  */
     832             : ObjectAddress
     833        1478 : ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
     834             : {
     835        1478 :     Oid         newowner = get_rolespec_oid(stmt->newowner, false);
     836             : 
     837        1472 :     switch (stmt->objectType)
     838             :     {
     839          30 :         case OBJECT_DATABASE:
     840          30 :             return AlterDatabaseOwner(strVal((Value *) stmt->object), newowner);
     841             : 
     842          26 :         case OBJECT_SCHEMA:
     843          26 :             return AlterSchemaOwner(strVal((Value *) stmt->object), newowner);
     844             : 
     845          92 :         case OBJECT_TYPE:
     846             :         case OBJECT_DOMAIN:     /* same as TYPE */
     847          92 :             return AlterTypeOwner(castNode(List, stmt->object), newowner, stmt->objectType);
     848             :             break;
     849             : 
     850          14 :         case OBJECT_FDW:
     851          14 :             return AlterForeignDataWrapperOwner(strVal((Value *) stmt->object),
     852             :                                                 newowner);
     853             : 
     854          46 :         case OBJECT_FOREIGN_SERVER:
     855          46 :             return AlterForeignServerOwner(strVal((Value *) stmt->object),
     856             :                                            newowner);
     857             : 
     858           8 :         case OBJECT_EVENT_TRIGGER:
     859           8 :             return AlterEventTriggerOwner(strVal((Value *) stmt->object),
     860             :                                           newowner);
     861             : 
     862           4 :         case OBJECT_PUBLICATION:
     863           4 :             return AlterPublicationOwner(strVal((Value *) stmt->object),
     864             :                                          newowner);
     865             : 
     866           8 :         case OBJECT_SUBSCRIPTION:
     867           8 :             return AlterSubscriptionOwner(strVal((Value *) stmt->object),
     868             :                                           newowner);
     869             : 
     870             :             /* Generic cases */
     871        1244 :         case OBJECT_AGGREGATE:
     872             :         case OBJECT_COLLATION:
     873             :         case OBJECT_CONVERSION:
     874             :         case OBJECT_FUNCTION:
     875             :         case OBJECT_LANGUAGE:
     876             :         case OBJECT_LARGEOBJECT:
     877             :         case OBJECT_OPERATOR:
     878             :         case OBJECT_OPCLASS:
     879             :         case OBJECT_OPFAMILY:
     880             :         case OBJECT_PROCEDURE:
     881             :         case OBJECT_ROUTINE:
     882             :         case OBJECT_STATISTIC_EXT:
     883             :         case OBJECT_TABLESPACE:
     884             :         case OBJECT_TSDICTIONARY:
     885             :         case OBJECT_TSCONFIGURATION:
     886             :             {
     887             :                 Relation    catalog;
     888             :                 Relation    relation;
     889             :                 Oid         classId;
     890             :                 ObjectAddress address;
     891             : 
     892        1244 :                 address = get_object_address(stmt->objectType,
     893             :                                              stmt->object,
     894             :                                              &relation,
     895             :                                              AccessExclusiveLock,
     896             :                                              false);
     897             :                 Assert(relation == NULL);
     898        1238 :                 classId = address.classId;
     899             : 
     900             :                 /*
     901             :                  * XXX - get_object_address returns Oid of pg_largeobject
     902             :                  * catalog for OBJECT_LARGEOBJECT because of historical
     903             :                  * reasons.  Fix up it here.
     904             :                  */
     905        1238 :                 if (classId == LargeObjectRelationId)
     906          10 :                     classId = LargeObjectMetadataRelationId;
     907             : 
     908        1238 :                 catalog = table_open(classId, RowExclusiveLock);
     909             : 
     910        1238 :                 AlterObjectOwner_internal(catalog, address.objectId, newowner);
     911        1122 :                 table_close(catalog, RowExclusiveLock);
     912             : 
     913        1122 :                 return address;
     914             :             }
     915             :             break;
     916             : 
     917           0 :         default:
     918           0 :             elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
     919             :                  (int) stmt->objectType);
     920             :             return InvalidObjectAddress;    /* keep compiler happy */
     921             :     }
     922             : }
     923             : 
     924             : /*
     925             :  * Generic function to change the ownership of a given object, for simple
     926             :  * cases (won't work for tables, nor other cases where we need to do more than
     927             :  * change the ownership column of a single catalog entry).
     928             :  *
     929             :  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
     930             :  * objectId: OID of object to change the ownership of
     931             :  * new_ownerId: OID of new object owner
     932             :  */
     933             : void
     934        1242 : AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
     935             : {
     936        1242 :     Oid         classId = RelationGetRelid(rel);
     937        1242 :     AttrNumber  Anum_oid = get_object_attnum_oid(classId);
     938        1242 :     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
     939        1242 :     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
     940        1242 :     AttrNumber  Anum_acl = get_object_attnum_acl(classId);
     941        1242 :     AttrNumber  Anum_name = get_object_attnum_name(classId);
     942             :     HeapTuple   oldtup;
     943             :     Datum       datum;
     944             :     bool        isnull;
     945             :     Oid         old_ownerId;
     946        1242 :     Oid         namespaceId = InvalidOid;
     947             : 
     948        1242 :     oldtup = get_catalog_object_by_oid(rel, Anum_oid, objectId);
     949        1242 :     if (oldtup == NULL)
     950           0 :         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
     951             :              objectId, RelationGetRelationName(rel));
     952             : 
     953        1242 :     datum = heap_getattr(oldtup, Anum_owner,
     954             :                          RelationGetDescr(rel), &isnull);
     955             :     Assert(!isnull);
     956        1242 :     old_ownerId = DatumGetObjectId(datum);
     957             : 
     958        1242 :     if (Anum_namespace != InvalidAttrNumber)
     959             :     {
     960         836 :         datum = heap_getattr(oldtup, Anum_namespace,
     961             :                              RelationGetDescr(rel), &isnull);
     962             :         Assert(!isnull);
     963         836 :         namespaceId = DatumGetObjectId(datum);
     964             :     }
     965             : 
     966        1242 :     if (old_ownerId != new_ownerId)
     967             :     {
     968             :         AttrNumber  nattrs;
     969             :         HeapTuple   newtup;
     970             :         Datum      *values;
     971             :         bool       *nulls;
     972             :         bool       *replaces;
     973             : 
     974             :         /* Superusers can bypass permission checks */
     975         228 :         if (!superuser())
     976             :         {
     977             :             /* must be owner */
     978         156 :             if (!has_privs_of_role(GetUserId(), old_ownerId))
     979             :             {
     980             :                 char       *objname;
     981             :                 char        namebuf[NAMEDATALEN];
     982             : 
     983          40 :                 if (Anum_name != InvalidAttrNumber)
     984             :                 {
     985          40 :                     datum = heap_getattr(oldtup, Anum_name,
     986             :                                          RelationGetDescr(rel), &isnull);
     987             :                     Assert(!isnull);
     988          40 :                     objname = NameStr(*DatumGetName(datum));
     989             :                 }
     990             :                 else
     991             :                 {
     992           0 :                     snprintf(namebuf, sizeof(namebuf), "%u", objectId);
     993           0 :                     objname = namebuf;
     994             :                 }
     995          40 :                 aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
     996             :                                objname);
     997             :             }
     998             :             /* Must be able to become new owner */
     999         116 :             check_is_member_of_role(GetUserId(), new_ownerId);
    1000             : 
    1001             :             /* New owner must have CREATE privilege on namespace */
    1002          40 :             if (OidIsValid(namespaceId))
    1003             :             {
    1004             :                 AclResult   aclresult;
    1005             : 
    1006          36 :                 aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
    1007             :                                                   ACL_CREATE);
    1008          36 :                 if (aclresult != ACLCHECK_OK)
    1009           0 :                     aclcheck_error(aclresult, OBJECT_SCHEMA,
    1010           0 :                                    get_namespace_name(namespaceId));
    1011             :             }
    1012             :         }
    1013             : 
    1014             :         /* Build a modified tuple */
    1015         112 :         nattrs = RelationGetNumberOfAttributes(rel);
    1016         112 :         values = palloc0(nattrs * sizeof(Datum));
    1017         112 :         nulls = palloc0(nattrs * sizeof(bool));
    1018         112 :         replaces = palloc0(nattrs * sizeof(bool));
    1019         112 :         values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
    1020         112 :         replaces[Anum_owner - 1] = true;
    1021             : 
    1022             :         /*
    1023             :          * Determine the modified ACL for the new owner.  This is only
    1024             :          * necessary when the ACL is non-null.
    1025             :          */
    1026         112 :         if (Anum_acl != InvalidAttrNumber)
    1027             :         {
    1028          52 :             datum = heap_getattr(oldtup,
    1029             :                                  Anum_acl, RelationGetDescr(rel), &isnull);
    1030          52 :             if (!isnull)
    1031             :             {
    1032             :                 Acl        *newAcl;
    1033             : 
    1034           0 :                 newAcl = aclnewowner(DatumGetAclP(datum),
    1035             :                                      old_ownerId, new_ownerId);
    1036           0 :                 values[Anum_acl - 1] = PointerGetDatum(newAcl);
    1037           0 :                 replaces[Anum_acl - 1] = true;
    1038             :             }
    1039             :         }
    1040             : 
    1041         112 :         newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
    1042             :                                    values, nulls, replaces);
    1043             : 
    1044             :         /* Perform actual update */
    1045         112 :         CatalogTupleUpdate(rel, &newtup->t_self, newtup);
    1046             : 
    1047             :         /* Update owner dependency reference */
    1048         112 :         if (classId == LargeObjectMetadataRelationId)
    1049           4 :             classId = LargeObjectRelationId;
    1050         112 :         changeDependencyOnOwner(classId, objectId, new_ownerId);
    1051             : 
    1052             :         /* Release memory */
    1053         112 :         pfree(values);
    1054         112 :         pfree(nulls);
    1055         112 :         pfree(replaces);
    1056             :     }
    1057             : 
    1058        1126 :     InvokeObjectPostAlterHook(classId, objectId, 0);
    1059        1126 : }

Generated by: LCOV version 1.13