aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/proclang.c288
1 files changed, 227 insertions, 61 deletions
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 3b90b4158be..499523ae007 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,31 +7,46 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.60 2005/04/14 20:03:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.61 2005/09/05 23:50:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <ctype.h>
-
#include "access/heapam.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_language.h"
+#include "catalog/pg_namespace.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/gramparse.h"
#include "parser/parse_func.h"
#include "utils/builtins.h"
+#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+typedef struct
+{
+ char *lanname; /* PL name */
+ bool lantrusted; /* trusted? */
+ char *lanhandler; /* name of handler function */
+ char *lanvalidator; /* name of validator function, or NULL */
+ char *lanlibrary; /* path of shared library */
+} PLTemplate;
+
+static void create_proc_lang(const char *languageName,
+ Oid handlerOid, Oid valOid, bool trusted);
+static PLTemplate *find_language_template(const char *languageName);
+
+
/* ---------------------------------------------------------------------
* CREATE PROCEDURAL LANGUAGE
* ---------------------------------------------------------------------
@@ -40,19 +55,11 @@ void
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
char *languageName;
- Oid procOid,
- valProcOid;
+ PLTemplate *pltemplate;
+ Oid handlerOid,
+ valOid;
Oid funcrettype;
Oid funcargtypes[1];
- NameData langname;
- char nulls[Natts_pg_language];
- Datum values[Natts_pg_language];
- Relation rel;
- HeapTuple tup;
- TupleDesc tupDesc;
- int i;
- ObjectAddress myself,
- referenced;
/*
* Check permission
@@ -76,64 +83,181 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
errmsg("language \"%s\" already exists", languageName)));
/*
- * Lookup the PL handler function and check that it is of the expected
- * return type
+ * If we have template information for the language, ignore the supplied
+ * parameters (if any) and use the template information.
*/
- procOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
- funcrettype = get_func_rettype(procOid);
- if (funcrettype != LANGUAGE_HANDLEROID)
+ if ((pltemplate = find_language_template(languageName)) != NULL)
{
+ List *funcname;
+
/*
- * We allow OPAQUE just so we can load old dump files. When we
- * see a handler function declared OPAQUE, change it to
- * LANGUAGE_HANDLER.
+ * Find or create the handler function, which we force to be in
+ * the pg_catalog schema. If already present, it must have the
+ * correct return type.
*/
- if (funcrettype == OPAQUEOID)
+ funcname = SystemFuncName(pltemplate->lanhandler);
+ handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
+ if (OidIsValid(handlerOid))
{
- ereport(WARNING,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
- NameListToString(stmt->plhandler))));
- SetFunctionReturnType(procOid, LANGUAGE_HANDLEROID);
+ funcrettype = get_func_rettype(handlerOid);
+ if (funcrettype != LANGUAGE_HANDLEROID)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s must return type \"language_handler\"",
+ NameListToString(funcname))));
}
else
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("function %s must return type \"language_handler\"",
- NameListToString(stmt->plhandler))));
- }
+ {
+ handlerOid = ProcedureCreate(pltemplate->lanhandler,
+ PG_CATALOG_NAMESPACE,
+ false, /* replace */
+ false, /* returnsSet */
+ LANGUAGE_HANDLEROID,
+ ClanguageId,
+ F_FMGR_C_VALIDATOR,
+ pltemplate->lanhandler,
+ pltemplate->lanlibrary,
+ false, /* isAgg */
+ false, /* security_definer */
+ false, /* isStrict */
+ PROVOLATILE_VOLATILE,
+ buildoidvector(funcargtypes, 0),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL));
+ }
- /* validate the validator function */
- if (stmt->plvalidator)
- {
- funcargtypes[0] = OIDOID;
- valProcOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
- /* return value is ignored, so we don't check the type */
+ /*
+ * Likewise for the validator, if required; but we don't care about
+ * its return type.
+ */
+ if (pltemplate->lanvalidator)
+ {
+ funcname = SystemFuncName(pltemplate->lanvalidator);
+ funcargtypes[0] = OIDOID;
+ valOid = LookupFuncName(funcname, 1, funcargtypes, true);
+ if (!OidIsValid(valOid))
+ {
+ valOid = ProcedureCreate(pltemplate->lanvalidator,
+ PG_CATALOG_NAMESPACE,
+ false, /* replace */
+ false, /* returnsSet */
+ VOIDOID,
+ ClanguageId,
+ F_FMGR_C_VALIDATOR,
+ pltemplate->lanvalidator,
+ pltemplate->lanlibrary,
+ false, /* isAgg */
+ false, /* security_definer */
+ false, /* isStrict */
+ PROVOLATILE_VOLATILE,
+ buildoidvector(funcargtypes, 1),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL));
+ }
+ }
+ else
+ valOid = InvalidOid;
+
+ /* ok, create it */
+ create_proc_lang(languageName, handlerOid, valOid,
+ pltemplate->lantrusted);
}
else
- valProcOid = InvalidOid;
+ {
+ /*
+ * No template, so use the provided information. If there's
+ * no handler clause, the user is trying to rely on a template
+ * that we don't have, so complain accordingly.
+ *
+ * XXX In 8.2, replace the detail message with a hint to look in
+ * pg_pltemplate.
+ */
+ if (!stmt->plhandler)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("unsupported language \"%s\"",
+ languageName),
+ errdetail("Supported languages are plpgsql, pltcl, pltclu, "
+ "plperl, plperlu, and plpythonu.")));
+
+ /*
+ * Lookup the PL handler function and check that it is of the expected
+ * return type
+ */
+ handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
+ funcrettype = get_func_rettype(handlerOid);
+ 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. (This is probably obsolete and removable?)
+ */
+ if (funcrettype == OPAQUEOID)
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
+ NameListToString(stmt->plhandler))));
+ SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s must return type \"language_handler\"",
+ NameListToString(stmt->plhandler))));
+ }
+
+ /* validate the validator function */
+ if (stmt->plvalidator)
+ {
+ funcargtypes[0] = OIDOID;
+ valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
+ /* return value is ignored, so we don't check the type */
+ }
+ else
+ valOid = InvalidOid;
+
+ /* ok, create it */
+ create_proc_lang(languageName, handlerOid, valOid, stmt->pltrusted);
+ }
+}
+
+/*
+ * Guts of language creation.
+ */
+static void
+create_proc_lang(const char *languageName,
+ Oid handlerOid, Oid valOid, bool trusted)
+{
+ Relation rel;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_language];
+ char nulls[Natts_pg_language];
+ NameData langname;
+ HeapTuple tup;
+ ObjectAddress myself,
+ referenced;
/*
* Insert the new language into pg_language
*/
- for (i = 0; i < Natts_pg_language; i++)
- {
- nulls[i] = ' ';
- values[i] = (Datum) NULL;
- }
+ rel = heap_open(LanguageRelationId, RowExclusiveLock);
+ tupDesc = rel->rd_att;
- i = 0;
- namestrcpy(&langname, languageName);
- values[i++] = NameGetDatum(&langname); /* lanname */
- values[i++] = BoolGetDatum(true); /* lanispl */
- values[i++] = BoolGetDatum(stmt->pltrusted); /* lanpltrusted */
- values[i++] = ObjectIdGetDatum(procOid); /* lanplcallfoid */
- values[i++] = ObjectIdGetDatum(valProcOid); /* lanvalidator */
- nulls[i] = 'n'; /* lanacl */
+ memset(values, 0, sizeof(values));
+ memset(nulls, ' ', sizeof(nulls));
- rel = heap_open(LanguageRelationId, RowExclusiveLock);
+ namestrcpy(&langname, languageName);
+ values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
+ values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
+ values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
+ values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
+ values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
+ nulls[Anum_pg_language_lanacl - 1] = 'n';
- tupDesc = rel->rd_att;
tup = heap_formtuple(tupDesc, values, nulls);
simple_heap_insert(rel, tup);
@@ -149,15 +273,15 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
/* dependency on the PL handler function */
referenced.classId = ProcedureRelationId;
- referenced.objectId = procOid;
+ referenced.objectId = handlerOid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on the validator function, if any */
- if (OidIsValid(valProcOid))
+ if (OidIsValid(valOid))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = valProcOid;
+ referenced.objectId = valOid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -165,6 +289,45 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
heap_close(rel, RowExclusiveLock);
}
+/*
+ * Look to see if we have template information for the given language name.
+ *
+ * XXX for PG 8.1, the template info is hard-wired. This is to be replaced
+ * by a shared system catalog in 8.2.
+ *
+ * XXX if you add languages to this list, add them also to the errdetail
+ * message above and the list in functioncmds.c. Those hard-wired lists
+ * should go away in 8.2, also.
+ */
+static PLTemplate *
+find_language_template(const char *languageName)
+{
+ static PLTemplate templates[] = {
+ { "plpgsql", true, "plpgsql_call_handler", "plpgsql_validator",
+ "$libdir/plpgsql" },
+ { "pltcl", true, "pltcl_call_handler", NULL,
+ "$libdir/pltcl" },
+ { "pltclu", false, "pltclu_call_handler", NULL,
+ "$libdir/pltcl" },
+ { "plperl", true, "plperl_call_handler", "plperl_validator",
+ "$libdir/plperl" },
+ { "plperlu", false, "plperl_call_handler", "plperl_validator",
+ "$libdir/plperl" },
+ { "plpythonu", false, "plpython_call_handler", NULL,
+ "$libdir/plpython" },
+ { NULL, false, NULL, NULL, NULL }
+ };
+
+ PLTemplate *ptr;
+
+ for (ptr = templates; ptr->lanname != NULL; ptr++)
+ {
+ if (strcmp(languageName, ptr->lanname) == 0)
+ return ptr;
+ }
+ return NULL;
+}
+
/* ---------------------------------------------------------------------
* DROP PROCEDURAL LANGUAGE
@@ -186,8 +349,7 @@ DropProceduralLanguage(DropPLangStmt *stmt)
errmsg("must be superuser to drop procedural language")));
/*
- * Translate the language name, check that this language exist and is
- * a PL
+ * Translate the language name, check that the language exists
*/
languageName = case_translate_language_name(stmt->plname);
@@ -244,6 +406,10 @@ RenameLanguage(const char *oldname, const char *newname)
HeapTuple tup;
Relation rel;
+ /* Translate both names for consistency with CREATE */
+ oldname = case_translate_language_name(oldname);
+ newname = case_translate_language_name(newname);
+
rel = heap_open(LanguageRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy(LANGNAME,
@@ -262,7 +428,7 @@ RenameLanguage(const char *oldname, const char *newname)
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("language \"%s\" already exists", newname)));
- /* must be superuser */
+ /* must be superuser, since we do not have owners for PLs */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),