aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/proclang.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/proclang.c')
-rw-r--r--src/backend/commands/proclang.c205
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);
+}