1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-22 21:53:06 +03:00
Files
postgres/src/backend/commands/proclang.c
Tom Lane eb3adab568 Provide an upgrade strategy for dump files containing functions declared
with OPAQUE.  CREATE LANGUAGE, CREATE TRIGGER, and CREATE TYPE will all
accept references to functions declared with OPAQUE --- but they will
issue a NOTICE, and will modify the function entries in pg_proc to have
the preferred type-safe argument or result types instead of OPAQUE.
Per recent pghackers discussions.
2002-09-21 18:39:26 +00:00

234 lines
5.9 KiB
C

/*-------------------------------------------------------------------------
*
* proclang.c
* PostgreSQL PROCEDURAL LANGUAGE support code.
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.43 2002/09/21 18:39:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/proclang.h"
#include "commands/defrem.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/* ---------------------------------------------------------------------
* CREATE PROCEDURAL LANGUAGE
* ---------------------------------------------------------------------
*/
void
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
char languageName[NAMEDATALEN];
Oid procOid,
valProcOid;
Oid funcrettype;
Oid typev[FUNC_MAX_ARGS];
char nulls[Natts_pg_language];
Datum values[Natts_pg_language];
Relation rel;
HeapTuple tup;
TupleDesc tupDesc;
int i;
ObjectAddress myself,
referenced;
/*
* Check permission
*/
if (!superuser())
elog(ERROR, "Only users with 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);
if (SearchSysCacheExists(LANGNAME,
PointerGetDatum(languageName),
0, 0, 0))
elog(ERROR, "Language %s already exists", languageName);
/*
* Lookup the PL handler function and check that it is of the expected
* return type
*/
MemSet(typev, 0, sizeof(typev));
procOid = LookupFuncName(stmt->plhandler, 0, typev);
if (!OidIsValid(procOid))
elog(ERROR, "function %s() doesn't exist",
NameListToString(stmt->plhandler));
funcrettype = get_func_rettype(procOid);
if (funcrettype != LANGUAGE_HANDLEROID)
{
/*
* We allow OPAQUE just so we can load old dump files. When we
* see a handler function declared OPAQUE, change it to
* LANGUAGE_HANDLER.
*/
if (funcrettype == OPAQUEOID)
{
elog(NOTICE, "CreateProceduralLanguage: changing return type of function %s() from OPAQUE to LANGUAGE_HANDLER",
NameListToString(stmt->plhandler));
SetFunctionReturnType(procOid, LANGUAGE_HANDLEROID);
}
else
elog(ERROR, "CreateProceduralLanguage: function %s() must return LANGUAGE_HANDLER",
NameListToString(stmt->plhandler));
}
/* validate the validator function */
if (stmt->plvalidator)
{
typev[0] = OIDOID;
valProcOid = LookupFuncName(stmt->plvalidator, 1, typev);
if (!OidIsValid(valProcOid))
elog(ERROR, "function %s(oid) doesn't exist",
NameListToString(stmt->plvalidator));
/* return value is ignored, so we don't check the type */
}
else
valProcOid = InvalidOid;
/*
* 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++] = BoolGetDatum(true); /* lanispl */
values[i++] = BoolGetDatum(stmt->pltrusted);
values[i++] = ObjectIdGetDatum(procOid);
values[i++] = ObjectIdGetDatum(valProcOid);
nulls[i] = 'n'; /* lanacl */
rel = heap_openr(LanguageRelationName, RowExclusiveLock);
tupDesc = rel->rd_att;
tup = heap_formtuple(tupDesc, values, nulls);
simple_heap_insert(rel, tup);
CatalogUpdateIndexes(rel, tup);
/*
* Create dependencies for language
*/
myself.classId = RelationGetRelid(rel);
myself.objectId = HeapTupleGetOid(tup);
myself.objectSubId = 0;
/* dependency on the PL handler function */
referenced.classId = RelOid_pg_proc;
referenced.objectId = procOid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on the validator function, if any */
if (OidIsValid(valProcOid))
{
referenced.classId = RelOid_pg_proc;
referenced.objectId = valProcOid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_close(rel, RowExclusiveLock);
}
/* ---------------------------------------------------------------------
* DROP PROCEDURAL LANGUAGE
* ---------------------------------------------------------------------
*/
void
DropProceduralLanguage(DropPLangStmt *stmt)
{
char languageName[NAMEDATALEN];
HeapTuple langTup;
ObjectAddress object;
/*
* Check permission
*/
if (!superuser())
elog(ERROR, "Only users with 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 = SearchSysCache(LANGNAME,
CStringGetDatum(languageName),
0, 0, 0);
if (!HeapTupleIsValid(langTup))
elog(ERROR, "Language %s doesn't exist", languageName);
object.classId = get_system_catalog_relid(LanguageRelationName);
object.objectId = HeapTupleGetOid(langTup);
object.objectSubId = 0;
ReleaseSysCache(langTup);
/*
* Do the deletion
*/
performDeletion(&object, stmt->behavior);
}
/*
* Guts of language dropping.
*/
void
DropProceduralLanguageById(Oid langOid)
{
Relation rel;
HeapTuple langTup;
rel = heap_openr(LanguageRelationName, RowExclusiveLock);
langTup = SearchSysCache(LANGOID,
ObjectIdGetDatum(langOid),
0, 0, 0);
if (!HeapTupleIsValid(langTup))
elog(ERROR, "DropProceduralLanguageById: language %u not found",
langOid);
simple_heap_delete(rel, &langTup->t_self);
ReleaseSysCache(langTup);
heap_close(rel, RowExclusiveLock);
}