1 /*-------------------------------------------------------------------------
4 * PostgreSQL PROCEDURAL LANGUAGE support code.
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.85 2009/06/11 14:48:56 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_authid.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_namespace.h"
23 #include "catalog/pg_pltemplate.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_proc_fn.h"
26 #include "catalog/pg_type.h"
27 #include "commands/dbcommands.h"
28 #include "commands/defrem.h"
29 #include "commands/proclang.h"
30 #include "miscadmin.h"
31 #include "parser/gramparse.h"
32 #include "parser/parse_func.h"
33 #include "utils/acl.h"
34 #include "utils/builtins.h"
35 #include "utils/fmgroids.h"
36 #include "utils/lsyscache.h"
37 #include "utils/rel.h"
38 #include "utils/syscache.h"
39 #include "utils/tqual.h"
44 bool tmpltrusted; /* trusted? */
45 bool tmpldbacreate; /* db owner allowed to create? */
46 char *tmplhandler; /* name of handler function */
47 char *tmplvalidator; /* name of validator function, or NULL */
48 char *tmpllibrary; /* path of shared library */
51 static void create_proc_lang(const char *languageName,
52 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted);
53 static PLTemplate *find_language_template(const char *languageName);
54 static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
58 /* ---------------------------------------------------------------------
59 * CREATE PROCEDURAL LANGUAGE
60 * ---------------------------------------------------------------------
63 CreateProceduralLanguage(CreatePLangStmt *stmt)
66 PLTemplate *pltemplate;
73 * Translate the language name and check that this language doesn't
76 languageName = case_translate_language_name(stmt->plname);
78 if (SearchSysCacheExists(LANGNAME,
79 PointerGetDatum(languageName),
82 (errcode(ERRCODE_DUPLICATE_OBJECT),
83 errmsg("language \"%s\" already exists", languageName)));
86 * If we have template information for the language, ignore the supplied
87 * parameters (if any) and use the template information.
89 if ((pltemplate = find_language_template(languageName)) != NULL)
94 * Give a notice if we are ignoring supplied parameters.
98 (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
105 if (!pltemplate->tmpldbacreate)
107 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
108 errmsg("must be superuser to create procedural language \"%s\"",
110 if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
111 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
112 get_database_name(MyDatabaseId));
116 * Find or create the handler function, which we force to be in the
117 * pg_catalog schema. If already present, it must have the correct
120 funcname = SystemFuncName(pltemplate->tmplhandler);
121 handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
122 if (OidIsValid(handlerOid))
124 funcrettype = get_func_rettype(handlerOid);
125 if (funcrettype != LANGUAGE_HANDLEROID)
127 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
128 errmsg("function %s must return type \"language_handler\"",
129 NameListToString(funcname))));
133 handlerOid = ProcedureCreate(pltemplate->tmplhandler,
134 PG_CATALOG_NAMESPACE,
136 false, /* returnsSet */
140 pltemplate->tmplhandler,
141 pltemplate->tmpllibrary,
143 false, /* isWindowFunc */
144 false, /* security_definer */
145 false, /* isStrict */
146 PROVOLATILE_VOLATILE,
147 buildoidvector(funcargtypes, 0),
148 PointerGetDatum(NULL),
149 PointerGetDatum(NULL),
150 PointerGetDatum(NULL),
152 PointerGetDatum(NULL),
158 * Likewise for the validator, if required; but we don't care about
161 if (pltemplate->tmplvalidator)
163 funcname = SystemFuncName(pltemplate->tmplvalidator);
164 funcargtypes[0] = OIDOID;
165 valOid = LookupFuncName(funcname, 1, funcargtypes, true);
166 if (!OidIsValid(valOid))
168 valOid = ProcedureCreate(pltemplate->tmplvalidator,
169 PG_CATALOG_NAMESPACE,
171 false, /* returnsSet */
175 pltemplate->tmplvalidator,
176 pltemplate->tmpllibrary,
178 false, /* isWindowFunc */
179 false, /* security_definer */
180 false, /* isStrict */
181 PROVOLATILE_VOLATILE,
182 buildoidvector(funcargtypes, 1),
183 PointerGetDatum(NULL),
184 PointerGetDatum(NULL),
185 PointerGetDatum(NULL),
187 PointerGetDatum(NULL),
196 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
197 pltemplate->tmpltrusted);
202 * No template, so use the provided information. If there's no
203 * handler clause, the user is trying to rely on a template that we
204 * don't have, so complain accordingly.
206 if (!stmt->plhandler)
208 (errcode(ERRCODE_UNDEFINED_OBJECT),
209 errmsg("unsupported language \"%s\"",
211 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
218 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
219 errmsg("must be superuser to create custom procedural language")));
222 * Lookup the PL handler function and check that it is of the expected
225 handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
226 funcrettype = get_func_rettype(handlerOid);
227 if (funcrettype != LANGUAGE_HANDLEROID)
230 * We allow OPAQUE just so we can load old dump files. When we
231 * see a handler function declared OPAQUE, change it to
232 * LANGUAGE_HANDLER. (This is probably obsolete and removable?)
234 if (funcrettype == OPAQUEOID)
237 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
238 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
239 NameListToString(stmt->plhandler))));
240 SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
244 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
245 errmsg("function %s must return type \"language_handler\"",
246 NameListToString(stmt->plhandler))));
249 /* validate the validator function */
250 if (stmt->plvalidator)
252 funcargtypes[0] = OIDOID;
253 valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
254 /* return value is ignored, so we don't check the type */
260 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
266 * Guts of language creation.
269 create_proc_lang(const char *languageName,
270 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
274 Datum values[Natts_pg_language];
275 bool nulls[Natts_pg_language];
278 ObjectAddress myself,
282 * Insert the new language into pg_language
284 rel = heap_open(LanguageRelationId, RowExclusiveLock);
285 tupDesc = rel->rd_att;
287 memset(values, 0, sizeof(values));
288 memset(nulls, false, sizeof(nulls));
290 namestrcpy(&langname, languageName);
291 values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
292 values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
293 values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
294 values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
295 values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
296 values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
297 nulls[Anum_pg_language_lanacl - 1] = true;
299 tup = heap_form_tuple(tupDesc, values, nulls);
301 simple_heap_insert(rel, tup);
303 CatalogUpdateIndexes(rel, tup);
306 * Create dependencies for language
308 myself.classId = LanguageRelationId;
309 myself.objectId = HeapTupleGetOid(tup);
310 myself.objectSubId = 0;
312 /* dependency on owner of language */
313 referenced.classId = AuthIdRelationId;
314 referenced.objectId = languageOwner;
315 referenced.objectSubId = 0;
316 recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
318 /* dependency on the PL handler function */
319 referenced.classId = ProcedureRelationId;
320 referenced.objectId = handlerOid;
321 referenced.objectSubId = 0;
322 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
324 /* dependency on the validator function, if any */
325 if (OidIsValid(valOid))
327 referenced.classId = ProcedureRelationId;
328 referenced.objectId = valOid;
329 referenced.objectSubId = 0;
330 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
333 heap_close(rel, RowExclusiveLock);
337 * Look to see if we have template information for the given language name.
340 find_language_template(const char *languageName)
348 rel = heap_open(PLTemplateRelationId, AccessShareLock);
351 Anum_pg_pltemplate_tmplname,
352 BTEqualStrategyNumber, F_NAMEEQ,
353 NameGetDatum(languageName));
354 scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
355 SnapshotNow, 1, &key);
357 tup = systable_getnext(scan);
358 if (HeapTupleIsValid(tup))
360 Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
364 result = (PLTemplate *) palloc0(sizeof(PLTemplate));
365 result->tmpltrusted = tmpl->tmpltrusted;
366 result->tmpldbacreate = tmpl->tmpldbacreate;
368 /* Remaining fields are variable-width so we need heap_getattr */
369 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
370 RelationGetDescr(rel), &isnull);
372 result->tmplhandler = TextDatumGetCString(datum);
374 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
375 RelationGetDescr(rel), &isnull);
377 result->tmplvalidator = TextDatumGetCString(datum);
379 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
380 RelationGetDescr(rel), &isnull);
382 result->tmpllibrary = TextDatumGetCString(datum);
384 /* Ignore template if handler or library info is missing */
385 if (!result->tmplhandler || !result->tmpllibrary)
391 systable_endscan(scan);
393 heap_close(rel, AccessShareLock);
400 * This just returns TRUE if we have a valid template for a given language
403 PLTemplateExists(const char *languageName)
405 return (find_language_template(languageName) != NULL);
409 /* ---------------------------------------------------------------------
410 * DROP PROCEDURAL LANGUAGE
411 * ---------------------------------------------------------------------
414 DropProceduralLanguage(DropPLangStmt *stmt)
418 ObjectAddress object;
421 * Translate the language name, check that the language exists
423 languageName = case_translate_language_name(stmt->plname);
425 langTup = SearchSysCache(LANGNAME,
426 CStringGetDatum(languageName),
428 if (!HeapTupleIsValid(langTup))
430 if (!stmt->missing_ok)
432 (errcode(ERRCODE_UNDEFINED_OBJECT),
433 errmsg("language \"%s\" does not exist", languageName)));
436 (errmsg("language \"%s\" does not exist, skipping",
445 if (!pg_language_ownercheck(HeapTupleGetOid(langTup), GetUserId()))
446 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
449 object.classId = LanguageRelationId;
450 object.objectId = HeapTupleGetOid(langTup);
451 object.objectSubId = 0;
453 ReleaseSysCache(langTup);
458 performDeletion(&object, stmt->behavior);
462 * Guts of language dropping.
465 DropProceduralLanguageById(Oid langOid)
470 rel = heap_open(LanguageRelationId, RowExclusiveLock);
472 langTup = SearchSysCache(LANGOID,
473 ObjectIdGetDatum(langOid),
475 if (!HeapTupleIsValid(langTup)) /* should not happen */
476 elog(ERROR, "cache lookup failed for language %u", langOid);
478 simple_heap_delete(rel, &langTup->t_self);
480 ReleaseSysCache(langTup);
482 heap_close(rel, RowExclusiveLock);
489 RenameLanguage(const char *oldname, const char *newname)
494 /* Translate both names for consistency with CREATE */
495 oldname = case_translate_language_name(oldname);
496 newname = case_translate_language_name(newname);
498 rel = heap_open(LanguageRelationId, RowExclusiveLock);
500 tup = SearchSysCacheCopy(LANGNAME,
501 CStringGetDatum(oldname),
503 if (!HeapTupleIsValid(tup))
505 (errcode(ERRCODE_UNDEFINED_OBJECT),
506 errmsg("language \"%s\" does not exist", oldname)));
508 /* make sure the new name doesn't exist */
509 if (SearchSysCacheExists(LANGNAME,
510 CStringGetDatum(newname),
513 (errcode(ERRCODE_DUPLICATE_OBJECT),
514 errmsg("language \"%s\" already exists", newname)));
516 /* must be owner of PL */
517 if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
518 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
522 namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
523 simple_heap_update(rel, &tup->t_self, tup);
524 CatalogUpdateIndexes(rel, tup);
526 heap_close(rel, NoLock);
531 * Change language owner
534 AlterLanguageOwner(const char *name, Oid newOwnerId)
539 /* Translate name for consistency with CREATE */
540 name = case_translate_language_name(name);
542 rel = heap_open(LanguageRelationId, RowExclusiveLock);
544 tup = SearchSysCache(LANGNAME,
545 CStringGetDatum(name),
547 if (!HeapTupleIsValid(tup))
549 (errcode(ERRCODE_UNDEFINED_OBJECT),
550 errmsg("language \"%s\" does not exist", name)));
552 AlterLanguageOwner_internal(tup, rel, newOwnerId);
554 ReleaseSysCache(tup);
556 heap_close(rel, RowExclusiveLock);
561 * Change language owner, specified by OID
564 AlterLanguageOwner_oid(Oid oid, Oid newOwnerId)
569 rel = heap_open(LanguageRelationId, RowExclusiveLock);
571 tup = SearchSysCache(LANGOID,
572 ObjectIdGetDatum(oid),
574 if (!HeapTupleIsValid(tup))
575 elog(ERROR, "cache lookup failed for language %u", oid);
577 AlterLanguageOwner_internal(tup, rel, newOwnerId);
579 ReleaseSysCache(tup);
581 heap_close(rel, RowExclusiveLock);
585 * Workhorse for AlterLanguageOwner variants
588 AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
590 Form_pg_language lanForm;
592 lanForm = (Form_pg_language) GETSTRUCT(tup);
595 * If the new owner is the same as the existing owner, consider the
596 * command to have succeeded. This is for dump restoration purposes.
598 if (lanForm->lanowner != newOwnerId)
600 Datum repl_val[Natts_pg_language];
601 bool repl_null[Natts_pg_language];
602 bool repl_repl[Natts_pg_language];
608 /* Otherwise, must be owner of the existing object */
609 if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
610 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
611 NameStr(lanForm->lanname));
613 /* Must be able to become new owner */
614 check_is_member_of_role(GetUserId(), newOwnerId);
616 memset(repl_null, false, sizeof(repl_null));
617 memset(repl_repl, false, sizeof(repl_repl));
619 repl_repl[Anum_pg_language_lanowner - 1] = true;
620 repl_val[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(newOwnerId);
623 * Determine the modified ACL for the new owner. This is only
624 * necessary when the ACL is non-null.
626 aclDatum = SysCacheGetAttr(LANGNAME, tup,
627 Anum_pg_language_lanacl,
631 newAcl = aclnewowner(DatumGetAclP(aclDatum),
632 lanForm->lanowner, newOwnerId);
633 repl_repl[Anum_pg_language_lanacl - 1] = true;
634 repl_val[Anum_pg_language_lanacl - 1] = PointerGetDatum(newAcl);
637 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
638 repl_val, repl_null, repl_repl);
640 simple_heap_update(rel, &newtuple->t_self, newtuple);
641 CatalogUpdateIndexes(rel, newtuple);
643 heap_freetuple(newtuple);
645 /* Update owner dependency reference */
646 changeDependencyOnOwner(LanguageRelationId, HeapTupleGetOid(tup),