LCOV - code coverage report
Current view: top level - src/backend/commands - alter.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 90.9 % 352 320
Test Date: 2026-09-15 23:15:41 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.0 % 190 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                 :          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_array(Datum, RelationGetNumberOfAttributes(rel));
     322                 :         169 :     nulls = palloc0_array(bool, RelationGetNumberOfAttributes(rel));
     323                 :         169 :     replaces = palloc0_array(bool, RelationGetNumberOfAttributes(rel));
     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                 :        1017 : ExecRenameStmt(RenameStmt *stmt)
     368                 :             : {
     369   [ +  +  +  +  :        1017 :     switch (stmt->renameType)
          +  +  +  +  +  
             +  +  +  - ]
     370                 :             :     {
     371                 :          60 :         case OBJECT_TABCONSTRAINT:
     372                 :             :         case OBJECT_DOMCONSTRAINT:
     373                 :          60 :             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                 :           9 :         case OBJECT_TABLESPACE:
     385                 :           9 :             return RenameTableSpace(stmt->subname, stmt->newname);
     386                 :             : 
     387                 :         303 :         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                 :         303 :             return RenameRelation(stmt);
     394                 :             : 
     395                 :         213 :         case OBJECT_COLUMN:
     396                 :             :         case OBJECT_ATTRIBUTE:
     397                 :         213 :             return renameatt(stmt);
     398                 :             : 
     399                 :          30 :         case OBJECT_RULE:
     400                 :          30 :             return RenameRewriteRule(stmt->relation, stmt->subname,
     401                 :          30 :                                      stmt->newname);
     402                 :             : 
     403                 :          38 :         case OBJECT_TRIGGER:
     404                 :          38 :             return renametrig(stmt);
     405                 :             : 
     406                 :          12 :         case OBJECT_POLICY:
     407                 :          12 :             return rename_policy(stmt);
     408                 :             : 
     409                 :          21 :         case OBJECT_DOMAIN:
     410                 :             :         case OBJECT_TYPE:
     411                 :          21 :             return RenameType(stmt);
     412                 :             : 
     413                 :         289 :         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                 :             :                 Relation    catalog;
     435                 :             : 
     436                 :         289 :                 address = get_object_address(stmt->renameType,
     437                 :             :                                              stmt->object,
     438                 :             :                                              NULL,
     439                 :             :                                              AccessExclusiveLock, false);
     440                 :             : 
     441                 :         281 :                 catalog = table_open(address.classId, RowExclusiveLock);
     442                 :         281 :                 AlterObjectRename_internal(catalog,
     443                 :             :                                            address.objectId,
     444                 :         281 :                                            stmt->newname);
     445                 :         169 :                 table_close(catalog, RowExclusiveLock);
     446                 :             : 
     447                 :         169 :                 return address;
     448                 :             :             }
     449                 :             : 
     450                 :           0 :         default:
     451         [ #  # ]:           0 :             elog(ERROR, "unrecognized rename stmt type: %d",
     452                 :             :                  (int) stmt->renameType);
     453                 :             :             return InvalidObjectAddress;    /* keep compiler happy */
     454                 :             :     }
     455                 :             : }
     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                 :          23 : ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress)
     466                 :             : {
     467                 :             :     ObjectAddress address;
     468                 :             :     ObjectAddress refAddr;
     469                 :             :     Relation    rel;
     470                 :             : 
     471                 :             :     address =
     472                 :          23 :         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                 :          23 :     check_object_ownership(GetUserId(),
     484                 :             :                            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         [ +  + ]:          23 :     if (rel)
     491                 :          17 :         table_close(rel, NoLock);
     492                 :             : 
     493                 :          23 :     refAddr = get_object_address(OBJECT_EXTENSION, (Node *) stmt->extname,
     494                 :             :                                  NULL, AccessExclusiveLock, false);
     495         [ +  - ]:          23 :     if (refAddress)
     496                 :          23 :         *refAddress = refAddr;
     497                 :             : 
     498         [ +  + ]:          23 :     if (stmt->remove)
     499                 :             :     {
     500                 :           4 :         deleteDependencyRecordsForSpecific(address.classId, address.objectId,
     501                 :             :                                            DEPENDENCY_AUTO_EXTENSION,
     502                 :             :                                            refAddr.classId, refAddr.objectId);
     503                 :             :     }
     504                 :             :     else
     505                 :             :     {
     506                 :             :         List       *currexts;
     507                 :             : 
     508                 :             :         /* Avoid duplicates */
     509                 :          19 :         currexts = getAutoExtensionsOfObject(address.classId,
     510                 :             :                                              address.objectId);
     511         [ +  + ]:          19 :         if (!list_member_oid(currexts, refAddr.objectId))
     512                 :          18 :             recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
     513                 :             :     }
     514                 :             : 
     515                 :          23 :     return address;
     516                 :             : }
     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                 :         271 : ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
     529                 :             :                           ObjectAddress *oldSchemaAddr)
     530                 :             : {
     531                 :             :     ObjectAddress address;
     532                 :             :     Oid         oldNspOid;
     533                 :             : 
     534   [ +  +  +  +  :         271 :     switch (stmt->objectType)
                      - ]
     535                 :             :     {
     536                 :           6 :         case OBJECT_EXTENSION:
     537         [ +  - ]:           6 :             address = AlterExtensionNamespace(strVal(stmt->object), stmt->newschema,
     538                 :             :                                               oldSchemaAddr ? &oldNspOid : NULL);
     539                 :           4 :             break;
     540                 :             : 
     541                 :          76 :         case OBJECT_FOREIGN_TABLE:
     542                 :             :         case OBJECT_SEQUENCE:
     543                 :             :         case OBJECT_TABLE:
     544                 :             :         case OBJECT_VIEW:
     545                 :             :         case OBJECT_MATVIEW:
     546         [ +  - ]:          76 :             address = AlterTableNamespace(stmt,
     547                 :             :                                           oldSchemaAddr ? &oldNspOid : NULL);
     548                 :          63 :             break;
     549                 :             : 
     550                 :          12 :         case OBJECT_DOMAIN:
     551                 :             :         case OBJECT_TYPE:
     552         [ +  - ]:          12 :             address = AlterTypeNamespace(castNode(List, stmt->object), stmt->newschema,
     553                 :             :                                          stmt->objectType,
     554                 :             :                                          oldSchemaAddr ? &oldNspOid : NULL);
     555                 :          12 :             break;
     556                 :             : 
     557                 :             :             /* generic code path */
     558                 :         177 :         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                 :             :                 Relation    catalog;
     574                 :             :                 Oid         classId;
     575                 :             :                 Oid         nspOid;
     576                 :             : 
     577                 :         177 :                 address = get_object_address(stmt->objectType,
     578                 :             :                                              stmt->object,
     579                 :             :                                              NULL,
     580                 :             :                                              AccessExclusiveLock,
     581                 :             :                                              false);
     582                 :         173 :                 classId = address.classId;
     583                 :         173 :                 catalog = table_open(classId, RowExclusiveLock);
     584                 :         173 :                 nspOid = LookupCreationNamespace(stmt->newschema);
     585                 :             : 
     586                 :         173 :                 oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
     587                 :             :                                                           nspOid);
     588                 :          96 :                 table_close(catalog, RowExclusiveLock);
     589                 :             :             }
     590                 :          96 :             break;
     591                 :             : 
     592                 :           0 :         default:
     593         [ #  # ]:           0 :             elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
     594                 :             :                  (int) stmt->objectType);
     595                 :             :             return InvalidObjectAddress;    /* keep compiler happy */
     596                 :             :     }
     597                 :             : 
     598         [ +  - ]:         175 :     if (oldSchemaAddr)
     599                 :         175 :         ObjectAddressSet(*oldSchemaAddr, NamespaceRelationId, oldNspOid);
     600                 :             : 
     601                 :         175 :     return address;
     602                 :             : }
     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                 :          21 : AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
     620                 :             :                          ObjectAddresses *objsMoved)
     621                 :             : {
     622                 :          21 :     Oid         oldNspOid = InvalidOid;
     623                 :             : 
     624   [ +  +  +  + ]:          21 :     switch (classId)
     625                 :             :     {
     626                 :           1 :         case RelationRelationId:
     627                 :             :             {
     628                 :             :                 Relation    rel;
     629                 :             : 
     630                 :           1 :                 rel = relation_open(objid, AccessExclusiveLock);
     631                 :           1 :                 oldNspOid = RelationGetNamespace(rel);
     632                 :             : 
     633                 :           1 :                 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
     634                 :             : 
     635                 :           1 :                 relation_close(rel, NoLock);
     636                 :           1 :                 break;
     637                 :             :             }
     638                 :             : 
     639                 :           8 :         case TypeRelationId:
     640                 :           8 :             oldNspOid = AlterTypeNamespace_oid(objid, nspOid, true, objsMoved);
     641                 :           8 :             break;
     642                 :             : 
     643                 :          11 :         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                 :             :                 Relation    catalog;
     656                 :             : 
     657                 :          11 :                 catalog = table_open(classId, RowExclusiveLock);
     658                 :             : 
     659                 :          11 :                 oldNspOid = AlterObjectNamespace_internal(catalog, objid,
     660                 :             :                                                           nspOid);
     661                 :             : 
     662                 :          11 :                 table_close(catalog, RowExclusiveLock);
     663                 :             :             }
     664                 :          11 :             break;
     665                 :             : 
     666                 :          21 :         default:
     667                 :             :             /* ignore object types that don't have schema-qualified names */
     668                 :             :             Assert(get_object_attnum_namespace(classId) == InvalidAttrNumber);
     669                 :             :     }
     670                 :             : 
     671                 :          21 :     return oldNspOid;
     672                 :             : }
     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                 :         184 : AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
     687                 :             : {
     688                 :         184 :     Oid         classId = RelationGetRelid(rel);
     689                 :         184 :     SysCacheIdentifier oidCacheId = get_object_catcache_oid(classId);
     690                 :         184 :     SysCacheIdentifier nameCacheId = get_object_catcache_name(classId);
     691                 :         184 :     AttrNumber  Anum_name = get_object_attnum_name(classId);
     692                 :         184 :     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
     693                 :         184 :     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
     694                 :             :     Oid         oldNspOid;
     695                 :             :     Datum       name,
     696                 :             :                 namespace;
     697                 :             :     bool        isnull;
     698                 :             :     HeapTuple   tup,
     699                 :             :                 newtup;
     700                 :             :     Datum      *values;
     701                 :             :     bool       *nulls;
     702                 :             :     bool       *replaces;
     703                 :             : 
     704                 :         184 :     tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
     705         [ -  + ]:         184 :     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                 :         184 :     name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
     710                 :             :     Assert(!isnull);
     711                 :         184 :     namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
     712                 :             :                              &isnull);
     713                 :             :     Assert(!isnull);
     714                 :         184 :     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         [ +  + ]:         184 :     if (oldNspOid == nspOid)
     721                 :             :     {
     722         [ -  + ]:           4 :         InvokeObjectPostAlterHook(classId, objid, 0);
     723                 :           4 :         return oldNspOid;
     724                 :             :     }
     725                 :             : 
     726                 :             :     /* Check basic namespace related issues */
     727                 :         180 :     CheckSetNamespace(oldNspOid, nspOid);
     728                 :             : 
     729                 :             :     /* Permission checks ... superusers can always do it */
     730         [ +  + ]:         180 :     if (!superuser())
     731                 :             :     {
     732                 :             :         Datum       owner;
     733                 :             :         Oid         ownerId;
     734                 :             :         AclResult   aclresult;
     735                 :             : 
     736                 :             :         /* Fail if object does not have an explicit owner */
     737         [ -  + ]:         104 :         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                 :         104 :         owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
     745                 :             :         Assert(!isnull);
     746                 :         104 :         ownerId = DatumGetObjectId(owner);
     747                 :             : 
     748         [ +  + ]:         104 :         if (!has_privs_of_role(GetUserId(), ownerId))
     749                 :          36 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objid),
     750                 :          36 :                            NameStr(*(DatumGetName(name))));
     751                 :             : 
     752                 :             :         /* User must have CREATE privilege on new namespace */
     753                 :          68 :         aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
     754         [ -  + ]:          68 :         if (aclresult != ACLCHECK_OK)
     755                 :           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
     756                 :           0 :                            get_namespace_name(nspOid));
     757                 :             :     }
     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         [ +  + ]:         144 :     if (classId == ProcedureRelationId)
     765                 :             :     {
     766                 :          40 :         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
     767                 :             : 
     768                 :          40 :         IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
     769                 :             :                                    &proc->proargtypes, nspOid);
     770                 :             :     }
     771         [ +  + ]:         104 :     else if (classId == CollationRelationId)
     772                 :             :     {
     773                 :           4 :         Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
     774                 :             : 
     775                 :           4 :         IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
     776                 :             :     }
     777         [ +  + ]:         100 :     else if (classId == OperatorClassRelationId)
     778                 :             :     {
     779                 :          12 :         Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
     780                 :             : 
     781                 :          12 :         IsThereOpClassInNamespace(NameStr(opc->opcname),
     782                 :             :                                   opc->opcmethod, nspOid);
     783                 :             :     }
     784         [ +  + ]:          88 :     else if (classId == OperatorFamilyRelationId)
     785                 :             :     {
     786                 :          12 :         Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
     787                 :             : 
     788                 :          12 :         IsThereOpFamilyInNamespace(NameStr(opf->opfname),
     789                 :             :                                    opf->opfmethod, nspOid);
     790                 :             :     }
     791   [ +  +  +  + ]:         144 :     else if (nameCacheId >= 0 &&
     792                 :          68 :              SearchSysCacheExists2(nameCacheId, name,
     793                 :             :                                    ObjectIdGetDatum(nspOid)))
     794                 :          24 :         report_namespace_conflict(classId,
     795                 :          24 :                                   NameStr(*(DatumGetName(name))),
     796                 :             :                                   nspOid);
     797                 :             : 
     798                 :             :     /* Build modified tuple */
     799                 :         104 :     values = palloc0_array(Datum, RelationGetNumberOfAttributes(rel));
     800                 :         104 :     nulls = palloc0_array(bool, RelationGetNumberOfAttributes(rel));
     801                 :         104 :     replaces = palloc0_array(bool, RelationGetNumberOfAttributes(rel));
     802                 :         104 :     values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
     803                 :         104 :     replaces[Anum_namespace - 1] = true;
     804                 :         104 :     newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
     805                 :             :                                values, nulls, replaces);
     806                 :             : 
     807                 :             :     /* Perform actual update */
     808                 :         104 :     CatalogTupleUpdate(rel, &tup->t_self, newtup);
     809                 :             : 
     810                 :             :     /* Release memory */
     811                 :         104 :     pfree(values);
     812                 :         104 :     pfree(nulls);
     813                 :         104 :     pfree(replaces);
     814                 :             : 
     815                 :             :     /* update dependency to point to the new schema */
     816         [ -  + ]:         104 :     if (changeDependencyFor(classId, objid,
     817                 :             :                             NamespaceRelationId, oldNspOid, nspOid) != 1)
     818         [ #  # ]:           0 :         elog(ERROR, "could not change schema dependency for object %u",
     819                 :             :              objid);
     820                 :             : 
     821         [ -  + ]:         103 :     InvokeObjectPostAlterHook(classId, objid, 0);
     822                 :             : 
     823                 :         103 :     return oldNspOid;
     824                 :             : }
     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                 :         974 : ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
     832                 :             : {
     833                 :         974 :     Oid         newowner = get_rolespec_oid(stmt->newowner, false);
     834                 :             : 
     835   [ +  +  +  +  :         967 :     switch (stmt->objectType)
          +  +  +  +  +  
                      - ]
     836                 :             :     {
     837                 :          50 :         case OBJECT_DATABASE:
     838                 :          50 :             return AlterDatabaseOwner(strVal(stmt->object), newowner);
     839                 :             : 
     840                 :          37 :         case OBJECT_SCHEMA:
     841                 :          37 :             return AlterSchemaOwner(strVal(stmt->object), newowner);
     842                 :             : 
     843                 :          71 :         case OBJECT_TYPE:
     844                 :             :         case OBJECT_DOMAIN:     /* same as TYPE */
     845                 :          71 :             return AlterTypeOwner(castNode(List, stmt->object), newowner, stmt->objectType);
     846                 :             :             break;
     847                 :             : 
     848                 :          13 :         case OBJECT_FDW:
     849                 :          13 :             return AlterForeignDataWrapperOwner(strVal(stmt->object),
     850                 :             :                                                 newowner);
     851                 :             : 
     852                 :          45 :         case OBJECT_FOREIGN_SERVER:
     853                 :          45 :             return AlterForeignServerOwner(strVal(stmt->object),
     854                 :             :                                            newowner);
     855                 :             : 
     856                 :           9 :         case OBJECT_EVENT_TRIGGER:
     857                 :           9 :             return AlterEventTriggerOwner(strVal(stmt->object),
     858                 :             :                                           newowner);
     859                 :             : 
     860                 :          26 :         case OBJECT_PUBLICATION:
     861                 :          26 :             return AlterPublicationOwner(strVal(stmt->object),
     862                 :             :                                          newowner);
     863                 :             : 
     864                 :          27 :         case OBJECT_SUBSCRIPTION:
     865                 :          27 :             return AlterSubscriptionOwner(strVal(stmt->object),
     866                 :             :                                           newowner);
     867                 :             : 
     868                 :             :             /* Generic cases */
     869                 :         689 :         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                 :         689 :                 address = get_object_address(stmt->objectType,
     888                 :             :                                              stmt->object,
     889                 :             :                                              NULL,
     890                 :             :                                              AccessExclusiveLock,
     891                 :             :                                              false);
     892                 :             : 
     893                 :         684 :                 AlterObjectOwner_internal(address.classId, address.objectId,
     894                 :             :                                           newowner);
     895                 :             : 
     896                 :         568 :                 return address;
     897                 :             :             }
     898                 :             :             break;
     899                 :             : 
     900                 :           0 :         default:
     901         [ #  # ]:           0 :             elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
     902                 :             :                  (int) stmt->objectType);
     903                 :             :             return InvalidObjectAddress;    /* keep compiler happy */
     904                 :             :     }
     905                 :             : }
     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                 :         700 : AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
     921                 :             : {
     922                 :             :     /* For large objects, the catalog to modify is pg_largeobject_metadata */
     923         [ +  + ]:         700 :     Oid         catalogId = (classId == LargeObjectRelationId) ? LargeObjectMetadataRelationId : classId;
     924                 :         700 :     AttrNumber  Anum_oid = get_object_attnum_oid(catalogId);
     925                 :         700 :     AttrNumber  Anum_owner = get_object_attnum_owner(catalogId);
     926                 :         700 :     AttrNumber  Anum_namespace = get_object_attnum_namespace(catalogId);
     927                 :         700 :     AttrNumber  Anum_acl = get_object_attnum_acl(catalogId);
     928                 :         700 :     AttrNumber  Anum_name = get_object_attnum_name(catalogId);
     929                 :             :     Relation    rel;
     930                 :             :     HeapTuple   oldtup;
     931                 :             :     Datum       datum;
     932                 :             :     bool        isnull;
     933                 :             :     Oid         old_ownerId;
     934                 :         700 :     Oid         namespaceId = InvalidOid;
     935                 :             : 
     936                 :         700 :     rel = table_open(catalogId, RowExclusiveLock);
     937                 :             : 
     938                 :             :     /* Search tuple and lock it. */
     939                 :             :     oldtup =
     940                 :         700 :         get_catalog_object_by_oid_extended(rel, Anum_oid, objectId, true);
     941         [ -  + ]:         700 :     if (oldtup == NULL)
     942         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
     943                 :             :              objectId, RelationGetRelationName(rel));
     944                 :             : 
     945                 :         700 :     datum = heap_getattr(oldtup, Anum_owner,
     946                 :             :                          RelationGetDescr(rel), &isnull);
     947                 :             :     Assert(!isnull);
     948                 :         700 :     old_ownerId = DatumGetObjectId(datum);
     949                 :             : 
     950         [ +  + ]:         700 :     if (Anum_namespace != InvalidAttrNumber)
     951                 :             :     {
     952                 :         594 :         datum = heap_getattr(oldtup, Anum_namespace,
     953                 :             :                              RelationGetDescr(rel), &isnull);
     954                 :             :         Assert(!isnull);
     955                 :         594 :         namespaceId = DatumGetObjectId(datum);
     956                 :             :     }
     957                 :             : 
     958         [ +  + ]:         700 :     if (old_ownerId != new_ownerId)
     959                 :             :     {
     960                 :             :         AttrNumber  nattrs;
     961                 :             :         HeapTuple   newtup;
     962                 :             :         Datum      *values;
     963                 :             :         bool       *nulls;
     964                 :             :         bool       *replaces;
     965                 :             : 
     966                 :             :         /* Superusers can bypass permission checks */
     967         [ +  + ]:         261 :         if (!superuser())
     968                 :             :         {
     969                 :             :             /* must be owner */
     970         [ +  + ]:         156 :             if (!has_privs_of_role(GetUserId(), old_ownerId))
     971                 :             :             {
     972                 :             :                 char       *objname;
     973                 :             :                 char        namebuf[NAMEDATALEN];
     974                 :             : 
     975         [ +  - ]:          40 :                 if (Anum_name != InvalidAttrNumber)
     976                 :             :                 {
     977                 :          40 :                     datum = heap_getattr(oldtup, Anum_name,
     978                 :             :                                          RelationGetDescr(rel), &isnull);
     979                 :             :                     Assert(!isnull);
     980                 :          40 :                     objname = NameStr(*DatumGetName(datum));
     981                 :             :                 }
     982                 :             :                 else
     983                 :             :                 {
     984                 :           0 :                     snprintf(namebuf, sizeof(namebuf), "%u", objectId);
     985                 :           0 :                     objname = namebuf;
     986                 :             :                 }
     987                 :          40 :                 aclcheck_error(ACLCHECK_NOT_OWNER,
     988                 :             :                                get_object_type(catalogId, objectId),
     989                 :             :                                objname);
     990                 :             :             }
     991                 :             :             /* Must be able to become new owner */
     992                 :         116 :             check_can_set_role(GetUserId(), new_ownerId);
     993                 :             : 
     994                 :             :             /* New owner must have CREATE privilege on namespace */
     995         [ +  + ]:          40 :             if (OidIsValid(namespaceId))
     996                 :             :             {
     997                 :             :                 AclResult   aclresult;
     998                 :             : 
     999                 :          36 :                 aclresult = object_aclcheck(NamespaceRelationId, namespaceId, new_ownerId,
    1000                 :             :                                             ACL_CREATE);
    1001         [ -  + ]:          36 :                 if (aclresult != ACLCHECK_OK)
    1002                 :           0 :                     aclcheck_error(aclresult, OBJECT_SCHEMA,
    1003                 :           0 :                                    get_namespace_name(namespaceId));
    1004                 :             :             }
    1005                 :             :         }
    1006                 :             : 
    1007                 :             :         /* Build a modified tuple */
    1008                 :         145 :         nattrs = RelationGetNumberOfAttributes(rel);
    1009                 :         145 :         values = palloc0_array(Datum, nattrs);
    1010                 :         145 :         nulls = palloc0_array(bool, nattrs);
    1011                 :         145 :         replaces = palloc0_array(bool, nattrs);
    1012                 :         145 :         values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
    1013                 :         145 :         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         [ +  + ]:         145 :         if (Anum_acl != InvalidAttrNumber)
    1020                 :             :         {
    1021                 :          76 :             datum = heap_getattr(oldtup,
    1022                 :             :                                  Anum_acl, RelationGetDescr(rel), &isnull);
    1023         [ +  + ]:          76 :             if (!isnull)
    1024                 :             :             {
    1025                 :             :                 Acl        *newAcl;
    1026                 :             : 
    1027                 :           8 :                 newAcl = aclnewowner(DatumGetAclP(datum),
    1028                 :             :                                      old_ownerId, new_ownerId);
    1029                 :           8 :                 values[Anum_acl - 1] = PointerGetDatum(newAcl);
    1030                 :           8 :                 replaces[Anum_acl - 1] = true;
    1031                 :             :             }
    1032                 :             :         }
    1033                 :             : 
    1034                 :         145 :         newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
    1035                 :             :                                    values, nulls, replaces);
    1036                 :             : 
    1037                 :             :         /* Perform actual update */
    1038                 :         145 :         CatalogTupleUpdate(rel, &newtup->t_self, newtup);
    1039                 :             : 
    1040                 :         145 :         UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
    1041                 :             : 
    1042                 :             :         /* Update owner dependency reference */
    1043                 :         145 :         changeDependencyOnOwner(classId, objectId, new_ownerId);
    1044                 :             : 
    1045                 :             :         /* Release memory */
    1046                 :         145 :         pfree(values);
    1047                 :         145 :         pfree(nulls);
    1048                 :         145 :         pfree(replaces);
    1049                 :             :     }
    1050                 :             :     else
    1051                 :         439 :         UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
    1052                 :             : 
    1053                 :             :     /* Note the post-alter hook gets classId not catalogId */
    1054         [ -  + ]:         584 :     InvokeObjectPostAlterHook(classId, objectId, 0);
    1055                 :             : 
    1056                 :         584 :     table_close(rel, RowExclusiveLock);
    1057                 :         584 : }
        

Generated by: LCOV version 2.0-1