aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/Makefile4
-rw-r--r--src/backend/commands/define.c53
-rw-r--r--src/backend/commands/proclang.c205
-rw-r--r--src/backend/commands/trigger.c112
4 files changed, 334 insertions, 40 deletions
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index 5d8e945a66a..c65f04da402 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -4,7 +4,7 @@
# Makefile for commands
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.4 1997/08/31 11:40:12 vadim Exp $
+# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.5 1997/10/28 14:54:43 vadim Exp $
#
#-------------------------------------------------------------------------
@@ -19,7 +19,7 @@ CFLAGS+=$(INCLUDE_OPT)
OBJS = async.o creatinh.o command.o copy.o defind.o define.o \
purge.o remove.o rename.o vacuum.o version.o view.o cluster.o \
- recipe.o explain.o sequence.o trigger.o
+ recipe.o explain.o sequence.o trigger.o proclang.o
all: SUBSYS.o
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 903bb516495..9aa8c098973 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.16 1997/09/08 21:42:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.17 1997/10/28 14:54:46 vadim Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -45,6 +45,7 @@
#include <catalog/pg_operator.h>
#include <catalog/pg_proc.h>
#include <catalog/pg_type.h>
+#include <catalog/pg_language.h>
#include <utils/syscache.h>
#include <fmgr.h> /* for fmgr */
#include <utils/builtins.h> /* prototype for textin() */
@@ -239,6 +240,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
bool canCache;
bool returnsSet;
+ bool lanisPL = false;
+
/* The function returns a set of values, as opposed to a singleton. */
@@ -262,19 +265,59 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
}
else
{
- elog(WARN,
+ HeapTuple languageTuple;
+ Form_pg_language languageStruct;
+
+ /* Lookup the language in the system cache */
+ languageTuple = SearchSysCacheTuple(LANNAME,
+ PointerGetDatum(languageName),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(languageTuple)) {
+
+ elog(WARN,
"Unrecognized language specified in a CREATE FUNCTION: "
- "'%s'. Recognized languages are sql, C, and internal.",
+ "'%s'. Recognized languages are sql, C, internal "
+ "and the created procedural languages.",
languageName);
+ }
+
+ /* Check that this language is a PL */
+ languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
+ if (!(languageStruct->lanispl)) {
+ elog(WARN,
+ "Language '%s' isn't defined as PL", languageName);
+ }
+
+ /*
+ * Functions in untrusted procedural languages are
+ * restricted to be defined by postgres superusers only
+ */
+ if (languageStruct->lanpltrusted == false && !superuser()) {
+ elog(WARN, "Only users with Postgres superuser privilege "
+ "are permitted to create a function in the '%s' "
+ "language.",
+ languageName);
+ }
+
+ lanisPL = true;
+
+ /*
+ * These are meaningless
+ */
+ perbyte_cpu = percall_cpu = 0;
+ byte_pct = outin_ratio = 100;
+ canCache = false;
}
interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
- if (strcmp(languageName, "sql") != 0 && !superuser())
+ if (strcmp(languageName, "sql") != 0 && lanisPL == false && !superuser())
elog(WARN,
"Only users with Postgres superuser privilege are permitted "
"to create a function "
- "in the '%s' language. Others may use the 'sql' language.",
+ "in the '%s' language. Others may use the 'sql' language "
+ "or the created procedural languages.",
languageName);
/* Above does not return. */
else
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);
+}
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 9215f410555..273136b2923 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -26,11 +26,11 @@
#include "utils/mcxt.h"
#include "utils/inval.h"
#include "utils/builtins.h"
+#include "utils/syscache.h"
#ifndef NO_SECURITY
#include "miscadmin.h"
#include "utils/acl.h"
-#include "utils/syscache.h"
#endif
TriggerData *CurrentTriggerData = NULL;
@@ -87,8 +87,8 @@ CreateTrigger(CreateTrigStmt * stmt)
if (stmt->row)
TRIGGER_SETT_ROW(tgtype);
else
- elog (WARN, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
-
+ elog(WARN, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
+
for (i = 0; i < 3 && stmt->actions[i]; i++)
{
switch (stmt->actions[i])
@@ -142,7 +142,22 @@ CreateTrigger(CreateTrigStmt * stmt)
elog(WARN, "CreateTrigger: function %s () does not exist", stmt->funcname);
if (((Form_pg_proc) GETSTRUCT(tuple))->prolang != ClanguageId)
- elog(WARN, "CreateTrigger: only C functions are supported");
+ {
+ HeapTuple langTup;
+
+ langTup = SearchSysCacheTuple(LANOID,
+ ObjectIdGetDatum(((Form_pg_proc) GETSTRUCT(tuple))->prolang),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(langTup))
+ {
+ elog(WARN, "CreateTrigger: cache lookup for PL failed");
+ }
+
+ if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
+ {
+ elog(WARN, "CreateTrigger: only C and PL functions are supported");
+ }
+ }
MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
@@ -159,10 +174,10 @@ CreateTrigger(CreateTrigStmt * stmt)
foreach(le, stmt->args)
{
- char *ar = (char *) lfirst(le);
+ char *ar = (char *) lfirst(le);
len += strlen(ar) + 4;
- for ( ; *ar; ar++)
+ for (; *ar; ar++)
{
if (*ar == '\\')
len++;
@@ -172,9 +187,9 @@ CreateTrigger(CreateTrigStmt * stmt)
args[0] = 0;
foreach(le, stmt->args)
{
- char *s = (char *) lfirst(le);
- char *d = args + strlen(args);
-
+ char *s = (char *) lfirst(le);
+ char *d = args + strlen(args);
+
while (*s)
{
if (*s == '\\')
@@ -399,6 +414,7 @@ RelationBuildTriggers(Relation relation)
build->tgname = nameout(&(pg_trigger->tgname));
build->tgfoid = pg_trigger->tgfoid;
build->tgfunc = NULL;
+ build->tgplfunc = NULL;
build->tgtype = pg_trigger->tgtype;
build->tgnargs = pg_trigger->tgnargs;
memcpy(build->tgattr, &(pg_trigger->tgattr), 8 * sizeof(int16));
@@ -578,6 +594,54 @@ DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger)
}
+static HeapTuple
+ExecCallTriggerFunc(Trigger * trigger)
+{
+
+ if (trigger->tgfunc != NULL)
+ {
+ return (HeapTuple) ((*(trigger->tgfunc)) ());
+ }
+
+ if (trigger->tgplfunc == NULL)
+ {
+ HeapTuple procTuple;
+ HeapTuple langTuple;
+ Form_pg_proc procStruct;
+ Form_pg_language langStruct;
+ int nargs;
+
+ procTuple = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(trigger->tgfoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(procTuple))
+ {
+ elog(WARN, "ExecCallTriggerFunc(): Cache lookup for proc %ld failed",
+ ObjectIdGetDatum(trigger->tgfoid));
+ }
+ procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
+
+ langTuple = SearchSysCacheTuple(LANOID,
+ ObjectIdGetDatum(procStruct->prolang),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(langTuple))
+ {
+ elog(WARN, "ExecCallTriggerFunc(): Cache lookup for language %ld failed",
+ ObjectIdGetDatum(procStruct->prolang));
+ }
+ langStruct = (Form_pg_language) GETSTRUCT(langTuple);
+
+ if (langStruct->lanispl == false)
+ {
+ fmgr_info(trigger->tgfoid, &(trigger->tgfunc), &nargs);
+ return (HeapTuple) ((*(trigger->tgfunc)) ());
+ }
+ fmgr_info(langStruct->lanplcallfoid, &(trigger->tgplfunc), &nargs);
+ }
+
+ return (HeapTuple) ((*(trigger->tgplfunc)) (trigger->tgfoid));
+}
+
HeapTuple
ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
{
@@ -586,7 +650,6 @@ ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
HeapTuple newtuple = trigtuple;
HeapTuple oldtuple;
- int nargs;
int i;
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -599,9 +662,7 @@ ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = oldtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ());
+ newtuple = ExecCallTriggerFunc(trigger[i]);
if (newtuple == NULL)
break;
else if (oldtuple != newtuple && oldtuple != trigtuple)
@@ -618,7 +679,6 @@ ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT];
- int nargs;
int i;
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@@ -630,9 +690,7 @@ ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- (void) ((*(trigger[i]->tgfunc)) ());
+ ExecCallTriggerFunc(trigger[i]);
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
@@ -647,7 +705,6 @@ ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
HeapTuple trigtuple;
HeapTuple newtuple = NULL;
- int nargs;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, true);
@@ -664,9 +721,7 @@ ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ());
+ newtuple = ExecCallTriggerFunc(trigger[i]);
if (newtuple == NULL)
break;
}
@@ -684,7 +739,6 @@ ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
HeapTuple trigtuple;
- int nargs;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, false);
@@ -700,9 +754,7 @@ ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- (void) ((*(trigger[i]->tgfunc)) ());
+ ExecCallTriggerFunc(trigger[i]);
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
@@ -719,7 +771,6 @@ ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
HeapTuple trigtuple;
HeapTuple oldtuple;
HeapTuple intuple = newtuple;
- int nargs;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, true);
@@ -736,9 +787,7 @@ ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_newtuple = oldtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ());
+ newtuple = ExecCallTriggerFunc(trigger[i]);
if (newtuple == NULL)
break;
else if (oldtuple != newtuple && oldtuple != intuple)
@@ -757,7 +806,6 @@ ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
HeapTuple trigtuple;
- int nargs;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, false);
@@ -773,9 +821,7 @@ ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_newtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
- if (trigger[i]->tgfunc == NULL)
- fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- (void) ((*(trigger[i]->tgfunc)) ());
+ ExecCallTriggerFunc(trigger[i]);
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);