PostgreSQL Source Code  git master
alter.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * alter.c
4  * Drivers for generic alter commands
5  *
6  * Portions Copyright (c) 1996-2018, 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/sysattr.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/namespace.h"
22 #include "catalog/objectaccess.h"
23 #include "catalog/pg_collation.h"
24 #include "catalog/pg_conversion.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_largeobject.h"
31 #include "catalog/pg_namespace.h"
32 #include "catalog/pg_opclass.h"
33 #include "catalog/pg_opfamily.h"
34 #include "catalog/pg_proc.h"
37 #include "catalog/pg_ts_config.h"
38 #include "catalog/pg_ts_dict.h"
39 #include "catalog/pg_ts_parser.h"
40 #include "catalog/pg_ts_template.h"
41 #include "commands/alter.h"
42 #include "commands/collationcmds.h"
44 #include "commands/dbcommands.h"
45 #include "commands/defrem.h"
46 #include "commands/event_trigger.h"
47 #include "commands/extension.h"
48 #include "commands/policy.h"
49 #include "commands/proclang.h"
51 #include "commands/schemacmds.h"
53 #include "commands/tablecmds.h"
54 #include "commands/tablespace.h"
55 #include "commands/trigger.h"
56 #include "commands/typecmds.h"
57 #include "commands/user.h"
58 #include "parser/parse_func.h"
59 #include "miscadmin.h"
60 #include "rewrite/rewriteDefine.h"
61 #include "tcop/utility.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/lsyscache.h"
65 #include "utils/rel.h"
66 #include "utils/syscache.h"
67 #include "utils/tqual.h"
68 
69 
70 static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
71 
72 /*
73  * Raise an error to the effect that an object of the given name is already
74  * present in the given namespace.
75  */
76 static void
77 report_name_conflict(Oid classId, const char *name)
78 {
79  char *msgfmt;
80 
81  switch (classId)
82  {
83  case EventTriggerRelationId:
84  msgfmt = gettext_noop("event trigger \"%s\" already exists");
85  break;
86  case ForeignDataWrapperRelationId:
87  msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
88  break;
89  case ForeignServerRelationId:
90  msgfmt = gettext_noop("server \"%s\" already exists");
91  break;
92  case LanguageRelationId:
93  msgfmt = gettext_noop("language \"%s\" already exists");
94  break;
95  case PublicationRelationId:
96  msgfmt = gettext_noop("publication \"%s\" already exists");
97  break;
98  case SubscriptionRelationId:
99  msgfmt = gettext_noop("subscription \"%s\" already exists");
100  break;
101  default:
102  elog(ERROR, "unsupported object class %u", classId);
103  break;
104  }
105 
106  ereport(ERROR,
108  errmsg(msgfmt, name)));
109 }
110 
111 static void
112 report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
113 {
114  char *msgfmt;
115 
116  Assert(OidIsValid(nspOid));
117 
118  switch (classId)
119  {
120  case ConversionRelationId:
121  Assert(OidIsValid(nspOid));
122  msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
123  break;
124  case StatisticExtRelationId:
125  Assert(OidIsValid(nspOid));
126  msgfmt = gettext_noop("statistics object \"%s\" already exists in schema \"%s\"");
127  break;
128  case TSParserRelationId:
129  Assert(OidIsValid(nspOid));
130  msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
131  break;
132  case TSDictionaryRelationId:
133  Assert(OidIsValid(nspOid));
134  msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
135  break;
136  case TSTemplateRelationId:
137  Assert(OidIsValid(nspOid));
138  msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
139  break;
140  case TSConfigRelationId:
141  Assert(OidIsValid(nspOid));
142  msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
143  break;
144  default:
145  elog(ERROR, "unsupported object class %u", classId);
146  break;
147  }
148 
149  ereport(ERROR,
151  errmsg(msgfmt, name, get_namespace_name(nspOid))));
152 }
153 
154 /*
155  * AlterObjectRename_internal
156  *
157  * Generic function to rename the given object, for simple cases (won't
158  * work for tables, nor other cases where we need to do more than change
159  * the name column of a single catalog entry).
160  *
161  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
162  * objectId: OID of object to be renamed
163  * new_name: CString representation of new name
164  */
165 static void
166 AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
167 {
168  Oid classId = RelationGetRelid(rel);
169  int oidCacheId = get_object_catcache_oid(classId);
170  int nameCacheId = get_object_catcache_name(classId);
171  AttrNumber Anum_name = get_object_attnum_name(classId);
172  AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
173  AttrNumber Anum_owner = get_object_attnum_owner(classId);
174  ObjectType objtype = get_object_type(classId, objectId);
175  HeapTuple oldtup;
176  HeapTuple newtup;
177  Datum datum;
178  bool isnull;
179  Oid namespaceId;
180  Oid ownerId;
181  char *old_name;
182  AclResult aclresult;
183  Datum *values;
184  bool *nulls;
185  bool *replaces;
186  NameData nameattrdata;
187 
188  oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
189  if (!HeapTupleIsValid(oldtup))
190  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
191  objectId, RelationGetRelationName(rel));
192 
193  datum = heap_getattr(oldtup, Anum_name,
194  RelationGetDescr(rel), &isnull);
195  Assert(!isnull);
196  old_name = NameStr(*(DatumGetName(datum)));
197 
198  /* Get OID of namespace */
199  if (Anum_namespace > 0)
200  {
201  datum = heap_getattr(oldtup, Anum_namespace,
202  RelationGetDescr(rel), &isnull);
203  Assert(!isnull);
204  namespaceId = DatumGetObjectId(datum);
205  }
206  else
207  namespaceId = InvalidOid;
208 
209  /* Permission checks ... superusers can always do it */
210  if (!superuser())
211  {
212  /* Fail if object does not have an explicit owner */
213  if (Anum_owner <= 0)
214  ereport(ERROR,
215  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
216  (errmsg("must be superuser to rename %s",
217  getObjectDescriptionOids(classId, objectId)))));
218 
219  /* Otherwise, must be owner of the existing object */
220  datum = heap_getattr(oldtup, Anum_owner,
221  RelationGetDescr(rel), &isnull);
222  Assert(!isnull);
223  ownerId = DatumGetObjectId(datum);
224 
225  if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
226  aclcheck_error(ACLCHECK_NOT_OWNER, objtype, old_name);
227 
228  /* User must have CREATE privilege on the namespace */
229  if (OidIsValid(namespaceId))
230  {
231  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
232  ACL_CREATE);
233  if (aclresult != ACLCHECK_OK)
234  aclcheck_error(aclresult, OBJECT_SCHEMA,
235  get_namespace_name(namespaceId));
236  }
237  }
238 
239  /*
240  * Check for duplicate name (more friendly than unique-index failure).
241  * Since this is just a friendliness check, we can just skip it in cases
242  * where there isn't suitable support.
243  */
244  if (classId == ProcedureRelationId)
245  {
246  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
247 
248  IsThereFunctionInNamespace(new_name, proc->pronargs,
249  &proc->proargtypes, proc->pronamespace);
250  }
251  else if (classId == CollationRelationId)
252  {
254 
255  IsThereCollationInNamespace(new_name, coll->collnamespace);
256  }
257  else if (classId == OperatorClassRelationId)
258  {
259  Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
260 
261  IsThereOpClassInNamespace(new_name, opc->opcmethod,
262  opc->opcnamespace);
263  }
264  else if (classId == OperatorFamilyRelationId)
265  {
267 
268  IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
269  opf->opfnamespace);
270  }
271  else if (classId == SubscriptionRelationId)
272  {
274  CStringGetDatum(new_name)))
275  report_name_conflict(classId, new_name);
276  }
277  else if (nameCacheId >= 0)
278  {
279  if (OidIsValid(namespaceId))
280  {
281  if (SearchSysCacheExists2(nameCacheId,
282  CStringGetDatum(new_name),
283  ObjectIdGetDatum(namespaceId)))
284  report_namespace_conflict(classId, new_name, namespaceId);
285  }
286  else
287  {
288  if (SearchSysCacheExists1(nameCacheId,
289  CStringGetDatum(new_name)))
290  report_name_conflict(classId, new_name);
291  }
292  }
293 
294  /* Build modified tuple */
295  values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
296  nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
297  replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
298  namestrcpy(&nameattrdata, new_name);
299  values[Anum_name - 1] = NameGetDatum(&nameattrdata);
300  replaces[Anum_name - 1] = true;
301  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
302  values, nulls, replaces);
303 
304  /* Perform actual update */
305  CatalogTupleUpdate(rel, &oldtup->t_self, newtup);
306 
307  InvokeObjectPostAlterHook(classId, objectId, 0);
308 
309  /* Release memory */
310  pfree(values);
311  pfree(nulls);
312  pfree(replaces);
313  heap_freetuple(newtup);
314 
315  ReleaseSysCache(oldtup);
316 }
317 
318 /*
319  * Executes an ALTER OBJECT / RENAME TO statement. Based on the object
320  * type, the function appropriate to that type is executed.
321  *
322  * Return value is the address of the renamed object.
323  */
326 {
327  switch (stmt->renameType)
328  {
331  return RenameConstraint(stmt);
332 
333  case OBJECT_DATABASE:
334  return RenameDatabase(stmt->subname, stmt->newname);
335 
336  case OBJECT_ROLE:
337  return RenameRole(stmt->subname, stmt->newname);
338 
339  case OBJECT_SCHEMA:
340  return RenameSchema(stmt->subname, stmt->newname);
341 
342  case OBJECT_TABLESPACE:
343  return RenameTableSpace(stmt->subname, stmt->newname);
344 
345  case OBJECT_TABLE:
346  case OBJECT_SEQUENCE:
347  case OBJECT_VIEW:
348  case OBJECT_MATVIEW:
349  case OBJECT_INDEX:
351  return RenameRelation(stmt);
352 
353  case OBJECT_COLUMN:
354  case OBJECT_ATTRIBUTE:
355  return renameatt(stmt);
356 
357  case OBJECT_RULE:
358  return RenameRewriteRule(stmt->relation, stmt->subname,
359  stmt->newname);
360 
361  case OBJECT_TRIGGER:
362  return renametrig(stmt);
363 
364  case OBJECT_POLICY:
365  return rename_policy(stmt);
366 
367  case OBJECT_DOMAIN:
368  case OBJECT_TYPE:
369  return RenameType(stmt);
370 
371  case OBJECT_AGGREGATE:
372  case OBJECT_COLLATION:
373  case OBJECT_CONVERSION:
375  case OBJECT_FDW:
377  case OBJECT_FUNCTION:
378  case OBJECT_OPCLASS:
379  case OBJECT_OPFAMILY:
380  case OBJECT_LANGUAGE:
381  case OBJECT_PROCEDURE:
382  case OBJECT_ROUTINE:
385  case OBJECT_TSDICTIONARY:
386  case OBJECT_TSPARSER:
387  case OBJECT_TSTEMPLATE:
388  case OBJECT_PUBLICATION:
389  case OBJECT_SUBSCRIPTION:
390  {
391  ObjectAddress address;
392  Relation catalog;
393  Relation relation;
394 
395  address = get_object_address(stmt->renameType,
396  stmt->object,
397  &relation,
398  AccessExclusiveLock, false);
399  Assert(relation == NULL);
400 
401  catalog = heap_open(address.classId, RowExclusiveLock);
403  address.objectId,
404  stmt->newname);
405  heap_close(catalog, RowExclusiveLock);
406 
407  return address;
408  }
409 
410  default:
411  elog(ERROR, "unrecognized rename stmt type: %d",
412  (int) stmt->renameType);
413  return InvalidObjectAddress; /* keep compiler happy */
414  }
415 }
416 
417 /*
418  * Executes an ALTER OBJECT / DEPENDS ON [EXTENSION] statement.
419  *
420  * Return value is the address of the altered object. refAddress is an output
421  * argument which, if not null, receives the address of the object that the
422  * altered object now depends on.
423  */
426 {
427  ObjectAddress address;
428  ObjectAddress refAddr;
429  Relation rel;
430 
431  address =
432  get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
433  &rel, AccessExclusiveLock, false);
434 
435  /*
436  * If a relation was involved, it would have been opened and locked. We
437  * don't need the relation here, but we'll retain the lock until commit.
438  */
439  if (rel)
440  heap_close(rel, NoLock);
441 
442  refAddr = get_object_address(OBJECT_EXTENSION, (Node *) stmt->extname,
443  &rel, AccessExclusiveLock, false);
444  Assert(rel == NULL);
445  if (refAddress)
446  *refAddress = refAddr;
447 
448  recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
449 
450  return address;
451 }
452 
453 /*
454  * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
455  * type, the function appropriate to that type is executed.
456  *
457  * Return value is that of the altered object.
458  *
459  * oldSchemaAddr is an output argument which, if not NULL, is set to the object
460  * address of the original schema.
461  */
464  ObjectAddress *oldSchemaAddr)
465 {
466  ObjectAddress address;
467  Oid oldNspOid;
468 
469  switch (stmt->objectType)
470  {
471  case OBJECT_EXTENSION:
472  address = AlterExtensionNamespace(strVal((Value *) stmt->object), stmt->newschema,
473  oldSchemaAddr ? &oldNspOid : NULL);
474  break;
475 
477  case OBJECT_SEQUENCE:
478  case OBJECT_TABLE:
479  case OBJECT_VIEW:
480  case OBJECT_MATVIEW:
481  address = AlterTableNamespace(stmt,
482  oldSchemaAddr ? &oldNspOid : NULL);
483  break;
484 
485  case OBJECT_DOMAIN:
486  case OBJECT_TYPE:
487  address = AlterTypeNamespace(castNode(List, stmt->object), stmt->newschema,
488  stmt->objectType,
489  oldSchemaAddr ? &oldNspOid : NULL);
490  break;
491 
492  /* generic code path */
493  case OBJECT_AGGREGATE:
494  case OBJECT_COLLATION:
495  case OBJECT_CONVERSION:
496  case OBJECT_FUNCTION:
497  case OBJECT_OPERATOR:
498  case OBJECT_OPCLASS:
499  case OBJECT_OPFAMILY:
500  case OBJECT_PROCEDURE:
501  case OBJECT_ROUTINE:
504  case OBJECT_TSDICTIONARY:
505  case OBJECT_TSPARSER:
506  case OBJECT_TSTEMPLATE:
507  {
508  Relation catalog;
509  Relation relation;
510  Oid classId;
511  Oid nspOid;
512 
513  address = get_object_address(stmt->objectType,
514  stmt->object,
515  &relation,
517  false);
518  Assert(relation == NULL);
519  classId = address.classId;
520  catalog = heap_open(classId, RowExclusiveLock);
521  nspOid = LookupCreationNamespace(stmt->newschema);
522 
523  oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
524  nspOid);
525  heap_close(catalog, RowExclusiveLock);
526  }
527  break;
528 
529  default:
530  elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
531  (int) stmt->objectType);
532  return InvalidObjectAddress; /* keep compiler happy */
533  }
534 
535  if (oldSchemaAddr)
536  ObjectAddressSet(*oldSchemaAddr, NamespaceRelationId, oldNspOid);
537 
538  return address;
539 }
540 
541 /*
542  * Change an object's namespace given its classOid and object Oid.
543  *
544  * Objects that don't have a namespace should be ignored.
545  *
546  * This function is currently used only by ALTER EXTENSION SET SCHEMA,
547  * so it only needs to cover object types that can be members of an
548  * extension, and it doesn't have to deal with certain special cases
549  * such as not wanting to process array types --- those should never
550  * be direct members of an extension anyway. Nonetheless, we insist
551  * on listing all OCLASS types in the switch.
552  *
553  * Returns the OID of the object's previous namespace, or InvalidOid if
554  * object doesn't have a schema.
555  */
556 Oid
557 AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
558  ObjectAddresses *objsMoved)
559 {
560  Oid oldNspOid = InvalidOid;
561  ObjectAddress dep;
562 
563  dep.classId = classId;
564  dep.objectId = objid;
565  dep.objectSubId = 0;
566 
567  switch (getObjectClass(&dep))
568  {
569  case OCLASS_CLASS:
570  {
571  Relation rel;
572 
573  rel = relation_open(objid, AccessExclusiveLock);
574  oldNspOid = RelationGetNamespace(rel);
575 
576  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
577 
578  relation_close(rel, NoLock);
579  break;
580  }
581 
582  case OCLASS_TYPE:
583  oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
584  break;
585 
586  case OCLASS_PROC:
587  case OCLASS_COLLATION:
588  case OCLASS_CONVERSION:
589  case OCLASS_OPERATOR:
590  case OCLASS_OPCLASS:
591  case OCLASS_OPFAMILY:
593  case OCLASS_TSPARSER:
594  case OCLASS_TSDICT:
595  case OCLASS_TSTEMPLATE:
596  case OCLASS_TSCONFIG:
597  {
598  Relation catalog;
599 
600  catalog = heap_open(classId, RowExclusiveLock);
601 
602  oldNspOid = AlterObjectNamespace_internal(catalog, objid,
603  nspOid);
604 
605  heap_close(catalog, RowExclusiveLock);
606  }
607  break;
608 
609  case OCLASS_CAST:
610  case OCLASS_CONSTRAINT:
611  case OCLASS_DEFAULT:
612  case OCLASS_LANGUAGE:
613  case OCLASS_LARGEOBJECT:
614  case OCLASS_AM:
615  case OCLASS_AMOP:
616  case OCLASS_AMPROC:
617  case OCLASS_REWRITE:
618  case OCLASS_TRIGGER:
619  case OCLASS_SCHEMA:
620  case OCLASS_ROLE:
621  case OCLASS_DATABASE:
622  case OCLASS_TBLSPACE:
623  case OCLASS_FDW:
625  case OCLASS_USER_MAPPING:
626  case OCLASS_DEFACL:
627  case OCLASS_EXTENSION:
629  case OCLASS_POLICY:
630  case OCLASS_PUBLICATION:
632  case OCLASS_SUBSCRIPTION:
633  case OCLASS_TRANSFORM:
634  /* ignore object types that don't have schema-qualified names */
635  break;
636 
637  /*
638  * There's intentionally no default: case here; we want the
639  * compiler to warn if a new OCLASS hasn't been handled above.
640  */
641  }
642 
643  return oldNspOid;
644 }
645 
646 /*
647  * Generic function to change the namespace of a given object, for simple
648  * cases (won't work for tables, nor other cases where we need to do more
649  * than change the namespace column of a single catalog entry).
650  *
651  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
652  * objid: OID of object to change the namespace of
653  * nspOid: OID of new namespace
654  *
655  * Returns the OID of the object's previous namespace.
656  */
657 static Oid
659 {
660  Oid classId = RelationGetRelid(rel);
661  int oidCacheId = get_object_catcache_oid(classId);
662  int nameCacheId = get_object_catcache_name(classId);
663  AttrNumber Anum_name = get_object_attnum_name(classId);
664  AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
665  AttrNumber Anum_owner = get_object_attnum_owner(classId);
666  ObjectType objtype = get_object_type(classId, objid);
667  Oid oldNspOid;
668  Datum name,
669  namespace;
670  bool isnull;
671  HeapTuple tup,
672  newtup;
673  Datum *values;
674  bool *nulls;
675  bool *replaces;
676 
677  tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
678  if (!HeapTupleIsValid(tup)) /* should not happen */
679  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
680  objid, RelationGetRelationName(rel));
681 
682  name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
683  Assert(!isnull);
684  namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
685  &isnull);
686  Assert(!isnull);
687  oldNspOid = DatumGetObjectId(namespace);
688 
689  /*
690  * If the object is already in the correct namespace, we don't need to do
691  * anything except fire the object access hook.
692  */
693  if (oldNspOid == nspOid)
694  {
695  InvokeObjectPostAlterHook(classId, objid, 0);
696  return oldNspOid;
697  }
698 
699  /* Check basic namespace related issues */
700  CheckSetNamespace(oldNspOid, nspOid);
701 
702  /* Permission checks ... superusers can always do it */
703  if (!superuser())
704  {
705  Datum owner;
706  Oid ownerId;
707  AclResult aclresult;
708 
709  /* Fail if object does not have an explicit owner */
710  if (Anum_owner <= 0)
711  ereport(ERROR,
712  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
713  (errmsg("must be superuser to set schema of %s",
714  getObjectDescriptionOids(classId, objid)))));
715 
716  /* Otherwise, must be owner of the existing object */
717  owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
718  Assert(!isnull);
719  ownerId = DatumGetObjectId(owner);
720 
721  if (!has_privs_of_role(GetUserId(), ownerId))
723  NameStr(*(DatumGetName(name))));
724 
725  /* User must have CREATE privilege on new namespace */
726  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
727  if (aclresult != ACLCHECK_OK)
728  aclcheck_error(aclresult, OBJECT_SCHEMA,
729  get_namespace_name(nspOid));
730  }
731 
732  /*
733  * Check for duplicate name (more friendly than unique-index failure).
734  * Since this is just a friendliness check, we can just skip it in cases
735  * where there isn't suitable support.
736  */
737  if (classId == ProcedureRelationId)
738  {
739  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
740 
741  IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
742  &proc->proargtypes, nspOid);
743  }
744  else if (classId == CollationRelationId)
745  {
747 
748  IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
749  }
750  else if (classId == OperatorClassRelationId)
751  {
753 
754  IsThereOpClassInNamespace(NameStr(opc->opcname),
755  opc->opcmethod, nspOid);
756  }
757  else if (classId == OperatorFamilyRelationId)
758  {
760 
761  IsThereOpFamilyInNamespace(NameStr(opf->opfname),
762  opf->opfmethod, nspOid);
763  }
764  else if (nameCacheId >= 0 &&
765  SearchSysCacheExists2(nameCacheId, name,
766  ObjectIdGetDatum(nspOid)))
768  NameStr(*(DatumGetName(name))),
769  nspOid);
770 
771  /* Build modified tuple */
772  values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
773  nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
774  replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
775  values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
776  replaces[Anum_namespace - 1] = true;
777  newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
778  values, nulls, replaces);
779 
780  /* Perform actual update */
781  CatalogTupleUpdate(rel, &tup->t_self, newtup);
782 
783  /* Release memory */
784  pfree(values);
785  pfree(nulls);
786  pfree(replaces);
787 
788  /* update dependencies to point to the new schema */
789  changeDependencyFor(classId, objid,
790  NamespaceRelationId, oldNspOid, nspOid);
791 
792  InvokeObjectPostAlterHook(classId, objid, 0);
793 
794  return oldNspOid;
795 }
796 
797 /*
798  * Executes an ALTER OBJECT / OWNER TO statement. Based on the object
799  * type, the function appropriate to that type is executed.
800  */
803 {
804  Oid newowner = get_rolespec_oid(stmt->newowner, false);
805 
806  switch (stmt->objectType)
807  {
808  case OBJECT_DATABASE:
809  return AlterDatabaseOwner(strVal((Value *) stmt->object), newowner);
810 
811  case OBJECT_SCHEMA:
812  return AlterSchemaOwner(strVal((Value *) stmt->object), newowner);
813 
814  case OBJECT_TYPE:
815  case OBJECT_DOMAIN: /* same as TYPE */
816  return AlterTypeOwner(castNode(List, stmt->object), newowner, stmt->objectType);
817  break;
818 
819  case OBJECT_FDW:
821  newowner);
822 
824  return AlterForeignServerOwner(strVal((Value *) stmt->object),
825  newowner);
826 
828  return AlterEventTriggerOwner(strVal((Value *) stmt->object),
829  newowner);
830 
831  case OBJECT_PUBLICATION:
832  return AlterPublicationOwner(strVal((Value *) stmt->object),
833  newowner);
834 
835  case OBJECT_SUBSCRIPTION:
836  return AlterSubscriptionOwner(strVal((Value *) stmt->object),
837  newowner);
838 
839  /* Generic cases */
840  case OBJECT_AGGREGATE:
841  case OBJECT_COLLATION:
842  case OBJECT_CONVERSION:
843  case OBJECT_FUNCTION:
844  case OBJECT_LANGUAGE:
845  case OBJECT_LARGEOBJECT:
846  case OBJECT_OPERATOR:
847  case OBJECT_OPCLASS:
848  case OBJECT_OPFAMILY:
849  case OBJECT_PROCEDURE:
850  case OBJECT_ROUTINE:
852  case OBJECT_TABLESPACE:
853  case OBJECT_TSDICTIONARY:
855  {
856  Relation catalog;
857  Relation relation;
858  Oid classId;
859  ObjectAddress address;
860 
861  address = get_object_address(stmt->objectType,
862  stmt->object,
863  &relation,
865  false);
866  Assert(relation == NULL);
867  classId = address.classId;
868 
869  /*
870  * XXX - get_object_address returns Oid of pg_largeobject
871  * catalog for OBJECT_LARGEOBJECT because of historical
872  * reasons. Fix up it here.
873  */
874  if (classId == LargeObjectRelationId)
875  classId = LargeObjectMetadataRelationId;
876 
877  catalog = heap_open(classId, RowExclusiveLock);
878 
879  AlterObjectOwner_internal(catalog, address.objectId, newowner);
880  heap_close(catalog, RowExclusiveLock);
881 
882  return address;
883  }
884  break;
885 
886  default:
887  elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
888  (int) stmt->objectType);
889  return InvalidObjectAddress; /* keep compiler happy */
890  }
891 }
892 
893 /*
894  * Generic function to change the ownership of a given object, for simple
895  * cases (won't work for tables, nor other cases where we need to do more than
896  * change the ownership column of a single catalog entry).
897  *
898  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
899  * objectId: OID of object to change the ownership of
900  * new_ownerId: OID of new object owner
901  */
902 void
903 AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
904 {
905  Oid classId = RelationGetRelid(rel);
906  AttrNumber Anum_owner = get_object_attnum_owner(classId);
907  AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
908  AttrNumber Anum_acl = get_object_attnum_acl(classId);
909  AttrNumber Anum_name = get_object_attnum_name(classId);
910  HeapTuple oldtup;
911  Datum datum;
912  bool isnull;
913  Oid old_ownerId;
914  Oid namespaceId = InvalidOid;
915 
916  oldtup = get_catalog_object_by_oid(rel, objectId);
917  if (oldtup == NULL)
918  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
919  objectId, RelationGetRelationName(rel));
920 
921  datum = heap_getattr(oldtup, Anum_owner,
922  RelationGetDescr(rel), &isnull);
923  Assert(!isnull);
924  old_ownerId = DatumGetObjectId(datum);
925 
926  if (Anum_namespace != InvalidAttrNumber)
927  {
928  datum = heap_getattr(oldtup, Anum_namespace,
929  RelationGetDescr(rel), &isnull);
930  Assert(!isnull);
931  namespaceId = DatumGetObjectId(datum);
932  }
933 
934  if (old_ownerId != new_ownerId)
935  {
936  AttrNumber nattrs;
937  HeapTuple newtup;
938  Datum *values;
939  bool *nulls;
940  bool *replaces;
941 
942  /* Superusers can bypass permission checks */
943  if (!superuser())
944  {
945  ObjectType objtype = get_object_type(classId, objectId);
946 
947  /* must be owner */
948  if (!has_privs_of_role(GetUserId(), old_ownerId))
949  {
950  char *objname;
951  char namebuf[NAMEDATALEN];
952 
953  if (Anum_name != InvalidAttrNumber)
954  {
955  datum = heap_getattr(oldtup, Anum_name,
956  RelationGetDescr(rel), &isnull);
957  Assert(!isnull);
958  objname = NameStr(*DatumGetName(datum));
959  }
960  else
961  {
962  snprintf(namebuf, sizeof(namebuf), "%u",
963  HeapTupleGetOid(oldtup));
964  objname = namebuf;
965  }
966  aclcheck_error(ACLCHECK_NOT_OWNER, objtype, objname);
967  }
968  /* Must be able to become new owner */
969  check_is_member_of_role(GetUserId(), new_ownerId);
970 
971  /* New owner must have CREATE privilege on namespace */
972  if (OidIsValid(namespaceId))
973  {
974  AclResult aclresult;
975 
976  aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
977  ACL_CREATE);
978  if (aclresult != ACLCHECK_OK)
979  aclcheck_error(aclresult, OBJECT_SCHEMA,
980  get_namespace_name(namespaceId));
981  }
982  }
983 
984  /* Build a modified tuple */
985  nattrs = RelationGetNumberOfAttributes(rel);
986  values = palloc0(nattrs * sizeof(Datum));
987  nulls = palloc0(nattrs * sizeof(bool));
988  replaces = palloc0(nattrs * sizeof(bool));
989  values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
990  replaces[Anum_owner - 1] = true;
991 
992  /*
993  * Determine the modified ACL for the new owner. This is only
994  * necessary when the ACL is non-null.
995  */
996  if (Anum_acl != InvalidAttrNumber)
997  {
998  datum = heap_getattr(oldtup,
999  Anum_acl, RelationGetDescr(rel), &isnull);
1000  if (!isnull)
1001  {
1002  Acl *newAcl;
1003 
1004  newAcl = aclnewowner(DatumGetAclP(datum),
1005  old_ownerId, new_ownerId);
1006  values[Anum_acl - 1] = PointerGetDatum(newAcl);
1007  replaces[Anum_acl - 1] = true;
1008  }
1009  }
1010 
1011  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
1012  values, nulls, replaces);
1013 
1014  /* Perform actual update */
1015  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
1016 
1017  /* Update owner dependency reference */
1018  if (classId == LargeObjectMetadataRelationId)
1019  classId = LargeObjectRelationId;
1020  changeDependencyOnOwner(classId, HeapTupleGetOid(newtup), new_ownerId);
1021 
1022  /* Release memory */
1023  pfree(values);
1024  pfree(nulls);
1025  pfree(replaces);
1026  }
1027 
1028  InvokeObjectPostAlterHook(classId, objectId, 0);
1029 }
ObjectAddress RenameSchema(const char *oldname, const char *newname)
Definition: schemacmds.c:242
RoleSpec * newowner
Definition: parsenodes.h:2891
#define NameGetDatum(X)
Definition: postgres.h:580
ObjectAddress RenameType(RenameStmt *stmt)
Definition: typecmds.c:3221
static void report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
Definition: alter.c:112
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
char * subname
Definition: parsenodes.h:2847
AttrNumber get_object_attnum_owner(Oid class_id)
ObjectType renameType
Definition: parsenodes.h:2843
#define RelationGetDescr(relation)
Definition: rel.h:433
Oid GetUserId(void)
Definition: miscinit.c:379
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:541
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2915
#define DatumGetObjectId(X)
Definition: postgres.h:485
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4833
ObjectType objectType
Definition: parsenodes.h:2888
int get_object_catcache_name(Oid class_id)
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:3068
#define gettext_noop(x)
Definition: c.h:1036
Definition: nodes.h:517
ObjectAddress AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
Definition: typecmds.c:3503
#define strVal(v)
Definition: value.h:54
static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Definition: alter.c:658
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
AttrNumber get_object_attnum_namespace(Oid class_id)
#define heap_close(r, l)
Definition: heapam.h:97
char * newname
Definition: parsenodes.h:2849
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2416
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4689
void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, Oid opcnamespace)
Definition: opclasscmds.c:1686
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:12853
ObjectAddress RenameDatabase(const char *oldname, const char *newname)
Definition: dbcommands.c:977
ObjectAddress AlterEventTriggerOwner(const char *name, Oid newOwnerId)
#define NAMEDATALEN
#define DatumGetName(X)
Definition: postgres.h:570
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:304
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:182
ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
Definition: typecmds.c:3299
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
ObjectAddress rename_policy(RenameStmt *stmt)
Definition: policy.c:1205
int get_object_catcache_oid(Oid class_id)
ItemPointerData t_self
Definition: htup.h:65
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12924
ObjectAddress AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:277
Definition: c.h:570
char * getObjectDescriptionOids(Oid classid, Oid objid)
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
AttrNumber get_object_attnum_acl(Oid class_id)
void AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
Definition: alter.c:903
#define NoLock
Definition: lockdefs.h:34
ObjectAddress get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:563
#define RelationGetRelationName(relation)
Definition: rel.h:441
Node * object
Definition: parsenodes.h:2846
void IsThereCollationInNamespace(const char *collname, Oid nspOid)
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4879
ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId)
ObjectAddress ExecRenameStmt(RenameStmt *stmt)
Definition: alter.c:325
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectAddress renametrig(RenameStmt *stmt)
Definition: trigger.c:1655
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:2880
ObjectType
Definition: parsenodes.h:1634
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:3017
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2947
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3540
void IsThereFunctionInNamespace(const char *proname, int pronargs, oidvector *proargtypes, Oid nspOid)
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:781
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:49
AttrNumber get_object_attnum_name(Oid class_id)
void * palloc0(Size size)
Definition: mcxt.c:955
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Oid MyDatabaseId
Definition: globals.c:84
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5149
ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId)
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
RangeVar * relation
Definition: parsenodes.h:2845
ObjectAddress ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress)
Definition: alter.c:425
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:132
#define InvalidOid
Definition: postgres_ext.h:36
ObjectAddress RenameRole(const char *oldname, const char *newname)
Definition: user.c:1143
ObjectAddress ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt, ObjectAddress *oldSchemaAddr)
Definition: alter.c:463
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
ObjectAddress AlterSchemaOwner(const char *name, Oid newOwnerId)
Definition: schemacmds.c:321
#define Assert(condition)
Definition: c.h:699
Definition: value.h:42
ObjectAddress AlterForeignServerOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:414
static void report_name_conflict(Oid classId, const char *name)
Definition: alter.c:77
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
static void AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
Definition: alter.c:166
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
ObjectAddress RenameRewriteRule(RangeVar *relation, const char *oldName, const char *newName)
ObjectAddress ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
Definition: alter.c:802
ObjectType get_object_type(Oid class_id, Oid object_id)
ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
Definition: dbcommands.c:1601
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:184
HeapTuple get_catalog_object_by_oid(Relation catalog, Oid objectId)
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:49
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:164
ObjectAddress RenameTableSpace(const char *oldname, const char *newname)
Definition: tablespace.c:912
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:557
#define NameStr(name)
Definition: c.h:576
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: pg_list.h:45
ObjectAddress AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *oldschema)
Definition: extension.c:2681
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:407
void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, Oid opfnamespace)
Definition: opclasscmds.c:1709
#define RelationGetNamespace(relation)
Definition: rel.h:448