PostgreSQL Source Code  git master
proclang.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * proclang.c
4  * PostgreSQL LANGUAGE support code.
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/commands/proclang.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/table.h"
17 #include "catalog/catalog.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/objectaccess.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_namespace.h"
23 #include "catalog/pg_proc.h"
24 #include "catalog/pg_type.h"
25 #include "commands/defrem.h"
26 #include "commands/proclang.h"
27 #include "miscadmin.h"
28 #include "parser/parse_func.h"
29 #include "utils/builtins.h"
30 #include "utils/lsyscache.h"
31 #include "utils/rel.h"
32 #include "utils/syscache.h"
33 
34 
35 /*
36  * CREATE LANGUAGE
37  */
40 {
41  const char *languageName = stmt->plname;
42  Oid languageOwner = GetUserId();
43  Oid handlerOid,
44  inlineOid,
45  valOid;
46  Oid funcrettype;
47  Oid funcargtypes[1];
48  Relation rel;
49  TupleDesc tupDesc;
50  Datum values[Natts_pg_language];
51  bool nulls[Natts_pg_language];
52  bool replaces[Natts_pg_language];
53  NameData langname;
54  HeapTuple oldtup;
55  HeapTuple tup;
56  Oid langoid;
57  bool is_update;
58  ObjectAddress myself,
59  referenced;
60 
61  /*
62  * Check permission
63  */
64  if (!superuser())
65  ereport(ERROR,
66  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
67  errmsg("must be superuser to create custom procedural language")));
68 
69  /*
70  * Lookup the PL handler function and check that it is of the expected
71  * return type
72  */
73  Assert(stmt->plhandler);
74  handlerOid = LookupFuncName(stmt->plhandler, 0, NULL, false);
75  funcrettype = get_func_rettype(handlerOid);
76  if (funcrettype != LANGUAGE_HANDLEROID)
77  ereport(ERROR,
78  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
79  errmsg("function %s must return type %s",
80  NameListToString(stmt->plhandler), "language_handler")));
81 
82  /* validate the inline function */
83  if (stmt->plinline)
84  {
85  funcargtypes[0] = INTERNALOID;
86  inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
87  /* return value is ignored, so we don't check the type */
88  }
89  else
90  inlineOid = InvalidOid;
91 
92  /* validate the validator function */
93  if (stmt->plvalidator)
94  {
95  funcargtypes[0] = OIDOID;
96  valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
97  /* return value is ignored, so we don't check the type */
98  }
99  else
100  valOid = InvalidOid;
101 
102  /* ok to create it */
103  rel = table_open(LanguageRelationId, RowExclusiveLock);
104  tupDesc = RelationGetDescr(rel);
105 
106  /* Prepare data to be inserted */
107  memset(values, 0, sizeof(values));
108  memset(nulls, false, sizeof(nulls));
109  memset(replaces, true, sizeof(replaces));
110 
111  namestrcpy(&langname, languageName);
112  values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
113  values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
114  values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
115  values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(stmt->pltrusted);
116  values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
117  values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
118  values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
119  nulls[Anum_pg_language_lanacl - 1] = true;
120 
121  /* Check for pre-existing definition */
122  oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
123 
124  if (HeapTupleIsValid(oldtup))
125  {
126  Form_pg_language oldform = (Form_pg_language) GETSTRUCT(oldtup);
127 
128  /* There is one; okay to replace it? */
129  if (!stmt->replace)
130  ereport(ERROR,
132  errmsg("language \"%s\" already exists", languageName)));
133 
134  /* This is currently pointless, since we already checked superuser */
135 #ifdef NOT_USED
136  if (!pg_language_ownercheck(oldform->oid, languageOwner))
138  languageName);
139 #endif
140 
141  /*
142  * Do not change existing oid, ownership or permissions. Note
143  * dependency-update code below has to agree with this decision.
144  */
145  replaces[Anum_pg_language_oid - 1] = false;
146  replaces[Anum_pg_language_lanowner - 1] = false;
147  replaces[Anum_pg_language_lanacl - 1] = false;
148 
149  /* Okay, do it... */
150  tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
151  CatalogTupleUpdate(rel, &tup->t_self, tup);
152 
153  langoid = oldform->oid;
154  ReleaseSysCache(oldtup);
155  is_update = true;
156  }
157  else
158  {
159  /* Creating a new language */
160  langoid = GetNewOidWithIndex(rel, LanguageOidIndexId,
161  Anum_pg_language_oid);
162  values[Anum_pg_language_oid - 1] = ObjectIdGetDatum(langoid);
163  tup = heap_form_tuple(tupDesc, values, nulls);
164  CatalogTupleInsert(rel, tup);
165  is_update = false;
166  }
167 
168  /*
169  * Create dependencies for the new language. If we are updating an
170  * existing language, first delete any existing pg_depend entries.
171  * (However, since we are not changing ownership or permissions, the
172  * shared dependencies do *not* need to change, and we leave them alone.)
173  */
174  myself.classId = LanguageRelationId;
175  myself.objectId = langoid;
176  myself.objectSubId = 0;
177 
178  if (is_update)
179  deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
180 
181  /* dependency on owner of language */
182  if (!is_update)
184  languageOwner);
185 
186  /* dependency on extension */
187  recordDependencyOnCurrentExtension(&myself, is_update);
188 
189  /* dependency on the PL handler function */
190  referenced.classId = ProcedureRelationId;
191  referenced.objectId = handlerOid;
192  referenced.objectSubId = 0;
193  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
194 
195  /* dependency on the inline handler function, if any */
196  if (OidIsValid(inlineOid))
197  {
198  referenced.classId = ProcedureRelationId;
199  referenced.objectId = inlineOid;
200  referenced.objectSubId = 0;
201  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
202  }
203 
204  /* dependency on the validator function, if any */
205  if (OidIsValid(valOid))
206  {
207  referenced.classId = ProcedureRelationId;
208  referenced.objectId = valOid;
209  referenced.objectSubId = 0;
210  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
211  }
212 
213  /* Post creation hook for new procedural language */
214  InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
215 
217 
218  return myself;
219 }
220 
221 /*
222  * Guts of language dropping.
223  */
224 void
226 {
227  Relation rel;
228  HeapTuple langTup;
229 
230  rel = table_open(LanguageRelationId, RowExclusiveLock);
231 
232  langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
233  if (!HeapTupleIsValid(langTup)) /* should not happen */
234  elog(ERROR, "cache lookup failed for language %u", langOid);
235 
236  CatalogTupleDelete(rel, &langTup->t_self);
237 
238  ReleaseSysCache(langTup);
239 
241 }
242 
243 /*
244  * get_language_oid - given a language name, look up the OID
245  *
246  * If missing_ok is false, throw an error if language name not found. If
247  * true, just return InvalidOid.
248  */
249 Oid
250 get_language_oid(const char *langname, bool missing_ok)
251 {
252  Oid oid;
253 
254  oid = GetSysCacheOid1(LANGNAME, Anum_pg_language_oid,
255  CStringGetDatum(langname));
256  if (!OidIsValid(oid) && !missing_ok)
257  ereport(ERROR,
258  (errcode(ERRCODE_UNDEFINED_OBJECT),
259  errmsg("language \"%s\" does not exist", langname)));
260  return oid;
261 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:448
bool pg_language_ownercheck(Oid lan_oid, Oid roleid)
Definition: aclchk.c:4824
#define PointerGetDatum(X)
Definition: postgres.h:556
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:192
void DropProceduralLanguageById(Oid langOid)
Definition: proclang.c:225
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:190
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:250
int errcode(int sqlerrcode)
Definition: elog.c:610
ObjectAddress CreateProceduralLanguage(CreatePLangStmt *stmt)
Definition: proclang.c:39
bool superuser(void)
Definition: superuser.c:46
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:609
#define RowExclusiveLock
Definition: lockdefs.h:38
struct statement * stmt
#define CStringGetDatum(X)
Definition: postgres.h:578
List * plvalidator
Definition: parsenodes.h:2486
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define LanguageOidIndexId
Definition: indexing.h:181
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static Datum values[MAXATTR]
Definition: bootstrap.c:167
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183