remove.c 12.6 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * remove.c--
4
 *	  POSTGRES remove (function | type | operator ) utilty code.
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.21 1998/01/15 19:42:38 pgsql Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
M
Marc G. Fournier 已提交
14
#include <postgres.h>
15

M
Marc G. Fournier 已提交
16 17 18 19 20 21 22 23 24 25 26
#include <utils/acl.h>
#include <access/heapam.h>
#include <utils/builtins.h>
#include <utils/syscache.h>
#include <catalog/catname.h>
#include <commands/defrem.h>
#include <miscadmin.h>
#include <catalog/pg_aggregate.h>
#include <catalog/pg_language.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_proc.h>
27 28
#include <catalog/pg_type.h>
#include <parser/parse_func.h>
M
Marc G. Fournier 已提交
29 30 31
#include <storage/bufmgr.h>
#include <fmgr.h>
#ifndef HAVE_MEMMOVE
32
#include <regex/utils.h>
M
Marc G. Fournier 已提交
33
#else
34
#include <string.h>
M
Marc G. Fournier 已提交
35
#endif
36 37 38

/*
 * RemoveOperator --
39
 *		Deletes an operator.
40 41
 *
 * Exceptions:
42 43 44 45
 *		BadArg if name is invalid.
 *		BadArg if type1 is invalid.
 *		"WARN" if operator nonexistent.
 *		...
46 47
 */
void
48 49 50
RemoveOperator(char *operatorName,		/* operator name */
			   char *typeName1, /* first type name */
			   char *typeName2) /* optional second type name */
51
{
52 53 54 55 56 57
	Relation	relation;
	HeapScanDesc scan;
	HeapTuple	tup;
	Oid			typeId1 = InvalidOid;
	Oid			typeId2 = InvalidOid;
	bool		defined;
58
	ItemPointerData itemPointerData;
59 60 61
	Buffer		buffer;
	ScanKeyData operatorKey[3];
	char	   *userName;
62 63 64 65 66 67

	if (typeName1)
	{
		typeId1 = TypeGet(typeName1, &defined);
		if (!OidIsValid(typeId1))
		{
68
			elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName1);
69 70
			return;
		}
71
	}
72 73 74 75 76 77

	if (typeName2)
	{
		typeId2 = TypeGet(typeName2, &defined);
		if (!OidIsValid(typeId2))
		{
78
			elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2);
79 80
			return;
		}
81
	}
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

	ScanKeyEntryInitialize(&operatorKey[0], 0x0,
						   Anum_pg_operator_oprname,
						   NameEqualRegProcedure,
						   PointerGetDatum(operatorName));

	ScanKeyEntryInitialize(&operatorKey[1], 0x0,
						   Anum_pg_operator_oprleft,
						   ObjectIdEqualRegProcedure,
						   ObjectIdGetDatum(typeId1));

	ScanKeyEntryInitialize(&operatorKey[2], 0x0,
						   Anum_pg_operator_oprright,
						   ObjectIdEqualRegProcedure,
						   ObjectIdGetDatum(typeId2));

	relation = heap_openr(OperatorRelationName);
99
	scan = heap_beginscan(relation, 0, false, 3, operatorKey);
100 101 102
	tup = heap_getnext(scan, 0, &buffer);
	if (HeapTupleIsValid(tup))
	{
103
#ifndef NO_SECURITY
104 105 106 107
		userName = GetPgUserName();
		if (!pg_ownercheck(userName,
						   (char *) ObjectIdGetDatum(tup->t_oid),
						   OPROID))
108
			elog(ERROR, "RemoveOperator: operator '%s': permission denied",
109
				 operatorName);
110
#endif
111 112
		ItemPointerCopy(&tup->t_ctid, &itemPointerData);
		heap_delete(relation, &itemPointerData);
113
	}
114 115 116 117
	else
	{
		if (OidIsValid(typeId1) && OidIsValid(typeId2))
		{
118
			elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
119 120 121 122 123 124
				 operatorName,
				 typeName1,
				 typeName2);
		}
		else if (OidIsValid(typeId1))
		{
125
			elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
126 127 128 129 130
				 operatorName,
				 typeName1);
		}
		else
		{
131
			elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
132 133 134 135 136 137
				 operatorName,
				 typeName2);
		}
	}
	heap_endscan(scan);
	heap_close(relation);
138 139 140 141 142 143 144 145
}

#ifdef NOTYET
/*
 * this stuff is to support removing all reference to a type
 * don't use it  - pma 2/1/94
 */
/*
146 147
 *	SingleOpOperatorRemove
 *		Removes all operators that have operands or a result of type 'typeOid'.
148 149 150 151
 */
static void
SingleOpOperatorRemove(Oid typeOid)
{
152 153 154 155
	Relation	rdesc;
	ScanKeyData key[3];
	HeapScanDesc sdesc;
	HeapTuple	tup;
156
	ItemPointerData itemPointerData;
157 158 159
	Buffer		buffer;
	static		attnums[3] = {7, 8, 9}; /* left, right, return */
	register	i;
160 161 162 163 164 165 166

	ScanKeyEntryInitialize(&key[0],
					   0, 0, ObjectIdEqualRegProcedure, (Datum) typeOid);
	rdesc = heap_openr(OperatorRelationName);
	for (i = 0; i < 3; ++i)
	{
		key[0].sk_attno = attnums[i];
167
		sdesc = heap_beginscan(rdesc, 0, false, 1, key);
168 169 170 171 172 173 174
		while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
		{
			ItemPointerCopy(&tup->t_ctid, &itemPointerData);
			/* XXX LOCK not being passed */
			heap_delete(rdesc, &itemPointerData);
		}
		heap_endscan(sdesc);
175
	}
176
	heap_close(rdesc);
177 178 179
}

/*
180 181 182 183
 *	AttributeAndRelationRemove
 *		Removes all entries in the attribute and relation relations
 *		that contain entries of type 'typeOid'.
 *		Currently nothing calls this code, it is untested.
184 185 186 187
 */
static void
AttributeAndRelationRemove(Oid typeOid)
{
188 189
	struct oidlist
	{
190
		Oid			reloid;
191 192 193
		struct oidlist *next;
	};
	struct oidlist *oidptr,
194 195 196 197 198
			   *optr;
	Relation	rdesc;
	ScanKeyData key[1];
	HeapScanDesc sdesc;
	HeapTuple	tup;
199
	ItemPointerData itemPointerData;
200
	Buffer		buffer;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215

	/*
	 * Get the oid's of the relations to be removed by scanning the entire
	 * attribute relation. We don't need to remove the attributes here,
	 * because amdestroy will remove all attributes of the relation. XXX
	 * should check for duplicate relations
	 */

	ScanKeyEntryInitialize(&key[0],
					   0, 3, ObjectIdEqualRegProcedure, (Datum) typeOid);

	oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
	oidptr->next = NULL;
	optr = oidptr;
	rdesc = heap_openr(AttributeRelationName);
216
	sdesc = heap_beginscan(rdesc, 0, false, 1, key);
217 218 219 220 221 222
	while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
	{
		ItemPointerCopy(&tup->t_ctid, &itemPointerData);
		optr->reloid = ((AttributeTupleForm) GETSTRUCT(tup))->attrelid;
		optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
		optr = optr->next;
223
	}
224 225 226 227 228 229 230 231 232 233 234 235 236
	optr->next = NULL;
	heap_endscan(sdesc);
	heap_close(rdesc);


	ScanKeyEntryInitialize(&key[0], 0,
						   ObjectIdAttributeNumber,
						   ObjectIdEqualRegProcedure, (Datum) 0);
	optr = oidptr;
	rdesc = heap_openr(RelationRelationName);
	while (PointerIsValid((char *) optr->next))
	{
		key[0].sk_argument = (Datum) (optr++)->reloid;
237
		sdesc = heap_beginscan(rdesc, 0, false, 1, key);
238 239 240
		tup = heap_getnext(sdesc, 0, &buffer);
		if (PointerIsValid(tup))
		{
241
			char	   *name;
242 243

			name = (((Form_pg_class) GETSTRUCT(tup))->relname).data;
244
			heap_destroy_with_catalog(name);
245 246 247 248
		}
	}
	heap_endscan(sdesc);
	heap_close(rdesc);
249
}
250 251

#endif							/* NOTYET */
252 253

/*
254 255 256
 *	TypeRemove
 *		Removes the type 'typeName' and all attributes and relations that
 *		use it.
257 258
 */
void
259
RemoveType(char *typeName)		/* type name to be removed */
260
{
261 262 263 264
	Relation	relation;
	HeapScanDesc scan;
	HeapTuple	tup;
	Oid			typeOid;
265 266 267 268
	ItemPointerData itemPointerData;
	static ScanKeyData typeKey[1] = {
		{0, Anum_pg_type_typname, NameEqualRegProcedure}
	};
269 270
	char	   *shadow_type;
	char	   *userName;
271

272
#ifndef NO_SECURITY
273 274
	userName = GetPgUserName();
	if (!pg_ownercheck(userName, typeName, TYPNAME))
275
		elog(ERROR, "RemoveType: type '%s': permission denied",
276
			 typeName);
277
#endif
278 279

	relation = heap_openr(TypeRelationName);
280 281
	fmgr_info(typeKey[0].sk_procedure, &typeKey[0].sk_func);
	typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
282 283 284 285 286

	/* Delete the primary type */

	typeKey[0].sk_argument = PointerGetDatum(typeName);

287
	scan = heap_beginscan(relation, 0, false, 1, typeKey);
288 289 290 291 292
	tup = heap_getnext(scan, 0, (Buffer *) 0);
	if (!HeapTupleIsValid(tup))
	{
		heap_endscan(scan);
		heap_close(relation);
293
		elog(ERROR, "RemoveType: type '%s' does not exist",
294 295 296 297 298
			 typeName);
	}
	typeOid = tup->t_oid;
	ItemPointerCopy(&tup->t_ctid, &itemPointerData);
	heap_delete(relation, &itemPointerData);
299
	heap_endscan(scan);
300 301 302 303 304

	/* Now, Delete the "array of" that type */
	shadow_type = makeArrayTypeName(typeName);
	typeKey[0].sk_argument = NameGetDatum(shadow_type);

305
	scan = heap_beginscan(relation, 0, false,
306 307 308 309
						  1, (ScanKey) typeKey);
	tup = heap_getnext(scan, 0, (Buffer *) 0);

	if (!HeapTupleIsValid(tup))
310
	{
311
		elog(ERROR, "RemoveType: type '%s': array stub not found",
312
			 typeName);
313
	}
314 315 316 317 318 319
	typeOid = tup->t_oid;
	ItemPointerCopy(&tup->t_ctid, &itemPointerData);
	heap_delete(relation, &itemPointerData);
	heap_endscan(scan);

	heap_close(relation);
320 321 322 323
}

/*
 * RemoveFunction --
324
 *		Deletes a function.
325 326
 *
 * Exceptions:
327 328 329
 *		BadArg if name is invalid.
 *		"WARN" if function nonexistent.
 *		...
330 331
 */
void
332 333
RemoveFunction(char *functionName,		/* function name to be removed */
			   int nargs,
334
			   List *argNameList /* list of TypeNames */ )
335
{
336 337 338 339 340 341 342
	Relation	relation;
	HeapScanDesc scan;
	HeapTuple	tup;
	Buffer		buffer = InvalidBuffer;
	bool		bufferUsed = FALSE;
	Oid			argList[8];
	Form_pg_proc the_proc = NULL;
343 344 345 346
	ItemPointerData itemPointerData;
	static ScanKeyData key[3] = {
		{0, Anum_pg_proc_proname, NameEqualRegProcedure}
	};
347 348 349
	char	   *userName;
	char	   *typename;
	int			i;
350

B
Bruce Momjian 已提交
351
	MemSet(argList, 0, 8 * sizeof(Oid));
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	for (i = 0; i < nargs; i++)
	{
/*		typename = ((TypeName*)(lfirst(argNameList)))->name; */
		typename = strVal(lfirst(argNameList));
		argNameList = lnext(argNameList);

		if (strcmp(typename, "opaque") == 0)
			argList[i] = 0;
		else
		{
			tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typename),
									  0, 0, 0);

			if (!HeapTupleIsValid(tup))
			{
367
				elog(ERROR, "RemoveFunction: type '%s' not found", typename);
368 369 370
			}
			argList[i] = tup->t_oid;
		}
371
	}
372 373 374 375 376 377 378

	tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(functionName),
							  Int32GetDatum(nargs),
							  PointerGetDatum(argList), 0);
	if (!HeapTupleIsValid(tup))
		func_error("RemoveFunction", functionName, nargs, argList);

379
#ifndef NO_SECURITY
380 381 382
	userName = GetPgUserName();
	if (!pg_func_ownercheck(userName, functionName, nargs, argList))
	{
383
		elog(ERROR, "RemoveFunction: function '%s': permission denied",
384
			 functionName);
385
	}
386 387 388 389
#endif

	key[0].sk_argument = PointerGetDatum(functionName);

390 391
	fmgr_info(key[0].sk_procedure, &key[0].sk_func);
	key[0].sk_nargs = key[0].sk_func.fn_nargs;
392 393

	relation = heap_openr(ProcedureRelationName);
394
	scan = heap_beginscan(relation, 0, false, 1, key);
395 396 397 398 399 400 401 402

	do
	{							/* hope this is ok because it's indexed */
		if (bufferUsed)
		{
			ReleaseBuffer(buffer);
			bufferUsed = FALSE;
		}
B
Bruce Momjian 已提交
403
		tup = heap_getnext(scan, 0, (Buffer *) &buffer);
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
		if (!HeapTupleIsValid(tup))
			break;
		bufferUsed = TRUE;
		the_proc = (Form_pg_proc) GETSTRUCT(tup);
	} while ((namestrcmp(&(the_proc->proname), functionName) == 0) &&
			 (the_proc->pronargs != nargs ||
			  !oid8eq(&(the_proc->proargtypes[0]), &argList[0])));


	if (!HeapTupleIsValid(tup) || namestrcmp(&(the_proc->proname),
											 functionName) != 0)
	{
		heap_endscan(scan);
		heap_close(relation);
		func_error("RemoveFunction", functionName, nargs, argList);
419
	}
420 421 422 423

	/* ok, function has been found */

	if (the_proc->prolang == INTERNALlanguageId)
424
		elog(ERROR, "RemoveFunction: function \"%s\" is built-in",
425 426 427 428 429 430
			 functionName);

	ItemPointerCopy(&tup->t_ctid, &itemPointerData);
	heap_delete(relation, &itemPointerData);
	heap_endscan(scan);
	heap_close(relation);
431 432 433
}

void
434
RemoveAggregate(char *aggName, char *aggType)
435
{
436 437 438
	Relation	relation;
	HeapScanDesc scan;
	HeapTuple	tup;
439
	ItemPointerData itemPointerData;
440 441 442 443
	char	   *userName;
	Oid			basetypeID = InvalidOid;
	bool		defined;
	ScanKeyData aggregateKey[3];
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460


	/*
	 * if a basetype is passed in, then attempt to find an aggregate for
	 * that specific type.
	 *
	 * else if the basetype is blank, then attempt to find an aggregate with
	 * a basetype of zero.	This is valid. It means that the aggregate is
	 * to apply to all basetypes.  ie, a counter of some sort.
	 *
	 */

	if (aggType)
	{
		basetypeID = TypeGet(aggType, &defined);
		if (!OidIsValid(basetypeID))
		{
461
			elog(ERROR, "RemoveAggregate: type '%s' does not exist", aggType);
462 463 464 465 466 467
		}
	}
	else
	{
		basetypeID = 0;
	}
468 469 470 471

/*
#ifndef NO_SECURITY
*/
472 473 474 475 476
	userName = GetPgUserName();
	if (!pg_aggr_ownercheck(userName, aggName, basetypeID))
	{
		if (aggType)
		{
477
			elog(ERROR, "RemoveAggregate: aggregate '%s' on type '%s': permission denied",
478 479 480 481
				 aggName, aggType);
		}
		else
		{
482
			elog(ERROR, "RemoveAggregate: aggregate '%s': permission denied",
483 484 485
				 aggName);
		}
	}
486 487 488 489
/*
#endif
*/

490 491 492 493 494 495 496 497 498 499 500
	ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
						   Anum_pg_aggregate_aggname,
						   NameEqualRegProcedure,
						   PointerGetDatum(aggName));

	ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
						   Anum_pg_aggregate_aggbasetype,
						   ObjectIdEqualRegProcedure,
						   ObjectIdGetDatum(basetypeID));

	relation = heap_openr(AggregateRelationName);
501
	scan = heap_beginscan(relation, 0, false, 2, aggregateKey);
502 503 504 505 506 507 508
	tup = heap_getnext(scan, 0, (Buffer *) 0);
	if (!HeapTupleIsValid(tup))
	{
		heap_endscan(scan);
		heap_close(relation);
		if (aggType)
		{
509
			elog(ERROR, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
510 511 512 513
				 aggName, aggType);
		}
		else
		{
514
			elog(ERROR, "RemoveAggregate: aggregate '%s' for all types does not exist",
515 516 517 518 519 520 521
				 aggName);
		}
	}
	ItemPointerCopy(&tup->t_ctid, &itemPointerData);
	heap_delete(relation, &itemPointerData);
	heap_endscan(scan);
	heap_close(relation);
522
}