remove.c 12.5 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
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.23 1998/04/27 04:05:19 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
B
Bruce Momjian 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#include "postgres.h"

#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "storage/bufmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/syscache.h"

M
Marc G. Fournier 已提交
32
#ifndef HAVE_MEMMOVE
33
#include <regex/utils.h>
M
Marc G. Fournier 已提交
34
#else
35
#include <string.h>
M
Marc G. Fournier 已提交
36
#endif
37 38 39

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

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

	if (typeName2)
	{
		typeId2 = TypeGet(typeName2, &defined);
		if (!OidIsValid(typeId2))
		{
79
			elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2);
80 81
			return;
		}
82
	}
83 84 85

	ScanKeyEntryInitialize(&operatorKey[0], 0x0,
						   Anum_pg_operator_oprname,
B
Bruce Momjian 已提交
86
						   F_NAMEEQ,
87 88 89 90
						   PointerGetDatum(operatorName));

	ScanKeyEntryInitialize(&operatorKey[1], 0x0,
						   Anum_pg_operator_oprleft,
B
Bruce Momjian 已提交
91
						   F_OIDEQ,
92 93 94 95
						   ObjectIdGetDatum(typeId1));

	ScanKeyEntryInitialize(&operatorKey[2], 0x0,
						   Anum_pg_operator_oprright,
B
Bruce Momjian 已提交
96
						   F_OIDEQ,
97 98 99
						   ObjectIdGetDatum(typeId2));

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

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

	ScanKeyEntryInitialize(&key[0],
B
Bruce Momjian 已提交
163
					   0, 0, F_OIDEQ, (Datum) typeOid);
164 165 166 167
	rdesc = heap_openr(OperatorRelationName);
	for (i = 0; i < 3; ++i)
	{
		key[0].sk_attno = attnums[i];
168
		sdesc = heap_beginscan(rdesc, 0, false, 1, key);
169 170 171 172 173 174 175
		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);
176
	}
177
	heap_close(rdesc);
178 179 180
}

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

	/*
	 * 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],
B
Bruce Momjian 已提交
211
					   0, 3, F_OIDEQ, (Datum) typeOid);
212 213 214 215 216

	oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
	oidptr->next = NULL;
	optr = oidptr;
	rdesc = heap_openr(AttributeRelationName);
217
	sdesc = heap_beginscan(rdesc, 0, false, 1, key);
218 219 220 221 222 223
	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;
224
	}
225 226 227 228 229 230 231
	optr->next = NULL;
	heap_endscan(sdesc);
	heap_close(rdesc);


	ScanKeyEntryInitialize(&key[0], 0,
						   ObjectIdAttributeNumber,
B
Bruce Momjian 已提交
232
						   F_OIDEQ, (Datum) 0);
233 234 235 236 237
	optr = oidptr;
	rdesc = heap_openr(RelationRelationName);
	while (PointerIsValid((char *) optr->next))
	{
		key[0].sk_argument = (Datum) (optr++)->reloid;
238
		sdesc = heap_beginscan(rdesc, 0, false, 1, key);
239 240 241
		tup = heap_getnext(sdesc, 0, &buffer);
		if (PointerIsValid(tup))
		{
242
			char	   *name;
243 244

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

#endif							/* NOTYET */
253 254

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

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

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

	/* Delete the primary type */

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

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

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

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

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

	heap_close(relation);
321 322 323 324
}

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

B
Bruce Momjian 已提交
352
	MemSet(argList, 0, 8 * sizeof(Oid));
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
	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))
			{
368
				elog(ERROR, "RemoveFunction: type '%s' not found", typename);
369 370 371
			}
			argList[i] = tup->t_oid;
		}
372
	}
373 374 375 376 377 378 379

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

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

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

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

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

	do
	{							/* hope this is ok because it's indexed */
		if (bufferUsed)
		{
			ReleaseBuffer(buffer);
			bufferUsed = FALSE;
		}
B
Bruce Momjian 已提交
404
		tup = heap_getnext(scan, 0, (Buffer *) &buffer);
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
		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);
420
	}
421 422 423 424

	/* ok, function has been found */

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

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

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


	/*
	 * 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))
		{
462
			elog(ERROR, "RemoveAggregate: type '%s' does not exist", aggType);
463 464 465 466 467 468
		}
	}
	else
	{
		basetypeID = 0;
	}
469 470 471 472

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

491 492
	ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
						   Anum_pg_aggregate_aggname,
B
Bruce Momjian 已提交
493
						   F_NAMEEQ,
494 495 496 497
						   PointerGetDatum(aggName));

	ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
						   Anum_pg_aggregate_aggbasetype,
B
Bruce Momjian 已提交
498
						   F_OIDEQ,
499 500 501
						   ObjectIdGetDatum(basetypeID));

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