Fix pg_dump bug in the database-level collation patch. "datcollate" and
[PostgreSQL.git] / src / backend / commands / schemacmds.c
blob4c617a5019295b83bb3de940e70e69dc1d1165d3
1 /*-------------------------------------------------------------------------
3 * schemacmds.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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);
38 * CREATE SCHEMA
40 void
41 CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
43 const char *schemaName = stmt->schemaname;
44 const char *authId = stmt->authid;
45 Oid namespaceId;
46 OverrideSearchPath *overridePath;
47 List *parsetree_list;
48 ListCell *parsetree_item;
49 Oid owner_uid;
50 Oid saved_uid;
51 bool saved_secdefcxt;
52 AclResult aclresult;
54 GetUserIdAndContext(&saved_uid, &saved_secdefcxt);
57 * Who is supposed to own the new schema?
59 if (authId)
60 owner_uid = get_roleid_checked(authId);
61 else
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))
80 ereport(ERROR,
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);
131 /* do this step */
132 ProcessUtility(stmt,
133 queryString,
134 NULL,
135 false, /* not top level */
136 None_Receiver,
137 NULL);
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);
151 * RemoveSchemas
152 * Implements DROP SCHEMA.
154 void
155 RemoveSchemas(DropStmt *drop)
157 ObjectAddresses *objects;
158 ListCell *cell;
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);
170 char *namespaceName;
171 Oid namespaceId;
172 ObjectAddress object;
174 if (list_length(names) != 1)
175 ereport(ERROR,
176 (errcode(ERRCODE_SYNTAX_ERROR),
177 errmsg("schema name cannot be qualified")));
178 namespaceName = strVal(linitial(names));
180 namespaceId = GetSysCacheOid(NAMESPACENAME,
181 CStringGetDatum(namespaceName),
182 0, 0, 0);
184 if (!OidIsValid(namespaceId))
186 if (!drop->missing_ok)
188 ereport(ERROR,
189 (errcode(ERRCODE_UNDEFINED_SCHEMA),
190 errmsg("schema \"%s\" does not exist",
191 namespaceName)));
193 else
195 ereport(NOTICE,
196 (errmsg("schema \"%s\" does not exist, skipping",
197 namespaceName)));
199 continue;
202 /* Permission check */
203 if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
204 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
205 namespaceName);
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.
227 void
228 RemoveSchemaById(Oid schemaOid)
230 Relation relation;
231 HeapTuple tup;
233 relation = heap_open(NamespaceRelationId, RowExclusiveLock);
235 tup = SearchSysCache(NAMESPACEOID,
236 ObjectIdGetDatum(schemaOid),
237 0, 0, 0);
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);
250 * Rename schema
252 void
253 RenameSchema(const char *oldname, const char *newname)
255 HeapTuple tup;
256 Relation rel;
257 AclResult aclresult;
259 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
261 tup = SearchSysCacheCopy(NAMESPACENAME,
262 CStringGetDatum(oldname),
263 0, 0, 0);
264 if (!HeapTupleIsValid(tup))
265 ereport(ERROR,
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),
273 0, 0, 0)))
274 ereport(ERROR,
275 (errcode(ERRCODE_DUPLICATE_SCHEMA),
276 errmsg("schema \"%s\" already exists", newname)));
278 /* must be owner */
279 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
280 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
281 oldname);
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))
290 ereport(ERROR,
291 (errcode(ERRCODE_RESERVED_NAME),
292 errmsg("unacceptable schema name \"%s\"", newname),
293 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
295 /* rename */
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);
301 heap_freetuple(tup);
304 void
305 AlterSchemaOwner_oid(Oid oid, Oid newOwnerId)
307 HeapTuple tup;
308 Relation rel;
310 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
312 tup = SearchSysCache(NAMESPACEOID,
313 ObjectIdGetDatum(oid),
314 0, 0, 0);
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
329 void
330 AlterSchemaOwner(const char *name, Oid newOwnerId)
332 HeapTuple tup;
333 Relation rel;
335 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
337 tup = SearchSysCache(NAMESPACENAME,
338 CStringGetDatum(name),
339 0, 0, 0);
340 if (!HeapTupleIsValid(tup))
341 ereport(ERROR,
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);
352 static void
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];
371 Acl *newAcl;
372 Datum aclDatum;
373 bool isNull;
374 HeapTuple newtuple;
375 AclResult aclresult;
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(),
395 ACL_CREATE);
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,
412 &isNull);
413 if (!isNull)
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),
430 newOwnerId);