aggregatecmds.c 5.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*-------------------------------------------------------------------------
 *
 * aggregatecmds.c
 *
 *	  Routines for aggregate-manipulation commands
 *
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
12
 *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.3 2002/07/12 18:43:15 tgl Exp $
13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * DESCRIPTION
 *	  The "DefineFoo" routines take the parse tree and pick out the
 *	  appropriate arguments/flags, passing the results to the
 *	  corresponding "FooDefine" routines (in src/catalog) that do
 *	  the actual catalog-munging.  These routines also verify permission
 *	  of the user to execute the command.
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/heapam.h"
#include "catalog/catname.h"
27
#include "catalog/dependency.h"
28 29
#include "catalog/namespace.h"
#include "catalog/pg_aggregate.h"
30
#include "catalog/pg_proc.h"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"


/*
 *	DefineAggregate
 */
void
DefineAggregate(List *names, List *parameters)
{
	char	   *aggName;
	Oid			aggNamespace;
49
	AclResult	aclresult;
50 51 52 53 54 55 56 57 58 59 60 61
	List	   *transfuncName = NIL;
	List	   *finalfuncName = NIL;
	TypeName   *baseType = NULL;
	TypeName   *transType = NULL;
	char	   *initval = NULL;
	Oid			baseTypeId;
	Oid			transTypeId;
	List	   *pl;

	/* Convert list of names to a name and namespace */
	aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName);

62 63 64 65 66
	/* Check we have creation rights in target namespace */
	aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, get_namespace_name(aggNamespace));

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 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 140 141 142 143
	foreach(pl, parameters)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);

		/*
		 * sfunc1, stype1, and initcond1 are accepted as obsolete
		 * spellings for sfunc, stype, initcond.
		 */
		if (strcasecmp(defel->defname, "sfunc") == 0)
			transfuncName = defGetQualifiedName(defel);
		else if (strcasecmp(defel->defname, "sfunc1") == 0)
			transfuncName = defGetQualifiedName(defel);
		else if (strcasecmp(defel->defname, "finalfunc") == 0)
			finalfuncName = defGetQualifiedName(defel);
		else if (strcasecmp(defel->defname, "basetype") == 0)
			baseType = defGetTypeName(defel);
		else if (strcasecmp(defel->defname, "stype") == 0)
			transType = defGetTypeName(defel);
		else if (strcasecmp(defel->defname, "stype1") == 0)
			transType = defGetTypeName(defel);
		else if (strcasecmp(defel->defname, "initcond") == 0)
			initval = defGetString(defel);
		else if (strcasecmp(defel->defname, "initcond1") == 0)
			initval = defGetString(defel);
		else
			elog(WARNING, "DefineAggregate: attribute \"%s\" not recognized",
				 defel->defname);
	}

	/*
	 * make sure we have our required definitions
	 */
	if (baseType == NULL)
		elog(ERROR, "Define: \"basetype\" unspecified");
	if (transType == NULL)
		elog(ERROR, "Define: \"stype\" unspecified");
	if (transfuncName == NIL)
		elog(ERROR, "Define: \"sfunc\" unspecified");

	/*
	 * Handle the aggregate's base type (input data type).  This can be
	 * specified as 'ANY' for a data-independent transition function, such
	 * as COUNT(*).
	 */
	baseTypeId = LookupTypeName(baseType);
	if (OidIsValid(baseTypeId))
	{
		/* no need to allow aggregates on as-yet-undefined types */
		if (!get_typisdefined(baseTypeId))
			elog(ERROR, "Type \"%s\" is only a shell",
				 TypeNameToString(baseType));
	}
	else
	{
		char      *typnam = TypeNameToString(baseType);

		if (strcasecmp(typnam, "ANY") != 0)
			elog(ERROR, "Type \"%s\" does not exist", typnam);
		baseTypeId = InvalidOid;
	}

	/* handle transtype --- no special cases here */
	transTypeId = typenameTypeId(transType);

	/*
	 * Most of the argument-checking is done inside of AggregateCreate
	 */
	AggregateCreate(aggName,	/* aggregate name */
					aggNamespace,	/* namespace */
					transfuncName,		/* step function name */
					finalfuncName,		/* final function name */
					baseTypeId,	/* type of data being aggregated */
					transTypeId,	/* transition data type */
					initval);	/* initial condition */
}


144 145 146 147
/*
 * RemoveAggregate
 *		Deletes an aggregate.
 */
148
void
149
RemoveAggregate(RemoveAggrStmt *stmt)
150
{
151 152
	List	   *aggName = stmt->aggname;
	TypeName   *aggType = stmt->aggtype;
153 154
	Oid			basetypeID;
	Oid			procOid;
155 156
	HeapTuple	tup;
	ObjectAddress object;
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

	/*
	 * 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 (eg, COUNT).
	 */
	if (aggType)
		basetypeID = typenameTypeId(aggType);
	else
		basetypeID = InvalidOid;

	procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);

173 174 175
	/*
	 * Find the function tuple, do permissions and validity checks
	 */
176 177 178 179 180 181 182
	tup = SearchSysCache(PROCOID,
						 ObjectIdGetDatum(procOid),
						 0, 0, 0);
	if (!HeapTupleIsValid(tup))	/* should not happen */
		elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
			 NameListToString(aggName));

183 184 185 186 187 188
	/* Permission check: must own agg or its namespace */
	if (!pg_proc_ownercheck(procOid, GetUserId()) &&
		!pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,
								 GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(aggName));

189
	/* find_aggregate_func already checked it is an aggregate */
190 191 192

	ReleaseSysCache(tup);

193 194 195 196 197 198
	/*
	 * Do the deletion
	 */
	object.classId = RelOid_pg_proc;
	object.objectId = procOid;
	object.objectSubId = 0;
199

200
	performDeletion(&object, stmt->behavior);
201
}