LCOV - code coverage report
Current view: top level - src/backend/commands - alter.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 81.2 % 452 367
Test Date: 2026-01-26 10:56:24 Functions: 80.0 % 10 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 55.0 % 242 133

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

Generated by: LCOV version 2.3.2-1