1 /*-------------------------------------------------------------------------
4 * PostgreSQL PROCEDURAL LANGUAGE support code.
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/commands/proclang.c
12 *-------------------------------------------------------------------------
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "access/htup_details.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/objectaccess.h"
22 #include "catalog/pg_authid.h"
23 #include "catalog/pg_language.h"
24 #include "catalog/pg_namespace.h"
25 #include "catalog/pg_pltemplate.h"
26 #include "catalog/pg_proc.h"
27 #include "catalog/pg_proc_fn.h"
28 #include "catalog/pg_type.h"
29 #include "commands/dbcommands.h"
30 #include "commands/defrem.h"
31 #include "commands/proclang.h"
32 #include "miscadmin.h"
33 #include "parser/parse_func.h"
34 #include "parser/parser.h"
35 #include "utils/acl.h"
36 #include "utils/builtins.h"
37 #include "utils/fmgroids.h"
38 #include "utils/lsyscache.h"
39 #include "utils/rel.h"
40 #include "utils/syscache.h"
41 #include "utils/tqual.h"
46 bool tmpltrusted; /* trusted? */
47 bool tmpldbacreate; /* db owner allowed to create? */
48 char *tmplhandler; /* name of handler function */
49 char *tmplinline; /* name of anonymous-block handler, or NULL */
50 char *tmplvalidator; /* name of validator function, or NULL */
51 char *tmpllibrary; /* path of shared library */
54 static ObjectAddress create_proc_lang(const char *languageName, bool replace,
55 Oid languageOwner, Oid handlerOid, Oid inlineOid,
56 Oid valOid, bool trusted);
57 static PLTemplate *find_language_template(const char *languageName);
59 /* ---------------------------------------------------------------------
60 * CREATE PROCEDURAL LANGUAGE
61 * ---------------------------------------------------------------------
64 CreateProceduralLanguage(CreatePLangStmt *stmt)
66 PLTemplate *pltemplate;
67 ObjectAddress tmpAddr;
75 * If we have template information for the language, ignore the supplied
76 * parameters (if any) and use the template information.
78 if ((pltemplate = find_language_template(stmt->plname)) != NULL)
83 * Give a notice if we are ignoring supplied parameters.
87 (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
94 if (!pltemplate->tmpldbacreate)
96 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
97 errmsg("must be superuser to create procedural language \"%s\"",
99 if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
100 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
101 get_database_name(MyDatabaseId));
105 * Find or create the handler function, which we force to be in the
106 * pg_catalog schema. If already present, it must have the correct
109 funcname = SystemFuncName(pltemplate->tmplhandler);
110 handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
111 if (OidIsValid(handlerOid))
113 funcrettype = get_func_rettype(handlerOid);
114 if (funcrettype != LANGUAGE_HANDLEROID)
116 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
117 errmsg("function %s must return type %s",
118 NameListToString(funcname), "language_handler")));
122 tmpAddr = ProcedureCreate(pltemplate->tmplhandler,
123 PG_CATALOG_NAMESPACE,
125 false, /* returnsSet */
127 BOOTSTRAP_SUPERUSERID,
130 pltemplate->tmplhandler,
131 pltemplate->tmpllibrary,
133 false, /* isWindowFunc */
134 false, /* security_definer */
135 false, /* isLeakProof */
136 false, /* isStrict */
137 PROVOLATILE_VOLATILE,
139 buildoidvector(funcargtypes, 0),
140 PointerGetDatum(NULL),
141 PointerGetDatum(NULL),
142 PointerGetDatum(NULL),
144 PointerGetDatum(NULL),
145 PointerGetDatum(NULL),
148 handlerOid = tmpAddr.objectId;
152 * Likewise for the anonymous block handler, if required; but we don't
153 * care about its return type.
155 if (pltemplate->tmplinline)
157 funcname = SystemFuncName(pltemplate->tmplinline);
158 funcargtypes[0] = INTERNALOID;
159 inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
160 if (!OidIsValid(inlineOid))
162 tmpAddr = ProcedureCreate(pltemplate->tmplinline,
163 PG_CATALOG_NAMESPACE,
165 false, /* returnsSet */
167 BOOTSTRAP_SUPERUSERID,
170 pltemplate->tmplinline,
171 pltemplate->tmpllibrary,
173 false, /* isWindowFunc */
174 false, /* security_definer */
175 false, /* isLeakProof */
177 PROVOLATILE_VOLATILE,
179 buildoidvector(funcargtypes, 1),
180 PointerGetDatum(NULL),
181 PointerGetDatum(NULL),
182 PointerGetDatum(NULL),
184 PointerGetDatum(NULL),
185 PointerGetDatum(NULL),
188 inlineOid = tmpAddr.objectId;
192 inlineOid = InvalidOid;
195 * Likewise for the validator, if required; but we don't care about
198 if (pltemplate->tmplvalidator)
200 funcname = SystemFuncName(pltemplate->tmplvalidator);
201 funcargtypes[0] = OIDOID;
202 valOid = LookupFuncName(funcname, 1, funcargtypes, true);
203 if (!OidIsValid(valOid))
205 tmpAddr = ProcedureCreate(pltemplate->tmplvalidator,
206 PG_CATALOG_NAMESPACE,
208 false, /* returnsSet */
210 BOOTSTRAP_SUPERUSERID,
213 pltemplate->tmplvalidator,
214 pltemplate->tmpllibrary,
216 false, /* isWindowFunc */
217 false, /* security_definer */
218 false, /* isLeakProof */
220 PROVOLATILE_VOLATILE,
222 buildoidvector(funcargtypes, 1),
223 PointerGetDatum(NULL),
224 PointerGetDatum(NULL),
225 PointerGetDatum(NULL),
227 PointerGetDatum(NULL),
228 PointerGetDatum(NULL),
231 valOid = tmpAddr.objectId;
238 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
239 handlerOid, inlineOid,
240 valOid, pltemplate->tmpltrusted);
245 * No template, so use the provided information. If there's no
246 * handler clause, the user is trying to rely on a template that we
247 * don't have, so complain accordingly.
249 if (!stmt->plhandler)
251 (errcode(ERRCODE_UNDEFINED_OBJECT),
252 errmsg("unsupported language \"%s\"",
254 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
261 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
262 errmsg("must be superuser to create custom procedural language")));
265 * Lookup the PL handler function and check that it is of the expected
268 handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
269 funcrettype = get_func_rettype(handlerOid);
270 if (funcrettype != LANGUAGE_HANDLEROID)
273 * We allow OPAQUE just so we can load old dump files. When we
274 * see a handler function declared OPAQUE, change it to
275 * LANGUAGE_HANDLER. (This is probably obsolete and removable?)
277 if (funcrettype == OPAQUEOID)
280 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
281 errmsg("changing return type of function %s from %s to %s",
282 NameListToString(stmt->plhandler),
283 "opaque", "language_handler")));
284 SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
288 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
289 errmsg("function %s must return type %s",
290 NameListToString(stmt->plhandler), "language_handler")));
293 /* validate the inline function */
296 funcargtypes[0] = INTERNALOID;
297 inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
298 /* return value is ignored, so we don't check the type */
301 inlineOid = InvalidOid;
303 /* validate the validator function */
304 if (stmt->plvalidator)
306 funcargtypes[0] = OIDOID;
307 valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
308 /* return value is ignored, so we don't check the type */
314 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
315 handlerOid, inlineOid,
316 valOid, stmt->pltrusted);
321 * Guts of language creation.
324 create_proc_lang(const char *languageName, bool replace,
325 Oid languageOwner, Oid handlerOid, Oid inlineOid,
326 Oid valOid, bool trusted)
330 Datum values[Natts_pg_language];
331 bool nulls[Natts_pg_language];
332 bool replaces[Natts_pg_language];
337 ObjectAddress myself,
340 rel = heap_open(LanguageRelationId, RowExclusiveLock);
341 tupDesc = RelationGetDescr(rel);
343 /* Prepare data to be inserted */
344 memset(values, 0, sizeof(values));
345 memset(nulls, false, sizeof(nulls));
346 memset(replaces, true, sizeof(replaces));
348 namestrcpy(&langname, languageName);
349 values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
350 values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
351 values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
352 values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
353 values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
354 values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
355 values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
356 nulls[Anum_pg_language_lanacl - 1] = true;
358 /* Check for pre-existing definition */
359 oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
361 if (HeapTupleIsValid(oldtup))
363 /* There is one; okay to replace it? */
366 (errcode(ERRCODE_DUPLICATE_OBJECT),
367 errmsg("language \"%s\" already exists", languageName)));
368 if (!pg_language_ownercheck(HeapTupleGetOid(oldtup), languageOwner))
369 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
373 * Do not change existing ownership or permissions. Note
374 * dependency-update code below has to agree with this decision.
376 replaces[Anum_pg_language_lanowner - 1] = false;
377 replaces[Anum_pg_language_lanacl - 1] = false;
380 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
381 CatalogTupleUpdate(rel, &tup->t_self, tup);
383 ReleaseSysCache(oldtup);
388 /* Creating a new language */
389 tup = heap_form_tuple(tupDesc, values, nulls);
390 CatalogTupleInsert(rel, tup);
395 * Create dependencies for the new language. If we are updating an
396 * existing language, first delete any existing pg_depend entries.
397 * (However, since we are not changing ownership or permissions, the
398 * shared dependencies do *not* need to change, and we leave them alone.)
400 myself.classId = LanguageRelationId;
401 myself.objectId = HeapTupleGetOid(tup);
402 myself.objectSubId = 0;
405 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
407 /* dependency on owner of language */
409 recordDependencyOnOwner(myself.classId, myself.objectId,
412 /* dependency on extension */
413 recordDependencyOnCurrentExtension(&myself, is_update);
415 /* dependency on the PL handler function */
416 referenced.classId = ProcedureRelationId;
417 referenced.objectId = handlerOid;
418 referenced.objectSubId = 0;
419 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
421 /* dependency on the inline handler function, if any */
422 if (OidIsValid(inlineOid))
424 referenced.classId = ProcedureRelationId;
425 referenced.objectId = inlineOid;
426 referenced.objectSubId = 0;
427 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
430 /* dependency on the validator function, if any */
431 if (OidIsValid(valOid))
433 referenced.classId = ProcedureRelationId;
434 referenced.objectId = valOid;
435 referenced.objectSubId = 0;
436 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
439 /* Post creation hook for new procedural language */
440 InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
442 heap_close(rel, RowExclusiveLock);
448 * Look to see if we have template information for the given language name.
451 find_language_template(const char *languageName)
459 rel = heap_open(PLTemplateRelationId, AccessShareLock);
462 Anum_pg_pltemplate_tmplname,
463 BTEqualStrategyNumber, F_NAMEEQ,
464 CStringGetDatum(languageName));
465 scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
468 tup = systable_getnext(scan);
469 if (HeapTupleIsValid(tup))
471 Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
475 result = (PLTemplate *) palloc0(sizeof(PLTemplate));
476 result->tmpltrusted = tmpl->tmpltrusted;
477 result->tmpldbacreate = tmpl->tmpldbacreate;
479 /* Remaining fields are variable-width so we need heap_getattr */
480 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
481 RelationGetDescr(rel), &isnull);
483 result->tmplhandler = TextDatumGetCString(datum);
485 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
486 RelationGetDescr(rel), &isnull);
488 result->tmplinline = TextDatumGetCString(datum);
490 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
491 RelationGetDescr(rel), &isnull);
493 result->tmplvalidator = TextDatumGetCString(datum);
495 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
496 RelationGetDescr(rel), &isnull);
498 result->tmpllibrary = TextDatumGetCString(datum);
500 /* Ignore template if handler or library info is missing */
501 if (!result->tmplhandler || !result->tmpllibrary)
507 systable_endscan(scan);
509 heap_close(rel, AccessShareLock);
516 * This just returns TRUE if we have a valid template for a given language
519 PLTemplateExists(const char *languageName)
521 return (find_language_template(languageName) != NULL);
525 * Guts of language dropping.
528 DropProceduralLanguageById(Oid langOid)
533 rel = heap_open(LanguageRelationId, RowExclusiveLock);
535 langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
536 if (!HeapTupleIsValid(langTup)) /* should not happen */
537 elog(ERROR, "cache lookup failed for language %u", langOid);
539 CatalogTupleDelete(rel, &langTup->t_self);
541 ReleaseSysCache(langTup);
543 heap_close(rel, RowExclusiveLock);
547 * get_language_oid - given a language name, look up the OID
549 * If missing_ok is false, throw an error if language name not found. If
550 * true, just return InvalidOid.
553 get_language_oid(const char *langname, bool missing_ok)
557 oid = GetSysCacheOid1(LANGNAME, CStringGetDatum(langname));
558 if (!OidIsValid(oid) && !missing_ok)
560 (errcode(ERRCODE_UNDEFINED_OBJECT),
561 errmsg("language \"%s\" does not exist", langname)));