schemacmds.c 5.54 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * schemacmds.c
4
 *	  schema creation/manipulation commands
5 6 7 8 9 10
 *
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.5 2002/07/18 16:47:24 tgl Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

17
#include "access/heapam.h"
18
#include "catalog/catalog.h"
19 20
#include "catalog/catname.h"
#include "catalog/dependency.h"
21
#include "catalog/namespace.h"
22 23 24 25 26
#include "catalog/pg_namespace.h"
#include "commands/schemacmds.h"
#include "miscadmin.h"
#include "parser/analyze.h"
#include "tcop/utility.h"
27
#include "utils/acl.h"
28
#include "utils/lsyscache.h"
29
#include "utils/syscache.h"
30 31 32 33 34 35 36 37 38 39


/*
 * CREATE SCHEMA
 */
void
CreateSchemaCommand(CreateSchemaStmt *stmt)
{
	const char *schemaName = stmt->schemaname;
	const char *authId = stmt->authid;
40
	Oid			namespaceId;
41 42 43 44 45
	List	   *parsetree_list;
	List	   *parsetree_item;
	const char *owner_name;
	Oid			owner_userid;
	Oid			saved_userid;
46
	AclResult	aclresult;
47 48 49

	saved_userid = GetUserId();

50 51 52 53
	/*
	 * Figure out user identities.
	 */

54 55 56
	if (!authId)
	{
		owner_userid = saved_userid;
Jan Wieck's avatar
Jan Wieck committed
57
		owner_name = GetUserNameFromId(owner_userid);
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
	}
	else if (superuser())
	{
		owner_name = authId;
		/* The following will error out if user does not exist */
		owner_userid = get_usesysid(owner_name);
		/*
		 * Set the current user to the requested authorization so
		 * that objects created in the statement have the requested
		 * owner.  (This will revert to session user on error or at
		 * the end of this routine.)
		 */
		SetUserId(owner_userid);
	}
	else /* not superuser */
	{
		owner_userid = saved_userid;
Jan Wieck's avatar
Jan Wieck committed
75
		owner_name = GetUserNameFromId(owner_userid);
76 77 78 79 80 81
		if (strcmp(authId, owner_name) != 0)
			elog(ERROR, "CREATE SCHEMA: permission denied"
				 "\n\t\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
				 owner_name, authId);
	}

82 83 84 85 86 87 88
	/*
	 * Permissions checks.
	 */
	aclresult = pg_database_aclcheck(MyDatabaseId, saved_userid, ACL_CREATE);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, DatabaseName);

89 90 91 92 93
	if (!allowSystemTableMods && IsReservedName(schemaName))
		elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
			 schemaName);

	/* Create the schema's namespace */
94
	namespaceId = NamespaceCreate(schemaName, owner_userid);
95

96
	/* Advance cmd counter to make the namespace visible */
97 98
	CommandCounterIncrement();

99 100 101 102 103 104 105
	/*
	 * Temporarily make the new namespace be the front of the search path,
	 * as well as the default creation target namespace.  This will be undone
	 * at the end of this routine, or upon error.
	 */
	PushSpecialNamespace(namespaceId);

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	/*
	 * Examine the list of commands embedded in the CREATE SCHEMA command,
	 * and reorganize them into a sequentially executable order with no
	 * forward references.  Note that the result is still a list of raw
	 * parsetrees in need of parse analysis --- we cannot, in general,
	 * run analyze.c on one statement until we have actually executed the
	 * prior ones.
	 */
	parsetree_list = analyzeCreateSchemaStmt(stmt);

	/*
	 * Analyze and execute each command contained in the CREATE SCHEMA
	 */
	foreach(parsetree_item, parsetree_list)
	{
		Node	   *parsetree = (Node *) lfirst(parsetree_item);
		List	   *querytree_list,
				   *querytree_item;

		querytree_list = parse_analyze(parsetree, NULL);

		foreach(querytree_item, querytree_list)
		{
			Query	   *querytree = (Query *) lfirst(querytree_item);

			/* schemas should contain only utility stmts */
			Assert(querytree->commandType == CMD_UTILITY);
			/* do this step */
			ProcessUtility(querytree->utilityStmt, None, NULL);
			/* make sure later steps can see the object created here */
			CommandCounterIncrement();
		}
	}

140 141 142
	/* Reset search path to normal state */
	PopSpecialNamespace(namespaceId);

143 144 145
	/* Reset current user */
	SetUserId(saved_userid);
}
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212


/*
 *	RemoveSchema
 *		Removes a schema.
 */
void
RemoveSchema(List *names, DropBehavior behavior)
{
	char	   *namespaceName;
	Oid			namespaceId;
	ObjectAddress object;

	if (length(names) != 1)
		elog(ERROR, "Schema name may not be qualified");
	namespaceName = strVal(lfirst(names));

	namespaceId = GetSysCacheOid(NAMESPACENAME,
								 CStringGetDatum(namespaceName),
								 0, 0, 0);
	if (!OidIsValid(namespaceId))
		elog(ERROR, "Schema \"%s\" does not exist", namespaceName);

	/* Permission check */
	if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, namespaceName);

	/*
	 * Do the deletion.  Objects contained in the schema are removed
	 * by means of their dependency links to the schema.
	 *
	 * XXX currently, index opclasses don't have creation/deletion
	 * commands, so they will not get removed when the containing
	 * schema is removed.  This is annoying but not fatal.
	 */
	object.classId = get_system_catalog_relid(NamespaceRelationName);
	object.objectId = namespaceId;
	object.objectSubId = 0;

	performDeletion(&object, behavior);
}


/*
 * Guts of schema deletion.
 */
void
RemoveSchemaById(Oid schemaOid)
{
	Relation	relation;
	HeapTuple	tup;

	relation = heap_openr(NamespaceRelationName, RowExclusiveLock);

	tup = SearchSysCache(NAMESPACEOID,
						 ObjectIdGetDatum(schemaOid),
						 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		elog(ERROR, "RemoveSchemaById: schema %u not found",
			 schemaOid);

	simple_heap_delete(relation, &tup->t_self);

	ReleaseSysCache(tup);

	heap_close(relation, RowExclusiveLock);
}