mirror of https://github.com/postgres/postgres
parent
9db2992640
commit
7bff4c5078
@ -0,0 +1,205 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* proclang.c-- |
||||
* PostgreSQL PROCEDURAL LANGUAGE support code. |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
#include "postgres.h" |
||||
|
||||
#include "access/heapam.h" |
||||
#include "catalog/catname.h" |
||||
#include "catalog/pg_user.h" |
||||
#include "catalog/pg_proc.h" |
||||
#include "catalog/pg_language.h" |
||||
#include "utils/syscache.h" |
||||
#include "commands/proclang.h" |
||||
#include "fmgr.h" |
||||
|
||||
|
||||
static void |
||||
case_translate_language_name(const char *input, char *output) |
||||
{ |
||||
/*-------------------------------------------------------------------------
|
||||
Translate the input language name to lower case, except if it's C, |
||||
translate to upper case. |
||||
--------------------------------------------------------------------------*/ |
||||
int i; |
||||
|
||||
for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i) |
||||
output[i] = tolower(input[i]); |
||||
|
||||
output[i] = '\0'; |
||||
|
||||
if (strcmp(output, "c") == 0) |
||||
output[0] = 'C'; |
||||
} |
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* CREATE PROCEDURAL LANGUAGE |
||||
* --------------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
CreateProceduralLanguage(CreatePLangStmt * stmt) |
||||
{ |
||||
char languageName[NAMEDATALEN]; |
||||
HeapTuple langTup; |
||||
HeapTuple procTup; |
||||
|
||||
Oid typev[8]; |
||||
char nulls[Natts_pg_language]; |
||||
Datum values[Natts_pg_language]; |
||||
Relation rdesc; |
||||
HeapTuple tup; |
||||
TupleDesc tupDesc; |
||||
|
||||
int i; |
||||
|
||||
/* ----------------
|
||||
* Check permission |
||||
* ---------------- |
||||
*/ |
||||
if (!superuser()) |
||||
{ |
||||
elog(WARN, "Only users with Postgres superuser privilege are " |
||||
"permitted to create procedural languages"); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* Translate the language name and check that |
||||
* this language doesn't already exist |
||||
* ---------------- |
||||
*/ |
||||
case_translate_language_name(stmt->plname, languageName); |
||||
|
||||
langTup = SearchSysCacheTuple(LANNAME, |
||||
PointerGetDatum(languageName), |
||||
0, 0, 0); |
||||
if (HeapTupleIsValid(langTup)) |
||||
{ |
||||
elog(WARN, "Language %s already exists", languageName); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* Lookup the PL handler function and check that it is |
||||
* of return type Opaque |
||||
* ---------------- |
||||
*/ |
||||
memset(typev, 0, sizeof(typev)); |
||||
procTup = SearchSysCacheTuple(PRONAME, |
||||
PointerGetDatum(stmt->plhandler), |
||||
UInt16GetDatum(0), |
||||
PointerGetDatum(typev), |
||||
0); |
||||
if (!HeapTupleIsValid(procTup)) |
||||
{ |
||||
elog(WARN, "PL handler function %s() doesn't exist", |
||||
stmt->plhandler); |
||||
} |
||||
if (((Form_pg_proc) GETSTRUCT(procTup))->prorettype != InvalidOid) |
||||
{ |
||||
elog(WARN, "PL handler function %s() isn't of return type Opaque", |
||||
stmt->plhandler); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* Insert the new language into pg_language |
||||
* ---------------- |
||||
*/ |
||||
for (i = 0; i < Natts_pg_language; i++) |
||||
{ |
||||
nulls[i] = ' '; |
||||
values[i] = (Datum) NULL; |
||||
} |
||||
|
||||
i = 0; |
||||
values[i++] = PointerGetDatum(languageName); |
||||
values[i++] = Int8GetDatum((bool) 1); |
||||
values[i++] = Int8GetDatum(stmt->pltrusted); |
||||
values[i++] = ObjectIdGetDatum(procTup->t_oid); |
||||
values[i++] = (Datum) fmgr(TextInRegProcedure, stmt->plcompiler); |
||||
|
||||
rdesc = heap_openr(LanguageRelationName); |
||||
|
||||
tupDesc = rdesc->rd_att; |
||||
tup = heap_formtuple(tupDesc, values, nulls); |
||||
|
||||
heap_insert(rdesc, tup); |
||||
|
||||
heap_close(rdesc); |
||||
return; |
||||
} |
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* DROP PROCEDURAL LANGUAGE |
||||
* --------------------------------------------------------------------- |
||||
*/ |
||||
void |
||||
DropProceduralLanguage(DropPLangStmt * stmt) |
||||
{ |
||||
char languageName[NAMEDATALEN]; |
||||
HeapTuple langTup; |
||||
|
||||
Relation rdesc; |
||||
HeapScanDesc scanDesc; |
||||
ScanKeyData scanKeyData; |
||||
HeapTuple tup; |
||||
|
||||
/* ----------------
|
||||
* Check permission |
||||
* ---------------- |
||||
*/ |
||||
if (!superuser()) |
||||
{ |
||||
elog(WARN, "Only users with Postgres superuser privilege are " |
||||
"permitted to drop procedural languages"); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* Translate the language name, check that |
||||
* this language exist and is a PL |
||||
* ---------------- |
||||
*/ |
||||
case_translate_language_name(stmt->plname, languageName); |
||||
|
||||
langTup = SearchSysCacheTuple(LANNAME, |
||||
PointerGetDatum(languageName), |
||||
0, 0, 0); |
||||
if (!HeapTupleIsValid(langTup)) |
||||
{ |
||||
elog(WARN, "Language %s doesn't exist", languageName); |
||||
} |
||||
|
||||
if (!((Form_pg_language) GETSTRUCT(langTup))->lanispl) |
||||
{ |
||||
elog(WARN, "Language %s isn't a created procedural language", |
||||
languageName); |
||||
} |
||||
|
||||
/* ----------------
|
||||
* Now scan pg_language and delete the PL tuple |
||||
* ---------------- |
||||
*/ |
||||
rdesc = heap_openr(LanguageRelationName); |
||||
|
||||
ScanKeyEntryInitialize(&scanKeyData, 0, Anum_pg_language_lanname, |
||||
F_NAMEEQ, PointerGetDatum(languageName)); |
||||
|
||||
scanDesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, &scanKeyData); |
||||
|
||||
tup = heap_getnext(scanDesc, 0, (Buffer *) NULL); |
||||
|
||||
if (!HeapTupleIsValid(tup)) |
||||
{ |
||||
elog(WARN, "Language with name '%s' not found", languageName); |
||||
} |
||||
|
||||
heap_delete(rdesc, &(tup->t_ctid)); |
||||
|
||||
heap_endscan(scanDesc); |
||||
heap_close(rdesc); |
||||
} |
@ -0,0 +1,17 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* proclang.h-- |
||||
* prototypes for proclang.c. |
||||
* |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PROCLANG_H |
||||
#define PROCLANG_H |
||||
|
||||
#include <nodes/parsenodes.h> |
||||
|
||||
extern void CreateProceduralLanguage(CreatePLangStmt * stmt); |
||||
extern void DropProceduralLanguage(DropPLangStmt * stmt); |
||||
|
||||
#endif /* PROCLANG_H */ |
Loading…
Reference in new issue