1 /*-------------------------------------------------------------------------
4 * PostgreSQL PROCEDURAL LANGUAGE support code.
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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, /* security_definer */
144 false, /* isStrict */
145 PROVOLATILE_VOLATILE
,
146 buildoidvector(funcargtypes
, 0),
147 PointerGetDatum(NULL
),
148 PointerGetDatum(NULL
),
149 PointerGetDatum(NULL
),
150 PointerGetDatum(NULL
),
156 * Likewise for the validator, if required; but we don't care about
159 if (pltemplate
->tmplvalidator
)
161 funcname
= SystemFuncName(pltemplate
->tmplvalidator
);
162 funcargtypes
[0] = OIDOID
;
163 valOid
= LookupFuncName(funcname
, 1, funcargtypes
, true);
164 if (!OidIsValid(valOid
))
166 valOid
= ProcedureCreate(pltemplate
->tmplvalidator
,
167 PG_CATALOG_NAMESPACE
,
169 false, /* returnsSet */
173 pltemplate
->tmplvalidator
,
174 pltemplate
->tmpllibrary
,
176 false, /* security_definer */
177 false, /* isStrict */
178 PROVOLATILE_VOLATILE
,
179 buildoidvector(funcargtypes
, 1),
180 PointerGetDatum(NULL
),
181 PointerGetDatum(NULL
),
182 PointerGetDatum(NULL
),
183 PointerGetDatum(NULL
),
192 create_proc_lang(languageName
, GetUserId(), handlerOid
, valOid
,
193 pltemplate
->tmpltrusted
);
198 * No template, so use the provided information. If there's no
199 * handler clause, the user is trying to rely on a template that we
200 * don't have, so complain accordingly.
202 if (!stmt
->plhandler
)
204 (errcode(ERRCODE_UNDEFINED_OBJECT
),
205 errmsg("unsupported language \"%s\"",
207 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
214 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
215 errmsg("must be superuser to create custom procedural language")));
218 * Lookup the PL handler function and check that it is of the expected
221 handlerOid
= LookupFuncName(stmt
->plhandler
, 0, funcargtypes
, false);
222 funcrettype
= get_func_rettype(handlerOid
);
223 if (funcrettype
!= LANGUAGE_HANDLEROID
)
226 * We allow OPAQUE just so we can load old dump files. When we
227 * see a handler function declared OPAQUE, change it to
228 * LANGUAGE_HANDLER. (This is probably obsolete and removable?)
230 if (funcrettype
== OPAQUEOID
)
233 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
234 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
235 NameListToString(stmt
->plhandler
))));
236 SetFunctionReturnType(handlerOid
, LANGUAGE_HANDLEROID
);
240 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
241 errmsg("function %s must return type \"language_handler\"",
242 NameListToString(stmt
->plhandler
))));
245 /* validate the validator function */
246 if (stmt
->plvalidator
)
248 funcargtypes
[0] = OIDOID
;
249 valOid
= LookupFuncName(stmt
->plvalidator
, 1, funcargtypes
, false);
250 /* return value is ignored, so we don't check the type */
256 create_proc_lang(languageName
, GetUserId(), handlerOid
, valOid
,
262 * Guts of language creation.
265 create_proc_lang(const char *languageName
,
266 Oid languageOwner
, Oid handlerOid
, Oid valOid
, bool trusted
)
270 Datum values
[Natts_pg_language
];
271 char nulls
[Natts_pg_language
];
274 ObjectAddress myself
,
278 * Insert the new language into pg_language
280 rel
= heap_open(LanguageRelationId
, RowExclusiveLock
);
281 tupDesc
= rel
->rd_att
;
283 memset(values
, 0, sizeof(values
));
284 memset(nulls
, ' ', sizeof(nulls
));
286 namestrcpy(&langname
, languageName
);
287 values
[Anum_pg_language_lanname
- 1] = NameGetDatum(&langname
);
288 values
[Anum_pg_language_lanowner
- 1] = ObjectIdGetDatum(languageOwner
);
289 values
[Anum_pg_language_lanispl
- 1] = BoolGetDatum(true);
290 values
[Anum_pg_language_lanpltrusted
- 1] = BoolGetDatum(trusted
);
291 values
[Anum_pg_language_lanplcallfoid
- 1] = ObjectIdGetDatum(handlerOid
);
292 values
[Anum_pg_language_lanvalidator
- 1] = ObjectIdGetDatum(valOid
);
293 nulls
[Anum_pg_language_lanacl
- 1] = 'n';
295 tup
= heap_formtuple(tupDesc
, values
, nulls
);
297 simple_heap_insert(rel
, tup
);
299 CatalogUpdateIndexes(rel
, tup
);
302 * Create dependencies for language
304 myself
.classId
= LanguageRelationId
;
305 myself
.objectId
= HeapTupleGetOid(tup
);
306 myself
.objectSubId
= 0;
308 /* dependency on owner of language */
309 referenced
.classId
= AuthIdRelationId
;
310 referenced
.objectId
= languageOwner
;
311 referenced
.objectSubId
= 0;
312 recordSharedDependencyOn(&myself
, &referenced
, SHARED_DEPENDENCY_OWNER
);
314 /* dependency on the PL handler function */
315 referenced
.classId
= ProcedureRelationId
;
316 referenced
.objectId
= handlerOid
;
317 referenced
.objectSubId
= 0;
318 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_NORMAL
);
320 /* dependency on the validator function, if any */
321 if (OidIsValid(valOid
))
323 referenced
.classId
= ProcedureRelationId
;
324 referenced
.objectId
= valOid
;
325 referenced
.objectSubId
= 0;
326 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_NORMAL
);
329 heap_close(rel
, RowExclusiveLock
);
333 * Look to see if we have template information for the given language name.
336 find_language_template(const char *languageName
)
344 rel
= heap_open(PLTemplateRelationId
, AccessShareLock
);
347 Anum_pg_pltemplate_tmplname
,
348 BTEqualStrategyNumber
, F_NAMEEQ
,
349 NameGetDatum(languageName
));
350 scan
= systable_beginscan(rel
, PLTemplateNameIndexId
, true,
351 SnapshotNow
, 1, &key
);
353 tup
= systable_getnext(scan
);
354 if (HeapTupleIsValid(tup
))
356 Form_pg_pltemplate tmpl
= (Form_pg_pltemplate
) GETSTRUCT(tup
);
360 result
= (PLTemplate
*) palloc0(sizeof(PLTemplate
));
361 result
->tmpltrusted
= tmpl
->tmpltrusted
;
362 result
->tmpldbacreate
= tmpl
->tmpldbacreate
;
364 /* Remaining fields are variable-width so we need heap_getattr */
365 datum
= heap_getattr(tup
, Anum_pg_pltemplate_tmplhandler
,
366 RelationGetDescr(rel
), &isnull
);
368 result
->tmplhandler
= TextDatumGetCString(datum
);
370 datum
= heap_getattr(tup
, Anum_pg_pltemplate_tmplvalidator
,
371 RelationGetDescr(rel
), &isnull
);
373 result
->tmplvalidator
= TextDatumGetCString(datum
);
375 datum
= heap_getattr(tup
, Anum_pg_pltemplate_tmpllibrary
,
376 RelationGetDescr(rel
), &isnull
);
378 result
->tmpllibrary
= TextDatumGetCString(datum
);
380 /* Ignore template if handler or library info is missing */
381 if (!result
->tmplhandler
|| !result
->tmpllibrary
)
387 systable_endscan(scan
);
389 heap_close(rel
, AccessShareLock
);
396 * This just returns TRUE if we have a valid template for a given language
399 PLTemplateExists(const char *languageName
)
401 return (find_language_template(languageName
) != NULL
);
405 /* ---------------------------------------------------------------------
406 * DROP PROCEDURAL LANGUAGE
407 * ---------------------------------------------------------------------
410 DropProceduralLanguage(DropPLangStmt
*stmt
)
414 ObjectAddress object
;
417 * Translate the language name, check that the language exists
419 languageName
= case_translate_language_name(stmt
->plname
);
421 langTup
= SearchSysCache(LANGNAME
,
422 CStringGetDatum(languageName
),
424 if (!HeapTupleIsValid(langTup
))
426 if (!stmt
->missing_ok
)
428 (errcode(ERRCODE_UNDEFINED_OBJECT
),
429 errmsg("language \"%s\" does not exist", languageName
)));
432 (errmsg("language \"%s\" does not exist, skipping",
441 if (!pg_language_ownercheck(HeapTupleGetOid(langTup
), GetUserId()))
442 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_LANGUAGE
,
445 object
.classId
= LanguageRelationId
;
446 object
.objectId
= HeapTupleGetOid(langTup
);
447 object
.objectSubId
= 0;
449 ReleaseSysCache(langTup
);
454 performDeletion(&object
, stmt
->behavior
);
458 * Guts of language dropping.
461 DropProceduralLanguageById(Oid langOid
)
466 rel
= heap_open(LanguageRelationId
, RowExclusiveLock
);
468 langTup
= SearchSysCache(LANGOID
,
469 ObjectIdGetDatum(langOid
),
471 if (!HeapTupleIsValid(langTup
)) /* should not happen */
472 elog(ERROR
, "cache lookup failed for language %u", langOid
);
474 simple_heap_delete(rel
, &langTup
->t_self
);
476 ReleaseSysCache(langTup
);
478 heap_close(rel
, RowExclusiveLock
);
485 RenameLanguage(const char *oldname
, const char *newname
)
490 /* Translate both names for consistency with CREATE */
491 oldname
= case_translate_language_name(oldname
);
492 newname
= case_translate_language_name(newname
);
494 rel
= heap_open(LanguageRelationId
, RowExclusiveLock
);
496 tup
= SearchSysCacheCopy(LANGNAME
,
497 CStringGetDatum(oldname
),
499 if (!HeapTupleIsValid(tup
))
501 (errcode(ERRCODE_UNDEFINED_OBJECT
),
502 errmsg("language \"%s\" does not exist", oldname
)));
504 /* make sure the new name doesn't exist */
505 if (SearchSysCacheExists(LANGNAME
,
506 CStringGetDatum(newname
),
509 (errcode(ERRCODE_DUPLICATE_OBJECT
),
510 errmsg("language \"%s\" already exists", newname
)));
512 /* must be owner of PL */
513 if (!pg_language_ownercheck(HeapTupleGetOid(tup
), GetUserId()))
514 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_LANGUAGE
,
518 namestrcpy(&(((Form_pg_language
) GETSTRUCT(tup
))->lanname
), newname
);
519 simple_heap_update(rel
, &tup
->t_self
, tup
);
520 CatalogUpdateIndexes(rel
, tup
);
522 heap_close(rel
, NoLock
);
527 * Change language owner
530 AlterLanguageOwner(const char *name
, Oid newOwnerId
)
535 /* Translate name for consistency with CREATE */
536 name
= case_translate_language_name(name
);
538 rel
= heap_open(LanguageRelationId
, RowExclusiveLock
);
540 tup
= SearchSysCache(LANGNAME
,
541 CStringGetDatum(name
),
543 if (!HeapTupleIsValid(tup
))
545 (errcode(ERRCODE_UNDEFINED_OBJECT
),
546 errmsg("language \"%s\" does not exist", name
)));
548 AlterLanguageOwner_internal(tup
, rel
, newOwnerId
);
550 ReleaseSysCache(tup
);
552 heap_close(rel
, RowExclusiveLock
);
557 * Change language owner, specified by OID
560 AlterLanguageOwner_oid(Oid oid
, Oid newOwnerId
)
565 rel
= heap_open(LanguageRelationId
, RowExclusiveLock
);
567 tup
= SearchSysCache(LANGOID
,
568 ObjectIdGetDatum(oid
),
570 if (!HeapTupleIsValid(tup
))
571 elog(ERROR
, "cache lookup failed for language %u", oid
);
573 AlterLanguageOwner_internal(tup
, rel
, newOwnerId
);
575 ReleaseSysCache(tup
);
577 heap_close(rel
, RowExclusiveLock
);
581 * Workhorse for AlterLanguageOwner variants
584 AlterLanguageOwner_internal(HeapTuple tup
, Relation rel
, Oid newOwnerId
)
586 Form_pg_language lanForm
;
588 lanForm
= (Form_pg_language
) GETSTRUCT(tup
);
591 * If the new owner is the same as the existing owner, consider the
592 * command to have succeeded. This is for dump restoration purposes.
594 if (lanForm
->lanowner
!= newOwnerId
)
596 Datum repl_val
[Natts_pg_language
];
597 char repl_null
[Natts_pg_language
];
598 char repl_repl
[Natts_pg_language
];
604 /* Otherwise, must be owner of the existing object */
605 if (!pg_language_ownercheck(HeapTupleGetOid(tup
), GetUserId()))
606 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_LANGUAGE
,
607 NameStr(lanForm
->lanname
));
609 /* Must be able to become new owner */
610 check_is_member_of_role(GetUserId(), newOwnerId
);
612 memset(repl_null
, ' ', sizeof(repl_null
));
613 memset(repl_repl
, ' ', sizeof(repl_repl
));
615 repl_repl
[Anum_pg_language_lanowner
- 1] = 'r';
616 repl_val
[Anum_pg_language_lanowner
- 1] = ObjectIdGetDatum(newOwnerId
);
619 * Determine the modified ACL for the new owner. This is only
620 * necessary when the ACL is non-null.
622 aclDatum
= SysCacheGetAttr(LANGNAME
, tup
,
623 Anum_pg_language_lanacl
,
627 newAcl
= aclnewowner(DatumGetAclP(aclDatum
),
628 lanForm
->lanowner
, newOwnerId
);
629 repl_repl
[Anum_pg_language_lanacl
- 1] = 'r';
630 repl_val
[Anum_pg_language_lanacl
- 1] = PointerGetDatum(newAcl
);
633 newtuple
= heap_modifytuple(tup
, RelationGetDescr(rel
),
634 repl_val
, repl_null
, repl_repl
);
636 simple_heap_update(rel
, &newtuple
->t_self
, newtuple
);
637 CatalogUpdateIndexes(rel
, newtuple
);
639 heap_freetuple(newtuple
);
641 /* Update owner dependency reference */
642 changeDependencyOnOwner(LanguageRelationId
, HeapTupleGetOid(tup
),