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-2024, 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_proc.h"
23 #include "catalog/pg_type.h"
24 #include "commands/proclang.h"
25 #include "miscadmin.h"
26 #include "parser/parse_func.h"
27 #include "utils/builtins.h"
28 #include "utils/lsyscache.h"
29 #include "utils/rel.h"
30 #include "utils/syscache.h"
31 
32 
33 /*
34  * CREATE LANGUAGE
35  */
38 {
39  const char *languageName = stmt->plname;
40  Oid languageOwner = GetUserId();
41  Oid handlerOid,
42  inlineOid,
43  valOid;
44  Oid funcrettype;
45  Oid funcargtypes[1];
46  Relation rel;
47  TupleDesc tupDesc;
48  Datum values[Natts_pg_language];
49  bool nulls[Natts_pg_language];
50  bool replaces[Natts_pg_language];
51  NameData langname;
52  HeapTuple oldtup;
53  HeapTuple tup;
54  Oid langoid;
55  bool is_update;
56  ObjectAddress myself,
57  referenced;
58  ObjectAddresses *addrs;
59 
60  /*
61  * Check permission
62  */
63  if (!superuser())
64  ereport(ERROR,
65  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
66  errmsg("must be superuser to create custom procedural language")));
67 
68  /*
69  * Lookup the PL handler function and check that it is of the expected
70  * return type
71  */
72  Assert(stmt->plhandler);
73  handlerOid = LookupFuncName(stmt->plhandler, 0, NULL, false);
74  funcrettype = get_func_rettype(handlerOid);
75  if (funcrettype != LANGUAGE_HANDLEROID)
76  ereport(ERROR,
77  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
78  errmsg("function %s must return type %s",
79  NameListToString(stmt->plhandler), "language_handler")));
80 
81  /* validate the inline function */
82  if (stmt->plinline)
83  {
84  funcargtypes[0] = INTERNALOID;
85  inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
86  /* return value is ignored, so we don't check the type */
87  }
88  else
89  inlineOid = InvalidOid;
90 
91  /* validate the validator function */
92  if (stmt->plvalidator)
93  {
94  funcargtypes[0] = OIDOID;
95  valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
96  /* return value is ignored, so we don't check the type */
97  }
98  else
99  valOid = InvalidOid;
100 
101  /* ok to create it */
102  rel = table_open(LanguageRelationId, RowExclusiveLock);
103  tupDesc = RelationGetDescr(rel);
104 
105  /* Prepare data to be inserted */
106  memset(values, 0, sizeof(values));
107  memset(nulls, false, sizeof(nulls));
108  memset(replaces, true, sizeof(replaces));
109 
110  namestrcpy(&langname, languageName);
111  values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
112  values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
113  values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
114  values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(stmt->pltrusted);
115  values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
116  values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
117  values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
118  nulls[Anum_pg_language_lanacl - 1] = true;
119 
120  /* Check for pre-existing definition */
121  oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
122 
123  if (HeapTupleIsValid(oldtup))
124  {
125  Form_pg_language oldform = (Form_pg_language) GETSTRUCT(oldtup);
126 
127  /* There is one; okay to replace it? */
128  if (!stmt->replace)
129  ereport(ERROR,
131  errmsg("language \"%s\" already exists", languageName)));
132 
133  /* This is currently pointless, since we already checked superuser */
134 #ifdef NOT_USED
135  if (!object_ownercheck(LanguageRelationId, oldform->oid, languageOwner))
137  languageName);
138 #endif
139 
140  /*
141  * Do not change existing oid, ownership or permissions. Note
142  * dependency-update code below has to agree with this decision.
143  */
144  replaces[Anum_pg_language_oid - 1] = false;
145  replaces[Anum_pg_language_lanowner - 1] = false;
146  replaces[Anum_pg_language_lanacl - 1] = false;
147 
148  /* Okay, do it... */
149  tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
150  CatalogTupleUpdate(rel, &tup->t_self, tup);
151 
152  langoid = oldform->oid;
153  ReleaseSysCache(oldtup);
154  is_update = true;
155  }
156  else
157  {
158  /* Creating a new language */
159  langoid = GetNewOidWithIndex(rel, LanguageOidIndexId,
160  Anum_pg_language_oid);
161  values[Anum_pg_language_oid - 1] = ObjectIdGetDatum(langoid);
162  tup = heap_form_tuple(tupDesc, values, nulls);
163  CatalogTupleInsert(rel, tup);
164  is_update = false;
165  }
166 
167  /*
168  * Create dependencies for the new language. If we are updating an
169  * existing language, first delete any existing pg_depend entries.
170  * (However, since we are not changing ownership or permissions, the
171  * shared dependencies do *not* need to change, and we leave them alone.)
172  */
173  myself.classId = LanguageRelationId;
174  myself.objectId = langoid;
175  myself.objectSubId = 0;
176 
177  if (is_update)
178  deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
179 
180  /* dependency on owner of language */
181  if (!is_update)
183  languageOwner);
184 
185  /* dependency on extension */
186  recordDependencyOnCurrentExtension(&myself, is_update);
187 
188  addrs = new_object_addresses();
189 
190  /* dependency on the PL handler function */
191  ObjectAddressSet(referenced, ProcedureRelationId, handlerOid);
192  add_exact_object_address(&referenced, addrs);
193 
194  /* dependency on the inline handler function, if any */
195  if (OidIsValid(inlineOid))
196  {
197  ObjectAddressSet(referenced, ProcedureRelationId, inlineOid);
198  add_exact_object_address(&referenced, addrs);
199  }
200 
201  /* dependency on the validator function, if any */
202  if (OidIsValid(valOid))
203  {
204  ObjectAddressSet(referenced, ProcedureRelationId, valOid);
205  add_exact_object_address(&referenced, addrs);
206  }
207 
209  free_object_addresses(addrs);
210 
211  /* Post creation hook for new procedural language */
212  InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
213 
215 
216  return myself;
217 }
218 
219 /*
220  * get_language_oid - given a language name, look up the OID
221  *
222  * If missing_ok is false, throw an error if language name not found. If
223  * true, just return InvalidOid.
224  */
225 Oid
226 get_language_oid(const char *langname, bool missing_ok)
227 {
228  Oid oid;
229 
230  oid = GetSysCacheOid1(LANGNAME, Anum_pg_language_oid,
231  CStringGetDatum(langname));
232  if (!OidIsValid(oid) && !missing_ok)
233  ereport(ERROR,
234  (errcode(ERRCODE_UNDEFINED_OBJECT),
235  errmsg("language \"%s\" does not exist", langname)));
236  return oid;
237 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2688
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2740
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
Oid GetUserId(void)
Definition: miscinit.c:514
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char * NameListToString(const List *names)
Definition: namespace.c:3579
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2143
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2284
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:160
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:226
ObjectAddress CreateProceduralLanguage(CreatePLangStmt *stmt)
Definition: proclang.c:37
#define RelationGetDescr(relation)
Definition: rel.h:531
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:741
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:104
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40