mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Implement a preliminary 'template' facility for procedural languages,
as per my recent proposal. For now the template data is hard-wired in proclang.c --- this should be replaced later by a new shared system catalog, but we don't want to force initdb during 8.1 beta. This change lets us cleanly load existing dump files even if they contain outright wrong information about a PL's support functions, such as a wrong path to the shared library or a missing validator function. Also, we can revert the recent kluges to make pg_dump dump PL support functions that are stored in pg_catalog. While at it, I removed the code in pg_regress that replaced $libdir with a hardcoded path for temporary installations. This is no longer needed given our support for relocatable installations.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
rel = heap_open(LanguageRelationId, RowExclusiveLock);
|
||||
|
||||
tupDesc = rel->rd_att;
|
||||
|
||||
memset(values, 0, sizeof(values));
|
||||
memset(nulls, ' ', sizeof(nulls));
|
||||
|
||||
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';
|
||||
|
||||
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),
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.509 2005/08/24 19:34:12 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.510 2005/09/05 23:50:48 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -2303,13 +2303,24 @@ IntegerOnly: SignedIconst { $$ = makeInteger($1); };
|
||||
|
||||
CreatePLangStmt:
|
||||
CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
|
||||
HANDLER handler_name opt_validator opt_lancompiler
|
||||
{
|
||||
CreatePLangStmt *n = makeNode(CreatePLangStmt);
|
||||
n->plname = $5;
|
||||
/* parameters are all to be supplied by system */
|
||||
n->plhandler = NIL;
|
||||
n->plvalidator = NIL;
|
||||
n->pltrusted = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
|
||||
HANDLER handler_name opt_validator opt_lancompiler
|
||||
{
|
||||
CreatePLangStmt *n = makeNode(CreatePLangStmt);
|
||||
n->plname = $5;
|
||||
n->plhandler = $7;
|
||||
n->plvalidator = $8;
|
||||
n->pltrusted = $2;
|
||||
/* LANCOMPILER is now ignored entirely */
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@ -2328,14 +2339,14 @@ handler_name:
|
||||
| name attrs { $$ = lcons(makeString($1), $2); }
|
||||
;
|
||||
|
||||
opt_lancompiler:
|
||||
LANCOMPILER Sconst { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = ""; }
|
||||
opt_validator:
|
||||
VALIDATOR handler_name { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
opt_validator:
|
||||
VALIDATOR handler_name { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
opt_lancompiler:
|
||||
LANCOMPILER Sconst { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
DropPLangStmt:
|
||||
|
@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.419 2005/08/23 22:40:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.420 2005/09/05 23:50:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2295,7 +2295,6 @@ getFuncs(int *numFuncs)
|
||||
int i_proargtypes;
|
||||
int i_prorettype;
|
||||
int i_proacl;
|
||||
int i_is_pl_handler;
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema("pg_catalog");
|
||||
@ -2304,34 +2303,16 @@ getFuncs(int *numFuncs)
|
||||
|
||||
if (g_fout->remoteVersion >= 70300)
|
||||
{
|
||||
/*
|
||||
* For 7.3 and up, we consider it's user-defined if it's not in
|
||||
* pg_catalog. We also collect info on functions in pg_catalog, but
|
||||
* only if they are call handlers or validators for PL languages.
|
||||
*/
|
||||
appendPQExpBuffer(query,
|
||||
"SELECT tableoid, oid, proname, prolang, "
|
||||
"pronargs, proargtypes, prorettype, proacl, "
|
||||
"pronamespace, "
|
||||
"(%s proowner) as rolname, "
|
||||
"CASE WHEN oid IN "
|
||||
" (select lanplcallfoid from pg_language "
|
||||
" where lanispl) THEN true "
|
||||
" WHEN oid IN "
|
||||
" (select lanvalidator from pg_language "
|
||||
" where lanispl) THEN true "
|
||||
" ELSE false END AS is_pl_handler "
|
||||
"(%s proowner) as rolname "
|
||||
"FROM pg_proc "
|
||||
"WHERE NOT proisagg "
|
||||
"AND (pronamespace != "
|
||||
" (select oid from pg_namespace "
|
||||
" where nspname = 'pg_catalog')"
|
||||
" OR oid IN "
|
||||
" (select lanplcallfoid from pg_language "
|
||||
" where lanispl) "
|
||||
" OR oid IN "
|
||||
" (select lanvalidator from pg_language "
|
||||
" where lanispl))",
|
||||
"AND pronamespace != "
|
||||
"(select oid from pg_namespace"
|
||||
" where nspname = 'pg_catalog')",
|
||||
username_subquery);
|
||||
}
|
||||
else if (g_fout->remoteVersion >= 70100)
|
||||
@ -2341,8 +2322,7 @@ getFuncs(int *numFuncs)
|
||||
"pronargs, proargtypes, prorettype, "
|
||||
"'{=X}' as proacl, "
|
||||
"0::oid as pronamespace, "
|
||||
"(%s proowner) as rolname, "
|
||||
"false AS is_pl_handler "
|
||||
"(%s proowner) as rolname "
|
||||
"FROM pg_proc "
|
||||
"where pg_proc.oid > '%u'::oid",
|
||||
username_subquery,
|
||||
@ -2358,8 +2338,7 @@ getFuncs(int *numFuncs)
|
||||
"pronargs, proargtypes, prorettype, "
|
||||
"'{=X}' as proacl, "
|
||||
"0::oid as pronamespace, "
|
||||
"(%s proowner) as rolname, "
|
||||
"false AS is_pl_handler "
|
||||
"(%s proowner) as rolname "
|
||||
"FROM pg_proc "
|
||||
"where pg_proc.oid > '%u'::oid",
|
||||
username_subquery,
|
||||
@ -2385,7 +2364,6 @@ getFuncs(int *numFuncs)
|
||||
i_proargtypes = PQfnumber(res, "proargtypes");
|
||||
i_prorettype = PQfnumber(res, "prorettype");
|
||||
i_proacl = PQfnumber(res, "proacl");
|
||||
i_is_pl_handler = PQfnumber(res,"is_pl_handler");
|
||||
|
||||
for (i = 0; i < ntups; i++)
|
||||
{
|
||||
@ -2402,8 +2380,6 @@ getFuncs(int *numFuncs)
|
||||
finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
|
||||
finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
|
||||
finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
|
||||
finfo[i].islanghandler =
|
||||
strcmp(PQgetvalue(res, i, i_is_pl_handler), "t") == 0;
|
||||
if (finfo[i].nargs == 0)
|
||||
finfo[i].argtypes = NULL;
|
||||
else
|
||||
@ -5131,7 +5107,9 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
{
|
||||
PQExpBuffer defqry;
|
||||
PQExpBuffer delqry;
|
||||
bool useParams;
|
||||
char *qlanname;
|
||||
char *lanschema;
|
||||
FuncInfo *funcInfo;
|
||||
FuncInfo *validatorInfo = NULL;
|
||||
|
||||
@ -5139,31 +5117,33 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Find the support functions, complaining if not there.
|
||||
* Try to find the support function(s). It is not an error if we
|
||||
* don't find them --- if the functions are in the pg_catalog schema,
|
||||
* as is standard in 8.1 and up, then we won't have loaded them.
|
||||
* (In this case we will emit a parameterless CREATE LANGUAGE command,
|
||||
* which will require PL template knowledge in the backend to reload.)
|
||||
*/
|
||||
|
||||
funcInfo = findFuncByOid(plang->lanplcallfoid);
|
||||
if (funcInfo == NULL)
|
||||
{
|
||||
write_msg(NULL, "WARNING: handler function for language \"%s\" not found\n",
|
||||
plang->dobj.name);
|
||||
return;
|
||||
}
|
||||
if (funcInfo != NULL && !funcInfo->dobj.namespace->dump)
|
||||
funcInfo = NULL; /* treat not-dumped same as not-found */
|
||||
|
||||
if (OidIsValid(plang->lanvalidator))
|
||||
{
|
||||
validatorInfo = findFuncByOid(plang->lanvalidator);
|
||||
if (validatorInfo == NULL)
|
||||
{
|
||||
write_msg(NULL, "WARNING: validator function for language \"%s\" not found\n",
|
||||
plang->dobj.name);
|
||||
return;
|
||||
}
|
||||
if (validatorInfo != NULL && !validatorInfo->dobj.namespace->dump)
|
||||
validatorInfo = NULL;
|
||||
}
|
||||
|
||||
/* Dump if we should, or if both support functions are dumpable */
|
||||
if (!shouldDumpProcLangs() &&
|
||||
!(funcInfo->dobj.namespace->dump &&
|
||||
(validatorInfo == NULL || validatorInfo->dobj.namespace->dump)))
|
||||
/*
|
||||
* If the functions are dumpable then emit a traditional CREATE LANGUAGE
|
||||
* with parameters. Otherwise, dump only if shouldDumpProcLangs() says
|
||||
* to dump it.
|
||||
*/
|
||||
useParams = (funcInfo != NULL &&
|
||||
(validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
|
||||
|
||||
if (!useParams && !shouldDumpProcLangs())
|
||||
return;
|
||||
|
||||
defqry = createPQExpBuffer();
|
||||
@ -5171,34 +5151,42 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
|
||||
qlanname = strdup(fmtId(plang->dobj.name));
|
||||
|
||||
/*
|
||||
* If dumping a HANDLER clause, treat the language as being in the
|
||||
* handler function's schema; this avoids cluttering the HANDLER clause.
|
||||
* Otherwise it doesn't really have a schema.
|
||||
*/
|
||||
if (useParams)
|
||||
lanschema = funcInfo->dobj.namespace->dobj.name;
|
||||
else
|
||||
lanschema = NULL;
|
||||
|
||||
appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
|
||||
qlanname);
|
||||
|
||||
appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
|
||||
plang->lanpltrusted ? "TRUSTED " : "",
|
||||
(useParams && plang->lanpltrusted) ? "TRUSTED " : "",
|
||||
qlanname);
|
||||
appendPQExpBuffer(defqry, " HANDLER %s",
|
||||
fmtId(funcInfo->dobj.name));
|
||||
if (OidIsValid(plang->lanvalidator))
|
||||
if (useParams)
|
||||
{
|
||||
appendPQExpBuffer(defqry, " VALIDATOR ");
|
||||
/* Cope with possibility that validator is in different schema */
|
||||
if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
|
||||
appendPQExpBuffer(defqry, "%s.",
|
||||
fmtId(validatorInfo->dobj.namespace->dobj.name));
|
||||
appendPQExpBuffer(defqry, "%s",
|
||||
fmtId(validatorInfo->dobj.name));
|
||||
appendPQExpBuffer(defqry, " HANDLER %s",
|
||||
fmtId(funcInfo->dobj.name));
|
||||
if (OidIsValid(plang->lanvalidator))
|
||||
{
|
||||
appendPQExpBuffer(defqry, " VALIDATOR ");
|
||||
/* Cope with possibility that validator is in different schema */
|
||||
if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
|
||||
appendPQExpBuffer(defqry, "%s.",
|
||||
fmtId(validatorInfo->dobj.namespace->dobj.name));
|
||||
appendPQExpBuffer(defqry, "%s",
|
||||
fmtId(validatorInfo->dobj.name));
|
||||
}
|
||||
}
|
||||
appendPQExpBuffer(defqry, ";\n");
|
||||
|
||||
/*
|
||||
* We mark the PL's archive entry as being in the call handler's
|
||||
* namespace; this is what makes it OK to refer to the handler with
|
||||
* an unqualified name above.
|
||||
*/
|
||||
ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
|
||||
plang->dobj.name,
|
||||
funcInfo->dobj.namespace->dobj.name, NULL, "",
|
||||
lanschema, NULL, "",
|
||||
false, "PROCEDURAL LANGUAGE",
|
||||
defqry->data, delqry->data, NULL,
|
||||
plang->dobj.dependencies, plang->dobj.nDeps,
|
||||
@ -5206,7 +5194,6 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
|
||||
/* Dump Proc Lang Comments */
|
||||
resetPQExpBuffer(defqry);
|
||||
|
||||
appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
|
||||
dumpComment(fout, defqry->data,
|
||||
NULL, "",
|
||||
@ -5215,7 +5202,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
if (plang->lanpltrusted)
|
||||
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
|
||||
qlanname, plang->dobj.name,
|
||||
funcInfo->dobj.namespace->dobj.name,
|
||||
lanschema,
|
||||
NULL, plang->lanacl);
|
||||
|
||||
free(qlanname);
|
||||
@ -5359,12 +5346,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
||||
char **argmodes = NULL;
|
||||
char **argnames = NULL;
|
||||
|
||||
if (dataOnly)
|
||||
return;
|
||||
|
||||
/* Dump only funcs in dumpable namespaces, or needed language handlers */
|
||||
if (!finfo->dobj.namespace->dump &&
|
||||
(!finfo->islanghandler || !shouldDumpProcLangs()))
|
||||
/* Dump only funcs in dumpable namespaces */
|
||||
if (!finfo->dobj.namespace->dump || dataOnly)
|
||||
return;
|
||||
|
||||
query = createPQExpBuffer();
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.120 2005/08/23 22:40:35 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.121 2005/09/05 23:50:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -132,7 +132,6 @@ typedef struct _funcInfo
|
||||
Oid *argtypes;
|
||||
Oid prorettype;
|
||||
char *proacl;
|
||||
bool islanghandler;
|
||||
} FuncInfo;
|
||||
|
||||
/* AggInfo is a superset of FuncInfo */
|
||||
|
@ -5,12 +5,12 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.19 2005/08/15 21:02:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.20 2005/09/05 23:50:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres_fe.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "print.h"
|
||||
|
||||
@ -28,7 +28,6 @@ main(int argc, char *argv[])
|
||||
{"username", required_argument, NULL, 'U'},
|
||||
{"password", no_argument, NULL, 'W'},
|
||||
{"dbname", required_argument, NULL, 'd'},
|
||||
{"pglib", required_argument, NULL, 'L'},
|
||||
{"echo", no_argument, NULL, 'e'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
@ -44,16 +43,9 @@ main(int argc, char *argv[])
|
||||
char *username = NULL;
|
||||
bool password = false;
|
||||
bool echo = false;
|
||||
char *pglib = NULL;
|
||||
char *langname = NULL;
|
||||
|
||||
char *p;
|
||||
bool handlerexists;
|
||||
bool validatorexists;
|
||||
bool trusted;
|
||||
char *handler;
|
||||
char *validator = NULL;
|
||||
char *object;
|
||||
|
||||
PQExpBufferData sql;
|
||||
|
||||
@ -65,7 +57,7 @@ main(int argc, char *argv[])
|
||||
|
||||
handle_help_version_opts(argc, argv, "createlang", help);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "lh:p:U:Wd:L:e", long_options, &optindex)) != -1)
|
||||
while ((c = getopt_long(argc, argv, "lh:p:U:Wd:e", long_options, &optindex)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -87,9 +79,6 @@ main(int argc, char *argv[])
|
||||
case 'd':
|
||||
dbname = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
pglib = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
echo = true;
|
||||
break;
|
||||
@ -165,75 +154,17 @@ main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!pglib)
|
||||
pglib = "$libdir";
|
||||
|
||||
for (p = langname; *p; p++)
|
||||
if (*p >= 'A' && *p <= 'Z')
|
||||
*p += ('a' - 'A');
|
||||
|
||||
if (strcmp(langname, "plpgsql") == 0)
|
||||
{
|
||||
trusted = true;
|
||||
handler = "plpgsql_call_handler";
|
||||
validator = "plpgsql_validator";
|
||||
object = "plpgsql";
|
||||
}
|
||||
else if (strcmp(langname, "pltcl") == 0)
|
||||
{
|
||||
trusted = true;
|
||||
handler = "pltcl_call_handler";
|
||||
object = "pltcl";
|
||||
}
|
||||
else if (strcmp(langname, "pltclu") == 0)
|
||||
{
|
||||
trusted = false;
|
||||
handler = "pltclu_call_handler";
|
||||
object = "pltcl";
|
||||
}
|
||||
else if (strcmp(langname, "plperl") == 0)
|
||||
{
|
||||
trusted = true;
|
||||
handler = "plperl_call_handler";
|
||||
validator = "plperl_validator";
|
||||
object = "plperl";
|
||||
}
|
||||
else if (strcmp(langname, "plperlu") == 0)
|
||||
{
|
||||
trusted = false;
|
||||
handler = "plperl_call_handler";
|
||||
validator = "plperl_validator";
|
||||
object = "plperl";
|
||||
}
|
||||
else if (strcmp(langname, "plpythonu") == 0)
|
||||
{
|
||||
trusted = false;
|
||||
handler = "plpython_call_handler";
|
||||
object = "plpython";
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, _("%s: unsupported language \"%s\"\n"),
|
||||
progname, langname);
|
||||
fprintf(stderr, _("Supported languages are plpgsql, pltcl, pltclu, "
|
||||
"plperl, plperlu, and plpythonu.\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||
|
||||
/*
|
||||
* Force schema search path to be just pg_catalog, so that we don't
|
||||
* have to be paranoid about search paths below.
|
||||
*/
|
||||
executeCommand(conn, "SET search_path = pg_catalog;",
|
||||
progname, echo);
|
||||
|
||||
/*
|
||||
* Make sure the language isn't already installed
|
||||
*/
|
||||
printfPQExpBuffer(&sql,
|
||||
"SELECT oid FROM pg_language WHERE lanname = '%s';",
|
||||
"SELECT oid FROM pg_catalog.pg_language WHERE lanname = '%s';",
|
||||
langname);
|
||||
result = executeQuery(conn, sql.data, progname, echo);
|
||||
if (PQntuples(result) > 0)
|
||||
@ -247,61 +178,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
PQclear(result);
|
||||
|
||||
/*
|
||||
* Check whether the call handler exists
|
||||
*/
|
||||
printfPQExpBuffer(&sql, "SELECT oid FROM pg_proc WHERE proname = '%s' "
|
||||
"AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') "
|
||||
"AND prorettype = 'language_handler'::regtype "
|
||||
"AND pronargs = 0;", handler);
|
||||
result = executeQuery(conn, sql.data, progname, echo);
|
||||
handlerexists = (PQntuples(result) > 0);
|
||||
PQclear(result);
|
||||
|
||||
/*
|
||||
* Check whether the validator exists
|
||||
*/
|
||||
if (validator)
|
||||
{
|
||||
printfPQExpBuffer(&sql, "SELECT oid FROM pg_proc WHERE proname = '%s' "
|
||||
"AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') "
|
||||
"AND proargtypes[0] = 'oid'::regtype "
|
||||
"AND pronargs = 1;", validator);
|
||||
result = executeQuery(conn, sql.data, progname, echo);
|
||||
validatorexists = (PQntuples(result) > 0);
|
||||
PQclear(result);
|
||||
}
|
||||
else
|
||||
validatorexists = true; /* don't try to create it */
|
||||
|
||||
/*
|
||||
* Create the function(s) and the language
|
||||
*
|
||||
* NOTE: the functions will be created in pg_catalog because
|
||||
* of our previous "SET search_path".
|
||||
*/
|
||||
resetPQExpBuffer(&sql);
|
||||
|
||||
if (!handlerexists)
|
||||
appendPQExpBuffer(&sql,
|
||||
"CREATE FUNCTION \"%s\" () RETURNS language_handler "
|
||||
"AS '%s/%s' LANGUAGE C;\n",
|
||||
handler, pglib, object);
|
||||
|
||||
if (!validatorexists)
|
||||
appendPQExpBuffer(&sql,
|
||||
"CREATE FUNCTION \"%s\" (oid) RETURNS void "
|
||||
"AS '%s/%s' LANGUAGE C;\n",
|
||||
validator, pglib, object);
|
||||
|
||||
appendPQExpBuffer(&sql,
|
||||
"CREATE %sLANGUAGE \"%s\" HANDLER \"%s\"",
|
||||
(trusted ? "TRUSTED " : ""), langname, handler);
|
||||
|
||||
if (validator)
|
||||
appendPQExpBuffer(&sql, " VALIDATOR \"%s\"", validator);
|
||||
|
||||
appendPQExpBuffer(&sql, ";\n");
|
||||
printfPQExpBuffer(&sql, "CREATE LANGUAGE \"%s\";\n", langname);
|
||||
|
||||
if (echo)
|
||||
printf("%s", sql.data);
|
||||
@ -330,7 +207,6 @@ help(const char *progname)
|
||||
printf(_(" -d, --dbname=DBNAME database to install language in\n"));
|
||||
printf(_(" -e, --echo show the commands being sent to the server\n"));
|
||||
printf(_(" -l, --list show a list of currently installed languages\n"));
|
||||
printf(_(" -L, --pglib=DIRECTORY find language interpreter file in DIRECTORY\n"));
|
||||
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
|
||||
printf(_(" -p, --port=PORT database server port\n"));
|
||||
printf(_(" -U, --username=USERNAME user name to connect as\n"));
|
||||
|
@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# $PostgreSQL: pgsql/src/test/regress/pg_regress.sh,v 1.59 2005/07/17 18:28:45 tgl Exp $
|
||||
# $PostgreSQL: pgsql/src/test/regress/pg_regress.sh,v 1.60 2005/09/05 23:50:49 tgl Exp $
|
||||
|
||||
me=`basename $0`
|
||||
: ${TMPDIR=/tmp}
|
||||
@ -84,7 +84,6 @@ fi
|
||||
: ${outputdir=.}
|
||||
|
||||
libdir='@libdir@'
|
||||
pkglibdir='@pkglibdir@'
|
||||
bindir='@bindir@'
|
||||
datadir='@datadir@'
|
||||
host_platform='@host_tuple@'
|
||||
@ -322,16 +321,7 @@ LOGDIR=$outputdir/log
|
||||
if [ x"$temp_install" != x"" ]
|
||||
then
|
||||
if echo x"$temp_install" | grep -v '^x/' >/dev/null 2>&1; then
|
||||
case $host_platform in
|
||||
*-*-mingw32*)
|
||||
pkglibdir="`pwd -W`/$temp_install/install/$pkglibdir"
|
||||
temp_install="`pwd`/$temp_install"
|
||||
;;
|
||||
*)
|
||||
temp_install="`pwd`/$temp_install"
|
||||
pkglibdir=$temp_install/install/$pkglibdir
|
||||
;;
|
||||
esac
|
||||
temp_install="`pwd`/$temp_install"
|
||||
fi
|
||||
|
||||
bindir=$temp_install/install/$bindir
|
||||
@ -412,13 +402,6 @@ then
|
||||
(exit 2); exit
|
||||
fi
|
||||
|
||||
# fix conversion shared objs path
|
||||
conv=$datadir/conversion_create.sql
|
||||
backup=$conv.bak
|
||||
mv $conv $backup
|
||||
sed -e "s@\$libdir@$pkglibdir@g" $backup > $conv
|
||||
rm $backup
|
||||
|
||||
message "initializing database system"
|
||||
[ "$debug" = yes ] && initdb_options='--debug'
|
||||
"$bindir/initdb" -D "$PGDATA" -L "$datadir" --noclean $initdb_options >"$LOGDIR/initdb.log" 2>&1
|
||||
@ -586,7 +569,7 @@ if [ "$enable_shared" = yes ]; then
|
||||
for lang in xyzzy $load_langs ; do
|
||||
if [ "$lang" != "xyzzy" ]; then
|
||||
message "installing $lang"
|
||||
"$bindir/createlang" -L "$pkglibdir" $psql_options $lang $dbname
|
||||
"$bindir/createlang" $psql_options $lang $dbname
|
||||
if [ $? -ne 0 ] && [ $? -ne 2 ]; then
|
||||
echo "$me: createlang $lang failed"
|
||||
(exit 2); exit
|
||||
|
Reference in New Issue
Block a user