diff options
Diffstat (limited to 'src/backend/commands/proclang.c')
-rw-r--r-- | src/backend/commands/proclang.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c new file mode 100644 index 00000000000..2b8836b70bb --- /dev/null +++ b/src/backend/commands/proclang.c @@ -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); +} |