alter.c 11.0 KB
Newer Older
1 2 3 4 5
/*-------------------------------------------------------------------------
 *
 * alter.c
 *	  Drivers for generic alter commands
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 8 9 10
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  src/backend/commands/alter.c
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

17 18
#include "catalog/dependency.h"
#include "catalog/indexing.h"
19
#include "catalog/namespace.h"
20
#include "catalog/pg_largeobject.h"
21
#include "catalog/pg_namespace.h"
22 23 24 25 26 27 28
#include "commands/alter.h"
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/tablecmds.h"
29
#include "commands/tablespace.h"
30
#include "commands/trigger.h"
31
#include "commands/typecmds.h"
32 33 34
#include "commands/user.h"
#include "miscadmin.h"
#include "parser/parse_clause.h"
35
#include "tcop/utility.h"
36
#include "utils/acl.h"
37
#include "utils/builtins.h"
38
#include "utils/lsyscache.h"
39
#include "utils/syscache.h"
40 41


42
/*
B
Bruce Momjian 已提交
43
 * Executes an ALTER OBJECT / RENAME TO statement.	Based on the object
44 45
 * type, the function appropriate to that type is executed.
 */
46 47 48 49 50 51
void
ExecRenameStmt(RenameStmt *stmt)
{
	switch (stmt->renameType)
	{
		case OBJECT_AGGREGATE:
T
Tom Lane 已提交
52
			RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
			break;

		case OBJECT_CONVERSION:
			RenameConversion(stmt->object, stmt->newname);
			break;

		case OBJECT_DATABASE:
			RenameDatabase(stmt->subname, stmt->newname);
			break;

		case OBJECT_FUNCTION:
			RenameFunction(stmt->object, stmt->objarg, stmt->newname);
			break;

		case OBJECT_LANGUAGE:
			RenameLanguage(stmt->subname, stmt->newname);
			break;

		case OBJECT_OPCLASS:
			RenameOpClass(stmt->object, stmt->subname, stmt->newname);
			break;

75 76 77 78
		case OBJECT_OPFAMILY:
			RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
			break;

79 80 81 82
		case OBJECT_ROLE:
			RenameRole(stmt->subname, stmt->newname);
			break;

83 84 85 86
		case OBJECT_SCHEMA:
			RenameSchema(stmt->subname, stmt->newname);
			break;

87 88 89 90
		case OBJECT_TABLESPACE:
			RenameTableSpace(stmt->subname, stmt->newname);
			break;

91
		case OBJECT_TABLE:
92 93
		case OBJECT_SEQUENCE:
		case OBJECT_VIEW:
T
Tom Lane 已提交
94
		case OBJECT_INDEX:
95
		case OBJECT_COLUMN:
96
		case OBJECT_ATTRIBUTE:
97
		case OBJECT_TRIGGER:
R
Robert Haas 已提交
98
		case OBJECT_FOREIGN_TABLE:
B
Bruce Momjian 已提交
99 100
			{
				Oid			relid;
101

B
Bruce Momjian 已提交
102
				CheckRelationOwnership(stmt->relation, true);
103

B
Bruce Momjian 已提交
104
				relid = RangeVarGetRelid(stmt->relation, false);
105

B
Bruce Momjian 已提交
106
				switch (stmt->renameType)
107
				{
B
Bruce Momjian 已提交
108
					case OBJECT_TABLE:
109 110
					case OBJECT_SEQUENCE:
					case OBJECT_VIEW:
T
Tom Lane 已提交
111
					case OBJECT_INDEX:
R
Robert Haas 已提交
112
					case OBJECT_FOREIGN_TABLE:
B
Bruce Momjian 已提交
113 114 115
						{
							/*
							 * RENAME TABLE requires that we (still) hold
B
Bruce Momjian 已提交
116 117
							 * CREATE rights on the containing namespace, as
							 * well as ownership of the table.
B
Bruce Momjian 已提交
118 119 120 121 122
							 */
							Oid			namespaceId = get_rel_namespace(relid);
							AclResult	aclresult;

							aclresult = pg_namespace_aclcheck(namespaceId,
123 124
															  GetUserId(),
															  ACL_CREATE);
B
Bruce Momjian 已提交
125 126
							if (aclresult != ACLCHECK_OK)
								aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
B
Bruce Momjian 已提交
127
											get_namespace_name(namespaceId));
B
Bruce Momjian 已提交
128

129
							RenameRelation(relid, stmt->newname, stmt->renameType);
B
Bruce Momjian 已提交
130 131 132
							break;
						}
					case OBJECT_COLUMN:
133
					case OBJECT_ATTRIBUTE:
134
						renameatt(relid, stmt);
B
Bruce Momjian 已提交
135 136 137 138 139 140 141 142 143 144
						break;
					case OBJECT_TRIGGER:
						renametrig(relid,
								   stmt->subname,		/* old att name */
								   stmt->newname);		/* new att name */
						break;
					default:
						 /* can't happen */ ;
				}
				break;
145 146
			}

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
		case OBJECT_TSPARSER:
			RenameTSParser(stmt->object, stmt->newname);
			break;

		case OBJECT_TSDICTIONARY:
			RenameTSDictionary(stmt->object, stmt->newname);
			break;

		case OBJECT_TSTEMPLATE:
			RenameTSTemplate(stmt->object, stmt->newname);
			break;

		case OBJECT_TSCONFIGURATION:
			RenameTSConfiguration(stmt->object, stmt->newname);
			break;

163 164 165 166
		case OBJECT_TYPE:
			RenameType(stmt->object, stmt->newname);
			break;

167
		default:
168 169
			elog(ERROR, "unrecognized rename stmt type: %d",
				 (int) stmt->renameType);
170 171
	}
}
172

173 174 175 176 177 178 179 180 181 182
/*
 * Executes an ALTER OBJECT / SET SCHEMA statement.  Based on the object
 * type, the function appropriate to that type is executed.
 */
void
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
{
	switch (stmt->objectType)
	{
		case OBJECT_AGGREGATE:
T
Tom Lane 已提交
183 184 185 186
			AlterFunctionNamespace(stmt->object, stmt->objarg, true,
								   stmt->newschema);
			break;

187 188 189 190
		case OBJECT_CONVERSION:
			AlterConversionNamespace(stmt->object, stmt->newschema);
			break;

191
		case OBJECT_FUNCTION:
T
Tom Lane 已提交
192
			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
193 194
								   stmt->newschema);
			break;
B
Bruce Momjian 已提交
195

196 197 198 199 200
		case OBJECT_OPERATOR:
			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
			break;

		case OBJECT_OPCLASS:
201
			AlterOpClassNamespace(stmt->object, stmt->addname, stmt->newschema);
202 203 204
			break;

		case OBJECT_OPFAMILY:
205
			AlterOpFamilyNamespace(stmt->object, stmt->addname, stmt->newschema);
206 207
			break;

208 209
		case OBJECT_SEQUENCE:
		case OBJECT_TABLE:
210
		case OBJECT_VIEW:
R
Robert Haas 已提交
211
		case OBJECT_FOREIGN_TABLE:
212
			CheckRelationOwnership(stmt->relation, true);
213
			AlterTableNamespace(stmt->relation, stmt->newschema,
214
								stmt->objectType, AccessExclusiveLock);
215
			break;
B
Bruce Momjian 已提交
216

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		case OBJECT_TSPARSER:
			AlterTSParserNamespace(stmt->object, stmt->newschema);
			break;

		case OBJECT_TSDICTIONARY:
			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
			break;

		case OBJECT_TSTEMPLATE:
			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
			break;

		case OBJECT_TSCONFIGURATION:
			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
			break;

233 234 235 236
		case OBJECT_TYPE:
		case OBJECT_DOMAIN:
			AlterTypeNamespace(stmt->object, stmt->newschema);
			break;
B
Bruce Momjian 已提交
237

238 239 240 241 242 243
		default:
			elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
				 (int) stmt->objectType);
	}
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
/*
 * Generic function to change the namespace of a given object, for simple
 * cases (won't work for tables or functions, objects which have more than 2
 * key-attributes to use when searching for their syscache entries --- we
 * don't want nor need to get this generic here).
 *
 * The AlterFooNamespace() calls just above will call a function whose job
 * is to lookup the arguments for the generic function here.
 *
 * Relation must already by open, it's the responsibility of the caller to
 * close it.
 */
void
AlterObjectNamespace(Relation rel, int cacheId,
					 Oid classId, Oid objid, Oid nspOid,
					 int Anum_name, int Anum_namespace, int Anum_owner,
					 AclObjectKind acl_kind,
					 bool superuser_only)
{
	Oid			oldNspOid;
	Datum       name, namespace;
	bool        isnull;
	HeapTuple	tup, newtup = NULL;
	Datum	   *values;
	bool	   *nulls;
	bool	   *replaces;

	tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
	if (!HeapTupleIsValid(tup)) /* should not happen */
		elog(ERROR, "cache lookup failed for object %u: %s",
			 objid, getObjectDescriptionOids(classId, objid));

	name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
	namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
	oldNspOid = DatumGetObjectId(namespace);

	/* Check basic namespace related issues */
	CheckSetNamespace(oldNspOid, nspOid, classId, objid);

	/* check for duplicate name (more friendly than unique-index failure) */
	if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("%s already exists in schema \"%s\"",
						getObjectDescriptionOids(classId, objid),
						get_namespace_name(nspOid))));

	/* Superusers can always do it */
	if (!superuser())
	{
		Datum       owner;
		Oid			ownerId;
		AclResult	aclresult;

		if (superuser_only)
			ereport(ERROR,
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					 (errmsg("must be superuser to SET SCHEMA of %s",
							 getObjectDescriptionOids(classId, objid)))));

		/* Otherwise, must be owner of the existing object */
		owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
		ownerId = DatumGetObjectId(owner);

		if (!has_privs_of_role(GetUserId(), ownerId))
			aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
						   NameStr(*(DatumGetName(name))));

		/* owner must have CREATE privilege on namespace */
		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
		if (aclresult != ACLCHECK_OK)
			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
						   get_namespace_name(oldNspOid));
	}

	/* Prepare to update tuple */
	values = palloc0(rel->rd_att->natts * sizeof(Datum));
	nulls = palloc0(rel->rd_att->natts * sizeof(bool));
	replaces = palloc0(rel->rd_att->natts * sizeof(bool));
	values[Anum_namespace - 1] = nspOid;
	replaces[Anum_namespace - 1] = true;
	newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);

	/* Perform actual update */
	simple_heap_update(rel, &tup->t_self, newtup);
	CatalogUpdateIndexes(rel, newtup);

	/* Release memory */
	pfree(values);
	pfree(nulls);
	pfree(replaces);

	/* update dependencies to point to the new schema */
	changeDependencyFor(classId, objid,
						NamespaceRelationId, oldNspOid, nspOid);
}


342 343 344 345 346 347 348
/*
 * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
 * type, the function appropriate to that type is executed.
 */
void
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
349
	Oid			newowner = get_role_oid(stmt->newowner, false);
350 351 352 353

	switch (stmt->objectType)
	{
		case OBJECT_AGGREGATE:
T
Tom Lane 已提交
354
			AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
355 356 357 358 359 360 361
			break;

		case OBJECT_CONVERSION:
			AlterConversionOwner(stmt->object, newowner);
			break;

		case OBJECT_DATABASE:
362
			AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
363 364 365 366 367 368
			break;

		case OBJECT_FUNCTION:
			AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
			break;

369
		case OBJECT_LANGUAGE:
370
			AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
371 372
			break;

373
		case OBJECT_LARGEOBJECT:
374
			LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner);
375 376
			break;

377
		case OBJECT_OPERATOR:
T
Tom Lane 已提交
378
			Assert(list_length(stmt->objarg) == 2);
379 380 381 382 383 384 385 386 387 388
			AlterOperatorOwner(stmt->object,
							   (TypeName *) linitial(stmt->objarg),
							   (TypeName *) lsecond(stmt->objarg),
							   newowner);
			break;

		case OBJECT_OPCLASS:
			AlterOpClassOwner(stmt->object, stmt->addname, newowner);
			break;

389 390 391 392
		case OBJECT_OPFAMILY:
			AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
			break;

393
		case OBJECT_SCHEMA:
394
			AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
395 396 397
			break;

		case OBJECT_TABLESPACE:
398
			AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
399 400 401 402 403 404 405
			break;

		case OBJECT_TYPE:
		case OBJECT_DOMAIN:		/* same as TYPE */
			AlterTypeOwner(stmt->object, newowner);
			break;

406 407 408 409 410 411 412 413
		case OBJECT_TSDICTIONARY:
			AlterTSDictionaryOwner(stmt->object, newowner);
			break;

		case OBJECT_TSCONFIGURATION:
			AlterTSConfigurationOwner(stmt->object, newowner);
			break;

414 415 416 417 418 419 420 421 422
		case OBJECT_FDW:
			AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
										 newowner);
			break;

		case OBJECT_FOREIGN_SERVER:
			AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
			break;

423 424 425 426 427
		default:
			elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
				 (int) stmt->objectType);
	}
}