postgresql/src/backend/commands/proclang.c

206 lines
4.9 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* 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_shadow.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]; ++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(ERROR, "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(ERROR, "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(ERROR, "PL handler function %s() doesn't exist",
stmt->plhandler);
}
if (((Form_pg_proc) GETSTRUCT(procTup))->prorettype != InvalidOid)
{
elog(ERROR, "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(ERROR, "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(ERROR, "Language %s doesn't exist", languageName);
}
if (!((Form_pg_language) GETSTRUCT(langTup))->lanispl)
{
elog(ERROR, "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, false, 1, &scanKeyData);
tup = heap_getnext(scanDesc, 0, (Buffer *) NULL);
if (!HeapTupleIsValid(tup))
{
elog(ERROR, "Language with name '%s' not found", languageName);
}
heap_delete(rdesc, &(tup->t_ctid));
heap_endscan(scanDesc);
heap_close(rdesc);
}