diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/Makefile | 4 | ||||
-rw-r--r-- | src/backend/commands/define.c | 53 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 205 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 112 |
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); |