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