LCOV - differential code coverage report
Current view: top level - src/backend/commands - alter.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 88.3 % 375 331 3 9 26 6 9 185 12 125 28 195 1 2
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 10 10 10 10
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a