Header And Logo

PostgreSQL
| The world's most advanced open source database.

alter.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * alter.c
00004  *    Drivers for generic alter commands
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/commands/alter.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/htup_details.h"
00018 #include "access/sysattr.h"
00019 #include "catalog/dependency.h"
00020 #include "catalog/indexing.h"
00021 #include "catalog/namespace.h"
00022 #include "catalog/objectaccess.h"
00023 #include "catalog/pg_collation.h"
00024 #include "catalog/pg_conversion.h"
00025 #include "catalog/pg_event_trigger.h"
00026 #include "catalog/pg_foreign_data_wrapper.h"
00027 #include "catalog/pg_foreign_server.h"
00028 #include "catalog/pg_language.h"
00029 #include "catalog/pg_largeobject.h"
00030 #include "catalog/pg_largeobject_metadata.h"
00031 #include "catalog/pg_namespace.h"
00032 #include "catalog/pg_opclass.h"
00033 #include "catalog/pg_opfamily.h"
00034 #include "catalog/pg_proc.h"
00035 #include "catalog/pg_ts_config.h"
00036 #include "catalog/pg_ts_dict.h"
00037 #include "catalog/pg_ts_parser.h"
00038 #include "catalog/pg_ts_template.h"
00039 #include "commands/alter.h"
00040 #include "commands/collationcmds.h"
00041 #include "commands/conversioncmds.h"
00042 #include "commands/dbcommands.h"
00043 #include "commands/defrem.h"
00044 #include "commands/event_trigger.h"
00045 #include "commands/extension.h"
00046 #include "commands/proclang.h"
00047 #include "commands/schemacmds.h"
00048 #include "commands/tablecmds.h"
00049 #include "commands/tablespace.h"
00050 #include "commands/trigger.h"
00051 #include "commands/typecmds.h"
00052 #include "commands/user.h"
00053 #include "parser/parse_func.h"
00054 #include "miscadmin.h"
00055 #include "rewrite/rewriteDefine.h"
00056 #include "tcop/utility.h"
00057 #include "utils/builtins.h"
00058 #include "utils/fmgroids.h"
00059 #include "utils/lsyscache.h"
00060 #include "utils/rel.h"
00061 #include "utils/syscache.h"
00062 #include "utils/tqual.h"
00063 
00064 
00065 static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
00066 
00067 /*
00068  * Raise an error to the effect that an object of the given name is already
00069  * present in the given namespace.
00070  */
00071 static void
00072 report_name_conflict(Oid classId, const char *name)
00073 {
00074     char   *msgfmt;
00075 
00076     switch (classId)
00077     {
00078         case EventTriggerRelationId:
00079             msgfmt = gettext_noop("event trigger \"%s\" already exists");
00080             break;
00081         case ForeignDataWrapperRelationId:
00082             msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
00083             break;
00084         case ForeignServerRelationId:
00085             msgfmt = gettext_noop("server \"%s\" already exists");
00086             break;
00087         case LanguageRelationId:
00088             msgfmt = gettext_noop("language \"%s\" already exists");
00089             break;
00090         default:
00091             elog(ERROR, "unsupported object class %u", classId);
00092             break;
00093     }
00094 
00095     ereport(ERROR,
00096             (errcode(ERRCODE_DUPLICATE_OBJECT),
00097              errmsg(msgfmt, name)));
00098 }
00099 
00100 static void
00101 report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
00102 {
00103     char   *msgfmt;
00104 
00105     Assert(OidIsValid(nspOid));
00106 
00107     switch (classId)
00108     {
00109         case ConversionRelationId:
00110             Assert(OidIsValid(nspOid));
00111             msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
00112             break;
00113         case TSParserRelationId:
00114             Assert(OidIsValid(nspOid));
00115             msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
00116             break;
00117         case TSDictionaryRelationId:
00118             Assert(OidIsValid(nspOid));
00119             msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
00120             break;
00121         case TSTemplateRelationId:
00122             Assert(OidIsValid(nspOid));
00123             msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
00124             break;
00125         case TSConfigRelationId:
00126             Assert(OidIsValid(nspOid));
00127             msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
00128             break;
00129         default:
00130             elog(ERROR, "unsupported object class %u", classId);
00131             break;
00132     }
00133 
00134     ereport(ERROR,
00135             (errcode(ERRCODE_DUPLICATE_OBJECT),
00136              errmsg(msgfmt, name, get_namespace_name(nspOid))));
00137 }
00138 
00139 /*
00140  * AlterObjectRename_internal
00141  *
00142  * Generic function to rename the given object, for simple cases (won't
00143  * work for tables, nor other cases where we need to do more than change
00144  * the name column of a single catalog entry).
00145  *
00146  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
00147  * objectId: OID of object to be renamed
00148  * new_name: CString representation of new name
00149  */
00150 static void
00151 AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
00152 {
00153     Oid         classId = RelationGetRelid(rel);
00154     int         oidCacheId = get_object_catcache_oid(classId);
00155     int         nameCacheId = get_object_catcache_name(classId);
00156     AttrNumber  Anum_name = get_object_attnum_name(classId);
00157     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
00158     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
00159     AclObjectKind acl_kind = get_object_aclkind(classId);
00160     HeapTuple   oldtup;
00161     HeapTuple   newtup;
00162     Datum       datum;
00163     bool        isnull;
00164     Oid         namespaceId;
00165     Oid         ownerId;
00166     char       *old_name;
00167     AclResult   aclresult;
00168     Datum      *values;
00169     bool       *nulls;
00170     bool       *replaces;
00171 
00172     oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
00173     if (!HeapTupleIsValid(oldtup))
00174         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
00175              objectId, RelationGetRelationName(rel));
00176 
00177     datum = heap_getattr(oldtup, Anum_name,
00178                          RelationGetDescr(rel), &isnull);
00179     Assert(!isnull);
00180     old_name = NameStr(*(DatumGetName(datum)));
00181 
00182     /* Get OID of namespace */
00183     if (Anum_namespace > 0)
00184     {
00185         datum = heap_getattr(oldtup, Anum_namespace,
00186                              RelationGetDescr(rel), &isnull);
00187         Assert(!isnull);
00188         namespaceId = DatumGetObjectId(datum);
00189     }
00190     else
00191         namespaceId = InvalidOid;
00192 
00193     /* Permission checks ... superusers can always do it */
00194     if (!superuser())
00195     {
00196         /* Fail if object does not have an explicit owner */
00197         if (Anum_owner <= 0)
00198             ereport(ERROR,
00199                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00200                      (errmsg("must be superuser to rename %s",
00201                              getObjectDescriptionOids(classId, objectId)))));
00202 
00203         /* Otherwise, must be owner of the existing object */
00204         datum = heap_getattr(oldtup, Anum_owner,
00205                              RelationGetDescr(rel), &isnull);
00206         Assert(!isnull);
00207         ownerId = DatumGetObjectId(datum);
00208 
00209         if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
00210             aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind, old_name);
00211 
00212         /* User must have CREATE privilege on the namespace */
00213         if (OidIsValid(namespaceId))
00214         {
00215             aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
00216                                               ACL_CREATE);
00217             if (aclresult != ACLCHECK_OK)
00218                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00219                                get_namespace_name(namespaceId));
00220         }
00221     }
00222 
00223     /*
00224      * Check for duplicate name (more friendly than unique-index failure).
00225      * Since this is just a friendliness check, we can just skip it in cases
00226      * where there isn't suitable support.
00227      */
00228     if (classId == ProcedureRelationId)
00229     {
00230         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
00231 
00232         IsThereFunctionInNamespace(new_name, proc->pronargs,
00233                                    proc->proargtypes, proc->pronamespace);
00234     }
00235     else if (classId == CollationRelationId)
00236     {
00237         Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(oldtup);
00238 
00239         IsThereCollationInNamespace(new_name, coll->collnamespace);
00240     }
00241     else if (classId == OperatorClassRelationId)
00242     {
00243         Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
00244 
00245         IsThereOpClassInNamespace(new_name, opc->opcmethod,
00246                                   opc->opcnamespace);
00247     }
00248     else if (classId == OperatorFamilyRelationId)
00249     {
00250         Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(oldtup);
00251 
00252         IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
00253                                    opf->opfnamespace);
00254     }
00255     else if (nameCacheId >= 0)
00256     {
00257         if (OidIsValid(namespaceId))
00258         {
00259             if (SearchSysCacheExists2(nameCacheId,
00260                                       CStringGetDatum(new_name),
00261                                       ObjectIdGetDatum(namespaceId)))
00262                 report_namespace_conflict(classId, new_name, namespaceId);
00263         }
00264         else
00265         {
00266             if (SearchSysCacheExists1(nameCacheId,
00267                                       CStringGetDatum(new_name)))
00268                 report_name_conflict(classId, new_name);
00269         }
00270     }
00271 
00272     /* Build modified tuple */
00273     values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
00274     nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
00275     replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
00276     values[Anum_name - 1] = PointerGetDatum(new_name);
00277     replaces[Anum_name - 1] = true;
00278     newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
00279                                values, nulls, replaces);
00280 
00281     /* Perform actual update */
00282     simple_heap_update(rel, &oldtup->t_self, newtup);
00283     CatalogUpdateIndexes(rel, newtup);
00284 
00285     InvokeObjectPostAlterHook(classId, objectId, 0);
00286 
00287     /* Release memory */
00288     pfree(values);
00289     pfree(nulls);
00290     pfree(replaces);
00291     heap_freetuple(newtup);
00292 
00293     ReleaseSysCache(oldtup);
00294 }
00295 
00296 /*
00297  * Executes an ALTER OBJECT / RENAME TO statement.  Based on the object
00298  * type, the function appropriate to that type is executed.
00299  */
00300 Oid
00301 ExecRenameStmt(RenameStmt *stmt)
00302 {
00303     switch (stmt->renameType)
00304     {
00305         case OBJECT_CONSTRAINT:
00306             return RenameConstraint(stmt);
00307 
00308         case OBJECT_DATABASE:
00309             return RenameDatabase(stmt->subname, stmt->newname);
00310 
00311         case OBJECT_ROLE:
00312             return RenameRole(stmt->subname, stmt->newname);
00313 
00314         case OBJECT_SCHEMA:
00315             return RenameSchema(stmt->subname, stmt->newname);
00316 
00317         case OBJECT_TABLESPACE:
00318             return RenameTableSpace(stmt->subname, stmt->newname);
00319 
00320         case OBJECT_TABLE:
00321         case OBJECT_SEQUENCE:
00322         case OBJECT_VIEW:
00323         case OBJECT_MATVIEW:
00324         case OBJECT_INDEX:
00325         case OBJECT_FOREIGN_TABLE:
00326             return RenameRelation(stmt);
00327 
00328         case OBJECT_COLUMN:
00329         case OBJECT_ATTRIBUTE:
00330             return renameatt(stmt);
00331 
00332         case OBJECT_RULE:
00333             return RenameRewriteRule(stmt->relation, stmt->subname,
00334                                      stmt->newname);
00335 
00336         case OBJECT_TRIGGER:
00337             return renametrig(stmt);
00338 
00339         case OBJECT_DOMAIN:
00340         case OBJECT_TYPE:
00341             return RenameType(stmt);
00342 
00343         case OBJECT_AGGREGATE:
00344         case OBJECT_COLLATION:
00345         case OBJECT_CONVERSION:
00346         case OBJECT_EVENT_TRIGGER:
00347         case OBJECT_FDW:
00348         case OBJECT_FOREIGN_SERVER:
00349         case OBJECT_FUNCTION:
00350         case OBJECT_OPCLASS:
00351         case OBJECT_OPFAMILY:
00352         case OBJECT_LANGUAGE:
00353         case OBJECT_TSCONFIGURATION:
00354         case OBJECT_TSDICTIONARY:
00355         case OBJECT_TSPARSER:
00356         case OBJECT_TSTEMPLATE:
00357             {
00358                 ObjectAddress   address;
00359                 Relation        catalog;
00360                 Relation        relation;
00361 
00362                 address = get_object_address(stmt->renameType,
00363                                              stmt->object, stmt->objarg,
00364                                              &relation,
00365                                              AccessExclusiveLock, false);
00366                 Assert(relation == NULL);
00367 
00368                 catalog = heap_open(address.classId, RowExclusiveLock);
00369                 AlterObjectRename_internal(catalog,
00370                                            address.objectId,
00371                                            stmt->newname);
00372                 heap_close(catalog, RowExclusiveLock);
00373 
00374                 return address.objectId;
00375             }
00376 
00377         default:
00378             elog(ERROR, "unrecognized rename stmt type: %d",
00379                  (int) stmt->renameType);
00380             return InvalidOid;          /* keep compiler happy */
00381     }
00382 }
00383 
00384 /*
00385  * Executes an ALTER OBJECT / SET SCHEMA statement.  Based on the object
00386  * type, the function appropriate to that type is executed.
00387  */
00388 Oid
00389 ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
00390 {
00391     switch (stmt->objectType)
00392     {
00393         case OBJECT_EXTENSION:
00394             return AlterExtensionNamespace(stmt->object, stmt->newschema);
00395 
00396         case OBJECT_FOREIGN_TABLE:
00397         case OBJECT_SEQUENCE:
00398         case OBJECT_TABLE:
00399         case OBJECT_VIEW:
00400         case OBJECT_MATVIEW:
00401             return AlterTableNamespace(stmt);
00402 
00403         case OBJECT_DOMAIN:
00404         case OBJECT_TYPE:
00405             return AlterTypeNamespace(stmt->object, stmt->newschema,
00406                                       stmt->objectType);
00407 
00408             /* generic code path */
00409         case OBJECT_AGGREGATE:
00410         case OBJECT_COLLATION:
00411         case OBJECT_CONVERSION:
00412         case OBJECT_FUNCTION:
00413         case OBJECT_OPERATOR:
00414         case OBJECT_OPCLASS:
00415         case OBJECT_OPFAMILY:
00416         case OBJECT_TSCONFIGURATION:
00417         case OBJECT_TSDICTIONARY:
00418         case OBJECT_TSPARSER:
00419         case OBJECT_TSTEMPLATE:
00420             {
00421                 Relation    catalog;
00422                 Relation    relation;
00423                 Oid         classId;
00424                 Oid         nspOid;
00425                 ObjectAddress address;
00426 
00427                 address = get_object_address(stmt->objectType,
00428                                              stmt->object,
00429                                              stmt->objarg,
00430                                              &relation,
00431                                              AccessExclusiveLock,
00432                                              false);
00433                 Assert(relation == NULL);
00434                 classId = address.classId;
00435                 catalog = heap_open(classId, RowExclusiveLock);
00436                 nspOid = LookupCreationNamespace(stmt->newschema);
00437 
00438                 AlterObjectNamespace_internal(catalog, address.objectId,
00439                                               nspOid);
00440                 heap_close(catalog, RowExclusiveLock);
00441 
00442                 return address.objectId;
00443             }
00444             break;
00445 
00446         default:
00447             elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
00448                  (int) stmt->objectType);
00449             return InvalidOid;  /* keep compiler happy */
00450     }
00451 }
00452 
00453 /*
00454  * Change an object's namespace given its classOid and object Oid.
00455  *
00456  * Objects that don't have a namespace should be ignored.
00457  *
00458  * This function is currently used only by ALTER EXTENSION SET SCHEMA,
00459  * so it only needs to cover object types that can be members of an
00460  * extension, and it doesn't have to deal with certain special cases
00461  * such as not wanting to process array types --- those should never
00462  * be direct members of an extension anyway.
00463  *
00464  * Returns the OID of the object's previous namespace, or InvalidOid if
00465  * object doesn't have a schema.
00466  */
00467 Oid
00468 AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
00469                          ObjectAddresses *objsMoved)
00470 {
00471     Oid         oldNspOid = InvalidOid;
00472     ObjectAddress dep;
00473 
00474     dep.classId = classId;
00475     dep.objectId = objid;
00476     dep.objectSubId = 0;
00477 
00478     switch (getObjectClass(&dep))
00479     {
00480         case OCLASS_CLASS:
00481             {
00482                 Relation    rel;
00483 
00484                 rel = relation_open(objid, AccessExclusiveLock);
00485                 oldNspOid = RelationGetNamespace(rel);
00486 
00487                 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
00488 
00489                 relation_close(rel, NoLock);
00490                 break;
00491             }
00492 
00493         case OCLASS_TYPE:
00494             oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
00495             break;
00496 
00497         case OCLASS_COLLATION:
00498         case OCLASS_CONVERSION:
00499         case OCLASS_OPERATOR:
00500         case OCLASS_OPCLASS:
00501         case OCLASS_OPFAMILY:
00502         case OCLASS_PROC:
00503         case OCLASS_TSPARSER:
00504         case OCLASS_TSDICT:
00505         case OCLASS_TSTEMPLATE:
00506         case OCLASS_TSCONFIG:
00507             {
00508                 Relation    catalog;
00509 
00510                 catalog = heap_open(classId, RowExclusiveLock);
00511 
00512                 oldNspOid = AlterObjectNamespace_internal(catalog, objid,
00513                                                           nspOid);
00514 
00515                 heap_close(catalog, RowExclusiveLock);
00516             }
00517             break;
00518 
00519         default:
00520             break;
00521     }
00522 
00523     return oldNspOid;
00524 }
00525 
00526 /*
00527  * Generic function to change the namespace of a given object, for simple
00528  * cases (won't work for tables, nor other cases where we need to do more
00529  * than change the namespace column of a single catalog entry).
00530  *
00531  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
00532  * objid: OID of object to change the namespace of
00533  * nspOid: OID of new namespace
00534  *
00535  * Returns the OID of the object's previous namespace.
00536  */
00537 static Oid
00538 AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
00539 {
00540     Oid         classId = RelationGetRelid(rel);
00541     int         oidCacheId = get_object_catcache_oid(classId);
00542     int         nameCacheId = get_object_catcache_name(classId);
00543     AttrNumber  Anum_name = get_object_attnum_name(classId);
00544     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
00545     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
00546     AclObjectKind acl_kind = get_object_aclkind(classId);
00547     Oid         oldNspOid;
00548     Datum       name,
00549                 namespace;
00550     bool        isnull;
00551     HeapTuple   tup,
00552                 newtup;
00553     Datum      *values;
00554     bool       *nulls;
00555     bool       *replaces;
00556 
00557     tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
00558     if (!HeapTupleIsValid(tup)) /* should not happen */
00559         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
00560              objid, RelationGetRelationName(rel));
00561 
00562     name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
00563     Assert(!isnull);
00564     namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
00565                              &isnull);
00566     Assert(!isnull);
00567     oldNspOid = DatumGetObjectId(namespace);
00568 
00569     /* Check basic namespace related issues */
00570     CheckSetNamespace(oldNspOid, nspOid, classId, objid);
00571 
00572     /* Permission checks ... superusers can always do it */
00573     if (!superuser())
00574     {
00575         Datum       owner;
00576         Oid         ownerId;
00577         AclResult   aclresult;
00578 
00579         /* Fail if object does not have an explicit owner */
00580         if (Anum_owner <= 0)
00581             ereport(ERROR,
00582                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00583                      (errmsg("must be superuser to set schema of %s",
00584                              getObjectDescriptionOids(classId, objid)))));
00585 
00586         /* Otherwise, must be owner of the existing object */
00587         owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
00588         Assert(!isnull);
00589         ownerId = DatumGetObjectId(owner);
00590 
00591         if (!has_privs_of_role(GetUserId(), ownerId))
00592             aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
00593                            NameStr(*(DatumGetName(name))));
00594 
00595         /* User must have CREATE privilege on new namespace */
00596         aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
00597         if (aclresult != ACLCHECK_OK)
00598             aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00599                            get_namespace_name(nspOid));
00600     }
00601 
00602     /*
00603      * Check for duplicate name (more friendly than unique-index failure).
00604      * Since this is just a friendliness check, we can just skip it in cases
00605      * where there isn't suitable support.
00606      */
00607     if (classId == ProcedureRelationId)
00608     {
00609         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
00610 
00611         IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
00612                                    proc->proargtypes, nspOid);
00613     }
00614     else if (classId == CollationRelationId)
00615     {
00616         Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
00617 
00618         IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
00619     }
00620     else if (classId == OperatorClassRelationId)
00621     {
00622         Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
00623 
00624         IsThereOpClassInNamespace(NameStr(opc->opcname),
00625                                   opc->opcmethod, nspOid);
00626     }
00627     else if (classId == OperatorFamilyRelationId)
00628     {
00629         Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
00630 
00631         IsThereOpFamilyInNamespace(NameStr(opf->opfname),
00632                                    opf->opfmethod, nspOid);
00633     }
00634     else if (nameCacheId >= 0 &&
00635              SearchSysCacheExists2(nameCacheId, name,
00636                                    ObjectIdGetDatum(nspOid)))
00637         report_namespace_conflict(classId,
00638                                   NameStr(*(DatumGetName(name))),
00639                                   nspOid);
00640 
00641     /* Build modified tuple */
00642     values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
00643     nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
00644     replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
00645     values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
00646     replaces[Anum_namespace - 1] = true;
00647     newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
00648                                values, nulls, replaces);
00649 
00650     /* Perform actual update */
00651     simple_heap_update(rel, &tup->t_self, newtup);
00652     CatalogUpdateIndexes(rel, newtup);
00653 
00654     /* Release memory */
00655     pfree(values);
00656     pfree(nulls);
00657     pfree(replaces);
00658 
00659     /* update dependencies to point to the new schema */
00660     changeDependencyFor(classId, objid,
00661                         NamespaceRelationId, oldNspOid, nspOid);
00662 
00663     InvokeObjectPostAlterHook(classId, objid, 0);
00664 
00665     return oldNspOid;
00666 }
00667 
00668 /*
00669  * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
00670  * type, the function appropriate to that type is executed.
00671  */
00672 Oid
00673 ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
00674 {
00675     Oid         newowner = get_role_oid(stmt->newowner, false);
00676 
00677     switch (stmt->objectType)
00678     {
00679         case OBJECT_DATABASE:
00680             return AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
00681 
00682         case OBJECT_SCHEMA:
00683             return AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
00684 
00685         case OBJECT_TYPE:
00686         case OBJECT_DOMAIN:     /* same as TYPE */
00687             return AlterTypeOwner(stmt->object, newowner, stmt->objectType);
00688             break;
00689 
00690         case OBJECT_FDW:
00691             return AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
00692                                                 newowner);
00693 
00694         case OBJECT_FOREIGN_SERVER:
00695             return AlterForeignServerOwner(strVal(linitial(stmt->object)),
00696                                            newowner);
00697 
00698         case OBJECT_EVENT_TRIGGER:
00699             return AlterEventTriggerOwner(strVal(linitial(stmt->object)),
00700                                           newowner);
00701 
00702         /* Generic cases */
00703         case OBJECT_AGGREGATE:
00704         case OBJECT_COLLATION:
00705         case OBJECT_CONVERSION:
00706         case OBJECT_FUNCTION:
00707         case OBJECT_LANGUAGE:
00708         case OBJECT_LARGEOBJECT:
00709         case OBJECT_OPERATOR:
00710         case OBJECT_OPCLASS:
00711         case OBJECT_OPFAMILY:
00712         case OBJECT_TABLESPACE:
00713         case OBJECT_TSDICTIONARY:
00714         case OBJECT_TSCONFIGURATION:
00715             {
00716                 Relation    catalog;
00717                 Relation    relation;
00718                 Oid         classId;
00719                 ObjectAddress   address;
00720 
00721                 address = get_object_address(stmt->objectType,
00722                                              stmt->object,
00723                                              stmt->objarg,
00724                                              &relation,
00725                                              AccessExclusiveLock,
00726                                              false);
00727                 Assert(relation == NULL);
00728                 classId = address.classId;
00729 
00730                 /*
00731                  * XXX - get_object_address returns Oid of pg_largeobject
00732                  * catalog for OBJECT_LARGEOBJECT because of historical
00733                  * reasons.  Fix up it here.
00734                  */
00735                 if (classId == LargeObjectRelationId)
00736                     classId = LargeObjectMetadataRelationId;
00737 
00738                 catalog = heap_open(classId, RowExclusiveLock);
00739 
00740                 AlterObjectOwner_internal(catalog, address.objectId, newowner);
00741                 heap_close(catalog, RowExclusiveLock);
00742 
00743                 return address.objectId;
00744             }
00745             break;
00746 
00747         default:
00748             elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
00749                  (int) stmt->objectType);
00750 
00751             return InvalidOid;  /* keep compiler happy */
00752     }
00753 }
00754 
00755 /*
00756  * Generic function to change the ownership of a given object, for simple
00757  * cases (won't work for tables, nor other cases where we need to do more than
00758  * change the ownership column of a single catalog entry).
00759  *
00760  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
00761  * objectId: OID of object to change the ownership of
00762  * new_ownerId: OID of new object owner
00763  */
00764 void
00765 AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
00766 {
00767     Oid         classId = RelationGetRelid(rel);
00768     AttrNumber  Anum_owner = get_object_attnum_owner(classId);
00769     AttrNumber  Anum_namespace = get_object_attnum_namespace(classId);
00770     AttrNumber  Anum_acl = get_object_attnum_acl(classId);
00771     AttrNumber  Anum_name = get_object_attnum_name(classId);
00772     HeapTuple   oldtup;
00773     Datum       datum;
00774     bool        isnull;
00775     Oid         old_ownerId;
00776     Oid         namespaceId = InvalidOid;
00777 
00778     oldtup = get_catalog_object_by_oid(rel, objectId);
00779     if (oldtup == NULL)
00780         elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
00781              objectId, RelationGetRelationName(rel));
00782 
00783     datum = heap_getattr(oldtup, Anum_owner,
00784                          RelationGetDescr(rel), &isnull);
00785     Assert(!isnull);
00786     old_ownerId = DatumGetObjectId(datum);
00787 
00788     if (Anum_namespace != InvalidAttrNumber)
00789     {
00790         datum = heap_getattr(oldtup, Anum_namespace,
00791                              RelationGetDescr(rel), &isnull);
00792         Assert(!isnull);
00793         namespaceId = DatumGetObjectId(datum);
00794     }
00795 
00796     if (old_ownerId != new_ownerId)
00797     {
00798         AttrNumber  nattrs;
00799         HeapTuple   newtup;
00800         Datum      *values;
00801         bool       *nulls;
00802         bool       *replaces;
00803 
00804         /* Superusers can bypass permission checks */
00805         if (!superuser())
00806         {
00807             AclObjectKind   aclkind = get_object_aclkind(classId);
00808 
00809             /* must be owner */
00810             if (!has_privs_of_role(GetUserId(), old_ownerId))
00811             {
00812                 char   *objname;
00813                 char    namebuf[NAMEDATALEN];
00814 
00815                 if (Anum_name != InvalidAttrNumber)
00816                 {
00817                     datum = heap_getattr(oldtup, Anum_name,
00818                                          RelationGetDescr(rel), &isnull);
00819                     Assert(!isnull);
00820                     objname = NameStr(*DatumGetName(datum));
00821                 }
00822                 else
00823                 {
00824                     snprintf(namebuf, sizeof(namebuf), "%u",
00825                              HeapTupleGetOid(oldtup));
00826                     objname = namebuf;
00827                 }
00828                 aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
00829             }
00830             /* Must be able to become new owner */
00831             check_is_member_of_role(GetUserId(), new_ownerId);
00832 
00833             /* New owner must have CREATE privilege on namespace */
00834             if (OidIsValid(namespaceId))
00835             {
00836                 AclResult   aclresult;
00837 
00838                 aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
00839                                                   ACL_CREATE);
00840                 if (aclresult != ACLCHECK_OK)
00841                     aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00842                                    get_namespace_name(namespaceId));
00843             }
00844         }
00845 
00846         /* Build a modified tuple */
00847         nattrs = RelationGetNumberOfAttributes(rel);
00848         values = palloc0(nattrs * sizeof(Datum));
00849         nulls = palloc0(nattrs * sizeof(bool));
00850         replaces = palloc0(nattrs * sizeof(bool));
00851         values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
00852         replaces[Anum_owner - 1] = true;
00853 
00854         /*
00855          * Determine the modified ACL for the new owner.  This is only
00856          * necessary when the ACL is non-null.
00857          */
00858         if (Anum_acl != InvalidAttrNumber)
00859         {
00860             datum = heap_getattr(oldtup,
00861                                  Anum_acl, RelationGetDescr(rel), &isnull);
00862             if (!isnull)
00863             {
00864                 Acl    *newAcl;
00865 
00866                 newAcl = aclnewowner(DatumGetAclP(datum),
00867                                      old_ownerId, new_ownerId);
00868                 values[Anum_acl - 1] = PointerGetDatum(newAcl);
00869                 replaces[Anum_acl - 1] = true;
00870             }
00871         }
00872 
00873         newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
00874                                    values, nulls, replaces);
00875 
00876         /* Perform actual update */
00877         simple_heap_update(rel, &newtup->t_self, newtup);
00878         CatalogUpdateIndexes(rel, newtup);
00879 
00880         /* Update owner dependency reference */
00881         if (classId == LargeObjectMetadataRelationId)
00882             classId = LargeObjectRelationId;
00883         changeDependencyOnOwner(classId, HeapTupleGetOid(newtup), new_ownerId);
00884 
00885         /* Release memory */
00886         pfree(values);
00887         pfree(nulls);
00888         pfree(replaces);
00889     }
00890 
00891     InvokeObjectPostAlterHook(classId, objectId, 0);
00892 }