Fix pg_dump bug in the database-level collation patch. "datcollate" and
[PostgreSQL.git] / src / backend / commands / proclang.c
blob1dbe8a7a76900c8463aef48f460bc7f7a4de1981
1 /*-------------------------------------------------------------------------
3 * proclang.c
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
9 * IDENTIFICATION
10 * $PostgreSQL$
12 *-------------------------------------------------------------------------
14 #include "postgres.h"
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"
42 typedef struct
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;
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);
58 /* ---------------------------------------------------------------------
59 * CREATE PROCEDURAL LANGUAGE
60 * ---------------------------------------------------------------------
62 void
63 CreateProceduralLanguage(CreatePLangStmt *stmt)
65 char *languageName;
66 PLTemplate *pltemplate;
67 Oid handlerOid,
68 valOid;
69 Oid funcrettype;
70 Oid funcargtypes[1];
73 * Translate the language name and check that this language doesn't
74 * already exist
76 languageName = case_translate_language_name(stmt->plname);
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)));
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)
91 List *funcname;
94 * Give a notice if we are ignoring supplied parameters.
96 if (stmt->plhandler)
97 ereport(NOTICE,
98 (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
101 * Check permission
103 if (!superuser())
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));
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.
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)
126 ereport(ERROR,
127 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
128 errmsg("function %s must return type \"language_handler\"",
129 NameListToString(funcname))));
131 else
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, /* 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
157 * its return type.
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,
168 false, /* replace */
169 false, /* returnsSet */
170 VOIDOID,
171 ClanguageId,
172 F_FMGR_C_VALIDATOR,
173 pltemplate->tmplvalidator,
174 pltemplate->tmpllibrary,
175 false, /* isAgg */
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),
188 else
189 valOid = InvalidOid;
191 /* ok, create it */
192 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
193 pltemplate->tmpltrusted);
195 else
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)
203 ereport(ERROR,
204 (errcode(ERRCODE_UNDEFINED_OBJECT),
205 errmsg("unsupported language \"%s\"",
206 languageName),
207 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
210 * Check permission
212 if (!superuser())
213 ereport(ERROR,
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
219 * return type
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)
232 ereport(WARNING,
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);
238 else
239 ereport(ERROR,
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 */
252 else
253 valOid = InvalidOid;
255 /* ok, create it */
256 create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
257 stmt->pltrusted);
262 * Guts of language creation.
264 static void
265 create_proc_lang(const char *languageName,
266 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
268 Relation rel;
269 TupleDesc tupDesc;
270 Datum values[Natts_pg_language];
271 char nulls[Natts_pg_language];
272 NameData langname;
273 HeapTuple tup;
274 ObjectAddress myself,
275 referenced;
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.
335 static PLTemplate *
336 find_language_template(const char *languageName)
338 PLTemplate *result;
339 Relation rel;
340 SysScanDesc scan;
341 ScanKeyData key;
342 HeapTuple tup;
344 rel = heap_open(PLTemplateRelationId, AccessShareLock);
346 ScanKeyInit(&key,
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);
357 Datum datum;
358 bool isnull;
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);
367 if (!isnull)
368 result->tmplhandler = TextDatumGetCString(datum);
370 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
371 RelationGetDescr(rel), &isnull);
372 if (!isnull)
373 result->tmplvalidator = TextDatumGetCString(datum);
375 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
376 RelationGetDescr(rel), &isnull);
377 if (!isnull)
378 result->tmpllibrary = TextDatumGetCString(datum);
380 /* Ignore template if handler or library info is missing */
381 if (!result->tmplhandler || !result->tmpllibrary)
382 result = NULL;
384 else
385 result = NULL;
387 systable_endscan(scan);
389 heap_close(rel, AccessShareLock);
391 return result;
396 * This just returns TRUE if we have a valid template for a given language
398 bool
399 PLTemplateExists(const char *languageName)
401 return (find_language_template(languageName) != NULL);
405 /* ---------------------------------------------------------------------
406 * DROP PROCEDURAL LANGUAGE
407 * ---------------------------------------------------------------------
409 void
410 DropProceduralLanguage(DropPLangStmt *stmt)
412 char *languageName;
413 HeapTuple langTup;
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),
423 0, 0, 0);
424 if (!HeapTupleIsValid(langTup))
426 if (!stmt->missing_ok)
427 ereport(ERROR,
428 (errcode(ERRCODE_UNDEFINED_OBJECT),
429 errmsg("language \"%s\" does not exist", languageName)));
430 else
431 ereport(NOTICE,
432 (errmsg("language \"%s\" does not exist, skipping",
433 languageName)));
435 return;
439 * Check permission
441 if (!pg_language_ownercheck(HeapTupleGetOid(langTup), GetUserId()))
442 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
443 languageName);
445 object.classId = LanguageRelationId;
446 object.objectId = HeapTupleGetOid(langTup);
447 object.objectSubId = 0;
449 ReleaseSysCache(langTup);
452 * Do the deletion
454 performDeletion(&object, stmt->behavior);
458 * Guts of language dropping.
460 void
461 DropProceduralLanguageById(Oid langOid)
463 Relation rel;
464 HeapTuple langTup;
466 rel = heap_open(LanguageRelationId, RowExclusiveLock);
468 langTup = SearchSysCache(LANGOID,
469 ObjectIdGetDatum(langOid),
470 0, 0, 0);
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);
482 * Rename language
484 void
485 RenameLanguage(const char *oldname, const char *newname)
487 HeapTuple tup;
488 Relation rel;
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),
498 0, 0, 0);
499 if (!HeapTupleIsValid(tup))
500 ereport(ERROR,
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),
507 0, 0, 0))
508 ereport(ERROR,
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,
515 oldname);
517 /* rename */
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);
523 heap_freetuple(tup);
527 * Change language owner
529 void
530 AlterLanguageOwner(const char *name, Oid newOwnerId)
532 HeapTuple tup;
533 Relation rel;
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),
542 0, 0, 0);
543 if (!HeapTupleIsValid(tup))
544 ereport(ERROR,
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
559 void
560 AlterLanguageOwner_oid(Oid oid, Oid newOwnerId)
562 HeapTuple tup;
563 Relation rel;
565 rel = heap_open(LanguageRelationId, RowExclusiveLock);
567 tup = SearchSysCache(LANGOID,
568 ObjectIdGetDatum(oid),
569 0, 0, 0);
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
583 static void
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];
599 Acl *newAcl;
600 Datum aclDatum;
601 bool isNull;
602 HeapTuple newtuple;
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,
624 &isNull);
625 if (!isNull)
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),
643 newOwnerId);