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-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/alter.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "access/relation.h"
19 #include "access/sysattr.h"
20 #include "access/table.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/namespace.h"
24 #include "catalog/objectaccess.h"
25 #include "catalog/pg_collation.h"
26 #include "catalog/pg_conversion.h"
30 #include "catalog/pg_language.h"
31 #include "catalog/pg_largeobject.h"
33 #include "catalog/pg_namespace.h"
34 #include "catalog/pg_opclass.h"
35 #include "catalog/pg_opfamily.h"
36 #include "catalog/pg_proc.h"
39 #include "catalog/pg_ts_config.h"
40 #include "catalog/pg_ts_dict.h"
41 #include "catalog/pg_ts_parser.h"
42 #include "catalog/pg_ts_template.h"
43 #include "commands/alter.h"
44 #include "commands/collationcmds.h"
46 #include "commands/dbcommands.h"
47 #include "commands/defrem.h"
48 #include "commands/event_trigger.h"
49 #include "commands/extension.h"
50 #include "commands/policy.h"
51 #include "commands/proclang.h"
53 #include "commands/schemacmds.h"
55 #include "commands/tablecmds.h"
56 #include "commands/tablespace.h"
57 #include "commands/trigger.h"
58 #include "commands/typecmds.h"
59 #include "commands/user.h"
60 #include "miscadmin.h"
61 #include "parser/parse_func.h"
62 #include "rewrite/rewriteDefine.h"
63 #include "tcop/utility.h"
64 #include "utils/builtins.h"
65 #include "utils/fmgroids.h"
66 #include "utils/lsyscache.h"
67 #include "utils/rel.h"
68 #include "utils/syscache.h"
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  HeapTuple oldtup;
175  HeapTuple newtup;
176  Datum datum;
177  bool isnull;
178  Oid namespaceId;
179  Oid ownerId;
180  char *old_name;
181  AclResult aclresult;
182  Datum *values;
183  bool *nulls;
184  bool *replaces;
185  NameData nameattrdata;
186 
187  oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
188  if (!HeapTupleIsValid(oldtup))
189  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
190  objectId, RelationGetRelationName(rel));
191 
192  datum = heap_getattr(oldtup, Anum_name,
193  RelationGetDescr(rel), &isnull);
194  Assert(!isnull);
195  old_name = NameStr(*(DatumGetName(datum)));
196 
197  /* Get OID of namespace */
198  if (Anum_namespace > 0)
199  {
200  datum = heap_getattr(oldtup, Anum_namespace,
201  RelationGetDescr(rel), &isnull);
202  Assert(!isnull);
203  namespaceId = DatumGetObjectId(datum);
204  }
205  else
206  namespaceId = InvalidOid;
207 
208  /* Permission checks ... superusers can always do it */
209  if (!superuser())
210  {
211  /* Fail if object does not have an explicit owner */
212  if (Anum_owner <= 0)
213  ereport(ERROR,
214  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
215  errmsg("must be superuser to rename %s",
216  getObjectDescriptionOids(classId, objectId))));
217 
218  /* Otherwise, must be owner of the existing object */
219  datum = heap_getattr(oldtup, Anum_owner,
220  RelationGetDescr(rel), &isnull);
221  Assert(!isnull);
222  ownerId = DatumGetObjectId(datum);
223 
224  if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
226  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  /* Also enforce regression testing naming rules, if enabled */
278 #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
279  if (strncmp(new_name, "regress_", 8) != 0)
280  elog(WARNING, "subscriptions created by regression test cases should have names starting with \"regress_\"");
281 #endif
282  }
283  else if (nameCacheId >= 0)
284  {
285  if (OidIsValid(namespaceId))
286  {
287  if (SearchSysCacheExists2(nameCacheId,
288  CStringGetDatum(new_name),
289  ObjectIdGetDatum(namespaceId)))
290  report_namespace_conflict(classId, new_name, namespaceId);
291  }
292  else
293  {
294  if (SearchSysCacheExists1(nameCacheId,
295  CStringGetDatum(new_name)))
296  report_name_conflict(classId, new_name);
297  }
298  }
299 
300  /* Build modified tuple */
301  values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
302  nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
303  replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
304  namestrcpy(&nameattrdata, new_name);
305  values[Anum_name - 1] = NameGetDatum(&nameattrdata);
306  replaces[Anum_name - 1] = true;
307  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
308  values, nulls, replaces);
309 
310  /* Perform actual update */
311  CatalogTupleUpdate(rel, &oldtup->t_self, newtup);
312 
313  InvokeObjectPostAlterHook(classId, objectId, 0);
314 
315  /* Release memory */
316  pfree(values);
317  pfree(nulls);
318  pfree(replaces);
319  heap_freetuple(newtup);
320 
321  ReleaseSysCache(oldtup);
322 }
323 
324 /*
325  * Executes an ALTER OBJECT / RENAME TO statement. Based on the object
326  * type, the function appropriate to that type is executed.
327  *
328  * Return value is the address of the renamed object.
329  */
332 {
333  switch (stmt->renameType)
334  {
337  return RenameConstraint(stmt);
338 
339  case OBJECT_DATABASE:
340  return RenameDatabase(stmt->subname, stmt->newname);
341 
342  case OBJECT_ROLE:
343  return RenameRole(stmt->subname, stmt->newname);
344 
345  case OBJECT_SCHEMA:
346  return RenameSchema(stmt->subname, stmt->newname);
347 
348  case OBJECT_TABLESPACE:
349  return RenameTableSpace(stmt->subname, stmt->newname);
350 
351  case OBJECT_TABLE:
352  case OBJECT_SEQUENCE:
353  case OBJECT_VIEW:
354  case OBJECT_MATVIEW:
355  case OBJECT_INDEX:
357  return RenameRelation(stmt);
358 
359  case OBJECT_COLUMN:
360  case OBJECT_ATTRIBUTE:
361  return renameatt(stmt);
362 
363  case OBJECT_RULE:
364  return RenameRewriteRule(stmt->relation, stmt->subname,
365  stmt->newname);
366 
367  case OBJECT_TRIGGER:
368  return renametrig(stmt);
369 
370  case OBJECT_POLICY:
371  return rename_policy(stmt);
372 
373  case OBJECT_DOMAIN:
374  case OBJECT_TYPE:
375  return RenameType(stmt);
376 
377  case OBJECT_AGGREGATE:
378  case OBJECT_COLLATION:
379  case OBJECT_CONVERSION:
381  case OBJECT_FDW:
383  case OBJECT_FUNCTION:
384  case OBJECT_OPCLASS:
385  case OBJECT_OPFAMILY:
386  case OBJECT_LANGUAGE:
387  case OBJECT_PROCEDURE:
388  case OBJECT_ROUTINE:
391  case OBJECT_TSDICTIONARY:
392  case OBJECT_TSPARSER:
393  case OBJECT_TSTEMPLATE:
394  case OBJECT_PUBLICATION:
395  case OBJECT_SUBSCRIPTION:
396  {
397  ObjectAddress address;
398  Relation catalog;
399  Relation relation;
400 
401  address = get_object_address(stmt->renameType,
402  stmt->object,
403  &relation,
404  AccessExclusiveLock, false);
405  Assert(relation == NULL);
406 
407  catalog = table_open(address.classId, RowExclusiveLock);
409  address.objectId,
410  stmt->newname);
411  table_close(catalog, RowExclusiveLock);
412 
413  return address;
414  }
415 
416  default:
417  elog(ERROR, "unrecognized rename stmt type: %d",
418  (int) stmt->renameType);
419  return InvalidObjectAddress; /* keep compiler happy */
420  }
421 }
422 
423 /*
424  * Executes an ALTER OBJECT / DEPENDS ON [EXTENSION] statement.
425  *
426  * Return value is the address of the altered object. refAddress is an output
427  * argument which, if not null, receives the address of the object that the
428  * altered object now depends on.
429  */
432 {
433  ObjectAddress address;
434  ObjectAddress refAddr;
435  Relation rel;
436  List *currexts;
437 
438  address =
439  get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
440  &rel, AccessExclusiveLock, false);
441 
442  /*
443  * Verify that the user is entitled to run the command.
444  *
445  * We don't check any privileges on the extension, because that's not
446  * needed. The object owner is stipulating, by running this command, that
447  * the extension owner can drop the object whenever they feel like it,
448  * which is not considered a problem.
449  */
451  stmt->objectType, address, stmt->object, rel);
452 
453  /*
454  * If a relation was involved, it would have been opened and locked. We
455  * don't need the relation here, but we'll retain the lock until commit.
456  */
457  if (rel)
458  table_close(rel, NoLock);
459 
460  refAddr = get_object_address(OBJECT_EXTENSION, (Node *) stmt->extname,
461  &rel, AccessExclusiveLock, false);
462  Assert(rel == NULL);
463  if (refAddress)
464  *refAddress = refAddr;
465 
466  /* Avoid duplicates */
467  currexts = getAutoExtensionsOfObject(address.classId,
468  address.objectId);
469  if (!list_member_oid(currexts, refAddr.objectId))
470  recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
471 
472  return address;
473 }
474 
475 /*
476  * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
477  * type, the function appropriate to that type is executed.
478  *
479  * Return value is that of the altered object.
480  *
481  * oldSchemaAddr is an output argument which, if not NULL, is set to the object
482  * address of the original schema.
483  */
486  ObjectAddress *oldSchemaAddr)
487 {
488  ObjectAddress address;
489  Oid oldNspOid;
490 
491  switch (stmt->objectType)
492  {
493  case OBJECT_EXTENSION:
494  address = AlterExtensionNamespace(strVal((Value *) stmt->object), stmt->newschema,
495  oldSchemaAddr ? &oldNspOid : NULL);
496  break;
497 
499  case OBJECT_SEQUENCE:
500  case OBJECT_TABLE:
501  case OBJECT_VIEW:
502  case OBJECT_MATVIEW:
503  address = AlterTableNamespace(stmt,
504  oldSchemaAddr ? &oldNspOid : NULL);
505  break;
506 
507  case OBJECT_DOMAIN:
508  case OBJECT_TYPE:
509  address = AlterTypeNamespace(castNode(List, stmt->object), stmt->newschema,
510  stmt->objectType,
511  oldSchemaAddr ? &oldNspOid : NULL);
512  break;
513 
514  /* generic code path */
515  case OBJECT_AGGREGATE:
516  case OBJECT_COLLATION:
517  case OBJECT_CONVERSION:
518  case OBJECT_FUNCTION:
519  case OBJECT_OPERATOR:
520  case OBJECT_OPCLASS:
521  case OBJECT_OPFAMILY:
522  case OBJECT_PROCEDURE:
523  case OBJECT_ROUTINE:
526  case OBJECT_TSDICTIONARY:
527  case OBJECT_TSPARSER:
528  case OBJECT_TSTEMPLATE:
529  {
530  Relation catalog;
531  Relation relation;
532  Oid classId;
533  Oid nspOid;
534 
535  address = get_object_address(stmt->objectType,
536  stmt->object,
537  &relation,
539  false);
540  Assert(relation == NULL);
541  classId = address.classId;
542  catalog = table_open(classId, RowExclusiveLock);
543  nspOid = LookupCreationNamespace(stmt->newschema);
544 
545  oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
546  nspOid);
547  table_close(catalog, RowExclusiveLock);
548  }
549  break;
550 
551  default:
552  elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
553  (int) stmt->objectType);
554  return InvalidObjectAddress; /* keep compiler happy */
555  }
556 
557  if (oldSchemaAddr)
558  ObjectAddressSet(*oldSchemaAddr, NamespaceRelationId, oldNspOid);
559 
560  return address;
561 }
562 
563 /*
564  * Change an object's namespace given its classOid and object Oid.
565  *
566  * Objects that don't have a namespace should be ignored.
567  *
568  * This function is currently used only by ALTER EXTENSION SET SCHEMA,
569  * so it only needs to cover object types that can be members of an
570  * extension, and it doesn't have to deal with certain special cases
571  * such as not wanting to process array types --- those should never
572  * be direct members of an extension anyway. Nonetheless, we insist
573  * on listing all OCLASS types in the switch.
574  *
575  * Returns the OID of the object's previous namespace, or InvalidOid if
576  * object doesn't have a schema.
577  */
578 Oid
579 AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
580  ObjectAddresses *objsMoved)
581 {
582  Oid oldNspOid = InvalidOid;
583  ObjectAddress dep;
584 
585  dep.classId = classId;
586  dep.objectId = objid;
587  dep.objectSubId = 0;
588 
589  switch (getObjectClass(&dep))
590  {
591  case OCLASS_CLASS:
592  {
593  Relation rel;
594 
595  rel = relation_open(objid, AccessExclusiveLock);
596  oldNspOid = RelationGetNamespace(rel);
597 
598  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
599 
600  relation_close(rel, NoLock);
601  break;
602  }
603 
604  case OCLASS_TYPE:
605  oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
606  break;
607 
608  case OCLASS_PROC:
609  case OCLASS_COLLATION:
610  case OCLASS_CONVERSION:
611  case OCLASS_OPERATOR:
612  case OCLASS_OPCLASS:
613  case OCLASS_OPFAMILY:
615  case OCLASS_TSPARSER:
616  case OCLASS_TSDICT:
617  case OCLASS_TSTEMPLATE:
618  case OCLASS_TSCONFIG:
619  {
620  Relation catalog;
621 
622  catalog = table_open(classId, RowExclusiveLock);
623 
624  oldNspOid = AlterObjectNamespace_internal(catalog, objid,
625  nspOid);
626 
627  table_close(catalog, RowExclusiveLock);
628  }
629  break;
630 
631  case OCLASS_CAST:
632  case OCLASS_CONSTRAINT:
633  case OCLASS_DEFAULT:
634  case OCLASS_LANGUAGE:
635  case OCLASS_LARGEOBJECT:
636  case OCLASS_AM:
637  case OCLASS_AMOP:
638  case OCLASS_AMPROC:
639  case OCLASS_REWRITE:
640  case OCLASS_TRIGGER:
641  case OCLASS_SCHEMA:
642  case OCLASS_ROLE:
643  case OCLASS_DATABASE:
644  case OCLASS_TBLSPACE:
645  case OCLASS_FDW:
647  case OCLASS_USER_MAPPING:
648  case OCLASS_DEFACL:
649  case OCLASS_EXTENSION:
651  case OCLASS_POLICY:
652  case OCLASS_PUBLICATION:
654  case OCLASS_SUBSCRIPTION:
655  case OCLASS_TRANSFORM:
656  /* ignore object types that don't have schema-qualified names */
657  break;
658 
659  /*
660  * There's intentionally no default: case here; we want the
661  * compiler to warn if a new OCLASS hasn't been handled above.
662  */
663  }
664 
665  return oldNspOid;
666 }
667 
668 /*
669  * Generic function to change the namespace of a given object, for simple
670  * cases (won't work for tables, nor other cases where we need to do more
671  * than change the namespace column of a single catalog entry).
672  *
673  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
674  * objid: OID of object to change the namespace of
675  * nspOid: OID of new namespace
676  *
677  * Returns the OID of the object's previous namespace.
678  */
679 static Oid
681 {
682  Oid classId = RelationGetRelid(rel);
683  int oidCacheId = get_object_catcache_oid(classId);
684  int nameCacheId = get_object_catcache_name(classId);
685  AttrNumber Anum_name = get_object_attnum_name(classId);
686  AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
687  AttrNumber Anum_owner = get_object_attnum_owner(classId);
688  Oid oldNspOid;
689  Datum name,
690  namespace;
691  bool isnull;
692  HeapTuple tup,
693  newtup;
694  Datum *values;
695  bool *nulls;
696  bool *replaces;
697 
698  tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
699  if (!HeapTupleIsValid(tup)) /* should not happen */
700  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
701  objid, RelationGetRelationName(rel));
702 
703  name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
704  Assert(!isnull);
705  namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
706  &isnull);
707  Assert(!isnull);
708  oldNspOid = DatumGetObjectId(namespace);
709 
710  /*
711  * If the object is already in the correct namespace, we don't need to do
712  * anything except fire the object access hook.
713  */
714  if (oldNspOid == nspOid)
715  {
716  InvokeObjectPostAlterHook(classId, objid, 0);
717  return oldNspOid;
718  }
719 
720  /* Check basic namespace related issues */
721  CheckSetNamespace(oldNspOid, nspOid);
722 
723  /* Permission checks ... superusers can always do it */
724  if (!superuser())
725  {
726  Datum owner;
727  Oid ownerId;
728  AclResult aclresult;
729 
730  /* Fail if object does not have an explicit owner */
731  if (Anum_owner <= 0)
732  ereport(ERROR,
733  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
734  errmsg("must be superuser to set schema of %s",
735  getObjectDescriptionOids(classId, objid))));
736 
737  /* Otherwise, must be owner of the existing object */
738  owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
739  Assert(!isnull);
740  ownerId = DatumGetObjectId(owner);
741 
742  if (!has_privs_of_role(GetUserId(), ownerId))
744  NameStr(*(DatumGetName(name))));
745 
746  /* User must have CREATE privilege on new namespace */
747  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
748  if (aclresult != ACLCHECK_OK)
749  aclcheck_error(aclresult, OBJECT_SCHEMA,
750  get_namespace_name(nspOid));
751  }
752 
753  /*
754  * Check for duplicate name (more friendly than unique-index failure).
755  * Since this is just a friendliness check, we can just skip it in cases
756  * where there isn't suitable support.
757  */
758  if (classId == ProcedureRelationId)
759  {
760  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
761 
762  IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
763  &proc->proargtypes, nspOid);
764  }
765  else if (classId == CollationRelationId)
766  {
768 
769  IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
770  }
771  else if (classId == OperatorClassRelationId)
772  {
774 
775  IsThereOpClassInNamespace(NameStr(opc->opcname),
776  opc->opcmethod, nspOid);
777  }
778  else if (classId == OperatorFamilyRelationId)
779  {
781 
782  IsThereOpFamilyInNamespace(NameStr(opf->opfname),
783  opf->opfmethod, nspOid);
784  }
785  else if (nameCacheId >= 0 &&
786  SearchSysCacheExists2(nameCacheId, name,
787  ObjectIdGetDatum(nspOid)))
789  NameStr(*(DatumGetName(name))),
790  nspOid);
791 
792  /* Build modified tuple */
793  values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
794  nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
795  replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
796  values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
797  replaces[Anum_namespace - 1] = true;
798  newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
799  values, nulls, replaces);
800 
801  /* Perform actual update */
802  CatalogTupleUpdate(rel, &tup->t_self, newtup);
803 
804  /* Release memory */
805  pfree(values);
806  pfree(nulls);
807  pfree(replaces);
808 
809  /* update dependencies to point to the new schema */
810  changeDependencyFor(classId, objid,
811  NamespaceRelationId, oldNspOid, nspOid);
812 
813  InvokeObjectPostAlterHook(classId, objid, 0);
814 
815  return oldNspOid;
816 }
817 
818 /*
819  * Executes an ALTER OBJECT / OWNER TO statement. Based on the object
820  * type, the function appropriate to that type is executed.
821  */
824 {
825  Oid newowner = get_rolespec_oid(stmt->newowner, false);
826 
827  switch (stmt->objectType)
828  {
829  case OBJECT_DATABASE:
830  return AlterDatabaseOwner(strVal((Value *) stmt->object), newowner);
831 
832  case OBJECT_SCHEMA:
833  return AlterSchemaOwner(strVal((Value *) stmt->object), newowner);
834 
835  case OBJECT_TYPE:
836  case OBJECT_DOMAIN: /* same as TYPE */
837  return AlterTypeOwner(castNode(List, stmt->object), newowner, stmt->objectType);
838  break;
839 
840  case OBJECT_FDW:
842  newowner);
843 
845  return AlterForeignServerOwner(strVal((Value *) stmt->object),
846  newowner);
847 
849  return AlterEventTriggerOwner(strVal((Value *) stmt->object),
850  newowner);
851 
852  case OBJECT_PUBLICATION:
853  return AlterPublicationOwner(strVal((Value *) stmt->object),
854  newowner);
855 
856  case OBJECT_SUBSCRIPTION:
857  return AlterSubscriptionOwner(strVal((Value *) stmt->object),
858  newowner);
859 
860  /* Generic cases */
861  case OBJECT_AGGREGATE:
862  case OBJECT_COLLATION:
863  case OBJECT_CONVERSION:
864  case OBJECT_FUNCTION:
865  case OBJECT_LANGUAGE:
866  case OBJECT_LARGEOBJECT:
867  case OBJECT_OPERATOR:
868  case OBJECT_OPCLASS:
869  case OBJECT_OPFAMILY:
870  case OBJECT_PROCEDURE:
871  case OBJECT_ROUTINE:
873  case OBJECT_TABLESPACE:
874  case OBJECT_TSDICTIONARY:
876  {
877  Relation catalog;
878  Relation relation;
879  Oid classId;
880  ObjectAddress address;
881 
882  address = get_object_address(stmt->objectType,
883  stmt->object,
884  &relation,
886  false);
887  Assert(relation == NULL);
888  classId = address.classId;
889 
890  /*
891  * XXX - get_object_address returns Oid of pg_largeobject
892  * catalog for OBJECT_LARGEOBJECT because of historical
893  * reasons. Fix up it here.
894  */
895  if (classId == LargeObjectRelationId)
896  classId = LargeObjectMetadataRelationId;
897 
898  catalog = table_open(classId, RowExclusiveLock);
899 
900  AlterObjectOwner_internal(catalog, address.objectId, newowner);
901  table_close(catalog, RowExclusiveLock);
902 
903  return address;
904  }
905  break;
906 
907  default:
908  elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
909  (int) stmt->objectType);
910  return InvalidObjectAddress; /* keep compiler happy */
911  }
912 }
913 
914 /*
915  * Generic function to change the ownership of a given object, for simple
916  * cases (won't work for tables, nor other cases where we need to do more than
917  * change the ownership column of a single catalog entry).
918  *
919  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
920  * objectId: OID of object to change the ownership of
921  * new_ownerId: OID of new object owner
922  */
923 void
924 AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
925 {
926  Oid classId = RelationGetRelid(rel);
927  AttrNumber Anum_oid = get_object_attnum_oid(classId);
928  AttrNumber Anum_owner = get_object_attnum_owner(classId);
929  AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
930  AttrNumber Anum_acl = get_object_attnum_acl(classId);
931  AttrNumber Anum_name = get_object_attnum_name(classId);
932  HeapTuple oldtup;
933  Datum datum;
934  bool isnull;
935  Oid old_ownerId;
936  Oid namespaceId = InvalidOid;
937 
938  oldtup = get_catalog_object_by_oid(rel, Anum_oid, objectId);
939  if (oldtup == NULL)
940  elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
941  objectId, RelationGetRelationName(rel));
942 
943  datum = heap_getattr(oldtup, Anum_owner,
944  RelationGetDescr(rel), &isnull);
945  Assert(!isnull);
946  old_ownerId = DatumGetObjectId(datum);
947 
948  if (Anum_namespace != InvalidAttrNumber)
949  {
950  datum = heap_getattr(oldtup, Anum_namespace,
951  RelationGetDescr(rel), &isnull);
952  Assert(!isnull);
953  namespaceId = DatumGetObjectId(datum);
954  }
955 
956  if (old_ownerId != new_ownerId)
957  {
958  AttrNumber nattrs;
959  HeapTuple newtup;
960  Datum *values;
961  bool *nulls;
962  bool *replaces;
963 
964  /* Superusers can bypass permission checks */
965  if (!superuser())
966  {
967  /* must be owner */
968  if (!has_privs_of_role(GetUserId(), old_ownerId))
969  {
970  char *objname;
971  char namebuf[NAMEDATALEN];
972 
973  if (Anum_name != InvalidAttrNumber)
974  {
975  datum = heap_getattr(oldtup, Anum_name,
976  RelationGetDescr(rel), &isnull);
977  Assert(!isnull);
978  objname = NameStr(*DatumGetName(datum));
979  }
980  else
981  {
982  snprintf(namebuf, sizeof(namebuf), "%u", objectId);
983  objname = namebuf;
984  }
986  objname);
987  }
988  /* Must be able to become new owner */
989  check_is_member_of_role(GetUserId(), new_ownerId);
990 
991  /* New owner must have CREATE privilege on namespace */
992  if (OidIsValid(namespaceId))
993  {
994  AclResult aclresult;
995 
996  aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
997  ACL_CREATE);
998  if (aclresult != ACLCHECK_OK)
999  aclcheck_error(aclresult, OBJECT_SCHEMA,
1000  get_namespace_name(namespaceId));
1001  }
1002  }
1003 
1004  /* Build a modified tuple */
1005  nattrs = RelationGetNumberOfAttributes(rel);
1006  values = palloc0(nattrs * sizeof(Datum));
1007  nulls = palloc0(nattrs * sizeof(bool));
1008  replaces = palloc0(nattrs * sizeof(bool));
1009  values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
1010  replaces[Anum_owner - 1] = true;
1011 
1012  /*
1013  * Determine the modified ACL for the new owner. This is only
1014  * necessary when the ACL is non-null.
1015  */
1016  if (Anum_acl != InvalidAttrNumber)
1017  {
1018  datum = heap_getattr(oldtup,
1019  Anum_acl, RelationGetDescr(rel), &isnull);
1020  if (!isnull)
1021  {
1022  Acl *newAcl;
1023 
1024  newAcl = aclnewowner(DatumGetAclP(datum),
1025  old_ownerId, new_ownerId);
1026  values[Anum_acl - 1] = PointerGetDatum(newAcl);
1027  replaces[Anum_acl - 1] = true;
1028  }
1029  }
1030 
1031  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
1032  values, nulls, replaces);
1033 
1034  /* Perform actual update */
1035  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
1036 
1037  /* Update owner dependency reference */
1038  if (classId == LargeObjectMetadataRelationId)
1039  classId = LargeObjectRelationId;
1040  changeDependencyOnOwner(classId, objectId, new_ownerId);
1041 
1042  /* Release memory */
1043  pfree(values);
1044  pfree(nulls);
1045  pfree(replaces);
1046  }
1047 
1048  InvokeObjectPostAlterHook(classId, objectId, 0);
1049 }
ObjectAddress RenameSchema(const char *oldname, const char *newname)
Definition: schemacmds.c:241
RoleSpec * newowner
Definition: parsenodes.h:2959
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
ObjectAddress RenameType(RenameStmt *stmt)
Definition: typecmds.c:3153
static void report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
Definition: alter.c:112
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * subname
Definition: parsenodes.h:2915
AttrNumber get_object_attnum_oid(Oid class_id)
AttrNumber get_object_attnum_owner(Oid class_id)
ObjectType renameType
Definition: parsenodes.h:2911
#define RelationGetDescr(relation)
Definition: rel.h:461
Oid GetUserId(void)
Definition: miscinit.c:439
#define castNode(_type_, nodeptr)
Definition: nodes.h:595
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:441
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:556
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2936
#define DatumGetObjectId(X)
Definition: postgres.h:500
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4900
ObjectType objectType
Definition: parsenodes.h:2956
int get_object_catcache_name(Oid class_id)
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:3337
#define gettext_noop(x)
Definition: c.h:1160
Definition: nodes.h:526
ObjectAddress AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
Definition: typecmds.c:3435
#define strVal(v)
Definition: value.h:54
static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Definition: alter.c:680
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
AttrNumber get_object_attnum_namespace(Oid class_id)
char * newname
Definition: parsenodes.h:2917
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2725
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4691
void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, Oid opcnamespace)
Definition: opclasscmds.c:1729
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:14778
ObjectAddress RenameDatabase(const char *oldname, const char *newname)
Definition: dbcommands.c:1018
ObjectAddress AlterEventTriggerOwner(const char *name, Oid newOwnerId)
#define NAMEDATALEN
#define DatumGetName(X)
Definition: postgres.h:585
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:309
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:183
ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
Definition: typecmds.c:3231
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
ObjectAddress rename_policy(RenameStmt *stmt)
Definition: policy.c:1219
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
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:14849
ObjectAddress AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:275
Definition: c.h:609
char * getObjectDescriptionOids(Oid classid, Oid objid)
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3120
AttrNumber get_object_attnum_acl(Oid class_id)
void AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
Definition: alter.c:924
#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:578
#define RelationGetRelationName(relation)
Definition: rel.h:469
Node * object
Definition: parsenodes.h:2914
void IsThereCollationInNamespace(const char *collname, Oid nspOid)
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4946
ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId)
ObjectAddress ExecRenameStmt(RenameStmt *stmt)
Definition: alter.c:331
ObjectAddress renametrig(RenameStmt *stmt)
Definition: trigger.c:1335
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:3142
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:3286
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2967
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3472
#define WARNING
Definition: elog.h:40
void IsThereFunctionInNamespace(const char *proname, int pronargs, oidvector *proargtypes, Oid nspOid)
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
AttrNumber get_object_attnum_name(Oid class_id)
void * palloc0(Size size)
Definition: mcxt.c:980
AclResult
Definition: acl.h:177
HeapTuple get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Oid MyDatabaseId
Definition: globals.c:85
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5217
ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId)
RangeVar * relation
Definition: parsenodes.h:2913
ObjectAddress ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress)
Definition: alter.c:431
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#define InvalidOid
Definition: postgres_ext.h:36
ObjectAddress RenameRole(const char *oldname, const char *newname)
Definition: user.c:1161
#define ereport(elevel,...)
Definition: elog.h:144
ObjectAddress ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt, ObjectAddress *oldSchemaAddr)
Definition: alter.c:485
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
ObjectAddress AlterSchemaOwner(const char *name, Oid newOwnerId)
Definition: schemacmds.c:322
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:738
Definition: value.h:42
ObjectAddress AlterForeignServerOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:415
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:224
ObjectAddress RenameRewriteRule(RangeVar *relation, const char *oldName, const char *newName)
ObjectAddress ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
Definition: alter.c:823
ObjectType get_object_type(Oid class_id, Oid object_id)
ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
Definition: dbcommands.c:1676
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:51
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ObjectAddress RenameTableSpace(const char *oldname, const char *newname)
Definition: tablespace.c:925
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:579
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:50
#define snprintf
Definition: port.h:192
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:656
ObjectAddress AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *oldschema)
Definition: extension.c:2774
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:435
void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, Oid opfnamespace)
Definition: opclasscmds.c:1752
#define RelationGetNamespace(relation)
Definition: rel.h:476