LCOV - code coverage report
Current view: top level - src/backend/commands - alter.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.0 % 355 323
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.3 % 192 135

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

Generated by: LCOV version 2.0-1