1 /*-------------------------------------------------------------------------
4 * PostgreSQL LANGUAGE support code.
6 * Portions Copyright (c) 1996-2019, 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/htup_details.h"
18 #include "access/table.h"
19 #include "catalog/catalog.h"
20 #include "catalog/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/objectaccess.h"
23 #include "catalog/pg_authid.h"
24 #include "catalog/pg_language.h"
25 #include "catalog/pg_namespace.h"
26 #include "catalog/pg_pltemplate.h"
27 #include "catalog/pg_proc.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"
45 bool tmpltrusted; /* trusted? */
46 bool tmpldbacreate; /* db owner allowed to create? */
47 char *tmplhandler; /* name of handler function */
48 char *tmplinline; /* name of anonymous-block handler, or NULL */
49 char *tmplvalidator; /* name of validator function, or NULL */
50 char *tmpllibrary; /* path of shared library */
53 static ObjectAddress create_proc_lang(const char *languageName, bool replace,
54 Oid languageOwner, Oid handlerOid, Oid inlineOid,
55 Oid valOid, bool trusted);
56 static PLTemplate *find_language_template(const char *languageName);
62 CreateProceduralLanguage(CreatePLangStmt *stmt)
64 PLTemplate *pltemplate;
65 ObjectAddress tmpAddr;
73 * If we have template information for the language, ignore the supplied
74 * parameters (if any) and use the template information.
76 if ((pltemplate = find_language_template(stmt->plname)) != NULL)
81 * Give a notice if we are ignoring supplied parameters.
85 (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
92 if (!pltemplate->tmpldbacreate)
94 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95 errmsg("must be superuser to create procedural language \"%s\"",
97 if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
98 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
99 get_database_name(MyDatabaseId));
103 * Find or create the handler function, which we force to be in the
104 * pg_catalog schema. If already present, it must have the correct
107 funcname = SystemFuncName(pltemplate->tmplhandler);
108 handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
109 if (OidIsValid(handlerOid))
111 funcrettype = get_func_rettype(handlerOid);
112 if (funcrettype != LANGUAGE_HANDLEROID)
114 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
115 errmsg("function %s must return type %s",
116 NameListToString(funcname), "language_handler")));
120 tmpAddr = ProcedureCreate(pltemplate->tmplhandler,
121 PG_CATALOG_NAMESPACE,
123 false, /* returnsSet */
125 BOOTSTRAP_SUPERUSERID,
128 pltemplate->tmplhandler,
129 pltemplate->tmpllibrary,
131 false, /* security_definer */
132 false, /* isLeakProof */
133 false, /* isStrict */
134 PROVOLATILE_VOLATILE,
136 buildoidvector(funcargtypes, 0),
137 PointerGetDatum(NULL),
138 PointerGetDatum(NULL),
139 PointerGetDatum(NULL),
141 PointerGetDatum(NULL),
142 PointerGetDatum(NULL),
146 handlerOid = tmpAddr.objectId;
150 * Likewise for the anonymous block handler, if required; but we don't
151 * care about its return type.
153 if (pltemplate->tmplinline)
155 funcname = SystemFuncName(pltemplate->tmplinline);
156 funcargtypes[0] = INTERNALOID;
157 inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
158 if (!OidIsValid(inlineOid))
160 tmpAddr = ProcedureCreate(pltemplate->tmplinline,
161 PG_CATALOG_NAMESPACE,
163 false, /* returnsSet */
165 BOOTSTRAP_SUPERUSERID,
168 pltemplate->tmplinline,
169 pltemplate->tmpllibrary,
171 false, /* security_definer */
172 false, /* isLeakProof */
174 PROVOLATILE_VOLATILE,
176 buildoidvector(funcargtypes, 1),
177 PointerGetDatum(NULL),
178 PointerGetDatum(NULL),
179 PointerGetDatum(NULL),
181 PointerGetDatum(NULL),
182 PointerGetDatum(NULL),
186 inlineOid = tmpAddr.objectId;
190 inlineOid = InvalidOid;
193 * Likewise for the validator, if required; but we don't care about
196 if (pltemplate->tmplvalidator)
198 funcname = SystemFuncName(pltemplate->tmplvalidator);
199 funcargtypes[0] = OIDOID;
200 valOid = LookupFuncName(funcname, 1, funcargtypes, true);
201 if (!OidIsValid(valOid))
203 tmpAddr = ProcedureCreate(pltemplate->tmplvalidator,
204 PG_CATALOG_NAMESPACE,
206 false, /* returnsSet */
208 BOOTSTRAP_SUPERUSERID,
211 pltemplate->tmplvalidator,
212 pltemplate->tmpllibrary,
214 false, /* security_definer */
215 false, /* isLeakProof */
217 PROVOLATILE_VOLATILE,
219 buildoidvector(funcargtypes, 1),
220 PointerGetDatum(NULL),
221 PointerGetDatum(NULL),
222 PointerGetDatum(NULL),
224 PointerGetDatum(NULL),
225 PointerGetDatum(NULL),
229 valOid = tmpAddr.objectId;
236 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
237 handlerOid, inlineOid,
238 valOid, pltemplate->tmpltrusted);
243 * No template, so use the provided information. If there's no
244 * handler clause, the user is trying to rely on a template that we
245 * don't have, so complain accordingly.
247 if (!stmt->plhandler)
249 (errcode(ERRCODE_UNDEFINED_OBJECT),
250 errmsg("unsupported language \"%s\"",
252 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
259 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
260 errmsg("must be superuser to create custom procedural language")));
263 * Lookup the PL handler function and check that it is of the expected
266 handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
267 funcrettype = get_func_rettype(handlerOid);
268 if (funcrettype != LANGUAGE_HANDLEROID)
271 * We allow OPAQUE just so we can load old dump files. When we
272 * see a handler function declared OPAQUE, change it to
273 * LANGUAGE_HANDLER. (This is probably obsolete and removable?)
275 if (funcrettype == OPAQUEOID)
278 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
279 errmsg("changing return type of function %s from %s to %s",
280 NameListToString(stmt->plhandler),
281 "opaque", "language_handler")));
282 SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
286 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
287 errmsg("function %s must return type %s",
288 NameListToString(stmt->plhandler), "language_handler")));
291 /* validate the inline function */
294 funcargtypes[0] = INTERNALOID;
295 inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
296 /* return value is ignored, so we don't check the type */
299 inlineOid = InvalidOid;
301 /* validate the validator function */
302 if (stmt->plvalidator)
304 funcargtypes[0] = OIDOID;
305 valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
306 /* return value is ignored, so we don't check the type */
312 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
313 handlerOid, inlineOid,
314 valOid, stmt->pltrusted);
319 * Guts of language creation.
322 create_proc_lang(const char *languageName, bool replace,
323 Oid languageOwner, Oid handlerOid, Oid inlineOid,
324 Oid valOid, bool trusted)
328 Datum values[Natts_pg_language];
329 bool nulls[Natts_pg_language];
330 bool replaces[Natts_pg_language];
336 ObjectAddress myself,
339 rel = table_open(LanguageRelationId, RowExclusiveLock);
340 tupDesc = RelationGetDescr(rel);
342 /* Prepare data to be inserted */
343 memset(values, 0, sizeof(values));
344 memset(nulls, false, sizeof(nulls));
345 memset(replaces, true, sizeof(replaces));
347 namestrcpy(&langname, languageName);
348 values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
349 values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
350 values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
351 values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
352 values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
353 values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
354 values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
355 nulls[Anum_pg_language_lanacl - 1] = true;
357 /* Check for pre-existing definition */
358 oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
360 if (HeapTupleIsValid(oldtup))
362 Form_pg_language oldform = (Form_pg_language) GETSTRUCT(oldtup);
364 /* There is one; okay to replace it? */
367 (errcode(ERRCODE_DUPLICATE_OBJECT),
368 errmsg("language \"%s\" already exists", languageName)));
369 if (!pg_language_ownercheck(oldform->oid, languageOwner))
370 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_LANGUAGE,
374 * Do not change existing oid, ownership or permissions. Note
375 * dependency-update code below has to agree with this decision.
377 replaces[Anum_pg_language_oid - 1] = false;
378 replaces[Anum_pg_language_lanowner - 1] = false;
379 replaces[Anum_pg_language_lanacl - 1] = false;
382 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
383 CatalogTupleUpdate(rel, &tup->t_self, tup);
385 langoid = oldform->oid;
386 ReleaseSysCache(oldtup);
391 /* Creating a new language */
392 langoid = GetNewOidWithIndex(rel, LanguageOidIndexId,
393 Anum_pg_language_oid);
394 values[Anum_pg_language_oid - 1] = ObjectIdGetDatum(langoid);
395 tup = heap_form_tuple(tupDesc, values, nulls);
396 CatalogTupleInsert(rel, tup);
401 * Create dependencies for the new language. If we are updating an
402 * existing language, first delete any existing pg_depend entries.
403 * (However, since we are not changing ownership or permissions, the
404 * shared dependencies do *not* need to change, and we leave them alone.)
406 myself.classId = LanguageRelationId;
407 myself.objectId = langoid;
408 myself.objectSubId = 0;
411 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
413 /* dependency on owner of language */
415 recordDependencyOnOwner(myself.classId, myself.objectId,
418 /* dependency on extension */
419 recordDependencyOnCurrentExtension(&myself, is_update);
421 /* dependency on the PL handler function */
422 referenced.classId = ProcedureRelationId;
423 referenced.objectId = handlerOid;
424 referenced.objectSubId = 0;
425 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
427 /* dependency on the inline handler function, if any */
428 if (OidIsValid(inlineOid))
430 referenced.classId = ProcedureRelationId;
431 referenced.objectId = inlineOid;
432 referenced.objectSubId = 0;
433 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
436 /* dependency on the validator function, if any */
437 if (OidIsValid(valOid))
439 referenced.classId = ProcedureRelationId;
440 referenced.objectId = valOid;
441 referenced.objectSubId = 0;
442 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
445 /* Post creation hook for new procedural language */
446 InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
448 table_close(rel, RowExclusiveLock);
454 * Look to see if we have template information for the given language name.
457 find_language_template(const char *languageName)
465 rel = table_open(PLTemplateRelationId, AccessShareLock);
468 Anum_pg_pltemplate_tmplname,
469 BTEqualStrategyNumber, F_NAMEEQ,
470 CStringGetDatum(languageName));
471 scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
474 tup = systable_getnext(scan);
475 if (HeapTupleIsValid(tup))
477 Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
481 result = (PLTemplate *) palloc0(sizeof(PLTemplate));
482 result->tmpltrusted = tmpl->tmpltrusted;
483 result->tmpldbacreate = tmpl->tmpldbacreate;
485 /* Remaining fields are variable-width so we need heap_getattr */
486 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
487 RelationGetDescr(rel), &isnull);
489 result->tmplhandler = TextDatumGetCString(datum);
491 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
492 RelationGetDescr(rel), &isnull);
494 result->tmplinline = TextDatumGetCString(datum);
496 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
497 RelationGetDescr(rel), &isnull);
499 result->tmplvalidator = TextDatumGetCString(datum);
501 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
502 RelationGetDescr(rel), &isnull);
504 result->tmpllibrary = TextDatumGetCString(datum);
506 /* Ignore template if handler or library info is missing */
507 if (!result->tmplhandler || !result->tmpllibrary)
513 systable_endscan(scan);
515 table_close(rel, AccessShareLock);
522 * This just returns true if we have a valid template for a given language
525 PLTemplateExists(const char *languageName)
527 return (find_language_template(languageName) != NULL);
531 * Guts of language dropping.
534 DropProceduralLanguageById(Oid langOid)
539 rel = table_open(LanguageRelationId, RowExclusiveLock);
541 langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
542 if (!HeapTupleIsValid(langTup)) /* should not happen */
543 elog(ERROR, "cache lookup failed for language %u", langOid);
545 CatalogTupleDelete(rel, &langTup->t_self);
547 ReleaseSysCache(langTup);
549 table_close(rel, RowExclusiveLock);
553 * get_language_oid - given a language name, look up the OID
555 * If missing_ok is false, throw an error if language name not found. If
556 * true, just return InvalidOid.
559 get_language_oid(const char *langname, bool missing_ok)
563 oid = GetSysCacheOid1(LANGNAME, Anum_pg_language_oid,
564 CStringGetDatum(langname));
565 if (!OidIsValid(oid) && !missing_ok)
567 (errcode(ERRCODE_UNDEFINED_OBJECT),
568 errmsg("language \"%s\" does not exist", langname)));