1 /*-------------------------------------------------------------------------
4 * schema creation/manipulation commands
6 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.58 2010/08/05 14:45:01 rhaas Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/xact.h"
19 #include "catalog/catalog.h"
20 #include "catalog/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/namespace.h"
23 #include "catalog/pg_namespace.h"
24 #include "commands/dbcommands.h"
25 #include "commands/schemacmds.h"
26 #include "miscadmin.h"
27 #include "parser/parse_utilcmd.h"
28 #include "tcop/utility.h"
29 #include "utils/acl.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/syscache.h"
35 static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
41 CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
43 const char *schemaName = stmt->schemaname;
44 const char *authId = stmt->authid;
46 OverrideSearchPath *overridePath;
48 ListCell *parsetree_item;
54 GetUserIdAndSecContext(&saved_uid, &save_sec_context);
57 * Who is supposed to own the new schema?
60 owner_uid = get_role_oid(authId, false);
62 owner_uid = saved_uid;
65 * To create a schema, must have schema-create privilege on the current
66 * database and must be able to become the target role (this does not
67 * imply that the target role itself must have create-schema privilege).
68 * The latter provision guards against "giveaway" attacks. Note that a
69 * superuser will always have both of these privileges a fortiori.
71 aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
72 if (aclresult != ACLCHECK_OK)
73 aclcheck_error(aclresult, ACL_KIND_DATABASE,
74 get_database_name(MyDatabaseId));
76 check_is_member_of_role(saved_uid, owner_uid);
78 /* Additional check to protect reserved schema names */
79 if (!allowSystemTableMods && IsReservedName(schemaName))
81 (errcode(ERRCODE_RESERVED_NAME),
82 errmsg("unacceptable schema name \"%s\"", schemaName),
83 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
86 * If the requested authorization is different from the current user,
87 * temporarily set the current user so that the object(s) will be created
88 * with the correct ownership.
90 * (The setting will be restored at the end of this routine, or in case of
91 * error, transaction abort will clean things up.)
93 if (saved_uid != owner_uid)
94 SetUserIdAndSecContext(owner_uid,
95 save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
97 /* Create the schema's namespace */
98 namespaceId = NamespaceCreate(schemaName, owner_uid);
100 /* Advance cmd counter to make the namespace visible */
101 CommandCounterIncrement();
104 * Temporarily make the new namespace be the front of the search path, as
105 * well as the default creation target namespace. This will be undone at
106 * the end of this routine, or upon error.
108 overridePath = GetOverrideSearchPath(CurrentMemoryContext);
109 overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas);
110 /* XXX should we clear overridePath->useTemp? */
111 PushOverrideSearchPath(overridePath);
114 * Examine the list of commands embedded in the CREATE SCHEMA command, and
115 * reorganize them into a sequentially executable order with no forward
116 * references. Note that the result is still a list of raw parsetrees ---
117 * we cannot, in general, run parse analysis on one statement until we
118 * have actually executed the prior ones.
120 parsetree_list = transformCreateSchemaStmt(stmt);
123 * Execute each command contained in the CREATE SCHEMA. Since the grammar
124 * allows only utility commands in CREATE SCHEMA, there is no need to pass
125 * them through parse_analyze() or the rewriter; we can just hand them
126 * straight to ProcessUtility.
128 foreach(parsetree_item, parsetree_list)
130 Node *stmt = (Node *) lfirst(parsetree_item);
136 false, /* not top level */
139 /* make sure later steps can see the object created here */
140 CommandCounterIncrement();
143 /* Reset search path to normal state */
144 PopOverrideSearchPath();
146 /* Reset current user and security context */
147 SetUserIdAndSecContext(saved_uid, save_sec_context);
153 * Implements DROP SCHEMA.
156 RemoveSchemas(DropStmt *drop)
158 ObjectAddresses *objects;
162 * First we identify all the schemas, then we delete them in a single
163 * performMultipleDeletions() call. This is to avoid unwanted DROP
164 * RESTRICT errors if one of the schemas depends on another.
166 objects = new_object_addresses();
168 foreach(cell, drop->objects)
170 List *names = (List *) lfirst(cell);
173 ObjectAddress object;
175 if (list_length(names) != 1)
177 (errcode(ERRCODE_SYNTAX_ERROR),
178 errmsg("schema name cannot be qualified")));
179 namespaceName = strVal(linitial(names));
181 namespaceId = get_namespace_oid(namespaceName, drop->missing_ok);
183 if (!OidIsValid(namespaceId))
186 (errmsg("schema \"%s\" does not exist, skipping",
191 /* Permission check */
192 if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
193 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
196 object.classId = NamespaceRelationId;
197 object.objectId = namespaceId;
198 object.objectSubId = 0;
200 add_exact_object_address(&object, objects);
204 * Do the deletions. Objects contained in the schema(s) are removed by
205 * means of their dependency links to the schema.
207 performMultipleDeletions(objects, drop->behavior);
209 free_object_addresses(objects);
214 * Guts of schema deletion.
217 RemoveSchemaById(Oid schemaOid)
222 relation = heap_open(NamespaceRelationId, RowExclusiveLock);
224 tup = SearchSysCache1(NAMESPACEOID,
225 ObjectIdGetDatum(schemaOid));
226 if (!HeapTupleIsValid(tup)) /* should not happen */
227 elog(ERROR, "cache lookup failed for namespace %u", schemaOid);
229 simple_heap_delete(relation, &tup->t_self);
231 ReleaseSysCache(tup);
233 heap_close(relation, RowExclusiveLock);
241 RenameSchema(const char *oldname, const char *newname)
247 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
249 tup = SearchSysCacheCopy1(NAMESPACENAME, CStringGetDatum(oldname));
250 if (!HeapTupleIsValid(tup))
252 (errcode(ERRCODE_UNDEFINED_SCHEMA),
253 errmsg("schema \"%s\" does not exist", oldname)));
255 /* make sure the new name doesn't exist */
256 if (OidIsValid(get_namespace_oid(newname, true)))
258 (errcode(ERRCODE_DUPLICATE_SCHEMA),
259 errmsg("schema \"%s\" already exists", newname)));
262 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
263 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
266 /* must have CREATE privilege on database */
267 aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE);
268 if (aclresult != ACLCHECK_OK)
269 aclcheck_error(aclresult, ACL_KIND_DATABASE,
270 get_database_name(MyDatabaseId));
272 if (!allowSystemTableMods && IsReservedName(newname))
274 (errcode(ERRCODE_RESERVED_NAME),
275 errmsg("unacceptable schema name \"%s\"", newname),
276 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
279 namestrcpy(&(((Form_pg_namespace) GETSTRUCT(tup))->nspname), newname);
280 simple_heap_update(rel, &tup->t_self, tup);
281 CatalogUpdateIndexes(rel, tup);
283 heap_close(rel, NoLock);
288 AlterSchemaOwner_oid(Oid oid, Oid newOwnerId)
293 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
295 tup = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(oid));
296 if (!HeapTupleIsValid(tup))
297 elog(ERROR, "cache lookup failed for schema %u", oid);
299 AlterSchemaOwner_internal(tup, rel, newOwnerId);
301 ReleaseSysCache(tup);
303 heap_close(rel, RowExclusiveLock);
308 * Change schema owner
311 AlterSchemaOwner(const char *name, Oid newOwnerId)
316 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
318 tup = SearchSysCache1(NAMESPACENAME, CStringGetDatum(name));
319 if (!HeapTupleIsValid(tup))
321 (errcode(ERRCODE_UNDEFINED_SCHEMA),
322 errmsg("schema \"%s\" does not exist", name)));
324 AlterSchemaOwner_internal(tup, rel, newOwnerId);
326 ReleaseSysCache(tup);
328 heap_close(rel, RowExclusiveLock);
332 AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
334 Form_pg_namespace nspForm;
336 Assert(tup->t_tableOid == NamespaceRelationId);
337 Assert(RelationGetRelid(rel) == NamespaceRelationId);
339 nspForm = (Form_pg_namespace) GETSTRUCT(tup);
342 * If the new owner is the same as the existing owner, consider the
343 * command to have succeeded. This is for dump restoration purposes.
345 if (nspForm->nspowner != newOwnerId)
347 Datum repl_val[Natts_pg_namespace];
348 bool repl_null[Natts_pg_namespace];
349 bool repl_repl[Natts_pg_namespace];
356 /* Otherwise, must be owner of the existing object */
357 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
358 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
359 NameStr(nspForm->nspname));
361 /* Must be able to become new owner */
362 check_is_member_of_role(GetUserId(), newOwnerId);
365 * must have create-schema rights
367 * NOTE: This is different from other alter-owner checks in that the
368 * current user is checked for create privileges instead of the
369 * destination owner. This is consistent with the CREATE case for
370 * schemas. Because superusers will always have this right, we need
371 * no special case for them.
373 aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
375 if (aclresult != ACLCHECK_OK)
376 aclcheck_error(aclresult, ACL_KIND_DATABASE,
377 get_database_name(MyDatabaseId));
379 memset(repl_null, false, sizeof(repl_null));
380 memset(repl_repl, false, sizeof(repl_repl));
382 repl_repl[Anum_pg_namespace_nspowner - 1] = true;
383 repl_val[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(newOwnerId);
386 * Determine the modified ACL for the new owner. This is only
387 * necessary when the ACL is non-null.
389 aclDatum = SysCacheGetAttr(NAMESPACENAME, tup,
390 Anum_pg_namespace_nspacl,
394 newAcl = aclnewowner(DatumGetAclP(aclDatum),
395 nspForm->nspowner, newOwnerId);
396 repl_repl[Anum_pg_namespace_nspacl - 1] = true;
397 repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl);
400 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
402 simple_heap_update(rel, &newtuple->t_self, newtuple);
403 CatalogUpdateIndexes(rel, newtuple);
405 heap_freetuple(newtuple);
407 /* Update owner dependency reference */
408 changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),