]> granicus.if.org Git - postgresql/blob - src/backend/commands/proclang.c
afb61981cecb1e70f31707703b327c0cc20413e2
[postgresql] / src / backend / commands / proclang.c
1 /*-------------------------------------------------------------------------
2  *
3  * proclang.c
4  *        PostgreSQL PROCEDURAL LANGUAGE support code.
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.85 2009/06/11 14:48:56 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
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"
40
41
42 typedef struct
43 {
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 */
49 } PLTemplate;
50
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,
55                                                         Oid newOwnerId);
56
57
58 /* ---------------------------------------------------------------------
59  * CREATE PROCEDURAL LANGUAGE
60  * ---------------------------------------------------------------------
61  */
62 void
63 CreateProceduralLanguage(CreatePLangStmt *stmt)
64 {
65         char       *languageName;
66         PLTemplate *pltemplate;
67         Oid                     handlerOid,
68                                 valOid;
69         Oid                     funcrettype;
70         Oid                     funcargtypes[1];
71
72         /*
73          * Translate the language name and check that this language doesn't
74          * already exist
75          */
76         languageName = case_translate_language_name(stmt->plname);
77
78         if (SearchSysCacheExists(LANGNAME,
79                                                          PointerGetDatum(languageName),
80                                                          0, 0, 0))
81                 ereport(ERROR,
82                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
83                                  errmsg("language \"%s\" already exists", languageName)));
84
85         /*
86          * If we have template information for the language, ignore the supplied
87          * parameters (if any) and use the template information.
88          */
89         if ((pltemplate = find_language_template(languageName)) != NULL)
90         {
91                 List       *funcname;
92
93                 /*
94                  * Give a notice if we are ignoring supplied parameters.
95                  */
96                 if (stmt->plhandler)
97                         ereport(NOTICE,
98                                         (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
99
100                 /*
101                  * Check permission
102                  */
103                 if (!superuser())
104                 {
105                         if (!pltemplate->tmpldbacreate)
106                                 ereport(ERROR,
107                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
108                                                  errmsg("must be superuser to create procedural language \"%s\"",
109                                                                 languageName)));
110                         if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
111                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
112                                                            get_database_name(MyDatabaseId));
113                 }
114
115                 /*
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
118                  * return type.
119                  */
120                 funcname = SystemFuncName(pltemplate->tmplhandler);
121                 handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
122                 if (OidIsValid(handlerOid))
123                 {
124                         funcrettype = get_func_rettype(handlerOid);
125                         if (funcrettype != LANGUAGE_HANDLEROID)
126                                 ereport(ERROR,
127                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
128                                   errmsg("function %s must return type \"language_handler\"",
129                                                  NameListToString(funcname))));
130                 }
131                 else
132                 {
133                         handlerOid = ProcedureCreate(pltemplate->tmplhandler,
134                                                                                  PG_CATALOG_NAMESPACE,
135                                                                                  false, /* replace */
136                                                                                  false, /* returnsSet */
137                                                                                  LANGUAGE_HANDLEROID,
138                                                                                  ClanguageId,
139                                                                                  F_FMGR_C_VALIDATOR,
140                                                                                  pltemplate->tmplhandler,
141                                                                                  pltemplate->tmpllibrary,
142                                                                                  false, /* isAgg */
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),
151                                                                                  NIL,
152                                                                                  PointerGetDatum(NULL),
153                                                                                  1,
154                                                                                  0);
155                 }
156
157                 /*
158                  * Likewise for the validator, if required; but we don't care about
159                  * its return type.
160                  */
161                 if (pltemplate->tmplvalidator)
162                 {
163                         funcname = SystemFuncName(pltemplate->tmplvalidator);
164                         funcargtypes[0] = OIDOID;
165                         valOid = LookupFuncName(funcname, 1, funcargtypes, true);
166                         if (!OidIsValid(valOid))
167                         {
168                                 valOid = ProcedureCreate(pltemplate->tmplvalidator,
169                                                                                  PG_CATALOG_NAMESPACE,
170                                                                                  false, /* replace */
171                                                                                  false, /* returnsSet */
172                                                                                  VOIDOID,
173                                                                                  ClanguageId,
174                                                                                  F_FMGR_C_VALIDATOR,
175                                                                                  pltemplate->tmplvalidator,
176                                                                                  pltemplate->tmpllibrary,
177                                                                                  false, /* isAgg */
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),
186                                                                                  NIL,
187                                                                                  PointerGetDatum(NULL),
188                                                                                  1,
189                                                                                  0);
190                         }
191                 }
192                 else
193                         valOid = InvalidOid;
194
195                 /* ok, create it */
196                 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
197                                                  pltemplate->tmpltrusted);
198         }
199         else
200         {
201                 /*
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.
205                  */
206                 if (!stmt->plhandler)
207                         ereport(ERROR,
208                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
209                                          errmsg("unsupported language \"%s\"",
210                                                         languageName),
211                                          errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
212
213                 /*
214                  * Check permission
215                  */
216                 if (!superuser())
217                         ereport(ERROR,
218                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
219                                          errmsg("must be superuser to create custom procedural language")));
220
221                 /*
222                  * Lookup the PL handler function and check that it is of the expected
223                  * return type
224                  */
225                 handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
226                 funcrettype = get_func_rettype(handlerOid);
227                 if (funcrettype != LANGUAGE_HANDLEROID)
228                 {
229                         /*
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?)
233                          */
234                         if (funcrettype == OPAQUEOID)
235                         {
236                                 ereport(WARNING,
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);
241                         }
242                         else
243                                 ereport(ERROR,
244                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
245                                   errmsg("function %s must return type \"language_handler\"",
246                                                  NameListToString(stmt->plhandler))));
247                 }
248
249                 /* validate the validator function */
250                 if (stmt->plvalidator)
251                 {
252                         funcargtypes[0] = OIDOID;
253                         valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
254                         /* return value is ignored, so we don't check the type */
255                 }
256                 else
257                         valOid = InvalidOid;
258
259                 /* ok, create it */
260                 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
261                                                  stmt->pltrusted);
262         }
263 }
264
265 /*
266  * Guts of language creation.
267  */
268 static void
269 create_proc_lang(const char *languageName,
270                                  Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
271 {
272         Relation        rel;
273         TupleDesc       tupDesc;
274         Datum           values[Natts_pg_language];
275         bool            nulls[Natts_pg_language];
276         NameData        langname;
277         HeapTuple       tup;
278         ObjectAddress myself,
279                                 referenced;
280
281         /*
282          * Insert the new language into pg_language
283          */
284         rel = heap_open(LanguageRelationId, RowExclusiveLock);
285         tupDesc = rel->rd_att;
286
287         memset(values, 0, sizeof(values));
288         memset(nulls, false, sizeof(nulls));
289
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;
298
299         tup = heap_form_tuple(tupDesc, values, nulls);
300
301         simple_heap_insert(rel, tup);
302
303         CatalogUpdateIndexes(rel, tup);
304
305         /*
306          * Create dependencies for language
307          */
308         myself.classId = LanguageRelationId;
309         myself.objectId = HeapTupleGetOid(tup);
310         myself.objectSubId = 0;
311
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);
317
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);
323
324         /* dependency on the validator function, if any */
325         if (OidIsValid(valOid))
326         {
327                 referenced.classId = ProcedureRelationId;
328                 referenced.objectId = valOid;
329                 referenced.objectSubId = 0;
330                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
331         }
332
333         heap_close(rel, RowExclusiveLock);
334 }
335
336 /*
337  * Look to see if we have template information for the given language name.
338  */
339 static PLTemplate *
340 find_language_template(const char *languageName)
341 {
342         PLTemplate *result;
343         Relation        rel;
344         SysScanDesc scan;
345         ScanKeyData key;
346         HeapTuple       tup;
347
348         rel = heap_open(PLTemplateRelationId, AccessShareLock);
349
350         ScanKeyInit(&key,
351                                 Anum_pg_pltemplate_tmplname,
352                                 BTEqualStrategyNumber, F_NAMEEQ,
353                                 NameGetDatum(languageName));
354         scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
355                                                           SnapshotNow, 1, &key);
356
357         tup = systable_getnext(scan);
358         if (HeapTupleIsValid(tup))
359         {
360                 Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
361                 Datum           datum;
362                 bool            isnull;
363
364                 result = (PLTemplate *) palloc0(sizeof(PLTemplate));
365                 result->tmpltrusted = tmpl->tmpltrusted;
366                 result->tmpldbacreate = tmpl->tmpldbacreate;
367
368                 /* Remaining fields are variable-width so we need heap_getattr */
369                 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
370                                                          RelationGetDescr(rel), &isnull);
371                 if (!isnull)
372                         result->tmplhandler = TextDatumGetCString(datum);
373
374                 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
375                                                          RelationGetDescr(rel), &isnull);
376                 if (!isnull)
377                         result->tmplvalidator = TextDatumGetCString(datum);
378
379                 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
380                                                          RelationGetDescr(rel), &isnull);
381                 if (!isnull)
382                         result->tmpllibrary = TextDatumGetCString(datum);
383
384                 /* Ignore template if handler or library info is missing */
385                 if (!result->tmplhandler || !result->tmpllibrary)
386                         result = NULL;
387         }
388         else
389                 result = NULL;
390
391         systable_endscan(scan);
392
393         heap_close(rel, AccessShareLock);
394
395         return result;
396 }
397
398
399 /*
400  * This just returns TRUE if we have a valid template for a given language
401  */
402 bool
403 PLTemplateExists(const char *languageName)
404 {
405         return (find_language_template(languageName) != NULL);
406 }
407
408
409 /* ---------------------------------------------------------------------
410  * DROP PROCEDURAL LANGUAGE
411  * ---------------------------------------------------------------------
412  */
413 void
414 DropProceduralLanguage(DropPLangStmt *stmt)
415 {
416         char       *languageName;
417         HeapTuple       langTup;
418         ObjectAddress object;
419
420         /*
421          * Translate the language name, check that the language exists
422          */
423         languageName = case_translate_language_name(stmt->plname);
424
425         langTup = SearchSysCache(LANGNAME,
426                                                          CStringGetDatum(languageName),
427                                                          0, 0, 0);
428         if (!HeapTupleIsValid(langTup))
429         {
430                 if (!stmt->missing_ok)
431                         ereport(ERROR,
432                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
433                                          errmsg("language \"%s\" does not exist", languageName)));
434                 else
435                         ereport(NOTICE,
436                                         (errmsg("language \"%s\" does not exist, skipping",
437                                                         languageName)));
438
439                 return;
440         }
441
442         /*
443          * Check permission
444          */
445         if (!pg_language_ownercheck(HeapTupleGetOid(langTup), GetUserId()))
446                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
447                                            languageName);
448
449         object.classId = LanguageRelationId;
450         object.objectId = HeapTupleGetOid(langTup);
451         object.objectSubId = 0;
452
453         ReleaseSysCache(langTup);
454
455         /*
456          * Do the deletion
457          */
458         performDeletion(&object, stmt->behavior);
459 }
460
461 /*
462  * Guts of language dropping.
463  */
464 void
465 DropProceduralLanguageById(Oid langOid)
466 {
467         Relation        rel;
468         HeapTuple       langTup;
469
470         rel = heap_open(LanguageRelationId, RowExclusiveLock);
471
472         langTup = SearchSysCache(LANGOID,
473                                                          ObjectIdGetDatum(langOid),
474                                                          0, 0, 0);
475         if (!HeapTupleIsValid(langTup))         /* should not happen */
476                 elog(ERROR, "cache lookup failed for language %u", langOid);
477
478         simple_heap_delete(rel, &langTup->t_self);
479
480         ReleaseSysCache(langTup);
481
482         heap_close(rel, RowExclusiveLock);
483 }
484
485 /*
486  * Rename language
487  */
488 void
489 RenameLanguage(const char *oldname, const char *newname)
490 {
491         HeapTuple       tup;
492         Relation        rel;
493
494         /* Translate both names for consistency with CREATE */
495         oldname = case_translate_language_name(oldname);
496         newname = case_translate_language_name(newname);
497
498         rel = heap_open(LanguageRelationId, RowExclusiveLock);
499
500         tup = SearchSysCacheCopy(LANGNAME,
501                                                          CStringGetDatum(oldname),
502                                                          0, 0, 0);
503         if (!HeapTupleIsValid(tup))
504                 ereport(ERROR,
505                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
506                                  errmsg("language \"%s\" does not exist", oldname)));
507
508         /* make sure the new name doesn't exist */
509         if (SearchSysCacheExists(LANGNAME,
510                                                          CStringGetDatum(newname),
511                                                          0, 0, 0))
512                 ereport(ERROR,
513                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
514                                  errmsg("language \"%s\" already exists", newname)));
515
516         /* must be owner of PL */
517         if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
518                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
519                                            oldname);
520
521         /* rename */
522         namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
523         simple_heap_update(rel, &tup->t_self, tup);
524         CatalogUpdateIndexes(rel, tup);
525
526         heap_close(rel, NoLock);
527         heap_freetuple(tup);
528 }
529
530 /*
531  * Change language owner
532  */
533 void
534 AlterLanguageOwner(const char *name, Oid newOwnerId)
535 {
536         HeapTuple       tup;
537         Relation        rel;
538
539         /* Translate name for consistency with CREATE */
540         name = case_translate_language_name(name);
541
542         rel = heap_open(LanguageRelationId, RowExclusiveLock);
543
544         tup = SearchSysCache(LANGNAME,
545                                                  CStringGetDatum(name),
546                                                  0, 0, 0);
547         if (!HeapTupleIsValid(tup))
548                 ereport(ERROR,
549                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
550                                  errmsg("language \"%s\" does not exist", name)));
551
552         AlterLanguageOwner_internal(tup, rel, newOwnerId);
553
554         ReleaseSysCache(tup);
555
556         heap_close(rel, RowExclusiveLock);
557
558 }
559
560 /*
561  * Change language owner, specified by OID
562  */
563 void
564 AlterLanguageOwner_oid(Oid oid, Oid newOwnerId)
565 {
566         HeapTuple       tup;
567         Relation        rel;
568
569         rel = heap_open(LanguageRelationId, RowExclusiveLock);
570
571         tup = SearchSysCache(LANGOID,
572                                                  ObjectIdGetDatum(oid),
573                                                  0, 0, 0);
574         if (!HeapTupleIsValid(tup))
575                 elog(ERROR, "cache lookup failed for language %u", oid);
576
577         AlterLanguageOwner_internal(tup, rel, newOwnerId);
578
579         ReleaseSysCache(tup);
580
581         heap_close(rel, RowExclusiveLock);
582 }
583
584 /*
585  * Workhorse for AlterLanguageOwner variants
586  */
587 static void
588 AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
589 {
590         Form_pg_language lanForm;
591
592         lanForm = (Form_pg_language) GETSTRUCT(tup);
593
594         /*
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.
597          */
598         if (lanForm->lanowner != newOwnerId)
599         {
600                 Datum           repl_val[Natts_pg_language];
601                 bool            repl_null[Natts_pg_language];
602                 bool            repl_repl[Natts_pg_language];
603                 Acl                *newAcl;
604                 Datum           aclDatum;
605                 bool            isNull;
606                 HeapTuple       newtuple;
607
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));
612
613                 /* Must be able to become new owner */
614                 check_is_member_of_role(GetUserId(), newOwnerId);
615
616                 memset(repl_null, false, sizeof(repl_null));
617                 memset(repl_repl, false, sizeof(repl_repl));
618
619                 repl_repl[Anum_pg_language_lanowner - 1] = true;
620                 repl_val[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(newOwnerId);
621
622                 /*
623                  * Determine the modified ACL for the new owner.  This is only
624                  * necessary when the ACL is non-null.
625                  */
626                 aclDatum = SysCacheGetAttr(LANGNAME, tup,
627                                                                    Anum_pg_language_lanacl,
628                                                                    &isNull);
629                 if (!isNull)
630                 {
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);
635                 }
636
637                 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
638                                                                          repl_val, repl_null, repl_repl);
639
640                 simple_heap_update(rel, &newtuple->t_self, newtuple);
641                 CatalogUpdateIndexes(rel, newtuple);
642
643                 heap_freetuple(newtuple);
644
645                 /* Update owner dependency reference */
646                 changeDependencyOnOwner(LanguageRelationId, HeapTupleGetOid(tup),
647                                                                 newOwnerId);
648         }
649 }