OSDN Git Service

215e21cae0826b870fce4856e7ed366f03c82a2b
[pg-rex/syncrep.git] / src / backend / commands / alter.c
1 /*-------------------------------------------------------------------------
2  *
3  * alter.c
4  *        Drivers for generic alter commands
5  *
6  * Portions Copyright (c) 1996-2011, 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 "catalog/dependency.h"
18 #include "catalog/indexing.h"
19 #include "catalog/namespace.h"
20 #include "catalog/pg_largeobject.h"
21 #include "catalog/pg_namespace.h"
22 #include "commands/alter.h"
23 #include "commands/collationcmds.h"
24 #include "commands/conversioncmds.h"
25 #include "commands/dbcommands.h"
26 #include "commands/defrem.h"
27 #include "commands/extension.h"
28 #include "commands/proclang.h"
29 #include "commands/schemacmds.h"
30 #include "commands/tablecmds.h"
31 #include "commands/tablespace.h"
32 #include "commands/trigger.h"
33 #include "commands/typecmds.h"
34 #include "commands/user.h"
35 #include "miscadmin.h"
36 #include "parser/parse_clause.h"
37 #include "tcop/utility.h"
38 #include "utils/acl.h"
39 #include "utils/builtins.h"
40 #include "utils/lsyscache.h"
41 #include "utils/syscache.h"
42
43
44 /*
45  * Executes an ALTER OBJECT / RENAME TO statement.      Based on the object
46  * type, the function appropriate to that type is executed.
47  */
48 void
49 ExecRenameStmt(RenameStmt *stmt)
50 {
51         switch (stmt->renameType)
52         {
53                 case OBJECT_AGGREGATE:
54                         RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
55                         break;
56
57                 case OBJECT_COLLATION:
58                         RenameCollation(stmt->object, stmt->newname);
59                         break;
60
61                 case OBJECT_CONVERSION:
62                         RenameConversion(stmt->object, stmt->newname);
63                         break;
64
65                 case OBJECT_DATABASE:
66                         RenameDatabase(stmt->subname, stmt->newname);
67                         break;
68
69                 case OBJECT_FUNCTION:
70                         RenameFunction(stmt->object, stmt->objarg, stmt->newname);
71                         break;
72
73                 case OBJECT_LANGUAGE:
74                         RenameLanguage(stmt->subname, stmt->newname);
75                         break;
76
77                 case OBJECT_OPCLASS:
78                         RenameOpClass(stmt->object, stmt->subname, stmt->newname);
79                         break;
80
81                 case OBJECT_OPFAMILY:
82                         RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
83                         break;
84
85                 case OBJECT_ROLE:
86                         RenameRole(stmt->subname, stmt->newname);
87                         break;
88
89                 case OBJECT_SCHEMA:
90                         RenameSchema(stmt->subname, stmt->newname);
91                         break;
92
93                 case OBJECT_TABLESPACE:
94                         RenameTableSpace(stmt->subname, stmt->newname);
95                         break;
96
97                 case OBJECT_TABLE:
98                 case OBJECT_SEQUENCE:
99                 case OBJECT_VIEW:
100                 case OBJECT_INDEX:
101                 case OBJECT_COLUMN:
102                 case OBJECT_ATTRIBUTE:
103                 case OBJECT_TRIGGER:
104                 case OBJECT_FOREIGN_TABLE:
105                         {
106                                 Oid                     relid;
107
108                                 CheckRelationOwnership(stmt->relation, true);
109
110                                 relid = RangeVarGetRelid(stmt->relation, false);
111
112                                 switch (stmt->renameType)
113                                 {
114                                         case OBJECT_TABLE:
115                                         case OBJECT_SEQUENCE:
116                                         case OBJECT_VIEW:
117                                         case OBJECT_INDEX:
118                                         case OBJECT_FOREIGN_TABLE:
119                                                 {
120                                                         /*
121                                                          * RENAME TABLE requires that we (still) hold
122                                                          * CREATE rights on the containing namespace, as
123                                                          * well as ownership of the table.
124                                                          */
125                                                         Oid                     namespaceId = get_rel_namespace(relid);
126                                                         AclResult       aclresult;
127
128                                                         aclresult = pg_namespace_aclcheck(namespaceId,
129                                                                                                                           GetUserId(),
130                                                                                                                           ACL_CREATE);
131                                                         if (aclresult != ACLCHECK_OK)
132                                                                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
133                                                                                         get_namespace_name(namespaceId));
134
135                                                         RenameRelation(relid, stmt->newname, stmt->renameType);
136                                                         break;
137                                                 }
138                                         case OBJECT_COLUMN:
139                                         case OBJECT_ATTRIBUTE:
140                                                 renameatt(relid, stmt);
141                                                 break;
142                                         case OBJECT_TRIGGER:
143                                                 renametrig(relid,
144                                                                    stmt->subname,               /* old att name */
145                                                                    stmt->newname);              /* new att name */
146                                                 break;
147                                         default:
148                                                  /* can't happen */ ;
149                                 }
150                                 break;
151                         }
152
153                 case OBJECT_TSPARSER:
154                         RenameTSParser(stmt->object, stmt->newname);
155                         break;
156
157                 case OBJECT_TSDICTIONARY:
158                         RenameTSDictionary(stmt->object, stmt->newname);
159                         break;
160
161                 case OBJECT_TSTEMPLATE:
162                         RenameTSTemplate(stmt->object, stmt->newname);
163                         break;
164
165                 case OBJECT_TSCONFIGURATION:
166                         RenameTSConfiguration(stmt->object, stmt->newname);
167                         break;
168
169                 case OBJECT_TYPE:
170                         RenameType(stmt->object, stmt->newname);
171                         break;
172
173                 default:
174                         elog(ERROR, "unrecognized rename stmt type: %d",
175                                  (int) stmt->renameType);
176         }
177 }
178
179 /*
180  * Executes an ALTER OBJECT / SET SCHEMA statement.  Based on the object
181  * type, the function appropriate to that type is executed.
182  */
183 void
184 ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
185 {
186         switch (stmt->objectType)
187         {
188                 case OBJECT_AGGREGATE:
189                         AlterFunctionNamespace(stmt->object, stmt->objarg, true,
190                                                                    stmt->newschema);
191                         break;
192
193                 case OBJECT_COLLATION:
194                         AlterCollationNamespace(stmt->object, stmt->newschema);
195                         break;
196
197                 case OBJECT_CONVERSION:
198                         AlterConversionNamespace(stmt->object, stmt->newschema);
199                         break;
200
201                 case OBJECT_EXTENSION:
202                         AlterExtensionNamespace(stmt->object, stmt->newschema);
203                         break;
204
205                 case OBJECT_FUNCTION:
206                         AlterFunctionNamespace(stmt->object, stmt->objarg, false,
207                                                                    stmt->newschema);
208                         break;
209
210                 case OBJECT_OPERATOR:
211                         AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
212                         break;
213
214                 case OBJECT_OPCLASS:
215                         AlterOpClassNamespace(stmt->object, stmt->addname, stmt->newschema);
216                         break;
217
218                 case OBJECT_OPFAMILY:
219                         AlterOpFamilyNamespace(stmt->object, stmt->addname, stmt->newschema);
220                         break;
221
222                 case OBJECT_SEQUENCE:
223                 case OBJECT_TABLE:
224                 case OBJECT_VIEW:
225                 case OBJECT_FOREIGN_TABLE:
226                         CheckRelationOwnership(stmt->relation, true);
227                         AlterTableNamespace(stmt->relation, stmt->newschema,
228                                                                 stmt->objectType, AccessExclusiveLock);
229                         break;
230
231                 case OBJECT_TSPARSER:
232                         AlterTSParserNamespace(stmt->object, stmt->newschema);
233                         break;
234
235                 case OBJECT_TSDICTIONARY:
236                         AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
237                         break;
238
239                 case OBJECT_TSTEMPLATE:
240                         AlterTSTemplateNamespace(stmt->object, stmt->newschema);
241                         break;
242
243                 case OBJECT_TSCONFIGURATION:
244                         AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
245                         break;
246
247                 case OBJECT_TYPE:
248                 case OBJECT_DOMAIN:
249                         AlterTypeNamespace(stmt->object, stmt->newschema);
250                         break;
251
252                 default:
253                         elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
254                                  (int) stmt->objectType);
255         }
256 }
257
258 /*
259  * Change an object's namespace given its classOid and object Oid.
260  *
261  * Objects that don't have a namespace should be ignored.
262  *
263  * This function is currently used only by ALTER EXTENSION SET SCHEMA,
264  * so it only needs to cover object types that can be members of an
265  * extension, and it doesn't have to deal with certain special cases
266  * such as not wanting to process array types --- those should never
267  * be direct members of an extension anyway.
268  *
269  * Returns the OID of the object's previous namespace, or InvalidOid if
270  * object doesn't have a schema.
271  */
272 Oid
273 AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid)
274 {
275         Oid                     oldNspOid = InvalidOid;
276         ObjectAddress dep;
277
278         dep.classId = classId;
279         dep.objectId = objid;
280         dep.objectSubId = 0;
281
282         switch (getObjectClass(&dep))
283         {
284                 case OCLASS_CLASS:
285                         {
286                                 Relation        rel;
287                                 Relation        classRel;
288
289                                 rel = relation_open(objid, AccessExclusiveLock);
290                                 oldNspOid = RelationGetNamespace(rel);
291
292                                 classRel = heap_open(RelationRelationId, RowExclusiveLock);
293
294                                 AlterRelationNamespaceInternal(classRel,
295                                                                                            objid,
296                                                                                            oldNspOid,
297                                                                                            nspOid,
298                                                                                            true);
299
300                                 heap_close(classRel, RowExclusiveLock);
301
302                                 relation_close(rel, NoLock);
303                                 break;
304                         }
305
306                 case OCLASS_PROC:
307                         oldNspOid = AlterFunctionNamespace_oid(objid, nspOid);
308                         break;
309
310                 case OCLASS_TYPE:
311                         oldNspOid = AlterTypeNamespace_oid(objid, nspOid);
312                         break;
313
314                 case OCLASS_COLLATION:
315                         oldNspOid = AlterCollationNamespace_oid(objid, nspOid);
316                         break;
317
318                 case OCLASS_CONVERSION:
319                         oldNspOid = AlterConversionNamespace_oid(objid, nspOid);
320                         break;
321
322                 case OCLASS_OPERATOR:
323                         oldNspOid = AlterOperatorNamespace_oid(objid, nspOid);
324                         break;
325
326                 case OCLASS_OPCLASS:
327                         oldNspOid = AlterOpClassNamespace_oid(objid, nspOid);
328                         break;
329
330                 case OCLASS_OPFAMILY:
331                         oldNspOid = AlterOpFamilyNamespace_oid(objid, nspOid);
332                         break;
333
334                 case OCLASS_TSPARSER:
335                         oldNspOid = AlterTSParserNamespace_oid(objid, nspOid);
336                         break;
337
338                 case OCLASS_TSDICT:
339                         oldNspOid = AlterTSDictionaryNamespace_oid(objid, nspOid);
340                         break;
341
342                 case OCLASS_TSTEMPLATE:
343                         oldNspOid = AlterTSTemplateNamespace_oid(objid, nspOid);
344                         break;
345
346                 case OCLASS_TSCONFIG:
347                         oldNspOid = AlterTSConfigurationNamespace_oid(objid, nspOid);
348                         break;
349
350                 default:
351                         break;
352         }
353
354         return oldNspOid;
355 }
356
357 /*
358  * Generic function to change the namespace of a given object, for simple
359  * cases (won't work for tables, nor other cases where we need to do more
360  * than change the namespace column of a single catalog entry).
361  *
362  * The AlterFooNamespace() calls just above will call a function whose job
363  * is to lookup the arguments for the generic function here.
364  *
365  * rel: catalog relation containing object (RowExclusiveLock'd by caller)
366  * oidCacheId: syscache that indexes this catalog by OID
367  * nameCacheId: syscache that indexes this catalog by name and namespace
368  *              (pass -1 if there is none)
369  * objid: OID of object to change the namespace of
370  * nspOid: OID of new namespace
371  * Anum_name: column number of catalog's name column
372  * Anum_namespace: column number of catalog's namespace column
373  * Anum_owner: column number of catalog's owner column, or -1 if none
374  * acl_kind: ACL type for object, or -1 if none assigned
375  *
376  * If the object does not have an owner or permissions, pass -1 for
377  * Anum_owner and acl_kind.  In this case the calling user must be superuser.
378  *
379  * Returns the OID of the object's previous namespace.
380  */
381 Oid
382 AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId,
383                                          Oid objid, Oid nspOid,
384                                          int Anum_name, int Anum_namespace, int Anum_owner,
385                                          AclObjectKind acl_kind)
386 {
387         Oid                     classId = RelationGetRelid(rel);
388         Oid                     oldNspOid;
389         Datum           name,
390                                 namespace;
391         bool            isnull;
392         HeapTuple       tup,
393                                 newtup;
394         Datum      *values;
395         bool       *nulls;
396         bool       *replaces;
397
398         tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
399         if (!HeapTupleIsValid(tup)) /* should not happen */
400                 elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
401                          objid, RelationGetRelationName(rel));
402
403         name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
404         Assert(!isnull);
405         namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel), &isnull);
406         Assert(!isnull);
407         oldNspOid = DatumGetObjectId(namespace);
408
409         /* Check basic namespace related issues */
410         CheckSetNamespace(oldNspOid, nspOid, classId, objid);
411
412         /* Permission checks ... superusers can always do it */
413         if (!superuser())
414         {
415                 Datum           owner;
416                 Oid                     ownerId;
417                 AclResult       aclresult;
418
419                 /* Fail if object does not have an explicit owner */
420                 if (Anum_owner <= 0)
421                         ereport(ERROR,
422                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
423                                          (errmsg("must be superuser to SET SCHEMA of %s",
424                                                          getObjectDescriptionOids(classId, objid)))));
425
426                 /* Otherwise, must be owner of the existing object */
427                 owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
428                 Assert(!isnull);
429                 ownerId = DatumGetObjectId(owner);
430
431                 if (!has_privs_of_role(GetUserId(), ownerId))
432                         aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
433                                                    NameStr(*(DatumGetName(name))));
434
435                 /* User must have CREATE privilege on new namespace */
436                 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
437                 if (aclresult != ACLCHECK_OK)
438                         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
439                                                    get_namespace_name(nspOid));
440         }
441
442         /*
443          * Check for duplicate name (more friendly than unique-index failure).
444          * Since this is just a friendliness check, we can just skip it in cases
445          * where there isn't a suitable syscache available.
446          */
447         if (nameCacheId >= 0 &&
448                 SearchSysCacheExists2(nameCacheId, name, ObjectIdGetDatum(nspOid)))
449                 ereport(ERROR,
450                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
451                                  errmsg("%s already exists in schema \"%s\"",
452                                                 getObjectDescriptionOids(classId, objid),
453                                                 get_namespace_name(nspOid))));
454
455         /* Build modified tuple */
456         values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
457         nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
458         replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
459         values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
460         replaces[Anum_namespace - 1] = true;
461         newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
462                                                            values, nulls, replaces);
463
464         /* Perform actual update */
465         simple_heap_update(rel, &tup->t_self, newtup);
466         CatalogUpdateIndexes(rel, newtup);
467
468         /* Release memory */
469         pfree(values);
470         pfree(nulls);
471         pfree(replaces);
472
473         /* update dependencies to point to the new schema */
474         changeDependencyFor(classId, objid,
475                                                 NamespaceRelationId, oldNspOid, nspOid);
476
477         return oldNspOid;
478 }
479
480
481 /*
482  * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
483  * type, the function appropriate to that type is executed.
484  */
485 void
486 ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
487 {
488         Oid                     newowner = get_role_oid(stmt->newowner, false);
489
490         switch (stmt->objectType)
491         {
492                 case OBJECT_AGGREGATE:
493                         AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
494                         break;
495
496                 case OBJECT_COLLATION:
497                         AlterCollationOwner(stmt->object, newowner);
498                         break;
499
500                 case OBJECT_CONVERSION:
501                         AlterConversionOwner(stmt->object, newowner);
502                         break;
503
504                 case OBJECT_DATABASE:
505                         AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
506                         break;
507
508                 case OBJECT_FUNCTION:
509                         AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
510                         break;
511
512                 case OBJECT_LANGUAGE:
513                         AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
514                         break;
515
516                 case OBJECT_LARGEOBJECT:
517                         LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner);
518                         break;
519
520                 case OBJECT_OPERATOR:
521                         Assert(list_length(stmt->objarg) == 2);
522                         AlterOperatorOwner(stmt->object,
523                                                            (TypeName *) linitial(stmt->objarg),
524                                                            (TypeName *) lsecond(stmt->objarg),
525                                                            newowner);
526                         break;
527
528                 case OBJECT_OPCLASS:
529                         AlterOpClassOwner(stmt->object, stmt->addname, newowner);
530                         break;
531
532                 case OBJECT_OPFAMILY:
533                         AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
534                         break;
535
536                 case OBJECT_SCHEMA:
537                         AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
538                         break;
539
540                 case OBJECT_TABLESPACE:
541                         AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
542                         break;
543
544                 case OBJECT_TYPE:
545                 case OBJECT_DOMAIN:             /* same as TYPE */
546                         AlterTypeOwner(stmt->object, newowner);
547                         break;
548
549                 case OBJECT_TSDICTIONARY:
550                         AlterTSDictionaryOwner(stmt->object, newowner);
551                         break;
552
553                 case OBJECT_TSCONFIGURATION:
554                         AlterTSConfigurationOwner(stmt->object, newowner);
555                         break;
556
557                 case OBJECT_FDW:
558                         AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
559                                                                                  newowner);
560                         break;
561
562                 case OBJECT_FOREIGN_SERVER:
563                         AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
564                         break;
565
566                 default:
567                         elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
568                                  (int) stmt->objectType);
569         }
570 }