1 /*-------------------------------------------------------------------------
4 * schema creation/manipulation commands
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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 GetUserIdAndContext(&saved_uid
, &saved_secdefcxt
);
57 * Who is supposed to own the new schema?
60 owner_uid
= get_roleid_checked(authId
);
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
91 * of error, transaction abort will clean things up.)
93 if (saved_uid
!= owner_uid
)
94 SetUserIdAndContext(owner_uid
, true);
96 /* Create the schema's namespace */
97 namespaceId
= NamespaceCreate(schemaName
, owner_uid
);
99 /* Advance cmd counter to make the namespace visible */
100 CommandCounterIncrement();
103 * Temporarily make the new namespace be the front of the search path, as
104 * well as the default creation target namespace. This will be undone at
105 * the end of this routine, or upon error.
107 overridePath
= GetOverrideSearchPath(CurrentMemoryContext
);
108 overridePath
->schemas
= lcons_oid(namespaceId
, overridePath
->schemas
);
109 /* XXX should we clear overridePath->useTemp? */
110 PushOverrideSearchPath(overridePath
);
113 * Examine the list of commands embedded in the CREATE SCHEMA command, and
114 * reorganize them into a sequentially executable order with no forward
115 * references. Note that the result is still a list of raw parsetrees ---
116 * we cannot, in general, run parse analysis on one statement until we
117 * have actually executed the prior ones.
119 parsetree_list
= transformCreateSchemaStmt(stmt
);
122 * Execute each command contained in the CREATE SCHEMA. Since the grammar
123 * allows only utility commands in CREATE SCHEMA, there is no need to pass
124 * them through parse_analyze() or the rewriter; we can just hand them
125 * straight to ProcessUtility.
127 foreach(parsetree_item
, parsetree_list
)
129 Node
*stmt
= (Node
*) lfirst(parsetree_item
);
135 false, /* not top level */
138 /* make sure later steps can see the object created here */
139 CommandCounterIncrement();
142 /* Reset search path to normal state */
143 PopOverrideSearchPath();
145 /* Reset current user */
146 SetUserIdAndContext(saved_uid
, saved_secdefcxt
);
152 * Implements DROP SCHEMA.
155 RemoveSchemas(DropStmt
*drop
)
157 ObjectAddresses
*objects
;
161 * First we identify all the schemas, then we delete them in a single
162 * performMultipleDeletions() call. This is to avoid unwanted
163 * DROP RESTRICT errors if one of the schemas depends on another.
165 objects
= new_object_addresses();
167 foreach(cell
, drop
->objects
)
169 List
*names
= (List
*) lfirst(cell
);
172 ObjectAddress object
;
174 if (list_length(names
) != 1)
176 (errcode(ERRCODE_SYNTAX_ERROR
),
177 errmsg("schema name cannot be qualified")));
178 namespaceName
= strVal(linitial(names
));
180 namespaceId
= GetSysCacheOid(NAMESPACENAME
,
181 CStringGetDatum(namespaceName
),
184 if (!OidIsValid(namespaceId
))
186 if (!drop
->missing_ok
)
189 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
190 errmsg("schema \"%s\" does not exist",
196 (errmsg("schema \"%s\" does not exist, skipping",
202 /* Permission check */
203 if (!pg_namespace_ownercheck(namespaceId
, GetUserId()))
204 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_NAMESPACE
,
207 object
.classId
= NamespaceRelationId
;
208 object
.objectId
= namespaceId
;
209 object
.objectSubId
= 0;
211 add_exact_object_address(&object
, objects
);
215 * Do the deletions. Objects contained in the schema(s) are removed by
216 * means of their dependency links to the schema.
218 performMultipleDeletions(objects
, drop
->behavior
);
220 free_object_addresses(objects
);
225 * Guts of schema deletion.
228 RemoveSchemaById(Oid schemaOid
)
233 relation
= heap_open(NamespaceRelationId
, RowExclusiveLock
);
235 tup
= SearchSysCache(NAMESPACEOID
,
236 ObjectIdGetDatum(schemaOid
),
238 if (!HeapTupleIsValid(tup
)) /* should not happen */
239 elog(ERROR
, "cache lookup failed for namespace %u", schemaOid
);
241 simple_heap_delete(relation
, &tup
->t_self
);
243 ReleaseSysCache(tup
);
245 heap_close(relation
, RowExclusiveLock
);
253 RenameSchema(const char *oldname
, const char *newname
)
259 rel
= heap_open(NamespaceRelationId
, RowExclusiveLock
);
261 tup
= SearchSysCacheCopy(NAMESPACENAME
,
262 CStringGetDatum(oldname
),
264 if (!HeapTupleIsValid(tup
))
266 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
267 errmsg("schema \"%s\" does not exist", oldname
)));
269 /* make sure the new name doesn't exist */
270 if (HeapTupleIsValid(
271 SearchSysCache(NAMESPACENAME
,
272 CStringGetDatum(newname
),
275 (errcode(ERRCODE_DUPLICATE_SCHEMA
),
276 errmsg("schema \"%s\" already exists", newname
)));
279 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup
), GetUserId()))
280 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_NAMESPACE
,
283 /* must have CREATE privilege on database */
284 aclresult
= pg_database_aclcheck(MyDatabaseId
, GetUserId(), ACL_CREATE
);
285 if (aclresult
!= ACLCHECK_OK
)
286 aclcheck_error(aclresult
, ACL_KIND_DATABASE
,
287 get_database_name(MyDatabaseId
));
289 if (!allowSystemTableMods
&& IsReservedName(newname
))
291 (errcode(ERRCODE_RESERVED_NAME
),
292 errmsg("unacceptable schema name \"%s\"", newname
),
293 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
296 namestrcpy(&(((Form_pg_namespace
) GETSTRUCT(tup
))->nspname
), newname
);
297 simple_heap_update(rel
, &tup
->t_self
, tup
);
298 CatalogUpdateIndexes(rel
, tup
);
300 heap_close(rel
, NoLock
);
305 AlterSchemaOwner_oid(Oid oid
, Oid newOwnerId
)
310 rel
= heap_open(NamespaceRelationId
, RowExclusiveLock
);
312 tup
= SearchSysCache(NAMESPACEOID
,
313 ObjectIdGetDatum(oid
),
315 if (!HeapTupleIsValid(tup
))
316 elog(ERROR
, "cache lookup failed for schema %u", oid
);
318 AlterSchemaOwner_internal(tup
, rel
, newOwnerId
);
320 ReleaseSysCache(tup
);
322 heap_close(rel
, RowExclusiveLock
);
327 * Change schema owner
330 AlterSchemaOwner(const char *name
, Oid newOwnerId
)
335 rel
= heap_open(NamespaceRelationId
, RowExclusiveLock
);
337 tup
= SearchSysCache(NAMESPACENAME
,
338 CStringGetDatum(name
),
340 if (!HeapTupleIsValid(tup
))
342 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
343 errmsg("schema \"%s\" does not exist", name
)));
345 AlterSchemaOwner_internal(tup
, rel
, newOwnerId
);
347 ReleaseSysCache(tup
);
349 heap_close(rel
, RowExclusiveLock
);
353 AlterSchemaOwner_internal(HeapTuple tup
, Relation rel
, Oid newOwnerId
)
355 Form_pg_namespace nspForm
;
357 Assert(tup
->t_tableOid
== NamespaceRelationId
);
358 Assert(RelationGetRelid(rel
) == NamespaceRelationId
);
360 nspForm
= (Form_pg_namespace
) GETSTRUCT(tup
);
363 * If the new owner is the same as the existing owner, consider the
364 * command to have succeeded. This is for dump restoration purposes.
366 if (nspForm
->nspowner
!= newOwnerId
)
368 Datum repl_val
[Natts_pg_namespace
];
369 char repl_null
[Natts_pg_namespace
];
370 char repl_repl
[Natts_pg_namespace
];
377 /* Otherwise, must be owner of the existing object */
378 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup
), GetUserId()))
379 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_NAMESPACE
,
380 NameStr(nspForm
->nspname
));
382 /* Must be able to become new owner */
383 check_is_member_of_role(GetUserId(), newOwnerId
);
386 * must have create-schema rights
388 * NOTE: This is different from other alter-owner checks in that the
389 * current user is checked for create privileges instead of the
390 * destination owner. This is consistent with the CREATE case for
391 * schemas. Because superusers will always have this right, we need
392 * no special case for them.
394 aclresult
= pg_database_aclcheck(MyDatabaseId
, GetUserId(),
396 if (aclresult
!= ACLCHECK_OK
)
397 aclcheck_error(aclresult
, ACL_KIND_DATABASE
,
398 get_database_name(MyDatabaseId
));
400 memset(repl_null
, ' ', sizeof(repl_null
));
401 memset(repl_repl
, ' ', sizeof(repl_repl
));
403 repl_repl
[Anum_pg_namespace_nspowner
- 1] = 'r';
404 repl_val
[Anum_pg_namespace_nspowner
- 1] = ObjectIdGetDatum(newOwnerId
);
407 * Determine the modified ACL for the new owner. This is only
408 * necessary when the ACL is non-null.
410 aclDatum
= SysCacheGetAttr(NAMESPACENAME
, tup
,
411 Anum_pg_namespace_nspacl
,
415 newAcl
= aclnewowner(DatumGetAclP(aclDatum
),
416 nspForm
->nspowner
, newOwnerId
);
417 repl_repl
[Anum_pg_namespace_nspacl
- 1] = 'r';
418 repl_val
[Anum_pg_namespace_nspacl
- 1] = PointerGetDatum(newAcl
);
421 newtuple
= heap_modifytuple(tup
, RelationGetDescr(rel
), repl_val
, repl_null
, repl_repl
);
423 simple_heap_update(rel
, &newtuple
->t_self
, newtuple
);
424 CatalogUpdateIndexes(rel
, newtuple
);
426 heap_freetuple(newtuple
);
428 /* Update owner dependency reference */
429 changeDependencyOnOwner(NamespaceRelationId
, HeapTupleGetOid(tup
),