proclang.c 7.11 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * proclang.c
4 5
 *	  PostgreSQL PROCEDURAL LANGUAGE support code.
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 8 9
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
10
 *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.53 2004/02/21 00:34:52 tgl Exp $
11
 *
12 13 14 15
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

16 17
#include <ctype.h>

18 19
#include "access/heapam.h"
#include "catalog/catname.h"
20
#include "catalog/dependency.h"
21
#include "catalog/indexing.h"
22
#include "catalog/namespace.h"
23
#include "catalog/pg_language.h"
Bruce Momjian's avatar
Bruce Momjian committed
24
#include "catalog/pg_proc.h"
25
#include "catalog/pg_type.h"
26
#include "commands/proclang.h"
27
#include "commands/defrem.h"
28
#include "fmgr.h"
29
#include "miscadmin.h"
30
#include "parser/parse_func.h"
31
#include "utils/builtins.h"
32
#include "utils/lsyscache.h"
Bruce Momjian's avatar
Bruce Momjian committed
33
#include "utils/syscache.h"
34 35 36 37 38 39 40


/* ---------------------------------------------------------------------
 * CREATE PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
41
CreateProceduralLanguage(CreatePLangStmt *stmt)
42
{
43
	char	   *languageName;
Bruce Momjian's avatar
Bruce Momjian committed
44 45
	Oid			procOid,
				valProcOid;
46
	Oid			funcrettype;
47
	Oid			typev[FUNC_MAX_ARGS];
48
	NameData	langname;
49 50
	char		nulls[Natts_pg_language];
	Datum		values[Natts_pg_language];
51
	Relation	rel;
52 53 54
	HeapTuple	tup;
	TupleDesc	tupDesc;
	int			i;
Bruce Momjian's avatar
Bruce Momjian committed
55 56
	ObjectAddress myself,
				referenced;
57

58
	/*
59 60 61
	 * Check permission
	 */
	if (!superuser())
62 63
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
Bruce Momjian's avatar
Bruce Momjian committed
64
			 errmsg("must be superuser to create procedural language")));
65

66 67 68
	/*
	 * Translate the language name and check that this language doesn't
	 * already exist
69
	 */
70
	languageName = case_translate_language_name(stmt->plname);
71

72 73 74
	if (SearchSysCacheExists(LANGNAME,
							 PointerGetDatum(languageName),
							 0, 0, 0))
75 76 77
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("language \"%s\" already exists", languageName)));
78

79
	/*
80 81
	 * Lookup the PL handler function and check that it is of the expected
	 * return type
82
	 */
83
	MemSet(typev, 0, sizeof(typev));
84
	procOid = LookupFuncName(stmt->plhandler, 0, typev, false);
85 86 87 88
	funcrettype = get_func_rettype(procOid);
	if (funcrettype != LANGUAGE_HANDLEROID)
	{
		/*
Bruce Momjian's avatar
Bruce Momjian committed
89
		 * We allow OPAQUE just so we can load old dump files.	When we
90 91 92 93 94
		 * see a handler function declared OPAQUE, change it to
		 * LANGUAGE_HANDLER.
		 */
		if (funcrettype == OPAQUEOID)
		{
95
			ereport(WARNING,
96
					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
97
					 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
98
							NameListToString(stmt->plhandler))));
99 100 101
			SetFunctionReturnType(procOid, LANGUAGE_HANDLEROID);
		}
		else
102 103
			ereport(ERROR,
					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
104
					 errmsg("function %s must return type \"language_handler\"",
105
							NameListToString(stmt->plhandler))));
106
	}
107

108 109 110 111
	/* validate the validator function */
	if (stmt->plvalidator)
	{
		typev[0] = OIDOID;
112
		valProcOid = LookupFuncName(stmt->plvalidator, 1, typev, false);
113
		/* return value is ignored, so we don't check the type */
114 115
	}
	else
116
		valProcOid = InvalidOid;
117

118
	/*
119 120 121 122 123 124 125 126 127
	 * Insert the new language into pg_language
	 */
	for (i = 0; i < Natts_pg_language; i++)
	{
		nulls[i] = ' ';
		values[i] = (Datum) NULL;
	}

	i = 0;
128 129 130 131 132 133 134
	namestrcpy(&langname, languageName);
	values[i++] = NameGetDatum(&langname);			/* lanname */
	values[i++] = BoolGetDatum(true);				/* lanispl */
	values[i++] = BoolGetDatum(stmt->pltrusted);	/* lanpltrusted */
	values[i++] = ObjectIdGetDatum(procOid);		/* lanplcallfoid */
	values[i++] = ObjectIdGetDatum(valProcOid);		/* lanvalidator */
	nulls[i] = 'n';									/* lanacl */
135

136
	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
137

138
	tupDesc = rel->rd_att;
139 140
	tup = heap_formtuple(tupDesc, values, nulls);

141
	simple_heap_insert(rel, tup);
142

143
	CatalogUpdateIndexes(rel, tup);
144

145 146 147 148
	/*
	 * Create dependencies for language
	 */
	myself.classId = RelationGetRelid(rel);
149
	myself.objectId = HeapTupleGetOid(tup);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
	myself.objectSubId = 0;

	/* dependency on the PL handler function */
	referenced.classId = RelOid_pg_proc;
	referenced.objectId = procOid;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on the validator function, if any */
	if (OidIsValid(valProcOid))
	{
		referenced.classId = RelOid_pg_proc;
		referenced.objectId = valProcOid;
		referenced.objectSubId = 0;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}

167
	heap_close(rel, RowExclusiveLock);
168 169 170 171 172 173 174 175
}


/* ---------------------------------------------------------------------
 * DROP PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
176
DropProceduralLanguage(DropPLangStmt *stmt)
177
{
178
	char	   *languageName;
179
	HeapTuple	langTup;
180
	ObjectAddress object;
181

182
	/*
183 184 185
	 * Check permission
	 */
	if (!superuser())
186 187
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
Bruce Momjian's avatar
Bruce Momjian committed
188
			   errmsg("must be superuser to drop procedural language")));
189

190 191 192
	/*
	 * Translate the language name, check that this language exist and is
	 * a PL
193
	 */
194
	languageName = case_translate_language_name(stmt->plname);
195

196 197 198
	langTup = SearchSysCache(LANGNAME,
							 CStringGetDatum(languageName),
							 0, 0, 0);
199
	if (!HeapTupleIsValid(langTup))
200 201 202
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("language \"%s\" does not exist", languageName)));
203

204
	object.classId = get_system_catalog_relid(LanguageRelationName);
205
	object.objectId = HeapTupleGetOid(langTup);
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	object.objectSubId = 0;

	ReleaseSysCache(langTup);

	/*
	 * Do the deletion
	 */
	performDeletion(&object, stmt->behavior);
}

/*
 * Guts of language dropping.
 */
void
DropProceduralLanguageById(Oid langOid)
{
	Relation	rel;
	HeapTuple	langTup;

	rel = heap_openr(LanguageRelationName, RowExclusiveLock);

	langTup = SearchSysCache(LANGOID,
							 ObjectIdGetDatum(langOid),
							 0, 0, 0);
Bruce Momjian's avatar
Bruce Momjian committed
230
	if (!HeapTupleIsValid(langTup))		/* should not happen */
231
		elog(ERROR, "cache lookup failed for language %u", langOid);
232

233
	simple_heap_delete(rel, &langTup->t_self);
234

235 236
	ReleaseSysCache(langTup);

237
	heap_close(rel, RowExclusiveLock);
238
}
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

/*
 * Rename language
 */
void
RenameLanguage(const char *oldname, const char *newname)
{
	HeapTuple	tup;
	Relation	rel;

	rel = heap_openr(ShadowRelationName, RowExclusiveLock);

	tup = SearchSysCacheCopy(LANGNAME,
							 CStringGetDatum(oldname),
							 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
256
				(errcode(ERRCODE_UNDEFINED_OBJECT),
257 258 259 260 261 262 263
				 errmsg("language \"%s\" does not exist", oldname)));

	/* make sure the new name doesn't exist */
	if (SearchSysCacheExists(LANGNAME,
							 CStringGetDatum(newname),
							 0, 0, 0))
		ereport(ERROR,
264
				(errcode(ERRCODE_DUPLICATE_OBJECT),
265 266 267 268 269
				 errmsg("language \"%s\" already exists", newname)));

	/* must be superuser */
	if (!superuser())
		ereport(ERROR,
270
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
Bruce Momjian's avatar
Bruce Momjian committed
271
			 errmsg("must be superuser to rename procedural language")));
272 273 274 275 276 277 278 279 280

	/* rename */
	namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
	simple_heap_update(rel, &tup->t_self, tup);
	CatalogUpdateIndexes(rel, tup);

	heap_close(rel, NoLock);
	heap_freetuple(tup);
}