1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Now we are able to CREATE PROCEDURAL LANGUAGE (Thanks, Jan).

This commit is contained in:
Vadim B. Mikheev
1997-10-28 15:11:45 +00:00
parent 9db2992640
commit 7bff4c5078
16 changed files with 638 additions and 145 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);